文章目录

    • 知识准备
    • 重要结构体成员分析
    • 释疑
  • 函数说明
    • av_init_packet
    • av_packet_unref
    • av_packet_alloc
    • av_packet_free
    • av_packet_clone
    • av_copy_packet
    • av_copy_packet_side_data

知识准备

AVPacket:存储压缩数据(视频对应H.264等码流数据,音频对应AAC/MP3等码流数据),简单来说就是携带一个NAL视频单元,或者多个NAL音频单元。 AVPacket保存一个NAL单元的解码前数据,该结构本身不直接包含数据,其有一个指向数据域的指针。传递给avcodec_send_packet函数的AVPacket结构体data中的数据前面是00 00 00 01开头,说明是NALU格式的数据

重要结构体成员分析

        AVBufferRef *buf; //当前AVPacket中压缩数据的引用计数,以及保存压缩数据的指针地址(压缩数据申请的空间在这里)uint8_t *data;//保存压缩数据的指针地址(data同时指向了buf中的data)int   size;//压缩数据的长度int   stream_index;//视频还是音频的索引

实战(构建包含一个NAL单元(长度为nLen)的AVPacket)

     AVPacket pkt1, *packet  = &pkt1;//nLen压缩数据长度av_new_packet(packet, nLen); //已经为packet->buf申请内存,而data和buf指向同一片内存memcpy(packet->data, data, nLen);packet->size = nLen;packet->stream_index = 0;

然后就可以将packet加入链表等待解码出一帧数据,或者调用avcodec_decode_video2进行解码,解码之后,可以调用av_free_packet或者 av_packet_unref释放资源

释疑

1)为什么不直接对packet->data申请内存,然后进行数据的拷贝?按结构体中定义说明 AVBufferRef只是数据的引用计数,可以为NULL,代表没有任何的引用
所以上面的代码修改(不推荐):

         av_init_packet(packet);//初始化结构体,尤其是AVBufferRef *buf,避免packet->data = (uint8_t *)malloc(sizeof(uint8_t)* nByte);memcpy(packet->data, data, nLen);packet->size = nLen;packet->stream_index = 0;

注意:av_init_packet(packet);//初始化结构体,尤其是AVBufferRef *buf,避免在解码的时候,访问到非法的指针地址。
不推荐原因:无法使用av_free_packet或者 av_packet_unref进行资源的释放,必须手动释放掉packet->data申请的内存,因为这两个函数释放资源针对的都是AVPacket结构体中的buf,而不是data

void av_free_packet(AVPacket *pkt)
{if (pkt) {if (pkt->buf)av_buffer_unref(&pkt->buf);pkt->data            = NULL;pkt->size            = 0;av_packet_free_side_data(pkt);}
}
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;
}

2)为什么 AVBufferRef里面中的data跟外层的data指针是一样的,但是size长度不一样
根据

int av_new_packet(AVPacket *pkt, int size)
{AVBufferRef *buf = NULL;int ret = packet_alloc(&buf, size);if (ret < 0)return ret;av_init_packet(pkt);pkt->buf      = buf;pkt->data     = buf->data;pkt->size     = size;return 0;
}

可以得知两个data指针指向的是同一块内存,但是在申请内存的时候,进行了字节的对齐
多申请AV_INPUT_BUFFER_PADDING_SIZE个字节的数据作为结尾的填充

函数说明

初始化和释放相关的函数

  • av_packet_alloc(): 为AVPacket分配内存,不涉及存储压缩编码数据的buffer,可以使用其他方法来为buffer分配空间比如av_new_packet()。
  • av_init_packet(): 使用默认值初始化一些字段,并不会触碰AVPacket的成员data和size。
  • av_new_packet(): 根据指定的数据大小为AVPacket的buf分配的内存,然后调用了av_init_packet()进行初始化。
  • av_packet_from_data(): 使用已经分配好的buffer初始化一个AVPacket,会设置AVPacket的data和size成员。传入的size参数是减去了AV_INPUT_BUFFER_PADDING_SIZE的,也就是size + AV_INPUT_BUFFER_PADDING_SIZE等于buffer总的大小。
  • av_packet_free(): 释放AVPacket内存,如果AVPacket的数据是以引用计数方式存储的,则先解引用。

av_init_packet

void av_init_packet(AVPacket * pkt)

  • Initialize optional fields of a packet with default values.
  • Note, this does not touch the data and size members, which have to be initialized separately.
  • 初始化packet的值为默认值,注意:该函数不会影响data引用的数据缓存空间和size,需要单独处理。

av_packet_unref

void av_packet_unref ( AVPacket **pkt)

  • Wipe the packet.
  • Unreference the buffer referenced by the packet and reset the remaining packet fields to their default values.
  • 将缓存空间的引用计数-1,并将Packet中的其他字段设为初始值。如果引用计数为0,自动的释放缓存空间。

av_packet_alloc

AVPacket* av_packet_alloc(void )

  • Allocate an AVPacket and set its fields to default values.
    The resulting struct must be freed using av_packet_free().
  • 开辟packet空间并初始化默认值,需要av_packet_free()释放空间

av_packet_free

| void av_packet_free ( AVPacket ** pkt )

  • Free the packet, if the packet is reference counted, it will be unreferenced first.
  • 释放AVpacket空间,当引用有引用的时候会释放引用,彻底销毁AVpacket,需要重新av_packet_alloc
  • 一般就是如果用了av_packet_alloc后就要调用av_packet_free来释放
void av_packet_free(AVPacket **pkt)
{if (!pkt || !*pkt)return;av_packet_unref(*pkt);av_freep(pkt);
}

av_packet_clone

AVPacket *av_packet_clone(const AVPacket *src);

  • 其功能是av_packet_alloc和av_packet_ref

av_copy_packet

int av_copy_packet(AVPacket *dst, const AVPacket *src);

  • 复制一个新的packet,包括数据缓存

av_copy_packet_side_data

int av_copy_packet_side_data(AVPacket *dst, const AVPacket *src);

  • 初始化一个引用计数的packet,并指定了其数据缓存
void av_init_packet(AVPacket *pkt)
{pkt->pts                  = AV_NOPTS_VALUE;pkt->dts                  = AV_NOPTS_VALUE;pkt->pos                  = -1;pkt->duration             = 0;
#if FF_API_CONVERGENCE_DURATION
FF_DISABLE_DEPRECATION_WARNINGSpkt->convergence_duration = 0;
FF_ENABLE_DEPRECATION_WARNINGS
#endifpkt->flags                = 0;pkt->stream_index         = 0;pkt->buf                  = NULL;pkt->side_data            = NULL;pkt->side_data_elems      = 0;
}
//AV_INPUT_BUFFER_PADDING_SIZE是为了进行数据的对齐,方便数据的访问
static int packet_alloc(AVBufferRef **buf, int size)
{int ret;if (size < 0 || size >= INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE)return AVERROR(EINVAL);ret = av_buffer_realloc(buf, size + AV_INPUT_BUFFER_PADDING_SIZE);if (ret < 0)return ret;memset((*buf)->data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE);return 0;
}
创建一个AVBufferRef实例,然后申请size长度的内存分配给AVBufferRef实例中的data
int av_buffer_realloc(AVBufferRef **pbuf, int size)
{AVBufferRef *buf = *pbuf;uint8_t *tmp;if (!buf) {/* allocate a new buffer with av_realloc(), so it will be reallocatable* later */uint8_t *data = av_realloc(NULL, size);if (!data)return AVERROR(ENOMEM);buf = av_buffer_create(data, size, av_buffer_default_free, NULL, 0);if (!buf) {av_freep(&data);return AVERROR(ENOMEM);}buf->buffer->flags |= BUFFER_FLAG_REALLOCATABLE;*pbuf = buf;return 0;} else if (buf->size == size)return 0;if (!(buf->buffer->flags & BUFFER_FLAG_REALLOCATABLE) ||!av_buffer_is_writable(buf) || buf->data != buf->buffer->data) {/* cannot realloc, allocate a new reallocable buffer and copy data */AVBufferRef *new = NULL;av_buffer_realloc(&new, size);if (!new)return AVERROR(ENOMEM);memcpy(new->data, buf->data, FFMIN(size, buf->size));buffer_replace(pbuf, &new);return 0;}tmp = av_realloc(buf->buffer->data, size);if (!tmp)return AVERROR(ENOMEM);buf->buffer->data = buf->data = tmp;buf->buffer->size = buf->size = size;return 0;
}
//释放AVBufferRef申请内存
void av_buffer_unref(AVBufferRef **buf)
{if (!buf || !*buf)return;buffer_replace(buf, NULL);
}
static void buffer_replace(AVBufferRef **dst, AVBufferRef **src)
{AVBuffer *b;b = (*dst)->buffer;if (src) {**dst = **src;av_freep(src);} elseav_freep(dst);if (atomic_fetch_add_explicit(&b->refcount, -1, memory_order_acq_rel) == 1) {b->free(b->opaque, b->data);av_freep(&b);}
}

3)

数据简单如下:

00 00 00 01 61 e1 40 01 58 2b fb 22 ff 29 7b 3f 6f 67 2f 29 fa 25 53 68 78 46 b1

在调用avcodec_send_packet函数的时候打印错误如下:

I:2018-01-06 15:06:05 ms:887:nal_unit_type: 1, nal_ref_idc: 3
I:2018-01-06 15:06:05 ms:888:non-existing PPS 0 referenced
I:2018-01-06 15:06:05 ms:888:decode_slice_header error
I:2018-01-06 15:06:05 ms:888:no frame!

当数据如下,可以正确的解析出一帧图像

00 00 00 01 67 42 00 2a 96 35 40 f0 04 4f cb 37 01 01 01 40 00 01 c2 00 00 57 e4
01 00 00 00 01 68 ce 3c 80 00 00 00 01 06 e5 01 ef 80 00 00 03 00 00 00 01 65 b8
00 00 52 58 00 00 27 f5 d4 48 7e b4 41 07 24 60 95 2c 92 37 68 75 63 4c ad 3f b1

很显然,67是SPS,68是PPS,然后65是关键帧,开始出来图像

结构体定义

/*** A reference to a data buffer.** The size of this struct is not a part of the public ABI and it is not meant* to be allocated directly.*/
typedef struct AVBufferRef {AVBuffer *buffer;/*** The data buffer. It is considered writable if and only if* this is the only reference to the buffer, in which case* av_buffer_is_writable() returns 1.*/uint8_t *data;/*** Size of data in bytes.*/int      size;
} AVBufferRef;
/*** 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.** 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 or destruct (deprecated)* fields. If either is set, the packet data is dynamically allocated and is* valid indefinitely until av_free_packet() is called (which in turn calls* av_buffer_unref()/the destruct callback to free the data). If neither is set,* the packet data is typically backed by some static buffer somewhere and is* only valid for a limited time (e.g. until the next read call when demuxing).** The side data is always allocated with av_malloc() and is freed in* av_free_packet().*/
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.*/struct {uint8_t *data;int      size;enum AVPacketSideDataType type;} *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.*/int   duration;
#if FF_API_DESTRUCT_PACKETattribute_deprecatedvoid  (*destruct)(struct AVPacket *);attribute_deprecatedvoid  *priv;
#endifint64_t pos;                            ///< byte position in stream, -1 if unknown/*** Time difference in AVStream->time_base units from the pts of this* packet to the point at which the output from the decoder has converged* independent from the availability of previous frames. That is, the* frames are virtually identical no matter if decoding started from* the very first frame or from this keyframe.* Is AV_NOPTS_VALUE if unknown.* This field is not the display duration of the current packet.* This field has no meaning if the packet does not have AV_PKT_FLAG_KEY* set.** The purpose of this field is to allow seeking in streams that have no* keyframes in the conventional sense. It corresponds to the* recovery point SEI in H.264 and match_time_delta in NUT. It is also* essential for some types of subtitle streams to ensure that all* subtitles are correctly displayed after seeking.*/int64_t convergence_duration;
} AVPacket;

https://www.cnblogs.com/wangguchangqing/p/6138683.html

FFmpeg AVPacket 剖析以及使用相关推荐

  1. FFmpeg AVPacket和av_packet_unref函数剖析

    描述 AVPacket保存一个NAL单元的解码前数据,该结构本身不直接包含数据,其有一个指向数据域的指针.传递给avcodec_send_packet函数的AVPacket结构体data中的数据前面是 ...

  2. FFMpeg AVPacket 之理解与掌握

    ---------------------------------------- author:hjjdebug date: 2022-01-23 -------------------------- ...

  3. [FFmpeg] AVPacket 的使用记录(初始化、引用、解引用、释放)

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 一.先看下与AVPacket相关的几个重要函数 1.AVPacket *av_packet_alloc(void) 2 ...

  4. 行车记录仪 - 录像 - ffmpeg AVPacket 复用

    背景 基于ffmpeg实现录像功能,性能不理想,分析现有流程发现:写每一帧数据都需要生成一个AVPacket变量传递给av_write_frame,流程如下: av_new_packet函数申请一定大 ...

  5. go 接收 ffmpeg avpacket

    c++部分: typedef int(*ByteFunc)(unsigned char*, int); MYLIBDLL int byte_url(char* url, ByteFunc tcallb ...

  6. ffmpeg - AVPacket内存问题分析(AVFrame一样的)

    目录: 1.av_packet_alloc()和av_packet_free() 2.av_init_packet()的问题 3.av_packet_move_ref()的问题 4.av_packet ...

  7. 【Android FFMPEG 开发】FFMPEG 解码 AVPacket 数据到 AVFrame ( AVPacket-解码器 | 初始化 AVFrame | 解码为 AVFrame 数据 )

    文章目录 I . FFMPEG 解码 AVPacket 数据到 AVFrame 前置操作 II . FFMPEG 解码 AVPacket 数据到 AVFrame 流程 III . FFMPEG 发送 ...

  8. 【Android FFMPEG 开发】FFMPEG 读取音视频流中的数据到 AVPacket ( 初始化 AVPacket 数据 | 读取 AVPacket )

    文章目录 I . FFMPEG 获取 AVPacket 数据前置操作 II . FFMPEG 获取 AVPacket 数据流程 III . FFMPEG AVPacket 结构体 IV . AVPac ...

  9. FFMPEG结构体分析之AVPacket

    AVPacket:存储一帧压缩编码数据 AVPacket 结构体定义在ffmpeg/libavcodec/packet.h中 /*** This structure stores compressed ...

最新文章

  1. 写入和读取图片(c# asp.net sqlserver)
  2. 用js获取当前地理位置的经纬度
  3. mysql如何让自增id从某个位置开始设置方法
  4. python语言编写一个生成九宫格图片的代码_python实现图片九宫格分割
  5. php判断字符是否在某个数组_php:如何快速在数组array中找出以某字符串开头的值...
  6. 15.Object Manager
  7. 轻松获奖五一数学建模和蓝桥杯
  8. [已解决]ubuntu下谷歌浏览器无法上网
  9. 走楼梯c语言程序,动态规划走楼梯
  10. 工业级无线路由器自助设备无线联网
  11. 联想拯救者wif开不了_联想拯救者wifi开关
  12. java程序制作成可执行.exe文件
  13. JavaScript生成字符画(ASCII Art)
  14. 截图或者模糊图片高清处理方式
  15. WS-Trust和WS-SecureConversation
  16. 新手追高,熟手突破,老手抄底,高手回撤,庄家筹码,机构算法!
  17. 史上最全最牛的C++整人代码
  18. 使用uni-app开发一个取流播放器(网络电视)app简陋版
  19. 3DMax基础操作快捷键
  20. Maxwell简介、部署、原理和使用介绍

热门文章

  1. SQL 插入数据和查询
  2. 【第九篇】Flowable中的候选人讲解
  3. definer mysql_mysql存储过程的definer和invoker
  4. flutter 阿里云上传文件
  5. worker里的ajax,Web Worker 调用Ajax
  6. 用Vue制作天气预报
  7. QT_7(菜单栏、工具栏、状态栏、资源文件的添加)
  8. nnUNet实战一使用预训练nnUNet模型进行推理
  9. 实现 长链接变 短 链接
  10. 宝藏世界中什么叫服务器中断了,宝藏世界版本检查错误解决方法 Trove登陆不了怎么办...