FFmpeg如何读取文件内容(AVPacket)
主要介绍AVPacket这个结构体以及其用法。
AVPacket
是FFmpeg中一个管理压缩后的媒体数据的结构,它本身不包含压缩的媒体数据,而是通过 data 指针指向媒体数据。
这里面的媒体数据通常是一帧视频的数据,或者一帧音频的数据。但是也有一些特殊情况,这个 AVPacket 的 data 是空的,只有 side data 的数据。side data 是一些附加信息。
读取文件内容相关函数:
1,av_packet_alloc
,初始化一个 AVPacket
。
2,av_read_frame
,从 AVFormatContext
容器里面读取一个 AVPacket
,需要注意,虽然函数名是 frame
,但是读取的是 AVPacket
。
3,av_packet_unref
,减少 AVPacket
对 编码数据的引用次数。减到 0 会释放 编码数据的内存。
4,av_packet_free
,释放 AVPacket
自身的内存。里面会调 av_packet_unref
av_packet_alloc
初始化一个 AVPacket
,那是不是用 av_read_frame
读一次数据,就要调一次 av_packet_alloc
呢?
不是,因为 AVPacket
他本身是没有编码数据的,他只是管理编码数据,也就是说 av_packet_alloc
的时候,AVPacket
里面还没有编码数据的,是后面通过 av_read_frame
把 AVPacket
里面的 buf
引用指向了编码数据。
如果你要调多次 av_read_frame
,只需要先用 av_packet_unref
消除 AVPacket
里面对之前的编码数据的引用即可。只有最后用不到 AVPacket
的时候,才需要调 av_packet_free
来释放 AVPacket
的内存。
av_read_frame
的返回值有很多种情况。
1,成功读取到一个 AVPacket
。
2,读取到文件末尾。
3,网络流有问题,或者本地硬盘坏了。导致 AVFormatContext
里面的 pb->error
有异常。
AVPacket
里面有一个 stream_index
字段,代表这个 AVPacket
属于哪个流,那我们怎么知道这是一个音频包,还是视频包?在下面的字段里面:
fmt_ctx->streams[0]->codecpar->codec_type
codec_type 等于 0 代表这是一个视频流,1 代表这是一个音频流
然后 AVPacket
里面还有一个 duration
字段,代表这帧数据要播放 多久。时间基是 11988 ,时间基就是 1秒钟分成11988份,然后这个视频包占了 500 份,也就是当前帧要播放 0.04 秒
然后 AVPacket
里面还有一个 pos
字段,这个字段就代表,data
里面的数据是从 mp4 文件的哪个位置读取出来的
AVPacket
里面 size
字段代表这个视频包有多大,也就是 data
的长度
详细的:
avpkt
(输入AVPacket
)
内容:
avpkt
通常包含单个视频帧或几个完整的音频帧。它是解码过程的输入。所有权:
AVPacket
的所有权保留在调用者手中。解码器不会修改AVPacket
本身(即不会写入数据到AVPacket
),但可能会创建对AVPacket
数据的引用(如果AVPacket
不是引用计数的,则可能会复制数据)。处理:与旧API不同,
AVPacket
总是被完全消耗。如果它包含多个帧(例如某些音频编解码器),则需要在发送新的AVPacket
之前多次调用avcodec_receive_frame()
函数来接收所有帧。空数据包/刷新流:
avpkt
可以是NULL
(或一个AVPacket
其data
设置为NULL
且size
设置为0
)。在这种情况下,它被视为一个刷新包(flush packet),用于指示流的结束。发送第一个刷新包将返回成功;后续的刷新包是不必要的,并会返回AVERROR_EOF
。如果解码器仍然有缓冲的帧,它将在发送刷新包后返回这些帧。