void GMPVideoDecoder::DrainComplete() { MOZ_ASSERT(IsOnGMPThread()); mDrainPromise.ResolveIfExists(mDecodedData, __func__); mDecodedData.Clear(); }
void GMPAudioDecoder::GMPInitDone(GMPAudioDecoderProxy* aGMP) { MOZ_ASSERT(IsOnGMPThread()); if (!aGMP) { mInitPromise.RejectIfExists(MediaDataDecoder::DecoderFailureReason::INIT_ERROR, __func__); return; } if (mInitPromise.IsEmpty()) { // GMP must have been shutdown while we were waiting for Init operation // to complete. aGMP->Close(); return; } nsTArray<uint8_t> codecSpecific; codecSpecific.AppendElements(mConfig.mCodecSpecificConfig->Elements(), mConfig.mCodecSpecificConfig->Length()); nsresult rv = aGMP->InitDecode(kGMPAudioCodecAAC, mConfig.mChannels, mConfig.mBitDepth, mConfig.mRate, codecSpecific, mAdapter); if (NS_FAILED(rv)) { aGMP->Close(); mInitPromise.Reject(MediaDataDecoder::DecoderFailureReason::INIT_ERROR, __func__); return; } mGMP = aGMP; mInitPromise.Resolve(TrackInfo::kAudioTrack, __func__); }
void AudioCallbackAdapter::ResetComplete() { MOZ_ASSERT(IsOnGMPThread()); mMustRecaptureAudioPosition = true; mCallback->FlushComplete(); }
void CDMProxy::gmp_Init(nsAutoPtr<InitData>&& aData) { MOZ_ASSERT(IsOnGMPThread()); nsCOMPtr<mozIGeckoMediaPluginService> mps = do_GetService("@mozilla.org/gecko-media-plugin-service;1"); if (!mps) { RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR, NS_LITERAL_CSTRING("Couldn't get MediaPluginService in CDMProxy::gmp_Init")); return; } // Make a copy before we transfer ownership of aData to the // gmp_InitGetGMPDecryptorCallback. InitData data(*aData); UniquePtr<GetNodeIdCallback> callback( new gmp_InitGetGMPDecryptorCallback(this, Move(aData))); nsresult rv = mps->GetNodeId(data.mOrigin, data.mTopLevelOrigin, data.mGMPName, data.mInPrivateBrowsing, Move(callback)); if (NS_FAILED(rv)) { RejectPromise(data.mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR, NS_LITERAL_CSTRING("Call to GetNodeId() failed early")); } }
nsresult EMEAudioDecoder::GmpInit() { MOZ_ASSERT(IsOnGMPThread()); nsTArray<nsCString> tags; tags.AppendElement(NS_LITERAL_CSTRING("aac")); tags.AppendElement(NS_ConvertUTF16toUTF8(mProxy->KeySystem())); nsresult rv = mMPS->GetGMPAudioDecoder(&tags, mProxy->GetNodeId(), &mGMP); NS_ENSURE_SUCCESS(rv, rv); MOZ_ASSERT(mGMP); mAudioRate = mConfig.samples_per_second; mAudioBytesPerSample = mConfig.bits_per_sample / 8; mAudioChannels = mConfig.channel_count; nsTArray<uint8_t> extraData; extraData.AppendElements(&mConfig.audio_specific_config[0], mConfig.audio_specific_config.length()); mGMP->InitDecode(kGMPAudioCodecAAC, mAudioChannels, mConfig.bits_per_sample, mAudioRate, extraData, this); return NS_OK; }
void GMPVideoDecoder::InputDataExhausted() { MOZ_ASSERT(IsOnGMPThread()); mDecodePromise.ResolveIfExists(mDecodedData, __func__); mDecodedData.Clear(); }
RefPtr<MediaDataDecoder::DecodePromise> GMPVideoDecoder::Decode(MediaRawData* aSample) { MOZ_ASSERT(IsOnGMPThread()); RefPtr<MediaRawData> sample(aSample); if (!mGMP) { return DecodePromise::CreateAndReject( MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR, RESULT_DETAIL("mGMP not initialized")), __func__); } mLastStreamOffset = sample->mOffset; GMPUniquePtr<GMPVideoEncodedFrame> frame = CreateFrame(sample); if (!frame) { return DecodePromise::CreateAndReject( MediaResult(NS_ERROR_OUT_OF_MEMORY, RESULT_DETAIL("CreateFrame returned null")), __func__); } RefPtr<DecodePromise> p = mDecodePromise.Ensure(__func__); nsTArray<uint8_t> info; // No codec specific per-frame info to pass. nsresult rv = mGMP->Decode(std::move(frame), false, info, 0); if (NS_FAILED(rv)) { mDecodePromise.Reject(MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR, RESULT_DETAIL("mGMP->Decode:%" PRIx32, static_cast<uint32_t>(rv))), __func__); } return p; }
void GMPVideoDecoder::Input(MediaRawData* aSample) { MOZ_ASSERT(IsOnGMPThread()); RefPtr<MediaRawData> sample(aSample); if (!mGMP) { mCallback->Error(MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR, RESULT_DETAIL("mGMP not initialized"))); return; } mAdapter->SetLastStreamOffset(sample->mOffset); GMPUniquePtr<GMPVideoEncodedFrame> frame = CreateFrame(sample); if (!frame) { mCallback->Error(MediaResult(NS_ERROR_OUT_OF_MEMORY, RESULT_DETAIL("CreateFrame returned null"))); return; } nsTArray<uint8_t> info; // No codec specific per-frame info to pass. nsresult rv = mGMP->Decode(Move(frame), false, info, 0); if (NS_FAILED(rv)) { mCallback->Error(MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR, RESULT_DETAIL("mGMP->Decode:%x", rv))); } }
nsresult EMEAudioDecoder::GmpInput(MP4Sample* aSample) { MOZ_ASSERT(IsOnGMPThread()); nsAutoPtr<MP4Sample> sample(aSample); if (!mGMP) { mCallback->Error(); return NS_ERROR_FAILURE; } if (sample->crypto.valid) { CDMCaps::AutoLock caps(mProxy->Capabilites()); MOZ_ASSERT(caps.CanDecryptAndDecodeAudio()); const auto& keyid = sample->crypto.key; if (!caps.IsKeyUsable(keyid)) { // DeliverSample assumes responsibility for deleting aSample. nsRefPtr<nsIRunnable> task(new DeliverSample(this, sample.forget())); caps.CallWhenKeyUsable(keyid, task, mGMPThread); return NS_OK; } } gmp::GMPAudioSamplesImpl samples(sample, mAudioChannels, mAudioRate); mGMP->Decode(samples); mStreamOffset = sample->byte_offset; return NS_OK; }
nsresult GMPAudioDecoder::Init() { MOZ_ASSERT(IsOnGMPThread()); mMPS = do_GetService("@mozilla.org/goanna-media-plugin-service;1"); MOZ_ASSERT(mMPS); nsTArray<nsCString> tags; InitTags(tags); nsresult rv = mMPS->GetGMPAudioDecoder(&tags, GetNodeId(), &mGMP); NS_ENSURE_SUCCESS(rv, rv); MOZ_ASSERT(mGMP); nsTArray<uint8_t> codecSpecific; codecSpecific.AppendElements(mConfig.audio_specific_config->Elements(), mConfig.audio_specific_config->Length()); rv = mGMP->InitDecode(kGMPAudioCodecAAC, mConfig.channel_count, mConfig.bits_per_sample, mConfig.samples_per_second, codecSpecific, mAdapter); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; }
nsresult EMEH264Decoder::Flush() { MOZ_ASSERT(!IsOnGMPThread()); // Runs on the decode task queue. MOZ_ASSERT(!mIsShutdown); { MonitorAutoLock mon(mMonitor); mFlushComplete = false; } nsRefPtr<nsIRunnable> task; task = NS_NewRunnableMethod(this, &EMEH264Decoder::GmpFlush); nsresult rv = mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL); NS_ENSURE_SUCCESS(rv, rv); { MonitorAutoLock mon(mMonitor); while (!mFlushComplete) { mon.Wait(); } } return NS_OK; }
void CDMProxy::gmp_Decrypted(uint32_t aId, GMPErr aResult, const nsTArray<uint8_t>& aDecryptedData) { MOZ_ASSERT(IsOnGMPThread()); for (size_t i = 0; i < mDecryptionJobs.Length(); i++) { DecryptJob* job = mDecryptionJobs[i]; if (job->mId == aId) { if (aDecryptedData.Length() != job->mSample->size) { NS_WARNING("CDM returned incorrect number of decrypted bytes"); } if (GMP_SUCCEEDED(aResult)) { PodCopy(job->mSample->data, aDecryptedData.Elements(), std::min<size_t>(aDecryptedData.Length(), job->mSample->size)); job->mClient->Decrypted(GMPNoErr, job->mSample.forget()); } else if (aResult == GMPNoKeyErr) { NS_WARNING("CDM returned GMPNoKeyErr"); // We still have the encrypted sample, so we can re-enqueue it to be // decrypted again once the key is usable again. job->mClient->Decrypted(GMPNoKeyErr, job->mSample.forget()); } else { nsAutoCString str("CDM returned decode failure GMPErr="); str.AppendInt(aResult); NS_WARNING(str.get()); job->mClient->Decrypted(aResult, nullptr); } mDecryptionJobs.RemoveElementAt(i); return; } } NS_WARNING("GMPDecryptorChild returned incorrect job ID"); }
void CDMProxy::gmp_Decrypted(uint32_t aId, GMPErr aResult, const nsTArray<uint8_t>& aDecryptedData) { MOZ_ASSERT(IsOnGMPThread()); #ifdef DEBUG bool jobIdFound = false; #endif for (size_t i = 0; i < mDecryptionJobs.Length(); i++) { DecryptJob* job = mDecryptionJobs[i]; if (job->mId == aId) { #ifdef DEBUG jobIdFound = true; #endif job->PostResult(aResult, aDecryptedData); mDecryptionJobs.RemoveElementAt(i); } } #ifdef DEBUG if (!jobIdFound) { NS_WARNING("GMPDecryptorChild returned incorrect job ID"); } #endif }
void EMEH264Decoder::Terminated() { MOZ_ASSERT(IsOnGMPThread()); NS_WARNING("H.264 GMP decoder terminated."); GmpShutdown(); }
void EMEAudioDecoder::Error(GMPErr aErr) { MOZ_ASSERT(IsOnGMPThread()); EME_LOG("EMEAudioDecoder::Error"); mCallback->Error(); GmpShutdown(); }
void EMEAudioDecoder::GmpDrain() { MOZ_ASSERT(IsOnGMPThread()); if (!mGMP || NS_FAILED(mGMP->Drain())) { mCallback->DrainComplete(); } }
void GMPVideoDecoder::Drain() { MOZ_ASSERT(IsOnGMPThread()); if (!mGMP || NS_FAILED(mGMP->Drain())) { mCallback->DrainComplete(); } }
void VideoCallbackAdapter::Error(GMPErr aErr) { MOZ_ASSERT(IsOnGMPThread()); mCallback->Error(MediaResult(aErr == GMPDecodeErr ? NS_ERROR_DOM_MEDIA_DECODE_ERR : NS_ERROR_DOM_MEDIA_FATAL_ERR, RESULT_DETAIL("GMPErr:%x", aErr))); }
void CDMProxy::gmp_Terminated() { MOZ_ASSERT(IsOnGMPThread()); EME_LOG("CDM terminated"); if (mCDM) { mCDM->Close(); mCDM = nullptr; } }
void GMPVideoDecoder::Flush() { MOZ_ASSERT(IsOnGMPThread()); if (!mGMP || NS_FAILED(mGMP->Reset())) { // Abort the flush. mCallback->FlushComplete(); } }
void CDMProxy::gmp_RemoveSession(nsAutoPtr<SessionOpData> aData) { MOZ_ASSERT(IsOnGMPThread()); if (!mCDM) { RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR); return; } mCDM->RemoveSession(aData->mPromiseId, aData->mSessionId); }
void EMEH264Decoder::ResetComplete() { MOZ_ASSERT(IsOnGMPThread()); { MonitorAutoLock mon(mMonitor); mFlushComplete = true; mon.NotifyAll(); } }
void CDMProxy::gmp_SetServerCertificate(nsAutoPtr<SetServerCertificateData> aData) { MOZ_ASSERT(IsOnGMPThread()); if (!mCDM) { RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR); return; } mCDM->SetServerCertificate(aData->mPromiseId, aData->mCert); }
void EMEAudioDecoder::GmpShutdown() { MOZ_ASSERT(IsOnGMPThread()); if (!mGMP) { return; } mGMP->Close(); mGMP = nullptr; }
nsresult EMEAudioDecoder::Input(MP4Sample* aSample) { MOZ_ASSERT(!IsOnGMPThread()); // Runs on the decode task queue. nsRefPtr<nsIRunnable> task(new DeliverSample(this, aSample)); nsresult rv = mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; }
void EMEAudioDecoder::GmpFlush() { MOZ_ASSERT(IsOnGMPThread()); if (!mGMP || NS_FAILED(mGMP->Reset())) { // Abort the flush... MonitorAutoLock mon(mMonitor); mFlushComplete = true; mon.NotifyAll(); } }
nsresult EMEAudioDecoder::Shutdown() { MOZ_ASSERT(!IsOnGMPThread()); // Runs on the decode task queue. nsRefPtr<nsIRunnable> task; task = NS_NewRunnableMethod(this, &EMEAudioDecoder::GmpShutdown); nsresult rv = mGMPThread->Dispatch(task, NS_DISPATCH_SYNC); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; }
void EMEAudioDecoder::ResetComplete() { MOZ_ASSERT(IsOnGMPThread()); mMustRecaptureAudioPosition = true; { MonitorAutoLock mon(mMonitor); mFlushComplete = true; mon.NotifyAll(); } }
nsresult GMPAudioDecoder::Drain() { MOZ_ASSERT(IsOnGMPThread()); if (!mGMP || NS_FAILED(mGMP->Drain())) { mCallback->DrainComplete(); } return NS_OK; }
void GMPVideoDecoder::Error(GMPErr aErr) { MOZ_ASSERT(IsOnGMPThread()); auto error = MediaResult(aErr == GMPDecodeErr ? NS_ERROR_DOM_MEDIA_DECODE_ERR : NS_ERROR_DOM_MEDIA_FATAL_ERR, RESULT_DETAIL("GMPErr:%x", aErr)); mDecodePromise.RejectIfExists(error, __func__); mDrainPromise.RejectIfExists(error, __func__); mFlushPromise.RejectIfExists(error, __func__); }