转自:
一、h264_demuxer过程中用到的几个函数
ffmpeg h264探测输入格式:
调用av_open_input_file(&pFormatCtx,is->filename,NULL,0,NULL)函数打开输入的文件.
1.分析一下函数原型:
intav_open_input_file(AVFormatContext**ic_ptr,// 输出参数: 格式上下文
constchar*filename,// 文件名
AVInputFormat*fmt,// 输入的格式, 为NULL, 即未知
intbuf_size,// 缓冲的大小, 为0
AVFormatParameters*ap);// 格式的参数, 为NULL
2.初始化探测数据:
AVProbeData probe_data,*pd=&probe_data;
pd->filename="";
if(filename)
pd->filename=filename;
pd->buf=NULL;
pd->buf_size=0;
3.探测输入的格式:
if(!fmt){// fmt == NULL, 成立
fmt=av_probe_input_format(pd,0);
}
进入av_probe_input_format函数:
AVInputFormat*av_probe_input_format(AVProbeData*pd,intis_opened){
intscore=0;
returnav_probe_input_format2(pd,is_opened,&score);
}
进入av_probe_input_format2函数:
AVInputFormat*av_probe_input_format2(AVProbeData*pd,intis_opened,int*score_max)
{
AVInputFormat*fmt1,*fmt;
intscore;
fmt=NULL;
for(fmt1=first_iformat;fmt1!=NULL;fmt1=fmt1->next){
if(!is_opened==!(fmt1->flags&AVFMT_NOFILE))// is_opened == 0, fmt1->flags 没有设置 AVFMT_NOFILE 标志时成立
continue;
/* 省略部分代码 */
}
见libavformat/raw.c文件:
AVInputFormat h264_demuxer={
"h264",
NULL_IF_CONFIG_SMALL("raw H.264 video format"),
0,
h264_probe,
video_read_header,
ff_raw_read_partial_packet,
.flags=AVFMT_GENERIC_INDEX,
.extensions="h26l,h264,264",//FIXME remove after writing mpeg4_probe
.value=CODEC_ID_H264,
};
由于 h264_demuxer.flags==AVFMT_GENERIC_INDEX,所以上面成立,continue,返回的 AVInputFormat 指针为NULL, 探测不成功.
AVInputFormat h264_demuxer= {
"h264",
NULL_IF_CONFIG_SMALL("raw H.264 video format"),
0,
h264_probe,
video_read_header,
ff_raw_read_partial_packet,
.flags=AVFMT_GENERIC_INDEX,
.extensions= "h26l,h264,264", //FIXME remove after writing mpeg4_probe
.value=CODEC_ID_H264,
};
总结:H264文件的基本过程。
//av_open_input_file、av_probe_input_format(h264_probe)、video_read_header、 ff_raw_read_partial_packet
二、H.264_probe函数的过程:
static int h264_probe(AVProbeData *p)
{
uint32_t code= -1;
int sps=0, pps=0, idr=0, res=0, sli=0;
int i;
for(i=0; i<p->buf_size; i++){
code = (code<<8) + p->buf[i];
if ((code & 0xffffff00) == 0x100) {
int ref_idc= (code>>5)&3;
int type = code & 0x1F;
static const int8_t ref_zero[32]={
2, 0, 0, 0, 0,-1, 1,-1,
-1, 1, 1, 1, 1,-1, 2, 2,
2, 2, 2, 0, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2
};
if(code & 0x80) //forbidden bit
return 0;
if(ref_zero[type] == 1 && ref_idc)
return 0;
if(ref_zero[type] ==-1 && !ref_idc)
return 0;
if(ref_zero[type] == 2)
res++;
switch(type){
case 1: sli++; break;
case 5: idr++; break;
case 7:
if(p->buf[i+2]&0x0F)
return 0;
sps++;
break;
case 8: pps++; break;
}
}
}
if(sps && pps && (idr||sli>3) && res<(sps+pps+idr))
return AVPROBE_SCORE_MAX/2+1; // +1 for .mpg
return 0;
}
#endif
2、video_read_header()函数
static int video_read_header(AVFormatContext *s,
AVFormatParameters *ap)
{
AVStream *st;
st = av_new_stream(s, 0);
if (!st)
return AVERROR(ENOMEM);
st->codec->codec_type = CODEC_TYPE_VIDEO;
st->codec->codec_id = s->iformat->value;
st->need_parsing = AVSTREAM_PARSE_FULL;
/* for MJPEG, specify frame rate */
/* for MPEG-4 specify it, too (most MPEG-4 streams do not have the fixed_vop_rate set ...)*/
if (ap->time_base.num) {
st->codec->time_base= ap->time_base;
} else if ( st->codec->codec_id == CODEC_ID_MJPEG ||
st->codec->codec_id == CODEC_ID_MPEG4 ||
st->codec->codec_id == CODEC_ID_DIRAC ||
st->codec->codec_id == CODEC_ID_H264) {
st->codec->time_base= (AVRational){1,25};
}
av_set_pts_info(st, 64, 1, 1200000);
return 0;
}
#endif
3、
int ff_raw_read_partial_packet(AVFormatContext *s, AVPacket *pkt)
{
int ret, size;
size = RAW_PACKET_SIZE;
if (av_new_packet(pkt, size) < 0)
return AVERROR(EIO);
pkt->pos= url_ftell(s->pb);
pkt->stream_index = 0;
ret = get_partial_buffer(s->pb, pkt->data, size);
if (ret <= 0) {
av_free_packet(pkt);
return AVERROR(EIO);
}
pkt->size = ret;
return ret;
}
#endif