[FFmpeg-trac] #9650(avcodec:new): h264_qsv DECODER eventually freezes after many seeks [WINDOWS]

FFmpeg trac at avcodec.org
Wed Feb 16 12:22:21 EET 2022


#9650: h264_qsv DECODER eventually freezes after many seeks [WINDOWS]
-------------------------------------+-------------------------------------
             Reporter:  teslan       |                     Type:  defect
               Status:  new          |                 Priority:  normal
            Component:  avcodec      |                  Version:  git-
             Keywords:  qsv, intel   |  master
  media sdk,                         |               Blocked By:
             Blocking:               |  Reproduced by developer:  0
Analyzed by developer:  0            |
-------------------------------------+-------------------------------------
 Summary of the bug:
 The h264_qsv decoder freezes after random number of seeks with flushes
 (most of the times you need max 100 seeks). Does not happen when standard
 h264 or h264_cuvid decoder is used.

 Note that this might be a bug not in FFMPEG, but in Intel Media SDK.
 I am not sure on which grave should I cry, but because there are
 developers from Intel actively enhancing the QSV support, i'll describe
 the issue both here and at Intel Media SDK github.

 Tested with both Windows-provided libmfxhw64.dll (File Version 11.21.4.14)
 and from the latest driver (File Version 21.11.3.320)

 This is the debug call stack on my decoding thread when the freeze
 happens:

 1  ZwWaitForAlertByThreadId
 ntdll                       0x7fff7a530764
 2  RtlSleepConditionVariableSRW
 ntdll                       0x7fff7a4f4021
 3  SleepConditionVariableSRW
 KERNELBASE                  0x7fff77ecce89
 4  MFXVideoVPP_GetVPPStat
 libmfxhw64                  0x7fff027ef8cc
 5  MFXVideoVPP_GetVPPStat
 libmfxhw64                  0x7fff027ec7f4
 6  MFXVideoVPP_GetVPPStat
 libmfxhw64                  0x7fff027ec69f
 7  MFXVideoVPP_GetVPPStat
 libmfxhw64                  0x7fff023575b0
 8  MFXVideoCORE_SyncOperation
 libmfxhw64                  0x7fff02337a4d
 9  av_qsv_alloc_context
 avcodec_59                  0x7fff10eb4c06
 10 av_qsv_alloc_context
 avcodec_59                  0x7fff10eb573d
 11 av_qsv_alloc_context
 avcodec_59                  0x7fff10eb59c7
 12 avcodec_default_get_buffer2
 avcodec_59                  0x7fff10a9f9b1
 13 avcodec_send_packet
 avcodec_59                  0x7fff10aa0590
 14 libavDecoder::playLoopPrivate
 libavdecoder.cpp   724      0x7ff78094f6da

 I am using FFMPEG builds from BtbN - confirmed with the latest master
 update (2022-02-15 12:35)

 How to reproduce:
 You need to flush the decoder and seek the video many times. Then after
 some decoded frames the decoder freezes. These are important excerpts from
 my code to hint how am I using it:

 Seek:
 {{{
 ...........................
 err = av_seek_frame(m.fmtctx, m.videoStream, [random-pts-in-media], 0);
         if(err != 0) {
                 av_strerror(err, errbuff, 256);
                 std::cerr << "Error Seeking. AVERROR: " << errbuff  <<
 std::endl;
         }

         ptsToFind = referencePts;
         seekMode = true;
         seekModeKeyframeFound = false;
         seekModeFlushed = false;

 .........................
 }}}
 Read&decode:

 {{{
 ...........................
  //Reads the right amount of data from stream
         err = av_read_frame(m.fmtctx, pPacket);
         if(err < 0) {
             av_strerror(err, errbuff, 256);
             std::cerr << "AV READ FRAME error or EOF " << errbuff << " "
 << m.lastPts[m.videoStream] << std::endl;
             if(err == AVERROR_EOF) {
                 emit endOfFile(m.lastPts[m.videoStream]);
             }
             av_packet_unref(pPacket);
             break;
         }

         //If we are seeking, flush the codec and reset the GOP counter (as
 we automatically found nearest I frame)
         if(seekMode) {

             if(!seekModeFlushed) {
                 if(!(pPacket->flags & AV_PKT_FLAG_KEY)){
                     av_packet_unref(pPacket);
                     continue;
                 }
                 avcodec_send_packet(avcc, NULL); //flush
                 avcodec_flush_buffers(avcc);
                 actual_gop_counter = 0;
                 seekModeFlushed = true;
             }
         }

         //Send the "right amount of data" to the decoder
         err = avcodec_send_packet(avcc, pPacket);
         if(err != 0) {
             av_strerror(err, errbuff, 256);
             std::cerr << "Error sending packet. AVERROR: " << errbuff <<
 std::endl;
             av_packet_unref(pPacket);
             continue;
         }


         //Gather first ready frame from the internal queue
         err = avcodec_receive_frame(avcc, pFrame);
         if(err != 0) {
             if(err != AVERROR(EAGAIN)) { //resource can be unavailable
 pretty often, do not write out anything in such case
                 av_strerror(err, errbuff, 256);
                 std::cerr << "Error receiving frame. AVERROR: " << errbuff
 << std::endl;
             }
             av_packet_unref(pPacket);
             av_frame_unref(pFrame);
             continue;
         }

         //Save data for average GOP computation
         if(pFrame->pict_type == AV_PICTURE_TYPE_I && actual_gop_counter !=
 0) {
             if(actual_gop_counter > max_gop) {
                 max_gop = actual_gop_counter;
             }
             actual_gop_counter = 0;
         }
         ++actual_gop_counter;

         if(seekMode) {
             if(pFrame->pts >= ptsToFind && pFrame->pts <= ptsToFind +
 avg_pts*MAX_ALLOWED_SKIP_FRAMES) {
                 seekMode = false;
                 //Because QSV is a fucked-up decoder, it always returns
 exactly TWO frames from the previous
                 //decoding chunk. And you can not flush it, it will only
 return them after you provide
                 //two fresh packets. Really fucked-up. Really. Therefore
 we can not stay with
                 //the check that if the pts is already the same or greater
 that the one we need to find.
                 //We also have to introduce if it is not too far away.
 That is defined in MAX_ALLOWED_SKIP_FRAMES
             }
             else {
                 av_frame_unref(pFrame);
                 av_packet_unref(pPacket);
                 continue; //do not proceed if still in seek
             }
         }

 .............................
 }}}





 Patches should be submitted to the ffmpeg-devel mailing list and not this
 bug tracker.
-- 
Ticket URL: <https://trac.ffmpeg.org/ticket/9650>
FFmpeg <https://ffmpeg.org>
FFmpeg issue tracker


More information about the FFmpeg-trac mailing list