首先要运行函数:
<span style="font-size:18px;">void avdevice_register_all(void)
{
static int initialized;
if (initialized)
return;
initialized = 1;
/* devices */
REGISTER_INOUTDEV(ALSA, alsa);
REGISTER_INDEV (AVFOUNDATION, avfoundation);
REGISTER_INDEV (BKTR, bktr);
REGISTER_OUTDEV (CACA, caca);
REGISTER_INOUTDEV(DECKLINK, decklink);
REGISTER_INDEV (DSHOW, dshow);
REGISTER_INDEV (DV1394, dv1394);
REGISTER_INOUTDEV(FBDEV, fbdev);
REGISTER_INDEV (GDIGRAB, gdigrab);
REGISTER_INDEV (IEC61883, iec61883);
REGISTER_INDEV (JACK, jack);
REGISTER_INDEV (LAVFI, lavfi);
REGISTER_INDEV (OPENAL, openal);
REGISTER_OUTDEV (OPENGL, opengl);
REGISTER_INOUTDEV(OSS, oss);
REGISTER_INOUTDEV(PULSE, pulse);
REGISTER_INDEV (QTKIT, qtkit);
REGISTER_OUTDEV (SDL, sdl);
REGISTER_INOUTDEV(SNDIO, sndio);
REGISTER_INOUTDEV(V4L2, v4l2);
// REGISTER_INDEV (V4L, v4l
REGISTER_INDEV (VFWCAP, vfwcap);
REGISTER_INDEV (X11GRAB, x11grab);
REGISTER_INDEV (X11GRAB_XCB, x11grab_xcb);
REGISTER_OUTDEV (XV, xv);
/* external libraries */
REGISTER_INDEV (LIBCDIO, libcdio);
REGISTER_INDEV (LIBDC1394, libdc1394);
</span>
这个函数里面调用了很多宏函数,注意这里开始是一个坑!巨坑。以v4l2为例。
<span style="font-size:18px;"> REGISTER_INOUTDEV(V4L2, v4l2);</span>
<span style="font-size:18px;">REGISTER_INOUTDEV</span>
的定义如下:
<span style="font-size:18px;">#define REGISTER_OUTDEV(X, x) \
{ \
extern AVOutputFormat ff_##x##_muxer; \
if (CONFIG_##X##_OUTDEV) \
av_register_output_format(&ff_##x##_muxer); \
}
#define REGISTER_INDEV(X, x) \
{ \
extern AVInputFormat ff_##x##_demuxer; \
if (CONFIG_##X##_INDEV) \
av_register_input_format(&ff_##x##_demuxer); \
}
#define REGISTER_INOUTDEV(X, x) REGISTER_OUTDEV(X, x); REGISTER_INDEV(X, x)</span>
一次性注册了x这种类型的输入和输出设备。
在这里,ff_##x##_demuxer 在进行宏替换的时候会变成,ff_v4l2_demuxer,
然后也就声明了extern AVInputFormat ff_v4l2_demuxer
最后av_register_input_format注册这个结构体,实际上是把这个设备描述的结构体添加到单向链表里面,后面av_find_input_format遍历这个链表查找需要的格式。
而实际上v4l2模块(v4l2.c)中的定义如下:
<span style="font-size:18px;">AVInputFormat ff_v4l2_demuxer = {
.name = "video4linux2,v4l2",
.long_name = NULL_IF_CONFIG_SMALL("Video4Linux2 device grab"),
.priv_data_size = sizeof(struct video_data),
.read_probe = v4l2_read_probe,
.read_header = v4l2_read_header,
.read_packet = v4l2_read_packet,
.read_close = v4l2_read_close,
.get_device_list = v4l2_get_device_list,
.flags = AVFMT_NOFILE,
.priv_class = &v4l2_class,
};
</span>
所以你在FFMPEG中搜索ff_v4l2_demuxer的被使用的地方,你作死都搜索不到!巨坑啊!
===================================================================================================
粗略的理解:
<span style="font-size:18px;">v4l2_read_header 初始化V4L2 设备和API</span>
v4l2_read_packet 读取数据缓冲区
v4l2_read_close 关闭设备