ffmpeg数据结构AVBuffer,AVFrame,AVPacket

AVBuffer
AVBuffer是FFmpeg中很常用的一种缓冲区,缓冲区使用引用计数(reference-counted)机制。
AVBufferRef则对AVBuffer缓冲区提供了一层封装,最主要的是作引用计数处理,实现了一种安全机制。用户不应直接访问AVBuffer,应通过AVBufferRef来访问AVBuffer,以保证安全。

struct AVBuffer {
    uint8_t *data; /**< data described by this buffer */
    int      size; /**< size of data in bytes */
 
    /**
     *  number of existing AVBufferRef instances referring to this buffer
     */
    atomic_uint refcount;
 
    /**
     * a callback for freeing the data
     */
    void (*free)(void *opaque, uint8_t *data);
 
    /**
     * an opaque pointer, to be used by the freeing callback
     */
    void *opaque;
 
    /**
     * A combination of BUFFER_FLAG_*
     */
    int flags;
};
  • data: 缓冲区地址
  • size: 缓冲区大小
  • refcount: 引用计数值
  • free: 用于释放缓冲区内存的回调函数
  • opaque: 提供给free回调函数的参数
  • flags: 缓冲区标志
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;
  • buffer: AVBuffer
  • data: 缓冲区地址,实际等于buffer->data
  • size: 缓冲区大小,实际等于buffer->size

AVFrame

AVFrame中存储的是经过解码后的原始数据。在解码中,AVFrame是解码器的输出;在编码中,AVFrame是编码器的输入。 

typedef struct AVFrame {
    uint8_t *data[AV_NUM_DATA_POINTERS];
    int linesize[AV_NUM_DATA_POINTERS];
    uint8_t **extended_data;
    int width, height;
    int nb_samples;
    int format;
    int key_frame;
    enum AVPictureType pict_type;
    AVRational sample_aspect_ratio;
    int64_t pts;
    ......
} AVFrame;

AVFrame数据结构非常重要,它的成员非常多,下面仅介绍一些重要成员。

data

存储原始帧数据(未编码的原始图像或音频格式,作为解码器的输出或编码器的输入)。
data是一个指针数组,数组的每一个元素是一个指针。
对于packet格式,一幅YUV图像的Y、U、V交织存储在一个plane中,形如YUVYUV...,data[0]指向这个plane;
一个双声道的音频帧其左声道L、右声道R交织存储在一个plane中,形如LRLRLR...,data[0]指向这个plane。
对于planar格式,一幅YUV图像有Y、U、V三个plane,data[0]指向Y plane,data[1]指向U plane,data[2]指向V plane;
一个双声道的音频帧有左声道L和右声道R两个plane,data[0]指向L plane,data[1]指向R plane。

linesize 

对于视频来说,linesize是每行图像的大小(字节数)。注意有对齐要求。
对于音频来说,linesize是每个plane的大小(字节数)。音频只使用linesize[0]。对于planar音频来说,每个plane的大小必须一样。
linesize可能会因性能上的考虑而填充一些额外的数据,因此linesize可能比实际对应的音视频数据尺寸要大。 

width, height 

视频帧宽和高(像素)。 

nb_samples 

音频帧中单个声道中包含的采样点数。 

format

帧格式。 

key_frame

视频帧是否是关键帧的标识,1->关键帧,0->非关键帧。

AVFrame相关函数
AVFrame *av_frame_alloc(void);
       构造一个AVFrame, 对象成员被设为默认值.

      此函数只分配AVFrame对象本身, 而不分配AVFrame中的数据缓存区.

void av_frame_free(AVFrame **frame);
       释放AVFrame.

int av_frame_ref(AVFrame *dst, const AVFrame *src);
      为src中的数据建立一个新的引用.

      将src中帧的各属性拷到dst中, 并且为src中每个AVBufferRef创建一个新的引用.

      如果src未使用引用计数, 则dst中会分配新的数据缓存区, 将src中缓存区的数据拷贝到dst中的缓存区.

AVFrame *av_frame_clone(const AVFrame *src);
       创建一个新的AVFrame, 新的AVFrame和src使用统一数据缓存区, 缓存区管理使用引用计数机制.

void av_frame_unref(AVFrame *frame);
       解除本AVFrame对AVFrame中所有缓存区的引用, 并复位AVFrame中的各成员.

void av_frame_move_ref(AVFrame *dst, AVFrame *src);
       将src中所有数据拷贝到dst中, 并复位src.

       为避免内存泄漏, 在调用av_frame_move_ref(dst, src)之前应先调用av_frame_unref(dst);

