当前位置: 首页 > news >正文

ffmpeg 问答系列


author: hjjdebug
date: 2025年 08月 23日 星期六 17:46:02 CST
descript: ffmpeg 问答系列.


文章目录

  • 问1: 流有类别和类型之说吗? 例如 pes 中的 0xe0, 0xc0 是什么?
  • 问2: 怎样区分流是音频流,视频流,或者数据流?
  • 问3: 怎样知道流的索引号? 流的索引号到底是什么意思?
  • 问4. codecpar->codec_id 从哪里来的? 是从codec 来的吗?
  • 问5: 音视频 codec_context 信息又从哪里来?
  • 回答第二个问题: ffmpeg读文件时, 流的索引信息是从哪里来的?

ffmpeg 中有些概念, 需要辨析一下, 逐步完善吧.

问1: 流有类别和类型之说吗? 例如 pes 中的 0xe0, 0xc0 是什么?

pes 中的 0xe0,0xc0 是 “流的ID”,
这些标识符被称为"流ID"(Stream ID)。在PES流中,流ID位于包头字段,用于区分负载内容类型
PES包头包含固定包头(6字节)和可选包头,其中"Stream ID"字段占用8位(1字节),
用于标识负载内容类型。例如:
"0xe0"对应视频帧
"0xc0"对应音频帧

私有数据:可能使用其他流ID(如0xf0),需结合具体协议定义

音频流,视频流,数据流这些概念是什么呢? 这是媒体类型. 说它是流的类型似乎不准确.

问2: 怎样区分流是音频流,视频流,或者数据流?

ffmpeg 通过codec->type 来区分. ,无codec 就是数据流, 那codec->type 又从哪里来? 从定义中来.
举个例子: 例如: AV_CODEC_ID_MPEG2VIDEO. 其codec 是
在libavcodec/mpeg12enc.c 中定义
const FFCodec ff_mpeg2video_encoder = {
.p.name = “mpeg2video”,
CODEC_LONG_NAME(“MPEG-2 video”),
.p.type = AVMEDIA_TYPE_VIDEO, //这个是流的type
.p.id = AV_CODEC_ID_MPEG2VIDEO, //这个是流的ID
… }
可见codec 把codec.type,codec.id 绑定在一起.
当我们依据id找到codec时, 其codec的类型也已经确定.
注意, codec_id 和 流的id 是不同的! 但它们是有关联的,后面有说明.
例如通过调用get_dvb_stream_type(s,st), 依据st->codecpar->codec_id可找到对应的stream_type
stream->codecparamter->codec_id 一般就等于找到的codec中定义的id

问3: 怎样知道流的索引号? 流的索引号到底是什么意思?

在FFmpeg中可通过AVFormatContext->streams[i]->index获取索引号,
其中i为流的顺序号.
那streams[i]->index 又是从哪里来的?

我们从创建AVFormatContext 来找一找出路. 开始的时候是没有stream的,
然后我们添加了一个stream(用:avformat_new_stream). 这第一个stream->index 就是0,
再创建一个stream ,stream->index 就是1… 依次类推.
它记录的就是stream 创建的顺序.

那这个顺序信息保留到哪里了呢? 我们读一个文件时怎样获得流的索引信息呢?
先解释第一句话:
在写文件pmt 时 调用 mpegts_write_pmt

static int mpegts_write_pmt(AVFormatContext* s, MpegTSService* service)
{MpegTSWrite* ts = s->priv_data;uint8_t data[SECTION_LENGTH], *q, *desc_length_ptr ;int val, stream_type, i, err = 0;....for (i = 0; i < s->nb_streams; i++) //然后进入循环, 依次写包含的stream 信息{AVStream* st = s->streams[i];   //枚举每一个streamMpegTSWriteStream* ts_st = st->priv_data;// 问codecpar->codec_id 从哪里来的? 是从codec 来的吗?enum AVCodecID codec_id = st->codecpar->codec_id; //get_dvb_stream_type: 从codecpar->codec_id 可以找到对应的stream_type
// 例如如下代码
//
//    switch (st->codecpar->codec_id)
//    {
//    case AV_CODEC_ID_MPEG1VIDEO:
//    case AV_CODEC_ID_MPEG2VIDEO:
//        stream_type = STREAM_TYPE_VIDEO_MPEG2;
//        break;stream_type = ts->m2ts_mode ? get_m2ts_stream_type(s, st) : get_dvb_stream_type(s, st);// stream_type 是写在pmt 表中的流类型*q++ = stream_type;                 //写stream_typeput16(&q, 0xe000 | ts_st->pid);     //写stream -> piddesc_length_ptr = q;q += 2; /* patched after *//* write optional descriptors here */switch (st->codecpar->codec_type)   // 写可选的描述符{case AVMEDIA_TYPE_AUDIO:......break;case AVMEDIA_TYPE_SUBTITLE:......break;case AVMEDIA_TYPE_VIDEO:......break;case AVMEDIA_TYPE_DATA:......break;}val = 0xf000 | (q - desc_length_ptr - 2);  //描述符长度可能为0desc_length_ptr[0] = val >> 8;desc_length_ptr[1] = val;}mpegts_write_section1(&service->pmt, PMT_TID, service->sid, ts->tables_version, 0, 0,data, q - data);return 0;
}

