1.使用注意

  • AVPacket需要用户通过av_packet_allc()创建好空间后.才能供给fimpeg进行获取解码前帧数据,由于解码前帧数据大小是不固定的(比如I帧数据量最大)所以ffmpeg会在AVPacket的成员里动态进行创建空间.
  • 并且我们每一次使用完AVPacket后(再次调用av_read_frame()读取新帧之前),必须要通过av_packet_unref()引用技术对AVPacket里的成员来手动清理.
  • 解码完成或者退出播放后,还要调用av_packet_free()来释放AVPacket本身.

2.结构体如下:

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;
//用来管理data指针引用的数据缓存,通过av_packet_ref() 和 av_packet_unref()
//来使buf->buffer->refcount成员引用计数+-,如果引用计数为0,则释放buffer.
//而buf->buffer存储的则是ffmpeg读取出来的未解码数据
/**
* 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;
//显示时间戳,需要所属媒体流AVStream的time_base时基来换算出当前显示的标准时间(时分秒)
//比如dpts = av_q2d(AVStream->time_base) * AVPacket->pts; int64_t dts; //解码时间戳,需要所属媒体流AVStream的time_base时基来换算出当前显示的标准时间(时分秒)
uint8_t *data; //指向未解码数据(实际指向buf->buffer所指向的地址) int size; //data的大小
int stream_index; //标识该AVPacket所属的视频/音频流
int flags; //标识,结合AV_PKT_FLAG使用,比如:
//#define AV_PKT_FLAG_KEY 0x0001 关键帧
//#define AV_PKT_FLAG_CORRUPT 0x0002 损坏的数据
//#define AV_PKT_FLAG_DISCARD 0x0004 丢弃的数据 /**
* 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; //数据的时长,需要所属媒体流AVStream的time_base时基来换算出当前的标准时间,未知则值为默认值0
int64_t pos; //数据在流媒体中的位置,未知则值为默认值-1 }AVPacket;

3.AVPacket常用函数如下:

  • av_packet_alloc(): 初始化
  • av_packet_unref(): 引用减1.若为0则释放压缩数据
  • av_packet_free():释放AVPacket本身
  • av_packet_ref(): 从src复制到一个初始化好的dst中,并引用+1
  • av_packet_clone(): 创建并返回一个复制好的AVPacket(在音视频同步处理中用到该函数)
  • av_packet_from_data(AVPacket *pkt, uint8_t *data, int size): 通过压缩数据来初始化一个AVPacket(pkt必须是创建好的),一般在读取流媒体时使用,因为解码函数的参数必须是AVPacket.

4.AVPacket解码示例:

AVPacket *packet = av_packet_alloc(); // 创建一个packet

while(av_read_frame(pFormatCtx,packet))
{
if(packet->stream_index == audio_index)
{
...
}
else if(packet->stream_index == video_index)
{
...
} av_packet_unref(packet); // 引用计数-1,如果为0,则释放压缩数据所在的空间
}
av_packet_free(packet); //释放packet,如果还想使用,则需要重新alloc

5.AVPacket函数分析

av_packet_alloc():初始化

AVPacket *av_packet_alloc(void)
{
AVPacket *pkt = av_mallocz(sizeof(AVPacket));
if (!pkt)
return pkt; av_packet_unref(pkt); return pkt;
}

创建一个AVPacket的实例,但该函数并不会为数据分配空间,其指向数据域的指针为NULL。

av_packet_unref():引用减1.若为0则释放压缩数据

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;
}

将AVPacket->buf->buffer->refcount成员减1(数据域的引用技术减为0时会自动释放),替代了旧api(av_free_packet)

av_packet_free():释放AVPacket本身

void av_packet_free(AVPacket **pkt)
{
if (!pkt || !*pkt)
return; av_packet_unref(*pkt);
av_freep(pkt);
}

首先将AVPacket->buf->buffer->refcount成员减1(数据域的引用技术减为0时会自动释放),然后再释放为AVPacket分配的空间。

av_packet_ref():从src复制到一个初始化好的dst中,并引用+1

int av_packet_ref(AVPacket *dst, const AVPacket *src)
{
int ret; ret = av_packet_copy_props(dst, src); //复制部分成员(比如:pts,dts,pos,duration,side_data)到dst
if (ret < )
return ret; if (!src->buf) { //如果src->buf为空,则为dst新分配一个数据域,并将src->data复制到dst->buf->data
ret = packet_alloc(&dst->buf, src->size);
if (ret < )
goto fail;
av_assert1(!src->size || src->data);
if (src->size)
memcpy(dst->buf->data, src->data, src->size); dst->data = dst->buf->data;
} else { //不为空,则调用av_buffer_ref()来使引用+1,并将dst->buf指向src->buf,
dst->buf = av_buffer_ref(src->buf);
if (!dst->buf) {
ret = AVERROR(ENOMEM);
goto fail;
}
dst->data = src->data; //然后将src->data复制到dst->data中
} dst->size = src->size; return ;
fail:
av_packet_free_side_data(dst);
return ret;
}

av_packet_ref将src内容复制到一个创建好的dst中.需要注意: dst必须提前已经注册好

av_packet_clone():创建并返回一个复制好的AVPacket(在音视频同步处理中用到该函数)

AVPacket *av_packet_clone(const AVPacket *src)
{
AVPacket *ret = av_packet_alloc(); if (!ret)
return ret; if (av_packet_ref(ret, src))
av_packet_free(&ret); return ret;
}

av_packet_from_data(AVPacket *pkt, uint8_t *data, int size): 通过压缩数据来初始化一个AVPacket(pkt必须是创建好的),一般在读取流媒体时使用,因为解码函数的参数必须是AVPacket.

int av_packet_from_data(AVPacket *pkt, uint8_t *data, int size)
{
if (size >= INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE)
return AVERROR(EINVAL); pkt->buf = av_buffer_create(data, size + AV_INPUT_BUFFER_PADDING_SIZE,
av_buffer_default_free, NULL, ); //创建新的AVBufferRef,并初始化
if (!pkt->buf)
return AVERROR(ENOMEM); pkt->data = data;
pkt->size = size; return ;
}

3.AVPacket使用的更多相关文章

  1. FFmpeg 中AVPacket的使用

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

  2. FFmpeg数据结构:AVPacket解析

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

  3. AVPicture、AVFrame和AVPacket

    http://blog.csdn.net/ym012/article/details/6540065 从定义上可知,AVPicture是AVFrame的一个子集,他们都是数据流在编解过程中用来保存数据 ...

  4. FFmpeg之AVPacket

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

  5. FFmpeg AVPacket

    AVPacket注解 AVPacket 是一个结构体,存储压缩数据.可作为编码器的输出,解码器的输入. 对于 Video 一般包含一个压缩帧,对于 Audio 可能包含多个压缩帧. 编码器允许输出空 ...

  6. FFMPEG结构体分析:AVPacket

    注:写了一系列的结构体的分析的文章,在这里列一个列表: FFMPEG结构体分析:AVFrame FFMPEG结构体分析:AVFormatContext FFMPEG结构体分析:AVCodecConte ...

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

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

  8. FFmpeg 结构体学习(三): AVPacket 分析

    在上文FFmpeg 结构体学习(二): AVStream 分析我们学习了AVStream结构体的相关内容.本文,我们将讲述一下AVPacket. AVPacket是存储压缩编码数据相关信息的结构体.下 ...

  9. FFmpeg AVPacket相关主要函数介绍

    1.AVPacket相关函数介绍 操作AVPacket的函数大约有30个,主要分为:AVPacket的创建初始化,AVPacket中的data数据管理(clone,free,copy),AVPacke ...

  10. FFmpeg数据结构AVPacket

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

随机推荐

  1. 第一次MySQL的SQL注入实验

    测试平台:https://www.mozhe.cn/news/detail/324 上完SQL注入的第一节课过来对着笔记一步一步来做.. 1.首页面上没有id=XXX的东西,看见“平台维护通知”,点开 ...

  2. 【Docker】 Error running deviceCreate (CreateSnapDeviceRaw)

    问题详细信息: [root@passport docker]# docker-compose -f docker-compose.yml up -ddocker_db_1_1651de706222 i ...

  3. JavaScript 跨站攻击脚本-XSS

    XSS: Cross Site Scripting XSS 概念 恶意攻击者往Web页面里插入恶意script代码, 当用户浏览该页之时,嵌入Web里面的script代码会被执行,从达到恶意攻击的目的 ...

  4. JavaScript学习系列博客_1_JavaScript简介

    这个系列博客主要用来记录本人学习JavaScript的笔记,从0开始,即使有些知识我也是知道的.但是会经常忘记,干脆就写成博客,没事的时候翻来看一看,留下一点学习的痕迹也好.可能写博客的水平暂时不太好 ...

  5. MySQL数据库修改字段名、字段类型、字段长度

    1.MySQL数据库中,修改字段SQL如下: alter table AppVersion change version versionCode varchar() DEFAULT NULL COMM ...

  6. Java异步CompletableFuture的使用

    所谓异步调用其实就是实现一个可无需等待被调用函数的返回值而让操作继续运行的方法.Java中的CompletableFuture 提供了四个静态方法来创建一个异步操作. public static Co ...

  7. 洛谷T90444 密码 题解

    [问题描述] 假发通过了不懈的努力,得到了将军家门锁的密码(一串小写英文字母).但是假发被十四和猩猩他们盯上了,所以假发需要把密码传递出去.因为假发不想十四他们发现几松门前贴的小纸条就是将军家的密码, ...

  8. 操作系统-存储管理(5)IA-32/Linux的地址转换

    IA-32/Linux按字节编址:在保护模式下,IA-32采用段页式虚拟存储管理方式,存储地址采用逻辑地址.线性地址和物理地址来进行描述. 逻辑地址由48位组成,包含16位段选择符(高13位为段表项的 ...

  9. Ubuntu 统计文件夹下文件个数的命令

    查看当前目录下的文件数量(不包含子目录中的文件) ls -l|grep "^-"| wc -l 查看当前目录下的文件数量(包含子目录中的文件) 注意:R,代表子目录 ls -lR| ...

  10. jQuery源码分析系列(二)Sizzle选择器引擎-上

    前言 我们继续从init()方法中的find()方法往下看, jQuery.find = Sizzle; ... find: function (selector) { /** ... */ ret ...