2015-07-20 26 views
1

下面的代碼片段是ffplay如何理解給定的ffplay C代碼片段?

static int decoder_decode_frame(Decoder *d, AVFrame *frame, AVSubtitle *sub) { 
    int got_frame = 0; 

    do { 
     int ret = -1; 

     if (d->queue->abort_request) 
      return -1; 

     if (!d->packet_pending || d->queue->serial != d->pkt_serial) { 
      AVPacket pkt; 
      do { 
       if (d->queue->nb_packets == 0) 
        SDL_CondSignal(d->empty_queue_cond); 
       if (packet_queue_get(d->queue, &pkt, 1, &d->pkt_serial) < 0) 
        return -1; 
       if (pkt.data == flush_pkt.data) { 
        avcodec_flush_buffers(d->avctx); 
        d->finished = 0; 
        d->next_pts = d->start_pts; 
        d->next_pts_tb = d->start_pts_tb; 
       } 
      } while (pkt.data == flush_pkt.data || d->queue->serial != d->pkt_serial); 
      av_free_packet(&d->pkt); 
      d->pkt_temp = d->pkt = pkt; 
      d->packet_pending = 1; 
     } 

     switch (d->avctx->codec_type) { 
      case AVMEDIA_TYPE_VIDEO: 
       ret = avcodec_decode_video2(d->avctx, frame, &got_frame, &d->pkt_temp); 
       if (got_frame) { 
        if (decoder_reorder_pts == -1) { 
         frame->pts = av_frame_get_best_effort_timestamp(frame); 
        } else if (decoder_reorder_pts) { 
         frame->pts = frame->pkt_pts; 
        } else { 
         frame->pts = frame->pkt_dts; 
        } 
       } 
       break; 
      case AVMEDIA_TYPE_AUDIO: 
       ret = avcodec_decode_audio4(d->avctx, frame, &got_frame, &d->pkt_temp); 
       if (got_frame) { 
        AVRational tb = (AVRational){1, frame->sample_rate}; 
        if (frame->pts != AV_NOPTS_VALUE) 
         frame->pts = av_rescale_q(frame->pts, d->avctx->time_base, tb); 
        else if (frame->pkt_pts != AV_NOPTS_VALUE) 
         frame->pts = av_rescale_q(frame->pkt_pts, av_codec_get_pkt_timebase(d->avctx), tb); 
        else if (d->next_pts != AV_NOPTS_VALUE) 
         frame->pts = av_rescale_q(d->next_pts, d->next_pts_tb, tb); 
        if (frame->pts != AV_NOPTS_VALUE) { 
         d->next_pts = frame->pts + frame->nb_samples; 
         d->next_pts_tb = tb; 
        } 
       } 
       break; 
      case AVMEDIA_TYPE_SUBTITLE: 
       ret = avcodec_decode_subtitle2(d->avctx, sub, &got_frame, &d->pkt_temp); 
       break; 
     } 

     if (ret < 0) { 
      d->packet_pending = 0; 
     } else { 
      d->pkt_temp.dts = 
      d->pkt_temp.pts = AV_NOPTS_VALUE; 
      if (d->pkt_temp.data) { 
       if (d->avctx->codec_type != AVMEDIA_TYPE_AUDIO) 
        ret = d->pkt_temp.size; 
       d->pkt_temp.data += ret; 
       d->pkt_temp.size -= ret; 
       if (d->pkt_temp.size <= 0) 
        d->packet_pending = 0; 
      } else { 
       if (!got_frame) { 
        d->packet_pending = 0; 
        d->finished = d->pkt_serial; // FLAG 
       } 
      } 
     } 
    } while (!got_frame && !d->finished); 

    return got_frame; 
} 

這是我很難理解下面的代碼:

d->finished = d->pkt_serial; // FLAG 

誰能幫助我?

謝謝。

回答

1

請參閱this提交。

串口目前有兩個目的:提交的初始目的是能夠區分數據包隊列中的數據包與查找前後的數據包。分路器(分組隊列的輸入)在單獨的線程中運行。在尋求之後,我們想要刷新它,但是我們不想停止生產者線程,因爲開銷太大。但是,我們也不想刷新太多或太多的數據包。因此,串行字段告訴我們哪些數據包是預先刷新和後刷新的,從而在丟棄那些數據包時不必停止生產者線程而丟棄哪些數據包。

第二個目的是您的代碼行:它告訴我們何時發生EOF。 Finished被設置爲來自用於解碼幀的分組隊列的分組的最後一個序列號。如果該序列號也是分組隊列的尾部(並且不再生成分組),這意味着我們停止生成分組對屬於該分組的幀進行解碼。換句話說:文件結束。在其他地方,你會發現沿着這些線路進行測試,然後播放停止或(如果啓用循環),我們回到文件的開頭(即調用循環行爲)。

(該寫了被有益由幾個FFmpeg的開發上IRC輔助)

+0

我發現了一個問題,'D->成品= D-> pkt_serial; // FLAG'已在連接音頻流時執行。明顯不是EOF。更重要的是,我啓用了設置:'fflags -nobuffer'。所以我對此感到困惑。 –

+0

完成不斷更新,我想你的意思是緩衝區是空的,但尚未完成。這可能確實是一個錯誤,並將值得上游的錯誤報告:https://www.ffmpeg.org/bugreports.html –

+0

是的,這就是我的意思。謝謝。 –