视频采集到录制 - MP4生成

文章讲述了如何利用MP4v2库将H264编码的视频流和AAC编码的音频流合并成一个MP4文件。过程中涉及到视频和音频轨道的初始化,参数设置,如音频的采样率和通道数,以及视频的SPS和PPS帧处理。时间戳的正确设置对于保证音视频同步至关重要。
摘要由CSDN通过智能技术生成

录制最终格式是MP4,视频流是采用H264编码流,音频是aac编码流

最终需要将两个流合并到一个文件里

采用的方案,是通过mp4v2的库,进行合并

原理很简单:

先创建文件,输入编码参数

        需要创建视频流初始

        也需要创建音频流初始化

//创建MP4文件

mFileHandle = CreateMP4File(file,90000);   记住handle

//创建音频通道

MP4TrackId audio = MP4AddAudioTrack(mFileHandle, VOICE_RATE, 1024, MP4_MPEG4_AUDIO_TYPE);

//创建视频通道

mVideoId = MP4AddH264VideoTrack( mFileHandle,
                mTimeScale,
                mTimeScale / mFrameRate,
                mWidth,
                mHeight,
                nalu.data[1], /* sps[1] AVCProfileIndication */
                nalu.data[2], /* sps[2] profile_compat */
                nalu.data[3], /* sps[3] AVCLevelIndication */
                3);  

然后按每帧内容存储至文件

看似简单,实际也有很多

1. 音频初始化参数设置

GetDecoderSpecificInfo

注意,他的参数含义,网上很多例子都是44.1k,因此,而参数里如果不细究,这个就会被忽略

auto config = GetDecoderSpecificInfo(2, 3, 2);

/*

参数1:AAC_LC-2;  这个表示音频编码

参数2:   48000-3,44100-4;

参数3:   2 channels : front - left, front - right

*/

/*添加aac音频*/
        MP4TrackId audio = MP4AddAudioTrack(mFileHandle, VOICE_RATE, 1024, MP4_MPEG4_AUDIO_TYPE);
        if (audio == MP4_INVALID_TRACK_ID)
        {           
            errorf("add audio track failed.\n");
            return false;
        }

        mVoiceId = audio;
        MP4SetAudioProfileLevel(mFileHandle, 0x2);

        /*P1:AAC_LC-2; P2:48000-3,44100-4; P3:2 channels : front - left, front - right*/
        auto config = GetDecoderSpecificInfo(2, 3, 2);
        if(!MP4SetTrackESConfiguration(mFileHandle, audio, (uint8_t*) &config, 2))
        {
            errorf("set audio config failed=2 4 2\n");
        }

2. 视频初始化

        视频编码库编码之后,会产生不同帧,需要解析nalu,不能直接存储

        收到sps帧,需要对视频通道进行初始化

mVideoId = MP4AddH264VideoTrack( mFileHandle,
                mTimeScale,
                mTimeScale / mFrameRate,
                mWidth,
                mHeight,
                nalu.data[1], /* sps[1] AVCProfileIndication */
                nalu.data[2], /* sps[2] profile_compat */
                nalu.data[3], /* sps[3] AVCLevelIndication */
                3);           /* 4 bytes length before each NAL unit */


            if (mVideoId == MP4_INVALID_TRACK_ID)
            {
                errorf("add video track failed.\n");
                return 0;
            }

            MP4SetVideoProfileLevel(mFileHandle, 0x7f); /*  main Profile @ Level 4 */
            MP4AddH264SequenceParameterSet(mFileHandle,mVideoId,nalu.data+4,nalu.size);

        收到pps帧,需要设置参数

        

MP4AddH264PictureParameterSet(mFileHandle,mVideoId,nalu.data+4,nalu.size);

另外需要注意是同步帧信息

3. 时间戳概念

        往往新手会忘记时间戳,但这个是神器,必须好好理解

        比如说:视频设置是25帧/秒,如果实际采集只有20帧,或者在变化(一会20,一会25)类似这样。如果不设置时间戳,那么回放的时候会很奇怪,视频一会快一会慢(当然相差不大,裸眼很难分辨出来),但回放时间很真实,例如明明录制了30分钟,但实际回放的时候,只有29分钟。

        

        因此要设置时间戳,时间戳的原点是创建通道的,后面每写入一帧数据,带入时间戳(相对第一个点的时间偏移)

        音频也是

        音频跟视频是分开两个通道的,因此,时间戳也是分开累计,同理,视频跟音频同步,也是基于时间戳!!

        注意第5参数

if(!MP4WriteSample(mFileHandle, mVideoId, nalu.data, nalu.size+4, (now - mVideoTick) * 90, 0, isSync))
uint64_t timeStemp = (tickTime - mVoiceTick) * VOICE_RATE_STAMP;
    mVoiceTick = tickTime;

  
    if(!MP4WriteSample(mFileHandle, mVoiceId, buf, size, timeStemp, 0, 1))

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值