[haiku-commits] haiku: hrev47624 - src/add-ons/media/plugins/ffmpeg

  • From: coling@xxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Mon, 4 Aug 2014 18:39:30 +0200 (CEST)

hrev47624 adds 1 changeset to branch 'master'
old head: 09785ce274ca9f989c51e6dfd29119bdc095c614
new head: a335ec823a394d84383d652630d13135e4338a56
overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=a335ec8+%5E09785ce

----------------------------------------------------------------------------

a335ec8: FFMPEG Plugin: Implement flushing of video frames from decoder.
  
  - Video frames still contained in the video decoder are now flushed when there
    are no encoded data chunks left (signaled by B_LAST_BUFFER_ERROR).
  - New code was successfully tested with mpeg2_decoder_test. The last test 
image
    is now decoded, too, resulting in a bump of the expected number of decoded
    images.
  - Refactor code to support flushing -and- keep the readability at a sane 
level.
  - Remove some uncommented code for the sake of readability.
  - Documentation updated accordingly.

                                           [ Colin Günther <coling@xxxxxx> ]

----------------------------------------------------------------------------

Revision:    hrev47624
Commit:      a335ec823a394d84383d652630d13135e4338a56
URL:         http://cgit.haiku-os.org/haiku/commit/?id=a335ec8
Author:      Colin Günther <coling@xxxxxx>
Date:        Mon Aug  4 16:15:02 2014 UTC

----------------------------------------------------------------------------

3 files changed, 115 insertions(+), 64 deletions(-)
.../media/plugins/ffmpeg/AVCodecDecoder.cpp      | 175 ++++++++++++-------
.../media/plugins/ffmpeg/AVCodecDecoder.h        |   2 +
.../mpeg2_decoder_test/mpeg2_decoder_test.cpp    |   2 +-

----------------------------------------------------------------------------

diff --git a/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.cpp 
b/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.cpp
index 437c79f..bef2586 100644
--- a/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.cpp
+++ b/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.cpp
@@ -735,10 +735,17 @@ AVCodecDecoder::_DecodeNextVideoFrame()
                        // Our packet buffer is empty, so fill it now.
                        status_t getNextChunkStatus = 
GetNextChunk(&fChunkBuffer,
                                &fChunkBufferSize, &chunkMediaHeader);
-                       if (getNextChunkStatus != B_OK) {
-                               TRACE("AVCodecDecoder::_DecodeNextVideoFrame(): 
error from "
-                                       "GetNextChunk(): %s\n", strerror(err));
-                               return getNextChunkStatus;
+                       switch (getNextChunkStatus) {
+                               case B_OK:
+                                       break;
+
+                               case B_LAST_BUFFER_ERROR:
+                                       return 
_FlushOneVideoFrameFromDecoderBuffer();
+
+                               default:
+                                       
TRACE("AVCodecDecoder::_DecodeNextVideoFrame(): error from "
+                                               "GetNextChunk(): %s\n", 
strerror(err));
+                                       return getNextChunkStatus;
                        }
 
                        fTempPacket.data = 
static_cast<uint8_t*>(const_cast<void*>(
@@ -807,75 +814,117 @@ AVCodecDecoder::_DecodeNextVideoFrame()
                fTempPacket.size -= decodedDataSizeInBytes;
                fTempPacket.data += decodedDataSizeInBytes;
 
-//TRACE("FFDEC: PTS = %d:%d:%d.%d - fContext->frame_number = %ld "
-//     "fContext->frame_rate = %ld\n", (int)(fContext->pts / (60*60*1000000)),
-//     (int)(fContext->pts / (60*1000000)), (int)(fContext->pts / (1000000)),
-//     (int)(fContext->pts % 1000000), fContext->frame_number,
-//     fContext->frame_rate);
-//TRACE("FFDEC: PTS = %d:%d:%d.%d - fContext->frame_number = %ld "
-//     "fContext->frame_rate = %ld\n",
-//     (int)(fRawDecodedPicture->pts / (60*60*1000000)),
-//     (int)(fRawDecodedPicture->pts / (60*1000000)),
-//     (int)(fRawDecodedPicture->pts / (1000000)),
-//     (int)(fRawDecodedPicture->pts % 1000000), fContext->frame_number,
-//     fContext->frame_rate);
-
-               if (gotPicture) {
+               bool gotNoPictureYet = gotPicture == 0;
+               if (gotNoPictureYet) {
+                       TRACE("frame %lld - no picture yet, 
decodedDataSizeInBytes: %d, "
+                               "chunk size: %ld\n", fFrame, 
decodedDataSizeInBytes,
+                               fChunkBufferSize);
+                       continue;
+               }
+
 #if DO_PROFILING
-                       bigtime_t formatConversionStart = system_time();
+               bigtime_t formatConversionStart = system_time();
+#endif
+
+               _HandleNewVideoFrameAndUpdateSystemState();
+
+#if DO_PROFILING
+               bigtime_t doneTime = system_time();
+               decodingTime += formatConversionStart - startTime;
+               conversionTime += doneTime - formatConversionStart;
+               profileCounter++;
+               if (!(fFrame % 5)) {
+                       if (info) {
+                               printf("[v] profile: d1 = %lld, d2 = %lld 
(%lld) required "
+                                       "%Ld\n",
+                                       decodingTime / profileCounter,
+                                       conversionTime / profileCounter,
+                                       fFrame, info->time_to_decode);
+                       } else {
+                               printf("[v] profile: d1 = %lld, d2 = %lld 
(%lld) required "
+                                       "%Ld\n",
+                                       decodingTime / profileCounter,
+                                       conversionTime / profileCounter,
+                                       fFrame, bigtime_t(1000000LL / 
fOutputFrameRate));
+                       }
+                       decodingTime = 0;
+                       conversionTime = 0;
+                       profileCounter = 0;
+               }
 #endif
-//                     TRACE("ONE FRAME OUT !! len=%d size=%ld (%s)\n", len, 
size,
-//                             pixfmt_to_string(fContext->pix_fmt));
+               return B_OK;
+       }
+}
+
 
-                       _UpdateMediaHeaderForVideoFrame();
-                       _DeinterlaceAndColorConvertVideoFrame();
+/*! \brief Executes all steps needed for a freshly decoded video frame.
 
-                       ConvertAVCodecContextToVideoFrameRate(*fContext, 
fOutputFrameRate);
+       \see _UpdateMediaHeaderForVideoFrame() and
+       \see _DeinterlaceAndColorConvertVideoFrame() for when you are allowed to
+       call this method.
+*/
+void
+AVCodecDecoder::_HandleNewVideoFrameAndUpdateSystemState()
+{
+       _UpdateMediaHeaderForVideoFrame();
+       _DeinterlaceAndColorConvertVideoFrame();
+
+       ConvertAVCodecContextToVideoFrameRate(*fContext, fOutputFrameRate);
 
 #ifdef DEBUG
-                       dump_ffframe(fRawDecodedPicture, "ffpict");
-//                     dump_ffframe(fPostProcessedDecodedPicture, "opict");
+       dump_ffframe(fRawDecodedPicture, "ffpict");
+//     dump_ffframe(fPostProcessedDecodedPicture, "opict");
 #endif
-                       fFrame++;
+       fFrame++;
+}
 
-#if DO_PROFILING
-                       bigtime_t doneTime = system_time();
-                       decodingTime += formatConversionStart - startTime;
-                       conversionTime += doneTime - formatConversionStart;
-                       profileCounter++;
-                       if (!(fFrame % 5)) {
-                               if (info) {
-                                       printf("[v] profile: d1 = %lld, d2 = 
%lld (%lld) required "
-                                               "%Ld\n",
-                                               decodingTime / profileCounter,
-                                               conversionTime / profileCounter,
-                                               fFrame, info->time_to_decode);
-                               } else {
-                                       printf("[v] profile: d1 = %lld, d2 = 
%lld (%lld) required "
-                                               "%Ld\n",
-                                               decodingTime / profileCounter,
-                                               conversionTime / profileCounter,
-                                               fFrame, bigtime_t(1000000LL / 
fOutputFrameRate));
-                               }
-                               decodingTime = 0;
-                               conversionTime = 0;
-                               profileCounter = 0;
-                       }
-#endif
-                       return B_OK;
-               } else {
-                       TRACE("frame %lld - no picture yet, len: %d, chunk 
size: %ld\n",
-                               fFrame, len, size);
-               }
+
+/*! \brief Flushes one video frame - if any - still buffered by the decoder.
+
+       Some FFMPEG decoder are buffering video frames. To retrieve those 
buffered
+       frames the decoder needs to be told so.
+
+       The intended use of this method is to call it, once there are no more 
data
+       chunks for decoding left. Reframed in other words: Once GetNextChunk()
+       returns with status B_LAST_BUFFER_ERROR it is time to start flushing.
+
+       \returns B_OK Retrieved one video frame, handled it accordingly and 
updated
+               the system state accordingly.
+               There maybe more video frames left. So it is valid for the 
client of
+               AVCodecDecoder to call it one more time.
+
+       \returns B_LAST_BUFFER_ERROR No video frame left.
+               The client of the AVCodecDecoder should stop calling it now.
+*/
+status_t
+AVCodecDecoder::_FlushOneVideoFrameFromDecoderBuffer()
+{
+       // Create empty fTempPacket to tell the video decoder it is time to 
flush
+       fTempPacket.data = NULL;
+       fTempPacket.size = 0;
+
+       int gotPicture = 0;
+       avcodec_decode_video2(fContext, fRawDecodedPicture, &gotPicture,
+               &fTempPacket);
+               // We are only interested in complete frames now, so ignore the 
return
+               // value.
+
+       if (gotPicture == 0) {
+               // video buffer is flushed successfully
+               return B_LAST_BUFFER_ERROR;
        }
+
+       _HandleNewVideoFrameAndUpdateSystemState();
+
+       return B_OK;
 }
 
 
 /*! \brief Updates relevant fields of the class member fHeader with the
                properties of the most recently decoded video frame.
 
-       It is assumed that this function is called in _DecodeNextVideoFrame() 
only
-       when the following asserts hold true:
+       It is assumed that this function is called only when the following 
asserts
+       hold true:
                1. We actually got a new picture decoded by the video decoder.
                2. fHeader wasn't updated for the new picture yet. You MUST 
call this
                   method only once per decoded video frame.
@@ -920,15 +969,15 @@ AVCodecDecoder::_UpdateMediaHeaderForVideoFrame()
 }
 
 
-/*! \brief This function applies deinterlacing (only if needed) and color 
conversion
-    to the video frame in fRawDecodedPicture.
+/*! \brief This function applies deinterlacing (only if needed) and color
+       conversion to the video frame in fRawDecodedPicture.
 
        It is assumed that fRawDecodedPicture wasn't deinterlaced and color
        converted yet (otherwise this function behaves in unknown manners).
 
-       You should only call this function in _DecodeNextVideoFrame() when we
-       got a new picture decoded by the video decoder and the fHeader variable 
was
-       updated accordingly (@see _UpdateMediaHeaderForVideoFrame()).
+       You should only call this function when you     got a new picture 
decoded by
+       the video decoder and the fHeader variable was updated accordingly (\see
+       _UpdateMediaHeaderForVideoFrame()).
 
        When this function finishes the postprocessed video frame will be 
available
        in fPostProcessedDecodedPicture and fDecodedData 
(fDecodedDataSizeInBytes
diff --git a/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.h 
b/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.h
index 25de738..13e0bc2 100644
--- a/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.h
+++ b/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.h
@@ -66,6 +66,8 @@ private:
                                                                        
media_header* mediaHeader,
                                                                        
media_decode_info* info);
                        status_t                        _DecodeNextVideoFrame();
+                       void                            
_HandleNewVideoFrameAndUpdateSystemState();
+                       status_t                        
_FlushOneVideoFrameFromDecoderBuffer();
                        void                            
_UpdateMediaHeaderForVideoFrame();
                        void                            
_DeinterlaceAndColorConvertVideoFrame();
 
diff --git a/src/tests/kits/media/mpeg2_decoder_test/mpeg2_decoder_test.cpp 
b/src/tests/kits/media/mpeg2_decoder_test/mpeg2_decoder_test.cpp
index 65bf9fc..fe9df4a 100644
--- a/src/tests/kits/media/mpeg2_decoder_test/mpeg2_decoder_test.cpp
+++ b/src/tests/kits/media/mpeg2_decoder_test/mpeg2_decoder_test.cpp
@@ -19,7 +19,7 @@
        Successful completion of this test results in a series of PNG image
        files created at the same location you start the test from.
 
-       The originally included test file results in 84 PNG images,
+       The originally included test file results in 85 PNG images,
        representing a movie sequence with the actress Anne Hathaway.
        This test file has the following properties:
                - The first frames cannot be decoded, due to missing I-Frames


Other related posts:

  • » [haiku-commits] haiku: hrev47624 - src/add-ons/media/plugins/ffmpeg - coling