☰
Linux FFmpeg深度解析之av_find_best_stream调用流程与实战(四)
2026/10/28 1:51:11 网站建设 项目流程

简介:CSDN博客专家、《Android系统多媒体进阶实战》作者

博主新书推荐:《Android系统多媒体进阶实战》🚀
Android Audio工程师专栏地址:Audio工程师进阶系列【原创干货持续更新中……】🚀
Android多媒体专栏地址:多媒体系统工程师系列【原创干货持续更新中……】🚀
专题一 二:AAOS车载系统+AOSP14系统攻城狮入门视频实战课🚀
专题三:Android14 Binder之HIDL与AIDL通信实战课🚀
专题四:Android15快速自定义与集成音效实战课🚀
专题五:Android15音频策略实战课🚀
专题六:Android15音频性能实战课(无声/杂音/断音/爆音实战案例)🚀

人生格言:人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.

更多原创,欢迎关注:Android系统攻城狮

点击获取二维码


🍉🍉🍉文章目录🍉🍉🍉

      • 🌻1.前言
      • 🌻2.应用场景和用法
        • 2.1按媒体类型选择目标流
        • 2.2函数原型与返回语义
      • 🌻3.调用流程剖析
        • 3.1筛选候选流并按优先级比较
        • 3.2流选择与解码器创建的边界
      • 🌻4.实战案例
        • 4.1打开输入并准备流信息
        • 4.2检查选择结果并读取对应包
        • 4.3完整代码
      • 🌻5.总结

🌻1.前言

本篇目的:理解av_find_best_stream()如何按照媒体类型和流信息选择候选流,说明返回索引与可选解码器之间的关系,并用音频输入示例检查选择结果。

一个媒体文件可以包含多条视频、音频或字幕流。应用需要先选定目标流,才能创建对应的解码器上下文并处理该流的包。av_find_best_stream()负责选择流索引,并可选地返回匹配的解码器;它不打开解码器,也不读取后续媒体包。

已读取流信息的AVFormatContext

av_find_best_stream

按媒体类型筛选候选流

返回流索引和可选解码器

应用创建解码路径

🌻2.应用场景和用法

2.1按媒体类型选择目标流

应用可在打开输入并读取流信息后,按媒体类型选择一路默认音频、视频或字幕流。选出的流索引可用于定位AVStream,再读取其中的codecpar配置解码器。

使用场景调用方式结果
选择默认视频流type设为AVMEDIA_TYPE_VIDEO返回选中视频流的索引
选择默认音频流type设为AVMEDIA_TYPE_AUDIO返回选中音频流的索引
指定流索引wanted_stream_nb传入非负索引只尝试该索引对应的流
优先选择同节目流设置related_stream,并令wanted_stream_nb为-1若关联节目存在,先在该节目范围内搜索
同时获取解码器decoder_ret传入有效指针成功时一并返回可用的AVCodec
2.2函数原型与返回语义

函数原型如下:

intav_find_best_stream(AVFormatContext*ic,enumAVMediaTypetype,intwanted_stream_nb,intrelated_stream,constAVCodec**decoder_ret,intflags);
参数含义
ic已打开并包含流信息的格式上下文
type要选择的媒体类型
wanted_stream_nb指定流索引;传入-1表示自动选择
related_stream用于优先搜索同一节目中相关流的索引;不指定时传入-1
decoder_ret可选的解码器输出指针;不需要函数检查解码器时可传入NULL
flags当前没有定义可用标志,通常传入0

函数成功时返回非负流索引。没有匹配类型的流时返回AVERROR_STREAM_NOT_FOUND;找到流但要求解码器、且没有可用解码器时返回AVERROR_DECODER_NOT_FOUND。

decoder_ret为非空时,函数成功返回就保证该指针指向有效的AVCodec。它只返回解码器描述对象,不会分配AVCodecContext,也不会调用avcodec_open2()。

🌻3.调用流程剖析

