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

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