AVPacket
AVPacket是存储压缩编码数据相关信息的结构AVPacket是FFmpeg中很重要的一个数据结构,它保存了解复用之后,解码之前的数据(仍然是压缩后的数据)和关于这些数据的一些附加信息,如显示时间戳(pts)、解码时间戳(dts)、数据时长,所在媒体流的索引等。对于视频来说,AVPacket通常包含一个压缩的Frame,而音频(Audio)则有可能包含多个压缩的Frame。并且,一个Packet
AVPacket是存储压缩编码数据相关信息的结构
AVPacket是FFmpeg中很重要的一个数据结构,它保存了解复用之后,解码之前的数据(仍然是压缩后的数据)和关于这些数据的一些附加信息,如显示时间戳(pts)、解码时间戳(dts)、数据时长,所在媒体流的索引等。对于视频来说,AVPacket通常包含一个压缩的Frame,而音频(Audio)则有可能包含多个压缩的Frame。并且,一个Packet有可能是空的,不包含任何压缩数据,只含有side
data(side
data,容器提供的关于Packet的一些附加信息。例如,在编码结束的时候更新一些流的参数)。AVPacket的大小是公共的ABI(public
ABI)一部分,这样的结构体在FFmpeg很少,由此也可见AVPacket的重要性。它可以被分配在栈空间上(可以使用语句AVPacket
packet; 在栈空间定义一个Packet ),并且除非libavcodec 和
libavformat有很大的改动,不然不会在AVPacket中添加新的字段。
AVPacket
avcodec.h
/**
* 该结构用来存储压缩数据. 这是典型的解复合器的输出然后塞入解码器,或者是接收编码器的输出然后塞入复合器
* 解复合器 --> AVPacket --> 解码器 --> YUV/RGB --> 编码器 --> AVPacket -->复合器
* 此结构存储压缩数据。它通常由分路器导出
* 然后作为输入传递给解码器,或作为输出从编码器接收和
* 然后传递给多路复用器。
*
* 对于视频,它通常应包含一个压缩帧。对于音频,它可能
* 包含几个压缩帧。编码器允许输出空
* 数据包,没有压缩数据,只包含边数据
*(例如在编码结束时更新一些流参数)。
*
* AVPacket 是 FFmpeg 中为数不多的结构体之一,其大小是 public 的一部分
* ABI。因此它可以在堆栈上分配并且不能向其中添加新字段
* 没有 libavcodec 和 libavformat 主要问题。
*
* 数据所有权的语义取决于 buf 字段。
* 如果设置,则包数据是动态分配的
* 无限期有效,直到调用 av_packet_unref() 减少
* 引用计数为 0。
*
* 如果未设置 buf 字段,则 av_packet_ref() 将进行复制
* 增加引用计数。
*
* 侧边数据总是用av_malloc()分配,复制
* av_packet_ref() 并由 av_packet_unref() 释放。
*
* @see av_packet_ref
* @see av_packet_unref
*/
typedef struct AVPacket {
/**
* 对数据包数据所在的引用计数缓冲区的引用
* 存储。
* 可能为NULL,则数据包数据不被引用计数。
*/
AVBufferRef *buf;
/**
* 以 AVStream->time_base 为单位的演示时间戳; 的时间
* 解压后的数据包将呈现给用户。
* 如果未存储在文件中,则可以是 AV_NOPTS_VALUE。
* pts 必须大于或等于 dts 因为演示不能在之前发生
* 解压,除非想要查看十六进制转储。 某些格式误用
* 术语 dts 和 pts/cts 表示不同的含义。 这样的时间戳
* 在将它们存储在 AVPacket 中之前,必须将它们转换为真正的 pts/dts。
*/
int64_t pts;
/**
* 以 AVStream->time_base 为单位的解压时间戳; 的时间
* 数据包被解压。
* 如果未存储在文件中,则可以是 AV_NOPTS_VALUE。
*/
int64_t dts;
uint8_t *data;
int size;
int stream_index;
/**
* AV_PKT_FLAG 值的组合
*/
int flags;
/**
* 容器可以提供的额外数据包数据。
* 数据包可以包含多种类型的边信息。
*/
AVPacketSideData *side_data;
int side_data_elems;
/**
* 此数据包的持续时间以 AVStream->time_base 为单位,如果未知则为 0。
* 等于 next_pts - this_pts 按演示顺序。
*/
int64_t duration;
int64_t pos; ///< byte position in stream, -1 if unknown
#if FF_API_CONVERGENCE_DURATION
/**
* @deprecated 与持续时间字段相同,但与 int64_t 相同。 这是必需的
* 对于 Matroska 字幕,其持续时间值可能会在
* 持续时间字段仍然是一个整数。
*/
attribute_deprecated
int64_t convergence_duration;
#endif
} AVPacket;
AVPacket相关API
av_packet_alloc()
/**
* 分配一个 AVPacket 并将其字段设置为默认值。 所结果的
* 必须使用 av_packet_free() 释放结构体。
*
* @return 一个 AVPacket 填充默认值或失败时为 NULL。
*
* @note 这只会分配 AVPacket 本身,而不是数据缓冲区。 那些
* 必须通过av_new_packet等其他方式分配。
*
* @see av_new_packet
*/
AVPacket *av_packet_alloc(void);
//源码:
AVPacket *av_packet_alloc(void)
{
AVPacket *pkt = av_mallocz(sizeof(AVPacket));
if (!pkt)
return pkt;
av_packet_unref(pkt);
return pkt;
}
av_packet_clone
/**
* 创建一个引用与 src 相同数据的新数据包。
*
* 这是 av_packet_alloc()+av_packet_ref() 的快捷方式。
*
* @return 成功时新创建的 AVPacket,错误时为 NULL。
*
* @see av_packet_alloc
* @see av_packet_ref
*/
AVPacket *av_packet_clone(const AVPacket *src);
//源码:
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_free
/**
* 释放数据包,如果数据包被引用计数,它将是
* 首先未引用。
*
* @param pkt 数据包被释放。 指针将被设置为 NULL。
* @note 传递 NULL 是空操作。
*/
void av_packet_free(AVPacket **pkt);
//源码:
void av_packet_free(AVPacket **pkt)
{
if (!pkt || !*pkt)
return;
av_packet_unref(*pkt);
av_freep(pkt);
}
av_init_packet
/**
* 使用默认值初始化数据包的可选字段。
*
* 注意,这不会触及数据和大小成员,它们必须是
* 单独初始化。
*
* @param pkt 数据包
*/
void av_init_packet(AVPacket *pkt);
//源码:
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_WARNINGS
pkt->convergence_duration = 0;
FF_ENABLE_DEPRECATION_WARNINGS
#endif
pkt->flags = 0;
pkt->stream_index = 0;
pkt->buf = NULL; //buf设置为NULL
pkt->side_data = NULL;
pkt->side_data_elems = 0;
}
av_new_packet
/**
* 分配一个数据包的有效载荷并初始化它的字段
* 默认值。
*
* @param pkt 数据包
* @param size 想要的有效载荷大小
* @return 0 如果正常,则 AVERROR_xxx 否则
*/
int av_new_packet(AVPacket *pkt, int 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;
}
av_shrink_packet
/**
*减少数据包大小,正确归零填充
*
* @param pkt 数据包
* @param size 新尺寸
*/
void av_shrink_packet(AVPacket *pkt, int size);
//定义;
void av_shrink_packet(AVPacket *pkt, int size)
{
if (pkt->size <= size)
return;
pkt->size = size;
memset(pkt->data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
}
av_grow_packet
/**
* 增加数据包大小,正确清零填充
*
* @param pkt 数据包
* @param grow_by 增加数据包大小的字节数
*/
int av_grow_packet(AVPacket *pkt, int grow_by);
//定义
int av_grow_packet(AVPacket *pkt, int grow_by)
{
int new_size;
av_assert0((unsigned)pkt->size <= INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE);
if ((unsigned)grow_by >
INT_MAX - (pkt->size + AV_INPUT_BUFFER_PADDING_SIZE))
return AVERROR(ENOMEM);
new_size = pkt->size + grow_by + AV_INPUT_BUFFER_PADDING_SIZE;
if (pkt->buf) {
size_t data_offset;
uint8_t *old_data = pkt->data;
if (pkt->data == NULL) {
data_offset = 0;
pkt->data = pkt->buf->data;
} else {
data_offset = pkt->data - pkt->buf->data;
if (data_offset > INT_MAX - new_size)
return AVERROR(ENOMEM);
}
if (new_size + data_offset > pkt->buf->size) {
int ret = av_buffer_realloc(&pkt->buf, new_size + data_offset);
if (ret < 0) {
pkt->data = old_data;
return ret;
}
pkt->data = pkt->buf->data + data_offset;
}
} else {
pkt->buf = av_buffer_alloc(new_size);
if (!pkt->buf)
return AVERROR(ENOMEM);
if (pkt->size > 0)
memcpy(pkt->buf->data, pkt->data, pkt->size);
pkt->data = pkt->buf->data;
}
pkt->size += grow_by;
memset(pkt->data + pkt->size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
return 0;
}
av_packet_from_data
/**
* 从 av_malloc()ed 数据初始化引用计数数据包。
*
* @param pkt 数据包被初始化。 此函数将设置数据、大小、
* 和 buf 字段,所有其他字段保持不变。
* @param data 由 av_malloc() 分配的数据,用作数据包数据。 如果这
* 函数返回成功,数据归底层AVBuffer所有。
* 来电者不得通过其他方式访问数据。
* @param size 以字节为单位的数据大小,没有填充。 IE。 完整的缓冲区
* 假定大小为 size + AV_INPUT_BUFFER_PADDING_SIZE。
*
* @return 成功时返回 0,错误时返回负 AVERROR
*/
int av_packet_from_data(AVPacket *pkt, uint8_t *data, int size);
//定义
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, 0);
if (!pkt->buf)
return AVERROR(ENOMEM);
pkt->data = data;
pkt->size = size;
return 0;
}
av_dup_packet
#if FF_API_AVPACKET_OLD_API
/**
* @warning 这是一个黑客 - 数据包内存分配的东西被破坏了。 这
* 如果数据包没有真正分配,则分配数据包。
*
* @deprecated 使用 av_packet_ref 或 av_packet_make_refcounted
*/
attribute_deprecated
int av_dup_packet(AVPacket *pkt);
//定义
int av_dup_packet(AVPacket *pkt)
{
AVPacket tmp_pkt;
if (!pkt->buf && pkt->data) {
tmp_pkt = *pkt;
return copy_packet_data(pkt, &tmp_pkt, 1);
}
return 0;
}
av_copy_packet
/**
* 复制数据包,包括内容
*
* @return 成功时返回 0,失败时返回负 AVERROR
*
* @deprecated 使用 av_packet_ref
*/
attribute_deprecated
int av_copy_packet(AVPacket *dst, const AVPacket *src);
//定义
int av_copy_packet(AVPacket *dst, const AVPacket *src)
{
*dst = *src;
return copy_packet_data(dst, src, 0);
}
av_copy_packet_side_data
/**
* 复制包端数据
*
* @return 成功时返回 0,失败时返回负 AVERROR
*
* @deprecated 使用 av_packet_copy_props
*/
attribute_deprecated
int av_copy_packet_side_data(AVPacket *dst, const AVPacket *src);
//定义
int av_copy_packet_side_data(AVPacket *pkt, const AVPacket *src)
{
if (src->side_data_elems) {
int i;
DUP_DATA(pkt->side_data, src->side_data,
src->side_data_elems * sizeof(*src->side_data), 0, ALLOC_MALLOC);
if (src != pkt) {
memset(pkt->side_data, 0,
src->side_data_elems * sizeof(*src->side_data));
}
for (i = 0; i < src->side_data_elems; i++) {
DUP_DATA(pkt->side_data[i].data, src->side_data[i].data,
src->side_data[i].size, 1, ALLOC_MALLOC);
pkt->side_data[i].size = src->side_data[i].size;
pkt->side_data[i].type = src->side_data[i].type;
}
}
pkt->side_data_elems = src->side_data_elems;
return 0;
failed_alloc:
av_packet_unref(pkt);
return AVERROR(ENOMEM);
}
av_free_packet
/**
* 免费一包。
*
* @deprecated 使用 av_packet_unref
*
* @param pkt 数据包释放
*/
attribute_deprecated
void av_free_packet(AVPacket *pkt);
//定义
FF_DISABLE_DEPRECATION_WARNINGS
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);
}
}
av_packet_new_side_data
#endif
/**
* 分配数据包的新信息。
*
* @param pkt 数据包
* @param type 边信息类型
* @param size 边信息大小
* @return 指向新分配数据的指针,否则为 NULL
*/
uint8_t* av_packet_new_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
int size);
//定义
uint8_t *av_packet_new_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
int size)
{
int ret;
uint8_t *data;
if ((unsigned)size > INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE)
return NULL;
data = av_mallocz(size + AV_INPUT_BUFFER_PADDING_SIZE);
if (!data)
return NULL;
ret = av_packet_add_side_data(pkt, type, data, size);
if (ret < 0) {
av_freep(&data);
return NULL;
}
return data;
}
av_packet_add_side_data
/**
* 将现有数组包装为数据包端数据。
*
* @param pkt 数据包
* @param type 边信息类型
* @param data 边数据数组。 它必须用 av_malloc() 分配
* 函数族。 数据的所有权转移到
* 包。
* @param size 边信息大小
* @return 成功时为非负数,成功时为负 AVERROR 代码
* 失败。 失败时,数据包不变,数据保持不变
* 由调用者拥有。
*/
int av_packet_add_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
uint8_t *data, size_t size);
//定义
int av_packet_add_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
uint8_t *data, size_t size)
{
AVPacketSideData *tmp;
int i, elems = pkt->side_data_elems;
for (i = 0; i < elems; i++) {
AVPacketSideData *sd = &pkt->side_data[i];
if (sd->type == type) {
av_free(sd->data);
sd->data = data;
sd->size = size;
return 0;
}
}
if ((unsigned)elems + 1 > AV_PKT_DATA_NB)
return AVERROR(ERANGE);
tmp = av_realloc(pkt->side_data, (elems + 1) * sizeof(*tmp));
if (!tmp)
return AVERROR(ENOMEM);
pkt->side_data = tmp;
pkt->side_data[elems].data = data;
pkt->side_data[elems].size = size;
pkt->side_data[elems].type = type;
pkt->side_data_elems++;
return 0;
}
av_packet_shrink_side_data
/**
* 缩小已经分配的侧数据缓冲区
*
* @param pkt 数据包
* @param type 边信息类型
* @param size 新的边信息大小
* @return 0 成功,< 0 失败
*/
int av_packet_shrink_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
int size);
//定义
int av_packet_shrink_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
int size)
{
int i;
for (i = 0; i < pkt->side_data_elems; i++) {
if (pkt->side_data[i].type == type) {
if (size > pkt->side_data[i].size)
return AVERROR(ENOMEM);
pkt->side_data[i].size = size;
return 0;
}
}
return AVERROR(ENOENT);
}
av_packet_get_side_data
/**
* 从数据包中获取边信息。
*
* @param pkt 数据包
* @param type 所需的边信息类型
* @param size 用于存储边信息大小的指针(可选)
* @return 指向数据的指针(如果存在,否则为 NULL)
*/
uint8_t* av_packet_get_side_data(const AVPacket *pkt, enum AVPacketSideDataType type,
int *size);
//定义
uint8_t *av_packet_get_side_data(const AVPacket *pkt, enum AVPacketSideDataType type,
int *size)
{
int i;
for (i = 0; i < pkt->side_data_elems; i++) {
if (pkt->side_data[i].type == type) {
if (size)
*size = pkt->side_data[i].size;
return pkt->side_data[i].data;
}
}
if (size)
*size = 0;
return NULL;
}
#if FF_API_MERGE_SD_API
attribute_deprecated
int av_packet_merge_side_data(AVPacket *pkt);
attribute_deprecated
int av_packet_split_side_data(AVPacket *pkt);
#endif
const char *av_packet_side_data_name(enum AVPacketSideDataType type);
av_paket_pack_dictionary
/**
* 打包用于 side_data 的字典。
*
* @param dict 要打包的字典。
* @param size 指针存储返回数据的大小
* @return 如果成功则返回数据指针,否则为NULL
*/
uint8_t *av_paket_pack_dictionary(AVDictionary *dict, int *size);
//定义
uint8_t *av_packet_pack_dictionary(AVDictionary *dict, int *size)
{
AVDictionaryEntry *t = NULL;
uint8_t *data = NULL;
*size = 0;
if (!dict)
return NULL;
while ((t = av_dict_get(dict, "", t, AV_DICT_IGNORE_SUFFIX))) {
const size_t keylen = strlen(t->key);
const size_t valuelen = strlen(t->value);
const size_t new_size = *size + keylen + 1 + valuelen + 1;
uint8_t *const new_data = av_realloc(data, new_size);
if (!new_data)
goto fail;
data = new_data;
if (new_size > INT_MAX)
goto fail;
memcpy(data + *size, t->key, keylen + 1);
memcpy(data + *size + keylen + 1, t->value, valuelen + 1);
*size = new_size;
}
return data;
fail:
av_freep(&data);
*size = 0;
return NULL;
}
av_packet_unpack_dictionary
/**
* 从 side_data 解压字典。
*
* @param data 来自 side_data 的数据
* @param size 数据的大小
* @param dict 元数据存储字典
* @return 0 成功,< 0 失败
*/
int av_packet_unpack_dictionary(const uint8_t *data, int size, AVDictionary **dict);
//定义
int av_packet_unpack_dictionary(const uint8_t *data, int size, AVDictionary **dict)
{
const uint8_t *end;
int ret = 0;
if (!dict || !data || !size)
return ret;
end = data + size;
if (size && end[-1])
return AVERROR_INVALIDDATA;
while (data < end) {
const uint8_t *key = data;
const uint8_t *val = data + strlen(key) + 1;
if (val >= end || !*key)
return AVERROR_INVALIDDATA;
ret = av_dict_set(dict, key, val, 0);
if (ret < 0)
break;
data = val + strlen(val) + 1;
}
return ret;
}
av_packet_free_side_data
/**
* 方便的功能可以释放所有存储的侧面数据。
* 所有其他字段保持不变。
*
* @param pkt 数据包
*/
void av_packet_free_side_data(AVPacket *pkt);
//定义
void av_packet_free_side_data(AVPacket *pkt)
{
int i;
for (i = 0; i < pkt->side_data_elems; i++)
av_freep(&pkt->side_data[i].data);
av_freep(&pkt->side_data);
pkt->side_data_elems = 0;
}
av_packet_ref
/**
* 设置对给定数据包描述的数据的新引用
*
* 如果 src 是引用计数,则将 dst 设置为对
* src 中的缓冲区。 否则在 dst 中分配一个新缓冲区并复制
* 将数据从 src 导入其中。
*
* 所有其他字段均从 src 复制。
*
* @see av_packet_unref
*
* @param dst 目标包
* @param src 源数据包
*
* @return 成功时返回 0,错误时返回负 AVERROR。
*/
int av_packet_ref(AVPacket *dst, const AVPacket *src);
//定义
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;
av_assert1(!src->size || src->data);
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_unref
/**
* 擦拭数据包。
*
* 取消引用数据包引用的缓冲区并重置
* 剩余的数据包字段为其默认值。
*
* @param pkt 要取消引用的数据包。
*/
void av_packet_unref(AVPacket *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;
}
av_packet_move_ref
/**
* 将 src 中的每个字段移动到 dst 并重置 src。
*
* @see av_packet_unref
*
* @param src 源数据包,将被重置
* @param dst 目标包
*/
void av_packet_move_ref(AVPacket *dst, AVPacket *src);
//定义
void av_packet_move_ref(AVPacket *dst, AVPacket *src)
{
*dst = *src;
av_init_packet(src);
src->data = NULL;
src->size = 0;
}
av_packet_copy_props
/**
* 仅将“属性”字段从 src 复制到 dst。
*
* 用于此功能的属性是所有字段
* 除了那些与包数据相关的(buf、data、size)
*
* @param dst 目标包
* @param src 源数据包
*
* @return 0 成功 AVERROR 失败。
*/
int av_packet_copy_props(AVPacket *dst, const AVPacket *src);
//定义
int av_packet_copy_props(AVPacket *dst, const AVPacket *src)
{
int i;
dst->pts = src->pts;
dst->dts = src->dts;
dst->pos = src->pos;
dst->duration = src->duration;
#if FF_API_CONVERGENCE_DURATION
FF_DISABLE_DEPRECATION_WARNINGS
dst->convergence_duration = src->convergence_duration;
FF_ENABLE_DEPRECATION_WARNINGS
#endif
dst->flags = src->flags;
dst->stream_index = src->stream_index;
dst->side_data = NULL;
dst->side_data_elems = 0;
for (i = 0; i < src->side_data_elems; i++) {
enum AVPacketSideDataType type = src->side_data[i].type;
int size = src->side_data[i].size;
uint8_t *src_data = src->side_data[i].data;
uint8_t *dst_data = av_packet_new_side_data(dst, type, size);
if (!dst_data) {
av_packet_free_side_data(dst);
return AVERROR(ENOMEM);
}
memcpy(dst_data, src_data, size);
}
return 0;
}
av_packet_make_refcounted
/**
* 确保给定数据包描述的数据被引用计数。
*
* @note 这个函数不能保证引用是可写的。
* 为此目的,请改用 av_packet_make_writable。
*
* @see av_packet_ref
* @see av_packet_make_writable
*
* @param pkt 数据包,其数据应进行引用计数。
*
* @return 成功时返回 0,错误时返回负 AVERROR。 失败时,
* 数据包不变。
*/
int av_packet_make_refcounted(AVPacket *pkt);
//定义
int av_packet_make_refcounted(AVPacket *pkt)
{
int ret;
if (pkt->buf)
return 0;
ret = packet_alloc(&pkt->buf, pkt->size);
if (ret < 0)
return ret;
av_assert1(!pkt->size || pkt->data);
if (pkt->size)
memcpy(pkt->buf->data, pkt->data, pkt->size);
pkt->data = pkt->buf->data;
return 0;
}
av_packet_make_writable
/**
* 为给定数据包描述的数据创建一个可写的引用,
* 尽可能避免数据复制。
*
* @param pkt 数据应可写的数据包。
*
* @return 成功时返回 0,失败时返回负的 AVERROR。 失败时,
* 数据包不变。
*/
int av_packet_make_writable(AVPacket *pkt);
//定义
int av_packet_make_writable(AVPacket *pkt)
{
AVBufferRef *buf = NULL;
int ret;
if (pkt->buf && av_buffer_is_writable(pkt->buf))
return 0;
ret = packet_alloc(&buf, pkt->size);
if (ret < 0)
return ret;
av_assert1(!pkt->size || pkt->data);
if (pkt->size)
memcpy(buf->data, pkt->data, pkt->size);
av_buffer_unref(&pkt->buf);
pkt->buf = buf;
pkt->data = buf->data;
return 0;
}
av_packet_rescale_ts
/**
* 将数据包中的有效计时字段(时间戳/持续时间)从一个转换
* 时基到另一个。 具有未知值 (AV_NOPTS_VALUE) 的时间戳将是
* 忽略。
*
* @param pkt 数据包,将在其上执行转换
* @param tb_src 源时基,其中pkt中的时序字段为
* 表达
* @param tb_dst 目标时基,计时字段将指向该时基
* 转换
*/
void av_packet_rescale_ts(AVPacket *pkt, AVRational tb_src, AVRational tb_dst);
//定义
void av_packet_rescale_ts(AVPacket *pkt, AVRational src_tb, AVRational dst_tb)
{
if (pkt->pts != AV_NOPTS_VALUE)
pkt->pts = av_rescale_q(pkt->pts, src_tb, dst_tb);
if (pkt->dts != AV_NOPTS_VALUE)
pkt->dts = av_rescale_q(pkt->dts, src_tb, dst_tb);
if (pkt->duration > 0)
pkt->duration = av_rescale_q(pkt->duration, src_tb, dst_tb);
#if FF_API_CONVERGENCE_DURATION
FF_DISABLE_DEPRECATION_WARNINGS
if (pkt->convergence_duration > 0)
pkt->convergence_duration = av_rescale_q(pkt->convergence_duration, src_tb, dst_tb);
FF_ENABLE_DEPRECATION_WARNINGS
#endif
}
测试
#include "avpacket.h"
#define MEM_ITEM_SIZE (20*1024*102)
#define AVPACKET_LOOP_COUNT 1000
// 测试 内存泄漏
/**
* @brief 测试av_packet_alloc和av_packet_free的配对使用
*/
void av_packet_test1()
{
AVPacket *pkt = NULL;
int ret = 0;
pkt = av_packet_alloc(); //分配一个 AVPacket 并将其字段设置为默认值。 所结果的必须使用 av_packet_free() 释放结构体。
ret = av_new_packet(pkt, MEM_ITEM_SIZE); // 引用计数初始化为1
memccpy(pkt->data, (void *)&av_packet_test1, 1, MEM_ITEM_SIZE);
av_packet_unref(pkt); // 要不要调用
av_packet_free(&pkt); // 如果不free将会发生内存泄漏,内部调用了 av_packet_unref
}
/**
* @brief 测试误用av_init_packet将会导致内存泄漏
*/
void av_packet_test2()
{
AVPacket *pkt = NULL;
int ret = 0;
pkt = av_packet_alloc();
ret = av_new_packet(pkt, MEM_ITEM_SIZE);
memccpy(pkt->data, (void *)&av_packet_test1, 1, MEM_ITEM_SIZE);
//av_init_packet(pkt); // 这个时候init就会导致内存无法释放
av_packet_free(&pkt);
}
/**
* @brief 测试av_packet_move_ref后,可以不用av_init_packet
*/
void av_packet_test3()
{
AVPacket *pkt = NULL;
AVPacket *pkt2 = NULL;
int ret = 0;
pkt = av_packet_alloc();
ret = av_new_packet(pkt, MEM_ITEM_SIZE);
memccpy(pkt->data, (void *)&av_packet_test1, 1, MEM_ITEM_SIZE);
pkt2 = av_packet_alloc(); // 必须先alloc
av_packet_move_ref(pkt2, pkt);//内部其实也调用了av_init_packet
av_init_packet(pkt);
av_packet_free(&pkt);
av_packet_free(&pkt2);
}
/**
* @brief 测试av_packet_clone
*/
void av_packet_test4()
{
AVPacket *pkt = NULL;
// av_packet_alloc()没有必要,因为av_packet_clone内部有调用 av_packet_alloc
AVPacket *pkt2 = NULL;
int ret = 0;
pkt = av_packet_alloc();
ret = av_new_packet(pkt, MEM_ITEM_SIZE);
memccpy(pkt->data, (void *)&av_packet_test1, 1, MEM_ITEM_SIZE);
pkt2 = av_packet_clone(pkt); // av_packet_alloc()+av_packet_ref()
av_init_packet(pkt);
av_packet_free(&pkt);
av_packet_free(&pkt2);
}
/**
* @brief 测试av_packet_ref
*/
void av_packet_test5()
{
AVPacket *pkt = NULL;
AVPacket *pkt2 = NULL;
int ret = 0;
pkt = av_packet_alloc(); //分配一个AVPacket空间
if(pkt->buf) // 打印referenc-counted,必须保证传入的是有效指针
{ printf("%s(%d) ref_count(pkt) = %d\n", __FUNCTION__, __LINE__,
av_buffer_get_ref_count(pkt->buf));
}
ret = av_new_packet(pkt, MEM_ITEM_SIZE);//分配一个数据包的有效载荷并初始化它的字段* 默认值。
if(pkt->buf) // 打印referenc-counted,必须保证传入的是有效指针
{ printf("%s(%d) ref_count(pkt) = %d\n", __FUNCTION__, __LINE__,
av_buffer_get_ref_count(pkt->buf));
}
memccpy(pkt->data, (void *)&av_packet_test1, 1, MEM_ITEM_SIZE);
pkt2 = av_packet_alloc(); // 必须先alloc
av_packet_move_ref(pkt2, pkt); // av_packet_move_ref 将 src 中的每个字段移动到 dst 并重置 src。
// av_init_packet(pkt); //av_packet_move_ref
av_packet_ref(pkt, pkt2); //引用计数, 如果 src 是引用计数,则将 dst 设置为对src 中的缓冲区。 否则在 dst 中分配一个新缓冲区并复制将数据从 src 导入其中。
av_packet_ref(pkt, pkt2); // 多次ref如果没有对应多次unref将会内存泄漏
if(pkt->buf) // 打印referenc-counted,必须保证传入的是有效指针
{ printf("%s(%d) ref_count(pkt) = %d\n", __FUNCTION__, __LINE__,
av_buffer_get_ref_count(pkt->buf));
}
if(pkt2->buf) // 打印referenc-counted,必须保证传入的是有效指针
{ printf("%s(%d) ref_count(pkt) = %d\n", __FUNCTION__, __LINE__,
av_buffer_get_ref_count(pkt2->buf));
}
av_packet_unref(pkt); // 将为2 取消引用数据包引用的缓冲区并重置剩余的数据包字段为其默认值。
av_packet_unref(pkt); // 做第二次是没有用的
if(pkt->buf)
printf("pkt->buf没有被置NULL\n");
else
printf("pkt->buf已经被置NULL\n");
if(pkt2->buf) // 打印referenc-counted,必须保证传入的是有效指针
{ printf("%s(%d) ref_count(pkt) = %d\n", __FUNCTION__, __LINE__,
av_buffer_get_ref_count(pkt2->buf));
}
av_packet_unref(pkt2);
av_packet_free(&pkt); //释放数据包
av_packet_free(&pkt2);
}
/**
* @brief 测试AVPacket整个结构体赋值, 和av_packet_move_ref类似
*/
void av_packet_test6()
{
AVPacket *pkt = NULL;
AVPacket *pkt2 = NULL;
int ret = 0;
pkt = av_packet_alloc();
ret = av_new_packet(pkt, MEM_ITEM_SIZE);
memccpy(pkt->data, (void *)&av_packet_test1, 1, MEM_ITEM_SIZE);
pkt2 = av_packet_alloc(); // 必须先alloc
*pkt2 = *pkt; // 有点类似 pkt可以重新分配内存
av_init_packet(pkt);
av_packet_free(&pkt);
av_packet_free(&pkt2);
}
void av_packet_test()
{
// av_packet_test1();
// av_packet_test2();
// av_packet_test3();
// av_packet_test4();
// av_packet_test5();
av_packet_test6();
}
更多推荐
所有评论(0)