2025年3月15日 星期六 甲辰(龙)年 月十四 设为首页 加入收藏
rss
您当前的位置:首页 > 计算机 > 文件格式与编码

FFmpeg多媒体文件格式探测

时间:01-02来源:作者:点击数:40

FFmpeg版本:3.4

在FFmpeg中,每一种文件容器格式都对应一种AVInputFormat 结构,位于源码中libavformat文件夹中。当调用avformat_open_input的时候,FFmpeg会根据媒体封装格式的特点(主要是根据AVInputFormat结构的read_probe函数根据传入的一段buffer来判断传入的文件是否能被解析为该AVInputFormat对应的容器格式),对全部已知的格式进行判断并设置一个分值,取其中最高的分值来关联到一种文件容器格式。

我们通过下面的函数调用堆栈信息来分析avformat_open_input是怎样一步步的关联到具体的文件容器格式的。

  • static int init_input(AVFormatContext *s, const char *filename,
  • AVDictionary **options)
  • {
  • //...
  • return av_probe_input_buffer2(s->pb, &s->iformat, filename,
  • s, 0, s->format_probesize);
  • }
  • int av_probe_input_buffer2(AVIOContext *pb, AVInputFormat **fmt,
  • const char *filename, void *logctx,
  • unsigned int offset, unsigned int max_probe_size)
  • {
  • //...
  • //把AVFormatContext和具体的AVInputFormat联系起来了
  • *fmt = av_probe_input_format2(&pd, 1, &score);
  • //...
  • }

FFmpeg中实现探测的函数是av_probe_input_buffer2和av_probe_input_format3。其核心代码如下:

  • //遍历所有的Demuxer
  • while ((fmt1 = av_demuxer_iterate(&i))) {
  • 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 = (AVInputFormat*)fmt1;
  • } else if (score == score_max)
  • fmt = NULL;
  • }

上面代码的原理就是优先使用demuxer的read_probe函数,然后参考文件名的后缀名来关联某个AVInputFormat。

  • 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;
  • if (i < size) {
  • //遍历demuxer_list中的所有demuxer
  • f = demuxer_list[i];
  • } else if (outdev_list) {
  • f = indev_list[i - size];
  • }
  • if (f)
  • *opaque = (void*)(i + 1);
  • return f;
  • }

demuxer_list数组定义在libavformat/demuxer_list.c中,该文件是编译FFMPEGconfigure的时候生成的

  • print_enabled_components libavformat/demuxer_list.c AVInputFormat demuxer_list $DEMUXER_LIST
  • static const AVInputFormat * const demuxer_list[] = {
  • &ff_aa_demuxer,
  • &ff_aac_demuxer,
  • &ff_ac3_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_amr_demuxer,
  • &ff_amrnb_demuxer,
  • &ff_amrwb_demuxer,
  • &ff_anm_demuxer,
  • &ff_apc_demuxer,
  • &ff_ape_demuxer,
  • &ff_apng_demuxer,
  • &ff_aptx_demuxer,
  • &ff_aptx_hd_demuxer,
  • &ff_aqtitle_demuxer,
  • &ff_asf_demuxer,
  • &ff_asf_o_demuxer,
  • &ff_ass_demuxer,
  • &ff_ast_demuxer,
  • &ff_au_demuxer,
  • &ff_avi_demuxer,
  • &ff_avr_demuxer,
  • &ff_avs_demuxer,
  • &ff_bethsoftvid_demuxer,
  • &ff_bfi_demuxer,
  • &ff_bintext_demuxer,
  • &ff_bink_demuxer,
  • &ff_bit_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_dfa_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_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_hevc_demuxer,
  • &ff_hls_demuxer,
  • &ff_hnm_demuxer,
  • &ff_ico_demuxer,
  • &ff_idcin_demuxer,
  • &ff_idf_demuxer,
  • &ff_iff_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_ircam_demuxer,
  • &ff_iss_demuxer,
  • &ff_iv8_demuxer,
  • &ff_ivf_demuxer,
  • &ff_ivr_demuxer,
  • &ff_jacosub_demuxer,
  • &ff_jv_demuxer,
  • &ff_lmlm4_demuxer,
  • &ff_loas_demuxer,
  • &ff_lrc_demuxer,
  • &ff_lvf_demuxer,
  • &ff_lxf_demuxer,
  • &ff_m4v_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_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_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_ogg_demuxer,
  • &ff_oma_demuxer,
  • &ff_paf_demuxer,
  • &ff_pcm_alaw_demuxer,
  • &ff_pcm_mulaw_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_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_sdp_demuxer,
  • &ff_sdr2_demuxer,
  • &ff_sds_demuxer,
  • &ff_sdx_demuxer,
  • &ff_segafilm_demuxer,
  • &ff_shorten_demuxer,
  • &ff_siff_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_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_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_dds_pipe_demuxer,
  • &ff_image_dpx_pipe_demuxer,
  • &ff_image_exr_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_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_xpm_pipe_demuxer,
  • &ff_image_xwd_pipe_demuxer,
  • NULL };

