在FFmpeg源码(以5.0.3版本为例)目录下的libavformat/img2dec.c中存在如下宏定义
#define IMAGEAUTO_DEMUXER(imgname, codecid)\
const AVInputFormat ff_image_ ## imgname ## _pipe_demuxer = {\
.name = AV_STRINGIFY(imgname) "_pipe",\
.long_name = NULL_IF_CONFIG_SMALL("piped " AV_STRINGIFY(imgname) " sequence"),\
.priv_data_size = sizeof(VideoDemuxData),\
.read_probe = imgname ## _probe,\
.read_header = ff_img_read_header,\
.read_packet = ff_img_read_packet,\
.priv_class = &imagepipe_class,\
.flags = AVFMT_GENERIC_INDEX, \
.raw_codec_id = codecid,\
};
IMAGEAUTO_DEMUXER(bmp, AV_CODEC_ID_BMP)
IMAGEAUTO_DEMUXER(cri, AV_CODEC_ID_CRI)
IMAGEAUTO_DEMUXER(dds, AV_CODEC_ID_DDS)
IMAGEAUTO_DEMUXER(dpx, AV_CODEC_ID_DPX)
IMAGEAUTO_DEMUXER(exr, AV_CODEC_ID_EXR)
IMAGEAUTO_DEMUXER(gem, AV_CODEC_ID_GEM)
IMAGEAUTO_DEMUXER(gif, AV_CODEC_ID_GIF)
IMAGEAUTO_DEMUXER(j2k, AV_CODEC_ID_JPEG2000)
IMAGEAUTO_DEMUXER(jpeg, AV_CODEC_ID_MJPEG)
IMAGEAUTO_DEMUXER(jpegls, AV_CODEC_ID_JPEGLS)
IMAGEAUTO_DEMUXER(pam, AV_CODEC_ID_PAM)
IMAGEAUTO_DEMUXER(pbm, AV_CODEC_ID_PBM)
IMAGEAUTO_DEMUXER(pcx, AV_CODEC_ID_PCX)
IMAGEAUTO_DEMUXER(pgm, AV_CODEC_ID_PGM)
IMAGEAUTO_DEMUXER(pgmyuv, AV_CODEC_ID_PGMYUV)
IMAGEAUTO_DEMUXER(pgx, AV_CODEC_ID_PGX)
IMAGEAUTO_DEMUXER(photocd, AV_CODEC_ID_PHOTOCD)
IMAGEAUTO_DEMUXER(pictor, AV_CODEC_ID_PICTOR)
IMAGEAUTO_DEMUXER(png, AV_CODEC_ID_PNG)
IMAGEAUTO_DEMUXER(ppm, AV_CODEC_ID_PPM)
IMAGEAUTO_DEMUXER(psd, AV_CODEC_ID_PSD)
IMAGEAUTO_DEMUXER(qdraw, AV_CODEC_ID_QDRAW)
IMAGEAUTO_DEMUXER(sgi, AV_CODEC_ID_SGI)
IMAGEAUTO_DEMUXER(sunrast, AV_CODEC_ID_SUNRAST)
IMAGEAUTO_DEMUXER(svg, AV_CODEC_ID_SVG)
IMAGEAUTO_DEMUXER(tiff, AV_CODEC_ID_TIFF)
IMAGEAUTO_DEMUXER(webp, AV_CODEC_ID_WEBP)
IMAGEAUTO_DEMUXER(xbm, AV_CODEC_ID_XBM)
IMAGEAUTO_DEMUXER(xpm, AV_CODEC_ID_XPM)
IMAGEAUTO_DEMUXER(xwd, AV_CODEC_ID_XWD)
上述代码
const AVInputFormat ff_image_ ## imgname ## _pipe_demuxer = {\
中的##是 宏定义中的操作连接符,具体参考:《define的一些骚操作:##操作连接符、#@字符化操作符、#字符串化操作符、\行继续操作》。
这里用到了C语言的设计艺术:使用##简化函数或变量的名称。
宏定义
#define IMAGEAUTO_DEMUXER(imgname, codecid)\
实现的是定义全局const变量,该变量类型为AVInputFormat 。AVInputFormat是FFmpeg中的解复用器结构体,每种作为输入的封装格式(例如BMP、FLV、MP4、TS等)都对应一种AVInputFormat 结构。
以BMP这种图片的封装格式为例,它对应的AVInputFormat 结构为:
IMAGEAUTO_DEMUXER(bmp, AV_CODEC_ID_BMP)
将该宏定义展开即为:
const AVInputFormat ff_image_bmp_pipe_demuxer = {
.name = "bmp_pipe",
.long_name = "piped bmp sequence",
.priv_data_size = 1208,
.read_probe = bmp_probe,
.read_header = ff_img_read_header,
.read_packet = ff_img_read_packet,
.priv_class = &imagepipe_class,
.flags = 256,
.raw_codec_id = AV_CODEC_ID_BMP,
};
所以通过这种宏定义的设计艺术,可以巧妙地把类型为AVInputFormat的结构体变量的名称中的“ff_image_” 和 “_pipe_demuxer”去掉,这样最后编写的代码非常整洁,具有简化结构体变量名,避免冗余代码的作用,下面的宏定义中每一行都相当于 定义了一种AVInputFormat 结构,也就是封装格式结构。
IMAGEAUTO_DEMUXER(bmp, AV_CODEC_ID_BMP)
IMAGEAUTO_DEMUXER(cri, AV_CODEC_ID_CRI)
IMAGEAUTO_DEMUXER(dds, AV_CODEC_ID_DDS)
IMAGEAUTO_DEMUXER(dpx, AV_CODEC_ID_DPX)
IMAGEAUTO_DEMUXER(exr, AV_CODEC_ID_EXR)
IMAGEAUTO_DEMUXER(gem, AV_CODEC_ID_GEM)
IMAGEAUTO_DEMUXER(gif, AV_CODEC_ID_GIF)
IMAGEAUTO_DEMUXER(j2k, AV_CODEC_ID_JPEG2000)
IMAGEAUTO_DEMUXER(jpeg, AV_CODEC_ID_MJPEG)
IMAGEAUTO_DEMUXER(jpegls, AV_CODEC_ID_JPEGLS)
IMAGEAUTO_DEMUXER(pam, AV_CODEC_ID_PAM)
IMAGEAUTO_DEMUXER(pbm, AV_CODEC_ID_PBM)
IMAGEAUTO_DEMUXER(pcx, AV_CODEC_ID_PCX)
IMAGEAUTO_DEMUXER(pgm, AV_CODEC_ID_PGM)
IMAGEAUTO_DEMUXER(pgmyuv, AV_CODEC_ID_PGMYUV)
IMAGEAUTO_DEMUXER(pgx, AV_CODEC_ID_PGX)
IMAGEAUTO_DEMUXER(photocd, AV_CODEC_ID_PHOTOCD)
IMAGEAUTO_DEMUXER(pictor, AV_CODEC_ID_PICTOR)
IMAGEAUTO_DEMUXER(png, AV_CODEC_ID_PNG)
IMAGEAUTO_DEMUXER(ppm, AV_CODEC_ID_PPM)
IMAGEAUTO_DEMUXER(psd, AV_CODEC_ID_PSD)
IMAGEAUTO_DEMUXER(qdraw, AV_CODEC_ID_QDRAW)
IMAGEAUTO_DEMUXER(sgi, AV_CODEC_ID_SGI)
IMAGEAUTO_DEMUXER(sunrast, AV_CODEC_ID_SUNRAST)
IMAGEAUTO_DEMUXER(svg, AV_CODEC_ID_SVG)
IMAGEAUTO_DEMUXER(tiff, AV_CODEC_ID_TIFF)
IMAGEAUTO_DEMUXER(webp, AV_CODEC_ID_WEBP)
IMAGEAUTO_DEMUXER(xbm, AV_CODEC_ID_XBM)
IMAGEAUTO_DEMUXER(xpm, AV_CODEC_ID_XPM)
IMAGEAUTO_DEMUXER(xwd, AV_CODEC_ID_XWD)
上述宏定义被demuxer_list数组使用。在FFmpeg源码目录下的libavformat/demuxer_list.c中,定义了demuxer_list数组,该数组定义了FFmpeg当前支持的媒体和图片的解封装协议,每个元素都指向了一种AVInputFormat 结构:
static const AVInputFormat * const demuxer_list[] = {
//...
&ff_image_bmp_pipe_demuxer,
&ff_image_cri_pipe_demuxer,
&ff_image_dds_pipe_demuxer,
&ff_image_dpx_pipe_demuxer,
&ff_image_exr_pipe_demuxer,
&ff_image_gem_pipe_demuxer,
&ff_image_gif_pipe_demuxer,
&ff_image_j2k_pipe_demuxer,
&ff_image_jpeg_pipe_demuxer,
&ff_image_jpegls_pipe_demuxer,
&ff_image_pam_pipe_demuxer,
&ff_image_pbm_pipe_demuxer,
&ff_image_pcx_pipe_demuxer,
&ff_image_pgmyuv_pipe_demuxer,
&ff_image_pgm_pipe_demuxer,
&ff_image_pgx_pipe_demuxer,
&ff_image_photocd_pipe_demuxer,
&ff_image_pictor_pipe_demuxer,
&ff_image_png_pipe_demuxer,
&ff_image_ppm_pipe_demuxer,
&ff_image_psd_pipe_demuxer,
&ff_image_qdraw_pipe_demuxer,
&ff_image_sgi_pipe_demuxer,
&ff_image_svg_pipe_demuxer,
&ff_image_sunrast_pipe_demuxer,
&ff_image_tiff_pipe_demuxer,
&ff_image_webp_pipe_demuxer,
&ff_image_xbm_pipe_demuxer,
&ff_image_xpm_pipe_demuxer,
&ff_image_xwd_pipe_demuxer,
NULL };