读取固定大小的 inputStream 字节

Read fixed size of bytes of inputSream

我们正在开发视频流应用程序, 目前我们能够捕获视频并逐帧处理,然后 send/receive 两个设备之间的数据。

问题出在接收方,因为我们发送的是固定大小的帧,所以接收方也应该以固定大小处理它们,否则他将无法获得帧。

希望这张图能说明问题。

传输过程:

代码:

public void process(@NonNull Frame frame) {
            byte[] data = frame.getData();           
            frameWidth = frame.getSize().getWidth();
            frameHieght = frame.getSize().getHeight();
            YuvImage yuv = new YuvImage(data, frame.getFormat(), frameWidth, frameHieght, null);
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            yuv.compressToJpeg(new Rect(0, 0, frameWidth, frameHieght), 25, out);
            final byte[] bytes = out.toByteArray();
            frameByteSize = bytes.length;

            OutputStream outputStream = StreamHandler.getOutputStream();
            if (out != null) {
             try {
                   outputStream.write(bytes, 0, frameByteSize);
                   } catch (IOException e) {
                     e.printStackTrace();
                   }
    }

复活过程:

代码:

public void run() {
        int read = 0;
        int hold = 0;
        int frameSize = StreamHandler.getFrameByteSize();
        try {
            Thread.sleep(10000);
            if (SrtreamHandler != null) {
                InputStream inputStream = StreamHandler.getInputStream();
                if (inputStream != null) {
                    BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
                    while (microPhoneActive) {
                        byte[] frame = new byte[frameSize];
                        read = bufferedInputStream.read(frame, 0, frame.length);
                        Bitmap bitmap = BitmapFactory.decodeByteArray(frame, 0, frame.length);
                        if (bitmap != null) {
                            final Bitmap rotatedBitmap = rotateBitmap(bitmap, -90);
                            frameEvent.onNewFrame(rotatedBitmap);
                        }

                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


    }

当前缓冲区reader正在读取不同大小的数据块,因此生成的位图如下:

由于缓冲的reader没有阻塞,等待所有缓冲都被填满,图像的黑色部分还没有被接收。

currently the buffer reader is reading chunks of data with different sizes

好的,这有什么问题吗?

由于各种原因,

read 并不总是读取您要求的所有数据。您需要继续阅读,直到阅读完所有您想阅读的数据。

所以问题是帧大小固定的错误假设,

逻辑是获取相机提供的第一个帧大小,然后将其发送到另一侧的不同控件 Chanel,然后根据该信息继续流的其余部分, 如果我不对图像进行有损压缩,那会起作用

yuv.compressToJpeg(new Rect(0, 0, frameWidth, frameHieght), 25, out);

导致不同的帧大小,在@Oleg 评论的帮助下 post如何读取服务器套接字中的所有输入流JAVA

代码如下所示, 发送:

public void process(@NonNull Frame frame) {
            byte[] data = frame.getData();
                frameWidth = frame.getSize().getWidth();
                frameHieght = frame.getSize().getHeight();

                YuvImage yuv = new YuvImage(data, frame.getFormat(), frameWidth, frameHieght, null);
                ByteArrayOutputStream out = new ByteArrayOutputStream();
                yuv.compressToJpeg(new Rect(0, 0, frameWidth, frameHieght), 25, out);
                final byte[] bytes = out.toByteArray();
                frameByteSize = bytes.length;

                if (StreamHandler != null) {
                    OutputStream outputStream = StreamHandler.getOutputStream();
                    if (out != null) {
                        try {
                            byte firstByte = (byte) ((bytes.length & 0xff00) >> 8);
                            byte secondByte = (byte) (bytes.length & 0xFF);
                            outputStream.write(firstByte);
                            outputStream.write(secondByte);
                            outputStream.write(bytes, 0, frameByteSize);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }

                }

            }
        }

正在接收:

public void run() {
        int read = 0;
        int hold = 0;
        int frameSize = StreamHandler.getFrameByteSize();
        try {
            if (StreamHandler != null) {
                InputStream inputStream = SrtreamHandler.getInputStream();
                if (inputStream != null) {
                    DataInputStream dataInputStream = new DataInputStream(inputStream);
                    byte[] frameInfo = new byte[2];
                    while (microPhoneActive) {
                        frameInfo[0] = dataInputStream.readByte();
                        frameInfo[1] = dataInputStream.readByte();
                        ByteBuffer byteBuffer = ByteBuffer.wrap(frameInfo, 0, 2);
                        int bytesToRead = byteBuffer.getShort();
                        byte[] frame = new byte[bytesToRead];
                        dataInputStream.readFully(frame, 0, bytesToRead);
                        Bitmap bitmap = BitmapFactory.decodeByteArray(frame, 0, frame.length);
                        if (bitmap != null) {
                            final Bitmap rotatedBitmap = rotateBitmap(bitmap, -90);
                            frameEvent.onNewFrame(rotatedBitmap);
                        }

                    }
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        }


    }