可见stream->index 并没有使用, write_pmt 只是按顺序写入streams[i]信息.
所以这个顺序就是index 的信息.

问4. codecpar->codec_id 从哪里来的? 是从codec 来的吗?

答: 虽然是一致的,但来历还有点复杂,
codecpar->codec_id 是从codec_context 中来的.
通过调用 avcodec_parameters_from_context()得到.
这里context 用了名称codec, 不太准确,凑合看吧,保持原色原味. 如下:

int avcodec_parameters_from_context(AVCodecParameters *par, const AVCodecContext *codec)par->codec_type = codec->codec_type;par->codec_id   = codec->codec_id;par->codec_tag  = codec->codec_tag;
...

而调用avcodec_parameters_from_context 是用户调用的代码, 所以要想把codec_paramters搞对,
必需要调用这个接口. 它放到了open_video或open_audio 中,
如果你要open_data,也要把AVCodecParameters 要搞对.
由于data_stream 没有codec_context, 那就直接手工设置CodecParameters

问5: 音视频 codec_context 信息又从哪里来?

是用户编写的代码, codec_context 信息大部分来自codec, 还有一部分手工编写
查代码发现,
在add_stream 时,
根据codec_id 查找codec, AVCodec codec = avcodec_find_encoder(codec_id);
根据codec,创建codec_context AVCodecContext
c_ctx = avcodec_alloc_context3(codec);
c_ctx->codec_id = codec_id; //手工付值的.
可见, context 中的codec_id, 就是codec中定义的id


回答第二个问题: ffmpeg读文件时, 流的索引信息是从哪里来的?


调用栈:
0 in avformat_new_stream of libavformat/options.c:321
1 in pmt_cb of libavformat/mpegts.c:2626
2 in write_section_data of libavformat/mpegts.c:507
3 in handle_packet of libavformat/mpegts.c:3053
4 in handle_packets of libavformat/mpegts.c:3233
5 in mpegts_read_header of libavformat/mpegts.c:3364
6 in avformat_open_input of libavformat/demux.c:316
7 in main of main.cpp:35

//AVCodec *c 没有使用, 下面是简化版,删掉了一些次要信息包括sti的信息

AVStream *avformat_new_stream(AVFormatContext *s, const AVCodec *c)
{FFFormatContext *const si = ffformatcontext(s);FFStream *sti; //内部的stream AVStream *st;  //暴露给外部的stream信息//把s->streams 扩充出一个位置s->streams = av_realloc_array(s->streams, s->nb_streams + 1, sizeof(*streams));sti = av_mallocz(sizeof(*sti));  //删除了sti 中的一些信息赋值,例如pts 一类st = &sti->pub;st->av_class = &stream_class;st->codecpar = avcodec_parameters_alloc(); //为stream 分配codec_parametersif (s->iformat) {avpriv_set_pts_info(st, 33, 1, 90000);} st->index      = s->nb_streams;        //我们看到,st->index, 就是当时的 nb_streams 个数st->start_time = AV_NOPTS_VALUE;st->duration   = AV_NOPTS_VALUE;st->sample_aspect_ratio = (AVRational) { 0, 1 };s->streams[s->nb_streams++] = st;return st;
fail:ff_free_stream(&st);return NULL;
}

这个调用链, pmt_cb, write_section_data,handle_packet,handle_packets 还是很关键的代码.
如果必要,最好搞懂这些代码.
再强调一下, st->index, 就是你 avformat_new_stream 的顺序,依次长上来的.

http://www.dtcms.com/a/346964.html

相关文章:

  • 《三驾马车:MySQL、MongoDB、Redis对比与融合实战》
  • 可视化-模块1-HTML-01
  • UniAD
  • 电容反射特性
  • Linux netfilter工作原理详解
  • Spring Boot 整合网易163邮箱发送邮件实现找回密码功能
  • 数据库MVCC是什么
  • 每日算法题【链表】:链表的中间节点、返回倒数第k个节点、合并两个有序链表
  • Git checkout 与 Git reset 核心区别解析(分支与版本关联逻辑)
  • C语言初学者笔记【动态内存管理】
  • 在WSL2 Ubuntu中部署FastDFS服务的完整指南
  • Elasticsearch底层存储原理
  • Codeforces Round 1043 (Div. 3)(A-E)
  • 数据库优化提速(三)JSON数据类型在酒店管理系统搜索—仙盟创梦IDE
  • jetson ubuntu 打不开 firefox和chromium浏览器
  • 非线性规划学习笔记
  • SpringBootWeb入门
  • 力扣(全排列)
  • 生成模型 | 扩散模型损失函数公式推导
  • Go语言数据结构与算法-基础数据结构
  • 《WinRAR》 [7.12] [x64] 烈火版 下载
  • 数据结构的线性表:顺序表
  • piecewise jerk算法介绍
  • 2025年音乐创作大模型有哪些?国内国外模型汇总以及优点分析
  • 高阶数据结构---ST表
  • 同类软件对比(一):Visual Studio(IDE) VS Visual Studio Code
  • [CISCN2019 华北赛区 Day1 Web5]CyberPunk
  • MySQL存储过程入门
  • OCR、文档解析工具合集(下)
  • MySQL InnoDB引擎