从头用脚分析FFmpeg源码 - avcodec_send_packet | avcodec_receive_frame

news/2024/7/10 21:07:44 标签: ffmpeg, 音视频, c
cle class="baidu_pl">
cle_content" class="article_content clearfix">
content_views" class="markdown_views prism-atom-one-dark"> cap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);">

avcodec_send_packet和avcodec_receive_frame是一对孪生兄弟࿰c;avcodec_send_packet把需要解码的AVPacket送到解码器中࿰c;avcodec_receive_frame则是得到解码完成后的frame。
这两个函数都是通过调用decode_receive_frame_internal来实现的。

codec_send_packet__4">avcodec_send_packet 作用

把未经过解码的AVPacket送到AVCodecContext中解码。
FFmpeg的说明如下:

<code class="prism language-c">class="token comment">/**
 * 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.)
 *
 * @return 0 on success, otherwise negative error code:
 *      AVERROR(EAGAIN):   input is not accepted in the current state - user
 *                         must read output with avcodec_receive_frame() (once
 *                         all output is read, the packet should be resent, and
 *                         the call will not fail with EAGAIN).
 *      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
 */
class="token keyword">int class="token function">avcodec_send_packetclass="token punctuation">(AVCodecContext class="token operator">*avctxclass="token punctuation">, class="token keyword">const AVPacket class="token operator">*avpktclass="token punctuation">)class="token punctuation">;

class="token comment">/**
 * Supply a raw video or audio frame to the encoder. Use avcodec_receive_packet()
 * to retrieve buffered output packets.
 * @return 0 on success, otherwise negative error code:
 *      AVERROR(EAGAIN):   input is not accepted in the current state - user
 *                         must read output with avcodec_receive_packet() (once
 *                         all output is read, the packet should be resent, and
 *                         the call will not fail with EAGAIN).
 *      AVERROR_EOF:       the encoder has been flushed, and no new frames can
 *                         be sent to it
 *      AVERROR(EINVAL):   codec not opened, refcounted_frames not set, it is a
 *                         decoder, or requires flush
 *      AVERROR(ENOMEM):   failed to add packet to internal queue, or similar
 *      other errors: legitimate encoding errors
 */
class="token keyword">int class="token function">avcodec_send_frameclass="token punctuation">(AVCodecContext class="token operator">*avctxclass="token punctuation">, class="token keyword">const AVFrame class="token operator">*frameclass="token punctuation">)class="token punctuation">;
code>

简而言之࿰c;avcodec_send_packet就是把AVPacket送到AVCodecContext࿰c;然后让AVCodecContext解码。avcodec_receive_frame获得解码后的AVFrame。
需要注意的是࿰c;AVCodecContext必须经过avcodec_open2函数打开࿰c;输入的AVPacket会在内部增加一个ref࿰c;所以如果要free࿰c;外部也应该调用av_packet_unref。

codec_send_packet__50">avcodec_send_packet 源码

把avpk送到avci->bsf中࿰c;等待解码。然后通过判断avci->buffer_frame->buf[0]是否null来决定是否调用decode_receive_frame_internal来接受解码后的frame。

<code class="prism language-c">class="token keyword">int attribute_align_arg class="token function">avcodec_send_packetclass="token punctuation">(AVCodecContext class="token operator">*avctxclass="token punctuation">, class="token keyword">const AVPacket class="token operator">*avpktclass="token punctuation">)
class="token punctuation">{
    AVCodecInternal class="token operator">*avci class="token operator">= avctxclass="token operator">->internalclass="token punctuation">;
    class="token keyword">int retclass="token punctuation">;

	class="token comment">// 未open和编码器都不行
    class="token keyword">if class="token punctuation">(class="token operator">!class="token function">avcodec_is_openclass="token punctuation">(avctxclass="token punctuation">) class="token operator">|| class="token operator">!class="token function">av_codec_is_decoderclass="token punctuation">(avctxclass="token operator">->codecclass="token punctuation">)class="token punctuation">)
        class="token keyword">return class="token function">AVERRORclass="token punctuation">(EINVALclass="token punctuation">)class="token punctuation">;

	class="token comment">// 检测是否应该先flush
    class="token keyword">if class="token punctuation">(avctxclass="token operator">->internalclass="token operator">->drainingclass="token punctuation">)
        class="token keyword">return AVERROR_EOFclass="token punctuation">;

    class="token keyword">if class="token punctuation">(avpkt class="token operator">&& class="token operator">!avpktclass="token operator">->size class="token operator">&& avpktclass="token operator">->dataclass="token punctuation">)
        class="token keyword">return class="token function">AVERRORclass="token punctuation">(EINVALclass="token punctuation">)class="token punctuation">;

    class="token function">av_packet_unrefclass="token punctuation">(avciclass="token operator">->buffer_pktclass="token punctuation">)class="token punctuation">;
    class="token comment">// avci->buffer_pkt也reference输入的avpkt
    class="token comment">// 相当于一次copy (不一定是深copy)
    class="token keyword">if class="token punctuation">(avpkt class="token operator">&& class="token punctuation">(avpktclass="token operator">->data class="token operator">|| avpktclass="token operator">->side_data_elemsclass="token punctuation">)class="token punctuation">) class="token punctuation">{
        ret class="token operator">= class="token function">av_packet_refclass="token punctuation">(avciclass="token operator">->buffer_pktclass="token punctuation">, avpktclass="token punctuation">)class="token punctuation">;
        class="token keyword">if class="token punctuation">(ret class="token operator">< class="token number">0class="token punctuation">)
            class="token keyword">return retclass="token punctuation">;
    class="token punctuation">}

	class="token comment">// 把avci->buffer_pkt送到avci->bsf中
	class="token comment">// 即将avci->buffer_pkt copy到avci->bsf->internal->buffer_pkt࿰c;然后可以经过bsf。
	class="token comment">// AVBSFContext一般是对AVPacket进行某些格式上的转换࿰c;比如对h264来说࿰c;存在AVCC和ANNEXB两种格式࿰c;这里就是把AVCC格式转换成为ANNEXB
    ret class="token operator">= class="token function">av_bsf_send_packetclass="token punctuation">(avciclass="token operator">->bsfclass="token punctuation">, avciclass="token operator">->buffer_pktclass="token punctuation">)class="token punctuation">;
    class="token keyword">if class="token punctuation">(ret class="token operator">< class="token number">0class="token punctuation">) class="token punctuation">{
        class="token function">av_packet_unrefclass="token punctuation">(avciclass="token operator">->buffer_pktclass="token punctuation">)class="token punctuation">;
        class="token keyword">return retclass="token punctuation">;
    class="token punctuation">}

    class="token keyword">if class="token punctuation">(class="token operator">!avciclass="token operator">->buffer_frameclass="token operator">->bufclass="token punctuation">[class="token number">0class="token punctuation">]class="token punctuation">) class="token punctuation">{
    	class="token comment">//这个函数会在avcodec_send_packet或者avcodec_receive_frame中调用
    	class="token comment">//avci->buffer_frame->buf[0]为null࿰c;就在avcodec_send_packet中调用
    	class="token comment">//avci->buffer_frame->buf[0]不为null࿰c;就在avcodec_receive_frame中调用
    	class="token comment">//decode_receive_frame_internal中
        ret class="token operator">= class="token function">decode_receive_frame_internalclass="token punctuation">(avctxclass="token punctuation">, avciclass="token operator">->buffer_frameclass="token punctuation">)class="token punctuation">;
        class="token keyword">if class="token punctuation">(ret class="token operator">< class="token number">0 class="token operator">&& ret class="token operator">!= class="token function">AVERRORclass="token punctuation">(EAGAINclass="token punctuation">) class="token operator">&& ret class="token operator">!= AVERROR_EOFclass="token punctuation">)
            class="token keyword">return retclass="token punctuation">;
    class="token punctuation">}

    class="token keyword">return class="token number">0class="token punctuation">;
class="token punctuation">}
code>

codec_receive_frame__100">avcodec_receive_frame 源码

<code class="prism language-c">class="token keyword">int attribute_align_arg class="token function">avcodec_receive_frameclass="token punctuation">(AVCodecContext class="token operator">*avctxclass="token punctuation">, AVFrame class="token operator">*frameclass="token punctuation">)
class="token punctuation">{
    AVCodecInternal class="token operator">*avci class="token operator">= avctxclass="token operator">->internalclass="token punctuation">;
    class="token keyword">int retclass="token punctuation">, changedclass="token punctuation">;

    class="token function">av_frame_unrefclass="token punctuation">(frameclass="token punctuation">)class="token punctuation">;

	class="token comment">// 判断是否调用过avcodec_open2函数࿰c;是否为解码器
    class="token keyword">if class="token punctuation">(class="token operator">!class="token function">avcodec_is_openclass="token punctuation">(avctxclass="token punctuation">) class="token operator">|| class="token operator">!class="token function">av_codec_is_decoderclass="token punctuation">(avctxclass="token operator">->codecclass="token punctuation">)class="token punctuation">)
        class="token keyword">return class="token function">AVERRORclass="token punctuation">(EINVALclass="token punctuation">)class="token punctuation">;

	class="token comment">// 根据avci->buffer_frame->buf[0]判断是否存在解码完成的帧࿰c;如果存在就直接move到frame中。
	class="token comment">// 如果没有就调用decode_receive_frame_internal把AVPacket送去解码线程࿰c;然后获得解码之后的AVFrame。
    class="token keyword">if class="token punctuation">(avciclass="token operator">->buffer_frameclass="token operator">->bufclass="token punctuation">[class="token number">0class="token punctuation">]class="token punctuation">) class="token punctuation">{
        class="token function">av_frame_move_refclass="token punctuation">(frameclass="token punctuation">, avciclass="token operator">->buffer_frameclass="token punctuation">)class="token punctuation">;
    class="token punctuation">} class="token keyword">else class="token punctuation">{
        ret class="token operator">= class="token function">decode_receive_frame_internalclass="token punctuation">(avctxclass="token punctuation">, frameclass="token punctuation">)class="token punctuation">;
        class="token keyword">if class="token punctuation">(ret class="token operator">< class="token number">0class="token punctuation">)
            class="token keyword">return retclass="token punctuation">;
    class="token punctuation">}

    class="token keyword">if class="token punctuation">(avctxclass="token operator">->codec_type class="token operator">== AVMEDIA_TYPE_VIDEOclass="token punctuation">) class="token punctuation">{
        ret class="token operator">= class="token function">apply_croppingclass="token punctuation">(avctxclass="token punctuation">, frameclass="token punctuation">)class="token punctuation">;
        class="token keyword">if class="token punctuation">(ret class="token operator">< class="token number">0class="token punctuation">) class="token punctuation">{
            class="token function">av_frame_unrefclass="token punctuation">(frameclass="token punctuation">)class="token punctuation">;
            class="token keyword">return retclass="token punctuation">;
        class="token punctuation">}
    class="token punctuation">}

    avctxclass="token operator">->frame_numberclass="token operator">++class="token punctuation">;

    class="token keyword">if class="token punctuation">(avctxclass="token operator">->flags class="token operator">& AV_CODEC_FLAG_DROPCHANGEDclass="token punctuation">) class="token punctuation">{

        class="token keyword">if class="token punctuation">(avctxclass="token operator">->frame_number class="token operator">== class="token number">1class="token punctuation">) class="token punctuation">{
            avciclass="token operator">->initial_format class="token operator">= frameclass="token operator">->formatclass="token punctuation">;
            class="token keyword">switchclass="token punctuation">(avctxclass="token operator">->codec_typeclass="token punctuation">) class="token punctuation">{
            class="token keyword">case AVMEDIA_TYPE_VIDEOclass="token operator">:
                avciclass="token operator">->initial_width  class="token operator">= frameclass="token operator">->widthclass="token punctuation">;
                avciclass="token operator">->initial_height class="token operator">= frameclass="token operator">->heightclass="token punctuation">;
                class="token keyword">breakclass="token punctuation">;
            class="token keyword">case AVMEDIA_TYPE_AUDIOclass="token operator">:
                avciclass="token operator">->initial_sample_rate class="token operator">= frameclass="token operator">->sample_rate class="token operator">? frameclass="token operator">->sample_rate class="token operator">:
                                                                 avctxclass="token operator">->sample_rateclass="token punctuation">;
                avciclass="token operator">->initial_channels       class="token operator">= frameclass="token operator">->channelsclass="token punctuation">;
                avciclass="token operator">->initial_channel_layout class="token operator">= frameclass="token operator">->channel_layoutclass="token punctuation">;
                class="token keyword">breakclass="token punctuation">;
            class="token punctuation">}
        class="token punctuation">}

        class="token keyword">if class="token punctuation">(avctxclass="token operator">->frame_number class="token operator">> class="token number">1class="token punctuation">) class="token punctuation">{
            changed class="token operator">= avciclass="token operator">->initial_format class="token operator">!= frameclass="token operator">->formatclass="token punctuation">;

            class="token keyword">switchclass="token punctuation">(avctxclass="token operator">->codec_typeclass="token punctuation">) class="token punctuation">{
            class="token keyword">case AVMEDIA_TYPE_VIDEOclass="token operator">:
                changed class="token operator">|= avciclass="token operator">->initial_width  class="token operator">!= frameclass="token operator">->width class="token operator">||
                           avciclass="token operator">->initial_height class="token operator">!= frameclass="token operator">->heightclass="token punctuation">;
                class="token keyword">breakclass="token punctuation">;
            class="token keyword">case AVMEDIA_TYPE_AUDIOclass="token operator">:
                changed class="token operator">|= avciclass="token operator">->initial_sample_rate    class="token operator">!= frameclass="token operator">->sample_rate class="token operator">||
                           avciclass="token operator">->initial_sample_rate    class="token operator">!= avctxclass="token operator">->sample_rate class="token operator">||
                           avciclass="token operator">->initial_channels       class="token operator">!= frameclass="token operator">->channels class="token operator">||
                           avciclass="token operator">->initial_channel_layout class="token operator">!= frameclass="token operator">->channel_layoutclass="token punctuation">;
                class="token keyword">breakclass="token punctuation">;
            class="token punctuation">}

            class="token keyword">if class="token punctuation">(changedclass="token punctuation">) class="token punctuation">{
                avciclass="token operator">->changed_frames_droppedclass="token operator">++class="token punctuation">;
                class="token function">av_logclass="token punctuation">(avctxclass="token punctuation">, AV_LOG_INFOclass="token punctuation">, class="token string">"dropped changed frame #%d pts %"PRId64
                                            class="token string">" drop count: %d \n"class="token punctuation">,
                                            avctxclass="token operator">->frame_numberclass="token punctuation">, frameclass="token operator">->ptsclass="token punctuation">,
                                            avciclass="token operator">->changed_frames_droppedclass="token punctuation">)class="token punctuation">;
                class="token function">av_frame_unrefclass="token punctuation">(frameclass="token punctuation">)class="token punctuation">;
                class="token keyword">return AVERROR_INPUT_CHANGEDclass="token punctuation">;
            class="token punctuation">}
        class="token punctuation">}
    class="token punctuation">}
    class="token keyword">return class="token number">0class="token punctuation">;
class="token punctuation">}
code>

