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指向的数据缓存