int av_frame_get_buffer(AVFrame *frame, int align); 
       为音频或视频数据分配新的缓冲区.

       调用本函数前, 帧中的以下成员必须先设置好:

       format

       width, height

       nb_samples, channel_layout

      本函数会填充AVFrame.data和AVFrame.buf数组,

      如果有需要, 还会分配和填充AVFrame.extended_data和 AVFrame.extended_buf.

      对于planar格式, 会为每个plane分配一个缓冲区.

int av_frame_copy(AVFrame *dst, const AVFrame *src);
      将src中的帧数据拷贝到dst中.

     本函数并不会有任何分配缓冲区的动作, 调用此函数前dst必须已经使用了和src同样的参数完成了初始化.

     本函数只拷贝帧中的数据缓冲区的内容, 而不涉及帧中的其它属性.

AVPacket
AVPacket中存储的是经过编码的压缩数据。在解码中,AVPacket由解复用器输出到解码器;在编码中,AVPacket由编码器输出到复用器。对于视频而言,一个AVPacket通常只包含一个压缩视频帧;而对于音频而言,一个AVPacket可能包含多个完整的音频压缩帧。

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.
     */
    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;
 
    int64_t pos;                            ///< byte position in stream, -1 if unknown
 
#if FF_API_CONVERGENCE_DURATION
    /**
     * @deprecated Same as the duration field, but as int64_t. This was required
     * for Matroska subtitles, whose duration values could overflow when the
     * duration field was still an int.
     */
    attribute_deprecated
    int64_t convergence_duration;
#endif
} AVPacket;

音视频数据缓冲区

uint8_t *data:
int size:
数据缓冲区地址与大小。音视频编码压缩数据存储于此片内存区域。此内存区域由AVBufferRef *buf管理。
AVBufferRef *buf:
数据缓冲区引用,也可叫引用计数缓冲区。对上一字段uint8_t *data指向的内存区域提供引用计数等管理机制。
AVBufferRef对数据缓冲区提供了管理机制,用户不应直接访问数据缓冲区。
如果buf值为NULL,则data指向的数据缓冲区不使用引用计数机制。av_packet_ref(dst, src)将执行数据缓冲区的拷贝,而非仅仅增加缓冲区引用计数。
如果buf值非NULL,则data指向的数据缓冲区使用引用计数机制。av_packet_ref(dst, src)将不拷贝缓冲区,而仅增加缓冲区引用计数。av_packet_unref()将数据缓冲区引用计数减1,当缓冲区引用计数为0时,缓冲区内存被FFmpeg回收。
对于struct AVPacket pkt对象,如果pkt.buf值非NULL,则有pkt.data == pkt.buf->data == pkt.buf->buffer.data
packet属性

int64_t pts:
显示时间戳。单位time_base,帧率的倒数。
int64_t dts:
解码时间戳。单位time_base,帧率的倒数。
int stream_index:
当前包(packet)所有流(stream)的索引(index)。
int flags:
packet标志位。比如是否关键帧等。
int64_t duration:
当前包解码后的帧播放持续的时长。单位timebase。值等于下一帧pts减当前帧pts。
int64_t pos:
当前包在流中的位置,单位字节。
AVPacket相关函数

void av_init_packet(AVPacket *pkt);

        初始化packet的值为默认值, 该函数不会影响data应用的数据缓存空间和size.

int av_new_packet(AVPacket *pkt, int size);
       内部调用了av_init_packet(pkt); 而且会为data分配空间.

AVPacket *av_packet_alloc(void);
      创建一个AVPacket, 将其字段设置为默认值, 没有给data分配空间.

int av_packet_ref(AVPacket *dst, const AVPacket *src);
     增加src->data引用计数.  如果src已经设置了引用计数, 则直接将引用计数+1;

     如果src没有设置引用计数, 则创建一个新的引用计数buf, 并复制src->data到buf->buffer中.最后复制src其它字段到dst中.

void av_packet_unref(AVPacket *pkt);
      将缓存空间的引用计数-1; 并将packet中的其它字段设置为初始值. 如果引用计数为0, 则释放缓存空间.

void av_packet_free(AVPacket **pkt);
       释放使用av_packet_alloc 创建的AVPacket,  该函数会调用av_packet_unref.

AVPacket *av_packet_clone(const AVPacket *src);
      函数内部调用了av_packet_alloc和av_packet_ref.

int av_copy_packet(AVPacket *dst, const AVPacket *src);
       复制一个新的packet, 包括数据缓存.

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

      复制src的附加数据到pkt.

int av_grow_packet(AVPacket *pkt, int grow_by);
       增大pkt->data指向的数据缓存.

void av_shrink_packet(AVPacket *pkt, int size)
       减小pkt->data指向的数据缓存

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值