code_receive_frame_internal__181">decode_receive_frame_internal 源码

获取解码后的frame。

<code class="prism language-c">class="token keyword">static class="token keyword">int class="token function">decode_receive_frame_internalclass="token punctuation">(AVCodecContext class="token operator">*avctxclass="token punctuation">, AVFrame class="token operator">*frameclass="token punctuation">)
class="token punctuation">{
    AVCodecInternal class="token operator">*avci class="token operator">= avctxclass="token operator">->internalclass="token punctuation">;
    class="token keyword">int retclass="token punctuation">;

    class="token function">av_assert0class="token punctuation">(class="token operator">!frameclass="token operator">->bufclass="token punctuation">[class="token number">0class="token punctuation">]class="token punctuation">)class="token punctuation">;

	class="token comment">// 只有少部分解码器会实现这个函数࿰c;实现这个函数的解码器不会实现多线程解码࿰c;比如mjpeg
    class="token keyword">if class="token punctuation">(avctxclass="token operator">->codecclass="token operator">->receive_frameclass="token punctuation">) class="token punctuation">{
        ret class="token operator">= avctxclass="token operator">->codecclass="token operator">->class="token function">receive_frameclass="token punctuation">(avctxclass="token punctuation">, frameclass="token punctuation">)class="token punctuation">;
        class="token keyword">if class="token punctuation">(ret class="token operator">!= class="token function">AVERRORclass="token punctuation">(EAGAINclass="token punctuation">)class="token punctuation">)
            class="token function">av_packet_unrefclass="token punctuation">(avciclass="token operator">->last_pkt_propsclass="token punctuation">)class="token punctuation">;
    class="token punctuation">} class="token keyword">else
    	class="token comment">//大部分都是调用这个函数
        ret class="token operator">= class="token function">decode_simple_receive_frameclass="token punctuation">(avctxclass="token punctuation">, frameclass="token punctuation">)class="token punctuation">;

    class="token keyword">if class="token punctuation">(ret class="token operator">== AVERROR_EOFclass="token punctuation">)
        avciclass="token operator">->draining_done class="token operator">= class="token number">1class="token punctuation">;

    class="token keyword">if class="token punctuation">(class="token operator">!retclass="token punctuation">) class="token punctuation">{
        frameclass="token operator">->best_effort_timestamp class="token operator">= class="token function">guess_correct_ptsclass="token punctuation">(avctxclass="token punctuation">,
                                                         frameclass="token operator">->ptsclass="token punctuation">,
                                                         frameclass="token operator">->pkt_dtsclass="token punctuation">)class="token punctuation">;

        class="token comment">/* the only case where decode data is not set should be decoders
         * that do not call ff_get_buffer() */
        class="token function">av_assert0class="token punctuation">(class="token punctuation">(frameclass="token operator">->private_ref class="token operator">&& frameclass="token operator">->private_refclass="token operator">->size class="token operator">== class="token keyword">sizeofclass="token punctuation">(FrameDecodeDataclass="token punctuation">)class="token punctuation">) class="token operator">||
                   class="token operator">!class="token punctuation">(avctxclass="token operator">->codecclass="token operator">->capabilities class="token operator">& AV_CODEC_CAP_DR1class="token punctuation">)class="token punctuation">)class="token punctuation">;

        class="token keyword">if class="token punctuation">(frameclass="token operator">->private_refclass="token punctuation">) class="token punctuation">{
            FrameDecodeData class="token operator">*fdd class="token operator">= class="token punctuation">(FrameDecodeDataclass="token operator">*class="token punctuation">)frameclass="token operator">->private_refclass="token operator">->dataclass="token punctuation">;

            class="token keyword">if class="token punctuation">(fddclass="token operator">->post_processclass="token punctuation">) class="token punctuation">{
                ret class="token operator">= fddclass="token operator">->class="token function">post_processclass="token punctuation">(avctxclass="token punctuation">, frameclass="token punctuation">)class="token punctuation">;
                class="token keyword">if class="token punctuation">(ret class="token operator">< class="token number">0class="token punctuation">) class="token punctuation">{
                    class="token function">av_frame_unrefclass="token punctuation">(frameclass="token punctuation">)class="token punctuation">;
                    class="token keyword">return retclass="token punctuation">;
                class="token punctuation">}
            class="token punctuation">}
        class="token punctuation">}
    class="token punctuation">}

    class="token comment">/* free the per-frame decode data */
    class="token function">av_buffer_unrefclass="token punctuation">(class="token operator">&frameclass="token operator">->private_refclass="token punctuation">)class="token punctuation">;

    class="token keyword">return retclass="token punctuation">;
class="token punctuation">}

code>

code_simple_receive_frame__234">decode_simple_receive_frame 源码

通过调用decode_simple_internal来实现解码AVPacket࿰c;然后获取解码后的frame。

<code class="prism language-c">class="token keyword">static class="token keyword">int class="token function">decode_simple_receive_frameclass="token punctuation">(AVCodecContext class="token operator">*avctxclass="token punctuation">, AVFrame class="token operator">*frameclass="token punctuation">)
class="token punctuation">{
    class="token keyword">int retclass="token punctuation">;
    class="token class-name">int64_t discarded_samples class="token operator">= class="token number">0class="token punctuation">;

    class="token keyword">while class="token punctuation">(class="token operator">!frameclass="token operator">->bufclass="token punctuation">[class="token number">0class="token punctuation">]class="token punctuation">) class="token punctuation">{
        class="token keyword">if class="token punctuation">(discarded_samples class="token operator">> avctxclass="token operator">->max_samplesclass="token punctuation">)
            class="token keyword">return class="token function">AVERRORclass="token punctuation">(EAGAINclass="token punctuation">)class="token punctuation">;
        ret class="token operator">= class="token function">decode_simple_internalclass="token punctuation">(avctxclass="token punctuation">, frameclass="token punctuation">, class="token operator">&discarded_samplesclass="token punctuation">)class="token punctuation">;
        class="token keyword">if class="token punctuation">(ret class="token operator">< class="token number">0class="token punctuation">)
            class="token keyword">return retclass="token punctuation">;
    class="token punctuation">}

    class="token keyword">return class="token number">0class="token punctuation">;
class="token punctuation">}
code>

code_simple_internal__254">decode_simple_internal 源码

avcodec_send_packet和avcodec_receive_frame中最核心的函数࿰c;大部分的编码格式都会调用到这里解码。

<code class="prism language-c">class="token comment">/*
 * The core of the receive_frame_wrapper for the decoders implementing
 * the simple API. Certain decoders might consume partial packets without
 * returning any output, so this function needs to be called in a loop until it
 * returns EAGAIN.
 **/
class="token keyword">static class="token keyword">inline class="token keyword">int class="token function">decode_simple_internalclass="token punctuation">(AVCodecContext class="token operator">*avctxclass="token punctuation">, AVFrame class="token operator">*frameclass="token punctuation">, class="token class-name">int64_t class="token operator">*discarded_samplesclass="token punctuation">)
class="token punctuation">{
    AVCodecInternal   class="token operator">*avci class="token operator">= avctxclass="token operator">->internalclass="token punctuation">;
    DecodeSimpleContext class="token operator">*ds class="token operator">= class="token operator">&avciclass="token operator">->dsclass="token punctuation">;
    AVPacket           class="token operator">*pkt class="token operator">= dsclass="token operator">->in_pktclass="token punctuation">;
    class="token keyword">int got_frameclass="token punctuation">, actual_got_frameclass="token punctuation">;
    class="token keyword">int retclass="token punctuation">;

    class="token keyword">if class="token punctuation">(class="token operator">!pktclass="token operator">->data class="token operator">&& class="token operator">!avciclass="token operator">->drainingclass="token punctuation">) class="token punctuation">{
        class="token function">av_packet_unrefclass="token punctuation">(pktclass="token punctuation">)class="token punctuation">;
        class="token comment">// 从avci->bsf中获得AVPacket࿰c;然后设置到pkt中
        ret class="token operator">= class="token function">ff_decode_get_packetclass="token punctuation">(avctxclass="token punctuation">, pktclass="token punctuation">)class="token punctuation">;
        class="token keyword">if class="token punctuation">(ret class="token operator">< class="token number">0 class="token operator">&& ret class="token operator">!= AVERROR_EOFclass="token punctuation">)
            class="token keyword">return retclass="token punctuation">;
    class="token punctuation">}

    class="token comment">// Some codecs (at least wma lossless) will crash when feeding drain packets
    class="token comment">// after EOF was signaled.
    class="token keyword">if class="token punctuation">(avciclass="token operator">->draining_doneclass="token punctuation">)
        class="token keyword">return AVERROR_EOFclass="token punctuation">;

    class="token keyword">if class="token punctuation">(class="token operator">!pktclass="token operator">->data class="token operator">&&
        class="token operator">!class="token punctuation">(avctxclass="token operator">->codecclass="token operator">->capabilities class="token operator">& AV_CODEC_CAP_DELAY class="token operator">||
          avctxclass="token operator">->active_thread_type class="token operator">& FF_THREAD_FRAMEclass="token punctuation">)class="token punctuation">)
        class="token keyword">return AVERROR_EOFclass="token punctuation">;

    got_frame class="token operator">= class="token number">0class="token punctuation">;

	class="token comment">// 多线程解码 或者 单线程
    class="token keyword">if class="token punctuation">(HAVE_THREADS class="token operator">&& avctxclass="token operator">->active_thread_type class="token operator">& FF_THREAD_FRAMEclass="token punctuation">) class="token punctuation">{
    	class="token comment">// 多线程解码
    	class="token comment">// 先调用avcodec_open2打开多个解码线程࿰c;然后这里实现多线程解码
        ret class="token operator">= class="token function">ff_thread_decode_frameclass="token punctuation">(avctxclass="token punctuation">, frameclass="token punctuation">, class="token operator">&got_frameclass="token punctuation">, pktclass="token punctuation">)class="token punctuation">;
    class="token punctuation">} class="token keyword">else class="token punctuation">{
    	class="token comment">//调用对应AVCodec的decode方法࿰c;h264默认解码器的话࿰c;就会调用class="tags" href="/tags/FFMPEG.html" title=ffmpeg>ffmpeg内置的h264解码器
        ret class="token operator">= avctxclass="token operator">->codecclass="token operator">->class="token function">decodeclass="token punctuation">(avctxclass="token punctuation">, frameclass="token punctuation">, class="token operator">&got_frameclass="token punctuation">, pktclass="token punctuation">)class="token punctuation">;

        class="token keyword">if class="token punctuation">(class="token operator">!class="token punctuation">(avctxclass="token operator">->codecclass="token operator">->caps_internal class="token operator">& FF_CODEC_CAP_SETS_PKT_DTSclass="token punctuation">)class="token punctuation">)
            frameclass="token operator">->pkt_dts class="token operator">= pktclass="token operator">->dtsclass="token punctuation">;
        class="token keyword">if class="token punctuation">(avctxclass="token operator">->codecclass="token operator">->type class="token operator">== AVMEDIA_TYPE_VIDEOclass="token punctuation">) class="token punctuation">{
            class="token keyword">ifclass="token punctuation">(class="token operator">!avctxclass="token operator">->has_b_framesclass="token punctuation">)
                frameclass="token operator">->pkt_pos class="token operator">= pktclass="token operator">->posclass="token punctuation">;
            class="token comment">//FIXME these should be under if(!avctx->has_b_frames)
            class="token comment">/* get_buffer is supposed to set frame parameters */
            class="token keyword">if class="token punctuation">(class="token operator">!class="token punctuation">(avctxclass="token operator">->codecclass="token operator">->capabilities class="token operator">& AV_CODEC_CAP_DR1class="token punctuation">)class="token punctuation">) class="token punctuation">{
                class="token keyword">if class="token punctuation">(class="token operator">!frameclass="token operator">->sample_aspect_ratioclass="token punctuation">.numclass="token punctuation">)  frameclass="token operator">->sample_aspect_ratio class="token operator">= avctxclass="token operator">->sample_aspect_ratioclass="token punctuation">;
                class="token keyword">if class="token punctuation">(class="token operator">!frameclass="token operator">->widthclass="token punctuation">)                    frameclass="token operator">->width               class="token operator">= avctxclass="token operator">->widthclass="token punctuation">;
                class="token keyword">if class="token punctuation">(class="token operator">!frameclass="token operator">->heightclass="token punctuation">)                   frameclass="token operator">->height              class="token operator">= avctxclass="token operator">->heightclass="token punctuation">;
                class="token keyword">if class="token punctuation">(frameclass="token operator">->format class="token operator">== AV_PIX_FMT_NONEclass="token punctuation">) frameclass="token operator">->format              class="token operator">= avctxclass="token operator">->pix_fmtclass="token punctuation">;
            class="token punctuation">}
        class="token punctuation">}
    class="token punctuation">}
    class="token function">emms_cclass="token punctuation">(class="token punctuation">)class="token punctuation">;
    actual_got_frame class="token operator">= got_frameclass="token punctuation">;

    class="token keyword">if class="token punctuation">(avctxclass="token operator">->codecclass="token operator">->type class="token operator">== AVMEDIA_TYPE_VIDEOclass="token punctuation">) class="token punctuation">{
    	class="token comment">//discard 丢弃掉了
        class="token keyword">if class="token punctuation">(frameclass="token operator">->flags class="token operator">& AV_FRAME_FLAG_DISCARDclass="token punctuation">)
            got_frame class="token operator">= class="token number">0class="token punctuation">;
    class="token punctuation">} class="token keyword">else class="token keyword">if class="token punctuation">(avctxclass="token operator">->codecclass="token operator">->type class="token operator">== AVMEDIA_TYPE_AUDIOclass="token punctuation">) class="token punctuation">{
        class="token class-name">uint8_t class="token operator">*sideclass="token punctuation">;
        class="token class-name">buffer_size_t side_sizeclass="token punctuation">;
        class="token class-name">uint32_t discard_padding class="token operator">= class="token number">0class="token punctuation">;
        class="token class-name">uint8_t skip_reason class="token operator">= class="token number">0class="token punctuation">;
        class="token class-name">uint8_t discard_reason class="token operator">= class="token number">0class="token punctuation">;

		class="token comment">//设置frame的一些参数
        class="token keyword">if class="token punctuation">(ret class="token operator">>= class="token number">0 class="token operator">&& got_frameclass="token punctuation">) class="token punctuation">{
            class="token keyword">if class="token punctuation">(frameclass="token operator">->format class="token operator">== AV_SAMPLE_FMT_NONEclass="token punctuation">)
                frameclass="token operator">->format class="token operator">= avctxclass="token operator">->sample_fmtclass="token punctuation">;
            class="token keyword">if class="token punctuation">(class="token operator">!frameclass="token operator">->channel_layoutclass="token punctuation">)
                frameclass="token operator">->channel_layout class="token operator">= avctxclass="token operator">->channel_layoutclass="token punctuation">;
            class="token keyword">if class="token punctuation">(class="token operator">!frameclass="token operator">->channelsclass="token punctuation">)
                frameclass="token operator">->channels class="token operator">= avctxclass="token operator">->channelsclass="token punctuation">;
            class="token keyword">if class="token punctuation">(class="token operator">!frameclass="token operator">->sample_rateclass="token punctuation">)
                frameclass="token operator">->sample_rate class="token operator">= avctxclass="token operator">->sample_rateclass="token punctuation">;
        class="token punctuation">}

        sideclass="token operator">= class="token function">av_packet_get_side_dataclass="token punctuation">(avciclass="token operator">->last_pkt_propsclass="token punctuation">, AV_PKT_DATA_SKIP_SAMPLESclass="token punctuation">, class="token operator">&side_sizeclass="token punctuation">)class="token punctuation">;
        class="token comment">//跳过skip_samples帧数
        class="token keyword">ifclass="token punctuation">(side class="token operator">&& side_sizeclass="token operator">>=class="token number">10class="token punctuation">) class="token punctuation">{
            avciclass="token operator">->skip_samples class="token operator">= class="token function">AV_RL32class="token punctuation">(sideclass="token punctuation">) class="token operator">* avciclass="token operator">->skip_samples_multiplierclass="token punctuation">;
            discard_padding class="token operator">= class="token function">AV_RL32class="token punctuation">(side class="token operator">+ class="token number">4class="token punctuation">)class="token punctuation">;
            class="token function">av_logclass="token punctuation">(avctxclass="token punctuation">, AV_LOG_DEBUGclass="token punctuation">, class="token string">"skip %d / discard %d samples due to side data\n"class="token punctuation">,
                   avciclass="token operator">->skip_samplesclass="token punctuation">, class="token punctuation">(class="token keyword">intclass="token punctuation">)discard_paddingclass="token punctuation">)class="token punctuation">;
            skip_reason class="token operator">= class="token function">AV_RL8class="token punctuation">(side class="token operator">+ class="token number">8class="token punctuation">)class="token punctuation">;
            discard_reason class="token operator">= class="token function">AV_RL8class="token punctuation">(side class="token operator">+ class="token number">9class="token punctuation">)class="token punctuation">;
        class="token punctuation">}

        class="token keyword">if class="token punctuation">(class="token punctuation">(frameclass="token operator">->flags class="token operator">& AV_FRAME_FLAG_DISCARDclass="token punctuation">) class="token operator">&& got_frame class="token operator">&&
            class="token operator">!class="token punctuation">(avctxclass="token operator">->flags2 class="token operator">& AV_CODEC_FLAG2_SKIP_MANUALclass="token punctuation">)class="token punctuation">) class="token punctuation">{
            avciclass="token operator">->skip_samples class="token operator">= class="token function">FFMAXclass="token punctuation">(class="token number">0class="token punctuation">, avciclass="token operator">->skip_samples class="token operator">- frameclass="token operator">->nb_samplesclass="token punctuation">)class="token punctuation">;
            got_frame class="token operator">= class="token number">0class="token punctuation">;
            class="token operator">*discarded_samples class="token operator">+= frameclass="token operator">->nb_samplesclass="token punctuation">;
        class="token punctuation">}

        class="token keyword">if class="token punctuation">(avciclass="token operator">->skip_samples class="token operator">> class="token number">0 class="token operator">&& got_frame class="token operator">&&
            class="token operator">!class="token punctuation">(avctxclass="token operator">->flags2 class="token operator">& AV_CODEC_FLAG2_SKIP_MANUALclass="token punctuation">)class="token punctuation">) class="token punctuation">{
            class="token keyword">ifclass="token punctuation">(frameclass="token operator">->nb_samples class="token operator"><= avciclass="token operator">->skip_samplesclass="token punctuation">)class="token punctuation">{
                got_frame class="token operator">= class="token number">0class="token punctuation">;
                class="token operator">*discarded_samples class="token operator">+= frameclass="token operator">->nb_samplesclass="token punctuation">;
                avciclass="token operator">->skip_samples class="token operator">-= frameclass="token operator">->nb_samplesclass="token punctuation">;
                class="token function">av_logclass="token punctuation">(avctxclass="token punctuation">, AV_LOG_DEBUGclass="token punctuation">, class="token string">"skip whole frame, skip left: %d\n"class="token punctuation">,
                       avciclass="token operator">->skip_samplesclass="token punctuation">)class="token punctuation">;
            class="token punctuation">} class="token keyword">else class="token punctuation">{
                class="token function">av_samples_copyclass="token punctuation">(frameclass="token operator">->extended_dataclass="token punctuation">, frameclass="token operator">->extended_dataclass="token punctuation">, class="token number">0class="token punctuation">, avciclass="token operator">->skip_samplesclass="token punctuation">,
                                frameclass="token operator">->nb_samples class="token operator">- avciclass="token operator">->skip_samplesclass="token punctuation">, avctxclass="token operator">->channelsclass="token punctuation">, frameclass="token operator">->formatclass="token punctuation">)class="token punctuation">;
                class="token keyword">ifclass="token punctuation">(avctxclass="token operator">->pkt_timebaseclass="token punctuation">.num class="token operator">&& avctxclass="token operator">->sample_rateclass="token punctuation">) class="token punctuation">{
                    class="token class-name">int64_t diff_ts class="token operator">= class="token function">av_rescale_qclass="token punctuation">(avciclass="token operator">->skip_samplesclass="token punctuation">,
                                                   class="token punctuation">(AVRationalclass="token punctuation">)class="token punctuation">{class="token number">1class="token punctuation">, avctxclass="token operator">->sample_rateclass="token punctuation">}class="token punctuation">,
                                                   avctxclass="token operator">->pkt_timebaseclass="token punctuation">)class="token punctuation">;
                    class="token keyword">ifclass="token punctuation">(frameclass="token operator">->ptsclass="token operator">!=AV_NOPTS_VALUEclass="token punctuation">)
                        frameclass="token operator">->pts class="token operator">+= diff_tsclass="token punctuation">;
class="token macro property">class="token directive-hash">#class="token directive keyword">if class="token expression">FF_API_PKT_PTS
FF_DISABLE_DEPRECATION_WARNINGS
                    class="token keyword">ifclass="token punctuation">(frameclass="token operator">->pkt_ptsclass="token operator">!=AV_NOPTS_VALUEclass="token punctuation">)
                        frameclass="token operator">->pkt_pts class="token operator">+= diff_tsclass="token punctuation">;
FF_ENABLE_DEPRECATION_WARNINGS
class="token macro property">class="token directive-hash">#class="token directive keyword">endif
                    class="token keyword">ifclass="token punctuation">(frameclass="token operator">->pkt_dtsclass="token operator">!=AV_NOPTS_VALUEclass="token punctuation">)
                        frameclass="token operator">->pkt_dts class="token operator">+= diff_tsclass="token punctuation">;
                    class="token keyword">if class="token punctuation">(frameclass="token operator">->pkt_duration class="token operator">>= diff_tsclass="token punctuation">)
                        frameclass="token operator">->pkt_duration class="token operator">-= diff_tsclass="token punctuation">;
                class="token punctuation">} class="token keyword">else class="token punctuation">{
                    class="token function">av_logclass="token punctuation">(avctxclass="token punctuation">, AV_LOG_WARNINGclass="token punctuation">, class="token string">"Could not update timestamps for skipped samples.\n"class="token punctuation">)class="token punctuation">;
                class="token punctuation">}
                class="token function">av_logclass="token punctuation">(avctxclass="token punctuation">, AV_LOG_DEBUGclass="token punctuation">, class="token string">"skip %d/%d samples\n"class="token punctuation">,
                       avciclass="token operator">->skip_samplesclass="token punctuation">, frameclass="token operator">->nb_samplesclass="token punctuation">)class="token punctuation">;
                class="token operator">*discarded_samples class="token operator">+= avciclass="token operator">->skip_samplesclass="token punctuation">;
                frameclass="token operator">->nb_samples class="token operator">-= avciclass="token operator">->skip_samplesclass="token punctuation">;
                avciclass="token operator">->skip_samples class="token operator">= class="token number">0class="token punctuation">;
            class="token punctuation">}
        class="token punctuation">}

        class="token keyword">if class="token punctuation">(discard_padding class="token operator">> class="token number">0 class="token operator">&& discard_padding class="token operator"><= frameclass="token operator">->nb_samples class="token operator">&& got_frame class="token operator">&&
            class="token operator">!class="token punctuation">(avctxclass="token operator">->flags2 class="token operator">& AV_CODEC_FLAG2_SKIP_MANUALclass="token punctuation">)class="token punctuation">) class="token punctuation">{
            class="token keyword">if class="token punctuation">(discard_padding class="token operator">== frameclass="token operator">->nb_samplesclass="token punctuation">) class="token punctuation">{
                class="token operator">*discarded_samples class="token operator">+= frameclass="token operator">->nb_samplesclass="token punctuation">;
                got_frame class="token operator">= class="token number">0class="token punctuation">;
            class="token punctuation">} class="token keyword">else class="token punctuation">{
                class="token keyword">ifclass="token punctuation">(avctxclass="token operator">->pkt_timebaseclass="token punctuation">.num class="token operator">&& avctxclass="token operator">->sample_rateclass="token punctuation">) class="token punctuation">{
                    class="token class-name">int64_t diff_ts class="token operator">= class="token function">av_rescale_qclass="token punctuation">(frameclass="token operator">->nb_samples class="token operator">- discard_paddingclass="token punctuation">,
                                                   class="token punctuation">(AVRationalclass="token punctuation">)class="token punctuation">{class="token number">1class="token punctuation">, avctxclass="token operator">->sample_rateclass="token punctuation">}class="token punctuation">,
                                                   avctxclass="token operator">->pkt_timebaseclass="token punctuation">)class="token punctuation">;
                    frameclass="token operator">->pkt_duration class="token operator">= diff_tsclass="token punctuation">;
                class="token punctuation">} class="token keyword">else class="token punctuation">{
                    class="token function">av_logclass="token punctuation">(avctxclass="token punctuation">, AV_LOG_WARNINGclass="token punctuation">, class="token string">"Could not update timestamps for discarded samples.\n"class="token punctuation">)class="token punctuation">;
                class="token punctuation">}
                class="token function">av_logclass="token punctuation">(avctxclass="token punctuation">, AV_LOG_DEBUGclass="token punctuation">, class="token string">"discard %d/%d samples\n"class="token punctuation">,
                       class="token punctuation">(class="token keyword">intclass="token punctuation">)discard_paddingclass="token punctuation">, frameclass="token operator">->nb_samplesclass="token punctuation">)class="token punctuation">;
                frameclass="token operator">->nb_samples class="token operator">-= discard_paddingclass="token punctuation">;
            class="token punctuation">}
        class="token punctuation">}

        class="token keyword">if class="token punctuation">(class="token punctuation">(avctxclass="token operator">->flags2 class="token operator">& AV_CODEC_FLAG2_SKIP_MANUALclass="token punctuation">) class="token operator">&& got_frameclass="token punctuation">) class="token punctuation">{
            AVFrameSideData class="token operator">*fside class="token operator">= class="token function">av_frame_new_side_dataclass="token punctuation">(frameclass="token punctuation">, AV_FRAME_DATA_SKIP_SAMPLESclass="token punctuation">, class="token number">10class="token punctuation">)class="token punctuation">;
            class="token keyword">if class="token punctuation">(fsideclass="token punctuation">) class="token punctuation">{
                class="token function">AV_WL32class="token punctuation">(fsideclass="token operator">->dataclass="token punctuation">, avciclass="token operator">->skip_samplesclass="token punctuation">)class="token punctuation">;
                class="token function">AV_WL32class="token punctuation">(fsideclass="token operator">->data class="token operator">+ class="token number">4class="token punctuation">, discard_paddingclass="token punctuation">)class="token punctuation">;
                class="token function">AV_WL8class="token punctuation">(fsideclass="token operator">->data class="token operator">+ class="token number">8class="token punctuation">, skip_reasonclass="token punctuation">)class="token punctuation">;
                class="token function">AV_WL8class="token punctuation">(fsideclass="token operator">->data class="token operator">+ class="token number">9class="token punctuation">, discard_reasonclass="token punctuation">)class="token punctuation">;
                avciclass="token operator">->skip_samples class="token operator">= class="token number">0class="token punctuation">;
            class="token punctuation">}
        class="token punctuation">}
    class="token punctuation">}

    class="token keyword">if class="token punctuation">(avctxclass="token operator">->codecclass="token operator">->type class="token operator">== AVMEDIA_TYPE_AUDIO class="token operator">&&
        class="token operator">!avciclass="token operator">->showed_multi_packet_warning class="token operator">&&
        ret class="token operator">>= class="token number">0 class="token operator">&& ret class="token operator">!= pktclass="token operator">->size class="token operator">&& class="token operator">!class="token punctuation">(avctxclass="token operator">->codecclass="token operator">->capabilities class="token operator">& AV_CODEC_CAP_SUBFRAMESclass="token punctuation">)class="token punctuation">) class="token punctuation">{
        class="token function">av_logclass="token punctuation">(avctxclass="token punctuation">, AV_LOG_WARNINGclass="token punctuation">, class="token string">"Multiple frames in a packet.\n"class="token punctuation">)class="token punctuation">;
        avciclass="token operator">->showed_multi_packet_warning class="token operator">= class="token number">1class="token punctuation">;
    class="token punctuation">}

    class="token keyword">if class="token punctuation">(class="token operator">!got_frameclass="token punctuation">)
        class="token function">av_frame_unrefclass="token punctuation">(frameclass="token punctuation">)class="token punctuation">;

    class="token keyword">if class="token punctuation">(ret class="token operator">>= class="token number">0 class="token operator">&& avctxclass="token operator">->codecclass="token operator">->type class="token operator">== AVMEDIA_TYPE_VIDEO class="token operator">&& class="token operator">!class="token punctuation">(avctxclass="token operator">->flags class="token operator">& AV_CODEC_FLAG_TRUNCATEDclass="token punctuation">)class="token punctuation">)
        ret class="token operator">= pktclass="token operator">->sizeclass="token punctuation">;

class="token macro property">class="token directive-hash">#class="token directive keyword">if class="token expression">FF_API_AVCTX_TIMEBASE
    class="token keyword">if class="token punctuation">(avctxclass="token operator">->framerateclass="token punctuation">.num class="token operator">> class="token number">0 class="token operator">&& avctxclass="token operator">->framerateclass="token punctuation">.den class="token operator">> class="token number">0class="token punctuation">)
        avctxclass="token operator">->time_base class="token operator">= class="token function">av_inv_qclass="token punctuation">(class="token function">av_mul_qclass="token punctuation">(avctxclass="token operator">->framerateclass="token punctuation">, class="token punctuation">(AVRationalclass="token punctuation">)class="token punctuation">{avctxclass="token operator">->ticks_per_frameclass="token punctuation">, class="token number">1class="token punctuation">}class="token punctuation">)class="token punctuation">)class="token punctuation">;
class="token macro property">class="token directive-hash">#class="token directive keyword">endif

    class="token comment">/* do not stop draining when actual_got_frame != 0 or ret < 0 */
    class="token comment">/* got_frame == 0 but actual_got_frame != 0 when frame is discarded */
    class="token keyword">if class="token punctuation">(avciclass="token operator">->draining class="token operator">&& class="token operator">!actual_got_frameclass="token punctuation">) class="token punctuation">{
        class="token keyword">if class="token punctuation">(ret class="token operator">< class="token number">0class="token punctuation">) class="token punctuation">{
            class="token comment">/* prevent infinite loop if a decoder wrongly always return error on draining */
            class="token comment">/* reasonable nb_errors_max = maximum b frames + thread count */
            class="token keyword">int nb_errors_max class="token operator">= class="token number">20 class="token operator">+ class="token punctuation">(HAVE_THREADS class="token operator">&& avctxclass="token operator">->active_thread_type class="token operator">& FF_THREAD_FRAME class="token operator">?
                                avctxclass="token operator">->thread_count class="token operator">: class="token number">1class="token punctuation">)class="token punctuation">;

            class="token keyword">if class="token punctuation">(avciclass="token operator">->nb_draining_errorsclass="token operator">++ class="token operator">>= nb_errors_maxclass="token punctuation">) class="token punctuation">{
                class="token function">av_logclass="token punctuation">(avctxclass="token punctuation">, AV_LOG_ERRORclass="token punctuation">, class="token string">"Too many errors when draining, this is a bug. "
                       class="token string">"Stop draining and force EOF.\n"class="token punctuation">)class="token punctuation">;
                avciclass="token operator">->draining_done class="token operator">= class="token number">1class="token punctuation">;
                ret class="token operator">= AVERROR_BUGclass="token punctuation">;
            class="token punctuation">}
        class="token punctuation">} class="token keyword">else class="token punctuation">{
            avciclass="token operator">->draining_done class="token operator">= class="token number">1class="token punctuation">;
        class="token punctuation">}
    class="token punctuation">}

class="token macro property">class="token directive-hash">#class="token directive keyword">if class="token expression">FF_API_OLD_ENCDEC
    avciclass="token operator">->compat_decode_consumed class="token operator">+= retclass="token punctuation">;
class="token macro property">class="token directive-hash">#class="token directive keyword">endif

    class="token keyword">if class="token punctuation">(ret class="token operator">>= pktclass="token operator">->size class="token operator">|| ret class="token operator">< class="token number">0class="token punctuation">) class="token punctuation">{
        class="token function">av_packet_unrefclass="token punctuation">(pktclass="token punctuation">)class="token punctuation">;
        class="token function">av_packet_unrefclass="token punctuation">(avciclass="token operator">->last_pkt_propsclass="token punctuation">)class="token punctuation">;
    class="token punctuation">} class="token keyword">else class="token punctuation">{
        class="token keyword">int consumed class="token operator">= retclass="token punctuation">;

        pktclass="token operator">->data                class="token operator">+= consumedclass="token punctuation">;
        pktclass="token operator">->size                class="token operator">-= consumedclass="token punctuation">;
        avciclass="token operator">->last_pkt_propsclass="token operator">->size class="token operator">-= consumedclass="token punctuation">; class="token comment">// See extract_packet_props() comment.
        pktclass="token operator">->pts                  class="token operator">= AV_NOPTS_VALUEclass="token punctuation">;
        pktclass="token operator">->dts                  class="token operator">= AV_NOPTS_VALUEclass="token punctuation">;
        avciclass="token operator">->last_pkt_propsclass="token operator">->pts class="token operator">= AV_NOPTS_VALUEclass="token punctuation">;
        avciclass="token operator">->last_pkt_propsclass="token operator">->dts class="token operator">= AV_NOPTS_VALUEclass="token punctuation">;
    class="token punctuation">}

    class="token keyword">if class="token punctuation">(got_frameclass="token punctuation">)
        class="token function">av_assert0class="token punctuation">(frameclass="token operator">->bufclass="token punctuation">[class="token number">0class="token punctuation">]class="token punctuation">)class="token punctuation">;

    class="token keyword">return ret class="token operator">< class="token number">0 class="token operator">? ret class="token operator">: class="token number">0class="token punctuation">;
class="token punctuation">}

code>

code_frame__494">ff_thread_decode_frame 源码

多线程解码实现࿰c;在此之前࿰c;通过需要先通过调用avcodec_open2创建多个线程。
然后在这个函数中࿰c;先调用submit_packet()函数提交packet到下一个解码线程࿰c;然后调用数组中最前面线程进行解码。相关代码如下:

<code class="prism language-c">class="token keyword">int class="token function">ff_thread_decode_frameclass="token punctuation">(AVCodecContext class="token operator">*avctxclass="token punctuation">,
                           AVFrame class="token operator">*pictureclass="token punctuation">, class="token keyword">int class="token operator">*got_picture_ptrclass="token punctuation">,
                           AVPacket class="token operator">*avpktclass="token punctuation">)
class="token punctuation">{
    FrameThreadContext class="token operator">*fctx class="token operator">= avctxclass="token operator">->internalclass="token operator">->thread_ctxclass="token punctuation">;
    class="token keyword">int finished class="token operator">= fctxclass="token operator">->next_finishedclass="token punctuation">;
    PerThreadContext class="token operator">*pclass="token punctuation">;
    class="token keyword">int errclass="token punctuation">;

    class="token comment">/* release the async lock, permitting blocked hwaccel threads to
     * go forward while we are in this function */
    class="token function">async_unlockclass="token punctuation">(fctxclass="token punctuation">)class="token punctuation">;

    class="token comment">/*
     * Submit a packet to the next decoding thread.
     */

    p class="token operator">= class="token operator">&fctxclass="token operator">->threadsclass="token punctuation">[fctxclass="token operator">->next_decodingclass="token punctuation">]class="token punctuation">;
    class="token comment">// PerThreadContext是对应线程的上下文࿰c;这是在调用avcodec_open2时候创建的。
    class="token comment">// 这里是把avpkt转移到p->avpkt࿰c;然后触发PerThreadContext的input_cond信号量࿰c;告诉对应的解码线程࿰c;可以开始解码了。
    class="token comment">// 具体的解码实现在pthread_frame.c文件中的frame_worker_thread函数。
    err class="token operator">= class="token function">submit_packetclass="token punctuation">(pclass="token punctuation">, avctxclass="token punctuation">, avpktclass="token punctuation">)class="token punctuation">;
    class="token keyword">if class="token punctuation">(errclass="token punctuation">)
        class="token keyword">goto finishclass="token punctuation">;

    class="token comment">/*
     * If we're still receiving the initial packets, don't return a frame.
     */

    class="token keyword">if class="token punctuation">(fctxclass="token operator">->next_decoding class="token operator">> class="token punctuation">(avctxclass="token operator">->thread_countclass="token operator">-class="token number">1class="token operator">-class="token punctuation">(avctxclass="token operator">->codec_id class="token operator">== AV_CODEC_ID_FFV1class="token punctuation">)class="token punctuation">)class="token punctuation">)
        fctxclass="token operator">->delaying class="token operator">= class="token number">0class="token punctuation">;

    class="token keyword">if class="token punctuation">(fctxclass="token operator">->delayingclass="token punctuation">) class="token punctuation">{
        class="token operator">*got_picture_ptrclass="token operator">=class="token number">0class="token punctuation">;
        class="token keyword">if class="token punctuation">(avpktclass="token operator">->sizeclass="token punctuation">) class="token punctuation">{
            err class="token operator">= avpktclass="token operator">->sizeclass="token punctuation">;
            class="token keyword">goto finishclass="token punctuation">;
        class="token punctuation">}
    class="token punctuation">}

