天天看點

FFmpeg資料結構AVFrame

本文為作者原創,轉載請注明出處:https://www.cnblogs.com/leisure_chn/p/10404502.html

本文基于 FFmpeg 4.1 版本。

1. 資料結構定義

1.1 相關基礎概念

在閱讀 AVFrame 資料結構之前,需要先了解與之相關的幾個基礎概念(此處隻考慮視訊相關):

pixel_format:像素格式,圖像像素在記憶體中的排列格式。一種像素格式包含有色彩空間、采樣方式、存儲模式、位深等資訊。

bit_depth: 位深,指每個分量(Y、U、V、R、G、B 等)單個采樣點所占的位寬度。

plane: 存儲圖像中一個或多個分量的一片記憶體區域。planar 存儲模式中,至少有一個分量占用單獨的一個 plane,planar 存儲模式至少有兩個 plane,具體到 yuv420p 格式有 Y、U、V 三個 plane,nv12 格式有 Y、UV 兩個 plane,gbrap 格式有 G、B、R、A 四個 plane。packed 存儲模式中,因為所有分量的像素是交織存放的,是以 packed 存儲模式隻有一個 plane。

slice: 圖像中一片連續的行,必須是連續的,順序由頂部到底部或由底部到頂部

stride/pitch: 一行圖像中某個分量(如亮度分量或色度分量)所占的位元組數, 也就是一個 plane 中一行資料的寬度。有對齊要求,計算公式如下:

stride 值 = 圖像寬度 * 分量數 * 單樣本位寬度 / 水準子采樣因子 / 8
           

其中,圖像寬度表示圖像寬度是多少個像素,分量數指目前 plane 包含多少個分量(如 rgb24 格式一個 plane 有 R、G、B 三個分量),機關本位寬度指某分量的一個樣本在考慮對齊後在記憶體中占用的實際位數(例如位深 8 占 8 位寬,位深 10 實際占 16 位寬,對齊值與平台相關),水準子采樣因子指在水準方向上每多少個像素采樣出一個色度樣本(亮度樣本不進行下采樣,是以采樣因子總是 1)。

上述概念的詳細說明可參考“色彩空間與像素格式”一文第 4 節。

1.2 AVFrame 資料結構

struct AVFrame 定義于 <libavutil/frame.h>

struct AVFrame frame;
           

AVFrame 中存儲的是經過解碼後的原始資料。在解碼中,AVFrame 是解碼器的輸出;在編碼中,AVFrame 是編碼器的輸入。下圖中,“decoded frames”的資料類型就是 AVFrame:

_______              ______________
|       |            |              |
| input |  demuxer   | encoded data |   decoder
| file  | ---------> | packets      | -----+
|_______|            |______________|      |
                                           v
                                       _________
                                      |         |
                                      | decoded |
                                      | frames  |
                                      |_________|
 ________             ______________       |
|        |           |              |      |
| output | <-------- | encoded data | <----+
| file   |   muxer   | packets      |   encoder
|________|           |______________|

           

AVFrame 資料結構非常重要,它的成員非常多,導緻資料結構定義篇幅很長。下面引用的資料結構定義中省略冗長的注釋以及大部分成員,先總體說明 AVFrame 的用法,然後再将一些重要成員摘錄出來單獨進行說明:

/**
 * This structure describes decoded (raw) audio or video data.
 *
 * AVFrame must be allocated using av_frame_alloc(). Note that this only
 * allocates the AVFrame itself, the buffers for the data must be managed
 * through other means (see below).
 * AVFrame must be freed with av_frame_free().
 *
 * AVFrame is typically allocated once and then reused multiple times to hold
 * different data (e.g. a single AVFrame to hold frames received from a
 * decoder). In such a case, av_frame_unref() will free any references held by
 * the frame and reset it to its original clean state before it
 * is reused again.
 *
 * The data described by an AVFrame is usually reference counted through the
 * AVBuffer API. The underlying buffer references are stored in AVFrame.buf /
 * AVFrame.extended_buf. An AVFrame is considered to be reference counted if at
 * least one reference is set, i.e. if AVFrame.buf[0] != NULL. In such a case,
 * every single data plane must be contained in one of the buffers in
 * AVFrame.buf or AVFrame.extended_buf.
 * There may be a single buffer for all the data, or one separate buffer for
 * each plane, or anything in between.
 *
 * sizeof(AVFrame) is not a part of the public ABI, so new fields may be added
 * to the end with a minor bump.
 *
 * Fields can be accessed through AVOptions, the name string used, matches the
 * C structure field name for fields accessible through AVOptions. The AVClass
 * for AVFrame can be obtained from avcodec_get_frame_class()
 */
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 的用法:

  1. AVFrame 對象必須調用 av_frame_alloc() 在堆上配置設定,注意此處指的是 AVFrame 對象本身,AVFrame 對象必須調用 av_frame_free() 進行銷毀。
  2. AVFrame 中包含的資料緩沖區是
  3. AVFrame 通常隻需配置設定一次,然後可以多次重用,每次重用前應調用 av_frame_unref() 将 frame 複位到原始的幹淨可用的狀态。

下面将一些重要的成員摘錄出來進行說明:

data

/**
     * pointer to the picture/channel planes.
     * This might be different from the first allocated byte
     *
     * Some decoders access areas outside 0,0 - width,height, please
     * see avcodec_align_dimensions2(). Some filters and swscale can read
     * up to 16 bytes beyond the planes, if these filters are to be used,
     * then 16 extra bytes must be allocated.
     *
     * NOTE: Except for hwaccel formats, pointers not needed by the format
     * MUST be set to NULL.
     */
    uint8_t *data[AV_NUM_DATA_POINTERS];
           

存儲原始幀資料(未編碼的原始圖像或音頻格式,作為解碼器的輸出或編碼器的輸入)。

data 是一個指針數組,數組的每一個元素是一個指針,指向視訊中圖像的某一 plane 或音頻中某一聲道的 plane。

關于圖像 plane 的詳細說明參考“色彩空間與像素格式”,音頻 plane 的詳細說明參數“ffplay 源碼解析 6-音頻重采樣 6.1.1 節”。下面簡單說明:

對于 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

/**
     * For video, size in bytes of each picture line.
     * For audio, size in bytes of each plane.
     *
     * For audio, only linesize[0] may be set. For planar audio, each channel
     * plane must be the same size.
     *
     * For video the linesizes should be multiples of the CPUs alignment
     * preference, this is 16 or 32 for modern desktop CPUs.
     * Some code requires such alignment other code can be slower without
     * correct alignment, for yet other it makes no difference.
     *
     * @note The linesize may be larger than the size of usable data -- there
     * may be extra padding present for performance reasons.
     */
    int linesize[AV_NUM_DATA_POINTERS];
           

linesize 是一個數組。

對于視訊來說,linesize 每個元素是一個圖像 plane 中一行圖像的大小(位元組數)。注意有對齊要求。 linesize 值同 1.1 節中 stride 值。對于 planar 格式視訊,有多個 plane,每個 plane 的 linesize 表示一行圖像在目前 plane 中所占的存儲空間大小。對于 packed 格式視訊,隻有一個 plane,linesize 表示一行圖像所占的存儲空間大小。

對于音頻來說,linesize 每個元素是一個音頻 plane 的大小(位元組數)。packed 格式多聲道音頻隻有一個 plane,planar 格式多聲道音頻有多個 plane。音頻隻使用 linesize[0],即使有多個 plane。對于 planar 音頻來說,每個 plane 的大小必須一樣。

linesize 可能會因性能上的考慮而填充一些額外的資料,是以 linesize 可能比實際對應的音視訊資料尺寸要大。

extended_data

/**
     * pointers to the data planes/channels.
     *
     * For video, this should simply point to data[].
     *
     * For planar audio, each channel has a separate data pointer, and
     * linesize[0] contains the size of each channel buffer.
     * For packed audio, there is just one data pointer, and linesize[0]
     * contains the total size of the buffer for all channels.
     *
     * Note: Both data and extended_data should always be set in a valid frame,
     * but for planar audio with more channels that can fit in data,
     * extended_data must be used in order to access all channels.
     */
    uint8_t **extended_data;
           

????extended_data 是幹啥的????

對于視訊來說,直接指向 data[]成員。

對于音頻來說,packet 格式音頻隻有一個 plane,一個音頻幀中各個聲道的采樣點交織存儲在此 plane 中;planar 格式音頻每個聲道一個 plane。在多聲道 planar 格式音頻中,必須使用 extended_data 才能通路所有聲道,什麼意思?

在有效的視訊/音頻 frame 中,data 和 extended_data 兩個成員都必須設定有效值。

width, height

