ffmpeg实现g711音频和H264,H265封装mp4(整理,非原创)

效果:实现G711和H264,H265存为mp4,录像文件VLC暴风影音可播放

注:播放mp4音视频没问题,但使用mp4分析工具分析 Sample size有问题(待解决)

修改1:

(资料来自:garefield ffmpeg添加MP4的pcm音频支持_garefield的专栏-CSDN博客

ffmpeg中对MP4的打包处理是在movenc.c中,在实际打包过程中发现除了mov类型外,其它类型如vob等均无法生成音频的声道信息,经过分析发现在mov_write_audio_tag函数的最后有如下代码

 if (track->mode == MODE_MOV && track->enc->codec_type == AVMEDIA_TYPE_AUDIO)

        mov_write_chan_tag(pb, track);

即只有MP4为mov类型的时候才会写入音频信息,因此这个判断需要修改为

 if ( track->enc->codec_type == AVMEDIA_TYPE_AUDIO)

        mov_write_chan_tag(pb, track);

即不论哪种MP4,均将声道信息写入。

为MP4编码添加pcm音频支持:

static const AVCodecTag codec_ipod_tags[] = {

    { AV_CODEC_ID_H264,     MKTAG('a','v','c','1') },

    { AV_CODEC_ID_MPEG4,    MKTAG('m','p','4','v') },

    { AV_CODEC_ID_AAC,      MKTAG('m','p','4','a') },

    { AV_CODEC_ID_PCM_MULAW,MKTAG('u','l','a','w') },

    { AV_CODEC_ID_PCM_ALAW, MKTAG('a','l','a','w') },

    { AV_CODEC_ID_ALAC,     MKTAG('a','l','a','c') },

    { AV_CODEC_ID_AC3,      MKTAG('a','c','-','3') },

    { AV_CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },

    { AV_CODEC_ID_MOV_TEXT, MKTAG('t','e','x','t') },

    { AV_CODEC_ID_NONE, 0 },

};

static const AVCodecTag codec_3gp_tags[] = {

    { AV_CODEC_ID_H263,     MKTAG('s','2','6','3') },

    { AV_CODEC_ID_H264,     MKTAG('a','v','c','1') },

    { AV_CODEC_ID_MPEG4,    MKTAG('m','p','4','v') },

    { AV_CODEC_ID_AAC,      MKTAG('m','p','4','a') },

    { AV_CODEC_ID_PCM_MULAW,MKTAG('u','l','a','w') },

    { AV_CODEC_ID_PCM_ALAW, MKTAG('a','l','a','w') },

    { AV_CODEC_ID_AMR_NB,   MKTAG('s','a','m','r') },

    { AV_CODEC_ID_AMR_WB,   MKTAG('s','a','w','b') },

    { AV_CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },

    { AV_CODEC_ID_NONE, 0 },

};

static const AVCodecTag codec_f4v_tags[] = { // XXX: add GIF/PNG/JPEG?

    { AV_CODEC_ID_MP3,    MKTAG('.','m','p','3') },

    { AV_CODEC_ID_AAC,    MKTAG('m','p','4','a') },

    { AV_CODEC_ID_PCM_MULAW,MKTAG('u','l','a','w') },

    { AV_CODEC_ID_PCM_ALAW,MKTAG('a','l','a','w') },

    { AV_CODEC_ID_H264,   MKTAG('a','v','c','1') },

    { AV_CODEC_ID_VP6A,   MKTAG('V','P','6','A') },

    { AV_CODEC_ID_VP6F,   MKTAG('V','P','6','F') },

    { AV_CODEC_ID_NONE, 0 },

};

以上红色部分是添加的针对pcm的格式信息,然后在mov_write_header函数中,还需要设置声道信息,将

 else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {

            track->timescale = st->codec->sample_rate;

改为

else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {

            if (st->codec->codec_id == AV_CODEC_ID_PCM_MULAW || st->codec->codec_id == AV_CODEC_ID_PCM_ALAW)

            {

                st->codec->channels = 1;

                st->codec->sample_rate = 8000;

                st->codec->channel_layout = AV_CH_LAYOUT_MONO;

                st->codec->sample_fmt = AV_SAMPLE_FMT_S16;

                track->enc->channels = 1;

                track->enc->channel_layout = AV_CH_LAYOUT_MONO;

            }

            track->timescale = st->codec->sample_rate;

红色部分是添加内容

此外,解码部分也要做修改,在mov_chan.c中,添加

static const enum MovChannelLayoutTag mov_ch_layouts_law[] = {

    MOV_CH_LAYOUT_MONO,

    MOV_CH_LAYOUT_STEREO,

    0,

};

以及修改mov_codec_ch_layouts的定义为

static const struct {

    enum AVCodecID codec_id;

    const enum MovChannelLayoutTag *layouts;

} mov_codec_ch_layouts[] = {

    { AV_CODEC_ID_AAC,     mov_ch_layouts_aac      },

    { AV_CODEC_ID_PCM_MULAW, mov_ch_layouts_law    },

    { AV_CODEC_ID_PCM_ALAW,  mov_ch_layouts_law    },

    { AV_CODEC_ID_AC3,     mov_ch_layouts_ac3      },

    { AV_CODEC_ID_ALAC,    mov_ch_layouts_alac     },

    { AV_CODEC_ID_PCM_U8,    mov_ch_layouts_wav    },

    { AV_CODEC_ID_PCM_S8,    mov_ch_layouts_wav    },

    { AV_CODEC_ID_PCM_S16LE, mov_ch_layouts_wav    },

    { AV_CODEC_ID_PCM_S16BE, mov_ch_layouts_wav    },

    { AV_CODEC_ID_PCM_S24LE, mov_ch_layouts_wav    },

    { AV_CODEC_ID_PCM_S24BE, mov_ch_layouts_wav    },

    { AV_CODEC_ID_PCM_S32LE, mov_ch_layouts_wav    },

    { AV_CODEC_ID_PCM_S32BE, mov_ch_layouts_wav    },

    { AV_CODEC_ID_PCM_F32LE, mov_ch_layouts_wav    },

    { AV_CODEC_ID_PCM_F32BE, mov_ch_layouts_wav    },

    { AV_CODEC_ID_PCM_F64LE, mov_ch_layouts_wav    },

    { AV_CODEC_ID_PCM_F64BE, mov_ch_layouts_wav    },

    { AV_CODEC_ID_NONE,    NULL                    },

};

这两部分内容是定义pam的声道模式,然后还要修改isom.c

在ff_mp4_obj_type中添加

    { AV_CODEC_ID_PCM_MULAW   , 0xE3 }, /* a private definition */

    { AV_CODEC_ID_PCM_ALAW  , 0xE4 }, /* a private definition */

这两个定义是pcm的流类型标志定义,参考自另一个MP4打包库mpeg4ip的MP4.h

修改2:

(资料来自:珠雨妮儿  C++编程-7:ffmpeg支持G711音频和H.264视频数据同步封装进MP4文件_zhuyunier的博客-CSDN博客

static int mov_write_audio_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)

中:

} else { /* reserved for mp4/3gp */
            avio_wb16(pb, 2);
            avio_wb16(pb, 16);

修改为:

avio_wb16(pb, track->par->channels > 0 ? 
                          track->par->channels : 1);
            track->par->bits_per_coded_sample = av_get_bits_per_sample(track->par->codec_id);
            avio_wb16(pb, track->par->bits_per_coded_sample > 0 ? 
                          track->par->bits_per_coded_sample : 16);

作用:默认的声音通道为2,sample 为16;这里将音频配置信息存为g711音频的配置。(否则VLC将解析错误音频)

static int mov_find_codec_tag(AVFormatContext *s, MOVTrack *track)
{
    int tag;

    if (track->mode == MODE_MP4 || track->mode == MODE_PSP)
        tag = mp4_get_codec_tag(s, track);
    else if (track->mode == MODE_ISM) {
        tag = mp4_get_codec_tag(s, track);
        if (!tag && track->par->codec_id == AV_CODEC_ID_WMAPRO)
            tag = MKTAG('w', 'm', 'a', ' ');
    } else if (track->mode == MODE_IPOD)
        tag = ipod_get_codec_tag(s, track);
    else if (track->mode & MODE_3GP)
        tag = ff_codec_get_tag(codec_3gp_tags, track->par->codec_id);
    else if (track->mode == MODE_F4V)
        tag = ff_codec_get_tag(codec_f4v_tags, track->par->codec_id);
    else
        tag = mov_get_codec_tag(s, track);
    if(tag ==0)
        tag = mov_get_codec_tag(s, track);

    return tag;
}
 


 

暂无时间研究,有研究者希望跟帖大家共同进步!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值