繁体   English   中英

使用MediaMuxer而不是FileOutputStream将帧保存到mp4文件中

[英]Using MediaMuxer instead of FileOutputStream to save frames into mp4 file

我使用下一个示例来记录来自缓冲区的视频(来自onPreviewFrame(byte[] data,... )。但是它使用Output Stream保存视频。我想更改为MediaMuxer。同样,使用此示例时,正在播放最终视频在视频播放器中具有很高的速度。我只是不确定要为encoder.queueInputBuffer(inputBufIndex, 0, 0, ptsUsec, MediaCodec.BUFFER_FLAG_END_OF_STREAM);设置什么时间encoder.queueInputBuffer(inputBufIndex, 0, 0, ptsUsec, MediaCodec.BUFFER_FLAG_END_OF_STREAM);我使用的是long ptsUsec = (System.currentTimeMillis() * 1000) / FRAME_RATE;

private void encodeVideoFrameFromBuffer(byte[] frameData) {
    if (encoder == null) return;
    final int TIMEOUT_USEC = 10000;
    ByteBuffer[] encoderInputBuffers = encoder.getInputBuffers();
    ByteBuffer[] encoderOutputBuffers = encoder.getOutputBuffers();
    MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();

    if (!outputDone && outputStream == null) {
        String fileName = Environment.getExternalStorageDirectory() + File.separator + "test" + 1280 + "x" + 720 + ".mp4";
        File file = new File(fileName);
        if (file.exists()) {
            file.delete();
        }
        try {
            outputStream = new FileOutputStream(fileName);
            Log.d(TAG, "encoded output will be saved as " + fileName);
        } catch (IOException ioe) {
            Log.w(TAG, "Unable to create debug output file " + fileName);
            throw new RuntimeException(ioe);

        }
    }
    if (outputStream != null) {
        int inputBufIndex = encoder.dequeueInputBuffer(TIMEOUT_USEC);

        if (inputBufIndex >= 0) {
            long ptsUsec = (System.currentTimeMillis() * 1000) / FRAME_RATE;
            if (outputDone) {
                encoder.queueInputBuffer(inputBufIndex, 0, 0, ptsUsec,
                        MediaCodec.BUFFER_FLAG_END_OF_STREAM);
            } else {
                ByteBuffer inputBuf = encoderInputBuffers[inputBufIndex];

                inputBuf.clear();
                inputBuf.put(frameData);
                encoder.queueInputBuffer(inputBufIndex, 0, frameData.length, ptsUsec, 0);

            }
            generateIndex++;
        }


        int encoderStatus = encoder.dequeueOutputBuffer(info, TIMEOUT_USEC);
        if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
            // no output available yet

        } else if (encoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
            // not expected for an encoder
            encoderOutputBuffers = encoder.getOutputBuffers();
            Log.d(TAG, "encoder output buffers changed");
        } else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
            MediaFormat newFormat = encoder.getOutputFormat();
            Log.d(TAG, "encoder output format changed: " + newFormat);
        } else if (encoderStatus < 0) {
            Log.e(TAG, "unexpected result from encoder.dequeueOutputBuffer: " + encoderStatus);
        } else { // encoderStatus >= 0
            ByteBuffer encodedData = encoderOutputBuffers[encoderStatus];
            encodedData.position(info.offset);
            encodedData.limit(info.offset + info.size);

            byte[] data = new byte[info.size];
            encodedData.get(data);
            encodedData.position(info.offset);
            try {
                outputStream.write(data);
            } catch (IOException ioe) {
                Log.w(TAG, "failed writing debug data to file");
                throw new RuntimeException(ioe);
            }

            encoder.releaseOutputBuffer(encoderStatus, false);
        }
    }

    if (outputDone) {
        if (outputStream != null) {


            try {
                outputStream.close();
            } catch (IOException ioe) {
                Log.w(TAG, "failed closing debug file");
                throw new RuntimeException(ioe);
            }
            outputStream = null;
            stopEncoder();
        }
    }
}

@Override
public void onPreviewFrame(byte[] data, Camera camera) {
    doEncodeDecodeVideoFromBuffer(data);

}

关于快速播放-尝试使用System.nanoTime() / 1000L而不是(System.currentTimeMillis() * 1000) / FRAME_RATE

要使用多路复用器,您必须在编码/解码过程之外对其进行初始化,并在解码部分将其与样本数据一起提供。 改变你的

try {
    outputStream.write(data);
} catch (IOException ioe) {
    Log.w(TAG, "failed writing debug data to file");
    throw new RuntimeException(ioe);
}

//somewhere outside encode/decode part
MediaCodec.BufferInfo videoInfo = new MediaCodec.BufferInfo();
muxer = new MediaMuxer(/*your file*/,
                MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
int videoTrack = muxer.addTrack(encoder.getOutputFormat());
muxer.start();

//try-catch block replacement
muxer.writeSampleData(videoTrack, data, videoInfo);

别忘了最终stop()然后release()多路复用器。 那应该工作

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM