Использование MediaMuxer вместо FileOutputStream для сохранения кадров в файл mp4

Я использую следующий пример для записи видео из буфера (из onPreviewFrame(byte[] data,...). Но он сохраняет видео с помощью Output Stream. Я хотел бы перейти на MediaMuxer. Также при использовании этого образца финальное видео воспроизводится с очень высокой скоростью в видеоплеере. Я просто не уверен, какое время устанавливать 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);

}

0 ответов

About fast playing - try to use 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. Измени свой

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() your muxer finally. Это должно работать

Другие вопросы по тегам