一、av_probe_input_format3函数的声明
av_probe_input_format3函数声明在FFmpeg源码(本文演示用的FFmpeg源码版本为5.0.3)的头文件libavformat/avformat.h中:
/**
* Guess the file format.
*
* @param is_opened Whether the file is already opened; determines whether
* demuxers with or without AVFMT_NOFILE are probed.
* @param score_ret The score of the best detection.
*/
const AVInputFormat *av_probe_input_format3(const AVProbeData *pd,
int is_opened, int *score_ret);
该函数在avformat_open_input函数内部被调用。其作用是:推测文件的格式。
形参pd:输入型参数,为AVProbeData类型的指针。
AVProbeData结构体声明在libavformat/avformat.h中:
/**
* This structure contains the data a format has to probe a file.
*/
typedef struct AVProbeData {
const char *filename;
unsigned char *buf; /**< Buffer must have AVPROBE_PADDING_SIZE of extra allocated bytes filled with zero. */
int buf_size; /**< Size of buf except extra allocated bytes */
const char *mime_type; /**< mime_type, when known. */
} AVProbeData;
pd->filename为:需要被推测格式的文件的路径。
pd->buf:如果路径为pd->filename的文件还没被打开,pd->buf的值为NULL。如果路径为pd->filename的文件已经被打开,pd->buf指向“存放从该文件读取出来的二进制数据”的缓冲区。
pd->buf_size:缓冲区pd->buf的大小,单位为字节。
pd->mime_type:一般为NULL,可忽略。
形参is_opened:输入型参数。值为0表示路径为pd->filename的文件还没被打开,值为1表示路径为pd->filename的文件已经被打开了。
形参score_ret:输出型参数,指向一个int型变量。执行av_probe_input_format3函数后,score_ret指向的int型变量的值会变为:最匹配“路径为pd->filename的文件”的格式的分值。
分值的范围为0到100分,值越大表示越匹配。分值对应的宏定义在头文件libavformat/avformat.h中被定义:
#define AVPROBE_SCORE_EXTENSION 50 ///< score for file extension
#define AVPROBE_SCORE_MIME 75 ///< score for file mime type
#define AVPROBE_SCORE_MAX 100 ///< maximum score
返回值:为AVInputFormat类型的指针。如果形参is_opened的值为0(文件还没被打开),返回值为NULL;如果is_opened的值为1(文件已经被打开了),则返回最匹配“路径为pd->filename的文件”的格式的AVInputFormat结构体指针。
AVInputFormat结构体声明在libavformat/avformat.h中:
/**
* @addtogroup lavf_decoding
* @{
*/
typedef struct AVInputFormat {
/**
* A comma separated list of short names for the format. New names
* may be appended with a minor bump.
*/
const char *name;
/**
* Descriptive name for the format, meant to be more human-readable
* than name. You should use the NULL_IF_CONFIG_SMALL() macro
* to define it.
*/
const char *long_name;
/**
* Can use flags: AVFMT_NOFILE, AVFMT_NEEDNUMBER, AVFMT_SHOW_IDS,
* AVFMT_NOTIMESTAMPS, AVFMT_GENERIC_INDEX, AVFMT_TS_DISCONT, AVFMT_NOBINSEARCH,
* AVFMT_NOGENSEARCH, AVFMT_NO_BYTE_SEEK, AVFMT_SEEK_TO_PTS.
*/
int flags;
/**
* If extensions are defined, then no probe is done. You should
* usually not use extension format guessing because it is not
* reliable enough
*/
const char *extensions;
const struct AVCodecTag * const *codec_tag;
const AVClass *priv_class; ///< AVClass for the private context
/**
* Comma-separated list of mime types.
* It is used check for matching mime types while probing.
* @see av_probe_input_format2
*/
const char *mime_type;
/*****************************************************************
* No fields below this line are part of the public API. They
* may not be used outside of libavformat and can be changed and
* removed at will.
* New public fields should be added right above.
*****************************************************************
*/
/**
* Raw demuxers store their codec ID here.
*/
int raw_codec_id;
/**
* Size of private data so that it can be allocated in the wrapper.
*/
int priv_data_size;
/**
* Internal flags. See FF_FMT_FLAG_* in internal.h.
*/
int flags_internal;
/**
* Tell if a given file has a chance of being parsed as this format.
* The buffer provided is guaranteed to be AVPROBE_PADDING_SIZE bytes
* big so you do not have to check for that unless you need more.
*/
int (*read_probe)(const AVProbeData *);
/**
* Read the format header and initialize the AVFormatContext
* structure. Return 0 if OK. 'avformat_new_stream' should be
* called to create new streams.
*/
int (*read_header)(struct AVFormatContext *);
/**
* Read one packet and put it in 'pkt'. pts and flags are also
* set. 'avformat_new_stream' can be called only if the flag
* AVFMTCTX_NOHEADER is used and only in the calling thread (not in a
* background thread).
* @return 0 on success, < 0 on error.
* Upon returning an error, pkt must be unreferenced by the caller.
*/
int (*read_packet)(struct AVFormatContext *, AVPacket *pkt);
/**
* Close the stream. The AVFormatContext and AVStreams are not
* freed by this function
*/
int (*read_close)(struct AVFormatContext *);
/**
* Seek to a given timestamp relative to the frames in
* stream component stream_index.
* @param stream_index Must not be -1.
* @param flags Selects which direction should be preferred if no exact
* match is available.
* @return >= 0 on success (but not necessarily the new offset)
*/
int (*read_seek)(struct AVFormatContext *,
int stream_index, int64_t timestamp, int flags);
/**
* Get the next timestamp in stream[stream_index].time_base units.
* @return the timestamp or AV_NOPTS_VALUE if an error occurred
*/
int64_t (*read_timestamp)(struct AVFormatContext *s, int stream_index,
int64_t *pos, int64_t pos_limit);
/**
* Start/resume playing - only meaningful if using a network-based format
* (RTSP).
*/
int (*read_play)(struct AVFormatContext *);
/**
* Pause playing - only meaningful if using a network-based format
* (RTSP).
*/
int (*read_pause)(struct AVFormatContext *);
/**
* Seek to timestamp ts.
* Seeking will be done so that the point from which all active streams
* can be presented successfully will be closest to ts and within min/max_ts.
* Active streams are all streams that have AVStream.discard < AVDISCARD_ALL.
*/
int (*read_seek2)(struct AVFormatContext *s, int stream_index, int64_t min_ts, int64_t ts, int64_t max_ts, int flags);
/**
* Returns device list with it properties.
* @see avdevice_list_devices() for more details.
*/
int (*get_device_list)(struct AVFormatContext *s, struct AVDeviceInfoList *device_list);
} AVInputFormat;
AVInputFormat是FFmpeg中的解复用器结构体,每种作为输入的封装格式(例如BMP、FLV、MP4、TS、H.264裸流文件等)都对应一种AVInputFormat 结构。
比如BMP这种图片的封装格式,它对应的AVInputFormat结构为:
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,
};
H.264裸流文件对应的AVInputFormat结构为:
const AVInputFormat ff_h264_demuxer= {
.name = "h264",
.long_name = "raw H.264 video",
.priv_data_size = 1208,
.read_probe = h264_probe,
.read_header = ff_raw_video_read_header,
.read_packet = ff_raw_read_partial_packet,
.priv_class = &ff_rawvideo_demuxer_class,
.flags = 256,
.raw_codec_id = AV_CODEC_ID_H264,
};
二、av_probe_input_format3函数的定义
av_probe_input_format3函数定义在源文件libavformat/format.c中:
const AVInputFormat *av_probe_input_format3(const AVProbeData *pd,
int is_opened, int *score_ret)
{
AVProbeData lpd = *pd;
const AVInputFormat *fmt1 = NULL;
const AVInputFormat *fmt = NULL;
int score, score_max = 0;
void *i = 0;
const static uint8_t zerobuffer[AVPROBE_PADDING_SIZE];
enum nodat {
NO_ID3,
ID3_ALMOST_GREATER_PROBE,
ID3_GREATER_PROBE,
ID3_GREATER_MAX_PROBE,
} nodat = NO_ID3;
if (!lpd.buf)
lpd.buf = (unsigned char *) zerobuffer;
if (lpd.buf_size > 10 && ff_id3v2_match(lpd.buf, ID3v2_DEFAULT_MAGIC)) {
int id3len = ff_id3v2_tag_len(lpd.buf);
if (lpd.buf_size > id3len + 16) {
if (lpd.buf_size < 2LL*id3len + 16)
nodat = ID3_ALMOST_GREATER_PROBE;
lpd.buf += id3len;
lpd.buf_size -= id3len;
} else if (id3len >= PROBE_BUF_MAX) {
nodat = ID3_GREATER_MAX_PROBE;
} else
nodat = ID3_GREATER_PROBE;
}
while ((fmt1 = av_demuxer_iterate(&i))) {
if (fmt1->flags & AVFMT_EXPERIMENTAL)
continue;
if (!is_opened == !(fmt1->flags & AVFMT_NOFILE) && strcmp(fmt1->name, "image2"))
continue;
score = 0;
if (fmt1->read_probe) {
score = fmt1->read_probe(&lpd);
if (score)
av_log(NULL, AV_LOG_TRACE, "Probing %s score:%d size:%d\n", fmt1->name, score, lpd.buf_size);
if (fmt1->extensions && av_match_ext(lpd.filename, fmt1->extensions)) {
switch (nodat) {
case NO_ID3:
score = FFMAX(score, 1);
break;
case ID3_GREATER_PROBE:
case ID3_ALMOST_GREATER_PROBE:
score = FFMAX(score, AVPROBE_SCORE_EXTENSION / 2 - 1);
break;
case ID3_GREATER_MAX_PROBE:
score = FFMAX(score, AVPROBE_SCORE_EXTENSION);
break;
}
}
} else if (fmt1->extensions) {
if (av_match_ext(lpd.filename, fmt1->extensions))
score = AVPROBE_SCORE_EXTENSION;
}
if (av_match_name(lpd.mime_type, fmt1->mime_type)) {
if (AVPROBE_SCORE_MIME > score) {
av_log(NULL, AV_LOG_DEBUG, "Probing %s score:%d increased to %d due to MIME type\n", fmt1->name, score, AVPROBE_SCORE_MIME);
score = AVPROBE_SCORE_MIME;
}
}
if (score > score_max) {
score_max = score;
fmt = fmt1;
} else if (score == score_max)
fmt = NULL;
}
if (nodat == ID3_GREATER_PROBE)
score_max = FFMIN(AVPROBE_SCORE_EXTENSION / 2 - 1, score_max);
*score_ret = score_max;
return fmt;
}
三、av_probe_input_format3函数的内部实现分析
当形参is_opened的值为1,也就是需要被推测格式的文件已经被打开时。函数av_probe_input_format3中,首先会通过语句:
AVProbeData lpd = *pd;
让lpd.buf指向“存放从该文件读取出来的二进制数据”的缓冲区,从而得到需要被推测格式的文件的二进制数据。
然后会循环执行:
while ((fmt1 = av_demuxer_iterate(&i))) {
//...
}
av_demuxer_iterate函数定义在libavformat/allformats.c中,作用是得到形参opaque(也就是i)对应的已被注册的解封装器,可以看到它内部获取了全局数组demuxer_list中的元素:
const AVInputFormat *av_demuxer_iterate(void **opaque)
{
static const uintptr_t size = sizeof(demuxer_list)/sizeof(demuxer_list[0]) - 1;
uintptr_t i = (uintptr_t)*opaque;
const AVInputFormat *f = NULL;
uintptr_t tmp;
if (i < size) {
f = demuxer_list[i];
} else if (tmp = atomic_load_explicit(&indev_list_intptr, memory_order_relaxed)) {
const AVInputFormat *const *indev_list = (const AVInputFormat *const *)tmp;
f = indev_list[i - size];
}
if (f)
*opaque = (void*)(i + 1);
return f;
}
全局数组demuxer_list定义在libavformat/demuxer_list.c中,数组中的每个元素都对应一种AVInputFormat结构,也就是说数组中的每个元素都对应一种输入的封装格式(BMP、FLV、MP4、TS、H.264裸流文件等):
static const AVInputFormat * const demuxer_list[] = {
&ff_aa_demuxer,
&ff_aac_demuxer,
&ff_aax_demuxer,
&ff_ac3_demuxer,
&ff_ace_demuxer,
&ff_acm_demuxer,
&ff_act_demuxer,
&ff_adf_demuxer,
&ff_adp_demuxer,
&ff_ads_demuxer,
&ff_adx_demuxer,
&ff_aea_demuxer,
&ff_afc_demuxer,
&ff_aiff_demuxer,
&ff_aix_demuxer,
&ff_alp_demuxer,
&ff_amr_demuxer,
&ff_amrnb_demuxer,
&ff_amrwb_demuxer,
&ff_anm_demuxer,
&ff_apc_demuxer,
&ff_ape_demuxer,
&ff_apm_demuxer,
&ff_apng_demuxer,
&ff_aptx_demuxer,
&ff_aptx_hd_demuxer,
&ff_aqtitle_demuxer,
&ff_argo_asf_demuxer,
&ff_argo_brp_demuxer,
&ff_argo_cvg_demuxer,
&ff_asf_demuxer,
&ff_asf_o_demuxer,
&ff_ass_demuxer,
&ff_ast_demuxer,
&ff_au_demuxer,
&ff_av1_demuxer,
&ff_avi_demuxer,
&ff_avr_demuxer,
&ff_avs_demuxer,
&ff_avs2_demuxer,
&ff_avs3_demuxer,
&ff_bethsoftvid_demuxer,
&ff_bfi_demuxer,
&ff_bintext_demuxer,
&ff_bink_demuxer,
&ff_binka_demuxer,
&ff_bit_demuxer,
&ff_bitpacked_demuxer,
&ff_bmv_demuxer,
&ff_bfstm_demuxer,
&ff_brstm_demuxer,
&ff_boa_demuxer,
&ff_c93_demuxer,
&ff_caf_demuxer,
&ff_cavsvideo_demuxer,
&ff_cdg_demuxer,
&ff_cdxl_demuxer,
&ff_cine_demuxer,
&ff_codec2_demuxer,
&ff_codec2raw_demuxer,
&ff_concat_demuxer,
&ff_data_demuxer,
&ff_daud_demuxer,
&ff_dcstr_demuxer,
&ff_derf_demuxer,
&ff_dfa_demuxer,
&ff_dhav_demuxer,
&ff_dirac_demuxer,
&ff_dnxhd_demuxer,
&ff_dsf_demuxer,
&ff_dsicin_demuxer,
&ff_dss_demuxer,
&ff_dts_demuxer,
&ff_dtshd_demuxer,
&ff_dv_demuxer,
&ff_dvbsub_demuxer,
&ff_dvbtxt_demuxer,
&ff_dxa_demuxer,
&ff_ea_demuxer,
&ff_ea_cdata_demuxer,
&ff_eac3_demuxer,
&ff_epaf_demuxer,
&ff_ffmetadata_demuxer,
&ff_filmstrip_demuxer,
&ff_fits_demuxer,
&ff_flac_demuxer,
&ff_flic_demuxer,
&ff_flv_demuxer,
&ff_live_flv_demuxer,
&ff_fourxm_demuxer,
&ff_frm_demuxer,
&ff_fsb_demuxer,
&ff_fwse_demuxer,
&ff_g722_demuxer,
&ff_g723_1_demuxer,
&ff_g726_demuxer,
&ff_g726le_demuxer,
&ff_g729_demuxer,
&ff_gdv_demuxer,
&ff_genh_demuxer,
&ff_gif_demuxer,
&ff_gsm_demuxer,
&ff_gxf_demuxer,
&ff_h261_demuxer,
&ff_h263_demuxer,
&ff_h264_demuxer,
&ff_hca_demuxer,
&ff_hcom_demuxer,
&ff_hevc_demuxer,
&ff_hls_demuxer,
&ff_hnm_demuxer,
&ff_ico_demuxer,
&ff_idcin_demuxer,
&ff_idf_demuxer,
&ff_iff_demuxer,
&ff_ifv_demuxer,
&ff_ilbc_demuxer,
&ff_image2_demuxer,
&ff_image2pipe_demuxer,
&ff_image2_alias_pix_demuxer,
&ff_image2_brender_pix_demuxer,
&ff_ingenient_demuxer,
&ff_ipmovie_demuxer,
&ff_ipu_demuxer,
&ff_ircam_demuxer,
&ff_iss_demuxer,
&ff_iv8_demuxer,
&ff_ivf_demuxer,
&ff_ivr_demuxer,
&ff_jacosub_demuxer,
&ff_jv_demuxer,
&ff_kux_demuxer,
&ff_kvag_demuxer,
&ff_lmlm4_demuxer,
&ff_loas_demuxer,
&ff_luodat_demuxer,
&ff_lrc_demuxer,
&ff_lvf_demuxer,
&ff_lxf_demuxer,
&ff_m4v_demuxer,
&ff_mca_demuxer,
&ff_mcc_demuxer,
&ff_matroska_demuxer,
&ff_mgsts_demuxer,
&ff_microdvd_demuxer,
&ff_mjpeg_demuxer,
&ff_mjpeg_2000_demuxer,
&ff_mlp_demuxer,
&ff_mlv_demuxer,
&ff_mm_demuxer,
&ff_mmf_demuxer,
&ff_mods_demuxer,
&ff_moflex_demuxer,
&ff_mov_demuxer,
&ff_mp3_demuxer,
&ff_mpc_demuxer,
&ff_mpc8_demuxer,
&ff_mpegps_demuxer,
&ff_mpegts_demuxer,
&ff_mpegtsraw_demuxer,
&ff_mpegvideo_demuxer,
&ff_mpjpeg_demuxer,
&ff_mpl2_demuxer,
&ff_mpsub_demuxer,
&ff_msf_demuxer,
&ff_msnwc_tcp_demuxer,
&ff_msp_demuxer,
&ff_mtaf_demuxer,
&ff_mtv_demuxer,
&ff_musx_demuxer,
&ff_mv_demuxer,
&ff_mvi_demuxer,
&ff_mxf_demuxer,
&ff_mxg_demuxer,
&ff_nc_demuxer,
&ff_nistsphere_demuxer,
&ff_nsp_demuxer,
&ff_nsv_demuxer,
&ff_nut_demuxer,
&ff_nuv_demuxer,
&ff_obu_demuxer,
&ff_ogg_demuxer,
&ff_oma_demuxer,
&ff_paf_demuxer,
&ff_pcm_alaw_demuxer,
&ff_pcm_mulaw_demuxer,
&ff_pcm_vidc_demuxer,
&ff_pcm_f64be_demuxer,
&ff_pcm_f64le_demuxer,
&ff_pcm_f32be_demuxer,
&ff_pcm_f32le_demuxer,
&ff_pcm_s32be_demuxer,
&ff_pcm_s32le_demuxer,
&ff_pcm_s24be_demuxer,
&ff_pcm_s24le_demuxer,
&ff_pcm_s16be_demuxer,
&ff_pcm_s16le_demuxer,
&ff_pcm_s8_demuxer,
&ff_pcm_u32be_demuxer,
&ff_pcm_u32le_demuxer,
&ff_pcm_u24be_demuxer,
&ff_pcm_u24le_demuxer,
&ff_pcm_u16be_demuxer,
&ff_pcm_u16le_demuxer,
&ff_pcm_u8_demuxer,
&ff_pjs_demuxer,
&ff_pmp_demuxer,
&ff_pp_bnk_demuxer,
&ff_pva_demuxer,
&ff_pvf_demuxer,
&ff_qcp_demuxer,
&ff_r3d_demuxer,
&ff_rawvideo_demuxer,
&ff_realtext_demuxer,
&ff_redspark_demuxer,
&ff_rl2_demuxer,
&ff_rm_demuxer,
&ff_roq_demuxer,
&ff_rpl_demuxer,
&ff_rsd_demuxer,
&ff_rso_demuxer,
&ff_rtp_demuxer,
&ff_rtsp_demuxer,
&ff_s337m_demuxer,
&ff_sami_demuxer,
&ff_sap_demuxer,
&ff_sbc_demuxer,
&ff_sbg_demuxer,
&ff_scc_demuxer,
&ff_scd_demuxer,
&ff_sdp_demuxer,
&ff_sdr2_demuxer,
&ff_sds_demuxer,
&ff_sdx_demuxer,
&ff_segafilm_demuxer,
&ff_ser_demuxer,
&ff_sga_demuxer,
&ff_shorten_demuxer,
&ff_siff_demuxer,
&ff_simbiosis_imx_demuxer,
&ff_sln_demuxer,
&ff_smacker_demuxer,
&ff_smjpeg_demuxer,
&ff_smush_demuxer,
&ff_sol_demuxer,
&ff_sox_demuxer,
&ff_spdif_demuxer,
&ff_srt_demuxer,
&ff_str_demuxer,
&ff_stl_demuxer,
&ff_subviewer1_demuxer,
&ff_subviewer_demuxer,
&ff_sup_demuxer,
&ff_svag_demuxer,
&ff_svs_demuxer,
&ff_swf_demuxer,
&ff_tak_demuxer,
&ff_tedcaptions_demuxer,
&ff_thp_demuxer,
&ff_threedostr_demuxer,
&ff_tiertexseq_demuxer,
&ff_tmv_demuxer,
&ff_truehd_demuxer,
&ff_tta_demuxer,
&ff_txd_demuxer,
&ff_tty_demuxer,
&ff_ty_demuxer,
&ff_v210_demuxer,
&ff_v210x_demuxer,
&ff_vag_demuxer,
&ff_vc1_demuxer,
&ff_vc1t_demuxer,
&ff_vividas_demuxer,
&ff_vivo_demuxer,
&ff_vmd_demuxer,
&ff_vobsub_demuxer,
&ff_voc_demuxer,
&ff_vpk_demuxer,
&ff_vplayer_demuxer,
&ff_vqf_demuxer,
&ff_w64_demuxer,
&ff_wav_demuxer,
&ff_wc3_demuxer,
&ff_webm_dash_manifest_demuxer,
&ff_webvtt_demuxer,
&ff_wsaud_demuxer,
&ff_wsd_demuxer,
&ff_wsvqa_demuxer,
&ff_wtv_demuxer,
&ff_wve_demuxer,
&ff_wv_demuxer,
&ff_xa_demuxer,
&ff_xbin_demuxer,
&ff_xmv_demuxer,
&ff_xvag_demuxer,
&ff_xwma_demuxer,
&ff_yop_demuxer,
&ff_yuv4mpegpipe_demuxer,
&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 };
所以下面语句实际上是循环得到全局数组demuxer_list中的下标为i的元素,也就是得到demuxer_list[i]对应的AVInputFormat结构。执行该语句后fmt1指向i对应的AVInputFormat结构,i的值会加1。通过该语句可以把FFmpeg中所有被注册的文件格式都遍历一遍:
while ((fmt1 = av_demuxer_iterate(&i))) {
//...
}
在上述循环中通过下面语句执行不同文件格式对应的解析函数,得到分值。read_probe是函数指针,执行fmt1->read_probe语句会调用不同文件格式对应的解析函数。比如对于BMP图片,会执行bmp_probe函数,对于H.264裸流文件,会执行h264_probe函数。执行完后会得到分值,表示跟该文件格式的匹配程度:
score = fmt1->read_probe(&lpd);
循环解析所有格式的文件的过程中,不断将最高分存贮到变量score_max中,让指针fmt指向最高分对应的AVInputFormat结构。从而在执行完所有不同文件格式对应的解析函数后,可以得到最匹配的文件格式:
if (score > score_max) {
score_max = score;
fmt = fmt1;
} else if (score == score_max)
fmt = NULL;
四、总结
av_probe_input_format3函数是FFmpeg中实现容器格式检测的函数,其内部通过循环while ((fmt1 = av_demuxer_iterate(&i))) 拿到所有容器格式对应的AVInputFormat结构,然后通过score = fmt1->read_probe(&lpd)语句执行不同容器格式对应的解析函数,根据是否能被解析,以及匹配程度,来判断出这是哪种容器格式。
本站资源均来自互联网,仅供研究学习,禁止违法使用和商用,产生法律纠纷本站概不负责!如果侵犯了您的权益请与我们联系!
转载请注明出处: 免费源码网-免费的源码资源网站 » FFmpeg源码:av_probe_input_format3函数分析
发表评论 取消回复