前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【FFmpeg】FFmpeg 播放器框架 ① ( “ 解封装 - 解码 - 播放 过程 “ 涉及到的函数和结构体 | AVFormatContext 结构体详解 )

【FFmpeg】FFmpeg 播放器框架 ① ( “ 解封装 - 解码 - 播放 过程 “ 涉及到的函数和结构体 | AVFormatContext 结构体详解 )

作者头像
韩曙亮
发布2024-09-25 09:41:03
1260
发布2024-09-25 09:41:03
举报
文章被收录于专栏:韩曙亮的移动开发专栏

一、" 解封装 - 解码 - 播放 过程 " 涉及到的函数和结构体

在之前的 【音视频原理】音视频 “ 采样 - 编码 - 封装 过程 “ 和 “ 解封装 - 解码 - 播放 过程 “ 分析 ( 视频采集处理流程 | 音频采集处理流程 | 音视频文件解封装播放流程 ) 博客中 , 介绍了

" 采样 - 编码 - 封装 过程 " 就是音视频录制并压缩的过程 ;

" 解封装 - 解码 - 播放 过程 " 就是音视频解码并播放的过程 ;

下图中详细的列举出了 解封装 过程中 要调用的函数 和 涉及到的 结构体模型 ;

二、AVFormatContext 结构体详解

1、初始化音视频文件格式 - AVFormatContext 结构体

AVFormatContext 是 FFmpeg 库中 的 结构体 , 其中封装了 多媒体文件 或 流的格式 相关信息 ;

FFmpeg 中处理 多媒体文件 或 流 的第一步通常是 创建和初始化 一个 AVFormatContext 结构体 ;

AVFormatContext 定义在 libavformat/avformat.h 头文件中 , 原型如下 :

代码语言:javascript
复制
/**
 * 格式 I/O 上下文。
 * 可以在末尾添加新字段,稍微版本更新即可。
 * 移除、重新排序和更改现有字段需要进行重大版本更新。
 * 不应在 libav* 之外使用 sizeof(AVFormatContext),请使用
 * avformat_alloc_context() 来创建 AVFormatContext。
 *
 * 字段可以通过 AVOptions (av_opt*) 访问,
 * 使用的名称字符串与关联的命令行参数名称匹配,
 * 相关信息可以在 libavformat/options_table.h 中找到。
 * 出于历史原因或简洁性,AVOption/命令行参数名称在某些情况下与 C
 * 结构字段名称不同。
 */
typedef struct AVFormatContext {
	// ... 
}

AVFormatContext 作用 :

  • 封装格式信息 : 该结构体 包含了 多媒体文件 或 流的封装格式 信息 , 如 FLV、MP4 等格式信息 ;
  • 管理音视频流 : 该结构体 管理 多媒体文件 中 包含的多个流 , 如 : 视频流、音频流、字幕流 , 每个流都由 AVStream 结构体表示 ;
    • 解复用 : 将 多媒体文件或流 分解成单独的流 , 以便后续 解码 使用 ;
    • 复用 : 将 多个流 封装成 一个多媒体文件或流 , 以便后续 编码 使用 ;

使用 AVFormatContext 结构体 前需要导入头文件 :

代码语言:javascript
复制
#include <libavformat/avformat.h> 

调用 avformat_alloc_context 函数 , 可以创建 AVFormatContext 结构体 , 返回一个指向该结构体的指针 ;

代码语言:javascript
复制
    // 创建 AVFormatContext  
    AVFormatContext *formatContext = avformat_alloc_context();  

相关打开媒体文件的部分代码示例 :

代码语言:javascript
复制
#include <libavformat/avformat.h>  
  
int main(int argc, char *argv[]) {  
    // 初始化 FFmpeg 库  
    av_register_all();  
  
    // 创建 AVFormatContext  
    AVFormatContext *formatContext = avformat_alloc_context();  
    
	// ... 省略 ...
}

2、AVFormatContext 结构体成员

AVFormatContext 主要结构体成员 :

  • struct AVInputFormat *iformat : 输入格式 , 描述了文件的封装格式 , 如 : MP4、MKV 等 ;
代码语言:javascript
复制
    /**
     * 输入容器格式。
     *
     * 仅用于解复用,由 avformat_open_input() 设置。
     */
    ff_const59 struct AVInputFormat *iformat;
  • struct AVOutputFormat *oformat : 输出格式 , 用于指定输出文件的封装格式 ;
代码语言:javascript
复制
    /**
     * 输出容器格式。
     *
     * 仅用于复用,调用者必须在 avformat_write_header() 之前设置。
     */
    ff_const59 struct AVOutputFormat *oformat;
  • unsigned int nb_streams : 多媒体文件中包含的 流 的数量 ;
代码语言:javascript
复制
    /**
     * AVFormatContext.streams 中的元素数量。
     *
     * 由 avformat_new_stream() 设置,不得被其他代码修改。
     */
    unsigned int nb_streams;
  • AVStream **streams : 一个指向 AVStream 指针数组 的指针 , 每个 AVStream 表示一个单独的媒体流 , 如 : 一个视频流 / 一个音频流 / 一个字幕流 ;
代码语言:javascript
复制
    /**
     * 文件中所有流的列表。新流通过 avformat_new_stream() 创建。
     *
     * - 解复用:流由 libavformat 在 avformat_open_input() 中创建。
     *             如果 ctx_flags 中设置了 AVFMTCTX_NOHEADER,则新流可能也会出现在 av_read_frame() 中。
     * - 复用:流由用户在 avformat_write_header() 之前创建。
     *
     * 在 avformat_free_context() 中由 libavformat 释放。
     */
    AVStream **streams;
  • char filename[1024] : 输入 或 输出 文件的文件名 ;
代码语言:javascript
复制
#if FF_API_FORMAT_FILENAME
    /**
     * 输入或输出文件名
     *
     * - 解复用:由 avformat_open_input() 设置
     * - 复用:可以在 avformat_write_header() 之前由调用者设置
     *
     * @deprecated 使用 url 代替。
     */
    attribute_deprecated
    char filename[1024];
#endif
  • char *url : 输入或输出流的 URL 地址 , 前提是 通过网络流等方式访问 ;
代码语言:javascript
复制
    /**
     * 输入或输出 URL。与旧的 filename 字段不同,此字段没有
     * 长度限制。
     *
     * - 解复用:由 avformat_open_input() 设置,如果 avformat_open_input() 中的 url 参数为 NULL,则初始化为空字符串。
     * - 复用:可以在调用 avformat_write_header() 之前(或如果首先调用 avformat_init_output())由调用者设置为一个可通过 av_free() 释放的字符串。
     *           如果在 avformat_init_output() 中为 NULL,则设置为空字符串。
     *
     * 在 avformat_free_context() 中由 libavformat 释放。
     */
    char *url;

3、AVFormatContext 结构体原型

AVFormatContext 结构体原型 : 该代码比较多 , 仅做参考 ;

代码语言:javascript
复制
/**
 * 格式化 I/O 上下文。
 * 新字段可以通过小版本升级在末尾添加。
 * 移除、重排和更改现有字段需要进行大版本升级。
 * 不应在 libav* 外使用 sizeof(AVFormatContext),请使用
 * avformat_alloc_context() 创建 AVFormatContext。
 *
 * 字段可以通过 AVOptions (av_opt*) 访问,
 * 使用的名称字符串与相关的命令行参数名称匹配,
 * 可以在 libavformat/options_table.h 中找到。
 * 出于历史原因或简洁性,AVOption/命令行参数名称在某些情况下与 C
 * 结构体字段名称不同。
 */
typedef struct AVFormatContext {
    /**
     * 用于日志记录和 @ref avoptions 的类。由 avformat_alloc_context() 设置。
     * 如果存在,导出 (解)复用器私有选项。
     */
    const AVClass *av_class;

    /**
     * 输入容器格式。
     *
     * 仅用于解复用,由 avformat_open_input() 设置。
     */
    ff_const59 struct AVInputFormat *iformat;

    /**
     * 输出容器格式。
     *
     * 仅用于复用,调用者必须在 avformat_write_header() 之前设置。
     */
    ff_const59 struct AVOutputFormat *oformat;

    /**
     * 格式私有数据。只有在 iformat/oformat.priv_class 不为 NULL 时,才是一个支持 AVOptions 的结构。
     *
     * - 复用:由 avformat_write_header() 设置
     * - 解复用:由 avformat_open_input() 设置
     */
    void *priv_data;

    /**
     * I/O 上下文。
     *
     * - 解复用:可以在 avformat_open_input() 之前由用户设置(那么用户必须手动关闭它),或由 avformat_open_input() 设置。
     * - 复用:在 avformat_write_header() 之前由用户设置。调用者必须
     *           负责关闭/释放 I/O 上下文。
     *
     * 如果在 iformat/oformat.flags 中设置了 AVFMT_NOFILE 标志,则不要设置此字段。
     * 在这种情况下,(解)复用器将以其他方式处理 I/O,此字段将为 NULL。
     */
    AVIOContext *pb;

    /* 流信息 */
    /**
     * 信号流属性的标志。AVFMTCTX_* 的组合。
     * 由 libavformat 设置。
     */
    int ctx_flags;

    /**
     * AVFormatContext.streams 中的元素数量。
     *
     * 由 avformat_new_stream() 设置,不得被其他代码修改。
     */
    unsigned int nb_streams;

    /**
     * 文件中所有流的列表。新流通过 avformat_new_stream() 创建。
     *
     * - 解复用:流由 libavformat 在 avformat_open_input() 中创建。
     *             如果 ctx_flags 中设置了 AVFMTCTX_NOHEADER,则新流可能也会出现在 av_read_frame() 中。
     * - 复用:流由用户在 avformat_write_header() 之前创建。
     *
     * 在 avformat_free_context() 中由 libavformat 释放。
     */
    AVStream **streams;

#if FF_API_FORMAT_FILENAME
    /**
     * 输入或输出文件名
     *
     * - 解复用:由 avformat_open_input() 设置
     * - 复用:可以在 avformat_write_header() 之前由调用者设置
     *
     * @deprecated 使用 url 代替。
     */
    attribute_deprecated
    char filename[1024];
#endif

    /**
     * 输入或输出 URL。与旧的 filename 字段不同,此字段没有
     * 长度限制。
     *
     * - 解复用:由 avformat_open_input() 设置,如果 avformat_open_input() 中的 url 参数为 NULL,则初始化为空字符串。
     * - 复用:可以在调用 avformat_write_header() 之前(或如果首先调用 avformat_init_output())由调用者设置为一个可通过 av_free() 释放的字符串。
     *           如果在 avformat_init_output() 中为 NULL,则设置为空字符串。
     *
     * 在 avformat_free_context() 中由 libavformat 释放。
     */
    char *url;

    /**
     * 组件的第一帧位置,单位为 AV_TIME_BASE 分数秒。切勿直接设置此值:
     * 它是根据 AVStream 值推断的。
     *
     * 仅用于解复用,由 libavformat 设置。
     */
    int64_t start_time;

    /**
     * 流的持续时间,单位为 AV_TIME_BASE 分数秒。仅在你知道没有任何单个流
     * 持续时间且也不设置它们时,才设置此值。如果未设置,则根据
     * AVStream 值推断。
     *
     * 仅用于解复用,由 libavformat 设置。
     */
    int64_t duration;

    /**
     * 总流比特率(比特/秒),如果不可用则为 0。
     * 如果文件大小和持续时间已知,请勿直接设置它,因为 FFmpeg 可以自动计算。
     */
    int64_t bit_rate;

    unsigned int packet_size;
    int max_delay;

    /**
     * 修改 (解)复用器行为的标志。AVFMT_FLAG_* 的组合。
     * 在 avformat_open_input() / avformat_write_header() 之前由用户设置。
     */
    int flags;
#define AVFMT_FLAG_GENPTS       0x0001 ///< 生成缺失的 pts,即使这需要解析未来的帧。
#define AVFMT_FLAG_IGNIDX       0x0002 ///< 忽略索引。
#define AVFMT_FLAG_NONBLOCK     0x0004 ///< 从输入读取数据包时不阻塞。
#define AVFMT_FLAG_IGNDTS       0x0008 ///< 忽略包含 DTS 和 PTS 的帧的 DTS
#define AVFMT_FLAG_NOFILLIN     0x0010 ///< 不从其他值推断任何值,只返回容器中存储的内容
#define AVFMT_FLAG_NOPARSE      0x0020 ///< 不使用 AVParsers,您还必须设置 AVFMT_FLAG_NOFILLIN,因为填充代码依赖于帧,而不解析 -> 没有帧。如果禁用解析以查找帧边界,寻址到帧也无法工作。
#define AVFMT_FLAG_NOBUFFER     0x0040 ///< 在可能的情况下不缓冲帧
#define AVFMT_FLAG_CUSTOM_IO    0x0080 ///< 调用者提供了自定义 AVIOContext,不要 avio_close() 它。
#define AVFMT_FLAG_DISCARD_CORRUPT  0x0100 ///< 丢弃标记为损坏的帧
#define AVFMT_FLAG_FLUSH_PACKETS    0x0200 ///< 每个数据包刷新 AVIOContext。
/**
 * 复用时,尽量避免将任何随机/易失性数据写入输出。
 * 这包括任何随机 ID、实时时间戳/日期、复用器版本等。
 *
 * 此标志主要用于测试。
 */
#define AVFMT_FLAG_BITEXACT         0x0400
#if FF_API_LAVF_MP4A_LATM
#define AVFMT_FLAG_MP4A_LATM    0x8000 ///< 已弃用,不执行任何操作。
#endif
#define AVFMT_FLAG_SORT_DTS    0x10000 ///< 尝试按 dts 交错输出的数据包(使用此标志可能会降低解复用速度)
#define AVFMT_FLAG_PRIV_OPT    0x20000 ///< 通过延迟编解码器打开启用私有选项的使用(在所有代码转换完成之前,这可以作为默认值)
#if FF_API_LAVF_KEEPSIDE_FLAG
#define AVFMT_FLAG_KEEP_SIDE_DATA 0x40000 ///< 已弃用,不执行任何操作。
#endif
#define AVFMT_FLAG_FAST_SEEK   0x80000 ///< 为某些格式启用快速但不准确的寻址
#define AVFMT_FLAG_SHORTEST   0x100000 ///< 当最短流停止时停止复用。
#define AVFMT_FLAG_AUTO_BSF   0x200000 ///< 根据复用器的要求添加比特流过滤器

    /**
     * 从输入中读取的数据的最大大小,用于确定
     * 输入容器格式。
     * 仅用于解复用,由调用者在 avformat_open_input() 之前设置。
     */
    int64_t probesize;

    /**
     * 从输入中读取的数据的最大持续时间(以 AV_TIME_BASE 单位)。
     * 仅用于解复用,由调用者在 avformat_find_stream_info() 之前设置。
     * 可以设置为 0,让 avformat 选择使用启发式方法。
     */
    int64_t max_analyze_duration;

    const uint8_t *key;
    int keylen;

    unsigned int nb_programs;
    AVProgram **programs;

    /**
     * 强制的视频 codec_id。
     * 解复用:由用户设置。
     */
    enum AVCodecID video_codec_id;

    /**
     * 强制的音频 codec_id。
     * 解复用:由用户设置。
     */
    enum AVCodecID audio_codec_id;

    /**
     * 强制的字幕 codec_id。
     * 解复用:由用户设置。
     */
    enum AVCodecID subtitle_codec_id;

    /**
     * 由用户设置的重编码标志。用于设置复用时的编码器。
     * 此标志的使用方式取决于容器格式。
     */
    int max_interleave_delta;

    /**
     * 输入文件的时区。解复用时设置。
     * 仅用于解复用,由 avformat_open_input() 设置。
     */
    char *time_zone;

    /**
     * 是否仅输出文件的码流,而不附加任何其他信息。
     * 复用时设置。
     */
    int use_default_muxer;

    /**
     * 是否打开 URL 以进行重用。如果使用此标志,
     * 则将使用 `avformat_open_input()` 来重用。
     * 否则,将直接使用 `avformat_write_header()`。
     */
    int open_url;

    /**
     * 指示是否为逐帧复用。解复用时设置。
     */
    int sequential;

    /**
     * 在读取时是否忽略 PTS。
     * 由用户在 avformat_open_input() 之前设置。
     */
    int ignore_pts;

    /**
     * 如果文件是分段的,则在 av_read_frame() 期间提供的内容。
     * 仅用于解复用,由 avformat_open_input() 设置。
     */
    int fragment;

    /**
     * 此文件的所有流的列表。将通过 avformat_new_stream() 创建。
     *
     * - 解复用:流由 libavformat 在 avformat_open_input() 中创建。
     * - 复用:流由用户在 avformat_write_header() 之前创建。
     *
     * 在 avformat_free_context() 中由 libavformat 释放。
     */
    AVStream **streams;

    /**
     * 输入或输出 URL。与旧的 filename 字段不同,此字段没有
     * 长度限制。
     *
     * - 解复用:由 avformat_open_input() 设置。
     * - 复用:可以在 avformat_write_header() 之前由调用者设置为一个可通过 av_free() 释放的字符串。
     */
    char *url;

    /**
     * 用于处理错误的上下文,存储返回值。
     * 由 libavformat 设置。
     */
    int *error;

    /**
     * 表示该上下文支持的编码器的编号。
     * 由 libavformat 设置。
     */
    int codec_tag;

    /**
     * 文件中所有流的属性标志。AVFMT_* 的组合。
     */
    int flags;

    /**
     * 统计信息的详细信息,包含有关 AVFormatContext 的信息。
     * 由 libavformat 设置。
     */
    AVFormatStatistics *statistics;
} AVFormatContext;

4、输入格式 - AVInputFormat 结构体

AVFormatContext 结构体成员 中 struct AVInputFormat *iformat 成员是 输入格式 , AVInputFormat 结构体定义了一种特定的输入格式 , 包含了读取该格式所需的所有信息和函数指针 ;

AVInputFormat 结构体 通常与 解复用器 Demuxer 一起使用 , 解复用器负责将多媒体流分解成单独的音视频流 ;

AVFormatContext 结构体原型 :

  • const char *name 成员 : 输入格式的名称 ;
  • const char *long_name 成员 : 输入格式的详细描述 ;
代码语言:javascript
复制
/**
 * @addtogroup lavf_decoding
 * @{
 */
typedef struct AVInputFormat {
    /**
     * 该格式的短名称以逗号分隔的列表。可以通过轻微增加来追加新名称。
     */
    const char *name;

    /**
     * 该格式的描述性名称,旨在比名称更易于人类阅读。
     * 你应该使用 NULL_IF_CONFIG_SMALL() 宏来定义它。
     */
    const char *long_name;

    /**
     * 可以使用的标志:AVFMT_NOFILE, AVFMT_NEEDNUMBER, AVFMT_SHOW_IDS,
     * AVFMT_NOTIMESTAMPS, AVFMT_GENERIC_INDEX, AVFMT_TS_DISCONT, AVFMT_NOBINSEARCH,
     * AVFMT_NOGENSEARCH, AVFMT_NO_BYTE_SEEK, AVFMT_SEEK_TO_PTS。
     */
    int flags;

    /**
     * 如果定义了扩展名,则不执行探测。通常不应使用扩展名格式猜测,
     * 因为它不够可靠。
     */
    const char *extensions;

    const struct AVCodecTag * const *codec_tag;

    const AVClass *priv_class; ///< 私有上下文的 AVClass

    /**
     * 以逗号分隔的 MIME 类型列表。
     * 在探测时用于检查匹配的 MIME 类型。
     * @see av_probe_input_format2
     */
    const char *mime_type;
	
	// ...
	
} AVInputFormat;

5、输出格式 - AVOutputFormat 结构体

AVOutputFormat 用于描述输出多媒体文件或流的封装格式 , 其中定义了如何写入封装格式特定的头信息、尾信息以及如何处理 Packet 数据包 和 Frame 帧 的写入 ;

代码语言:javascript
复制
/**
 * @addtogroup lavf_encoding
 * @{
 */
typedef struct AVOutputFormat {
    const char *name;
    /**
     * 格式的描述性名称,旨在比名称更易于人类阅读。
     * 你应该使用 NULL_IF_CONFIG_SMALL() 宏来定义它。
     */
    const char *long_name;
    const char *mime_type;
    const char *extensions; /**< 以逗号分隔的文件扩展名 */
    /* 输出支持 */
    enum AVCodecID audio_codec;    /**< 默认音频编解码器 */
    enum AVCodecID video_codec;    /**< 默认视频编解码器 */
    enum AVCodecID subtitle_codec; /**< 默认字幕编解码器 */
    /**
     * 可以使用的标志: AVFMT_NOFILE, AVFMT_NEEDNUMBER,
     * AVFMT_GLOBALHEADER, AVFMT_NOTIMESTAMPS, AVFMT_VARIABLE_FPS,
     * AVFMT_NODIMENSIONS, AVFMT_NOSTREAMS, AVFMT_ALLOW_FLUSH,
     * AVFMT_TS_NONSTRICT, AVFMT_TS_NEGATIVE
     */
    int flags;

    /**
     * 支持的 codec_id-codec_tag 对的列表,按“更好的选择优先”排序。
     * 所有数组都以 AV_CODEC_ID_NONE 结束。
     */
    const struct AVCodecTag * const *codec_tag;

    const AVClass *priv_class; ///< 私有上下文的 AVClass

} AVOutputFormat;

三、打开媒体文件 - avformat_open_input 函数


avformat_open_input 是 FFmpeg 库中的一个函数,用于打开一个多媒体文件并读取其头信息 ;

avformat_open_input 函数原型如下 :

代码语言:javascript
复制
int avformat_open_input(AVFormatContext **ps, const char *url, AVInputFormat *fmt, AVDictionary **options);

参数解析 :

  • `AVFormatContext ps** **参数 :** 指向 AVFormatContext 结构体的 指针地址 , 这是个二级指针 , 在上面章节有介绍 , 在本函数中*ps` 指针会被 初始化 或 重新初始化 以指向新的格式上下文 ;
    • 该参数是方法的最终执行结果 , 返回值信息 ;
  • const char *url 参数 : 多媒体文件的位置 , 本地文件路径 或 远程 URL 地址 ;
  • AVInputFormat *fmt 参数 : 设置输入格式 , 一般设置为 NULL , FFmpeg 可以自动检测输入格式 ;
  • `AVDictionary options`** 参数 : 设置各种格式相关的选项 , 传递一个字典来配置 AVFormatContext 的特定选项 , 如 : 网络超时、HTTP 头部 等 ;
    • 如果没有特殊选项需要设置 , 可以将其设置为 NULL ;

返回值解析 :

  • 函数执行成功 : 返回 0 ;
  • 函数执行失败 : 返回 负值 错误码 , 下面是几个错误码示例 , 定义在了 libavutil/error.h 头文件中 ;
代码语言:javascript
复制
#define FFERRTAG(a, b, c, d) (-(int)MKTAG(a, b, c, d))

#define AVERROR_BSF_NOT_FOUND      FFERRTAG(0xF8,'B','S','F') ///< 找不到比特流过滤器
#define AVERROR_BUG                FFERRTAG( 'B','U','G','!') ///< 内部错误,另请参见 AVERROR_BUG2
#define AVERROR_BUFFER_TOO_SMALL   FFERRTAG( 'B','U','F','S') ///< 缓冲区太小
#define AVERROR_DECODER_NOT_FOUND  FFERRTAG(0xF8,'D','E','C') ///< 找不到解码器
#define AVERROR_DEMUXER_NOT_FOUND  FFERRTAG(0xF8,'D','E','M') ///< 找不到解复用器
#define AVERROR_ENCODER_NOT_FOUND  FFERRTAG(0xF8,'E','N','C') ///< 找不到编码器
#define AVERROR_EOF                FFERRTAG( 'E','O','F',' ') ///< 文件结束
#define AVERROR_EXIT               FFERRTAG( 'E','X','I','T') ///< 请求立即退出;调用的函数不应重新启动
#define AVERROR_EXTERNAL           FFERRTAG( 'E','X','T',' ') ///< 外部库中的通用错误
#define AVERROR_FILTER_NOT_FOUND   FFERRTAG(0xF8,'F','I','L') ///< 找不到过滤器
#define AVERROR_INVALIDDATA        FFERRTAG( 'I','N','D','A') ///< 处理输入时发现无效数据
#define AVERROR_MUXER_NOT_FOUND    FFERRTAG(0xF8,'M','U','X') ///< 找不到复用器
#define AVERROR_OPTION_NOT_FOUND   FFERRTAG(0xF8,'O','P','T') ///< 找不到选项
#define AVERROR_PATCHWELCOME       FFERRTAG( 'P','A','W','E') ///< FFmpeg 中尚未实现,欢迎提交补丁
#define AVERROR_PROTOCOL_NOT_FOUND FFERRTAG(0xF8,'P','R','O') ///< 找不到协议
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-09-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、" 解封装 - 解码 - 播放 过程 " 涉及到的函数和结构体
  • 二、AVFormatContext 结构体详解
    • 1、初始化音视频文件格式 - AVFormatContext 结构体
      • 2、AVFormatContext 结构体成员
        • 3、AVFormatContext 结构体原型
          • 4、输入格式 - AVInputFormat 结构体
            • 5、输出格式 - AVOutputFormat 结构体
            • 三、打开媒体文件 - avformat_open_input 函数
            相关产品与服务
            容器服务
            腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档