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

news/2024/12/22 14:21:10 标签: 音视频, ffmpeg

一、引言

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

./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:

    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函数:

        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函数:

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函数代码如下:

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:

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:

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函数中将视频压缩编码格式打印出来:

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属性获取视频帧率的实现》)。


http://www.niftyadmin.cn/n/5795433.html

相关文章

Redis——缓存预热+缓存雪崩+缓存击穿+缓存穿透

文章目录 1、 缓存预热2、 缓存雪崩3、 缓存击穿4、 缓存穿透总结 1、 缓存预热 什么是预热&#xff1a; mysql加入新增100条记录&#xff0c;一般默认以mysql为准作为底单数据&#xff0c;如何同步给redis&#xff08;布隆过滤器&#xff09;这100条新数据。 为什么需要预热…

网络直播带货查询系统设计与实现:SSM + JAVA 核心架构与 JSP 支撑

第四章 系统设计 4.1 系统体系结构 网络直播带货网站的结构图4-1所示&#xff1a; 图4-1 系统结构 模块包括主界面&#xff0c;主页、个人中心、用户管理、商品分类管理、商品信息管理、系统管理、订单管理等进行相应的操作。 登录系统结构图&#xff0c;如图4-2所示&#xf…

Suno Api V4模型无水印开发「高清音频WAV下载」 —— 「Suno Api系列」第6篇

历史文章 Suno AI API接入 - 将AI音乐接入到自己的产品中&#xff0c;支持120并发任务 Suno Api V4模型无水印开发「灵感模式」 —— 「Suno Api系列」第1篇 Suno Api V4模型无水印开发「自定义模式」 —— 「Suno Api系列」第2篇 Suno Api V4模型无水印开发「AI生成歌词」…

python:正则表达式

正则表达式&#xff08;Regular Expressions&#xff0c;简称 regex&#xff09;是一种强大的文本处理工具&#xff0c;用于匹配字符串中的字符组合。Python 提供了 re 模块来支持正则表达式的操作。以下是一些常用的正则表达式操作和示例&#xff1a; 导入 re 模块 首先&…

Docker dockerfile镜像编码 centos7

一、 大多数docker基础镜像使用locale查看编码&#xff0c;发现默认编码都是POSIX&#xff0c;这会导致中文乱码。 解决方法如下: 二、首先使用locale -a查看容器所有语言环境 三、dockerfile中加入以下参数重新生成镜像   ENV LANGen_US.UTF-8   ENV TZAsia/Shanghai  …

四川托普信息技术职业学院教案1

四川托普信息技术职业学院教案 【计科系】 周次 第 1周&#xff0c;第1次课 备 注 章节名称 第1章 XML语言简介 引言 1.1 HTML与标记语言 1.2 XML的来源 1.3 XML的制定目标 1.4 XML概述 1.5 有了HTML了&#xff0c;为什么还要发展XML 1.5.1 HTML的缺点 1.5.2 XML的特点 1.6 X…

常见八股文03

35.autowired、qualifier和Resource区别 Autowired&#xff1a;基于类型的注入 Qualifier&#xff1a;基于名称进行注入 Resource:按名称装配注入&#xff0c;如果找不到与名称匹配的bean&#xff0c;则按类型装配注入&#xff0c;可以用于字段和方法上 36.代理模式 动态代…

重拾设计模式-外观模式和适配器模式的异同

文章目录 目的不同适配器模式&#xff1a;外观模式&#xff1a; 结构和实现方式不同适配器模式&#xff1a;外观模式&#xff1a; 对客户端的影响不同适配器模式&#xff1a;外观模式&#xff1a; 目的不同 适配器模式&#xff1a; 主要目的是解决两个接口不兼容的问题&#…