From adf3e336a31fd2725c580b247faee08636cf0abd Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Thu, 12 Mar 2015 11:07:19 +1100 Subject: [PATCH] Bug 1128381: Part3. Handle on the fly video format change. r=cpearce Add monitoring of the current SPS NAL and destroy/recreate H264 decoder as required. --HG-- extra : rebase_source : fbab04b0ae3b4be42eea34a1c6f1b19bf39ad2f0 --- dom/media/fmp4/AVCCDecoderModule.cpp | 25 +++++++++++++++++-- media/libstagefright/binding/AnnexB.cpp | 8 ++++++ .../binding/include/mp4_demuxer/AnnexB.h | 3 +++ 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/dom/media/fmp4/AVCCDecoderModule.cpp b/dom/media/fmp4/AVCCDecoderModule.cpp index 4d0315b18e51..dead69529faf 100644 --- a/dom/media/fmp4/AVCCDecoderModule.cpp +++ b/dom/media/fmp4/AVCCDecoderModule.cpp @@ -44,6 +44,7 @@ private: // will set mError accordingly. nsresult CreateDecoder(); nsresult CreateDecoderAndInit(mp4_demuxer::MP4Sample* aSample); + nsresult CheckForSPSChange(mp4_demuxer::MP4Sample* aSample); nsRefPtr mPDM; mp4_demuxer::VideoDecoderConfig mCurrentConfig; @@ -92,18 +93,21 @@ AVCCMediaDataDecoder::Input(mp4_demuxer::MP4Sample* aSample) if (!mp4_demuxer::AnnexB::ConvertSampleToAVCC(aSample)) { return NS_ERROR_FAILURE; } + nsresult rv; if (!mDecoder) { // It is not possible to create an AVCC H264 decoder without SPS. // As such, creation will fail if the extra_data just extracted doesn't // contain a SPS. - nsresult rv = CreateDecoderAndInit(aSample); + rv = CreateDecoderAndInit(aSample); if (rv == NS_ERROR_NOT_INITIALIZED) { // We are missing the required SPS to create the decoder. // Ignore for the time being, the MP4Sample will be dropped. return NS_OK; } - NS_ENSURE_SUCCESS(rv, rv); + } else { + rv = CheckForSPSChange(aSample); } + NS_ENSURE_SUCCESS(rv, rv); aSample->extra_data = mCurrentConfig.extra_data; @@ -230,6 +234,23 @@ AVCCMediaDataDecoder::IsHardwareAccelerated() const return MediaDataDecoder::IsHardwareAccelerated(); } +nsresult +AVCCMediaDataDecoder::CheckForSPSChange(mp4_demuxer::MP4Sample* aSample) +{ + nsRefPtr extra_data = + mp4_demuxer::AnnexB::ExtractExtraData(aSample); + if (!mp4_demuxer::AnnexB::HasSPS(extra_data) || + mp4_demuxer::AnnexB::CompareExtraData(extra_data, + mCurrentConfig.extra_data)) { + return NS_OK; + } + // The SPS has changed, signal to flush the current decoder and create a + // new one. + mDecoder->Flush(); + mDecoder->Shutdown(); + return CreateDecoderAndInit(aSample); +} + // AVCCDecoderModule AVCCDecoderModule::AVCCDecoderModule(PlatformDecoderModule* aPDM) diff --git a/media/libstagefright/binding/AnnexB.cpp b/media/libstagefright/binding/AnnexB.cpp index 0a88e5092aa6..64f1cfcce2bc 100644 --- a/media/libstagefright/binding/AnnexB.cpp +++ b/media/libstagefright/binding/AnnexB.cpp @@ -378,4 +378,12 @@ AnnexB::IsAnnexB(const MP4Sample* aSample) return header == 0x00000001 || (header >> 8) == 0x000001; } +bool +AnnexB::CompareExtraData(const ByteBuffer* aExtraData1, + const ByteBuffer* aExtraData2) +{ + // Very crude comparison. + return aExtraData1 == aExtraData2 || *aExtraData1 == *aExtraData2; +} + } // namespace mp4_demuxer diff --git a/media/libstagefright/binding/include/mp4_demuxer/AnnexB.h b/media/libstagefright/binding/include/mp4_demuxer/AnnexB.h index 5a4968ddd57c..0a8d6ede6308 100644 --- a/media/libstagefright/binding/include/mp4_demuxer/AnnexB.h +++ b/media/libstagefright/binding/include/mp4_demuxer/AnnexB.h @@ -39,6 +39,9 @@ public: static bool IsAVCC(const MP4Sample* aSample); // Returns true if format is AnnexB. static bool IsAnnexB(const MP4Sample* aSample); + // Return true if both extradata are equal. + static bool CompareExtraData(const ByteBuffer* aExtraData1, + const ByteBuffer* aExtraData2); private: // AVCC box parser helper.