예제 #1
0
void
GMPVideoDecoder::DrainComplete()
{
  MOZ_ASSERT(IsOnGMPThread());
  mDrainPromise.ResolveIfExists(mDecodedData, __func__);
  mDecodedData.Clear();
}
예제 #2
0
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__);
}
예제 #3
0
void
AudioCallbackAdapter::ResetComplete()
{
  MOZ_ASSERT(IsOnGMPThread());
  mMustRecaptureAudioPosition = true;
  mCallback->FlushComplete();
}
예제 #4
0
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"));
  }
}
예제 #5
0
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;
}
예제 #6
0
void
GMPVideoDecoder::InputDataExhausted()
{
  MOZ_ASSERT(IsOnGMPThread());
  mDecodePromise.ResolveIfExists(mDecodedData, __func__);
  mDecodedData.Clear();
}
예제 #7
0
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;
}
예제 #8
0
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)));
  }
}
예제 #9
0
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;
}
예제 #10
0
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;
}
예제 #11
0
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;
}
예제 #12
0
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");
}
예제 #13
0
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
}
예제 #14
0
void
EMEH264Decoder::Terminated()
{
  MOZ_ASSERT(IsOnGMPThread());

  NS_WARNING("H.264 GMP decoder terminated.");
  GmpShutdown();
}
예제 #15
0
void
EMEAudioDecoder::Error(GMPErr aErr)
{
  MOZ_ASSERT(IsOnGMPThread());
  EME_LOG("EMEAudioDecoder::Error");
  mCallback->Error();
  GmpShutdown();
}
예제 #16
0
void
EMEAudioDecoder::GmpDrain()
{
  MOZ_ASSERT(IsOnGMPThread());
  if (!mGMP || NS_FAILED(mGMP->Drain())) {
    mCallback->DrainComplete();
  }
}
예제 #17
0
void
GMPVideoDecoder::Drain()
{
  MOZ_ASSERT(IsOnGMPThread());

  if (!mGMP || NS_FAILED(mGMP->Drain())) {
    mCallback->DrainComplete();
  }
}
예제 #18
0
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)));
}
예제 #19
0
void
CDMProxy::gmp_Terminated()
{
  MOZ_ASSERT(IsOnGMPThread());
  EME_LOG("CDM terminated");
  if (mCDM) {
    mCDM->Close();
    mCDM = nullptr;
  }
}
예제 #20
0
void
GMPVideoDecoder::Flush()
{
  MOZ_ASSERT(IsOnGMPThread());

  if (!mGMP || NS_FAILED(mGMP->Reset())) {
    // Abort the flush.
    mCallback->FlushComplete();
  }
}
예제 #21
0
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);
}
예제 #22
0
void
EMEH264Decoder::ResetComplete()
{
  MOZ_ASSERT(IsOnGMPThread());
  {
    MonitorAutoLock mon(mMonitor);
    mFlushComplete = true;
    mon.NotifyAll();
  }
}
예제 #23
0
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);
}
예제 #24
0
void
EMEAudioDecoder::GmpShutdown()
{
  MOZ_ASSERT(IsOnGMPThread());
  if (!mGMP) {
    return;
  }
  mGMP->Close();
  mGMP = nullptr;
}
예제 #25
0
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;
}
예제 #26
0
void
EMEAudioDecoder::GmpFlush()
{
  MOZ_ASSERT(IsOnGMPThread());
  if (!mGMP || NS_FAILED(mGMP->Reset())) {
    // Abort the flush...
    MonitorAutoLock mon(mMonitor);
    mFlushComplete = true;
    mon.NotifyAll();
  }
}
예제 #27
0
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;
}
예제 #28
0
void
EMEAudioDecoder::ResetComplete()
{
  MOZ_ASSERT(IsOnGMPThread());
  mMustRecaptureAudioPosition = true;
  {
    MonitorAutoLock mon(mMonitor);
    mFlushComplete = true;
    mon.NotifyAll();
  }
}
예제 #29
0
nsresult
GMPAudioDecoder::Drain()
{
  MOZ_ASSERT(IsOnGMPThread());

  if (!mGMP || NS_FAILED(mGMP->Drain())) {
    mCallback->DrainComplete();
  }

  return NS_OK;
}
예제 #30
0
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__);
}