    class="token comment">/*
     * Return the next available frame from the oldest thread.
     * If we're at the end of the stream, then we have to skip threads that
     * didn't output a frame/error, because we don't want to accidentally signal
     * EOF (avpkt->size == 0 && *got_picture_ptr == 0 && err >= 0).
     */

    class="token keyword">do class="token punctuation">{
        p class="token operator">= class="token operator">&fctxclass="token operator">->threadsclass="token punctuation">[finishedclass="token operator">++class="token punctuation">]class="token punctuation">;
		class="token comment">//上面通过调用submit_packet提交AVPacket给解码线程后࿰c;这里就等待output_cond完成
        class="token keyword">if class="token punctuation">(class="token function">atomic_loadclass="token punctuation">(class="token operator">&pclass="token operator">->stateclass="token punctuation">) class="token operator">!= STATE_INPUT_READYclass="token punctuation">) class="token punctuation">{
            class="token function">pthread_mutex_lockclass="token punctuation">(class="token operator">&pclass="token operator">->progress_mutexclass="token punctuation">)class="token punctuation">;
            class="token keyword">while class="token punctuation">(class="token function">atomic_load_explicitclass="token punctuation">(class="token operator">&pclass="token operator">->stateclass="token punctuation">, memory_order_relaxedclass="token punctuation">) class="token operator">!= STATE_INPUT_READYclass="token punctuation">)
                class="token function">pthread_cond_waitclass="token punctuation">(class="token operator">&pclass="token operator">->output_condclass="token punctuation">, class="token operator">&pclass="token operator">->progress_mutexclass="token punctuation">)class="token punctuation">;
            class="token function">pthread_mutex_unlockclass="token punctuation">(class="token operator">&pclass="token operator">->progress_mutexclass="token punctuation">)class="token punctuation">;
        class="token punctuation">}
		class="token comment">//获取解码后的frame࿰c;然后把frame给到picture。
        class="token function">av_frame_move_refclass="token punctuation">(pictureclass="token punctuation">, pclass="token operator">->frameclass="token punctuation">)class="token punctuation">;
        class="token operator">*got_picture_ptr class="token operator">= pclass="token operator">->got_frameclass="token punctuation">;
        pictureclass="token operator">->pkt_dts class="token operator">= pclass="token operator">->avpktclass="token operator">->dtsclass="token punctuation">;
        err class="token operator">= pclass="token operator">->resultclass="token punctuation">;

        class="token comment">/*
         * A later call with avkpt->size == 0 may loop over all threads,
         * including this one, searching for a frame/error to return before being
         * stopped by the "finished != fctx->next_finished" condition.
         * Make sure we don't mistakenly return the same frame/error again.
         */
        pclass="token operator">->got_frame class="token operator">= class="token number">0class="token punctuation">;
        pclass="token operator">->result class="token operator">= class="token number">0class="token punctuation">;

        class="token keyword">if class="token punctuation">(finished class="token operator">>= avctxclass="token operator">->thread_countclass="token punctuation">) finished class="token operator">= class="token number">0class="token punctuation">;
    class="token punctuation">} class="token keyword">while class="token punctuation">(class="token operator">!avpktclass="token operator">->size class="token operator">&& class="token operator">!class="token operator">*got_picture_ptr class="token operator">&& err class="token operator">>= class="token number">0 class="token operator">&& finished class="token operator">!= fctxclass="token operator">->next_finishedclass="token punctuation">)class="token punctuation">;

    class="token function">update_context_from_threadclass="token punctuation">(avctxclass="token punctuation">, pclass="token operator">->avctxclass="token punctuation">, class="token number">1class="token punctuation">)class="token punctuation">;

    class="token keyword">if class="token punctuation">(fctxclass="token operator">->next_decoding class="token operator">>= avctxclass="token operator">->thread_countclass="token punctuation">) fctxclass="token operator">->next_decoding class="token operator">= class="token number">0class="token punctuation">;

    fctxclass="token operator">->next_finished class="token operator">= finishedclass="token punctuation">;

    class="token comment">/* return the size of the consumed packet if no error occurred */
    class="token keyword">if class="token punctuation">(err class="token operator">>= class="token number">0class="token punctuation">)
        err class="token operator">= avpktclass="token operator">->sizeclass="token punctuation">;
finishclass="token operator">:
    class="token function">async_lockclass="token punctuation">(fctxclass="token punctuation">)class="token punctuation">;
    class="token keyword">return errclass="token punctuation">;
class="token punctuation">}

code>

http://www.niftyadmin.cn/n/189406.html

相关文章

UART、RS232 、RS485 区别

UART 、RS232 、RS485 区别 UART、RS232、RS485这些物理层的串口通信&#xff0c;它们都是在同一时间发送一位。 RS232、RS485只是串口通讯的变种&#xff0c;理解了UART串口通讯&#xff0c;那么RS232和RS485也就很好理解了。 了解今天的内容你可能还需要补充下“电平标准”…

Android 通用抓包方式

前言 抓包思路有两种 中间人hook android libssl.so 获取ssl key log 中间人的优势是简单方便&#xff0c;实时。hook的方式优势是原汁原味&#xff08;比如可以看到两端握手的过程&#xff09;。具体选哪一种&#xff0c;根据实际需求决定 中间人 可以利用的工具有pcap r…

C++函数重载

函数重载是指在同一作用域中定义多个名称相同但参数列表不同的函数。函数重载发生在编译时期&#xff0c;编译器在编译代码时会根据函数调用时的实参类型、数量、顺序等信息来选择最匹配的重载函数。 当程序调用一个重载函数时&#xff0c;编译器会首先根据函数名和参数列表的…

VR全景图片,助力VR全景制作,720全景效果图

VR全景图片是指通过全景相机或多相机组合拍摄全景画面&#xff0c;并进行拼接处理生成全景图像的过程。VR全景图片的应用范围广泛&#xff0c;包括旅游和景区、房地产、汽车、艺术和文化、电影和娱乐等领域。本文将详细介绍VR全景图片的类型、应用场景、市场前景和发展趋势。 一…

【洛谷 P1102】A-B 数对 题解(映射)

A-B 数对 题目背景 出题是一件痛苦的事情&#xff01; 相同的题目看多了也会有审美疲劳&#xff0c;于是我舍弃了大家所熟悉的 AB Problem&#xff0c;改用 A-B 了哈哈&#xff01; 题目描述 给出一串正整数数列以及一个正整数 CCC&#xff0c;要求计算出所有满足 A−BCA …

代码随想录算法训练营第五十八天|739.每日温度、496.下一个更大元素Ⅰ

day58 2023/03/30 一、每日温度 请根据每日 气温 列表&#xff0c;重新生成一个列表。对应位置的输出为&#xff1a;要想观测到更高的气温&#xff0c;至少需要等待的天数。如果气温在这之后都不会升高&#xff0c;请在该位置用 0 来代替。 例如&#xff0c;给定一个列表 te…

表规范化过程

数据库的规范化 在介绍多表查询之前&#xff0c;我们先讨论一下产生多表查询的主要原因。图7-1是一张简化了的公司订单。其公司的名字为&#xff1a;天上人间快餐大中华总店。 如何基于这张订单来设计一个关系数据库的表呢&#xff1f;一种最简单的办法是把该订单的所有数据存…

面试官:讲讲vue中的指令、参数、修饰符

指令&#xff08;Directive&#xff09; 在 Vue 中&#xff0c;指令&#xff08;Directive&#xff09;是一种特殊的 HTML 属性&#xff0c;它们的值被绑定到 Vue 实例的数据上&#xff0c;并且在数据发生改变时&#xff0c;它们会自动更新视图。指令以 v- 开头&#xff0c;后…