FFmpeg AVPacket 剖析以及使用

知识准备
        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;
     av_new_packet(packet, nLen);
     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个字节的数据作为结尾的填充
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;
    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);
    } else
        av_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

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。