在android上解码/播放视频流并录制到文件的最佳实践

xbp102n0  于 2021-07-08  发布在  Java
关注(0)|答案(0)|浏览(281)

我正在编写一个应用程序,通过tcp连接收集h264流,并将其显示在屏幕上 TextureView 越快越好(也许越快越好)。它工作的很好,但我打赌它可以做得更好。现在我需要添加一个录音功能,我猜如何做到这一点,而不失去表演。这是我的密码:

public void run() {
        byte[] nal = new byte[NAL_SIZE_INC];
        int nalLen = 0;
        int numZeroes = 0;
        int numReadErrors = 0;
        int connection_retries = 0;

        try {
            decoder = MediaCodec.createDecoderByType("video/avc");

            byte[] buffer = new byte[BUFFER_SIZE];

            do {
                if(camera.getStreamingProtocol() == Protocol.UDP)
                    reader = new UdpListner(camera.getPort());
                else //if(camera.getStreamingProtocol() == Protocol.TCP)
                    reader = new TcpIpReader(camera.getAddress(), camera.getPort());

                connection_retries++;
                Thread.sleep(VIDEO_STREAM_RESPAWN);
            } while (!reader.isConnected() && (connection_retries < MAX_CONN_RETRIES));

            if (!reader.isConnected()) {
                //throw new Exception();
                Log.d(getClass().getName(), "Link respawn: " + connection_retries);
                return;
            }

            while (keep_running) {
                int len = reader.read(buffer);
                if (!keep_running) break;

                if (len > 0) {
                    numReadErrors = 0;
                    for (int i = 0; i < len && keep_running; i++) {
                        if (nalLen == nal.length) {
                            nal = Arrays.copyOf(nal, nal.length + NAL_SIZE_INC);
                        }
                        nal[nalLen++] = buffer[i];

                        if (buffer[i] == 0) {
                            numZeroes++;
                        } else {
                            if (buffer[i] == 1 && numZeroes == 3) {
                                if (nalLen > 4) {
                                    int nalType = processNal(nal, nalLen - 4);
                                    if (!keep_running) break;
                                    if (nalType == -1) {
                                        nal[0] = nal[1] = nal[2] = 0;
                                        nal[3] = 1;
                                    }
                                }
                                nalLen = 4;
                            }
                            numZeroes = 0;
                        }
                    }
                } else {
                    numReadErrors++;
                    if (numReadErrors >= MAX_READ_ERRORS) {
                        setVideoMessage(R.string.error_lost_connection);
                        break;
                    }
                }

                if (format != null && decoding) {
                    if (!keep_running) break;
                    MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
                    int index;
                    do {
                        index = decoder.dequeueOutputBuffer(info, 0);
                        if (!keep_running) break;
                        if (index >= 0) {
                            decoder.releaseOutputBuffer(index, true);
                        }
                    } while (index >= 0);
                }
            }
        } catch (Exception ex) {
            Log.e(getClass().getName(), "Exception: " + ex.toString());
            if (reader == null || !reader.isConnected()) {
                setVideoMessage(R.string.error_couldnt_connect);
                finishHandler.postDelayed(finishRunner, FINISH_TIMEOUT);
            } else {
                setVideoMessage(R.string.error_lost_connection);
            }
            ex.printStackTrace();
        }

        if (reader != null) {
            try {
                reader.close();
            } catch (Exception ex) {
                Log.i(getClass().getName(), "Exception: " + ex.getMessage());
            }
            reader = null;
        }

        if (decoder != null) {
            try {
                setDecodingState(false);
                decoder.release();
            } catch (Exception ex) {
                Log.e(getClass().getName(), "Exception: " + ex.getMessage());
            }
            decoder = null;
        }
    }

这当然是 run() a方法 Thread 在上管理作业的派生对象 Fragment 显示视频。
创建一个简单的缓冲输出流,并在每个缓冲输出流上进行写入 buffer 从传入流收集的数据应该可以正常工作,否则可能会延迟视频渲染?
我必须添加头数据到h264输出文件,使其可读?
有没有办法优化接收/显示部分?我愿意接受任何建议。。。我想用udp代替tcp。
祝你好运,迈克

暂无答案!

目前还没有任何答案,快来回答吧!

相关问题