欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 旅游 > FFmpeg源码:av_probe_input_format3函数分析

FFmpeg源码:av_probe_input_format3函数分析

2024/10/23 23:26:20 来源:https://blog.csdn.net/u014552102/article/details/140550691  浏览:    关键词:FFmpeg源码:av_probe_input_format3函数分析

一、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;} elsenodat = 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)语句执行不同容器格式对应的解析函数,根据是否能被解析,以及匹配程度,来判断出这是哪种容器格式。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com