3.1筛选候选流并按优先级比较

在FFmpeg6.1实现中,函数遍历上下文中的流;当指定related_stream且未指定固定流索引时,如果能找到对应节目,就先在该节目包含的流索引范围内搜索。

每个候选流先按codecpar->codec_type与请求类型匹配。指定了wanted_stream_nb时,其他索引会被跳过。音频候选还要求声道布局和采样率有效。

若decoder_ret非空,函数会查找候选流的默认解码器;找不到解码器的候选流不会被选中。其余候选流按流Disposition、已读取的编解码帧数和码率等信息比较,最终返回优先级最高的流索引。

是

否

AVFormatContext中的流

按节目范围和指定索引筛选

匹配媒体类型和必要参数

是否要求解码器

查找候选流的默认解码器

直接参与流优先级比较

比较Disposition帧数和码率

返回流索引和可选解码器

3.2流选择与解码器创建的边界

典型调用顺序是先使用avformat_open_input()打开输入,再调用avformat_find_stream_info()读取流信息,然后使用av_find_best_stream()选流。

av_find_best_stream()本身不会调用av_read_frame()读取媒体包,也不会创建解码器上下文。应用需要用返回索引访问ic->streams[index],再将该流的codecpar复制到AVCodecContext并打开解码器。

如果decoder_ret传入NULL,函数不会因为缺少解码器而跳过候选流;如果传入非空指针,则解码器是否可用会参与候选筛选。指定固定流索引时,选择也不会自动改用其他流。

🌻4.实战案例

4.1打开输入并准备流信息

程序接收一个媒体文件路径,打开输入并读取流信息。它请求选择默认音频流,并让函数同时返回该流的默认解码器。

4.2检查选择结果并读取对应包

程序通过返回索引取得AVStream,打印流索引和解码器名称。随后调用av_read_frame()遍历输入,只统计stream_index等于选中索引的包,以确认流选择结果与实际解封装包相对应。

4.3完整代码
#include<libavcodec/avcodec.h>#include<libavformat/avformat.h>#include<libavutil/error.h>#include<stdio.h>intmain(intargc,char**argv){AVFormatContext*fmt_ctx=NULL;AVPacket*pkt=NULL;constAVCodec*decoder=NULL;AVStream*audio_stream;intaudio_index;intret;intread_ret;int64_taudio_packet_count=0;if(argc<2){fprintf(stderr,"Usage: %s input\n",argv[0]);return1;}/* 打开输入并读取流信息,供后续候选筛选使用 */ret=avformat_open_input(&fmt_ctx,argv[1],NULL,NULL);if(ret<0)gotoend;ret=avformat_find_stream_info(fmt_ctx,NULL);if(ret<0)gotoend;/* 自动选择音频流,并同时要求返回可用解码器 */audio_index=av_find_best_stream(fmt_ctx,AVMEDIA_TYPE_AUDIO,-1,-1,&decoder,0);if(audio_index<0){ret=audio_index;gotoend;}/* 返回值是流索引,解码器仍未打开 */audio_stream=fmt_ctx->streams[audio_index];printf("audio stream index=%d codec=%s\n",audio_index,decoder->name);pkt=av_packet_alloc();if(pkt==NULL){ret=AVERROR(ENOMEM);gotoend;}/* 通过包上的stream_index验证被选中的流 */while((read_ret=av_read_frame(fmt_ctx,pkt))>=0){if(pkt->stream_index==audio_stream->index)audio_packet_count++;av_packet_unref(pkt);}if(read_ret==AVERROR_EOF){printf("selected audio packet count=%lld\n",(longlong)audio_packet_count);ret=0;}else{ret=read_ret;}end:av_packet_free(&pkt);avformat_close_input(&fmt_ctx);returnret<0?1:0;}

🌻5.总结

av_find_best_stream()根据媒体类型和流信息选择流索引,并可选返回默认解码器,但不创建解码器上下文或读取媒体包。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询