void H264Converter::OnDecoderInitDone(const TrackType aTrackType) { mInitPromiseRequest.Complete(); RefPtr<MediaRawData> sample = mPendingSample.forget(); DecodeFirstSample(sample); }
MediaResult H264Converter::CreateDecoderAndInit(MediaRawData* aSample) { RefPtr<MediaByteBuffer> extra_data = H264::ExtractExtraData(aSample); bool inbandExtradata = H264::HasSPS(extra_data); if (!inbandExtradata && !H264::HasSPS(mCurrentConfig.mExtraData)) { return NS_ERROR_NOT_INITIALIZED; } if (inbandExtradata) { UpdateConfigFromExtraData(extra_data); } MediaResult rv = CreateDecoder(mCurrentConfig, /* DecoderDoctorDiagnostics* */ nullptr); if (NS_SUCCEEDED(rv)) { RefPtr<H264Converter> self = this; RefPtr<MediaRawData> sample = aSample; mDecoder->Init() ->Then( AbstractThread::GetCurrent()->AsTaskQueue(), __func__, [self, sample, this](const TrackType aTrackType) { mInitPromiseRequest.Complete(); mNeedAVCC = Some(mDecoder->NeedsConversion() == ConversionRequired::kNeedAVCC); mCanRecycleDecoder = Some(CanRecycleDecoder()); if (!mFlushPromise.IsEmpty()) { // A Flush is pending, abort the current operation. mFlushPromise.Resolve(true, __func__); return; } DecodeFirstSample(sample); }, [self, this](const MediaResult& aError) { mInitPromiseRequest.Complete(); if (!mFlushPromise.IsEmpty()) { // A Flush is pending, abort the current operation. mFlushPromise.Reject(aError, __func__); return; } mDecodePromise.Reject( MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR, RESULT_DETAIL("Unable to initialize H264 decoder")), __func__); }) ->Track(mInitPromiseRequest); return NS_ERROR_DOM_MEDIA_INITIALIZING_DECODER; } return rv; }
nsresult H264Converter::CheckForSPSChange(MediaRawData* aSample) { 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; } mPendingSample = aSample; if (CanRecycleDecoder()) { // Do not recreate the decoder, reuse it. UpdateConfigFromExtraData(extra_data); // Ideally we would want to drain the decoder instead of flushing it. // However the draining operation requires calling Drain and looping several // times which isn't possible from within the H264Converter. So instead we // flush the decoder. In practice, this is a no-op as SPS change will only // be used with MSE. And with MSE, the MediaFormatReader would have drained // the decoder already. RefPtr<H264Converter> self = this; mDecoder->Flush() ->Then(AbstractThread::GetCurrent()->AsTaskQueue(), __func__, [self, this]() { mFlushRequest.Complete(); DecodeFirstSample(mPendingSample); mPendingSample = nullptr; }, [self, this](const MediaResult& aError) { mFlushRequest.Complete(); mDecodePromise.Reject(aError, __func__); }) ->Track(mFlushRequest); mNeedKeyframe = true; // This is not really initializing the decoder, but it will do as it // indicates an operation is pending. return NS_ERROR_DOM_MEDIA_INITIALIZING_DECODER; } // The SPS has changed, signal to flush the current decoder and create a // new one. RefPtr<H264Converter> self = this; mDecoder->Flush() ->Then(AbstractThread::GetCurrent()->AsTaskQueue(), __func__, [self, this]() { mFlushRequest.Complete(); mShutdownPromise = Shutdown(); mShutdownPromise ->Then(AbstractThread::GetCurrent()->AsTaskQueue(), __func__, [self, this]() { mShutdownRequest.Complete(); mShutdownPromise = nullptr; mNeedAVCC.reset(); RefPtr<MediaRawData> sample = mPendingSample.forget(); nsresult rv = CreateDecoderAndInit(sample); if (rv == NS_ERROR_DOM_MEDIA_INITIALIZING_DECODER) { // All good so far, will continue later. return; } MOZ_ASSERT(NS_FAILED(rv)); mDecodePromise.Reject(rv, __func__); return; }, [] { MOZ_CRASH("Can't reach here'"); }) ->Track(mShutdownRequest); }, [self, this](const MediaResult& aError) { mFlushRequest.Complete(); mDecodePromise.Reject(aError, __func__); }) ->Track(mFlushRequest); return NS_ERROR_DOM_MEDIA_INITIALIZING_DECODER; }