nsresult MP4Reader::ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags) { if (!mDemuxerInitialized) { MonitorAutoLock mon(mDemuxerMonitor); bool ok = InvokeAndRetry(this, &MP4Reader::InitDemuxer, mStream, &mDemuxerMonitor); NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE); mIndexReady = true; // To decode, we need valid video and a place to put it. mInfo.mVideo.mHasVideo = mVideo.mActive = mDemuxer->HasValidVideo() && mDecoder->GetImageContainer(); if (mVideo.mActive) { mVideo.mTrackDemuxer = new MP4VideoDemuxer(mDemuxer); } mInfo.mAudio.mHasAudio = mAudio.mActive = mDemuxer->HasValidAudio(); if (mAudio.mActive) { mAudio.mTrackDemuxer = new MP4AudioDemuxer(mDemuxer); } mCrypto = mDemuxer->Crypto(); { MonitorAutoUnlock unlock(mDemuxerMonitor); ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); mInfo.mCrypto.mIsEncrypted = mIsEncrypted = mCrypto.valid; } // Remember that we've initialized the demuxer, so that if we're decoding // an encrypted stream and we need to wait for a CDM to be set, we don't // need to reinit the demuxer. mDemuxerInitialized = true; } else if (mPlatform && !IsWaitingMediaResources()) { *aInfo = mInfo; *aTags = nullptr; return NS_OK; } if (HasAudio()) { const AudioDecoderConfig& audio = mDemuxer->AudioConfig(); mInfo.mAudio.mRate = audio.samples_per_second; mInfo.mAudio.mChannels = audio.channel_count; mAudio.mCallback = new DecoderCallback(this, kAudio); } if (HasVideo()) { const VideoDecoderConfig& video = mDemuxer->VideoConfig(); mInfo.mVideo.mDisplay = nsIntSize(video.display_width, video.display_height); mVideo.mCallback = new DecoderCallback(this, kVideo); // Collect telemetry from h264 AVCC SPS. if (!mFoundSPSForTelemetry) { mFoundSPSForTelemetry = AccumulateSPSTelemetry(video.extra_data); } } if (mIsEncrypted) { nsTArray<uint8_t> initData; ExtractCryptoInitData(initData); if (initData.Length() == 0) { return NS_ERROR_FAILURE; } mInfo.mCrypto.mInitData = initData; mInfo.mCrypto.mType = NS_LITERAL_STRING("cenc"); } // Get the duration, and report it to the decoder if we have it. Microseconds duration; { MonitorAutoLock lock(mDemuxerMonitor); duration = mDemuxer->Duration(); } if (duration != -1) { ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); mDecoder->SetMediaDuration(duration); } *aInfo = mInfo; *aTags = nullptr; if (!IsWaitingMediaResources() && !IsWaitingOnCDMResource()) { NS_ENSURE_TRUE(EnsureDecodersSetup(), NS_ERROR_FAILURE); } MonitorAutoLock mon(mDemuxerMonitor); UpdateIndex(); return NS_OK; }
nsresult MP4Reader::ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags) { if (!mDemuxerInitialized) { MonitorAutoLock mon(mDemuxerMonitor); bool ok = InvokeAndRetry(this, &MP4Reader::InitDemuxer, mStream, &mDemuxerMonitor); NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE); mIndexReady = true; // To decode, we need valid video and a place to put it. mVideo.mActive = mDemuxer->HasValidVideo() && mDecoder->GetImageContainer(); if (mVideo.mActive) { mVideo.mTrackDemuxer = new MP4VideoDemuxer(mDemuxer); } mAudio.mActive = mDemuxer->HasValidAudio(); if (mAudio.mActive) { mAudio.mTrackDemuxer = new MP4AudioDemuxer(mDemuxer); } mCrypto = mDemuxer->Crypto(); { MonitorAutoUnlock unlock(mDemuxerMonitor); ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); mIsEncrypted = mCrypto.valid; } // Remember that we've initialized the demuxer, so that if we're decoding // an encrypted stream and we need to wait for a CDM to be set, we don't // need to reinit the demuxer. mDemuxerInitialized = true; } else if (mPlatform && !IsWaitingMediaResources()) { *aInfo = mInfo; *aTags = nullptr; } if (HasAudio()) { mInfo.mAudio = mDemuxer->AudioConfig(); mAudio.mCallback = new DecoderCallback(this, TrackInfo::kAudioTrack); } if (HasVideo()) { mInfo.mVideo = mDemuxer->VideoConfig(); mVideo.mCallback = new DecoderCallback(this, TrackInfo::kVideoTrack); // Collect telemetry from h264 AVCC SPS. if (!mFoundSPSForTelemetry) { mFoundSPSForTelemetry = AccumulateSPSTelemetry(mInfo.mVideo.mExtraData); } } if (mCrypto.valid) { nsTArray<uint8_t> initData; ExtractCryptoInitData(initData); if (initData.Length() == 0) { return NS_ERROR_FAILURE; } // Add init data to info, will get sent from HTMLMediaElement::MetadataLoaded // (i.e., when transitioning from HAVE_NOTHING to HAVE_METADATA). mInfo.mCrypto.AddInitData(NS_LITERAL_STRING("cenc"), Move(initData)); } // Get the duration, and report it to the decoder if we have it. Microseconds duration; { MonitorAutoLock lock(mDemuxerMonitor); duration = mDemuxer->Duration(); } if (duration != -1) { ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); mDecoder->SetMediaDuration(duration); } *aInfo = mInfo; *aTags = nullptr; if (!IsWaitingOnCDMResource()) { NS_ENSURE_TRUE(EnsureDecodersSetup(), NS_ERROR_FAILURE); } MonitorAutoLock mon(mDemuxerMonitor); UpdateIndex(); return NS_OK; }