本文为作者原创,转载请注明出处: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:

 _______              ______________
| | | |
| input | demuxer | encoded data | decoder
| file | ---------> | packets | -----+
|_______| |______________| |
v
_________
| |
| decoded |
| frames |
|_________|
________ ______________ |
| | | | |
| output | <-------- | encoded data | <----+
| file | muxer | packets | encoder
|________| |______________|

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

AVPacket对象可以在栈上分配,注意此处指的是AVPacket对象本身。而AVPacket中包含的数据缓冲区是通过av_malloc()在堆上分配的。

TODO: AVPacket对象在栈上分配,原理不清楚,待研究

/**
* This structure stores compressed data. It is typically exported by demuxers
* and then passed as input to decoders, or received as output from encoders and
* then passed to muxers.
*
* For video, it should typically contain one compressed frame. For audio it may
* contain several compressed frames. Encoders are allowed to output empty
* packets, with no compressed data, containing only side data
* (e.g. to update some stream parameters at the end of encoding).
*
* AVPacket is one of the few structs in FFmpeg, whose size is a part of public
* ABI. Thus it may be allocated on stack and no new fields can be added to it
* without libavcodec and libavformat major bump.
*
* The semantics of data ownership depends on the buf field.
* If it is set, the packet data is dynamically allocated and is
* valid indefinitely until a call to av_packet_unref() reduces the
* reference count to 0.
*
* If the buf field is not set av_packet_ref() would make a copy instead
* of increasing the reference count.
*
* The side data is always allocated with av_malloc(), copied by
* av_packet_ref() and freed by av_packet_unref().
*
* @see av_packet_ref
* @see av_packet_unref
*/
typedef struct AVPacket {
/**
* A reference to the reference-counted buffer where the packet data is
* stored.
* May be NULL, then the packet data is not reference-counted.
*/
AVBufferRef *buf;
/**
* Presentation timestamp in AVStream->time_base units; the time at which
* the decompressed packet will be presented to the user.
* Can be AV_NOPTS_VALUE if it is not stored in the file.
* pts MUST be larger or equal to dts as presentation cannot happen before
* decompression, unless one wants to view hex dumps. Some formats misuse
* the terms dts and pts/cts to mean something different. Such timestamps
* must be converted to true pts/dts before they are stored in AVPacket.
*/
int64_t pts;
/**
* Decompression timestamp in AVStream->time_base units; the time at which
* the packet is decompressed.
* Can be AV_NOPTS_VALUE if it is not stored in the file.
*/
int64_t dts;
uint8_t *data;
int size;
int stream_index;
/**
* A combination of AV_PKT_FLAG values
*/
int flags;
/**
* Additional packet data that can be provided by the container.
* Packet can contain several types of side information.
*/
AVPacketSideData *side_data;
int side_data_elems; /**
* Duration of this packet in AVStream->time_base units, 0 if unknown.
* Equals next_pts - this_pts in presentation order.
*/
int64_t duration; int64_t pos; ///< byte position in stream, -1 if unknown #if FF_API_CONVERGENCE_DURATION
/**
* @deprecated Same as the duration field, but as int64_t. This was required
* for Matroska subtitles, whose duration values could overflow when the
* duration field was still an int.
*/
attribute_deprecated
int64_t convergence_duration;
#endif
} 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)提供的额外包数据。TODO: 待研究

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()

int av_packet_ref(AVPacket *dst, const AVPacket *src)
{
int ret; ret = av_packet_copy_props(dst, src);
if (ret < 0)
return ret; if (!src->buf) {
ret = packet_alloc(&dst->buf, src->size);
if (ret < 0)
goto fail;
if (src->size)
memcpy(dst->buf->data, src->data, src->size); dst->data = dst->buf->data;
} else {
dst->buf = av_buffer_ref(src->buf);
if (!dst->buf) {
ret = AVERROR(ENOMEM);
goto fail;
}
dst->data = src->data;
} dst->size = src->size; return 0;
fail:
av_packet_free_side_data(dst);
return ret;
}

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()

void av_packet_unref(AVPacket *pkt)
{
av_packet_free_side_data(pkt);
av_buffer_unref(&pkt->buf);
av_init_packet(pkt);
pkt->data = NULL;
pkt->size = 0;
}

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 初稿

FFmpeg数据结构AVPacket的更多相关文章

  1. FFmpeg数据结构AVFrame

    本文为作者原创,转载请注明出处:https://www.cnblogs.com/leisure_chn/p/10404502.html 本文基于FFmpeg 4.1版本. 1. 数据结构定义 stru ...

  2. FFmpeg数据结构:AVPacket解析

    本文主要从以下几个方面对AVPacket做解析: AVPacket在FFmpeg中的作用 字段说明 AVPacket中的内存管理 AVPacket相关函数的说明 结合AVPacket队列说明下AVPa ...

  3. FFmpeg 中AVPacket的使用

    AVPacket保存的是解码前的数据,也就是压缩后的数据.该结构本身不直接包含数据,其有一个指向数据域的指针,FFmpeg中很多的数据结构都使用这种方法来管理数据. AVPacket的使用通常离不开下 ...

  4. FFmpeg数据结构AVBuffer

    本文为作者原创,转载请注明出处:https://www.cnblogs.com/leisure_chn/p/10399048.html AVBuffer是FFmpeg中很常用的一种缓冲区,缓冲区使用引 ...

  5. FFmpeg之AVPacket

    花满楼原创 AVPacket,是压缩数据的结构体(解码前或编码后的结构体). 本文介绍FFmepg中常见结构AVPacekt,尽量用具体值来理解. 整个用于调试的代码可以这样写: #include & ...

  6. ffmpeg常用数据结构

    from :http://my.oschina.net/u/555701/blog/56748 AVCodecContext 这是一个描述编解码器上下文的数据结构,包含了众多编解码器需要的参数信息,如 ...

  7. C/C++音视频库ffmpeg的数据包AVPacket分析

    ffmpeg下载地址 http://www.ffmpeg.club/ AVPacket是ffmpeg用来存放编码后的视频帧数据,我们来分析一下这个结构体,先贴出ffmpeg3.2中AVPacket声明 ...

  8. FFmpeg详解

    认识FFMPEG FFMPEG堪称自由软件中最完备的一套多媒体支持库,它几乎实现了所有当下常见的数据封装格式.多媒体传输协议以及音视频编解码器.因此,对于从事多媒体技术开发的工程师来说,深入研究FFM ...

  9. 最新FFMPEG解码流程

    FFMPEG解码流程: 1. 注册所有容器格式和CODEC:  av_register_all() 2. 打开文件:                    av_open_input_file() 3 ...

随机推荐

  1. js使用锚点回到顶部

    使用锚点链接是一种简单的返回顶部的功能实现.该实现主要在页面顶部放置一个指定名称的锚点链接,然后在页面下方放置一个返回到该锚点的链接,用户点击该链接即可返回到该锚点所在的顶部位置 <body s ...

  2. ibatis (六) dynamic的用法

    view plain copy print? dynamic可以去除第一个prepend="and"中的字符(这里为and),从而可以帮助你实现一些很实用的功能.具体情况如下: 1 ...

  3. 综合数据api接口使用

    由于请求数据接口是跨域的,但是我们无法改变接口的代码 先从请求后台,然后从后台进行二次请求,请求数据接口 原生代码 package edu.nf.http.test; import org.apach ...

  4. Day02 (黑客成长日记)

    #用户登录次数为三代码 # i = 0 # while i < 3: # username = input('请输入账号:') # password = input('请输入密码:') # if ...

  5. 基于ALTERA SOPC设计的概述

    下图是比较传统的系统设计开发板的设备图 由于元器件比较多,成本,复杂性和功耗都比较高,所以需要一种新的方案来降低成本和复杂性. ALTERAL  就提供了一种SOPC解决方案,将系统的I/O.CPU和 ...

  6. Hadoop 系列文章(二) Hadoop配置部署启动HDFS及本地模式运行MapReduce

    接着上一篇文章,继续我们 hadoop 的入门案例. 1. 修改 core-site.xml 文件 [bamboo@hadoop-senior hadoop-2.5.0]$ vim etc/hadoo ...

  7. 团队作业第五周(HCL盐酸队)

    一.Alpha版本测试报告 1.测试计划 测试项目 上下移动   左右移动   发射子弹   与敌方坦克进行攻击 2.测试过程 测试截图 错误记录(提交issues到码云团队项目) 3.测试找出的bu ...

  8. 9.3AspectJ

    1.1 介绍 AspectJ是一个基于Java语言的AOP框架 Spring2.0以后新增了对AspectJ切点表达式支持 @AspectJ 是AspectJ1.5新增功能,通过JDK5注解技术,允许 ...

  9. Dynamic Programming | Set 3 (Longest Increasing Subsequence)

    在 Dynamic Programming | Set 1 (Overlapping Subproblems Property) 和 Dynamic Programming | Set 2 (Opti ...

  10. 聚簇索引(clustered index )和非聚簇索引(secondary index)的区别

    这两个名字虽然都叫做索引,但这并不是一种单独的索引类型,而是一种数据存储方式.对于聚簇索引存储来说,行数据和主键B+树存储在一起,辅助键B+树只存储辅助键和主键,主键和非主键B+树几乎是两种类型的树. ...