溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

FFmpeg3最新的解碼接口avcodec_send_packet和avcodec_receive_frame分析

發(fā)布時(shí)間:2020-07-14 00:52:57 來(lái)源:網(wǎng)絡(luò) 閱讀:41680 作者:夏曹俊 欄目:編程語(yǔ)言

ffmpeg3版本的解碼接口做了不少調(diào)整,之前的視頻解碼接口avcodec_decode_video2和avcodec_decode_audio4音頻解碼被設(shè)置為deprecated,對(duì)這兩個(gè)接口做了合并,使用統(tǒng)一的接口。并且將音視頻解碼步驟分為了兩步,第一步avcodec_send_packet,第二步avcodec_receive_frame,通過(guò)接口名字我們就可以知道第一步是發(fā)送編碼數(shù)據(jù)包,第二步是接收解碼后數(shù)據(jù)。新版本是否只是做了接口的變化,還有有哪些我們需要注意的事項(xiàng),我們來(lái)分析一下。

      首先我們先看一下這兩個(gè)接口。

avcodec_send_packet

  • 接口源碼

/**
 * Supply raw packet data as input to a decoder.
 *
 * Internally, this call will copy relevant AVCodecContext fields, which can
 * influence decoding per-packet, and apply them when the packet is actually
 * decoded. (For example AVCodecContext.skip_frame, which might direct the
 * decoder to drop the frame contained by the packet sent with this function.)
 *
 * @warning The input buffer, avpkt->data must be AV_INPUT_BUFFER_PADDING_SIZE
 *          larger than the actual read bytes because some optimized bitstream
 *          readers read 32 or 64 bits at once and could read over the end.
 *
 * @warning Do not mix this API with the legacy API (like avcodec_decode_video2())
 *          on the same AVCodecContext. It will return unexpected results now
 *          or in future libavcodec versions.
 *
 * @note The AVCodecContext MUST have been opened with @ref avcodec_open2()
 *       before packets may be fed to the decoder.
 *
 * @param avctx codec context
 * @param[in] avpkt The input AVPacket. Usually, this will be a single video
 *                  frame, or several complete audio frames.
 *                  Ownership of the packet remains with the caller, and the
 *                  decoder will not write to the packet. The decoder may create
 *                  a reference to the packet data (or copy it if the packet is
 *                  not reference-counted).
 *                  Unlike with older APIs, the packet is always fully consumed,
 *                  and if it contains multiple frames (e.g. some audio codecs),
 *                  will require you to call avcodec_receive_frame() multiple
 *                  times afterwards before you can send a new packet.
 *                  It can be NULL (or an AVPacket with data set to NULL and
 *                  size set to 0); in this case, it is considered a flush
 *                  packet, which signals the end of the stream. Sending the
 *                  first flush packet will return success. Subsequent ones are
 *                  unnecessary and will return AVERROR_EOF. If the decoder
 *                  still has frames buffered, it will return them after sending
 *                  a flush packet.
 *
 * @return 0 on success, otherwise negative error code:
 *      AVERROR(EAGAIN):   input is not accepted right now - the packet must be
 *                         resent after trying to read output
 *      AVERROR_EOF:       the decoder has been flushed, and no new packets can
 *                         be sent to it (also returned if more than 1 flush
 *                         packet is sent)
 *      AVERROR(EINVAL):   codec not opened, it is an encoder, or requires flush
 *      AVERROR(ENOMEM):   failed to add packet to internal queue, or similar
 *      other errors: legitimate decoding errors

 */

int avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt);

  • 參數(shù)分析

AVCodecContext *avctx:第一個(gè)參數(shù)與舊的接口一致,是視頻解碼的上下文,包含×××。

const AVPacket *avpkt: 編碼的音視頻幀數(shù)據(jù)

  • 為什么要傳遞空的avpkt

這里有一個(gè)說(shuō)明是可以傳遞NULL,什么情況下需要傳遞NULL,你平時(shí)看一些視頻播放器,播放經(jīng)常會(huì)少最后幾幀,很多情況就是因?yàn)闆](méi)有處理好緩沖幀的問(wèn)題,ffmpeg內(nèi)部會(huì)緩沖幾幀,要想取出來(lái)就需要傳遞空的AVPacket進(jìn)去。

avcodec_receive_frame

  • 接口源碼

/**
 * Return decoded output data from a decoder.
 *
 * @param avctx codec context
 * @param frame This will be set to a reference-counted video or audio
 *              frame (depending on the decoder type) allocated by the
 *              decoder. Note that the function will always call
 *              av_frame_unref(frame) before doing anything else.
 *
 * @return
 *      0:                 success, a frame was returned
 *      AVERROR(EAGAIN):   output is not available right now - user must try
 *                         to send new input
 *      AVERROR_EOF:       the decoder has been fully flushed, and there will be
 *                         no more output frames
 *      AVERROR(EINVAL):   codec not opened, or it is an encoder
 *      other negative values: legitimate decoding errors

 */

int avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame);

  • 參數(shù)分析

AVCodecContext *avctx:第一個(gè)參數(shù)視頻解碼的上下文,與上面接口一致。

AVFrame *frame:解碼后的視頻幀數(shù)據(jù)。

  • 空間申請(qǐng)和釋放問(wèn)題

     解碼后圖像空間由函數(shù)內(nèi)部申請(qǐng),你所做的只需要分配 AVFrame 對(duì)象空間,如果你每次調(diào)用avcodec_receive_frame傳遞同一個(gè)對(duì)象,接口內(nèi)部會(huì)判斷空間是否已經(jīng)分配,如果沒(méi)有分配會(huì)在函數(shù)內(nèi)部分配。

avcodec_send_packet和avcodec_receive_frame調(diào)用關(guān)系并不一定是一對(duì)一的,比如一些音頻數(shù)據(jù)一個(gè)AVPacket中包含了1秒鐘的音頻,調(diào)用一次avcodec_send_packet之后,可能需要調(diào)用25次 avcodec_receive_frame才能獲取全部的解碼音頻數(shù)據(jù),所以要做如下處理:

int re = avcodec_send_packet(codec, pkt);

if (re != 0)

{

    return;

}

while( avcodec_receive_frame(codec, frame) == 0)

{

    //讀取到一幀音頻或者視頻

    //處理解碼后音視頻 frame

}


更多的資料也可以關(guān)注我51CTO上的視頻課程

夏老師的課堂 http://edu.51cto.com/lecturer/12016059.html

手把手教您開(kāi)發(fā)視頻播放器

http://edu.51cto.com/course/course_id-8059.html


FFmpeg3最新的解碼接口avcodec_send_packet和avcodec_receive_frame分析





向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI