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