簡體   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