音视频入门基础:MPEG2-TS专题(6)——FFmpeg源码中,获取MPEG2-TS传输流每个transport packet长度的实现

一、引言

从《音视频入门基础:MPEG2-TS专题(3)------TS Header简介》可以知道,TS格式有三种:分别为transport packet长度固定为188、192和204字节。而FFmpeg源码中是通过get_packet_size函数获取一段MPEG2-TS传输流中每个transport packet的长度,从而判断其是哪种TS格式的。

二、get_packet_size函数的定义

get_packet_size函数定义在FFmpeg源码(本文演示用的FFmpeg源码版本为7.0.1)的源文件libavformat/mpegts.c中:

cpp 复制代码
/* autodetect fec presence */
static int get_packet_size(AVFormatContext* s)
{
    int score, fec_score, dvhs_score;
    int margin;
    int ret;

    /*init buffer to store stream for probing */
    uint8_t buf[PROBE_PACKET_MAX_BUF] = {0};
    int buf_size = 0;
    int max_iterations = 16;

    while (buf_size < PROBE_PACKET_MAX_BUF && max_iterations--) {
        ret = avio_read_partial(s->pb, buf + buf_size, PROBE_PACKET_MAX_BUF - buf_size);
        if (ret < 0)
            return AVERROR_INVALIDDATA;
        buf_size += ret;

        score      = analyze(buf, buf_size, TS_PACKET_SIZE,      0);
        dvhs_score = analyze(buf, buf_size, TS_DVHS_PACKET_SIZE, 0);
        fec_score  = analyze(buf, buf_size, TS_FEC_PACKET_SIZE,  0);
        av_log(s, AV_LOG_TRACE, "Probe: %d, score: %d, dvhs_score: %d, fec_score: %d \n",
            buf_size, score, dvhs_score, fec_score);

        margin = mid_pred(score, fec_score, dvhs_score);

        if (buf_size < PROBE_PACKET_MAX_BUF)
            margin += PROBE_PACKET_MARGIN; /*if buffer not filled */

        if (score > margin)
            return TS_PACKET_SIZE;
        else if (dvhs_score > margin)
            return TS_DVHS_PACKET_SIZE;
        else if (fec_score > margin)
            return TS_FEC_PACKET_SIZE;
    }
    return AVERROR_INVALIDDATA;
}

该函数的作用是:读取s->pb表示的AVIOContext输入缓冲区中存贮的MPEG2-TS传输流数据,判断其每个transport packet长度。

形参s:既是输入型参数也是输出型参数。指向一个AVFormatContext类型变量。

返回值:返回TS_PACKET_SIZE(188)表示这段MPEG2-TS传输流中每个transport packet长度为188字节;返回TS_DVHS_PACKET_SIZE(192)表示transport packet长度为192字节;返回TS_FEC_PACKET_SIZE(204)表示transport packet长度为204字节;返回AVERROR_INVALIDDATA表示出错。

三、get_packet_size函数的内部实现分析

get_packet_size函数中,首先定义一个数组buf用来存贮需要被检测的MPEG2-TS传输流:

cpp 复制代码
    /*init buffer to store stream for probing */
    uint8_t buf[PROBE_PACKET_MAX_BUF] = {0};
    int buf_size = 0;
    int max_iterations = 16;

通过avio_read_partial函数读取需要被检测的MPEG2-TS传输流,存贮到"buf + buf_size"指向的缓冲区中。关于avio_read_partial函数的用法可以参考:《FFmpeg源码:avio_read_partial函数分析》:

cpp 复制代码
        ret = avio_read_partial(s->pb, buf + buf_size, PROBE_PACKET_MAX_BUF - buf_size);
        if (ret < 0)
            return AVERROR_INVALIDDATA;
        buf_size += ret;

检测这段码流符合transport packet长度固定为188字节的TS格式的程度,将对应的分数赋值给变量score。关于analyze函数的用法可以参考:《音视频入门基础:MPEG2-TS专题(5)------FFmpeg源码中,判断某文件是否为TS文件的实现》:

cpp 复制代码
     score      = analyze(buf, buf_size, TS_PACKET_SIZE,      0);

检测这段码流符合transport packet长度固定为192字节的TS格式的程度,将对应的分数赋值给变量dvhs_score:

cpp 复制代码
        dvhs_score = analyze(buf, buf_size, TS_DVHS_PACKET_SIZE, 0);

检测这段码流符合transport packet长度固定为204字节的TS格式的程度,将对应的分数赋值给变量fec_score:

cpp 复制代码
        fec_score  = analyze(buf, buf_size, TS_FEC_PACKET_SIZE,  0);

通过mid_pred函数取score、fec_score、dvhs_score的中位数,赋值给变量margin。关于mid_pred函数的用法可以参考:《FFmpeg源码:mid_pred函数分析》:

cpp 复制代码
        margin = mid_pred(score, fec_score, dvhs_score);

将score、fec_score、dvhs_score分别和它们的中位数进行比较,得到它们的最高分。根据这个最高分,判断这段码流属于哪种TS格式。返回这段MPEG2-TS传输流中每个transport packet的长度:

cpp 复制代码
        if (score > margin)
            return TS_PACKET_SIZE;
        else if (dvhs_score > margin)
            return TS_DVHS_PACKET_SIZE;
        else if (fec_score > margin)
            return TS_FEC_PACKET_SIZE;
相关推荐
大师兄66688 小时前
HarmonyOS7 音视频播放:AVPlayer 实战
音视频·avplayer·harmonyos7
做萤石二次开发的哈哈12 小时前
萤石开放平台如何拉取 RTC 房间成员列表?
音视频·萤石开放平台
离离原上草7713 小时前
Pavo AI Agent 源码深度解析:从自然语言故事到视频分镜的 Multi-Agent 工程实践
人工智能·音视频
YWamy15 小时前
播放器类音视频 SDK 选型指南:主流产品对比与适配建议
音视频
weixin_4462608515 小时前
HumanForge:基于多智能体伪造推理的以人为中心深度伪造视频基准
人工智能·音视频
美狐美颜SDK开放平台16 小时前
从RTC到AI美颜:直播APP开发中的直播美颜SDK技术架构解析
人工智能·音视频·实时音视频·美颜sdk·视频美颜sdk·美颜api
潜创微科技16 小时前
一根网线传 4K60:基于 IT9205 的网线延长方案,把 HDMI 送到 100 米外
音视频
蓝田~17 小时前
AI 图片与视频处理 — 从原理到实践
网络·人工智能·音视频
乐橙开放平台19 小时前
巡店系统笔记:乐橙 listDeviceDetailsByPage 台账 + bindDeviceLive 辅码流最小闭环
网络·笔记·物联网·自动化·音视频·智能家居
鲲穹AI全能助理19 小时前
实用音频合成工具分享:灵境配音 使用场景与功能说明
ffmpeg·音视频