Bug 1299105 - Part1 - Check if the decoder support recycling to prevent from recreating decoder.
MozReview-Commit-ID: 7Xj6tSnGM81
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -259,16 +259,20 @@ public:
const char* GetDescriptionName() const override
{
return mDecoder->GetDescriptionName();
}
void SetSeekThreshold(const media::TimeUnit& aTime) override
{
mDecoder->SetSeekThreshold(aTime);
}
+ bool SupportDecoderRecycling() const override
+ {
+ return mDecoder->SupportDecoderRecycling();
+ }
void Shutdown() override
{
mDecoder->Shutdown();
mDecoder = nullptr;
mToken = nullptr;
}
private:
@@ -1297,39 +1301,48 @@ MediaFormatReader::HandleDemuxedSamples(
RefPtr<SharedTrackInfo> info = sample->mTrackInfo;
if (info && decoder.mLastStreamSourceID != info->GetID()) {
if (samplesPending) {
// Let existing samples complete their decoding. We'll resume later.
return;
}
+ bool supportRecycling = decoder.mDecoder->SupportDecoderRecycling();
if (decoder.mNextStreamSourceID.isNothing() ||
decoder.mNextStreamSourceID.ref() != info->GetID()) {
- LOG("%s stream id has changed from:%d to:%d, draining decoder.",
+ if (!supportRecycling) {
+ LOG("%s stream id has changed from:%d to:%d, draining decoder.",
TrackTypeToStr(aTrack), decoder.mLastStreamSourceID,
info->GetID());
- decoder.mNeedDraining = true;
- decoder.mNextStreamSourceID = Some(info->GetID());
- ScheduleUpdate(aTrack);
- return;
+ decoder.mNeedDraining = true;
+ decoder.mNextStreamSourceID = Some(info->GetID());
+ ScheduleUpdate(aTrack);
+ return;
+ }
}
- LOG("%s stream id has changed from:%d to:%d, recreating decoder.",
+ LOG("%s stream id has changed from:%d to:%d.",
TrackTypeToStr(aTrack), decoder.mLastStreamSourceID,
info->GetID());
decoder.mLastStreamSourceID = info->GetID();
decoder.mNextStreamSourceID.reset();
- // Reset will clear our array of queued samples. So make a copy now.
- nsTArray<RefPtr<MediaRawData>> samples{decoder.mQueuedSamples};
- Reset(aTrack);
- decoder.ShutdownDecoder();
+ if (!supportRecycling) {
+ LOG("Decoder does not support recycling, recreate decoder.");
+ // Reset will clear our array of queued samples. So make a copy now.
+ nsTArray<RefPtr<MediaRawData>> samples{decoder.mQueuedSamples};
+ Reset(aTrack);
+ decoder.ShutdownDecoder();
+ if (sample->mKeyframe) {
+ decoder.mQueuedSamples.AppendElements(Move(samples));
+ }
+ }
+
decoder.mInfo = info;
if (sample->mKeyframe) {
- decoder.mQueuedSamples.AppendElements(Move(samples));
ScheduleUpdate(aTrack);
} else {
TimeInterval time =
TimeInterval(TimeUnit::FromMicroseconds(sample->mTime),
TimeUnit::FromMicroseconds(sample->GetEndTime()));
InternalSeekTarget seekTarget =
decoder.mTimeThreshold.refOr(InternalSeekTarget(time, false));
LOG("Stream change occurred on a non-keyframe. Seeking to:%lld",
--- a/dom/media/platforms/PlatformDecoderModule.h
+++ b/dom/media/platforms/PlatformDecoderModule.h
@@ -292,13 +292,19 @@ public:
// Set a hint of seek target time to decoder. Decoder will drop any decoded
// data which pts is smaller than this value. This threshold needs to be clear
// after reset decoder.
// Decoder may not honor this value. However, it'd be better that
// video decoder implements this API to improve seek performance.
// Note: it should be called before Input() or after Flush().
virtual void SetSeekThreshold(const media::TimeUnit& aTime) {}
+
+ // When playing adaptive playback, recreating an Android video decoder will
+ // cause the transition not smooth during resolution change.
+ // Reuse the decoder if the decoder support recycling.
+ // Currently, only Android video decoder will return true.
+ virtual bool SupportDecoderRecycling() const { return false; }
};
} // namespace mozilla
#endif
--- a/dom/media/platforms/android/MediaCodecDataDecoder.cpp
+++ b/dom/media/platforms/android/MediaCodecDataDecoder.cpp
@@ -118,16 +118,18 @@ public:
presentationTimeUs,
gfx::IntRect(0, 0,
mConfig.mDisplay.width,
mConfig.mDisplay.height));
INVOKE_CALLBACK(Output, v);
return NS_OK;
}
+ bool SupportDecoderRecycling() const override { return true; }
+
protected:
layers::ImageContainer* mImageContainer;
const VideoInfo& mConfig;
RefPtr<AndroidSurfaceTexture> mSurfaceTexture;
RefPtr<SamplesWaitingForKey> mSamplesWaitingForKey;
};
--- a/dom/media/platforms/android/RemoteDataDecoder.cpp
+++ b/dom/media/platforms/android/RemoteDataDecoder.cpp
@@ -240,16 +240,18 @@ public:
}
void Input(MediaRawData* aSample) override
{
RemoteDataDecoder::Input(aSample);
mInputDurations.Put(aSample->mDuration);
}
+ bool SupportDecoderRecycling() const override { return true; }
+
private:
class DurationQueue {
public:
void Clear()
{
mValues.clear();
}
--- a/dom/media/platforms/wrappers/H264Converter.cpp
+++ b/dom/media/platforms/wrappers/H264Converter.cpp
@@ -280,16 +280,23 @@ H264Converter::CheckForSPSChange(MediaRa
{
RefPtr<MediaByteBuffer> extra_data =
mp4_demuxer::AnnexB::ExtractExtraData(aSample);
if (!mp4_demuxer::AnnexB::HasSPS(extra_data) ||
mp4_demuxer::AnnexB::CompareExtraData(extra_data,
mCurrentConfig.mExtraData)) {
return NS_OK;
}
+
+ if (mDecoder->SupportDecoderRecycling()) {
+ // Do not recreate the decoder, reuse it.
+ UpdateConfigFromExtraData(extra_data);
+ mNeedKeyframe = true;
+ return NS_OK;
+ }
// The SPS has changed, signal to flush the current decoder and create a
// new one.
mDecoder->Flush();
Shutdown();
return CreateDecoderAndInit(aSample);
}
void
--- a/dom/media/platforms/wrappers/H264Converter.h
+++ b/dom/media/platforms/wrappers/H264Converter.h
@@ -34,16 +34,23 @@ public:
const char* GetDescriptionName() const override
{
if (mDecoder) {
return mDecoder->GetDescriptionName();
}
return "H264Converter decoder (pending)";
}
void SetSeekThreshold(const media::TimeUnit& aTime) override;
+ bool SupportDecoderRecycling() const override
+ {
+ if (mDecoder) {
+ return mDecoder->SupportDecoderRecycling();
+ }
+ return false;
+ }
nsresult GetLastError() const { return mLastError; }
private:
// Will create the required MediaDataDecoder if need AVCC and we have a SPS NAL.
// Returns NS_ERROR_FAILURE if error is permanent and can't be recovered and
// will set mError accordingly.
nsresult CreateDecoder(DecoderDoctorDiagnostics* aDiagnostics);