音视频入门基础:MPEG2-TS专题(21)——FFmpeg源码中,获取TS流的视频信息的实现

一、引言

通过FFmpeg命令可以获取到TS文件/TS流的视频压缩编码格式、色彩格式(像素格式)、分辨率、帧率信息:

cpp 复制代码
./ffmpeg -i XXX.ts

本文以H.264为例讲述FFmpeg到底是从哪个地方获取到这些视频信息的。

二、视频压缩编码格式

FFmpeg获取TS文件/TS流的视频压缩编码格式,是从PMT表的stream_type属性中获取的。由《音视频入门基础:MPEG2-TS专题(16)------PMT简介》可以知道,TS文件/TS流的PMT表中存在一个占8位的stream_type属性,表示媒体流的类型,即音视频压缩编码格式:

由《音视频入门基础:MPEG2-TS专题(17)------FFmpeg源码中,解析TS program map section的实现》可以知道,FFmpeg源码中使用pmt_cb函数解析PMT表中的TS program map section。pmt_cb函数会通过下面代码块将stream_type属性提取出来,赋值给变量stream_type:

cpp 复制代码
    for (i = 0; i < MAX_STREAMS_PER_PROGRAM; i++) {
        st = 0;
        pes = NULL;
        stream_type = get8(&p, p_end);
        if (stream_type < 0)
            break;
    //...
}

然后pmt_cb函数中,会调用mpegts_set_stream_info函数:

cpp 复制代码
        if (pes && !pes->stream_type)
            mpegts_set_stream_info(st, pes, stream_type, prog_reg_desc);

mpegts_set_stream_info函数内部又会将上述得到的stream_type属性赋值给变量pes->stream_type,然后调用mpegts_find_stream_type函数:

cpp 复制代码
static int mpegts_set_stream_info(AVStream *st, PESContext *pes,
                                  uint32_t stream_type, uint32_t prog_reg_desc)
{
//...
    pes->stream_type = stream_type;
//...
    mpegts_find_stream_type(st, pes->stream_type, ISO_types);
//...
}

mpegts_find_stream_type函数代码如下:

cpp 复制代码
static void mpegts_find_stream_type(AVStream *st,
                                    uint32_t stream_type,
                                    const StreamType *types)
{
    FFStream *const sti = ffstream(st);
    for (; types->stream_type; types++)
        if (stream_type == types->stream_type) {
            if (st->codecpar->codec_type != types->codec_type ||
                st->codecpar->codec_id   != types->codec_id) {
                st->codecpar->codec_type = types->codec_type;
                st->codecpar->codec_id   = types->codec_id;
                sti->need_context_update = 1;
            }
            sti->request_probe = 0;
            return;
        }
}

ISO_types是一个数组,根据上述表格将stream_type属性和音视频压缩编码格式对应起来。所以调用mpegts_find_stream_type函数后,st->codecpar->codec_type,即AVCodecParameters的codec_id会得到该stream_type属性对应的音视频压缩编码格式。比如stream_type的值为0x1B,那对应的视频压缩编码格式就是H.264:

cpp 复制代码
static const StreamType ISO_types[] = {
    { 0x01, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_MPEG2VIDEO },
    { 0x02, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_MPEG2VIDEO },
    { 0x03, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_MP3        },
    { 0x04, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_MP3        },
    { 0x0f, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AAC        },
    { 0x10, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_MPEG4      },
    /* Makito encoder sets stream type 0x11 for AAC,
     * so auto-detect LOAS/LATM instead of hardcoding it. */
#if !CONFIG_LOAS_DEMUXER
    { 0x11, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AAC_LATM   }, /* LATM syntax */
#endif
    { 0x1b, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_H264       },
    { 0x1c, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AAC        },
    { 0x20, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_H264       },
    { 0x21, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_JPEG2000   },
    { 0x24, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_HEVC       },
    { 0x33, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_VVC        },
    { 0x42, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_CAVS       },
    { 0xd1, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_DIRAC      },
    { 0xd2, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_AVS2       },
    { 0xd4, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_AVS3       },
    { 0xea, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_VC1        },
    { 0 },
};

然后在pmt_cb函数外部,通过avcodec_parameters_to_context函数将AVCodecParameters的codec_id赋值给AVCodecContext的codec_id:

cpp 复制代码
int avcodec_parameters_to_context(AVCodecContext *codec,
                                  const AVCodecParameters *par)
{
//...
    codec->codec_id   = par->codec_id;
//...
}

然后在dump_stream_format函数中,通过avcodec_string函数中的语句:codec_name = avcodec_get_name(enc->codec_id) 拿到AVCodecContext的codec_id对应的视频压缩编码格式名称。最后再在dump_stream_format函数中将视频压缩编码格式打印出来:

cpp 复制代码
void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode)
{
//...
    codec_name = avcodec_get_name(enc->codec_id);
//...
}

所以FFmpeg获取TS文件/TS流的视频压缩编码格式,是根据PMT表的stream_type属性获取的:

三、视频压缩编码格式的profile

如果TS文件/TS流中的视频压缩编码格式为H.264,FFmpeg获取其视频压缩编码格式的profile,是通过SPS的profile_idc属性获取到的,具体可以参考:《音视频入门基础:H.264专题(17)------FFmpeg源码中,获取H.264视频的profile的实现》:

四、视频的色彩格式

如果TS文件/TS流中的视频压缩编码格式为H.264,FFmpeg获取其视频的色彩格式,是通过SPS中的属性chroma_format_idc获取到的,具体可以参考:《音视频入门基础:H.264专题(13)------FFmpeg源码中通过SPS属性获取视频色彩格式的实现》:

五、视频分辨率

如果TS文件/TS流中的视频压缩编码格式为H.264,FFmpeg获取其视频分辨率,是通过SPS中的属性获取的,具体可以参考:《音视频入门基础:H.264专题(12)------FFmpeg源码中通过SPS属性计算视频分辨率的实现》:

六、视频码率

由于TS文件/TS流的文件格式(包括TS Header、PES packet header)不包含视频码率信息,所以无法通过FFmpeg直接获取到其视频码率。与之对应,由于FLV文件的Script Tag中包含视频码率信息,所以FFmpeg可以直接打印FLV文件的视频码率,具体可以参考:《音视频入门基础:FLV专题(24)------FFmpeg源码中,获取FLV文件视频信息的实现》。

七、视频帧率

如果TS文件/TS流中的视频压缩编码格式为H.264,对其视频进行编解码时,FFmpeg源码内部使用的是通过SPS中的属性计算得到的视频帧率(具体可以参考:《音视频入门基础:H.264专题(15)------FFmpeg源码中通过SPS属性获取视频帧率的实现》)。

相关推荐
美狐美颜SDK开放平台3 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
2601_955662463 天前
短剧多人对白怎么配?2026年多角色配音工具对比
大数据·人工智能·音视频·语音识别
开发笔记-阿牛3 天前
蓝牙音乐灯拆解,又一次拆到蓝牙音乐灯芯片CK6865L
人工智能·单片机·嵌入式硬件·音视频·音频
旺仔小馒头wang3 天前
AI 智能手机发布会:赋予人类的五种新能力
人工智能·学习·音视频
纳祥科技3 天前
拆机拆到芯片级:ARC功放机里的NX7026、NX8420、NX6805
单片机·音视频·智能音箱
youandyouyou3 天前
律所内部培训共享的内网部署方案:架构、参数与三步落地
音视频
爱吃提升3 天前
文生视频核心
人工智能·音视频
2601_955662463 天前
抖音视频怎么做多语言配音?2026年AI配音工具与制作流程详解
人工智能·音视频·语音识别·视频
音视频牛哥3 天前
Android与HarmonyOS NEXT如何接入GB28181:从SIP到PS/RTP的完整链路
音视频·gb28181-2022对接·鸿蒙next gb28181·gb/t 28181-2022·gb/t 28181-2016·gb28181-2022平台
美狐美颜SDK开放平台3 天前
直播APP源码与视频美颜sdk如何配合?一套完整开发思路
android·人工智能·计算机视觉·音视频·直播美颜sdk