FFmpeg数据结构AVPacket

本文为作者原创,转载请注明出处:https://www.cnblogs.com/leisure_chn/p/10410320.html

本文基于FFmpeg 4.1版本。

1. 数据结构定义

struct AVPacket定义于<libavcodec/avcodec.h>

struct AVPacket packet;

AVPacket中存储的是经过编码的压缩数据。在解码中,AVPacket由解复用器输出到解码器;在编码中,AVPacket由编码器输出到复用器。下图中,解复用器(demuxer)的输出和复用器(muxer)的输入“encoded data packets”的数据类型就是AVPacket:

1 _______ ______________ 2| | | | 3| input | demuxer | encoded data | decoder 4| file | ---------> | packets | -----+ 5|_______| |______________| | 6 v 7 _________ 8 | | 9 | decoded | 10 | frames | 11 |_________| 12 ________ ______________ | 13| | | | | 14| output | <-------- | encoded data | <----+ 15| file | muxer | packets | encoder 16|________| |______________| 17

对于视频而言,一个AVPacket通常只包含一个压缩视频帧。而对于音频而言,一个AVPacket可能包含多个完整的音频压缩帧。AVPacket也可以不包含压缩编码数据,而只包含side data,这种包可以称为空packet。例如,编码结束后只需要更新一些参数时就可以发空packet。

AVPacket对象可以在栈上分配,注意此处指的是AVPacket对象本身。而AVPacket中包含的数据缓冲区是通过av_malloc()在堆上分配的。
<font color=red>TODO: AVPacket对象在栈上分配,原理不清楚,待研究</font>

