AVPacket 详细说明

AVPacket中的字段可用分为两部分:实际的帧数据、帖的属性数据和相关管理信息

数据的属性有以下字段

  • pts 显示时间戳                                         //取值为time_base的num和den之前的值
  • dts 解码时间戳
  • stream_index Packet所在stream的index
  • flats 标志,其中最低为1表示该数据是一个关键帧
  • duration 数据的时长,以所属媒体流的时间基准为单位
  • pos 数据在媒体流中的位置,未知则值为-1
  • convergence_duration 该字段已被deprecated,不再使用

AVPacket可以理解为一个容器,能过一个指针指向帧数据缓存区,然后通过缓存区引用计数来共享缓存区数据,提高数据空间使用效率。AVPacket中包含有两种数据:

  • data 指向保存压缩数据的指针,这就是AVPacket实际的数据。
  • side_data 容器提供的一些附加数据
  • buf 是AVBufferRef类型的指针,用来管理data指针引用的数据缓存的

AVPacket中的内存管理

当从一个Packet去创建另一个Packet的时候,有两种情况:

  • 两个Packet的data引用的是同一数据缓存空间,这时候要注意数据缓存空间的释放问题
  • 两个Packet的data引用不同的数据缓存空间,每个Packet都有数据缓存空间的copy。

对于多个Packet共享同一个缓存空间,FFmpeg使用的引用计数的机制(reference-count)。当有新的Packet引用共享的缓存空间时,就将引用计数+1;当释放了引用共享空间的Packet,就将引用计数-1;引用计数为0时,就释放掉引用的缓存空间。
AVPacket中的AVBufferRef *buf;就是用来管理这个引用计数的。

能过av_packet_refav_packet_unref可以对引用计数进行操作,av_packet_ref增加引用,av_packet_unref减少引用:av_packet_ref当源buf为空时会分配一个缓存区,并把两个buf都指向过去。

av_read_frame(pFormatCtx, &packet)  // 读取
Packet av_packet_ref(&dst,&packet)     // dst packet共享同一个数据缓存空间
av_packet_unref(&dst);                          //减少引用计数,引用计数为0时会释放缓存

AVPacket 相关函数介绍

av_read_frame:从媒体流中读取帧填充到Packet的数据缓存空间。如果Packet->buf为空,则Packet的数据缓存空间会在下次调用av_read_frame的时候失效。这也就是为何在FFmpeg3:播放音频中,从流中读取到Packet的时,在将该Packet插入队列时,要调用av_dup_avpacket重新复制一份缓存数据。

av_packet_alloc: 创建一个AVPacket,将其字段设为默认值(data为空,没有数据缓存空间)

av_packet_free: 释放使用av_packet_alloc创建的AVPacket,如果该Packet有引用计数(packet->buf不为空),则先调用av_packet_unref(&packet)

av_packet_clone: 其功能是 av_packet_alloc + av_packet_ref

av_init_packet: 初始化packet的值为默认值,该函数不会影响data引用的数据缓存空间和size,需要单独处理。

av_new_packet: av_init_packet的增强版,不但会初始化字段,还为data分配了存储空间。

av_copy_packet: 复制一个新的packet,包括数据缓存。

av_packet_from_data: 初始化一个引用计数的packet,并指定了其数据缓存。

av_grow_packet: 增大Packet->data指向的数据缓存。

av_shrink_packet :减小Packet->data指向的数据缓存。

av_dup_packet: 是复制src->data引用的数据缓存,赋值给dst,也就是创建两个独立packet。说是3的版本册除了该方法,但4.1的源码里面又出现了该方法。

已经废弃的两个函数:av_dup_packetav_free_packet
av_free_packet: 释放packet,包括其data引用的数据缓存,现在可以使用av_packet_free或av_packet_unref代替。

读包示例代码:

AVPacket packet; 
while (av_read_frame(pFormatCtx, &packet) >= 0) 
{ 
    // 这里只读视频包
    if (packet.stream_index == videoStream) {
       push_packet_queue(&packet)    // 将包按插入到队列相应位置
    } else {
        av_packet_unref(&packet);    // OR av_packet_free(&packet)
    }
}

上一篇:javaIO流学习,读一次写一次,效率低的文件拷贝


下一篇:字节输入输出流综合练习