首页 > 解决方案 > 如何将原始 h.264 文件转换为 mp4

问题描述

我看到了如何使用 MediaCodec 将视频转换为 mp4。这些示例使用的是 Surface。

然后我认为h.264 => decode => Surface => encode(file),这是一个不必要的encode/decode过程。

是否可以使用 android MediaCodec / MediaMuxer 在不编码/解码的情况下制作原始 h.264 文件 mp4?

更新

我实现了一些代码引用链接(https://developer.android.com/reference/android/media/MediaMuxer)的评论。

        while(!finished) {
            // getInputBuffer() will fill the inputBuffer with one frame of encoded
            // sample from either MediaCodec or MediaExtractor, set isAudioSample to
            // true when the sample is audio data, set up all the fields of bufferInfo,
            // and return true if there are no more samples.
            byte[] tempBuffer = new byte[1000000];
            try {
                inputBuffer.clear();
                int bytesRead = videoFis.read(tempBuffer, 0, inputBuffer.limit());
                if(bytesRead <= -1) {
                    break;
                }
                else {
                    inputBuffer.put(tempBuffer, 0, bytesRead);
                    int currentTrackIndex = videoTrackIndex; // isAudioSample ? audioTrackIndex : videoTrackIndex;
                    muxer.writeSampleData(currentTrackIndex, inputBuffer, bufferInfo);

                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

上面的代码不起作用。我没有得到一帧编码。

// getInputBuffer() will fill the inputBuffer with one frame of encoded
// sample from either MediaCodec or MediaExtractor

为了从原始 h.264 编码一帧,我应该使用 MediaCodec 吗?

更新2

                bb.mark();
        // read all
        while(true) {
            try {
                int bb2 = videoFis.read(tempBuffer, 0, tempBuffer.length);
                if(bb2 != -1) {
                    bb.put(tempBuffer, 0, bb2);
                }
                else {
                    break;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        bb.reset();

        int mata[][] = new int[5][256];
        mata[0][0] = 1;
        mata[1][0] = 2;
        mata[2][0] = 3;
        mata[3][1] = 4;
        int step = 0;
        // find first key frame.
        while(bb.hasRemaining()) {
            step = mata[step][(bb.get() & 0xFF)];
            if(step < 4) {
                step = mata[step][(bb.get() & 0xFF)];
            }
            else if(step == 4) {
                byte g = bb.get();
                if((g & 0x1f) == 5) {
                    bb.position(bb.position() - 5);
                    break;
                }
            }
        }
        step = 0;
        while(!finished) {
            int nextPosition = -1;
            int offset = bb.position();
            bb.get(); bb.get(); bb.get(); bb.get();
            byte nalUnit = bb.get();
            while(bb.hasRemaining()) {
                if(step < 4) {
                    step = mata[step][(bb.get() & 0xFF)];
                }
                else if(step == 4) {
                    byte g = bb.get();
                    if((g & 0x60) != 0) {
                        nextPosition = bb.position() - 5;
                        break;
                    }
                }
            }
            step = 0;
            bufferInfo.flags = (nalUnit & 0x1f) == 5 ? MediaCodec.BUFFER_FLAG_KEY_FRAME : 0;
            bufferInfo.offset = offset;
            bufferInfo.size = nextPosition - offset;
            bufferInfo.presentationTimeUs += 1000 * 1000 / 15;
            Log.d(",,", "offset: " + bufferInfo.offset + "..." + "size: " + bufferInfo.size + "..." + "pts: " + bufferInfo.presentationTimeUs);
            muxer.writeSampleData(videoTrackIndex, inputBuffer, bufferInfo);
            bb.position(nextPosition);
            if(bufferInfo.presentationTimeUs >= 666660)
            {
                bufferInfo.size = 0;
                break;
            }
        }
        muxer.stop();
        muxer.release();

像上面的实现一样,我发现 0x00 0x00 0x00 0x01 称为 NAL,我用偏移量、大小、pts 填充了 bufferInfo。但我收到了消息

...
02-23 17:59:25.131 7597-7738/com.example.ksoo.ballbotpkg I/MPEG4Writer: setStartTimestampUs: 66666
    Earliest track starting time: 66666
02-23 17:59:25.131 7597-7597/com.example.ksoo.ballbotpkg D/,,: offset: 284939...size: 10531...pts: 133332
02-23 17:59:25.132 7597-7597/com.example.ksoo.ballbotpkg D/,,: offset: 295470...size: 15908...pts: 199998
    offset: 311378...size: 20194...pts: 266664
02-23 17:59:25.133 7597-7597/com.example.ksoo.ballbotpkg D/,,: offset: 331572...size: 20628...pts: 333330
    offset: 352200...size: 21346...pts: 399996
02-23 17:59:25.134 7597-7597/com.example.ksoo.ballbotpkg D/,,: offset: 373546...size: 21407...pts: 466662
02-23 17:59:25.134 7597-7597/com.example.ksoo.ballbotpkg D/,,: offset: 394953...size: 22494...pts: 533328
02-23 17:59:25.135 7597-7597/com.example.ksoo.ballbotpkg D/,,: offset: 417447...size: 23230...pts: 599994
02-23 17:59:25.135 7597-7597/com.example.ksoo.ballbotpkg D/,,: offset: 440677...size: 23820...pts: 666660
02-23 17:59:25.136 7597-7597/com.example.ksoo.ballbotpkg I/MPEG4Writer: Normal stop process
02-23 17:59:25.136 7597-7597/com.example.ksoo.ballbotpkg D/MPEG4Writer: Video track stopping. Stop source
    Video track source stopping
    Video track source stopped
02-23 17:59:25.136 7597-7738/com.example.ksoo.ballbotpkg I/MPEG4Writer: Received total/0-length (10/0) buffers and encoded 10 frames. - Video
02-23 17:59:25.136 7597-7597/com.example.ksoo.ballbotpkg D/MPEG4Writer: Video track stopped. Stop source
    Stopping writer thread
02-23 17:59:25.137 7597-7737/com.example.ksoo.ballbotpkg D/MPEG4Writer: 0 chunks are written in the last batch
02-23 17:59:25.137 7597-7597/com.example.ksoo.ballbotpkg D/MPEG4Writer: Writer thread stopped
02-23 17:59:25.138 7597-7597/com.example.ksoo.ballbotpkg I/MPEG4Writer: The mp4 file will not be streamable.
02-23 17:59:25.138 7597-7597/com.example.ksoo.ballbotpkg D/MPEG4Writer: Video track stopping. Stop source

我犯错了吗?

标签: androidh.264android-mediacodecmediamuxer

解决方案


推荐阅读