效果:实现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;
}
暂无时间研究,有研究者希望跟帖大家共同进步!