關於ffmpeg(libav)解碼視頻最後丟幀的問題

來源:互聯網
上載者:User

標籤:style   blog   http   color   io   使用   ar   檔案   2014   

    其實最初不是為瞭解決這個問題而來的,是Peter兄給我的提示解決另一個問題卻讓我誤打誤撞解決了另外一個問題之後也把這個隱藏了很久的bug找到(之前總是有一些特別短的視頻產生不知所措還以為是視頻素材本身有問題呢),今天真是收穫頗豐啊,對libav的理解更深。

    一直以來我的程式架構是讓讀一幀av_read_frame,然後去嘗試根據packet的type類型分別去decode video或者audio,然而這樣總是在視頻的結尾會有許多幀丟失的問題,我找過avplay代碼中似乎沒找到我想象中的那種讀packet完畢後特殊處理的代碼。

一下log是我設定將其avcodec_decode_video2函數調用前後輸出的pts、dts值(註:Frame:為decode之後,測試視頻為純視頻無音訊檔案),可以看出來,開頭為了順序正確,libav暫存了9個packet,讀packet完畢後,我當然不能就直接不管了,還是要將libav暫存的那些幀取出來才行。


    綜上幾點我認為是在調用avcodec_decode_video2函數的時候,函數內會去發現這個packet尚不足以解碼下一幀的時候就會暫存packet在內部隊列中(我自己給他們取的名字,望能理解),這樣問題就來了,等到整個視頻檔案都讀取完了,剩下libav內部存的packet還有一大堆沒處理,我的架構又是要求函數直接向視頻索取一幀,因此就需要在讀新packet完畢後還 單獨調用decode video函數或者decode audio函數來取出剩餘的AVFrame。

為了這些bug我破例無恥的使用了goto語句:

首先定義了類成員變數,初始化都為false:

bool            _no_packet;   //代表是否還有packetbool            _end_video_frame;   //代表是否video中的隊列取出完畢bool            _end_audio_frame;   //代表是否audio中的隊列取出完畢
AVPacket packet = {0};while(true){        auto auto_releaser = std::shared_ptr<AVPacket>(&packet, [](AVPacket* p) { av_free_packet(p); });        int ret = av_read_frame(_context.get(), &packet);        if ( ret != 0)        {            _no_packet = true;            if(!_end_video_frame)                goto loop_end_video;            if(!_end_audio_frame)                goto loop_end_audio;            if(_end_video_frame && _end_audio_frame)                return false;        }        if(packet.stream_index == vstream_index)        {loop_end_video:            int frame_finished = true;            if(avcodec_decode_video2(_vcodec, _decoded_frame, &frame_finished, &packet) < 0)             {// 。。。。do something。。。             }             if(frame_finished)             {//。。。。do something。。。             }             else             {                if(_no_packet)                    _end_video_frame = true;            }       }       else if (packet.stream_index == astream_index && (type & MEDIA_AUDIO) != 0)        {            loop_end_audio:            int frame_finished;            if (avcodec_decode_audio4(_acodec, _decoded_frame, &frame_finished, &packet) < 0)             {// 。。。。do something。。。             }             if(frame_finished)             {//。。。。do something。。。             }             else             {                if(_no_packet)                    _end_audio_frame = true;            }       }}

有了這些跳轉,就能完美的在read_frame完之後還繼續decode為我所用。希望能協助到與我遇到了相同問題的人。

再次感謝Peter~

關於ffmpeg(libav)解碼視頻最後丟幀的問題

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.