read_probe实现

一般probe有两种情况。

对于在文件开头存在特征码的封装格式,比如avi、rm/rmvb、flv、mkv、asf可以直接使用特征码。

AVI的特征码是RIFF AVI,下面是FFmpeg中的avi探测函数实现:

  • //libavformat/avidec.c
  • static const char avi_headers[][8] = {
  • { 'R', 'I', 'F', 'F', 'A', 'V', 'I', ' ' },
  • { 'R', 'I', 'F', 'F', 'A', 'V', 'I', 'X' },
  • { 'R', 'I', 'F', 'F', 'A', 'V', 'I', 0x19 },
  • { 'O', 'N', '2', ' ', 'O', 'N', '2', 'f' },
  • { 'R', 'I', 'F', 'F', 'A', 'M', 'V', ' ' },
  • { 0 }
  • };
  • static int avi_probe(AVProbeData *p)
  • {
  • int i;
  • /* check file header */
  • for (i = 0; avi_headers[i][0]; i++)
  • if (AV_RL32(p->buf ) == AV_RL32(avi_headers[i] ) &&
  • AV_RL32(p->buf + 8) == AV_RL32(avi_headers[i] + 4))
  • return AVPROBE_SCORE_MAX;
  • return 0;
  • }

rm/rmvb文件的特征码是.RMF、.ra,下面是FFmpeg中rm探测函数:

  • //libavformat/rmdec.c
  • static int rm_probe(AVProbeData *p)
  • {
  • /* check file header */
  • if ((p->buf[0] == '.' && p->buf[1] == 'R' &&
  • p->buf[2] == 'M' && p->buf[3] == 'F' &&
  • p->buf[4] == 0 && p->buf[5] == 0) ||
  • (p->buf[0] == '.' && p->buf[1] == 'r' &&
  • p->buf[2] == 'a' && p->buf[3] == 0xfd))
  • return AVPROBE_SCORE_MAX;
  • else
  • return 0;
  • }

flv文件的特征码是FLV,下面是FFmpeg中flv探测函数:

  • //libavformat/flvdec.c
  • static int probe(AVProbeData *p, int live)
  • {
  • const uint8_t *d = p->buf;
  • unsigned offset = AV_RB32(d + 5);
  • if (d[0] == 'F' &&
  • d[1] == 'L' &&
  • d[2] == 'V' &&
  • d[3] < 5 && d[5] == 0 &&
  • offset + 100 < p->buf_size &&
  • offset > 8) {
  • int is_live = !memcmp(d + offset + 40, "NGINX RTMP", 10);
  • if (live == is_live)
  • return AVPROBE_SCORE_MAX;
  • }
  • return 0;
  • }
  • static int flv_probe(AVProbeData *p)
  • {
  • return probe(p, 0);
  • }

mkv的特征码就是EBML_Header_ID和已知的DocType,下面是FFmpeg的mkv探测函数:

  • //libavformat/matroskadec.c
  • /* top-level master-IDs */
  • #define EBML_ID_HEADER 0x1A45DFA3
  • static int matroska_probe(AVProbeData *p)
  • {
  • uint64_t total = 0;
  • int len_mask = 0x80, size = 1, n = 1, i;
  • /* EBML header? */
  • if (AV_RB32(p->buf) != EBML_ID_HEADER)
  • return 0;
  • /* length of header */
  • total = p->buf[4];
  • while (size <= 8 && !(total & len_mask)) {
  • size++;
  • len_mask >>= 1;
  • }
  • if (size > 8)
  • return 0;
  • total &= (len_mask - 1);
  • while (n < size)
  • total = (total << 8) | p->buf[4 + n++];
  • /* Does the probe data contain the whole header? */
  • if (p->buf_size < 4 + size + total)
  • return 0;
  • /* The header should contain a known document type. For now,
  • * we don't parse the whole header but simply check for the
  • * availability of that array of characters inside the header.
  • * Not fully fool-proof, but good enough. */
  • for (i = 0; i < FF_ARRAY_ELEMS(matroska_doctypes); i++) {
  • size_t probelen = strlen(matroska_doctypes[i]);
  • if (total < probelen)
  • continue;
  • for (n = 4 + size; n <= 4 + size + total - probelen; n++)
  • if (!memcmp(p->buf + n, matroska_doctypes[i], probelen))
  • return AVPROBE_SCORE_MAX;
  • }
  • // probably valid EBML header but no recognized doctype
  • return AVPROBE_SCORE_EXTENSION;
  • }

ASF/WMV文件的特征码就是ASF_HEADER_GUID,下面是FFmpeg中asf探测函数:

  • //libavformat/asfdec_f.c
  • const ff_asf_guid ff_asf_header = {
  • 0x30, 0x26, 0xB2, 0x75, 0x8E, 0x66, 0xCF, 0x11, 0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C
  • };
  • static int asf_probe(AVProbeData *pd)
  • {
  • /* check file header */
  • if (!ff_guidcmp(pd->buf, &ff_asf_header))
  • return AVPROBE_SCORE_MAX;
  • else
  • return 0;
  • }

MP4文件是由不同BOX构成的,需要根据box type来探测实际类型,FFmpeg中mp4探测函数(也包括mov,m4a,3gp,3g2)如下:

  • //libavformat/mov.c
  • static int mov_probe(AVProbeData *p)
  • {
  • int64_t offset;
  • uint32_t tag;
  • int score = 0;
  • int moov_offset = -1;
  • /* check file header */
  • offset = 0;
  • for (;;) {
  • /* ignore invalid offset */
  • if ((offset + 8) > (unsigned int)p->buf_size)
  • break;
  • tag = AV_RL32(p->buf + offset + 4);
  • switch(tag) {
  • /* check for obvious tags */
  • case MKTAG('m','o','o','v'):
  • moov_offset = offset + 4;
  • case MKTAG('m','d','a','t'):
  • case MKTAG('p','n','o','t'): /* detect movs with preview pics like ew.mov and april.mov */
  • case MKTAG('u','d','t','a'): /* Packet Video PVAuthor adds this and a lot of more junk */
  • case MKTAG('f','t','y','p'):
  • if (AV_RB32(p->buf+offset) < 8 &&
  • (AV_RB32(p->buf+offset) != 1 ||
  • offset + 12 > (unsigned int)p->buf_size ||
  • AV_RB64(p->buf+offset + 8) == 0)) {
  • score = FFMAX(score, AVPROBE_SCORE_EXTENSION);
  • } else if (tag == MKTAG('f','t','y','p') &&
  • ( AV_RL32(p->buf + offset + 8) == MKTAG('j','p','2',' ')
  • || AV_RL32(p->buf + offset + 8) == MKTAG('j','p','x',' ')
  • )) {
  • score = FFMAX(score, 5);
  • } else {
  • score = AVPROBE_SCORE_MAX;
  • }
  • offset = FFMAX(4, AV_RB32(p->buf+offset)) + offset;
  • break;
  • /* those are more common words, so rate then a bit less */
  • case MKTAG('e','d','i','w'): /* xdcam files have reverted first tags */
  • case MKTAG('w','i','d','e'):
  • case MKTAG('f','r','e','e'):
  • case MKTAG('j','u','n','k'):
  • case MKTAG('p','i','c','t'):
  • score = FFMAX(score, AVPROBE_SCORE_MAX - 5);
  • offset = FFMAX(4, AV_RB32(p->buf+offset)) + offset;
  • break;
  • case MKTAG(0x82,0x82,0x7f,0x7d):
  • case MKTAG('s','k','i','p'):
  • case MKTAG('u','u','i','d'):
  • case MKTAG('p','r','f','l'):
  • /* if we only find those cause probedata is too small at least rate them */
  • score = FFMAX(score, AVPROBE_SCORE_EXTENSION);
  • offset = FFMAX(4, AV_RB32(p->buf+offset)) + offset;
  • break;
  • default:
  • offset = FFMAX(4, AV_RB32(p->buf+offset)) + offset;
  • }
  • }
  • if(score > AVPROBE_SCORE_MAX - 50 && moov_offset != -1) {
  • /* moov atom in the header - we should make sure that this is not a
  • * MOV-packed MPEG-PS */
  • offset = moov_offset;
  • while(offset < (p->buf_size - 16)){ /* Sufficient space */
  • /* We found an actual hdlr atom */
  • if(AV_RL32(p->buf + offset ) == MKTAG('h','d','l','r') &&
  • AV_RL32(p->buf + offset + 8) == MKTAG('m','h','l','r') &&
  • AV_RL32(p->buf + offset + 12) == MKTAG('M','P','E','G')){
  • av_log(NULL, AV_LOG_WARNING, "Found media data tag MPEG indicating this is a MOV-packed MPEG-PS.\n");
  • /* We found a media handler reference atom describing an
  • * MPEG-PS-in-MOV, return a
  • * low score to force expanding the probe window until
  • * mpegps_probe finds what it needs */
  • return 5;
  • }else
  • /* Keep looking */
  • offset+=2;
  • }
  • }
  • return score;
  • }

对于像TS这种流媒体格式,通常通过0x47同步字节和pid判断,FFmpeg中ts的探测函数如下:

  • //libavformat/mpegts.c
  • static int analyze(const uint8_t *buf, int size, int packet_size,
  • int probe)
  • {
  • int stat[TS_MAX_PACKET_SIZE];
  • int stat_all = 0;
  • int i;
  • int best_score = 0;
  • memset(stat, 0, packet_size * sizeof(*stat));
  • for (i = 0; i < size - 3; i++) {
  • if (buf[i] == 0x47) {
  • int pid = AV_RB16(buf+1) & 0x1FFF;
  • int asc = buf[i + 3] & 0x30;
  • if (!probe || pid == 0x1FFF || asc) {
  • int x = i % packet_size;
  • stat[x]++;
  • stat_all++;
  • if (stat[x] > best_score) {
  • best_score = stat[x];
  • }
  • }
  • }
  • }
  • return best_score - FFMAX(stat_all - 10*best_score, 0)/10;
  • }
  • static int mpegts_probe(AVProbeData *p)
  • {
  • const int size = p->buf_size;
  • int maxscore = 0;
  • int sumscore = 0;
  • int i;
  • int check_count = size / TS_FEC_PACKET_SIZE;
  • #define CHECK_COUNT 10
  • #define CHECK_BLOCK 100
  • if (!check_count)
  • return 0;
  • for (i = 0; i<check_count; i+=CHECK_BLOCK) {
  • int left = FFMIN(check_count - i, CHECK_BLOCK);
  • int score = analyze(p->buf + TS_PACKET_SIZE *i, TS_PACKET_SIZE *left, TS_PACKET_SIZE , 1);
  • int dvhs_score = analyze(p->buf + TS_DVHS_PACKET_SIZE*i, TS_DVHS_PACKET_SIZE*left, TS_DVHS_PACKET_SIZE, 1);
  • int fec_score = analyze(p->buf + TS_FEC_PACKET_SIZE *i, TS_FEC_PACKET_SIZE *left, TS_FEC_PACKET_SIZE , 1);
  • score = FFMAX3(score, dvhs_score, fec_score);
  • sumscore += score;
  • maxscore = FFMAX(maxscore, score);
  • }
  • sumscore = sumscore * CHECK_COUNT / check_count;
  • maxscore = maxscore * CHECK_COUNT / CHECK_BLOCK;
  • ff_dlog(0, "TS score: %d %d\n", sumscore, maxscore);
  • if (check_count > CHECK_COUNT && sumscore > 6) {
  • return AVPROBE_SCORE_MAX + sumscore - CHECK_COUNT;
  • } else if (check_count >= CHECK_COUNT && sumscore > 6) {
  • return AVPROBE_SCORE_MAX/2 + sumscore - CHECK_COUNT;
  • } else if (check_count >= CHECK_COUNT && maxscore > 6) {
  • return AVPROBE_SCORE_MAX/2 + sumscore - CHECK_COUNT;
  • } else if (sumscore > 6) {
  • return 2;
  • } else {
  • return 0;
  • }
  • }
方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门