AVFormatContext编解码层:理论与实战(一)

简介: AVFormatContext编解码层:理论与实战(一)

前言

AVFormatContext 是一个贯穿始终的数据结构,很多函数都用到它作为参数,是输入输出相关信息的一个容器,本文讲解 AVFormatContext 的编解码层,主要包括三大数据结构:AVStreamAVCodecContexAVCodec


一、FFmpeg 解码流程

得到输入文件 -> 解封格式 -> 得到编码的数据包 -> 解码数据包 -> 得到解码后的数据帧 -> 处理数据帧 -> 编码 -> 得到编码后的数据包 -> 封装格式 -> 输出文件

涉及到下面的 API 函数:

  • 注册所有容器格式和 CODEC:av_register_all()
  • 打开文件:av_open_input_file()
  • 从文件中提取流信息:av_find_stream_info()
  • 穷举所有的流,查找其中种类为 CODEC_TYPE_VIDEO
  • 查找对应的解码器:avcodec_find_decoder()
  • 打开编解码器:avcodec_open()
  • 为解码帧分配内存:avcodec_alloc_frame()
  • 不停地从码流中提取出帧数据:av_read_frame()
  • 判断帧的类型,对于视频帧调用:avcodec_decode_video()
  • 解码完后,释放解码器:avcodec_close()
  • 关闭输入文件:av_close_input_file()

程序流程图如下图所示:

二、FFmpeg 转码流程

  • 大流程可以划分为输入、输出、转码、播放四大块;
  • 其中转码涉及比较多的处理环节,从图中可以看出,转码功能在整个功能图中占比很大。转码的核心功能在解码和编码两个部分,但在一个可用的示例程序中,编码解码与输入输出是难以分割的。
  • 解复用器为解码器提供输入,解码器会输出原始帧,对原始帧可进行各种复杂的滤镜处理,滤镜处理后的帧经编码器生成编码帧,多路流的编码帧经复用器输出到输出文件。

三、编解码 API 详解

  • 解码使用 avcodec_send_packet()avcodec_receive_frame() 两个函数。
  • 编码使用 avcodec_send_frame()avcodec_receive_packet() 两个函数。

1、解码 API 使用详解

关于 avcodec_send_packet()avcodec_receive_frame() 的使用说明:

  • ①、按 dts 递增的顺序向解码器送入编码帧 packet,解码器按 pts 递增的顺序输出原始帧 frame,实际上解码器不关注输入 packet 的 dts(错值都没关系),它只管依次处理收到的 packet,按需缓冲和解码;
  • ②、avcodec_receive_frame() 输出 frame 时,会根据各种因素设置好 frame->best_effort_timestamp(文档明确说明),实测 frame->pts 也会被设置(通常直接拷贝自对应的 packet.pts,文档未明确说明)用户应确保 avcodec_send_packet() 发送的 packet 具有正确的 pts,编码帧 packet 与原始帧 frame 间的对应关系通过 pts 确定;
  • ③、avcodec_receive_frame() 输 出 frame 时 ,frame->pkt_dts 拷贝自当前 avcodec_send_packet() 发送的 packet 中的 dts, 如果当前 packet 为 NULL(flush packet),解码器进入 flush 模式,当前及剩余的 frame->pkt_dts 值总为 AV_NOPTS_VALUE。因为解码器中有缓存帧,当前输出的 frame 并不是由当前输入的 packet 解码得到的,所以这个 frame->pkt_dts 没什么实际意义,可以不必关注;
  • ④、avcodec_send_packet() 发送第一个 NULL 会返回成功,后续的 NULL 会返回 AVERROR_EOF
  • ⑤、avcodec_send_packet() 多次发送 NULL 并不会导致解码器中缓存的帧丢失,使用 avcodec_flush_buffers() 可以立即丢掉解码器中缓存帧。因此播放完毕时应 avcodec_send_packet(NULL) 来取完缓存的帧,而 SEEK 操作或切换流时应调用 avcodec_flush_buffers() 来直接丢弃缓存帧;
  • ⑥、解码器通常的冲洗方法:调用一次 avcodec_send_packet(NULL)(返回成功),然后不停调用 avcodec_receive_frame() 直到其返回 AVERROR_EOF,取出所有缓存帧,avcodec_receive_frame() 返回 AVERROR_EOF 这一次是没有有效数据的,仅仅获取到一个结束标志;

2、编码 API 使用详解

关于 avcodec_send_frame()avcodec_receive_packet() 的使用说明:

  • ①、按 pts 递增的顺序向编码器送入原始帧 frame, 编码器按 dts 递增的顺序输出编码帧 packet,实际上编码器关注输入 frame 的 pts 不关注其 dts,它只管依次处理收到的 frame,按需缓冲和编码;
  • ②、avcodec_receive_packet() 输出 packet 时,会设置 packet.dts,从 0 开始,每次输出的 packet 的 dts 加 1,这是视频层的 dts,用户写输出前应将其转换为容器层的 dts;
  • ③、avcodec_receive_packet() 输出 packet 时,packet.pts 拷贝自对应的 frame.pts,这是视频层的 pts,用户写输出前应将其转换为容器层的 pts;
  • ④、avcodec_send_frame() 发送 NULL frame 时, 编码器进入 flush 模式;
  • ⑤、avcodec_send_frame() 发送第一个 NULL 会返回成功 ,后续的 NULL 会返回 AVERROR_EOF
  • ⑥、avcodec_send_frame() 多次发送 NULL 并不会导致编码器中缓存的帧丢失,使用 avcodec_flush_buffers() 可以立即丢掉编码器中缓存帧。因此编码完毕时应使用 avcodec_send_frame(NULL) 来取完缓存的帧,而 SEEK 操作或切换流时应调用 avcodec_flush_buffers() 来直接丢弃缓存帧;
  • ⑦、编码器通常的冲洗方法:调用一次 avcodec_send_frame(NULL)(返回成功),然后不停调用avcodec_receive_packet() 直到其返回 AVERROR_EOF,取出所有缓存帧,avcodec_receive_packet() 返回AVERROR_EOF 这一次是没有有效数据的,仅仅获取到一个结束标志;
  • ⑧、对音频来说,如果 AV_CODEC_CAP_VARIABLE_FRAME_SIZE(在 AVCodecContext.codec.capabilities 变量中,只读)标志有效,表示编码器支持可变尺寸音频帧,送入编码器的音频帧可以包含任意数量的采样点。如果此标志无效,则每一个音频帧的采样点数目(frame->nb_samples)必须等于编码器设定的音频帧尺寸(avctx->frame_size),最后一帧除外,最后一帧音频帧采样点数可以小于 avctx->frame_size

AVFormatContext编解码层:理论与实战(二)https://developer.aliyun.com/article/1473960

目录
相关文章
|
2月前
|
存储 缓存 编解码
AVFormatContext封装层:理论与实战(一)
AVFormatContext封装层:理论与实战(一)
33 1
|
2月前
|
编解码 算法 容器
AVFormatContext封装层:理论与实战(二)
AVFormatContext封装层:理论与实战(二)
30 0
|
2月前
|
编解码
AVFormatContext编解码层:理论与实战(二)
AVFormatContext编解码层:理论与实战(二)
31 0
|
2月前
|
编解码 内存技术
AVFormatContext编解码层:理论与实战(三)
AVFormatContext编解码层:理论与实战(三)
24 0
|
2月前
|
大数据 测试技术 API
AVFormatContext协议层:理论与实战(一)
AVFormatContext协议层:理论与实战(一)
20 0
|
4天前
|
编解码 数据可视化 搜索推荐
ffdshow源代码分析:解码、编码与多媒体处理的深度探索
ffdshow是知名的DirectShow解码器,集成多种视频音频解码器如libavcodec、libmpeg2等,支持格式丰富。它提供滤镜处理(如锐化、亮度调节)和可视化效果,允许用户个性化设置。此外,ffdshow处理音频,支持AC3、MP3等格式,可外挂DSP插件增强音效。通过对源代码的分析,能深入了解其解码、处理机制,预示着ffdshow将持续改进以提升多媒体体验。
|
2月前
|
编解码 内存技术
AVFormatContext封装层:理论与实战(三)
AVFormatContext封装层:理论与实战(三)
15 1
AVFormatContext封装层:理论与实战(三)
|
2月前
|
测试技术
AVFormatContext协议层:理论与实战(三)
AVFormatContext协议层:理论与实战(三)
21 4
|
2月前
|
测试技术
AVFormatContext协议层:理论与实战(二)
AVFormatContext协议层:理论与实战(二)
19 1
|
2月前
|
Web App开发 存储 网络协议
C/C++ 数据结构设计与应用(四):C++数据压缩与传输:从理论到实践的全景解析
C/C++ 数据结构设计与应用(四):C++数据压缩与传输:从理论到实践的全景解析
167 3