• ffmpeg之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必须使用av_frame_alloc进行分配,重点是只会分配AVFrame本身,不会分配存储真实数据的buffer
     * AVFrame必须使用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.
     * AVFrame通常一次分配,多次使用(while前alloc,后free,内部多次使用,av_frame_unref会释放buffe的所有引用,并将其置为原始干净状态,然后再次使用)
     * 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.
     * AVFrame的原始数据有引用计数进行内存管理;
     * 对于planar存储的数据格式,多通道数据存储在二维数组data中
     * 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 {
    #define AV_NUM_DATA_POINTERS 8
        /**
         * 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.
         * 编码前的原始图片或者声音数据,最多存储8个通道的数据
         */
        uint8_t *data[AV_NUM_DATA_POINTERS];
    
        /**
         * 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.
         * 对于音频,智能设置linesize[0],对于planar,每个通道必须相同的linesize
         * 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.
         * 对于视频,16或者32的倍数
         * @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];
    
        /**
         * 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.
         * 对于需求更多通道的音频,必须使用extended_data
         */
        uint8_t **extended_data;
    
        /**
         * @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;
        /**
         * @}
         */
    
        /**
         * number of audio samples (per channel) described by this frame
         * 音频参数
         */
        int nb_samples;
    
        /**
         * format of the frame, -1 if unknown or unset
         * Values correspond to enum AVPixelFormat for video frames,
         * enum AVSampleFormat for audio)
         * 未知或者未设置则为-1
         * 音频的AVSampleForamt,视频的AVPixelFormat
         */
        int format;
    
        /**
         * 1 -> keyframe, 0-> not
         * 关键帧
         */
        int key_frame;
    
        /**
         * Picture type of the frame.
         */
        enum AVPictureType pict_type;
    
        /**
         * Sample aspect ratio for the video frame, 0/1 if unknown/unspecified.
         */
        AVRational sample_aspect_ratio;
    
        /**
         * Presentation timestamp in time_base units (time when frame should be shown to user).
         */
        int64_t 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
    
        /**
         * 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;
    
        /**
         * picture number in bitstream order
         * 解码后index, 0I 3B 2B 4B 5P
         */
        int coded_picture_number;
        /**
         * picture number in display order
         */
        int display_picture_number;
    
        /**
         * quality (between 1 (good) and FF_LAMBDA_MAX (bad))
         */
        int quality;
    
        /**
         * for some private data of the user
         */
        void *opaque;
    
    #if FF_API_ERROR_FRAME
        /**
         * @deprecated unused
         */
        attribute_deprecated
        uint64_t error[AV_NUM_DATA_POINTERS];
    #endif
    
        /**
         * When decoding, this signals how much the picture must be delayed.
         * extra_delay = repeat_pict / (2*fps)
         */
        int repeat_pict;
    
        /**
         * The content of the picture is interlaced.
         */
        int interlaced_frame;
    
        /**
         * If the content is interlaced, is top field displayed first.
         */
        int top_field_first;
    
        /**
         * Tell user application that palette has changed from previous frame.
         */
        int palette_has_changed;
    
        /**
         * reordered opaque 64 bits (generally an integer or a double precision float
         * PTS but can be anything).
         * The user sets AVCodecContext.reordered_opaque to represent the input at
         * that time,
         * the decoder reorders values as needed and sets AVFrame.reordered_opaque
         * to exactly one of the values provided by the user through AVCodecContext.reordered_opaque
         */
        int64_t reordered_opaque;
    
        /**
         * Sample rate of the audio data.
         * 音频采样率
         */
        int sample_rate;
    
        /**
         * Channel layout of the audio data.
         * 量化格式
         */
        uint64_t channel_layout;
    
        /**
         * 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.
         * 同data
         */
        AVBufferRef *buf[AV_NUM_DATA_POINTERS];
    
        /**
         * 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().
         * 同extended_data
         */
        AVBufferRef **extended_buf;
        /**
         * Number of elements in extended_buf.
         */
        int        nb_extended_buf;
    
        AVFrameSideData **side_data;
        int            nb_side_data;
    
    /**
     * @defgroup lavu_frame_flags AV_FRAME_FLAGS
     * @ingroup lavu_frame
     * Flags describing additional frame properties.
     *
     * @{
     */
    
    /**
     * The frame data may be corrupted, e.g. due to decoding errors.
     */
    #define AV_FRAME_FLAG_CORRUPT       (1 << 0)
    /**
     * A flag to mark the frames which need to be decoded, but shouldn't be output.
     */
    #define AV_FRAME_FLAG_DISCARD   (1 << 2)
    /**
     * @}
     */
    
        /**
         * Frame flags, a combination of @ref lavu_frame_flags
         */
        int flags;
    
        /**
         * MPEG vs JPEG YUV range.
         * - encoding: Set by user
         * - decoding: Set by libavcodec
         */
        enum AVColorRange color_range;
    
        enum AVColorPrimaries color_primaries;
    
        enum AVColorTransferCharacteristic color_trc;
    
        /**
         * YUV colorspace type.
         * - encoding: Set by user
         * - decoding: Set by libavcodec
         */
        enum AVColorSpace colorspace;
    
        enum AVChromaLocation chroma_location;
    
        /**
         * frame timestamp estimated using various heuristics, in stream time base
         * - encoding: unused
         * - decoding: set by libavcodec, read by user.
         */
        int64_t best_effort_timestamp;
    
        /**
         * reordered pos from the last AVPacket that has been input into the decoder
         * - encoding: unused
         * - decoding: Read by user.
         */
        int64_t pkt_pos;
    
        /**
         * duration of the corresponding packet, expressed in
         * AVStream->time_base units, 0 if unknown.
         * - encoding: unused
         * - decoding: Read by user.
         */
        int64_t pkt_duration;
    
        /**
         * metadata.
         * - encoding: Set by user.
         * - decoding: Set by libavcodec.
         */
        AVDictionary *metadata;
    
        /**
         * decode error flags of the frame, set to a combination of
         * FF_DECODE_ERROR_xxx flags if the decoder produced a frame, but there
         * were errors during the decoding.
         * - encoding: unused
         * - decoding: set by libavcodec, read by user.
         */
        int decode_error_flags;
    #define FF_DECODE_ERROR_INVALID_BITSTREAM   1
    #define FF_DECODE_ERROR_MISSING_REFERENCE   2
    #define FF_DECODE_ERROR_CONCEALMENT_ACTIVE  4
    #define FF_DECODE_ERROR_DECODE_SLICES       8
    
        /**
         * number of audio channels, only used for audio.
         * - encoding: unused
         * - decoding: Read by user.
         * 通道数
         */
        int channels;
    
        /**
         * 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.
         * 此Frame的数据长度
         */
        int pkt_size;
    
    #if FF_API_FRAME_QP
        /**
         * QP table
         */
        attribute_deprecated
        int8_t *qscale_table;
        /**
         * QP store stride
         */
        attribute_deprecated
        int qstride;
    
        attribute_deprecated
        int qscale_type;
    
        attribute_deprecated
        AVBufferRef *qp_table_buf;
    #endif
        /**
         * For hwaccel-format frames, this should be a reference to the
         * AVHWFramesContext describing the frame.
         */
        AVBufferRef *hw_frames_ctx;
    
        /**
         * AVBufferRef for free use by the API user. FFmpeg will never check the
         * contents of the buffer ref. FFmpeg calls av_buffer_unref() on it when
         * the frame is unreferenced. av_frame_copy_props() calls create a new
         * reference with av_buffer_ref() for the target frame's opaque_ref field.
         *
         * This is unrelated to the opaque field, although it serves a similar
         * purpose.
         */
        AVBufferRef *opaque_ref;
    
        /**
         * @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;
        /**
         * @}
         */
    
        /**
         * AVBufferRef for internal use by a single libav* library.
         * Must not be used to transfer data between libraries.
         * Has to be NULL when ownership of the frame leaves the respective library.
         *
         * Code outside the FFmpeg libs should never check or change the contents of the buffer ref.
         *
         * FFmpeg calls av_buffer_unref() on it when the frame is unreferenced.
         * av_frame_copy_props() calls create a new reference with av_buffer_ref()
         * for the target frame's private_ref field.
         */
        AVBufferRef *private_ref;
    } AVFrame;
    
    /**
     * @}
     * @}
     * @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
    };
    
    

    相关函数

    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)
    {
        AVFrame *frame = av_mallocz(sizeof(*frame));
    
        if (!frame)
            return NULL;
    
        frame->extended_data = NULL;
        get_frame_defaults(frame);
    
        return frame;
    }
    

    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)
    {
        if (!frame || !*frame)
            return;
    
        av_frame_unref(*frame);
        av_freep(frame);
    }
    

    av_framme_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)
    {
        int i, ret = 0;
    
        av_assert1(dst->width == 0 && dst->height == 0);
        av_assert1(dst->channels == 0);
    
        dst->format         = src->format;
        dst->width          = src->width;
        dst->height         = src->height;
        dst->channels       = src->channels;
        dst->channel_layout = src->channel_layout;
        dst->nb_samples     = src->nb_samples;
    
        ret = frame_copy_props(dst, src, 0);
        if (ret < 0)
            return ret;
    
        /* duplicate the frame data if it's not refcounted */
        if (!src->buf[0]) {
            ret = av_frame_get_buffer(dst, 32);
            if (ret < 0)
                return ret;
    
            ret = av_frame_copy(dst, src);
            if (ret < 0)
                av_frame_unref(dst);
    
            return ret;
        }
    
        /* ref the buffers */
        for (i = 0; i < FF_ARRAY_ELEMS(src->buf); i++) {
            if (!src->buf[i])
                continue;
            dst->buf[i] = av_buffer_ref(src->buf[i]);
            if (!dst->buf[i]) {
                ret = AVERROR(ENOMEM);
                goto fail;
            }
        }
    
        if (src->extended_buf) {
            dst->extended_buf = av_mallocz_array(sizeof(*dst->extended_buf),
                                           src->nb_extended_buf);
            if (!dst->extended_buf) {
                ret = AVERROR(ENOMEM);
                goto fail;
            }
            dst->nb_extended_buf = src->nb_extended_buf;
    
            for (i = 0; i < src->nb_extended_buf; i++) {
                dst->extended_buf[i] = av_buffer_ref(src->extended_buf[i]);
                if (!dst->extended_buf[i]) {
                    ret = AVERROR(ENOMEM);
                    goto fail;
                }
            }
        }
    
        if (src->hw_frames_ctx) {
            dst->hw_frames_ctx = av_buffer_ref(src->hw_frames_ctx);
            if (!dst->hw_frames_ctx) {
                ret = AVERROR(ENOMEM);
                goto fail;
            }
        }
    
        /* duplicate extended data */
        if (src->extended_data != src->data) {
            int ch = src->channels;
    
            if (!ch) {
                ret = AVERROR(EINVAL);
                goto fail;
            }
            CHECK_CHANNELS_CONSISTENCY(src);
    
            dst->extended_data = av_malloc_array(sizeof(*dst->extended_data), ch);
            if (!dst->extended_data) {
                ret = AVERROR(ENOMEM);
                goto fail;
            }
            memcpy(dst->extended_data, src->extended_data, sizeof(*src->extended_data) * ch);
        } else
            dst->extended_data = dst->data;
    
        memcpy(dst->data,     src->data,     sizeof(src->data));
        memcpy(dst->linesize, src->linesize, sizeof(src->linesize));
    
        return 0;
    
    fail:
        av_frame_unref(dst);
        return ret;
    }
    

    av_frame_unref

    /**
     * Unreference all the buffers referenced by frame and reset the frame fields.
     */
    void av_frame_unref(AVFrame *frame)
    {
        int i;
    
        if (!frame)
            return;
    
        wipe_side_data(frame);
    
        for (i = 0; i < FF_ARRAY_ELEMS(frame->buf); i++)
            av_buffer_unref(&frame->buf[i]);
        for (i = 0; i < frame->nb_extended_buf; i++)
            av_buffer_unref(&frame->extended_buf[i]);
        av_freep(&frame->extended_buf);
        av_dict_free(&frame->metadata);
    #if FF_API_FRAME_QP
    FF_DISABLE_DEPRECATION_WARNINGS
        av_buffer_unref(&frame->qp_table_buf);
    FF_ENABLE_DEPRECATION_WARNINGS
    #endif
    
        av_buffer_unref(&frame->hw_frames_ctx);
    
        av_buffer_unref(&frame->opaque_ref);
        av_buffer_unref(&frame->private_ref);
    
        get_frame_defaults(frame);
    }
    
    static void get_frame_defaults(AVFrame *frame)
    {
        if (frame->extended_data != frame->data)
            av_freep(&frame->extended_data);
    
        memset(frame, 0, sizeof(*frame));
    
        frame->pts                   =
        frame->pkt_dts               = AV_NOPTS_VALUE;
    #if FF_API_PKT_PTS
    FF_DISABLE_DEPRECATION_WARNINGS
        frame->pkt_pts               = AV_NOPTS_VALUE;
    FF_ENABLE_DEPRECATION_WARNINGS
    #endif
        frame->best_effort_timestamp = AV_NOPTS_VALUE;
        frame->pkt_duration        = 0;
        frame->pkt_pos             = -1;
        frame->pkt_size            = -1;
        frame->key_frame           = 1;
        frame->sample_aspect_ratio = (AVRational){ 0, 1 };
        frame->format              = -1; /* unknown */
        frame->extended_data       = frame->data;
        frame->color_primaries     = AVCOL_PRI_UNSPECIFIED;
        frame->color_trc           = AVCOL_TRC_UNSPECIFIED;
        frame->colorspace          = AVCOL_SPC_UNSPECIFIED;
        frame->color_range         = AVCOL_RANGE_UNSPECIFIED;
        frame->chroma_location     = AVCHROMA_LOC_UNSPECIFIED;
        frame->flags               = 0;
    }
    

    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)
    {
        av_assert1(dst->width == 0 && dst->height == 0);
        av_assert1(dst->channels == 0);
    
        *dst = *src;
        if (src->extended_data == src->data)
            dst->extended_data = dst->data;
        memset(src, 0, sizeof(*src));
        get_frame_defaults(src);
    }
    

    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)
    {
        AVFrame *ret = av_frame_alloc();
    
        if (!ret)
            return NULL;
    
        if (av_frame_ref(ret, src) < 0)
            av_frame_free(&ret);
    
        return ret;
    }
    

    av_frame_is_writable

    /**
     * Check if the frame data is writable.
     *
     * @return A positive value if the frame data is writable (which is true if and
     * only if each of the underlying buffers has only one reference, namely the one
     * stored in this frame). Return 0 otherwise.
     *
     * If 1 is returned the answer is valid until av_buffer_ref() is called on any
     * of the underlying AVBufferRefs (e.g. through av_frame_ref() or directly).
     *
     * @see av_frame_make_writable(), av_buffer_is_writable()
     */
    int av_frame_is_writable(AVFrame *frame)
    {
        int i, ret = 1;
    
        /* assume non-refcounted frames are not writable */
        if (!frame->buf[0])
            return 0;
    
        for (i = 0; i < FF_ARRAY_ELEMS(frame->buf); i++)
            if (frame->buf[i])
                ret &= !!av_buffer_is_writable(frame->buf[i]);
        for (i = 0; i < frame->nb_extended_buf; i++)
            ret &= !!av_buffer_is_writable(frame->extended_buf[i]);
    
        return ret;
    }
    

    av_frame_make_writable

    /**
     * Ensure that the frame data is writable, avoiding data copy if possible.
     *
     * Do nothing if the frame is writable, allocate new buffers and copy the data
     * if it is not.
     *
     * @return 0 on success, a negative AVERROR on error.
     *
     * @see av_frame_is_writable(), av_buffer_is_writable(),
     * av_buffer_make_writable()
     */
    int av_frame_make_writable(AVFrame *frame)
    {
        AVFrame tmp;
        int ret;
    
        if (!frame->buf[0])
            return AVERROR(EINVAL);
    
        if (av_frame_is_writable(frame))
            return 0;
    
        memset(&tmp, 0, sizeof(tmp));
        tmp.format         = frame->format;
        tmp.width          = frame->width;
        tmp.height         = frame->height;
        tmp.channels       = frame->channels;
        tmp.channel_layout = frame->channel_layout;
        tmp.nb_samples     = frame->nb_samples;
        ret = av_frame_get_buffer(&tmp, 32);
        if (ret < 0)
            return ret;
    
        ret = av_frame_copy(&tmp, frame);
        if (ret < 0) {
            av_frame_unref(&tmp);
            return ret;
        }
    
        ret = av_frame_copy_props(&tmp, frame);
        if (ret < 0) {
            av_frame_unref(&tmp);
            return ret;
        }
    
        av_frame_unref(frame);
    
        *frame = tmp;
        if (tmp.data == tmp.extended_data)
            frame->extended_data = frame->data;
    
        return 0;
    }
    

    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)
    {
        if (frame->format < 0)
            return AVERROR(EINVAL);
    
        if (frame->width > 0 && frame->height > 0)
            return get_video_buffer(frame, align);
        else if (frame->nb_samples > 0 && (frame->channel_layout || frame->channels > 0))
            return get_audio_buffer(frame, align);
    
        return AVERROR(EINVAL);
    }
    
    static int get_video_buffer(AVFrame *frame, int align)
    {
        const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format);
        int ret, i, padded_height;
        int plane_padding = FFMAX(16 + 16/*STRIDE_ALIGN*/, align);
    
        if (!desc)
            return AVERROR(EINVAL);
    
        if ((ret = av_image_check_size(frame->width, frame->height, 0, NULL)) < 0)
            return ret;
    
        if (!frame->linesize[0]) {
            if (align <= 0)
                align = 32; /* STRIDE_ALIGN. Should be av_cpu_max_align() */
    
            for(i=1; i<=align; i+=i) {
                ret = av_image_fill_linesizes(frame->linesize, frame->format,
                                              FFALIGN(frame->width, i));
                if (ret < 0)
                    return ret;
                if (!(frame->linesize[0] & (align-1)))
                    break;
            }
    
            for (i = 0; i < 4 && frame->linesize[i]; i++)
                frame->linesize[i] = FFALIGN(frame->linesize[i], align);
        }
    
        padded_height = FFALIGN(frame->height, 32);
        if ((ret = av_image_fill_pointers(frame->data, frame->format, padded_height,
                                          NULL, frame->linesize)) < 0)
            return ret;
    
        frame->buf[0] = av_buffer_alloc(ret + 4*plane_padding);
        if (!frame->buf[0]) {
            ret = AVERROR(ENOMEM);
            goto fail;
        }
    
        if ((ret = av_image_fill_pointers(frame->data, frame->format, padded_height,
                                          frame->buf[0]->data, frame->linesize)) < 0)
            goto fail;
    
        for (i = 1; i < 4; i++) {
            if (frame->data[i])
                frame->data[i] += i * plane_padding;
        }
    
        frame->extended_data = frame->data;
    
        return 0;
    fail:
        av_frame_unref(frame);
        return ret;
    }
    
    static int get_audio_buffer(AVFrame *frame, int align)
    {
        int channels;
        int planar   = av_sample_fmt_is_planar(frame->format);
        int planes;
        int ret, i;
    
        if (!frame->channels)
            frame->channels = av_get_channel_layout_nb_channels(frame->channel_layout);
    
        channels = frame->channels;
        planes = planar ? channels : 1;
    
        CHECK_CHANNELS_CONSISTENCY(frame);
        if (!frame->linesize[0]) {
            ret = av_samples_get_buffer_size(&frame->linesize[0], channels,
                                             frame->nb_samples, frame->format,
                                             align);
            if (ret < 0)
                return ret;
        }
    
        if (planes > AV_NUM_DATA_POINTERS) {
            frame->extended_data = av_mallocz_array(planes,
                                              sizeof(*frame->extended_data));
            frame->extended_buf  = av_mallocz_array((planes - AV_NUM_DATA_POINTERS),
                                              sizeof(*frame->extended_buf));
            if (!frame->extended_data || !frame->extended_buf) {
                av_freep(&frame->extended_data);
                av_freep(&frame->extended_buf);
                return AVERROR(ENOMEM);
            }
            frame->nb_extended_buf = planes - AV_NUM_DATA_POINTERS;
        } else
            frame->extended_data = frame->data;
    
        for (i = 0; i < FFMIN(planes, AV_NUM_DATA_POINTERS); i++) {
            frame->buf[i] = av_buffer_alloc(frame->linesize[0]);
            if (!frame->buf[i]) {
                av_frame_unref(frame);
                return AVERROR(ENOMEM);
            }
            frame->extended_data[i] = frame->data[i] = frame->buf[i]->data;
        }
        for (i = 0; i < planes - AV_NUM_DATA_POINTERS; i++) {
            frame->extended_buf[i] = av_buffer_alloc(frame->linesize[0]);
            if (!frame->extended_buf[i]) {
                av_frame_unref(frame);
                return AVERROR(ENOMEM);
            }
            frame->extended_data[i + AV_NUM_DATA_POINTERS] = frame->extended_buf[i]->data;
        }
        return 0;
    
    }
    

    av_frame_get_planar_buffer

    /**
     * Get the buffer reference a given data plane is stored in.
     *
     * @param plane index of the data plane of interest in frame->extended_data.
     *
     * @return the buffer reference that contains the plane or NULL if the input
     * frame is not valid.
     */
    AVBufferRef *av_frame_get_plane_buffer(AVFrame *frame, int plane)
    {
        uint8_t *data;
        int planes, i;
    
        if (frame->nb_samples) {
            int channels = frame->channels;
            if (!channels)
                return NULL;
            CHECK_CHANNELS_CONSISTENCY(frame);
            planes = av_sample_fmt_is_planar(frame->format) ? channels : 1;
        } else
            planes = 4;
    
        if (plane < 0 || plane >= planes || !frame->extended_data[plane])
            return NULL;
        data = frame->extended_data[plane];
    
        for (i = 0; i < FF_ARRAY_ELEMS(frame->buf) && frame->buf[i]; i++) {
            AVBufferRef *buf = frame->buf[i];
            if (data >= buf->data && data < buf->data + buf->size)
                return buf;
        }
        for (i = 0; i < frame->nb_extended_buf; i++) {
            AVBufferRef *buf = frame->extended_buf[i];
            if (data >= buf->data && data < buf->data + buf->size)
                return buf;
        }
        return NULL;
    }
    

    frame_copy_video

    static int frame_copy_video(AVFrame *dst, const AVFrame *src)
    {
        const uint8_t *src_data[4];
        int i, planes;
    
        if (dst->width  < src->width ||
            dst->height < src->height)
            return AVERROR(EINVAL);
    
        planes = av_pix_fmt_count_planes(dst->format);
        for (i = 0; i < planes; i++)
            if (!dst->data[i] || !src->data[i])
                return AVERROR(EINVAL);
    
        memcpy(src_data, src->data, sizeof(src_data));
        av_image_copy(dst->data, dst->linesize,
                      src_data, src->linesize,
                      dst->format, src->width, src->height);
    
        return 0;
    }
    

    frame_copy_audio

    static int frame_copy_audio(AVFrame *dst, const AVFrame *src)
    {
        int planar   = av_sample_fmt_is_planar(dst->format);
        int channels = dst->channels;
        int planes   = planar ? channels : 1;
        int i;
    
        if (dst->nb_samples     != src->nb_samples ||
            dst->channels       != src->channels ||
            dst->channel_layout != src->channel_layout)
            return AVERROR(EINVAL);
    
        CHECK_CHANNELS_CONSISTENCY(src);
    
        for (i = 0; i < planes; i++)
            if (!dst->extended_data[i] || !src->extended_data[i])
                return AVERROR(EINVAL);
    
        av_samples_copy(dst->extended_data, src->extended_data, 0, 0,
                        dst->nb_samples, channels, dst->format);
    
        return 0;
    }
    
    

    本文来自博客园,作者:faithlocus,转载请注明原文链接:https://www.cnblogs.com/faithlocus/p/15636173.html

  • 相关阅读:
    QEMU内存分析(四):ept页表构建
    virtio简介(二) —— virtioballoon guest侧驱动
    将数据库所有的表的字符集改为utf8
    windows 10 mysql 安装
    Windows10 安装MySQL详细教程2020版 亲测亲写
    发现了一个可以免费下载jar包的网站,所有jar包都有
    我的新书《Flink大数据分析实战》出版啦
    2022最新 Navicat Premium 16中文软件激活安装永久使用正版(支持MAC+win)
    Adobe全家桶PS、PR、AU等2022正版永久有效,无需破解直接安装就能用
    虚拟机问题:VMware Workstation 与 Device/Credential Guard 不兼容。在禁用 Device/Credential Guard 后,可以运行
  • 原文地址:https://www.cnblogs.com/faithlocus/p/15636173.html
Copyright © 2020-2023  润新知