/**
     * @name Video dimensions
     * Video frames only. The coded dimensions (in pixels) of the video frame,
     * i.e. the size of the rectangle that contains some well-defined values.
     *
     * @note The part of the frame intended for display/presentation is further
     * restricted by the @ref cropping "Cropping rectangle".
     * @{
     */
    int width, height;
           

視訊幀寬和高(像素)。

nb_samples

/**
     * number of audio samples (per channel) described by this frame
     */
    int nb_samples;
           

音頻幀中單個聲道中包含的采樣點數。

format

/**
     * format of the frame, -1 if unknown or unset
     * Values correspond to enum AVPixelFormat for video frames,
     * enum AVSampleFormat for audio)
     */
    int format;
           

幀格式。如果是未知格式或未設定,則值為-1。

對于視訊幀,此值對應于“enum AVPixelFormat”結構:

enum AVPixelFormat {
    AV_PIX_FMT_NONE = -1,
    AV_PIX_FMT_YUV420P,   ///< planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
    AV_PIX_FMT_YUYV422,   ///< packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr
    AV_PIX_FMT_RGB24,     ///< packed RGB 8:8:8, 24bpp, RGBRGB...
    AV_PIX_FMT_BGR24,     ///< packed RGB 8:8:8, 24bpp, BGRBGR...
    ......
}
           

對于音頻幀,此值對應于“enum AVSampleFormat”格式:

enum AVSampleFormat {
    AV_SAMPLE_FMT_NONE = -1,
    AV_SAMPLE_FMT_U8,          ///< unsigned 8 bits
    AV_SAMPLE_FMT_S16,         ///< signed 16 bits
    AV_SAMPLE_FMT_S32,         ///< signed 32 bits
    AV_SAMPLE_FMT_FLT,         ///< float
    AV_SAMPLE_FMT_DBL,         ///< double

    AV_SAMPLE_FMT_U8P,         ///< unsigned 8 bits, planar
    AV_SAMPLE_FMT_S16P,        ///< signed 16 bits, planar
    AV_SAMPLE_FMT_S32P,        ///< signed 32 bits, planar
    AV_SAMPLE_FMT_FLTP,        ///< float, planar
    AV_SAMPLE_FMT_DBLP,        ///< double, planar
    AV_SAMPLE_FMT_S64,         ///< signed 64 bits
    AV_SAMPLE_FMT_S64P,        ///< signed 64 bits, planar

    AV_SAMPLE_FMT_NB           ///< Number of sample formats. DO NOT USE if linking dynamically
};
           

key_frame

/**
     * 1 -> keyframe, 0-> not
     */
    int key_frame;
           

視訊幀是否是關鍵幀的辨別,1->關鍵幀,0->非關鍵幀。

pict_type

/**
     * Picture type of the frame.
     */
    enum AVPictureType pict_type;
           

視訊幀類型(I、B、P 等)。如下:

/**
 * @}
 * @}
 * @defgroup lavu_picture Image related
 *
 * AVPicture types, pixel formats and basic image planes manipulation.
 *
 * @{
 */

enum AVPictureType {
    AV_PICTURE_TYPE_NONE = 0, ///< Undefined
    AV_PICTURE_TYPE_I,     ///< Intra
    AV_PICTURE_TYPE_P,     ///< Predicted
    AV_PICTURE_TYPE_B,     ///< Bi-dir predicted
    AV_PICTURE_TYPE_S,     ///< S(GMC)-VOP MPEG-4
    AV_PICTURE_TYPE_SI,    ///< Switching Intra
    AV_PICTURE_TYPE_SP,    ///< Switching Predicted
    AV_PICTURE_TYPE_BI,    ///< BI type
};
           

sample_aspect_ratio

/**
     * Sample aspect ratio for the video frame, 0/1 if unknown/unspecified.
     */
    AVRational sample_aspect_ratio;
           

視訊幀的寬高比。

pts

/**
     * Presentation timestamp in time_base units (time when frame should be shown to user).
     */
    int64_t pts;
           

顯示時間戳。機關是 time_base。

pkt_pts

#if FF_API_PKT_PTS
    /**
     * PTS copied from the AVPacket that was decoded to produce this frame.
     * @deprecated use the pts field instead
     */
    attribute_deprecated
    int64_t pkt_pts;
#endif
           

此 frame 對應的 packet 中的顯示時間戳。是從對應 packet(解碼生成此 frame)中拷貝 PTS 得到此值。

pkt_dts

/**
     * DTS copied from the AVPacket that triggered returning this frame. (if frame threading isn't used)
     * This is also the Presentation time of this AVFrame calculated from
     * only AVPacket.dts values without pts values.
     */
    int64_t pkt_dts;
           

此 frame 對應的 packet 中的解碼時間戳。是從對應 packet(解碼生成此 frame)中拷貝 DTS 得到此值。

如果對應的 packet 中隻有 dts 而未設定 pts,則此值也是此 frame 的 pts。

coded_picture_number

/**
     * picture number in bitstream order
     */
    int coded_picture_number;
           

在編碼流中目前圖像的序号。

display_picture_number

/**
     * picture number in display order
     */
    int display_picture_number;
           

在顯示序列中目前圖像的序号。

interlaced_frame

/**
     * The content of the picture is interlaced.
     */
    int interlaced_frame;
           

圖像逐行/隔行模式辨別。

sample_rate

/**
     * Sample rate of the audio data.
     */
    int sample_rate;
           

音頻采樣率。

channel_layout

/**
     * Channel layout of the audio data.
     */
    uint64_t channel_layout;
           

音頻聲道布局。每 bit 代表一個特定的聲道,參考 channel_layout.h 中的定義,一目了然:

/**
 * @defgroup channel_masks Audio channel masks
 *
 * A channel layout is a 64-bits integer with a bit set for every channel.
 * The number of bits set must be equal to the number of channels.
 * The value 0 means that the channel layout is not known.
 * @note this data structure is not powerful enough to handle channels
 * combinations that have the same channel multiple times, such as
 * dual-mono.
 *
 * @{
 */
#define AV_CH_FRONT_LEFT             0x00000001
#define AV_CH_FRONT_RIGHT            0x00000002
#define AV_CH_FRONT_CENTER           0x00000004
#define AV_CH_LOW_FREQUENCY          0x00000008
......

/**
 * @}
 * @defgroup channel_mask_c Audio channel layouts
 * @{
 * */
#define AV_CH_LAYOUT_MONO              (AV_CH_FRONT_CENTER)
#define AV_CH_LAYOUT_STEREO            (AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT)
#define AV_CH_LAYOUT_2POINT1           (AV_CH_LAYOUT_STEREO|AV_CH_LOW_FREQUENCY)
           

buf

/**
     * AVBuffer references backing the data for this frame. If all elements of
     * this array are NULL, then this frame is not reference counted. This array
     * must be filled contiguously -- if buf[i] is non-NULL then buf[j] must
     * also be non-NULL for all j < i.
     *
     * There may be at most one AVBuffer per data plane, so for video this array
     * always contains all the references. For planar audio with more than
     * AV_NUM_DATA_POINTERS channels, there may be more buffers than can fit in
     * this array. Then the extra AVBufferRef pointers are stored in the
     * extended_buf array.
     */
    AVBufferRef *buf[AV_NUM_DATA_POINTERS];
           

此幀的資料可以由 AVBufferRef 管理,AVBufferRef 提供 AVBuffer 引用機制。這裡涉及到緩沖區引用計數概念:

AVBuffer 是 FFmpeg 中很常用的一種緩沖區,緩沖區使用引用計數(reference-counted)機制。

AVBufferRef 則對 AVBuffer 緩沖區提供了一層封裝,最主要的是作引用計數處理,實作了一種安全機制。使用者不應直接通路 AVBuffer,應通過 AVBufferRef 來通路 AVBuffer,以保證安全。

FFmpeg 中很多基礎的資料結構都包含了 AVBufferRef 成員,來間接使用 AVBuffer 緩沖區。

相關内容參考“FFmpeg 資料結構 AVBuffer”

????幀的資料緩沖區 AVBuffer 就是前面的 data 成員,使用者不應直接使用 data 成員,應通過 buf 成員間接使用 data 成員。那 extended_data 又是做什麼的呢????

如果 buf[]的所有元素都為 NULL,則此幀不會被引用計數。必須連續填充 buf[] - 如果 buf[i]為非 NULL,則對于所有 j<i,buf[j]也必須為非 NULL。

每個 plane 最多可以有一個 AVBuffer,一個 AVBufferRef 指針指向一個 AVBuffer,一個 AVBuffer 引用指的就是一個 AVBufferRef 指針。

對于視訊來說,buf[]包含所有 AVBufferRef 指針。對于具有多于 AV_NUM_DATA_POINTERS 個聲道的 planar 音頻來說,可能 buf[]存不下所有的 AVBbufferRef 指針,多出的 AVBufferRef 指針存儲在 extended_buf 數組中。

extended_buf&nb_extended_buf

/**
     * For planar audio which requires more than AV_NUM_DATA_POINTERS
     * AVBufferRef pointers, this array will hold all the references which
     * cannot fit into AVFrame.buf.
     *
     * Note that this is different from AVFrame.extended_data, which always
     * contains all the pointers. This array only contains the extra pointers,
     * which cannot fit into AVFrame.buf.
     *
     * This array is always allocated using av_malloc() by whoever constructs
     * the frame. It is freed in av_frame_unref().
     */
    AVBufferRef **extended_buf;
    /**
     * Number of elements in extended_buf.
     */
    int        nb_extended_buf;
           

對于具有多于 AV_NUM_DATA_POINTERS 個聲道的 planar 音頻來說,可能 buf[]存不下所有的 AVBbufferRef 指針,多出的 AVBufferRef 指針存儲在 extended_buf 數組中。

注意此處的 extended_buf 和 AVFrame.extended_data 的不同,AVFrame.extended_data 包含所有指向各 plane 的指針,而 extended_buf 隻包含 AVFrame.buf 中裝不下的指針。

extended_buf 是構造 frame 時 av_frame_alloc()中自動調用 av_malloc()來配置設定空間的。調用 av_frame_unref 會釋放掉 extended_buf。

nb_extended_buf 是 extended_buf 中的元素數目。

best_effort_timestamp

/**
     * frame timestamp estimated using various heuristics, in stream time base
     * - encoding: unused
     * - decoding: set by libavcodec, read by user.
     */
    int64_t best_effort_timestamp;
           

????

pkt_pos

/**
     * reordered pos from the last AVPacket that has been input into the decoder
     * - encoding: unused
     * - decoding: Read by user.
     */
    int64_t pkt_pos;
           

記錄最後一個扔進解碼器的 packet 在輸入檔案中的位置偏移量。

pkt_duration

/**
     * duration of the corresponding packet, expressed in
     * AVStream->time_base units, 0 if unknown.
     * - encoding: unused
     * - decoding: Read by user.
     */
    int64_t pkt_duration;
           

對應 packet 的時長,機關是 AVStream->time_base。

channels

/**
     * number of audio channels, only used for audio.
     * - encoding: unused
     * - decoding: Read by user.
     */
    int channels;
           

音頻聲道數量。

pkt_size

/**
     * size of the corresponding packet containing the compressed
     * frame.
     * It is set to a negative value if unknown.
     * - encoding: unused
     * - decoding: set by libavcodec, read by user.
     */
    int pkt_size;
           

對應 packet 的大小。

crop_

/**
     * @anchor cropping
     * @name Cropping
     * Video frames only. The number of pixels to discard from the the
     * top/bottom/left/right border of the frame to obtain the sub-rectangle of
     * the frame intended for presentation.
     * @{
     */
    size_t crop_top;
    size_t crop_bottom;
    size_t crop_left;
    size_t crop_right;
    /**
     * @}
     */
           

用于視訊幀圖像裁切。四個值分别為從 frame 的上/下/左/右邊界裁切的像素數。

2. 相關函數使用說明

2.1 av_frame_alloc()

/**
 * Allocate an AVFrame and set its fields to default values.  The resulting
 * struct must be freed using av_frame_free().
 *
 * @return An AVFrame filled with default values or NULL on failure.
 *
 * @note this only allocates the AVFrame itself, not the data buffers. Those
 * must be allocated through other means, e.g. with av_frame_get_buffer() or
 * manually.
 */
AVFrame *av_frame_alloc(void);
           

構造一個 frame,對象各成員被設為預設值。

此函數隻配置設定 AVFrame 對象本身,而不配置設定 AVFrame 中的資料緩沖區。

2.2 av_frame_free()

/**
 * Free the frame and any dynamically allocated objects in it,
 * e.g. extended_data. If the frame is reference counted, it will be
 * unreferenced first.
 *
 * @param frame frame to be freed. The pointer will be set to NULL.
 */
void av_frame_free(AVFrame **frame);
           

釋放一個 frame。

2.3 av_frame_ref()

/**
 * Set up a new reference to the data described by the source frame.
 *
 * Copy frame properties from src to dst and create a new reference for each
 * AVBufferRef from src.
 *
 * If src is not reference counted, new buffers are allocated and the data is
 * copied.
 *
 * @warning: dst MUST have been either unreferenced with av_frame_unref(dst),
 *           or newly allocated with av_frame_alloc() before calling this
 *           function, or undefined behavior will occur.
 *
 * @return 0 on success, a negative AVERROR on error
 */
int av_frame_ref(AVFrame *dst, const AVFrame *src);
           

為 src 中的資料建立一個新的引用。

将 src 中幀的各屬性拷到 dst 中,并且為 src 中每個 AVBufferRef 建立一個新的引用。

如果 src 未使用引用計數,則 dst 中會配置設定新的資料緩沖區,将将 src 中緩沖區的資料拷貝到 dst 中的緩沖區。

2.4 av_frame_clone()

/**
 * Create a new frame that references the same data as src.
 *
 * This is a shortcut for av_frame_alloc()+av_frame_ref().
 *
 * @return newly created AVFrame on success, NULL on error.
 */
AVFrame *av_frame_clone(const AVFrame *src);
           

建立一個新的 frame,新的 frame 和 src 使用同一資料緩沖區,緩沖區管理使用引用計數機制。

本函數相當于 av_frame_alloc()+av_frame_ref()

2.5 av_frame_unref()

/**
 * Unreference all the buffers referenced by frame and reset the frame fields.
 */
void av_frame_unref(AVFrame *frame);
           

解除本 frame 對本 frame 中所有緩沖區的引用,并複位 frame 中各成員。

2.6 av_frame_move_ref()

/**
 * Move everything contained in src to dst and reset src.
 *
 * @warning: dst is not unreferenced, but directly overwritten without reading
 *           or deallocating its contents. Call av_frame_unref(dst) manually
 *           before calling this function to ensure that no memory is leaked.
 */
void av_frame_move_ref(AVFrame *dst, AVFrame *src);
           

将 src 中所有資料拷貝到 dst 中,并複位 src。

為避免記憶體洩漏,在調用

av_frame_move_ref(dst, src)

之前應先調用

av_frame_unref(dst)

2.7 av_frame_get_buffer()

/**
 * Allocate new buffer(s) for audio or video data.
 *
 * The following fields must be set on frame before calling this function:
 * - format (pixel format for video, sample format for audio)
 * - width and height for video
 * - nb_samples and channel_layout for audio
 *
 * This function will fill AVFrame.data and AVFrame.buf arrays and, if
 * necessary, allocate and fill AVFrame.extended_data and AVFrame.extended_buf.
 * For planar formats, one buffer will be allocated for each plane.
 *
 * @warning: if frame already has been allocated, calling this function will
 *           leak memory. In addition, undefined behavior can occur in certain
 *           cases.
 *
 * @param frame frame in which to store the new buffers.
 * @param align Required buffer size alignment. If equal to 0, alignment will be
 *              chosen automatically for the current CPU. It is highly
 *              recommended to pass 0 here unless you know what you are doing.
 *
 * @return 0 on success, a negative AVERROR on error.
 */
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 配置設定一個緩沖區。

2.8 av_frame_copy()

/**
 * Copy the frame data from src to dst.
 *
 * This function does not allocate anything, dst must be already initialized and
 * allocated with the same parameters as src.
 *
 * This function only copies the frame data (i.e. the contents of the data /
 * extended data arrays), not any other properties.
 *
 * @return >= 0 on success, a negative AVERROR on error.
 */
int av_frame_copy(AVFrame *dst, const AVFrame *src);
           

将 src 中的幀資料拷貝到 dst 中。

本函數并不會有任何配置設定緩沖區的動作,調用此函數前 dst 必須已經使用了和 src 同樣的參數完成了初始化。

本函數隻拷貝幀中的資料緩沖區的内容(data/extended_data 數組中的内容),而不涉及幀中任何其他的屬性。

3. 參考資料

[1] FFMPEG 結構體分析:AVFrame, https://blog.csdn.net/leixiaohua1020/article/details/14214577

[2] 色彩空間與像素格式, https://www.cnblogs.com/leisure_chn/p/10290575.html

4. 修改記錄

2019-01-13 V1.0 初稿

2021-01-06 V1.1 增加 1.1 節,修複 linesize 描述不清晰的問題

2021-01-16 V1.1 更新 1.1 節内容,詳細解釋放到“色彩空間與像素格式”文章中