十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
AVInputFormat结构体
AVInputFormat 每种码流输入格式(例如h364,FLV, MKV, MP4, AVI)对应一个结构体,用来保存视音频的解码参数,目前以h364码流格式为例,描述结构体成员:
name:封装格式名称简写(short_name)[h364]
long_name:码流输入格式的长名称[raw H.264 video]
extensions:码流输入格式的扩展名[h36l,h364,264,avc]
raw_codec_id:码流输入格式ID[28]
read_packet:avformat-57.dll!0x000007fee101ca90 (加载符号以获取其他信息)
read_header:avformat-57.dll!0x000007fee101cb70 (加载符号以获取其他信息)
关键函数:int (*read_packet)(struct AVFormatContext *, AVPacket *pkt);
read_packet函数读取一个AVPacket,然后放在pkt,这个函数在进行分帧
av_read_frame函数的里面会被调用到,调用相应的×××获取一帧的完整数据
问题:各种码流输入格式是什么时候被加载的?
回答:当第一次调用av_register_all的时候就会注册复用器,其中就包含了各种码流的输入格式的处理函数
查看调用关系
av_register_all
register_all
REGISTER_MUXDEMUX(H264, h364);
#define REGISTER_MUXDEMUX(X, x) REGISTER_MUXER(X, x); REGISTER_DEMUXER(X, x)
#define REGISTER_MUXER(X, x) \
{ \
extern AVOutputFormat ff_##x##_muxer; \
if (CONFIG_##X##_MUXER) \
av_register_output_format(&ff_##x##_muxer); \
}
#define REGISTER_DEMUXER(X, x) \
{ \
extern AVInputFormat ff_##x##_demuxer; \
if (CONFIG_##X##_DEMUXER) \
av_register_input_format(&ff_##x##_demuxer); \
}
看看注册码流输入格式的函数
void av_register_input_format(AVInputFormat *format)
{
AVInputFormat **p = last_iformat;
// Note, format could be added after the first 2 checks but that implies that *p is no longer NULL
while(p != &format->next && !format->next && avpriv_atomic_ptr_cas((void * volatile *)p, NULL, format))
p = &(*p)->next;
if (!format->next)
last_iformat = &format->next;
}
其中关键的全局变量是
static AVInputFormat *first_iformat = NULL;
static AVInputFormat **last_iformat = &first_iformat;
保存了所有码流格式
AVInputFormat *av_iformat_next(const AVInputFormat *f)
{
if (f)
return f->next;
else
return first_iformat;
}
AVInputFormat *av_find_input_format(const char *short_name)
{
AVInputFormat *fmt = NULL;
while ((fmt = av_iformat_next(fmt)))//获取×××的链表指针,
if (av_match_name(short_name, fmt->name))//根据输入的码流格式简写,轮询链表查找×××
return fmt;
return NULL;
}
在avformat_open_input函数优化篇就直接指定码流的输入格式,从而减少了探测码流格式的时间
参考
http://blog.csdn.net/leixiaohua1020/article/details/12677129
http://blog.csdn.net/neustar1/article/details/38231937
创新互联是一家集网站建设,南湖企业网站建设,南湖品牌网站建设,网站定制,南湖网站建设报价,网络营销,网络优化,南湖网站推广为一体的创新建站企业,帮助传统企业提升企业形象加强企业竞争力。可充分满足这一群体相比中小企业更为丰富、高端、多元的互联网需求。同时我们时刻保持专业、时尚、前沿,时刻以成就客户成长自我,坚持不断学习、思考、沉淀、净化自己,让我们为更多的企业打造出实用型网站。
AVFMT_NOFILE宏定义剖析
使用说明
当前为了避免在调用init_input函数的时候,读取缓存区的数据,从而设置了该标志位,但是最终在avformat_open_input的其他地方还是读取了缓冲区的数据
pAVInputFormat = av_find_input_format("h364");
pAVInputFormat->flags |= AVFMT_NOFILE;
宏定义
/// Demuxer will use avio_open, no opened file should be provided by the caller.
//解复用器将调用avio_open函数,调用者提供一个没有打开的文件,估计是打开的文件会被占用
#define AVFMT_NOFILE 0x0001
#define AVFMT_NEEDNUMBER 0x0002 /**< Needs '%d' in filename. */
#define AVFMT_SHOW_IDS 0x0008 /**< Show format stream IDs numbers. */
AVFMT_NOFILE formats will not have a AVIOContext
当设置了AVFMT_NOFILE标志,将不会携带AVIOContext
/* Open input file and probe the format if necessary. */
static int init_input(AVFormatContext *s, const char *filename,
AVDictionary **options)
{
int ret;
AVProbeData pd = { filename, NULL, 0 };
int score = AVPROBE_SCORE_RETRY;
//这里探测码流的方式,企图通过AVIOContext结构体中的read_packet函数
//如果码流格式已经指定并且指定了标志位,直接返回
if (s->pb) {
s->flags |= AVFMT_FLAG_CUSTOM_IO;
//如果没有指定输入格式,开始探测码流格式
if (!s->iformat)
return av_probe_input_buffer2(s->pb, &s->iformat, filename,
s, 0, s->format_probesize);
else if (s->iformat->flags & AVFMT_NOFILE)
av_log(s, AV_LOG_WARNING, "Custom AVIOContext makes no sense and "
"will be ignored with AVFMT_NOFILE format.\n");
return 0;
}
//这里探测码流的方式,企图通过通过进来的文件名称
//如果码流格式已经指定并且指定了标志位,直接返回
//这里非常明显网络RTSP流,肯定是不会走到这里
if ((s->iformat && s->iformat->flags & AVFMT_NOFILE) ||
(!s->iformat && (s->iformat = av_probe_input_format2(&pd, 0, &score))))
return score;
//如果指定了iformat结构体,并且没有设置标志位,肯定执行下面的语句,该语句会调用read_packet函数
//进行分析码流
if ((ret = s->io_open(s, &s->pb, filename, AVIO_FLAG_READ | s->avio_flags, options)) < 0)
return ret;
if (s->iformat)
return 0;
return av_probe_input_buffer2(s->pb, &s->iformat, filename,
s, 0, s->format_probesize);
}
从下面的说明可以得知,当添加了AVFMT_NOFILE标志位,AVIOContext *pb会设置为空
/**
* I/O context.
*
* - demuxing: either set by the user before avformat_open_input() (then
* the user must close it manually) or set by avformat_open_input().
* - muxing: set by the user before avformat_write_header(). The caller must
* take care of closing / freeing the IO context.
*
* Do NOT set this field if AVFMT_NOFILE flag is set in
* iformat/oformat.flags. In such a case, the (de)muxer will handle
* I/O in some other way and this field will be NULL.
*/
AVIOContext *pb;
/**
* Custom interrupt callbacks for the I/O layer.
*
* demuxing: set by the user before avformat_open_input().
* muxing: set by the user before avformat_write_header()
* (mainly useful for AVFMT_NOFILE formats). The callback
* should also be passed to avio_open2() if it's used to
* open the file.
*/
AVIOInterruptCB interrupt_callback;
/**
* Guess the file format.
*
* @param pd data to be probed
* @param is_opened Whether the file is already opened; determines whether
* demuxers with or without AVFMT_NOFILE are probed.
*/
AVInputFormat *av_probe_input_format(AVProbeData *pd, int is_opened);
AVInputFormat *av_probe_input_format2(AVProbeData *pd, int is_opened, int *score_max);
AVInputFormat *av_probe_input_format3(AVProbeData *pd, int is_opened, int *score_ret);