1/** 2 * This structure stores compressed data. It is typically exported by demuxers 3 * and then passed as input to decoders, or received as output from encoders and 4 * then passed to muxers. 5 * 6 * For video, it should typically contain one compressed frame. For audio it may 7 * contain several compressed frames. Encoders are allowed to output empty 8 * packets, with no compressed data, containing only side data 9 * (e.g. to update some stream parameters at the end of encoding). 10 * 11 * AVPacket is one of the few structs in FFmpeg, whose size is a part of public 12 * ABI. Thus it may be allocated on stack and no new fields can be added to it 13 * without libavcodec and libavformat major bump. 14 * 15 * The semantics of data ownership depends on the buf field. 16 * If it is set, the packet data is dynamically allocated and is 17 * valid indefinitely until a call to av_packet_unref() reduces the 18 * reference count to 0. 19 * 20 * If the buf field is not set av_packet_ref() would make a copy instead 21 * of increasing the reference count. 22 * 23 * The side data is always allocated with av_malloc(), copied by 24 * av_packet_ref() and freed by av_packet_unref(). 25 * 26 * @see av_packet_ref 27 * @see av_packet_unref 28 */ 29typedef struct AVPacket { 30 /** 31 * A reference to the reference-counted buffer where the packet data is 32 * stored. 33 * May be NULL, then the packet data is not reference-counted. 34 */ 35 AVBufferRef *buf; 36 /** 37 * Presentation timestamp in AVStream->time_base units; the time at which 38 * the decompressed packet will be presented to the user. 39 * Can be AV_NOPTS_VALUE if it is not stored in the file. 40 * pts MUST be larger or equal to dts as presentation cannot happen before 41 * decompression, unless one wants to view hex dumps. Some formats misuse 42 * the terms dts and pts/cts to mean something different. Such timestamps 43 * must be converted to true pts/dts before they are stored in AVPacket. 44 */ 45 int64_t pts; 46 /** 47 * Decompression timestamp in AVStream->time_base units; the time at which 48 * the packet is decompressed. 49 * Can be AV_NOPTS_VALUE if it is not stored in the file. 50 */ 51 int64_t dts; 52 uint8_t *data; 53 int size; 54 int stream_index; 55 /** 56 * A combination of AV_PKT_FLAG values 57 */ 58 int flags; 59 /** 60 * Additional packet data that can be provided by the container. 61 * Packet can contain several types of side information. 62 */ 63 AVPacketSideData *side_data; 64 int side_data_elems; 65 66 /** 67 * Duration of this packet in AVStream->time_base units, 0 if unknown. 68 * Equals next_pts - this_pts in presentation order. 69 */ 70 int64_t duration; 71 72 int64_t pos; ///< byte position in stream, -1 if unknown 73 74#if FF_API_CONVERGENCE_DURATION 75 /** 76 * @deprecated Same as the duration field, but as int64_t. This was required 77 * for Matroska subtitles, whose duration values could overflow when the 78 * duration field was still an int. 79 */ 80 attribute_deprecated 81 int64_t convergence_duration; 82#endif 83} AVPacket;

音视频数据缓冲区

  • uint8_t *data:
  • int size:
    数据缓冲区地址与大小。音视频编码压缩数据存储于此片内存区域。此内存区域由AVBufferRef *buf管理。
  • AVBufferRef *buf:
    数据缓冲区引用,也可叫引用计数缓冲区。对上一字段uint8_t *data指向的内存区域提供引用计数等管理机制。
    AVBufferRef对数据缓冲区提供了管理机制,用户不应直接访问数据缓冲区。参考“FFmpeg数据结构AVBuffer
    如果buf值为NULL,则data指向的数据缓冲区不使用引用计数机制。av_packet_ref(dst, src)将执行数据缓冲区的拷贝,而非仅仅增加缓冲区引用计数。
    如果buf值非NULL,则data指向的数据缓冲区使用引用计数机制。av_packet_ref(dst, src)将不拷贝缓冲区,而仅增加缓冲区引用计数。av_packet_unref()将数据缓冲区引用计数减1,当缓冲区引用计数为0时,缓冲区内存被FFmpeg回收。
    对于struct AVPacket pkt对象,如果pkt.buf值非NULL,则有pkt.data == pkt.buf->data == pkt.buf->buffer.data

额外类型数据

  • AVPacketSideData *side_data
  • int side_data_elems
    由容器(container)提供的额外包数据。<font color=red>TODO: 待研究</font>

packet属性

  • int64_t pts:
    显示时间戳。单位time_base,帧率的倒数。
  • int64_t dts:
    解码时间戳。单位time_base,帧率的倒数。
  • int stream_index:
    当前包(packet)所有流(stream)的索引(index)。
  • int flags:
    packet标志位。比如是否关键帧等。
  • int64_t duration:
    当前包解码后的帧播放持续的时长。单位timebase。值等于下一帧pts减当前帧pts。
  • int64_t pos:
    当前包在流中的位置,单位字节。

2. 关键函数实现

这里列出的几个关键函数,主要是为了帮助理解struct AVPacket数据结构

2.1 av_packet_ref()

1int av_packet_ref(AVPacket *dst, const AVPacket *src) 2{ 3 int ret; 4 5 ret = av_packet_copy_props(dst, src); 6 if (ret < 0) 7 return ret; 8 9 if (!src->buf) { 10 ret = packet_alloc(&dst->buf, src->size); 11 if (ret < 0) 12 goto fail; 13 if (src->size) 14 memcpy(dst->buf->data, src->data, src->size); 15 16 dst->data = dst->buf->data; 17 } else { 18 dst->buf = av_buffer_ref(src->buf); 19 if (!dst->buf) { 20 ret = AVERROR(ENOMEM); 21 goto fail; 22 } 23 dst->data = src->data; 24 } 25 26 dst->size = src->size; 27 28 return 0; 29fail: 30 av_packet_free_side_data(dst); 31 return ret; 32}

av_packet_ref()作了处理如下:
a) 如果src->buf为NULL,则将src缓冲区拷贝到新创建的dst缓冲区,注意src缓冲区不支持引用计数,但新建的dst缓冲区是支持引用计数的,因为dst->buf不为NULL。
b) 如果src->buf不为空,则dst与src共用缓冲区,调用av_buffer_ref()增加缓冲区引用计数即可。av_buffer_ref()分析参考“FFmpeg数据结构AVBuffer

2.2 av_packet_unref()

1void av_packet_unref(AVPacket *pkt) 2{ 3 av_packet_free_side_data(pkt); 4 av_buffer_unref(&pkt->buf); 5 av_init_packet(pkt); 6 pkt->data = NULL; 7 pkt->size = 0; 8}

av_packet_unref()注销AVPacket *pkt对象,并调用av_buffer_unref(&pkt->buf);将缓冲区引用计数减1。
av_buffer_unref()中将缓冲区引用计数减1后,若缓冲区引用计数变成0,则回收缓冲区内存。av_buffer_unref()分析参考“FFmpeg数据结构AVBuffer

3. 参考资料

[1] FFmpeg数据结构:AVPacket解析, https://www.cnblogs.com/wangguchangqing/p/5790705.html

4. 修改记录

2018-12-14 V1.0 初稿

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )