简体   繁体   English

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

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

I use next sample to record video from buffer (from onPreviewFrame(byte[] data,... ). But it saves video using Output Stream. I would like to change to MediaMuxer. Also when using this sample the final video is being played with very high speed in video player. I'm just not sure what time to set for encoder.queueInputBuffer(inputBufIndex, 0, 0, ptsUsec, MediaCodec.BUFFER_FLAG_END_OF_STREAM); I use long ptsUsec = (System.currentTimeMillis() * 1000) / FRAME_RATE; 我使用下一个示例来记录来自缓冲区的视频(来自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);

}

About fast playing - try to use System.nanoTime() / 1000L instead of (System.currentTimeMillis() * 1000) / FRAME_RATE 关于快速播放-尝试使用System.nanoTime() / 1000L而不是(System.currentTimeMillis() * 1000) / FRAME_RATE

to use muxer you have to initialize it outside of your encode/decode process and feed it with sample data in decode part. 要使用多路复用器,您必须在编码/解码过程之外对其进行初始化,并在解码部分将其与样本数据一起提供。 Change your 改变你的

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

to

//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);

don't forget to stop() and release() your muxer finally. 别忘了最终stop()然后release()多路复用器。 That should work 那应该工作

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

相关问题 Android使用mediamuxer mediacodec和mediaextractor(没有mp4parser)合并mp4和aac文件 - Android merging mp4 and aac file using mediamuxer mediacodec and mediaextractor (without mp4parser) 使用MediaMuxer和MediaCodec将wmv视频文件转换为mp4视频文件 - Converting wmv video file to mp4 video file using MediaMuxer and MediaCodec 在没有MediaMuxer的情况下将PCM转换为AAC或MP4文件 - Convert PCM to AAC or MP4 file without MediaMuxer Android_无法播放MediaMuxer生成的mp4文件 - Android_Can't play the mp4 file generated by MediaMuxer 如何修复由 MediaMuxer 生成的损坏的 Mp4 文件? - How to repair Corrupted Mp4 file generated by MediaMuxer? camera2 api -&gt; mediaCodec -&gt; mediaMuxer -&gt; mp4 文件 - camera2 api -> mediaCodec -> mediaMuxer -> mp4 file 使用 android 的 MediaMuxer 连接多个 mp4 音频文件 - Concatenate multiple mp4 audio files using android´s MediaMuxer 使用MediaMuxer编码MP4文件,但在调用mediaMuxer.stop()时崩溃 - Use MediaMuxer to encode a MP4 file but it crashes when calling mediaMuxer.stop() 如何使用ExtractMpegFrames.java将mp4中的帧正确保存为png文件? - How to properly save frames from mp4 as png files using ExtractMpegFrames.java? mp4文件使用mediacodec和mediamuxer时的音频和视频轨道同步问题 - audio and video track synchronization issue when using mediacodec and mediamuxer for mp4 files
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM