红色基调网站,曲阜人网站,网站开发需要逻辑吗,wordpress目录阅览一、引言
通过FFmpeg命令#xff1a;
./ffmpeg -i XXX.ps
可以判断出某个文件是否为PS文件#xff1a; 所以FFmpeg是怎样判断出某个文件是否为PS文件呢#xff1f;它内部其实是通过mpegps_probe函数来判断的。从《FFmpeg源码#xff1a;av_probe_input_format3函数和AVI…一、引言
通过FFmpeg命令
./ffmpeg -i XXX.ps
可以判断出某个文件是否为PS文件 所以FFmpeg是怎样判断出某个文件是否为PS文件呢它内部其实是通过mpegps_probe函数来判断的。从《FFmpeg源码av_probe_input_format3函数和AVInputFormat结构体分析FFmpeg源码5.0.3版本》和《7.0.1版本的FFmpeg源码中av_probe_input_format3函数和AVInputFormat结构体的改变》
中可以知道FFmpeg源码中实现容器格式检测的函数是av_probe_input_format3函数其内部通过循环while ((fmt1 av_demuxer_iterate(i))) 拿到所有容器格式对应的AVInputFormat结构然后通过score fmt1-read_probe(lpd)语句执行不同容器格式对应的解析函数根据是否能被解析以及匹配程度来判断出这是哪种容器格式。而PS文件对应的解析函数就是mpegps_probe函数。 二、mpegps_probe函数的定义
mpegps_probe函数定义在FFmpeg源码本文演示用的FFmpeg源码版本为7.0.1的源文件libavformat/mpeg.c中
static int mpegps_probe(const AVProbeData *p)
{uint32_t code -1;int i;int sys 0, pspack 0, priv1 0, vid 0;int audio 0, invalid 0, score 0;int endpes 0;for (i 0; i p-buf_size; i) {code (code 8) p-buf[i];if ((code 0xffffff00) 0x100) {int len p-buf[i 1] 8 | p-buf[i 2];int pes endpes i check_pes(p-buf i, p-buf p-buf_size);int pack check_pack_header(p-buf i);if (code SYSTEM_HEADER_START_CODE)sys;else if (code PACK_START_CODE pack)pspack;else if ((code 0xf0) VIDEO_ID pes) {endpes i len;vid;}// skip pes payload to avoid start code emulation for private// and audio streamselse if ((code 0xe0) AUDIO_ID pes) {audio; ilen;}else if (code PRIVATE_STREAM_1 pes) {priv1; ilen;}else if (code 0x1fd pes) vid; //VC1else if ((code 0xf0) VIDEO_ID !pes) invalid;else if ((code 0xe0) AUDIO_ID !pes) invalid;else if (code PRIVATE_STREAM_1 !pes) invalid;}}if (vid audio invalid 1) /* invalid VDR files nd short PES streams */score AVPROBE_SCORE_EXTENSION / 2;// av_log(NULL, AV_LOG_ERROR, vid:%d aud:%d sys:%d pspack:%d invalid:%d size:%d \n,
// vid, audio, sys, pspack, invalid, p-buf_size);if (sys invalid sys * 9 pspack * 10)return (audio 12 || vid 3 || pspack 2) ? AVPROBE_SCORE_EXTENSION 2: AVPROBE_SCORE_EXTENSION / 2 (audio vid pspack 1); // 1 more than mp3if (pspack invalid (priv1 vid audio) * 10 pspack * 9)return pspack 2 ? AVPROBE_SCORE_EXTENSION 2: AVPROBE_SCORE_EXTENSION / 2; // 1 more than .mpgif ((!!vid ^ !!audio) (audio 4 || vid 1) !sys !pspack p-buf_size 2048 vid audio invalid) /* PES stream */return (audio 12 || vid 6 2 * invalid) ? AVPROBE_SCORE_EXTENSION 2: AVPROBE_SCORE_EXTENSION / 2;// 02-Penguin.flac has sys:0 priv1:0 pspack:0 vid:0 audio:1// mp3_misidentified_2.mp3 has sys:0 priv1:0 pspack:0 vid:0 audio:6// Have\ Yourself\ a\ Merry\ Little\ Christmas.mp3 0 0 0 5 0 1 len:21618return score;
}
该函数的作用就是检测某个文件是否为PS文件。 形参p输入型参数为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; p-filename为需要被推测格式的文件的路径。
p-buf指向“存放从路径为p-filename的PS文件中读取出来的二进制数据”的缓冲区。
p-buf_size缓冲区p-buf的大小单位为字节。注FFmpeg判断某个文件的格式时不会读取完整个文件只会读取它前面的一部分比如最开始的2048个字节。只要根据前面的这些字节就足够判断出它的格式了所以p-buf_size的值一般就是2048。
p-mime_type一般为NULL可忽略。
返回值返回一个类型为整形的分值。返回0表示该文件完全不符合PS格式。返回的值越接近100表示该文件越符合PS格式。 三、mpegps_probe函数的内部实现分析
mpegps_probe函数中首先会定义整形变量。其中变量sys表示这段长度为p-buf_size的码流中system header的个数pspack为这段码流中pack header的个数priv1为这段码流中私有流的个数vid为这段码流中视频流的个数 int sys 0, pspack 0, priv1 0, vid 0; 不断读取出存放在数组p-buf[i]中的二进制码流数据 for (i 0; i p-buf_size; i) {code (code 8) p-buf[i];if ((code 0xffffff00) 0x100) {//...}} 宏SYSTEM_HEADER_START_CODE定义在libavformat/mpeg.h中值为0x000001bb表示system header的起始码system header的system_header_start_code属性
#define SYSTEM_HEADER_START_CODE ((unsigned int)0x000001bb) 根据是否是system header的起始码判断是否读取到了PS流的system header如果读取到了让变量sys的值加1 if (code SYSTEM_HEADER_START_CODE)sys; 宏PACK_START_CODE定义在libavformat/mpeg.h中值为0x000001ba表示pack header的起始码pack header的pack_start_code属性
#define PACK_START_CODE ((unsigned int)0x000001ba) 根据是否是pack header的起始码判断是否读取到了PS流的pack header如果读取到了让变量pspack的值加1 int pack check_pack_header(p-buf i); //...else if (code PACK_START_CODE pack)pspack; 检查是否读取到了PES流。如果读取到了通过PES packet中的stream_id属性判断里面的ES流是否为视频流。如果是视频流让变量vid的值加1 int pes endpes i check_pes(p-buf i, p-buf p-buf_size);//...else if ((code 0xf0) VIDEO_ID pes) {endpes i len;vid;} 返回最终表示符合程度的分数 if (sys invalid sys * 9 pspack * 10)return (audio 12 || vid 3 || pspack 2) ? AVPROBE_SCORE_EXTENSION 2: AVPROBE_SCORE_EXTENSION / 2 (audio vid pspack 1); // 1 more than mp3if (pspack invalid (priv1 vid audio) * 10 pspack * 9)return pspack 2 ? AVPROBE_SCORE_EXTENSION 2: AVPROBE_SCORE_EXTENSION / 2; // 1 more than .mpgif ((!!vid ^ !!audio) (audio 4 || vid 1) !sys !pspack p-buf_size 2048 vid audio invalid) /* PES stream */return (audio 12 || vid 6 2 * invalid) ? AVPROBE_SCORE_EXTENSION 2: AVPROBE_SCORE_EXTENSION / 2;// 02-Penguin.flac has sys:0 priv1:0 pspack:0 vid:0 audio:1// mp3_misidentified_2.mp3 has sys:0 priv1:0 pspack:0 vid:0 audio:6// Have\ Yourself\ a\ Merry\ Little\ Christmas.mp3 0 0 0 5 0 1 len:21618return score; 四、总结
从上面我们可以知道FFmpeg检测某个文件是否为PS文件是通过判断这段码流中读取到的system header、pack header、PES流中视频流的个数等信息实现的。