diff --git a/configure.in b/configure.in index 4cb9f733dd10..9a7495b7794a 100644 --- a/configure.in +++ b/configure.in @@ -3929,7 +3929,6 @@ MOZ_SAMPLE_TYPE_FLOAT32= MOZ_SAMPLE_TYPE_S16= MOZ_OPUS=1 MOZ_WEBM=1 -MOZ_DASH= MOZ_DIRECTSHOW= MOZ_WMF= MOZ_WEBRTC=1 @@ -8633,7 +8632,6 @@ AC_SUBST(MOZ_VORBIS) AC_SUBST(MOZ_TREMOR) AC_SUBST(MOZ_OPUS) AC_SUBST(MOZ_WEBM) -AC_SUBST(MOZ_DASH) AC_SUBST(MOZ_WMF) AC_SUBST(MOZ_DIRECTSHOW) AC_SUBST(MOZ_MEDIA_PLUGINS) diff --git a/content/media/dash/DASHDecoder.cpp b/content/media/dash/DASHDecoder.cpp deleted file mode 100644 index b85763828efa..000000000000 --- a/content/media/dash/DASHDecoder.cpp +++ /dev/null @@ -1,1387 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ - -/* This Source Code Form Is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* DASH - Dynamic Adaptive Streaming over HTTP. - * - * DASH is an adaptive bitrate streaming technology where a multimedia file is - * partitioned into one or more segments and delivered to a client using HTTP. - * - * Interaction with MediaDecoderStateMachine, HTMLMediaElement, - * ChannelMediaResource and sub-decoders (WebMDecoder). - * - * - * MediaDecoderStateMachine HTMLMediaElement - * 1 / \ 1 / 1 - * / \ / - * 1 / \ 1 / 1 - * DASHReader ------ DASHDecoder ------------ ChannelMediaResource - * |1 1 1 |1 \1 (for MPD Manifest) - * | | ------------ - * |* |* \* - * WebMReader ------- DASHRepDecoder ------- ChannelMediaResource - * 1 1 1 1 (for media streams) - * - * One decoder and state-machine, as with current, non-DASH decoders. - * - * DASH adds multiple readers, decoders and resources, in order to manage - * download and decode of the MPD manifest and individual media streams. - * - * Rep/|Representation| is for an individual media stream, e.g. audio - * DASHRepDecoder is the decoder for a rep/|Representation|. - * - * FLOW - * - * 1 - Download and parse the MPD (DASH XML-based manifest). - * - * Media element creates new |DASHDecoder| object: - * member var initialization to default values, including a/v sub-decoders. - * MediaDecoder and MediaDecoder constructors are called. - * MediaDecoder::Init() is called. - * - * Media element creates new |ChannelMediaResource|: - * used to download MPD manifest. - * - * Media element calls |DASHDecoder|->Load() to download the MPD file: - * creates an |DASHReader| object to forward calls to multiple - * WebMReaders (corresponding to MPD |Representation|s i.e. streams). - * Note: 1 |DASHReader| per DASH/WebM MPD. - * - * also calls |ChannelMediaResource|::Open(). - * uses nsHttpChannel to download MPD; notifies DASHDecoder. - * - * Meanwhile, back in |DASHDecoder|->Load(): - * MediaDecoderStateMachine is created. - * has ref to |DASHReader| object. - * state machine is scheduled. - * - * Media element finishes decoder setup: - * element added to media URI table etc. - * - * -- At this point, objects are waiting on HTTP returning MPD data. - * - * MPD Download (Async |ChannelMediaResource| channel callbacks): - * calls DASHDecoder::|NotifyDownloadEnded|(). - * DASHDecoder parses MPD XML to DOM to MPD classes. - * gets |Segment| URLs from MPD for audio and video streams. - * creates |nsIChannel|s, |ChannelMediaResource|s. - * stores resources as member vars (to forward function calls later). - * creates |WebMReader|s and |DASHRepDecoder|s. - * DASHreader creates |WebMReader|s. - * |Representation| decoders are connected to the |ChannelMediaResource|s. - * - * |DASHDecoder|->|LoadRepresentations|() starts download and decode. - * - * - * 2 - Media Stream, Byte Range downloads. - * - * -- At this point the Segment media stream downloads are managed by - * individual |ChannelMediaResource|s and |WebMReader|s. - * A single |DASHDecoder| and |MediaDecoderStateMachine| manage them - * and communicate to |HTMLMediaElement|. - * - * Each |DASHRepDecoder| gets init range and index range from its MPD - * |Representation|. |DASHRepDecoder| uses ChannelMediaResource to start the - * byte range downloads, calling |OpenByteRange| with a |MediaByteRange| - * object. - * Once the init and index segments have been downloaded and |ReadMetadata| has - * completed, each |WebMReader| notifies it's peer |DASHRepDecoder|. - * Note: the decoder must wait until index data is parsed because it needs to - * get the offsets of the subsegments (WebM clusters) from the media file - * itself. - * Since byte ranges for subsegments are obtained, |nsDASHRepdecoder| continues - * downloading the files in byte range chunks. - * - * XXX Note that this implementation of DASHRepDecoder is focused on DASH - * WebM On Demand profile: on the todo list is an action item to make this - * more abstract. - * - * Note on |Seek|: Currently, |MediaCache| requires that seeking start at the - * beginning of the block in which the desired offset would be - * found. As such, when |ChannelMediaResource| does a seek - * using DASH WebM subsegments (clusters), it requests a start - * offset that corresponds to the beginning of the block, not - * the start offset of the cluster. For DASH Webm, which has - * media encoded in single files, this is fine. Future work on - * other profiles will require this to be re-examined. - */ - -#include -#include -#include "nsIURI.h" -#include "nsIFileURL.h" -#include "nsNetUtil.h" -#include "VideoUtils.h" -#include "nsThreadUtils.h" -#include "nsContentUtils.h" -#include "nsIContentPolicy.h" -#include "nsIContentSecurityPolicy.h" -#include "nsICachingChannel.h" -#include "MediaDecoderStateMachine.h" -#include "WebMDecoder.h" -#include "WebMReader.h" -#include "DASHReader.h" -#include "nsDASHMPDParser.h" -#include "DASHRepDecoder.h" -#include "DASHDecoder.h" -#include - -namespace mozilla { - -#ifdef PR_LOGGING -extern PRLogModuleInfo* gMediaDecoderLog; -#define LOG(msg, ...) PR_LOG(gMediaDecoderLog, PR_LOG_DEBUG, \ - ("%p [DASHDecoder] " msg, this, __VA_ARGS__)) -#define LOG1(msg) PR_LOG(gMediaDecoderLog, PR_LOG_DEBUG, \ - ("%p [DASHDecoder] " msg, this)) -#else -#define LOG(msg, ...) -#define LOG1(msg) -#endif - -DASHDecoder::DASHDecoder() : - MediaDecoder(), - mNotifiedLoadAborted(false), - mBuffer(nullptr), - mBufferLength(0), - mMPDReaderThread(nullptr), - mPrincipal(nullptr), - mDASHReader(nullptr), - mVideoAdaptSetIdx(-1), - mAudioRepDecoderIdx(-1), - mVideoRepDecoderIdx(-1), - mAudioSubsegmentIdx(0), - mVideoSubsegmentIdx(0), - mAudioMetadataReadCount(0), - mVideoMetadataReadCount(0), - mSeeking(false), - mStatisticsLock("DASHDecoder.mStatisticsLock") -{ - MOZ_COUNT_CTOR(DASHDecoder); - mAudioStatistics = new MediaChannelStatistics(); - mVideoStatistics = new MediaChannelStatistics(); -} - -DASHDecoder::~DASHDecoder() -{ - MOZ_COUNT_DTOR(DASHDecoder); -} - -MediaDecoderStateMachine* -DASHDecoder::CreateStateMachine() -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - return new MediaDecoderStateMachine(this, mDASHReader); -} - -void -DASHDecoder::ReleaseStateMachine() -{ - NS_ASSERTION(NS_IsMainThread(), "Must be on main thread."); - - // Since state machine owns mDASHReader, remove reference to it. - mDASHReader = nullptr; - - MediaDecoder::ReleaseStateMachine(); - for (uint i = 0; i < mAudioRepDecoders.Length(); i++) { - mAudioRepDecoders[i]->ReleaseStateMachine(); - } - for (uint i = 0; i < mVideoRepDecoders.Length(); i++) { - mVideoRepDecoders[i]->ReleaseStateMachine(); - } -} - -nsresult -DASHDecoder::Load(nsIStreamListener** aStreamListener, - MediaDecoder* aCloneDonor) -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - - mDASHReader = new DASHReader(this); - - nsresult rv = OpenResource(aStreamListener); - NS_ENSURE_SUCCESS(rv, rv); - - mDecoderStateMachine = CreateStateMachine(); - if (!mDecoderStateMachine) { - LOG1("Failed to create state machine!"); - return NS_ERROR_FAILURE; - } - return NS_OK; -} - -void -DASHDecoder::NotifyDownloadEnded(nsresult aStatus) -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - - // Should be no download ended notification if MPD Manager exists. - if (mMPDManager) { - LOG("Network Error! Repeated MPD download notification but MPD Manager " - "[%p] already exists!", mMPDManager.get()); - NetworkError(); - return; - } - - if (NS_SUCCEEDED(aStatus)) { - LOG1("MPD downloaded."); - - // mPrincipal must be set on main thread before dispatch to parser thread. - mPrincipal = GetCurrentPrincipal(); - - // Create reader thread for |ChannelMediaResource|::|Read|. - nsCOMPtr event = - NS_NewRunnableMethod(this, &DASHDecoder::ReadMPDBuffer); - NS_ENSURE_TRUE_VOID(event); - - nsresult rv = NS_NewNamedThread("DASH MPD Reader", - getter_AddRefs(mMPDReaderThread), - event, - MEDIA_THREAD_STACK_SIZE); - if (NS_FAILED(rv) || !mMPDReaderThread) { - LOG("Error creating MPD reader thread: rv[%x] thread [%p].", - rv, mMPDReaderThread.get()); - DecodeError(); - return; - } - } else if (aStatus == NS_BINDING_ABORTED) { - LOG("MPD download has been cancelled by the user: aStatus [%x].", aStatus); - if (mOwner) { - mOwner->LoadAborted(); - } - return; - } else if (aStatus != NS_BASE_STREAM_CLOSED) { - LOG("Network error trying to download MPD: aStatus [%x].", aStatus); - NetworkError(); - } -} - -void -DASHDecoder::ReadMPDBuffer() -{ - NS_ASSERTION(!NS_IsMainThread(), "Should not be on main thread."); - - LOG1("Started reading from the MPD buffer."); - - int64_t length = mResource->GetLength(); - if (length <= 0 || length > DASH_MAX_MPD_SIZE) { - LOG("MPD is larger than [%d]MB.", DASH_MAX_MPD_SIZE/(1024*1024)); - DecodeError(); - return; - } - - mBuffer = new char[length]; - - uint32_t count = 0; - nsresult rv = mResource->Read(mBuffer, length, &count); - // By this point, all bytes should be available for reading. - if (NS_FAILED(rv) || count != length) { - LOG("Error reading MPD buffer: rv [%x] count [%d] length [%d].", - rv, count, length); - DecodeError(); - return; - } - // Store buffer length for processing on main thread. - mBufferLength = static_cast(length); - - LOG1("Finished reading MPD buffer; back to main thread for parsing."); - - // Dispatch event to Main thread to parse MPD buffer. - nsCOMPtr event = - NS_NewRunnableMethod(this, &DASHDecoder::OnReadMPDBufferCompleted); - rv = NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); - if (NS_FAILED(rv)) { - LOG("Error dispatching parse event to main thread: rv[%x]", rv); - DecodeError(); - return; - } -} - -void -DASHDecoder::OnReadMPDBufferCompleted() -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - - if (mShuttingDown) { - LOG1("Shutting down! Ignoring OnReadMPDBufferCompleted()."); - return; - } - - // Shutdown the thread. - if (!mMPDReaderThread) { - LOG1("Error: MPD reader thread does not exist!"); - DecodeError(); - return; - } - nsresult rv = mMPDReaderThread->Shutdown(); - if (NS_FAILED(rv)) { - LOG("MPD reader thread did not shutdown correctly! rv [%x]", rv); - DecodeError(); - return; - } - mMPDReaderThread = nullptr; - - // Start parsing the MPD data and loading the media. - rv = ParseMPDBuffer(); - if (NS_FAILED(rv)) { - LOG("Error parsing MPD buffer! rv [%x]", rv); - DecodeError(); - return; - } - rv = CreateRepDecoders(); - if (NS_FAILED(rv)) { - LOG("Error creating decoders for Representations! rv [%x]", rv); - DecodeError(); - return; - } - - rv = LoadRepresentations(); - if (NS_FAILED(rv)) { - LOG("Error loading Representations! rv [%x]", rv); - NetworkError(); - return; - } - - // Notify reader that it can start reading metadata. Sub-readers will still - // block until sub-resources have downloaded data into the media cache. - mDASHReader->ReadyToReadMetadata(); -} - -nsresult -DASHDecoder::ParseMPDBuffer() -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - NS_ENSURE_TRUE(mBuffer, NS_ERROR_NULL_POINTER); - - LOG1("Started parsing the MPD buffer."); - - // Parse MPD buffer and get root DOM element. - nsAutoPtr parser; - parser = new nsDASHMPDParser(mBuffer.forget(), mBufferLength, mPrincipal, - mResource->URI()); - mozilla::net::DASHMPDProfile profile; - parser->Parse(getter_Transfers(mMPDManager), &profile); - mBuffer = nullptr; - NS_ENSURE_TRUE(mMPDManager, NS_ERROR_NULL_POINTER); - - LOG("Finished parsing the MPD buffer. Profile is [%d].", profile); - - return NS_OK; -} - -nsresult -DASHDecoder::CreateRepDecoders() -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - NS_ENSURE_TRUE(mMPDManager, NS_ERROR_NULL_POINTER); - - // Global settings for the presentation. - int64_t startTime = mMPDManager->GetStartTime(); - SetDuration(mMPDManager->GetDuration()); - NS_ENSURE_TRUE(startTime >= 0 && mDuration > 0, NS_ERROR_ILLEGAL_VALUE); - - // For each audio/video stream, create a |ChannelMediaResource| object. - - for (uint32_t i = 0; i < mMPDManager->GetNumAdaptationSets(); i++) { - IMPDManager::AdaptationSetType asType = mMPDManager->GetAdaptationSetType(i); - if (asType == IMPDManager::DASH_VIDEO_STREAM) { - mVideoAdaptSetIdx = i; - } - for (uint32_t j = 0; j < mMPDManager->GetNumRepresentations(i); j++) { - // Get URL string. - nsAutoString segmentUrl; - nsresult rv = mMPDManager->GetFirstSegmentUrl(i, j, segmentUrl); - NS_ENSURE_SUCCESS(rv, rv); - - // Get segment |nsIURI|; use MPD's base URI in case of relative paths. - nsCOMPtr url; - rv = NS_NewURI(getter_AddRefs(url), segmentUrl, nullptr, mResource->URI()); - NS_ENSURE_SUCCESS(rv, rv); -#ifdef PR_LOGGING - nsAutoCString newUrl; - rv = url->GetSpec(newUrl); - NS_ENSURE_SUCCESS(rv, rv); - LOG("Using URL=\"%s\" for AdaptationSet [%d] Representation [%d]", - newUrl.get(), i, j); -#endif - - // 'file://' URLs are not supported. - nsCOMPtr fileURL = do_QueryInterface(url); - NS_ENSURE_FALSE(fileURL, NS_ERROR_ILLEGAL_VALUE); - - // Create |DASHRepDecoder| objects for each representation. - if (asType == IMPDManager::DASH_VIDEO_STREAM) { - Representation const * rep = mMPDManager->GetRepresentation(i, j); - NS_ENSURE_TRUE(rep, NS_ERROR_NULL_POINTER); - rv = CreateVideoRepDecoder(url, rep); - NS_ENSURE_SUCCESS(rv, rv); - } else if (asType == IMPDManager::DASH_AUDIO_STREAM) { - Representation const * rep = mMPDManager->GetRepresentation(i, j); - NS_ENSURE_TRUE(rep, NS_ERROR_NULL_POINTER); - rv = CreateAudioRepDecoder(url, rep); - NS_ENSURE_SUCCESS(rv, rv); - } - } - } - - NS_ENSURE_TRUE(VideoRepDecoder(), NS_ERROR_NOT_INITIALIZED); - NS_ENSURE_TRUE(AudioRepDecoder(), NS_ERROR_NOT_INITIALIZED); - - return NS_OK; -} - -nsresult -DASHDecoder::CreateAudioRepDecoder(nsIURI* aUrl, - mozilla::net::Representation const * aRep) -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - NS_ENSURE_ARG(aUrl); - NS_ENSURE_ARG(aRep); - NS_ENSURE_TRUE(mOwner, NS_ERROR_NOT_INITIALIZED); - - // Create subdecoder and init with media element. - DASHRepDecoder* audioDecoder = new DASHRepDecoder(this); - NS_ENSURE_TRUE(audioDecoder->Init(mOwner), NS_ERROR_NOT_INITIALIZED); - - // Set current decoder to the first one created. - if (mAudioRepDecoderIdx == -1) { - mAudioRepDecoderIdx = 0; - } - mAudioRepDecoders.AppendElement(audioDecoder); - - // Create sub-reader; attach to DASH reader and sub-decoder. - WebMReader* audioReader = new WebMReader(audioDecoder); - if (mDASHReader) { - audioReader->SetMainReader(mDASHReader); - mDASHReader->AddAudioReader(audioReader); - } - audioDecoder->SetReader(audioReader); - - // Create media resource with URL and connect to sub-decoder. - MediaResource* audioResource - = CreateAudioSubResource(aUrl, static_cast(audioDecoder)); - NS_ENSURE_TRUE(audioResource, NS_ERROR_NOT_INITIALIZED); - - audioDecoder->SetResource(audioResource); - audioDecoder->SetMPDRepresentation(aRep); - - LOG("Created audio DASHRepDecoder [%p]", audioDecoder); - - return NS_OK; -} - -nsresult -DASHDecoder::CreateVideoRepDecoder(nsIURI* aUrl, - mozilla::net::Representation const * aRep) -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - NS_ENSURE_ARG(aUrl); - NS_ENSURE_ARG(aRep); - NS_ENSURE_TRUE(mOwner, NS_ERROR_NOT_INITIALIZED); - - // Create subdecoder and init with media element. - DASHRepDecoder* videoDecoder = new DASHRepDecoder(this); - NS_ENSURE_TRUE(videoDecoder->Init(mOwner), NS_ERROR_NOT_INITIALIZED); - - // Set current decoder to the first one created. - if (mVideoRepDecoderIdx == -1) { - mVideoRepDecoderIdx = 0; - } - mVideoRepDecoders.AppendElement(videoDecoder); - - // Create sub-reader; attach to DASH reader and sub-decoder. - WebMReader* videoReader = new WebMReader(videoDecoder); - if (mDASHReader) { - videoReader->SetMainReader(mDASHReader); - mDASHReader->AddVideoReader(videoReader); - } - videoDecoder->SetReader(videoReader); - - // Create media resource with URL and connect to sub-decoder. - MediaResource* videoResource - = CreateVideoSubResource(aUrl, static_cast(videoDecoder)); - NS_ENSURE_TRUE(videoResource, NS_ERROR_NOT_INITIALIZED); - - videoDecoder->SetResource(videoResource); - videoDecoder->SetMPDRepresentation(aRep); - - LOG("Created video DASHRepDecoder [%p]", videoDecoder); - - return NS_OK; -} - -MediaResource* -DASHDecoder::CreateAudioSubResource(nsIURI* aUrl, - MediaDecoder* aAudioDecoder) -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - NS_ENSURE_TRUE(aUrl, nullptr); - NS_ENSURE_TRUE(aAudioDecoder, nullptr); - - // Create channel for representation. - nsCOMPtr channel; - nsresult rv = CreateSubChannel(aUrl, getter_AddRefs(channel)); - NS_ENSURE_SUCCESS(rv, nullptr); - - // Create resource for representation. - MediaResource* audioResource - = MediaResource::Create(aAudioDecoder, channel); - NS_ENSURE_TRUE(audioResource, nullptr); - - audioResource->RecordStatisticsTo(mAudioStatistics); - return audioResource; -} - -MediaResource* -DASHDecoder::CreateVideoSubResource(nsIURI* aUrl, - MediaDecoder* aVideoDecoder) -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - NS_ENSURE_TRUE(aUrl, nullptr); - NS_ENSURE_TRUE(aVideoDecoder, nullptr); - - // Create channel for representation. - nsCOMPtr channel; - nsresult rv = CreateSubChannel(aUrl, getter_AddRefs(channel)); - NS_ENSURE_SUCCESS(rv, nullptr); - - // Create resource for representation. - MediaResource* videoResource - = MediaResource::Create(aVideoDecoder, channel); - NS_ENSURE_TRUE(videoResource, nullptr); - - videoResource->RecordStatisticsTo(mVideoStatistics); - return videoResource; -} - -nsresult -DASHDecoder::CreateSubChannel(nsIURI* aUrl, nsIChannel** aChannel) -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - NS_ENSURE_ARG(aUrl); - - NS_ENSURE_TRUE(mOwner, NS_ERROR_NULL_POINTER); - HTMLMediaElement* element = mOwner->GetMediaElement(); - NS_ENSURE_TRUE(element, NS_ERROR_NULL_POINTER); - - nsCOMPtr loadGroup = - element->GetDocumentLoadGroup(); - NS_ENSURE_TRUE(loadGroup, NS_ERROR_NULL_POINTER); - - // Check for a Content Security Policy to pass down to the channel - // created to load the media content. - nsCOMPtr channelPolicy; - nsCOMPtr csp; - nsresult rv = element->NodePrincipal()->GetCsp(getter_AddRefs(csp)); - NS_ENSURE_SUCCESS(rv,rv); - if (csp) { - channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1"); - channelPolicy->SetContentSecurityPolicy(csp); - channelPolicy->SetLoadType(nsIContentPolicy::TYPE_MEDIA); - } - nsCOMPtr channel; - rv = NS_NewChannel(getter_AddRefs(channel), - aUrl, - nullptr, - loadGroup, - nullptr, - nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY, - channelPolicy); - NS_ENSURE_SUCCESS(rv,rv); - NS_ENSURE_TRUE(channel, NS_ERROR_NULL_POINTER); - - NS_ADDREF(*aChannel = channel); - return NS_OK; -} - -nsresult -DASHDecoder::LoadRepresentations() -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - - nsresult rv; - { - // Hold the lock while we do this to set proper lock ordering - // expectations for dynamic deadlock detectors: decoder lock(s) - // should be grabbed before the cache lock. - ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); - - // Load the decoders for each |Representation|'s media streams. - // XXX Prob ok to load all audio decoders, since there should only be one - // created, but need to review the rest of the file. - if (AudioRepDecoder()) { - rv = AudioRepDecoder()->Load(); - NS_ENSURE_SUCCESS(rv, rv); - mAudioMetadataReadCount++; - } - // Load all video decoders. - for (uint32_t i = 0; i < mVideoRepDecoders.Length(); i++) { - rv = mVideoRepDecoders[i]->Load(); - NS_ENSURE_SUCCESS(rv, rv); - mVideoMetadataReadCount++; - } - if (AudioRepDecoder()) { - AudioRepDecoder()->SetStateMachine(mDecoderStateMachine); - } - for (uint32_t i = 0; i < mVideoRepDecoders.Length(); i++) { - mVideoRepDecoders[i]->SetStateMachine(mDecoderStateMachine); - } - } - - // Ensure decoder is set to play if its already been requested. - if (mPlayState == PLAY_STATE_PLAYING) { - mNextState = PLAY_STATE_PLAYING; - } - - // Now that subreaders are init'd, it's ok to init state machine. - return InitializeStateMachine(nullptr); -} - -void -DASHDecoder::NotifyDownloadEnded(DASHRepDecoder* aRepDecoder, - nsresult aStatus, - int32_t const aSubsegmentIdx) -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - - if (mShuttingDown) { - LOG1("Shutting down! Ignoring NotifyDownloadEnded()."); - return; - } - - // MPD Manager must exist, indicating MPD has been downloaded and parsed. - if (!mMPDManager) { - LOG1("Network Error! MPD Manager must exist, indicating MPD has been " - "downloaded and parsed"); - NetworkError(); - return; - } - - // Decoder for the media |Representation| must not be null. - if (!aRepDecoder) { - LOG1("Decoder for Representation is reported as null."); - DecodeError(); - return; - } - - if (NS_SUCCEEDED(aStatus)) { - LOG("Byte range downloaded: decoder [%p] subsegmentIdx [%d]", - aRepDecoder, aSubsegmentIdx); - - if (aSubsegmentIdx < 0) { - LOG("Last subsegment for decoder [%p] was downloaded", - aRepDecoder); - return; - } - - ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); - nsRefPtr decoder = aRepDecoder; - { - if (!IsDecoderAllowedToDownloadSubsegment(aRepDecoder, - aSubsegmentIdx)) { - NS_WARNING("Decoder downloaded subsegment but it is not allowed!"); - LOG("Error! Decoder [%p] downloaded subsegment [%d] but it is not " - "allowed!", aRepDecoder, aSubsegmentIdx); - return; - } - - if (aRepDecoder == VideoRepDecoder() && - mVideoSubsegmentIdx == aSubsegmentIdx) { - IncrementSubsegmentIndex(aRepDecoder); - } else if (aRepDecoder == AudioRepDecoder() && - mAudioSubsegmentIdx == aSubsegmentIdx) { - IncrementSubsegmentIndex(aRepDecoder); - } else { - return; - } - - // Do Stream Switching here before loading next bytes. - // Audio stream switching not supported. - if (aRepDecoder == VideoRepDecoder() && - (uint32_t)mVideoSubsegmentIdx < VideoRepDecoder()->GetNumDataByteRanges()) { - nsresult rv = PossiblySwitchDecoder(aRepDecoder); - if (NS_FAILED(rv)) { - LOG("Failed possibly switching decoder rv[0x%x]", rv); - DecodeError(); - return; - } - decoder = VideoRepDecoder(); - } - } - - // Check that decoder is valid. - if (!decoder || (decoder != AudioRepDecoder() && - decoder != VideoRepDecoder())) { - LOG("Invalid decoder [%p]: video idx [%d] audio idx [%d]", - decoder.get(), AudioRepDecoder(), VideoRepDecoder()); - DecodeError(); - return; - } - - // Before loading, note the index of the decoder which will downloaded the - // next video subsegment. - if (decoder == VideoRepDecoder()) { - if (mVideoSubsegmentLoads.IsEmpty() || - (uint32_t)mVideoSubsegmentIdx >= mVideoSubsegmentLoads.Length()) { - LOG("Appending decoder [%d] [%p] to mVideoSubsegmentLoads at index " - "[%d] before load; mVideoSubsegmentIdx[%d].", - mVideoRepDecoderIdx, VideoRepDecoder(), - mVideoSubsegmentLoads.Length(), mVideoSubsegmentIdx); - mVideoSubsegmentLoads.AppendElement(mVideoRepDecoderIdx); - } else { - // Change an existing load, and keep subsequent entries to help - // determine if subsegments are cached already. - LOG("Setting decoder [%d] [%p] in mVideoSubsegmentLoads at index " - "[%d] before load; mVideoSubsegmentIdx[%d].", - mVideoRepDecoderIdx, VideoRepDecoder(), - mVideoSubsegmentIdx, mVideoSubsegmentIdx); - mVideoSubsegmentLoads[mVideoSubsegmentIdx] = mVideoRepDecoderIdx; - } - LOG("Notifying switch decided for video subsegment [%d]", - mVideoSubsegmentIdx); - mon.NotifyAll(); - } - - // Load the next range of data bytes. If the range is already cached, - // this function will be called again to adaptively download the next - // subsegment. - bool resourceLoaded = false; - if (decoder.get() == AudioRepDecoder()) { - LOG("Requesting load for audio decoder [%p] subsegment [%d].", - decoder.get(), mAudioSubsegmentIdx); - if (mAudioSubsegmentIdx >= decoder->GetNumDataByteRanges()) { - resourceLoaded = true; - } - } else if (decoder.get() == VideoRepDecoder()) { - LOG("Requesting load for video decoder [%p] subsegment [%d].", - decoder.get(), mVideoSubsegmentIdx); - if (mVideoSubsegmentIdx >= decoder->GetNumDataByteRanges()) { - resourceLoaded = true; - } - } - if (resourceLoaded) { - ResourceLoaded(); - return; - } - decoder->LoadNextByteRange(); - } else if (aStatus == NS_BINDING_ABORTED) { - LOG("Media download has been cancelled by the user: aStatus[%x]", aStatus); - if (mOwner) { - mOwner->LoadAborted(); - } - return; - } else if (aStatus != NS_BASE_STREAM_CLOSED) { - LOG("Network error trying to download MPD: aStatus [%x].", aStatus); - NetworkError(); - } -} - -void -DASHDecoder::LoadAborted() -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - - if (!mNotifiedLoadAborted && mOwner) { - LOG1("Load Aborted! Notifying media element."); - mOwner->LoadAborted(); - mNotifiedLoadAborted = true; - } -} - -void -DASHDecoder::Suspend() -{ - MOZ_ASSERT(NS_IsMainThread()); - // Suspend MPD download if not yet complete. - if (!mMPDManager && mResource) { - LOG1("Suspending MPD download."); - mResource->Suspend(true); - return; - } - - // Otherwise, forward |Suspend| to active rep decoders. - if (AudioRepDecoder()) { - LOG("Suspending download for audio decoder [%p].", AudioRepDecoder()); - AudioRepDecoder()->Suspend(); - } - if (VideoRepDecoder()) { - LOG("Suspending download for video decoder [%p].", VideoRepDecoder()); - VideoRepDecoder()->Suspend(); - } -} - -void -DASHDecoder::Resume(bool aForceBuffering) -{ - MOZ_ASSERT(NS_IsMainThread()); - // Resume MPD download if not yet complete. - if (!mMPDManager) { - if (mResource) { - LOG1("Resuming MPD download."); - mResource->Resume(); - } - if (aForceBuffering) { - ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); - if (mDecoderStateMachine) { - mDecoderStateMachine->StartBuffering(); - } - } - } - - // Otherwise, forward |Resume| to active rep decoders. - if (AudioRepDecoder()) { - LOG("Resuming download for audio decoder [%p].", AudioRepDecoder()); - AudioRepDecoder()->Resume(aForceBuffering); - } - if (VideoRepDecoder()) { - LOG("Resuming download for video decoder [%p].", VideoRepDecoder()); - VideoRepDecoder()->Resume(aForceBuffering); - } -} - -void -DASHDecoder::Shutdown() -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - - LOG1("Shutting down."); - - // Notify reader of shutdown first. - if (mDASHReader) { - mDASHReader->NotifyDecoderShuttingDown(); - } - - // Call parent class shutdown. - MediaDecoder::Shutdown(); - NS_ENSURE_TRUE_VOID(mShuttingDown); - - // Shutdown reader thread if not already done. - if (mMPDReaderThread) { - nsresult rv = mMPDReaderThread->Shutdown(); - NS_ENSURE_SUCCESS_VOID(rv); - mMPDReaderThread = nullptr; - } - - // Forward to sub-decoders. - for (uint i = 0; i < mAudioRepDecoders.Length(); i++) { - if (mAudioRepDecoders[i]) { - mAudioRepDecoders[i]->Shutdown(); - } - } - for (uint i = 0; i < mVideoRepDecoders.Length(); i++) { - if (mVideoRepDecoders[i]) { - mVideoRepDecoders[i]->Shutdown(); - } - } -} - -void -DASHDecoder::DecodeError() -{ - if (NS_IsMainThread()) { - MediaDecoder::DecodeError(); - } else { - nsCOMPtr event = - NS_NewRunnableMethod(this, &MediaDecoder::DecodeError); - nsresult rv = NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); - if (NS_FAILED(rv)) { - LOG("Error dispatching DecodeError event to main thread: rv[%x]", rv); - } - } -} - -void -DASHDecoder::OnReadMetadataCompleted(DASHRepDecoder* aRepDecoder) -{ - if (mShuttingDown) { - LOG1("Shutting down! Ignoring OnReadMetadataCompleted()."); - return; - } - - NS_ASSERTION(aRepDecoder, "aRepDecoder is null!"); - NS_ASSERTION(OnDecodeThread(), "Should be on decode thread."); - - LOG("Metadata loaded for decoder[%p]", aRepDecoder); - - // Decrement audio|video metadata read counter and get ref to active decoder. - nsRefPtr activeDecoder; - { - ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); - for (uint32_t i = 0; i < mAudioRepDecoders.Length(); i++) { - if (aRepDecoder == mAudioRepDecoders[i]) { - --mAudioMetadataReadCount; - break; - } - } - for (uint32_t i = 0; i < mVideoRepDecoders.Length(); i++) { - if (aRepDecoder == mVideoRepDecoders[i]) { - --mVideoMetadataReadCount; - break; - } - } - } - - // Once all metadata is downloaded for audio|video decoders, start loading - // data for the active decoder. - if (mAudioMetadataReadCount == 0 && mVideoMetadataReadCount == 0) { - if (AudioRepDecoder()) { - LOG("Dispatching load event for audio decoder [%p]", AudioRepDecoder()); - nsCOMPtr event = - NS_NewRunnableMethod(AudioRepDecoder(), &DASHRepDecoder::LoadNextByteRange); - nsresult rv = NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); - if (NS_FAILED(rv)) { - LOG("Error dispatching audio decoder [%p] load event to main thread: " - "rv[%x]", AudioRepDecoder(), rv); - DecodeError(); - return; - } - } - if (VideoRepDecoder()) { - LOG("Dispatching load event for video decoder [%p]", VideoRepDecoder()); - // Add decoder to subsegment load history. - NS_ASSERTION(mVideoSubsegmentLoads.IsEmpty(), - "No subsegment loads should be recorded at this stage!"); - NS_ASSERTION(mVideoSubsegmentIdx == 0, - "Current subsegment should be 0 at this stage!"); - LOG("Appending decoder [%d] [%p] to mVideoSubsegmentLoads at index " - "[%d] before load; mVideoSubsegmentIdx[%d].", - mVideoRepDecoderIdx, VideoRepDecoder(), - (uint32_t)mVideoSubsegmentLoads.Length(), mVideoSubsegmentIdx); - mVideoSubsegmentLoads.AppendElement(mVideoRepDecoderIdx); - - nsCOMPtr event = - NS_NewRunnableMethod(VideoRepDecoder(), &DASHRepDecoder::LoadNextByteRange); - nsresult rv = NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); - if (NS_FAILED(rv)) { - LOG("Error dispatching video decoder [%p] load event to main thread: " - "rv[%x]", VideoRepDecoder(), rv); - DecodeError(); - return; - } - } - } -} - -nsresult -DASHDecoder::PossiblySwitchDecoder(DASHRepDecoder* aRepDecoder) -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - NS_ENSURE_FALSE(mShuttingDown, NS_ERROR_UNEXPECTED); - NS_ENSURE_TRUE(aRepDecoder == VideoRepDecoder(), NS_ERROR_ILLEGAL_VALUE); - NS_ASSERTION((uint32_t)mVideoRepDecoderIdx < mVideoRepDecoders.Length(), - "Index for video decoder is out of bounds!"); - NS_ASSERTION((uint32_t)mVideoSubsegmentIdx < VideoRepDecoder()->GetNumDataByteRanges(), - "Can't switch to a byte range out of bounds."); - ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); - - // Now, determine if and which decoder to switch to. - // XXX This download rate is averaged over time, and only refers to the bytes - // downloaded for the video decoder. A running average would be better, and - // something that includes all downloads. But this will do for now. - NS_ASSERTION(VideoRepDecoder(), "Video decoder should not be null."); - NS_ASSERTION(VideoRepDecoder()->GetResource(), - "Video resource should not be null"); - bool reliable = false; - double downloadRate = 0; - { - MutexAutoLock lock(mStatisticsLock); - downloadRate = mVideoStatistics->GetRate(&reliable); - } - uint32_t bestRepIdx = UINT32_MAX; - bool noRepAvailable = !mMPDManager->GetBestRepForBandwidth(mVideoAdaptSetIdx, - downloadRate, - bestRepIdx); - LOG("downloadRate [%0.2f kbps] reliable [%s] bestRepIdx [%d] noRepAvailable [%s]", - downloadRate/1000.0, (reliable ? "yes" : "no"), bestRepIdx, - (noRepAvailable ? "yes" : "no")); - - // If there is a higher bitrate stream that can be downloaded with the - // current estimated bandwidth, step up to the next stream, for a graceful - // increase in quality. - uint32_t toDecoderIdx = mVideoRepDecoderIdx; - if (bestRepIdx > toDecoderIdx) { - toDecoderIdx = std::min(toDecoderIdx+1, mVideoRepDecoders.Length()-1); - } else if (toDecoderIdx < bestRepIdx) { - // If the bitrate is too much for the current bandwidth, just use that - // stream directly. - toDecoderIdx = bestRepIdx; - } - - // Upgrade |toDecoderIdx| if a better subsegment was previously downloaded and - // is still cached. - if (mVideoSubsegmentIdx < mVideoSubsegmentLoads.Length() && - toDecoderIdx < mVideoSubsegmentLoads[mVideoSubsegmentIdx]) { - // Check if the subsegment is cached. - uint32_t betterRepIdx = mVideoSubsegmentLoads[mVideoSubsegmentIdx]; - if (mVideoRepDecoders[betterRepIdx]->IsSubsegmentCached(mVideoSubsegmentIdx)) { - toDecoderIdx = betterRepIdx; - } - } - - NS_ENSURE_TRUE(toDecoderIdx < mVideoRepDecoders.Length(), - NS_ERROR_ILLEGAL_VALUE); - - // Notify reader and sub decoders and do the switch. - if (toDecoderIdx != (uint32_t)mVideoRepDecoderIdx) { - LOG("*** Switching video decoder from [%d] [%p] to [%d] [%p] at " - "subsegment [%d]", mVideoRepDecoderIdx, VideoRepDecoder(), - toDecoderIdx, mVideoRepDecoders[toDecoderIdx].get(), - mVideoSubsegmentIdx); - - // Tell main reader to switch subreaders at |subsegmentIdx| - equates to - // switching data source for reading. - mDASHReader->RequestVideoReaderSwitch(mVideoRepDecoderIdx, toDecoderIdx, - mVideoSubsegmentIdx); - // Notify decoder it is about to be switched. - mVideoRepDecoders[mVideoRepDecoderIdx]->PrepareForSwitch(); - // Switch video decoders - equates to switching download source. - mVideoRepDecoderIdx = toDecoderIdx; - } - - return NS_OK; -} - -nsresult -DASHDecoder::Seek(double aTime) -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - NS_ENSURE_FALSE(mShuttingDown, NS_ERROR_UNEXPECTED); - - LOG("Seeking to [%.2fs]", aTime); - - { - ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); - // Set the seeking flag, so that when current subsegments download (if - // any), the next subsegment will not be downloaded. - mSeeking = true; - } - - return MediaDecoder::Seek(aTime); -} - -void -DASHDecoder::NotifySeekInVideoSubsegment(int32_t aRepDecoderIdx, - int32_t aSubsegmentIdx) -{ - NS_ASSERTION(OnDecodeThread(), "Should be on decode thread."); - - ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); - - NS_ASSERTION(0 <= aRepDecoderIdx && - aRepDecoderIdx < mVideoRepDecoders.Length(), - "Video decoder index is out of bounds"); - - // Reset current subsegment to match the one being seeked. - mVideoSubsegmentIdx = aSubsegmentIdx; - // Reset current decoder to match the one returned by - // |GetRepIdxForVideoSubsegmentLoad|. - mVideoRepDecoderIdx = aRepDecoderIdx; - - mSeeking = false; - - LOG("Dispatching load for video decoder [%d] [%p]: seek in subsegment [%d]", - mVideoRepDecoderIdx, VideoRepDecoder(), aSubsegmentIdx); - - nsCOMPtr event = - NS_NewRunnableMethod(VideoRepDecoder(), - &DASHRepDecoder::LoadNextByteRange); - nsresult rv = NS_DispatchToMainThread(event); - if (NS_FAILED(rv)) { - LOG("Error dispatching video byte range load: rv[0x%x].", - rv); - NetworkError(); - return; - } -} - -void -DASHDecoder::NotifySeekInAudioSubsegment(int32_t aSubsegmentIdx) -{ - NS_ASSERTION(OnDecodeThread(), "Should be on decode thread."); - - ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); - - // Reset current subsegment to match the one being seeked. - mAudioSubsegmentIdx = aSubsegmentIdx; - - LOG("Dispatching seeking load for audio decoder [%d] [%p]: subsegment [%d]", - mAudioRepDecoderIdx, AudioRepDecoder(), aSubsegmentIdx); - - nsCOMPtr event = - NS_NewRunnableMethod(AudioRepDecoder(), - &DASHRepDecoder::LoadNextByteRange); - nsresult rv = NS_DispatchToMainThread(event); - if (NS_FAILED(rv)) { - LOG("Error dispatching audio byte range load: rv[0x%x].", - rv); - NetworkError(); - return; - } -} - -bool -DASHDecoder::IsDecoderAllowedToDownloadData(DASHRepDecoder* aRepDecoder) -{ - NS_ASSERTION(aRepDecoder, "DASHRepDecoder pointer is null."); - - ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); - LOG("Checking aRepDecoder [%p] with AudioRepDecoder [%p] metadataReadCount " - "[%d] and VideoRepDecoder [%p] metadataReadCount [%d]", - aRepDecoder, AudioRepDecoder(), mAudioMetadataReadCount, - VideoRepDecoder(), mVideoMetadataReadCount); - // Only return true if |aRepDecoder| is active and metadata for all - // representations has been downloaded. - return ((aRepDecoder == AudioRepDecoder() && mAudioMetadataReadCount == 0) || - (aRepDecoder == VideoRepDecoder() && mVideoMetadataReadCount == 0)); -} - -bool -DASHDecoder::IsDecoderAllowedToDownloadSubsegment(DASHRepDecoder* aRepDecoder, - int32_t const aSubsegmentIdx) -{ - NS_ASSERTION(aRepDecoder, "DASHRepDecoder pointer is null."); - - ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); - - // Forbid any downloads until we've been told what subsegment to seek to. - if (mSeeking) { - return false; - } - // Return false if there is still metadata to be downloaded. - if (mAudioMetadataReadCount != 0 || mVideoMetadataReadCount != 0) { - return false; - } - // No audio switching; allow the audio decoder to download all subsegments. - if (aRepDecoder == AudioRepDecoder()) { - return true; - } - - int32_t videoDecoderIdx = GetRepIdxForVideoSubsegmentLoad(aSubsegmentIdx); - if (aRepDecoder == mVideoRepDecoders[videoDecoderIdx]) { - return true; - } - return false; -} - -void -DASHDecoder::SetSubsegmentIndex(DASHRepDecoder* aRepDecoder, - int32_t aSubsegmentIdx) -{ - NS_ASSERTION(0 <= aSubsegmentIdx, - "Subsegment index should not be negative!"); - ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); - if (aRepDecoder == AudioRepDecoder()) { - mAudioSubsegmentIdx = aSubsegmentIdx; - } else if (aRepDecoder == VideoRepDecoder()) { - // If this is called in the context of a Seek, we need to cancel downloads - // from other rep decoders, or all rep decoders if we're not seeking in the - // current subsegment. - // Note: NotifySeekInSubsegment called from DASHReader will already have - // set the current decoder. - mVideoSubsegmentIdx = aSubsegmentIdx; - } -} - -double -DASHDecoder::ComputePlaybackRate(bool* aReliable) -{ - GetReentrantMonitor().AssertCurrentThreadIn(); - MOZ_ASSERT(NS_IsMainThread() || OnStateMachineThread()); - NS_ASSERTION(aReliable, "Bool pointer aRelible should not be null!"); - - // While downloading the MPD, return 0; do not count manifest as media data. - if (mResource && !mMPDManager) { - return 0; - } - - // Once MPD is downloaded, use the rate from the video decoder. - // XXX Not ideal, but since playback rate is used to estimate if we have - // enough data to continue playing, this should be sufficient. - double videoRate = 0; - if (VideoRepDecoder()) { - videoRate = VideoRepDecoder()->ComputePlaybackRate(aReliable); - } - return videoRate; -} - -void -DASHDecoder::UpdatePlaybackRate() -{ - MOZ_ASSERT(NS_IsMainThread() || OnStateMachineThread()); - GetReentrantMonitor().AssertCurrentThreadIn(); - // While downloading the MPD, return silently; playback rate has no meaning - // for the manifest. - if (mResource && !mMPDManager) { - return; - } - // Once MPD is downloaded and audio/video decoder(s) are loading, forward to - // active rep decoders. - if (AudioRepDecoder()) { - AudioRepDecoder()->UpdatePlaybackRate(); - } - if (VideoRepDecoder()) { - VideoRepDecoder()->UpdatePlaybackRate(); - } -} - -void -DASHDecoder::NotifyPlaybackStarted() -{ - GetReentrantMonitor().AssertCurrentThreadIn(); - // While downloading the MPD, return silently; playback rate has no meaning - // for the manifest. - if (mResource && !mMPDManager) { - return; - } - // Once MPD is downloaded and audio/video decoder(s) are loading, forward to - // active rep decoders. - if (AudioRepDecoder()) { - AudioRepDecoder()->NotifyPlaybackStarted(); - } - if (VideoRepDecoder()) { - VideoRepDecoder()->NotifyPlaybackStarted(); - } -} - -void -DASHDecoder::NotifyPlaybackStopped() -{ - GetReentrantMonitor().AssertCurrentThreadIn(); - // While downloading the MPD, return silently; playback rate has no meaning - // for the manifest. - if (mResource && !mMPDManager) { - return; - } - // Once // Once MPD is downloaded and audio/video decoder(s) are loading, forward to - // active rep decoders. - if (AudioRepDecoder()) { - AudioRepDecoder()->NotifyPlaybackStopped(); - } - if (VideoRepDecoder()) { - VideoRepDecoder()->NotifyPlaybackStopped(); - } -} - -MediaDecoder::Statistics -DASHDecoder::GetStatistics() -{ - MOZ_ASSERT(NS_IsMainThread() || OnStateMachineThread()); - Statistics result; - - ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); - if (mResource && !mMPDManager) { - return MediaDecoder::GetStatistics(); - } - - // XXX Use video decoder and its media resource to get stats. - // This assumes that the following getter functions are getting relevant - // video data only. - if (VideoRepDecoder() && VideoRepDecoder()->GetResource()) { - MediaResource *resource = VideoRepDecoder()->GetResource(); - // Note: this rate reflects the rate observed for all video downloads. - result.mDownloadRate = - resource->GetDownloadRate(&result.mDownloadRateReliable); - result.mDownloadPosition = - resource->GetCachedDataEnd(VideoRepDecoder()->mDecoderPosition); - result.mTotalBytes = resource->GetLength(); - result.mPlaybackRate = ComputePlaybackRate(&result.mPlaybackRateReliable); - result.mDecoderPosition = VideoRepDecoder()->mDecoderPosition; - result.mPlaybackPosition = VideoRepDecoder()->mPlaybackPosition; - } - else { - result.mDownloadRate = 0; - result.mDownloadRateReliable = true; - result.mPlaybackRate = 0; - result.mPlaybackRateReliable = true; - result.mDecoderPosition = 0; - result.mPlaybackPosition = 0; - result.mDownloadPosition = 0; - result.mTotalBytes = 0; - } - - return result; -} - -bool -DASHDecoder::IsDataCachedToEndOfResource() -{ - NS_ASSERTION(!mShuttingDown, "Don't call during shutdown!"); - GetReentrantMonitor().AssertCurrentThreadIn(); - - if (!mMPDManager || !mResource) { - return false; - } - - bool resourceIsLoaded = false; - if (VideoRepDecoder()) { - resourceIsLoaded = VideoRepDecoder()->IsDataCachedToEndOfResource(); - LOG("IsDataCachedToEndOfResource for VideoRepDecoder %p = %s", - VideoRepDecoder(), resourceIsLoaded ? "yes" : "no"); - } - if (AudioRepDecoder()) { - bool isAudioResourceLoaded = - AudioRepDecoder()->IsDataCachedToEndOfResource(); - LOG("IsDataCachedToEndOfResource for AudioRepDecoder %p = %s", - AudioRepDecoder(), isAudioResourceLoaded ? "yes" : "no"); - resourceIsLoaded = resourceIsLoaded && isAudioResourceLoaded; - } - - return resourceIsLoaded; -} - -void -DASHDecoder::StopProgressUpdates() -{ - MOZ_ASSERT(OnStateMachineThread() || OnDecodeThread()); - GetReentrantMonitor().AssertCurrentThreadIn(); - mIgnoreProgressData = true; - for (uint32_t i = 0; i < mVideoRepDecoders.Length(); i++) { - mVideoRepDecoders[i]->StopProgressUpdates(); - } - for (uint32_t i = 0; i < mAudioRepDecoders.Length(); i++) { - mAudioRepDecoders[i]->StopProgressUpdates(); - } -} - -void -DASHDecoder::StartProgressUpdates() -{ - MOZ_ASSERT(OnStateMachineThread() || OnDecodeThread()); - GetReentrantMonitor().AssertCurrentThreadIn(); - mIgnoreProgressData = false; - for (uint32_t i = 0; i < mVideoRepDecoders.Length(); i++) { - mVideoRepDecoders[i]->StartProgressUpdates(); - } - for (uint32_t i = 0; i < mAudioRepDecoders.Length(); i++) { - mAudioRepDecoders[i]->StartProgressUpdates(); - } -} - -int32_t -DASHDecoder::GetRepIdxForVideoSubsegmentLoadAfterSeek(int32_t aSubsegmentIndex) -{ - NS_ASSERTION(OnDecodeThread(), "Should be on decode thread."); - ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); - // Should not be requesting decoder index for the first subsegment, nor any - // after the final subsegment. - if (aSubsegmentIndex < 1 || - aSubsegmentIndex >= VideoRepDecoder()->GetNumDataByteRanges()) { - return -1; - } - // Wait if we are still loading the subsegment previous to the one that was - // queried. Note: |mVideoSubsegmentIdx| should have been updated to reflect - // loads of the seeked subsegment before |DASHRepReader|::|Seek| was called, - // i.e. before this function was called. - while (mVideoSubsegmentIdx == aSubsegmentIndex-1) { - LOG("Waiting for switching decision for video subsegment [%d].", - aSubsegmentIndex); - mon.Wait(); - } - - return mVideoSubsegmentLoads[aSubsegmentIndex]; -} - -} // namespace mozilla diff --git a/content/media/dash/DASHDecoder.h b/content/media/dash/DASHDecoder.h deleted file mode 100644 index adc9dfd453e5..000000000000 --- a/content/media/dash/DASHDecoder.h +++ /dev/null @@ -1,412 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ - -/* This Source Code Form Is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* DASH - Dynamic Adaptive Streaming over HTTP - * - * DASH is an adaptive bitrate streaming technology where a multimedia file is - * partitioned into one or more segments and delivered to a client using HTTP. - * - * see DASHDecoder.cpp for info on DASH interaction with the media engine.*/ - -#if !defined(DASHDecoder_h_) -#define DASHDecoder_h_ - -#include "nsTArray.h" -#include "nsIURI.h" -#include "nsITimer.h" -#include "MediaDecoder.h" -#include "DASHReader.h" - -namespace mozilla { -namespace net { -class IMPDManager; -class nsDASHMPDParser; -class Representation; -}// net - -class DASHRepDecoder; - -class DASHDecoder : public MediaDecoder -{ -public: - typedef class mozilla::net::IMPDManager IMPDManager; - typedef class mozilla::net::nsDASHMPDParser nsDASHMPDParser; - typedef class mozilla::net::Representation Representation; - - // XXX Arbitrary max file size for MPD. 50MB seems generously large. - static const uint32_t DASH_MAX_MPD_SIZE = 50*1024*1024; - - DASHDecoder(); - ~DASHDecoder(); - - MediaDecoder* Clone() MOZ_OVERRIDE { - if (!IsDASHEnabled()) { - return nullptr; - } - return new DASHDecoder(); - } - - // Creates a single state machine for all stream decoders. - // Called from Load on the main thread only. - MediaDecoderStateMachine* CreateStateMachine(); - - // Loads the MPD from the network and subsequently loads the media streams. - // Called from the main thread only. - virtual nsresult Load(nsIStreamListener** aListener, - MediaDecoder* aCloneDonor) MOZ_OVERRIDE; - - // Notifies download of MPD file has ended. - // Called on the main thread only. - void NotifyDownloadEnded(nsresult aStatus); - - // Notification from |DASHReader| that a seek has occurred in - // |aSubsegmentIdx|. Passes notification onto subdecoder which downloaded - // the subsegment already, if download is in the past. Otherwise, it returns. - void NotifySeekInVideoSubsegment(int32_t aRepDecoderIdx, - int32_t aSubsegmentIdx); - void NotifySeekInAudioSubsegment(int32_t aSubsegmentIdx); - - // Notifies that a byte range download has ended. As per the DASH spec, this - // allows for stream switching at the boundaries of the byte ranges. - // Called on the main thread only. - void NotifyDownloadEnded(DASHRepDecoder* aRepDecoder, - nsresult aStatus, - int32_t const aSubsegmentIdx); - - // Notification from an |MediaDecoderReader| class that metadata has been - // read. Declared here to allow overloading. - void OnReadMetadataCompleted() MOZ_OVERRIDE { } - - // Seeks to aTime in seconds - nsresult Seek(double aTime) MOZ_OVERRIDE; - - // Notification from |DASHRepDecoder| that a metadata has been read. - // |DASHDecoder| will initiate load of data bytes for active audio/video - // decoders. Called on the decode thread. - void OnReadMetadataCompleted(DASHRepDecoder* aRepDecoder); - - // Returns true if all subsegments from current decode position are - // downloaded. Must be in monitor. Call from any thread. - bool IsDataCachedToEndOfResource() MOZ_OVERRIDE; - - // Refers to downloading data bytes, i.e. non metadata. - // Returns true if |aRepDecoder| is an active audio or video sub decoder AND - // if metadata for all audio or video decoders has been read. - // Could be called from any thread; enters decoder monitor. - bool IsDecoderAllowedToDownloadData(DASHRepDecoder* aRepDecoder); - - // Refers to downloading data bytes during SEEKING. - // Returns true if |aRepDecoder| is the active audio sub decoder, OR if - // it is a video decoder and is allowed to download this subsegment. - // Returns false if there is still some metadata to download. - // Could be called from any thread; enters decoder monitor. - bool IsDecoderAllowedToDownloadSubsegment(DASHRepDecoder* aRepDecoder, - int32_t const aSubsegmentIdx); - - // Determines if rep/sub decoders should be switched, and if so switches - // them. Notifies |DASHReader| if and when it should switch readers. - // Returns a pointer to the new active decoder. - // Called on the main thread. - nsresult PossiblySwitchDecoder(DASHRepDecoder* aRepDecoder); - - // Sets the byte range index for audio|video downloads. Will only increment - // for current active decoders. Could be called from any thread. - // Requires monitor because of write to |mAudioSubsegmentIdx| or - // |mVideoSubsegmentIdx|. - void SetSubsegmentIndex(DASHRepDecoder* aRepDecoder, - int32_t aSubsegmentIdx); - - // Suspend any media downloads that are in progress. Called by the - // media element when it is sent to the bfcache, or when we need - // to throttle the download. Call on the main thread only. This can - // be called multiple times, there's an internal "suspend count". - void Suspend() MOZ_OVERRIDE; - - // Resume any media downloads that have been suspended. Called by the - // media element when it is restored from the bfcache, or when we need - // to stop throttling the download. Call on the main thread only. - // The download will only actually resume once as many Resume calls - // have been made as Suspend calls. When aForceBuffering is true, - // we force the decoder to go into buffering state before resuming - // playback. - void Resume(bool aForceBuffering) MOZ_OVERRIDE; -private: - // Increments the byte range index for audio|video downloads. Will only - // increment for current active decoders. Could be called from any thread. - // Requires monitor because of write to |mAudioSubsegmentIdx| or - // |mVideoSubsegmentIdx|. - void IncrementSubsegmentIndex(DASHRepDecoder* aRepDecoder) - { - ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); - if (aRepDecoder == AudioRepDecoder()) { - mAudioSubsegmentIdx++; - } else if (aRepDecoder == VideoRepDecoder()) { - mVideoSubsegmentIdx++; - } - } -public: - // Gets the byte range index for audio|video downloads. Will only increment - // for current active decoders. Could be called from any thread. Will enter - // monitor for read access off the decode thread. - int32_t GetSubsegmentIndex(DASHRepDecoder* aRepDecoder) - { - ReentrantMonitorConditionallyEnter mon(!OnDecodeThread(), - GetReentrantMonitor()); - if (aRepDecoder == AudioRepDecoder()) { - return mAudioSubsegmentIdx; - } else if (aRepDecoder == VideoRepDecoder()) { - return mVideoSubsegmentIdx; - } - return (-1); - } - - // Returns the total number of subsegments that have been loaded. Will enter - // monitor for read access off the decode thread. - uint32_t GetNumSubsegmentLoads() { - ReentrantMonitorConditionallyEnter mon(!OnDecodeThread(), - GetReentrantMonitor()); - return mVideoSubsegmentLoads.Length(); - } - - // Returns the index of the rep decoder used to load a subsegment. Will enter - // monitor for read access off the decode thread. - int32_t GetRepIdxForVideoSubsegmentLoad(int32_t aSubsegmentIdx) - { - NS_ASSERTION(0 <= aSubsegmentIdx, "Subsegment index should not be negative."); - ReentrantMonitorConditionallyEnter mon(!OnDecodeThread(), - GetReentrantMonitor()); - if ((uint32_t)aSubsegmentIdx < mVideoSubsegmentLoads.Length()) { - return mVideoSubsegmentLoads[aSubsegmentIdx]; - } else { - // If it hasn't been downloaded yet, use the lowest bitrate decoder. - return 0; - } - } - - // Returns the index of the rep decoder used to load a subsegment, after a - // seek. Called on the decode thread, and will block if the subsegment - // previous to the one specified has not yet been loaded. This ensures that - // |DASHDecoder| has had a chance to determine which decoder should load the - // next subsegment, in the case where |DASHRepReader|::|DecodeToTarget| has - // read all the data for the current subsegment from the cache, and needs to - // know which reader (including itself) to use next. - int32_t GetRepIdxForVideoSubsegmentLoadAfterSeek(int32_t aSubsegmentIndex); - - int32_t GetSwitchCountAtVideoSubsegment(int32_t aSubsegmentIdx) - { - ReentrantMonitorConditionallyEnter mon(!OnDecodeThread(), - GetReentrantMonitor()); - NS_ASSERTION(0 <= aSubsegmentIdx, "Subsegment index should not be negative."); - if (aSubsegmentIdx == 0) { - // Do the zeroeth switch next. - return 0; - } - int32_t switchCount = 0; - for (uint32_t i = 1; - i < mVideoSubsegmentLoads.Length() && - i <= (uint32_t)aSubsegmentIdx; - i++) { - if (mVideoSubsegmentLoads[i-1] != mVideoSubsegmentLoads[i]) { - switchCount++; - } - } - return switchCount; - } - - // The actual playback rate computation. The monitor must be held. - // XXX Computes playback for the current video rep decoder only. - double ComputePlaybackRate(bool* aReliable) MOZ_OVERRIDE; - - // Something has changed that could affect the computed playback rate, - // so recompute it. The monitor must be held. Will be forwarded to current - // audio and video rep decoders. - void UpdatePlaybackRate() MOZ_OVERRIDE; - - // Stop updating the bytes downloaded for progress notifications. Called - // when seeking to prevent wild changes to the progress notification. - // Forwarded to sub-decoders. Must be called with the decoder monitor held. - void StopProgressUpdates() MOZ_OVERRIDE; - - // Allow updating the bytes downloaded for progress notifications. - // Forwarded to sub-decoders. Must be called with the decoder monitor held. - void StartProgressUpdates() MOZ_OVERRIDE; - - // Used to estimate rates of data passing through the decoder's channel. - // Records activity starting on the channel. The monitor must be held. - virtual void NotifyPlaybackStarted() MOZ_OVERRIDE; - - // Used to estimate rates of data passing through the decoder's channel. - // Records activity stopping on the channel. The monitor must be held. - virtual void NotifyPlaybackStopped() MOZ_OVERRIDE; - - // Return statistics. This is used for progress events and other things. - // This can be called from any thread. It's only a snapshot of the - // current state, since other threads might be changing the state - // at any time. - // XXX Stats are calculated based on the current video rep decoder, with the - // exception of download rate, which is based on all video downloads. - virtual Statistics GetStatistics() MOZ_OVERRIDE; - - // Drop reference to state machine and tell sub-decoders to do the same. - // Only called during shutdown dance, on main thread only. - void ReleaseStateMachine(); - - // Overridden to forward |Shutdown| to sub-decoders. - // Called on the main thread only. - void Shutdown(); - - // Called by sub-decoders when load has been aborted. Will notify media - // element only once. Called on the main thread only. - void LoadAborted(); - - // Notifies the element that decoding has failed. On main thread, call is - // forwarded to |MediaDecoder|::|Error| immediately. On other threads, - // a call is dispatched for execution on the main thread. - void DecodeError(); - -private: - // Reads the MPD data from resource to a byte stream. - // Called on the MPD reader thread. - void ReadMPDBuffer(); - - // Called when MPD data is completely read. - // On the main thread. - void OnReadMPDBufferCompleted(); - - // Parses the copied MPD byte stream. - // On the main thread: DOM APIs complain when off the main thread. - nsresult ParseMPDBuffer(); - - // Creates the sub-decoders for a |Representation|, i.e. media streams. - // On the main thread. - nsresult CreateRepDecoders(); - - // Creates audio/video decoders for individual |Representation|s. - // On the main thread. - nsresult CreateAudioRepDecoder(nsIURI* aUrl, Representation const * aRep); - nsresult CreateVideoRepDecoder(nsIURI* aUrl, Representation const * aRep); - - // Get audio sub-decoder for current audio |Representation|. Will return - // nullptr for out of range indexes. - // Enters monitor for read access off the decode thread. - // XXX Note: Although an array of audio decoders is provided, audio stream - // switching is not yet supported. - DASHRepDecoder* AudioRepDecoder() { - ReentrantMonitorConditionallyEnter mon(!OnDecodeThread(), - GetReentrantMonitor()); - if (0 == mAudioRepDecoders.Length()) { - return nullptr; - } - NS_ENSURE_TRUE((uint32_t)mAudioRepDecoderIdx < mAudioRepDecoders.Length(), - nullptr); - if (mAudioRepDecoderIdx < 0) { - return nullptr; - } else { - return mAudioRepDecoders[mAudioRepDecoderIdx]; - } - } - - // Get video sub-decoder for current video |Representation|. Will return - // nullptr for out of range indexes. - // Enters monitor for read access off the decode thread. - DASHRepDecoder* VideoRepDecoder() { - ReentrantMonitorConditionallyEnter mon(!OnDecodeThread(), - GetReentrantMonitor()); - if (0 == mVideoRepDecoders.Length()) { - return nullptr; - } - NS_ENSURE_TRUE((uint32_t)mVideoRepDecoderIdx < mVideoRepDecoders.Length(), - nullptr); - if (mVideoRepDecoderIdx < 0) { - return nullptr; - } else { - return mVideoRepDecoders[mVideoRepDecoderIdx]; - } - } - - // Creates audio/video resources for individual |Representation|s. - // On the main thread. - MediaResource* CreateAudioSubResource(nsIURI* aUrl, - MediaDecoder* aAudioDecoder); - MediaResource* CreateVideoSubResource(nsIURI* aUrl, - MediaDecoder* aVideoDecoder); - - // Creates an http channel for a |Representation|. - // On the main thread. - nsresult CreateSubChannel(nsIURI* aUrl, nsIChannel** aChannel); - - // Loads the media |Representations|, i.e. the media streams. - // On the main thread. - nsresult LoadRepresentations(); - - // True when media element has already been notified of an aborted load. - bool mNotifiedLoadAborted; - - // Ptr for the MPD data. - nsAutoArrayPtr mBuffer; - // Length of the MPD data. - uint32_t mBufferLength; - // Ptr to the MPD Reader thread. - nsCOMPtr mMPDReaderThread; - // Document Principal. - nsCOMPtr mPrincipal; - - // MPD Manager provides access to the MPD information. - nsAutoPtr mMPDManager; - - // Main reader object; manages all sub-readers for |Representation|s. Owned by - // state machine; destroyed in state machine's destructor. - DASHReader* mDASHReader; - - // Sub-decoder vars. Note: For all following members, the decode monitor - // should be held for write access on decode thread, and all read/write off - // the decode thread. - - // Index of the video |AdaptationSet|. - int32_t mVideoAdaptSetIdx; - - // Indexes for the current audio and video decoders. - int32_t mAudioRepDecoderIdx; - int32_t mVideoRepDecoderIdx; - - // Array of pointers for the |Representation|s in the audio/video - // |AdaptationSet|. - nsTArray > mAudioRepDecoders; - nsTArray > mVideoRepDecoders; - - // Current index of subsegments downloaded for audio/video decoder. - int32_t mAudioSubsegmentIdx; - int32_t mVideoSubsegmentIdx; - - // Count for the number of readers which have called |OnReadMetadataCompleted|. - // Initialised to 0; incremented for every decoder which has |Load| called; - // and decremented for every call to |OnReadMetadataCompleted|. When it is - // zero again, all metadata has been read for audio or video, and data bytes - // can be downloaded. - uint32_t mAudioMetadataReadCount; - uint32_t mVideoMetadataReadCount; - - // Array records the index of the decoder/Representation which loaded each - // subsegment. - nsTArray mVideoSubsegmentLoads; - - // True when Seek is called; will block any downloads until - // |NotifySeekInSubsegment| is called, which will set it to false, and will - // start a new series of downloads from the seeked subsegment. - bool mSeeking; - - // Mutex for statistics. - Mutex mStatisticsLock; - // Stores snapshot statistics, such as download rate, for the audio|video - // data streams. |mStatisticsLock| must be locked for access. - nsRefPtr mAudioStatistics; - nsRefPtr mVideoStatistics; -}; - -} // namespace mozilla - -#endif diff --git a/content/media/dash/DASHReader.cpp b/content/media/dash/DASHReader.cpp deleted file mode 100644 index da3b5f96eb80..000000000000 --- a/content/media/dash/DASHReader.cpp +++ /dev/null @@ -1,674 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ - -/* This Source Code Form Is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* DASH - Dynamic Adaptive Streaming over HTTP - * - * DASH is an adaptive bitrate streaming technology where a multimedia file is - * partitioned into one or more segments and delivered to a client using HTTP. - * - * see DASHDecoder.cpp for info on DASH interaction with the media engine.*/ - -#include "mozilla/dom/TimeRanges.h" -#include "VideoFrameContainer.h" -#include "AbstractMediaDecoder.h" -#include "DASHReader.h" -#include "DASHDecoder.h" -#include - -namespace mozilla { - -#ifdef PR_LOGGING -PRLogModuleInfo* gDASHReaderLog; -#define LOG(msg, ...) PR_LOG(gDASHReaderLog, PR_LOG_DEBUG, \ - ("%p [DASHReader] " msg, this, __VA_ARGS__)) -#define LOG1(msg) PR_LOG(gDASHReaderLog, PR_LOG_DEBUG, \ - ("%p [DASHReader] " msg, this)) -#else -#define LOG(msg, ...) -#define LOG1(msg) -#endif - -DASHReader::DASHReader(AbstractMediaDecoder* aDecoder) : - MediaDecoderReader(aDecoder), - mReadMetadataMonitor("media.dashreader.readmetadata"), - mReadyToReadMetadata(false), - mDecoderIsShuttingDown(false), - mAudioReader(this), - mVideoReader(this), - mAudioReaders(this), - mVideoReaders(this), - mSwitchVideoReaders(false), - mSwitchCount(-1) -{ - MOZ_COUNT_CTOR(DASHReader); -#ifdef PR_LOGGING - if (!gDASHReaderLog) { - gDASHReaderLog = PR_NewLogModule("DASHReader"); - } -#endif -} - -DASHReader::~DASHReader() -{ - MOZ_COUNT_DTOR(DASHReader); -} - -nsresult -DASHReader::ResetDecode() -{ - MediaDecoderReader::ResetDecode(); - nsresult rv; - for (uint i = 0; i < mAudioReaders.Length(); i++) { - rv = mAudioReaders[i]->ResetDecode(); - NS_ENSURE_SUCCESS(rv, rv); - } - for (uint i = 0; i < mVideoReaders.Length(); i++) { - rv = mVideoReaders[i]->ResetDecode(); - NS_ENSURE_SUCCESS(rv, rv); - } - return NS_OK; -} - -nsresult -DASHReader::Init(MediaDecoderReader* aCloneDonor) -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - - ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); - NS_ASSERTION(mAudioReaders.Length() != 0 && mVideoReaders.Length() != 0, - "Audio and video readers should exist already."); - - nsresult rv; - for (uint i = 0; i < mAudioReaders.Length(); i++) { - rv = mAudioReaders[i]->Init(nullptr); - NS_ENSURE_SUCCESS(rv, rv); - } - for (uint i = 0; i < mVideoReaders.Length(); i++) { - rv = mVideoReaders[i]->Init(nullptr); - NS_ENSURE_SUCCESS(rv, rv); - } - return NS_OK; -} - -void -DASHReader::AddAudioReader(DASHRepReader* aAudioReader) -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - NS_ENSURE_TRUE_VOID(aAudioReader); - - ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); - - mAudioReaders.AppendElement(aAudioReader); - // XXX For now, just pick the first reader to be default. - if (!mAudioReader) - mAudioReader = aAudioReader; -} - -void -DASHReader::AddVideoReader(DASHRepReader* aVideoReader) -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - NS_ENSURE_TRUE_VOID(aVideoReader); - - ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); - - mVideoReaders.AppendElement(aVideoReader); - // XXX For now, just pick the first reader to be default. - if (!mVideoReader) - mVideoReader = aVideoReader; -} - -bool -DASHReader::HasAudio() -{ - NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); - return mAudioReader ? mAudioReader->HasAudio() : false; -} - -bool -DASHReader::HasVideo() -{ - NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); - return mVideoReader ? mVideoReader->HasVideo() : false; -} - -int64_t -DASHReader::VideoQueueMemoryInUse() -{ - ReentrantMonitorConditionallyEnter mon(!mDecoder->OnDecodeThread(), - mDecoder->GetReentrantMonitor()); - return VideoQueueMemoryInUse(); -} - -int64_t -DASHReader::AudioQueueMemoryInUse() -{ - ReentrantMonitorConditionallyEnter mon(!mDecoder->OnDecodeThread(), - mDecoder->GetReentrantMonitor()); - return AudioQueueMemoryInUse(); -} - -bool -DASHReader::DecodeVideoFrame(bool &aKeyframeSkip, - int64_t aTimeThreshold) -{ - NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); - if (mVideoReader) { - return mVideoReader->DecodeVideoFrame(aKeyframeSkip, aTimeThreshold); - } else { - return false; - } -} - -bool -DASHReader::DecodeAudioData() -{ - NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); - return (mAudioReader ? mAudioReader->DecodeAudioData() : false); -} - -nsresult -DASHReader::ReadMetadata(MediaInfo* aInfo, - MetadataTags** aTags) -{ - NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); - - // Wait for MPD to be parsed and child readers created. - LOG1("Waiting for metadata download."); - nsresult rv = WaitForMetadata(); - // If we get an abort, return silently; the decoder is shutting down. - if (NS_ERROR_ABORT == rv) { - return NS_OK; - } - // Verify no other errors before continuing. - NS_ENSURE_SUCCESS(rv, rv); - - NS_ASSERTION(aTags, "Called with null MetadataTags**."); - *aTags = nullptr; - - // Get metadata from child readers. - MediaInfo audioInfo, videoInfo; - - // Read metadata for all video streams. - for (uint i = 0; i < mVideoReaders.Length(); i++) { - // Use an nsAutoPtr here to ensure |tags| memory does not leak. - nsAutoPtr tags; - rv = mVideoReaders[i]->ReadMetadata(&videoInfo, getter_Transfers(tags)); - NS_ENSURE_SUCCESS(rv, rv); - // Use metadata from current video sub reader to populate aInfo. - if (mVideoReaders[i] == mVideoReader) { - mInfo.mVideo = videoInfo.mVideo; - } - } - // Read metadata for audio stream. - // Note: Getting metadata tags from audio reader only for now. - // XXX Audio stream switching not yet supported. - if (mAudioReader) { - rv = mAudioReader->ReadMetadata(&audioInfo, aTags); - NS_ENSURE_SUCCESS(rv, rv); - mInfo.mAudio = audioInfo.mAudio; - } - - *aInfo = mInfo; - - return NS_OK; -} - -nsresult -DASHReader::Seek(int64_t aTime, - int64_t aStartTime, - int64_t aEndTime, - int64_t aCurrentTime) -{ - NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); - - NS_ENSURE_SUCCESS(ResetDecode(), NS_ERROR_FAILURE); - - LOG("Seeking to [%.2fs]", aTime/1000000.0); - - nsresult rv; - DASHDecoder* dashDecoder = static_cast(mDecoder); - - if (mAudioReader) { - int64_t subsegmentIdx = -1; - { - ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); - subsegmentIdx = mAudioReader->GetSubsegmentForSeekTime(aTime); - NS_ENSURE_TRUE(0 <= subsegmentIdx, NS_ERROR_ILLEGAL_VALUE); - } - dashDecoder->NotifySeekInAudioSubsegment(subsegmentIdx); - - rv = mAudioReader->Seek(aTime, aStartTime, aEndTime, aCurrentTime); - NS_ENSURE_SUCCESS(rv, rv); - } - - if (mVideoReader) { - // Determine the video subsegment we're seeking to. - int32_t subsegmentIdx = -1; - { - ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); - subsegmentIdx = mVideoReader->GetSubsegmentForSeekTime(aTime); - NS_ENSURE_TRUE(0 <= subsegmentIdx, NS_ERROR_ILLEGAL_VALUE); - } - - LOG("Seek to [%.2fs] found in video subsegment [%d]", - aTime/1000000.0, subsegmentIdx); - - // Determine if/which video reader previously downloaded this subsegment. - int32_t readerIdx = dashDecoder->GetRepIdxForVideoSubsegmentLoad(subsegmentIdx); - - dashDecoder->NotifySeekInVideoSubsegment(readerIdx, subsegmentIdx); - - if (0 <= readerIdx) { - NS_ENSURE_TRUE(readerIdx < mVideoReaders.Length(), - NS_ERROR_ILLEGAL_VALUE); - // Switch to this reader and do the Seek. - DASHRepReader* fromReader = mVideoReader; - DASHRepReader* toReader = mVideoReaders[readerIdx]; - - { - ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); - if (fromReader != toReader) { - LOG("Switching video readers now from [%p] to [%p] for a seek to " - "[%.2fs] in subsegment [%d]", - fromReader, toReader, aTime/1000000.0, subsegmentIdx); - - mVideoReader = toReader; - } - } - - rv = mVideoReader->Seek(aTime, aStartTime, aEndTime, aCurrentTime); - if (NS_FAILED(rv)) { - NS_ENSURE_SUCCESS(rv, rv); - } - - // Go back to the appropriate count in the switching history, and setup - // this main reader and the sub readers for the next switch (if any). - { - ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); - mSwitchCount = dashDecoder->GetSwitchCountAtVideoSubsegment(subsegmentIdx); - LOG("After mVideoReader->Seek() mSwitchCount %d", mSwitchCount); - NS_ENSURE_TRUE(0 <= mSwitchCount, NS_ERROR_ILLEGAL_VALUE); - NS_ENSURE_TRUE(mSwitchCount <= subsegmentIdx, NS_ERROR_ILLEGAL_VALUE); - } - } else { - LOG("Error getting rep idx for video subsegment [%d]", - subsegmentIdx); - } - } - return NS_OK; -} - -nsresult -DASHReader::GetBuffered(TimeRanges* aBuffered, - int64_t aStartTime) -{ - NS_ENSURE_ARG(aBuffered); - - MediaResource* resource = nullptr; - AbstractMediaDecoder* decoder = nullptr; - - TimeRanges audioBuffered, videoBuffered; - uint32_t audioRangeCount = 0, videoRangeCount = 0; - bool audioCachedAtEnd = false, videoCachedAtEnd = false; - - nsresult rv = NS_OK; - - // Get all audio and video buffered ranges. Include inactive streams, since - // we may have carried out a seek and future subsegments may be in currently - // inactive decoders. - ReentrantMonitorConditionallyEnter mon(!mDecoder->OnDecodeThread(), - mDecoder->GetReentrantMonitor()); - for (uint32_t i = 0; i < mAudioReaders.Length(); i++) { - decoder = mAudioReaders[i]->GetDecoder(); - NS_ENSURE_TRUE(decoder, NS_ERROR_NULL_POINTER); - resource = decoder->GetResource(); - NS_ENSURE_TRUE(resource, NS_ERROR_NULL_POINTER); - resource->Pin(); - rv = mAudioReaders[i]->GetBuffered(&audioBuffered, aStartTime); - NS_ENSURE_SUCCESS(rv, rv); - // If data was cached at the end, then the final timestamp refers to the - // end of the data. Use this later to extend end time if necessary. - if (!audioCachedAtEnd) { - audioCachedAtEnd = mAudioReaders[i]->IsDataCachedAtEndOfSubsegments(); - } - resource->Unpin(); - } - for (uint32_t i = 0; i < mVideoReaders.Length(); i++) { - decoder = mVideoReaders[i]->GetDecoder(); - NS_ENSURE_TRUE(decoder, NS_ERROR_NULL_POINTER); - resource = decoder->GetResource(); - NS_ENSURE_TRUE(resource, NS_ERROR_NULL_POINTER); - resource->Pin(); - rv = mVideoReaders[i]->GetBuffered(&videoBuffered, aStartTime); - NS_ENSURE_SUCCESS(rv, rv); - // If data was cached at the end, then the final timestamp refers to the - // end of the data. Use this later to extend end time if necessary. - if (!videoCachedAtEnd) { - videoCachedAtEnd = mVideoReaders[i]->IsDataCachedAtEndOfSubsegments(); - } - resource->Unpin(); - } - - audioBuffered.Normalize(); - videoBuffered.Normalize(); - - rv = audioBuffered.GetLength(&audioRangeCount); - NS_ENSURE_SUCCESS(rv, rv); - rv = videoBuffered.GetLength(&videoRangeCount); - NS_ENSURE_SUCCESS(rv, rv); - -#ifdef PR_LOGGING - double start = 0, end = 0; - for (uint32_t i = 0; i < audioRangeCount; i++) { - rv = audioBuffered.Start(i, &start); - NS_ENSURE_SUCCESS(rv, rv); - rv = audioBuffered.End(i, &end); - NS_ENSURE_SUCCESS(rv, rv); - LOG("audioBuffered[%d] = (%f, %f)", - i, start, end); - } - for (uint32_t i = 0; i < videoRangeCount; i++) { - rv = videoBuffered.Start(i, &start); - NS_ENSURE_SUCCESS(rv, rv); - rv = videoBuffered.End(i, &end); - NS_ENSURE_SUCCESS(rv, rv); - LOG("videoBuffered[%d] = (%f, %f)", - i, start, end); - } -#endif - - // If audio and video are cached to the end of their subsegments, extend the - // end time of the shorter of the two. Presentation of the shorter stream - // will stop at the end, while the other continues until the combined - // playback is complete. - // Note: Only in cases where the shorter stream is fully cached, and the - // longer stream is partially cached, but with more time buffered than the - // shorter stream. - // - // Audio ========| - // 20 - // Video ============|----| - // 30 40 - // Combo ============| <----- End time EXTENDED. - // - // For example, audio is fully cached to 20s, but video is partially cached - // to 30s, full duration 40s. In this case, the buffered end time should be - // extended to the video's end time. - // - // Audio =================| - // 40 - // Video ========|----| - // 20 30 - // Combo ========| <------ End time NOT EXTENDED. - // - // Conversely, if the longer stream is fully cached, but the shorter one is - // not, no extension of end time should occur - we should consider the - // partially cached, shorter end time to be the end time of the combined - // stream - - if (audioCachedAtEnd || videoCachedAtEnd) { - NS_ENSURE_TRUE(audioRangeCount, NS_ERROR_FAILURE); - NS_ENSURE_TRUE(videoRangeCount, NS_ERROR_FAILURE); - - double audioEndTime = 0, videoEndTime = 0; - // Get end time of the last range of buffered audio. - audioEndTime = audioBuffered.GetFinalEndTime(); - NS_ENSURE_TRUE(audioEndTime > 0, NS_ERROR_ILLEGAL_VALUE); - // Get end time of the last range of buffered video. - videoEndTime = videoBuffered.GetFinalEndTime(); - NS_ENSURE_TRUE(videoEndTime > 0, NS_ERROR_ILLEGAL_VALUE); - - // API for TimeRanges requires extending through adding and normalizing. - if (videoCachedAtEnd && audioEndTime > videoEndTime) { - videoBuffered.Add(videoEndTime, audioEndTime); - videoBuffered.Normalize(); - LOG("videoBuffered extended to %f", audioEndTime); - } else if (audioCachedAtEnd && videoEndTime > audioEndTime) { - audioBuffered.Add(audioEndTime, videoEndTime); - audioBuffered.Normalize(); - LOG("audioBuffered extended to %f", videoEndTime); - } - } - - // Calculate intersecting ranges for video and audio. - if (!mAudioReaders.IsEmpty() && !mVideoReaders.IsEmpty()) { - for (uint32_t i = 0; i < audioRangeCount; i++) { - // |A|udio, |V|ideo, |I|ntersect. - double startA, startV, startI; - double endA, endV, endI; - rv = audioBuffered.Start(i, &startA); - NS_ENSURE_SUCCESS(rv, rv); - rv = audioBuffered.End(i, &endA); - NS_ENSURE_SUCCESS(rv, rv); - - for (uint32_t j = 0; j < videoRangeCount; j++) { - rv = videoBuffered.Start(i, &startV); - NS_ENSURE_SUCCESS(rv, rv); - rv = videoBuffered.End(i, &endV); - NS_ENSURE_SUCCESS(rv, rv); - - // If video block is before audio block, compare next video block. - if (startA > endV) { - continue; - // If video block is after audio block, all of them are; compare next - // audio block. - } else if (endA < startV) { - break; - } - // Calculate intersections of current audio and video blocks. - startI = (startA > startV) ? startA : startV; - endI = (endA > endV) ? endV : endA; - aBuffered->Add(startI, endI); - } - } - } else if (!mAudioReaders.IsEmpty()) { - *aBuffered = audioBuffered; - } else if (!mVideoReaders.IsEmpty()) { - *aBuffered = videoBuffered; - } else { - return NS_ERROR_NOT_INITIALIZED; - } - - return NS_OK; -} - -VideoData* -DASHReader::FindStartTime(int64_t& aOutStartTime) -{ - NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(), - "Should be on state machine or decode thread."); - - // Extract the start times of the bitstreams in order to calculate - // the duration. - int64_t videoStartTime = INT64_MAX; - int64_t audioStartTime = INT64_MAX; - VideoData* videoData = nullptr; - - ReentrantMonitorConditionallyEnter mon(!mDecoder->OnDecodeThread(), - mDecoder->GetReentrantMonitor()); - if (HasVideo()) { - // Forward to video reader. - videoData = mVideoReader->DecodeToFirstVideoData(); - if (videoData) { - videoStartTime = videoData->mTime; - } - } - if (HasAudio()) { - // Forward to audio reader. - AudioData* audioData = mAudioReader->DecodeToFirstAudioData(); - if (audioData) { - audioStartTime = audioData->mTime; - } - } - - int64_t startTime = std::min(videoStartTime, audioStartTime); - if (startTime != INT64_MAX) { - aOutStartTime = startTime; - } - - return videoData; -} - -MediaQueue& -DASHReader::AudioQueue() -{ - ReentrantMonitorConditionallyEnter mon(!mDecoder->OnDecodeThread(), - mDecoder->GetReentrantMonitor()); - NS_ASSERTION(mAudioReader, "mAudioReader is NULL!"); - return mAudioQueue; -} - -MediaQueue& -DASHReader::VideoQueue() -{ - ReentrantMonitorConditionallyEnter mon(!mDecoder->OnDecodeThread(), - mDecoder->GetReentrantMonitor()); - NS_ASSERTION(mVideoReader, "mVideoReader is NULL!"); - return mVideoQueue; -} - -void -DASHReader::RequestVideoReaderSwitch(uint32_t aFromReaderIdx, - uint32_t aToReaderIdx, - uint32_t aSubsegmentIdx) -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - NS_ASSERTION(aFromReaderIdx < mVideoReaders.Length(), - "From index is greater than number of video readers!"); - NS_ASSERTION(aToReaderIdx < mVideoReaders.Length(), - "To index is greater than number of video readers!"); - NS_ASSERTION(aToReaderIdx != aFromReaderIdx, - "Don't request switches to same reader!"); - mDecoder->GetReentrantMonitor().AssertCurrentThreadIn(); - - if (mSwitchCount < 0) { - mSwitchCount = 0; - } - - DASHRepReader* fromReader = mVideoReaders[aFromReaderIdx]; - DASHRepReader* toReader = mVideoReaders[aToReaderIdx]; - - LOG("Switch requested from reader [%d] [%p] to reader [%d] [%p] " - "at subsegment[%d].", - aFromReaderIdx, fromReader, aToReaderIdx, toReader, aSubsegmentIdx); - - // Append the subsegment index to the list of pending switches. - for (uint32_t i = 0; i < mSwitchToVideoSubsegmentIndexes.Length(); i++) { - if (mSwitchToVideoSubsegmentIndexes[i] == aSubsegmentIdx) { - // A backwards |Seek| has changed the switching history; delete from - // this point on. - mSwitchToVideoSubsegmentIndexes.TruncateLength(i); - break; - } - } - mSwitchToVideoSubsegmentIndexes.AppendElement(aSubsegmentIdx); - - // Tell the SWITCH FROM reader when it should stop reading. - fromReader->RequestSwitchAtSubsegment(aSubsegmentIdx, toReader); - - // Tell the SWITCH TO reader to seek to the correct offset. - toReader->RequestSeekToSubsegment(aSubsegmentIdx); - - mSwitchVideoReaders = true; -} - -void -DASHReader::PossiblySwitchVideoReaders() -{ - NS_ASSERTION(mDecoder, "Decoder should not be null"); - NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); - - // Flag to switch streams is set in |RequestVideoReaderSwitch|. - if (!mSwitchVideoReaders) { - return; - } - - // Only switch if we reached a switch access point. - NS_ENSURE_TRUE_VOID(0 <= mSwitchCount); - NS_ENSURE_TRUE_VOID((uint32_t)mSwitchCount < mSwitchToVideoSubsegmentIndexes.Length()); - uint32_t switchIdx = mSwitchToVideoSubsegmentIndexes[mSwitchCount]; - if (!mVideoReader->HasReachedSubsegment(switchIdx)) { - return; - } - - // Get Representation index to switch to. - DASHDecoder* dashDecoder = static_cast(mDecoder); - int32_t toReaderIdx = dashDecoder->GetRepIdxForVideoSubsegmentLoad(switchIdx); - NS_ENSURE_TRUE_VOID(0 <= toReaderIdx); - NS_ENSURE_TRUE_VOID((uint32_t)toReaderIdx < mVideoReaders.Length()); - - DASHRepReader* fromReader = mVideoReader; - DASHRepReader* toReader = mVideoReaders[toReaderIdx]; - NS_ENSURE_TRUE_VOID(fromReader != toReader); - - LOG("Switching video readers now from [%p] to [%p] at subsegment [%d]: " - "mSwitchCount [%d].", - fromReader, toReader, switchIdx, mSwitchCount); - - // Switch readers while in the monitor. - ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); - mVideoReader = toReader; - - // Prep readers for next switch, also while in monitor. - if ((uint32_t)++mSwitchCount < mSwitchToVideoSubsegmentIndexes.Length()) { - // Get the subsegment at which to switch. - switchIdx = mSwitchToVideoSubsegmentIndexes[mSwitchCount]; - - // Update from and to reader ptrs for next switch. - fromReader = toReader; - toReaderIdx = dashDecoder->GetRepIdxForVideoSubsegmentLoad(switchIdx); - toReader = mVideoReaders[toReaderIdx]; - NS_ENSURE_TRUE_VOID((uint32_t)toReaderIdx < mVideoReaders.Length()); - NS_ENSURE_TRUE_VOID(fromReader != toReader); - - // Tell the SWITCH FROM reader when it should stop reading. - fromReader->RequestSwitchAtSubsegment(switchIdx, toReader); - - // Tell the SWITCH TO reader to seek to the correct offset. - toReader->RequestSeekToSubsegment(switchIdx); - } else { - // If there are no more pending switches, unset the switch readers flag. - mSwitchVideoReaders = false; - } -} - -void -DASHReader::PrepareToDecode() -{ - NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); - - // Flag to switch streams is set by |DASHDecoder|. - if (!mSwitchVideoReaders) { - return; - } - - PossiblySwitchVideoReaders(); - - // Prepare each sub reader for decoding: includes seeking to the correct - // offset if a seek was previously requested. - for (uint32_t i = 0; i < mVideoReaders.Length(); i++) { - mVideoReaders[i]->PrepareToDecode(); - } -} - -DASHRepReader* -DASHReader::GetReaderForSubsegment(uint32_t aSubsegmentIdx) -{ - NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); - DASHDecoder* dashDecoder = static_cast(mDecoder); - int32_t repIdx = - dashDecoder->GetRepIdxForVideoSubsegmentLoadAfterSeek((int32_t)aSubsegmentIdx); - if (0 <= repIdx && repIdx < mVideoReaders.Length()) { - return mVideoReaders[repIdx]; - } else { - return nullptr; - } -} - - -} // namespace mozilla diff --git a/content/media/dash/DASHReader.h b/content/media/dash/DASHReader.h deleted file mode 100644 index 6a79fdeb27f9..000000000000 --- a/content/media/dash/DASHReader.h +++ /dev/null @@ -1,303 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ - -/* This Source Code Form Is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* DASH - Dynamic Adaptive Streaming over HTTP - * - * DASH is an adaptive bitrate streaming technology where a multimedia file is - * partitioned into one or more segments and delivered to a client using HTTP. - * - * see DASHDecoder.cpp for comments on DASH object interaction - */ - -#if !defined(DASHReader_h_) -#define DASHReader_h_ - -#include "VideoUtils.h" -#include "MediaDecoderReader.h" -#include "DASHRepReader.h" - -namespace mozilla { - -class DASHRepReader; - -class DASHReader : public MediaDecoderReader -{ -public: - DASHReader(AbstractMediaDecoder* aDecoder); - ~DASHReader(); - nsresult ResetDecode() MOZ_OVERRIDE; - - // Adds a pointer to a audio/video reader for a media |Representation|. - // Called on the main thread only. - void AddAudioReader(DASHRepReader* aAudioReader); - void AddVideoReader(DASHRepReader* aVideoReader); - - // Waits for metadata bytes to be downloaded, then reads and parses them. - // Called on the decode thread only. - nsresult ReadMetadata(MediaInfo* aInfo, - MetadataTags** aTags) MOZ_OVERRIDE; - - // Waits for |ReadyToReadMetadata| or |NotifyDecoderShuttingDown| - // notification, whichever comes first. Ensures no attempt to read metadata - // during |DASHDecoder|::|Shutdown|. Called on decode thread only. - nsresult WaitForMetadata() { - NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); - ReentrantMonitorAutoEnter mon(mReadMetadataMonitor); - while (true) { - // Abort if the decoder has started shutting down. - if (mDecoderIsShuttingDown) { - return NS_ERROR_ABORT; - } else if (mReadyToReadMetadata) { - break; - } - mon.Wait(); - } - return NS_OK; - } - - // Called on the main thread by |DASHDecoder| to notify that metadata bytes - // have been downloaded. - void ReadyToReadMetadata() { - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - ReentrantMonitorAutoEnter mon(mReadMetadataMonitor); - mReadyToReadMetadata = true; - mon.NotifyAll(); - } - - // Called on the main thread by |DASHDecoder| when it starts Shutdown. Will - // wake metadata monitor if waiting for a silent return from |ReadMetadata|. - void NotifyDecoderShuttingDown() { - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - ReentrantMonitorAutoEnter metadataMon(mReadMetadataMonitor); - mDecoderIsShuttingDown = true; - // Notify |ReadMetadata| of the shutdown if it's waiting. - metadataMon.NotifyAll(); - } - - // Audio/video status are dependent on the presence of audio/video readers. - // Call on decode thread only. - bool HasAudio() MOZ_OVERRIDE; - bool HasVideo() MOZ_OVERRIDE; - - // Returns references to the audio/video queues of sub-readers. Called on - // decode, state machine and audio threads. - MediaQueue& AudioQueue() MOZ_OVERRIDE; - MediaQueue& VideoQueue() MOZ_OVERRIDE; - - // Called from MediaDecoderStateMachine on the main thread. - nsresult Init(MediaDecoderReader* aCloneDonor) MOZ_OVERRIDE; - - // Used by |MediaMemoryReporter|. - int64_t VideoQueueMemoryInUse() MOZ_OVERRIDE; - int64_t AudioQueueMemoryInUse() MOZ_OVERRIDE; - - // Called on the decode thread, at the start of the decode loop, before - // |DecodeVideoFrame|. Carries out video reader switch if previously - // requested, and tells sub-readers to |PrepareToDecode|. - void PrepareToDecode() MOZ_OVERRIDE; - - // Called on the decode thread. - bool DecodeVideoFrame(bool &aKeyframeSkip, int64_t aTimeThreshold) MOZ_OVERRIDE; - bool DecodeAudioData() MOZ_OVERRIDE; - - // Converts seek time to byte offset. Called on the decode thread only. - nsresult Seek(int64_t aTime, - int64_t aStartTime, - int64_t aEndTime, - int64_t aCurrentTime) MOZ_OVERRIDE; - - // Called by state machine on multiple threads. - nsresult GetBuffered(mozilla::dom::TimeRanges* aBuffered, int64_t aStartTime) MOZ_OVERRIDE; - - // Called on the state machine or decode threads. - VideoData* FindStartTime(int64_t& aOutStartTime) MOZ_OVERRIDE; - - // Prepares for an upcoming switch of video readers. Called by - // |DASHDecoder| when it has switched download streams. Sets the index of - // the reader to switch TO and the index of the subsegment to switch AT - // (start offset). (Note: Subsegment boundaries are switch access points for - // DASH-WebM). Called on the main thread. Must be in the decode monitor. - void RequestVideoReaderSwitch(uint32_t aFromReaderIdx, - uint32_t aToReaderIdx, - uint32_t aSubsegmentIdx); - - // Returns a pointer to the reader which should be used for the specified - // subsegment. Called on the decode thread only. - DASHRepReader* GetReaderForSubsegment(uint32_t aSubsegmentIdx); - -private: - // Switches video subreaders if a stream-switch flag has been set, and the - // current reader has read up to the switching subsegment (start offset). - // Called on the decode thread only. - void PossiblySwitchVideoReaders(); - - // Monitor and booleans used to wait for metadata bytes to be downloaded, and - // skip reading metadata if |DASHDecoder|'s shutdown is in progress. - ReentrantMonitor mReadMetadataMonitor; - bool mReadyToReadMetadata; - bool mDecoderIsShuttingDown; - - // Wrapper class protecting accesses to sub-readers. Asserts that the - // decoder monitor has been entered for write access on all threads and read - // access on all threads that are not the decode thread. Read access on the - // decode thread does not need to be protected. - class MonitoredSubReader - { - public: - // Main constructor takes a pointer to the owning |DASHReader| to verify - // correct entry into the decoder's |ReentrantMonitor|. - MonitoredSubReader(DASHReader* aReader) : - mReader(aReader), - mSubReader(nullptr) - { - MOZ_COUNT_CTOR(DASHReader::MonitoredSubReader); - NS_ASSERTION(mReader, "Reader is null!"); - } - // Note: |mSubReader|'s refcount will be decremented in this destructor. - ~MonitoredSubReader() - { - MOZ_COUNT_DTOR(DASHReader::MonitoredSubReader); - } - - // Override '=' to always assert thread is "in monitor" for writes/changes - // to |mSubReader|. - MonitoredSubReader& operator=(DASHRepReader* rhs) - { - NS_ASSERTION(mReader->GetDecoder(), "Decoder is null!"); - mReader->GetDecoder()->GetReentrantMonitor().AssertCurrentThreadIn(); - mSubReader = rhs; - return *this; - } - - // Override '*' to assert threads other than the decode thread are "in - // monitor" for ptr reads. - operator DASHRepReader*() const - { - NS_ASSERTION(mReader->GetDecoder(), "Decoder is null!"); - if (!mReader->GetDecoder()->OnDecodeThread()) { - mReader->GetDecoder()->GetReentrantMonitor().AssertCurrentThreadIn(); - } - return mSubReader; - } - - // Override '->' to assert threads other than the decode thread are "in - // monitor" for |mSubReader| function calls. - DASHRepReader* operator->() const - { - return *this; - } - private: - // Pointer to |DASHReader| object which owns this |MonitoredSubReader|. - DASHReader* mReader; - // Ref ptr to the sub reader. - nsRefPtr mSubReader; - }; - - // Wrapped ref ptrs to current sub-readers of individual media - // |Representation|s. Decoder monitor must be entered for write access on all - // threads and read access on all threads that are not the decode thread. - // Read access on the decode thread does not need to be protected. - // Note: |MonitoredSubReader| class will assert correct monitor use. - MonitoredSubReader mAudioReader; - MonitoredSubReader mVideoReader; - - // Wrapper class protecting accesses to sub-reader list. Asserts that the - // decoder monitor has been entered for write access on all threads and read - // access on all threads that are not the decode thread. Read access on the - // decode thread does not need to be protected. - // Note: Elems accessed via operator[] are not protected with monitor - // assertion checks once obtained. - class MonitoredSubReaderList - { - public: - // Main constructor takes a pointer to the owning |DASHReader| to verify - // correct entry into the decoder's |ReentrantMonitor|. - MonitoredSubReaderList(DASHReader* aReader) : - mReader(aReader) - { - MOZ_COUNT_CTOR(DASHReader::MonitoredSubReaderList); - NS_ASSERTION(mReader, "Reader is null!"); - } - // Note: Elements in |mSubReaderList| will have their refcounts decremented - // in this destructor. - ~MonitoredSubReaderList() - { - MOZ_COUNT_DTOR(DASHReader::MonitoredSubReaderList); - } - - // Returns Length of |mSubReaderList| array. Will assert threads other than - // the decode thread are "in monitor". - uint32_t Length() const - { - NS_ASSERTION(mReader->GetDecoder(), "Decoder is null!"); - if (!mReader->GetDecoder()->OnDecodeThread()) { - mReader->GetDecoder()->GetReentrantMonitor().AssertCurrentThreadIn(); - } - return mSubReaderList.Length(); - } - - // Returns true if |mSubReaderList| is empty. Will assert that threads - // other than the decode thread are "in monitor". - bool IsEmpty() const - { - NS_ASSERTION(mReader->GetDecoder(), "Decoder is null!"); - if (!mReader->GetDecoder()->OnDecodeThread()) { - mReader->GetDecoder()->GetReentrantMonitor().AssertCurrentThreadIn(); - } - return mSubReaderList.IsEmpty(); - } - // Override '[]' to assert threads other than the decode thread are "in - // monitor" for accessing individual elems. Note: elems returned do not - // have monitor assertions builtin like |MonitoredSubReader| objects. - nsRefPtr& operator[](uint32_t i) - { - NS_ASSERTION(mReader->GetDecoder(), "Decoder is null!"); - if (!mReader->GetDecoder()->OnDecodeThread()) { - mReader->GetDecoder()->GetReentrantMonitor().AssertCurrentThreadIn(); - } - return mSubReaderList[i]; - } - - // Appends a reader to the end of |mSubReaderList|. Will always assert that - // the thread is "in monitor". - void - AppendElement(DASHRepReader* aReader) - { - NS_ASSERTION(mReader->GetDecoder(), "Decoder is null!"); - mReader->GetDecoder()->GetReentrantMonitor().AssertCurrentThreadIn(); - mSubReaderList.AppendElement(aReader); - } - private: - // Pointer to |DASHReader| object which owns this |MonitoredSubReader|. - DASHReader* mReader; - // Ref ptrs to the sub readers. - nsTArray > mSubReaderList; - }; - - // Ref ptrs to all sub-readers of individual media |Representation|s. - // Decoder monitor must be entered for write access on all threads and read - // access on all threads that are not the decode thread. Read acces on the - // decode thread does not need to be protected. - MonitoredSubReaderList mAudioReaders; - MonitoredSubReaderList mVideoReaders; - - // When true, indicates that we should switch reader. Must be in the monitor - // for write access and read access off the decode thread. - bool mSwitchVideoReaders; - - // Indicates the subsegment index at which the reader should switch. Must be - // in the monitor for write access and read access off the decode thread. - nsTArray mSwitchToVideoSubsegmentIndexes; - - // Counts the number of switches that have taken place. Must be in the - // monitor for write access and read access off the decode thread. - int32_t mSwitchCount; -}; - -} // namespace mozilla - -#endif diff --git a/content/media/dash/DASHRepDecoder.cpp b/content/media/dash/DASHRepDecoder.cpp deleted file mode 100644 index 742061f3a6af..000000000000 --- a/content/media/dash/DASHRepDecoder.cpp +++ /dev/null @@ -1,517 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ - -/* This Source Code Form Is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* DASH - Dynamic Adaptive Streaming over HTTP - * - * DASH is an adaptive bitrate streaming technology where a multimedia file is - * partitioned into one or more segments and delivered to a client using HTTP. - * - * see DASHDecoder.cpp for info on DASH interaction with the media engine.*/ - -#include "prlog.h" -#include "VideoUtils.h" -#include "SegmentBase.h" -#include "MediaDecoderStateMachine.h" -#include "DASHReader.h" -#include "MediaResource.h" -#include "DASHRepDecoder.h" -#include "WebMReader.h" -#include - -namespace mozilla { - -#ifdef PR_LOGGING -extern PRLogModuleInfo* gMediaDecoderLog; -#define LOG(msg, ...) PR_LOG(gMediaDecoderLog, PR_LOG_DEBUG, \ - ("%p [DASHRepDecoder] " msg, this, __VA_ARGS__)) -#define LOG1(msg) PR_LOG(gMediaDecoderLog, PR_LOG_DEBUG, \ - ("%p [DASHRepDecoder] " msg, this)) -#else -#define LOG(msg, ...) -#define LOG1(msg) -#endif - -MediaDecoderStateMachine* -DASHRepDecoder::CreateStateMachine() -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - // Do not create; just return current state machine. - return mDecoderStateMachine; -} - -nsresult -DASHRepDecoder::SetStateMachine(MediaDecoderStateMachine* aSM) -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - mDecoderStateMachine = aSM; - return NS_OK; -} - -void -DASHRepDecoder::SetResource(MediaResource* aResource) -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - mResource = aResource; -} - -void -DASHRepDecoder::SetMPDRepresentation(Representation const * aRep) -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - mMPDRepresentation = aRep; -} - -void -DASHRepDecoder::SetReader(WebMReader* aReader) -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - mReader = aReader; -} - -nsresult -DASHRepDecoder::Load(nsIStreamListener** aListener, - MediaDecoder* aCloneDonor) -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - NS_ENSURE_TRUE(mMPDRepresentation, NS_ERROR_NOT_INITIALIZED); - - // Get init range and index range from MPD. - SegmentBase const * segmentBase = mMPDRepresentation->GetSegmentBase(); - NS_ENSURE_TRUE(segmentBase, NS_ERROR_NULL_POINTER); - - // Get and set init range. - segmentBase->GetInitRange(&mInitByteRange.mStart, &mInitByteRange.mEnd); - NS_ENSURE_TRUE(!mInitByteRange.IsNull(), NS_ERROR_NOT_INITIALIZED); - mReader->SetInitByteRange(mInitByteRange); - - // Get and set index range. - segmentBase->GetIndexRange(&mIndexByteRange.mStart, &mIndexByteRange.mEnd); - NS_ENSURE_TRUE(!mIndexByteRange.IsNull(), NS_ERROR_NOT_INITIALIZED); - mReader->SetIndexByteRange(mIndexByteRange); - - // Determine byte range to Open. - // For small deltas between init and index ranges, we need to bundle the byte - // range requests together in order to deal with |MediaCache|'s control of - // seeking (see |MediaCache|::|Update|). |MediaCache| will not initiate a - // |ChannelMediaResource|::|CacheClientSeek| for the INDEX byte range if the - // delta between it and the INIT byte ranges is less than - // |SEEK_VS_READ_THRESHOLD|. To get around this, request all metadata bytes - // now so |MediaCache| can assume the bytes are en route. - int64_t delta = std::max(mIndexByteRange.mStart, mInitByteRange.mStart) - - std::min(mIndexByteRange.mEnd, mInitByteRange.mEnd); - MediaByteRange byteRange; - if (delta <= SEEK_VS_READ_THRESHOLD) { - byteRange.mStart = std::min(mIndexByteRange.mStart, mInitByteRange.mStart); - byteRange.mEnd = std::max(mIndexByteRange.mEnd, mInitByteRange.mEnd); - // Loading everything in one chunk . - mMetadataChunkCount = 1; - } else { - byteRange = mInitByteRange; - // Loading in two chunks: init and index. - mMetadataChunkCount = 2; - } - mCurrentByteRange = byteRange; - return mResource->OpenByteRange(nullptr, byteRange); -} - -void -DASHRepDecoder::NotifyDownloadEnded(nsresult aStatus) -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - - if (!mMainDecoder) { - if (!mShuttingDown) { - LOG("Error! Main Decoder is null before shutdown: mMainDecoder [%p] ", - mMainDecoder.get()); - DecodeError(); - } - return; - } - - if (NS_SUCCEEDED(aStatus)) { - ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); - // Decrement counter as metadata chunks are downloaded. - // Note: Reader gets next chunk download via |ChannelMediaResource|:|Seek|. - if (mMetadataChunkCount > 0) { - LOG("Metadata chunk [%d] downloaded: range requested [%lld - %lld] " - "subsegmentIdx [%d]", - mMetadataChunkCount, - mCurrentByteRange.mStart, mCurrentByteRange.mEnd, mSubsegmentIdx); - mMetadataChunkCount--; - } else { - LOG("Byte range downloaded: status [%x] range requested [%lld - %lld] " - "subsegmentIdx [%d]", - aStatus, mCurrentByteRange.mStart, mCurrentByteRange.mEnd, - mSubsegmentIdx); - if ((uint32_t)mSubsegmentIdx == mByteRanges.Length()-1) { - mResource->NotifyLastByteRange(); - } - // Notify main decoder that a DATA byte range is downloaded. - mMainDecoder->NotifyDownloadEnded(this, aStatus, mSubsegmentIdx); - } - } else if (aStatus == NS_BINDING_ABORTED) { - LOG("Media download has been cancelled by the user: aStatus [%x].", - aStatus); - if (mMainDecoder) { - mMainDecoder->LoadAborted(); - } - return; - } else if (aStatus != NS_BASE_STREAM_CLOSED) { - LOG("Network error trying to download MPD: aStatus [%x].", aStatus); - NetworkError(); - } -} - -void -DASHRepDecoder::OnReadMetadataCompleted() -{ - NS_ASSERTION(OnDecodeThread(), "Should be on decode thread."); - - // If shutting down, just return silently. - if (mShuttingDown) { - LOG1("Shutting down! Ignoring OnReadMetadataCompleted()."); - return; - } - - LOG1("Metadata has been read."); - - // Metadata loaded and read for this stream; ok to populate byte ranges. - nsresult rv = PopulateByteRanges(); - if (NS_FAILED(rv) || mByteRanges.IsEmpty()) { - LOG("Error populating byte ranges [%x]", rv); - DecodeError(); - return; - } - - mMainDecoder->OnReadMetadataCompleted(this); -} - -nsresult -DASHRepDecoder::PopulateByteRanges() -{ - NS_ASSERTION(OnDecodeThread(), "Should be on decode thread."); - - // Should not be called during shutdown. - NS_ENSURE_FALSE(mShuttingDown, NS_ERROR_UNEXPECTED); - - ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); - if (!mByteRanges.IsEmpty()) { - return NS_OK; - } - NS_ENSURE_TRUE(mReader, NS_ERROR_NULL_POINTER); - LOG1("Populating byte range array."); - return mReader->GetSubsegmentByteRanges(mByteRanges); -} - -void -DASHRepDecoder::LoadNextByteRange() -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - NS_ASSERTION(mResource, "Error: resource is reported as null!"); - - // Return silently if shutting down. - if (mShuttingDown) { - LOG1("Shutting down! Ignoring LoadNextByteRange()."); - return; - } - - ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); - NS_ASSERTION(mMainDecoder, "Error: main decoder is null!"); - NS_ASSERTION(mMainDecoder->IsDecoderAllowedToDownloadData(this), - "Should not be called on non-active decoders!"); - - // Cannot have empty byte ranges. - if (mByteRanges.IsEmpty()) { - LOG1("Error getting list of subsegment byte ranges."); - DecodeError(); - return; - } - - // Get byte range for subsegment. - int32_t subsegmentIdx = mMainDecoder->GetSubsegmentIndex(this); - NS_ASSERTION(0 <= subsegmentIdx, - "Subsegment index should be >= 0 for active decoders"); - if (subsegmentIdx >= 0 && (uint32_t)subsegmentIdx < mByteRanges.Length()) { - mCurrentByteRange = mByteRanges[subsegmentIdx]; - mSubsegmentIdx = subsegmentIdx; - } else { - mCurrentByteRange.Clear(); - mSubsegmentIdx = -1; - LOG("End of subsegments: index [%d] out of range.", subsegmentIdx); - return; - } - - // Request a seek for the first reader. Required so that the reader is - // primed to start here, and will block subsequent subsegment seeks unless - // the subsegment has been read. - if (subsegmentIdx == 0) { - ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); - mReader->RequestSeekToSubsegment(0); - } - - // Query resource for cached ranges; only download if it's not there. - if (IsSubsegmentCached(mSubsegmentIdx)) { - LOG("Subsegment [%d] bytes [%lld] to [%lld] already cached. No need to " - "download.", mSubsegmentIdx, - mCurrentByteRange.mStart, mCurrentByteRange.mEnd); - nsCOMPtr event = - NS_NewRunnableMethod(this, &DASHRepDecoder::DoNotifyDownloadEnded); - nsresult rv = NS_DispatchToMainThread(event); - if (NS_FAILED(rv)) { - LOG("Error notifying subsegment [%d] cached: rv[0x%x].", - mSubsegmentIdx, rv); - NetworkError(); - } - return; - } - - // Open byte range corresponding to subsegment. - nsresult rv = mResource->OpenByteRange(nullptr, mCurrentByteRange); - if (NS_FAILED(rv)) { - LOG("Error opening byte range [%lld - %lld]: subsegmentIdx [%d] rv [%x].", - mCurrentByteRange.mStart, mCurrentByteRange.mEnd, mSubsegmentIdx, rv); - NetworkError(); - return; - } -} - -bool -DASHRepDecoder::IsSubsegmentCached(int32_t aSubsegmentIdx) -{ - GetReentrantMonitor().AssertCurrentThreadIn(); - - MediaByteRange byteRange = mByteRanges[aSubsegmentIdx]; - int64_t start = mResource->GetNextCachedData(byteRange.mStart); - int64_t end = mResource->GetCachedDataEnd(byteRange.mStart); - return (start == byteRange.mStart && - end >= byteRange.mEnd); -} - -void -DASHRepDecoder::DoNotifyDownloadEnded() -{ - NotifyDownloadEnded(NS_OK); -} - -nsresult -DASHRepDecoder::GetByteRangeForSeek(int64_t const aOffset, - MediaByteRange& aByteRange) -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - - // Only check data ranges if they're available and if this decoder is active, - // i.e. inactive rep decoders should only load metadata. - ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); - - for (uint32_t i = 0; i < mByteRanges.Length(); i++) { - NS_ENSURE_FALSE(mByteRanges[i].IsNull(), NS_ERROR_NOT_INITIALIZED); - // Check if |aOffset| lies within the current data range. - if (mByteRanges[i].mStart <= aOffset && aOffset <= mByteRanges[i].mEnd) { - if (mMainDecoder->IsDecoderAllowedToDownloadSubsegment(this, i)) { - mCurrentByteRange = aByteRange = mByteRanges[i]; - mSubsegmentIdx = i; - // XXX Hack: should be setting subsegment outside this function, but - // need to review seeking for multiple switches anyhow. - mMainDecoder->SetSubsegmentIndex(this, i); - LOG("Getting DATA range [%d] for seek offset [%lld]: " - "bytes [%lld] to [%lld]", - i, aOffset, aByteRange.mStart, aByteRange.mEnd); - return NS_OK; - } - break; - } - } - // Don't allow metadata downloads once they're loaded and byte ranges have - // been populated. - bool canDownloadMetadata = mByteRanges.IsEmpty(); - if (canDownloadMetadata) { - // Check metadata ranges; init range. - if (mInitByteRange.mStart <= aOffset && aOffset <= mInitByteRange.mEnd) { - mCurrentByteRange = aByteRange = mInitByteRange; - mSubsegmentIdx = 0; - LOG("Getting INIT range for seek offset [%lld]: bytes [%lld] to " - "[%lld]", aOffset, aByteRange.mStart, aByteRange.mEnd); - return NS_OK; - } - // ... index range. - if (mIndexByteRange.mStart <= aOffset && aOffset <= mIndexByteRange.mEnd) { - mCurrentByteRange = aByteRange = mIndexByteRange; - mSubsegmentIdx = 0; - LOG("Getting INDEXES range for seek offset [%lld]: bytes [%lld] to " - "[%lld]", aOffset, aByteRange.mStart, aByteRange.mEnd); - return NS_OK; - } - } else { - LOG1("Metadata should be read; inhibiting further metadata downloads."); - } - - // If no byte range is found by this stage, clear the parameter and return. - aByteRange.Clear(); - if (mByteRanges.IsEmpty() || !canDownloadMetadata) { - // Assume mByteRanges will be populated after metadata is read. - LOG("Data ranges not populated [%s]; metadata download restricted [%s]: " - "offset[%lld].", - (mByteRanges.IsEmpty() ? "yes" : "no"), - (canDownloadMetadata ? "no" : "yes"), aOffset); - return NS_ERROR_NOT_AVAILABLE; - } else { - // Cannot seek to an unknown offset. - // XXX Revisit this for dynamic MPD profiles if MPD is regularly updated. - LOG("Error! Offset [%lld] is in an unknown range!", aOffset); - return NS_ERROR_ILLEGAL_VALUE; - } -} - -void -DASHRepDecoder::PrepareForSwitch() -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - // Ensure that the media cache writes any data held in its partial block. - mResource->FlushCache(); -} - -void -DASHRepDecoder::NetworkError() -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - if (mMainDecoder) { mMainDecoder->NetworkError(); } -} - -void -DASHRepDecoder::SetDuration(double aDuration) -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - if (mMainDecoder) { mMainDecoder->SetDuration(aDuration); } -} - -void -DASHRepDecoder::SetInfinite(bool aInfinite) -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - if (mMainDecoder) { mMainDecoder->SetInfinite(aInfinite); } -} - -void -DASHRepDecoder::SetMediaSeekable(bool aMediaSeekable) -{ - NS_ASSERTION(NS_IsMainThread() || OnDecodeThread(), - "Should be on main thread or decode thread."); - if (mMainDecoder) { mMainDecoder->SetMediaSeekable(aMediaSeekable); } -} - -void -DASHRepDecoder::Progress(bool aTimer) -{ - if (mMainDecoder) { mMainDecoder->Progress(aTimer); } -} - -void -DASHRepDecoder::NotifyDataArrived(const char* aBuffer, - uint32_t aLength, - int64_t aOffset) -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - - LOG("Data bytes [%lld - %lld] arrived via buffer [%p].", - aOffset, aOffset+aLength, aBuffer); - // Notify reader directly, since call to |MediaDecoderStateMachine|:: - // |NotifyDataArrived| will go to |DASHReader|::|NotifyDataArrived|, which - // has no way to forward the notification to the correct sub-reader. - if (mReader) { - mReader->NotifyDataArrived(aBuffer, aLength, aOffset); - } - // Forward to main decoder which will notify state machine. - if (mMainDecoder) { - mMainDecoder->NotifyDataArrived(aBuffer, aLength, aOffset); - } -} - -void -DASHRepDecoder::NotifyBytesDownloaded() -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - if (mMainDecoder) { mMainDecoder->NotifyBytesDownloaded(); } -} - -void -DASHRepDecoder::NotifySuspendedStatusChanged() -{ - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - if (mMainDecoder) { mMainDecoder->NotifySuspendedStatusChanged(); } -} - -bool -DASHRepDecoder::OnStateMachineThread() const -{ - return (mMainDecoder ? mMainDecoder->OnStateMachineThread() : false); -} - -bool -DASHRepDecoder::OnDecodeThread() const -{ - return (mMainDecoder ? mMainDecoder->OnDecodeThread() : false); -} - -ReentrantMonitor& -DASHRepDecoder::GetReentrantMonitor() -{ - NS_ASSERTION(mMainDecoder, "Can't get monitor if main decoder is null!"); - if (mMainDecoder) { - return mMainDecoder->GetReentrantMonitor(); - } else { - // XXX If mMainDecoder is gone, most likely we're past shutdown and - // a waiting function has been wakened. Just return this decoder's own - // monitor and let the function complete. - return MediaDecoder::GetReentrantMonitor(); - } -} - -mozilla::layers::ImageContainer* -DASHRepDecoder::GetImageContainer() -{ - return (mMainDecoder ? mMainDecoder->GetImageContainer() : nullptr); -} - -void -DASHRepDecoder::DecodeError() -{ - if (NS_IsMainThread()) { - MediaDecoder::DecodeError(); - } else { - nsCOMPtr event = - NS_NewRunnableMethod(this, &MediaDecoder::DecodeError); - nsresult rv = NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); - if (NS_FAILED(rv)) { - LOG("Error dispatching DecodeError event to main thread: rv[%x]", rv); - } - } -} - -void -DASHRepDecoder::ReleaseStateMachine() -{ - NS_ASSERTION(NS_IsMainThread(), "Must be on main thread."); - - // Since state machine owns mReader, remove reference to it. - mReader = nullptr; - - MediaDecoder::ReleaseStateMachine(); -} - -void DASHRepDecoder::StopProgressUpdates() -{ - NS_ENSURE_TRUE_VOID(mMainDecoder); - MediaDecoder::StopProgressUpdates(); -} - -void DASHRepDecoder::StartProgressUpdates() -{ - NS_ENSURE_TRUE_VOID(mMainDecoder); - MediaDecoder::StartProgressUpdates(); -} - -} // namespace mozilla diff --git a/content/media/dash/DASHRepDecoder.h b/content/media/dash/DASHRepDecoder.h deleted file mode 100644 index 3634f121c428..000000000000 --- a/content/media/dash/DASHRepDecoder.h +++ /dev/null @@ -1,237 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ - -/* This Source Code Form Is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* DASH - Dynamic Adaptive Streaming over HTTP - * - * DASH is an adaptive bitrate streaming technology where a multimedia file is - * partitioned into one or more segments and delivered to a client using HTTP. - * - * see DASHDecoder.cpp for info on DASH interaction with the media engine.*/ - -#if !defined(DASHRepDecoder_h_) -#define DASHRepDecoder_h_ - -#include "Representation.h" -#include "DASHDecoder.h" -#include "WebMDecoder.h" -#include "WebMReader.h" -#include "MediaDecoder.h" - -namespace mozilla { - -namespace layers { -class ImageContainer; -} - -class DASHDecoder; -class DASHRepReader; - -class DASHRepDecoder : public MediaDecoder -{ -public: - typedef mozilla::net::Representation Representation; - typedef mozilla::net::SegmentBase SegmentBase; - typedef mozilla::layers::ImageContainer ImageContainer; - - // Constructor takes a ptr to the main decoder. - DASHRepDecoder(DASHDecoder* aMainDecoder) : - mMainDecoder(aMainDecoder), - mMPDRepresentation(nullptr), - mMetadataChunkCount(0), - mCurrentByteRange(), - mSubsegmentIdx(-1), - mReader(nullptr) - { - MOZ_COUNT_CTOR(DASHRepDecoder); - } - - ~DASHRepDecoder() - { - MOZ_COUNT_DTOR(DASHRepDecoder); - } - - // Clone not supported; just return nullptr. - virtual MediaDecoder* Clone() { return nullptr; } - - // Called by the main decoder at creation time; points to the main state - // machine managed by the main decoder. Called on the main thread only. - nsresult SetStateMachine(MediaDecoderStateMachine* aSM); - -private: - // Overridden to return the ptr set by SetStateMachine. Called on the main - // thread only. - MediaDecoderStateMachine* CreateStateMachine(); - -public: - // Called by DASHDecoder at creation time; points to the media resource - // for this decoder's |Representation|. Called on the main thread only. - void SetResource(MediaResource* aResource); - - // Sets the |Representation| object for this decoder. Called on the main - // thread. - void SetMPDRepresentation(Representation const * aRep); - - // Called from DASHDecoder on main thread; Starts media stream download. - virtual nsresult Load(nsIStreamListener** aListener = nullptr, - MediaDecoder* aCloneDonor = nullptr) MOZ_OVERRIDE; - - // Loads the next byte range (or first one on first call). Called on the main - // thread only. - void LoadNextByteRange(); - - // Returns true if the subsegment is already in the media cache. - bool IsSubsegmentCached(int32_t aSubsegmentIdx); - - // Calls from DASHRepDecoder. Called on the main thread only. - void SetReader(WebMReader* aReader); - - // Called if the media file encounters a network error. Call on the main - // thread only. - void NetworkError(); - - // Called from reader during ReadMetadata. This should be ignored here, and - // instead, duration should be set following MPD parsing. - void SetMediaDuration(int64_t aDuration) MOZ_OVERRIDE { }; - - // Set the duration of the media resource in units of seconds. - // This is called via a channel listener if it can pick up the duration - // from a content header. Must be called from the main thread only. - virtual void SetDuration(double aDuration); - - // Set media stream as infinite. Called on the main thread only. - void SetInfinite(bool aInfinite); - - // Sets media stream as seekable. Called on main thread only. - void SetMediaSeekable(bool aSeekable); - - // Fire progress events if needed according to the time and byte - // constraints outlined in the specification. aTimer is true - // if the method is called as a result of the progress timer rather - // than the result of downloaded data. - void Progress(bool aTimer); - - // Called as data arrives on the stream and is read into the cache. Called - // on the main thread only. - void NotifyDataArrived(const char* aBuffer, - uint32_t aLength, - int64_t aOffset); - - // Called by MediaResource when some data has been received. - // Call on the main thread only. - void NotifyBytesDownloaded(); - - // Notify that a byte range request has been completed by the media resource. - // Called on the main thread only. - void NotifyDownloadEnded(nsresult aStatus); - - // Called asynchronously by |LoadNextByteRange| if the data is already in the - // media cache. This will call NotifyDownloadEnded on the main thread with - // |aStatus| of NS_OK. - void DoNotifyDownloadEnded(); - - // Called by MediaResource when the "cache suspended" status changes. - // If MediaResource::IsSuspendedByCache returns true, then the decoder - // should stop buffering or otherwise waiting for download progress and - // start consuming data, if possible, because the cache is full. - void NotifySuspendedStatusChanged(); - - // Increments the parsed and decoded frame counters by the passed in counts. - // Can be called on any thread. - void NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded) MOZ_OVERRIDE { - if (mMainDecoder) {mMainDecoder->NotifyDecodedFrames(aParsed, aDecoded); } - } - - // Gets a byte range containing the byte offset. Call on main thread only. - nsresult GetByteRangeForSeek(int64_t const aOffset, - MediaByteRange& aByteRange); - - // Gets the number of data byte ranges (not inc. metadata). - uint32_t GetNumDataByteRanges() { - return mByteRanges.Length(); - } - - // Notify that a switch is about to happen. Called on the main thread. - void PrepareForSwitch(); - - // Returns true if the current thread is the state machine thread. - bool OnStateMachineThread() const MOZ_OVERRIDE; - - // Returns true if the current thread is the decode thread. - bool OnDecodeThread() const MOZ_OVERRIDE; - - // Returns main decoder's monitor for synchronised access. - ReentrantMonitor& GetReentrantMonitor() MOZ_OVERRIDE; - - // Called on the decode thread from WebMReader. - ImageContainer* GetImageContainer() MOZ_OVERRIDE; - - // Called when Metadata has been read; notifies that index data is read. - // Called on the decode thread only. - void OnReadMetadataCompleted() MOZ_OVERRIDE; - - // Stop updating the bytes downloaded for progress notifications. Called - // when seeking to prevent wild changes to the progress notification. - // Must be called with the decoder monitor held. - void StopProgressUpdates() MOZ_OVERRIDE; - - // Allow updating the bytes downloaded for progress notifications. Must - // be called with the decoder monitor held. - void StartProgressUpdates() MOZ_OVERRIDE; - - // Overridden to cleanup ref to |DASHDecoder|. Called on main thread only. - void Shutdown() { - NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - // Remove ref to state machine before |MediaDecoder|::|Shutdown|, since - // |DASHDecoder| is responsible for its shutdown. - mDecoderStateMachine = nullptr; - // Call parent class shutdown. - MediaDecoder::Shutdown(); - NS_ENSURE_TRUE_VOID(mShuttingDown); - // Cleanup ref to main decoder. - mMainDecoder = nullptr; - } - - // Drop reference to state machine and mReader (owned by state machine). - // Only called during shutdown dance. - void ReleaseStateMachine(); - - // Notifies the element that decoding has failed. - void DecodeError(); - -private: - // Populates |mByteRanges| by calling |GetIndexByteRanges| from |mReader|. - // Called on the main thread only. - nsresult PopulateByteRanges(); - - // The main decoder. - nsRefPtr mMainDecoder; - // This decoder's MPD |Representation| object. - Representation const * mMPDRepresentation; - - // Countdown var for loading metadata byte ranges. - uint16_t mMetadataChunkCount; - - // All the byte ranges for this |Representation|. - nsTArray mByteRanges; - - // Byte range for the init and index bytes. - MediaByteRange mInitByteRange; - MediaByteRange mIndexByteRange; - - // The current byte range being requested. - MediaByteRange mCurrentByteRange; - // Index of the current byte range. Initialized to -1. - int32_t mSubsegmentIdx; - - // Ptr to the reader object for this |Representation|. Owned by state - // machine. - DASHRepReader* mReader; -}; - -} // namespace mozilla - -#endif //DASHRepDecoder_h_ diff --git a/content/media/dash/DASHRepReader.h b/content/media/dash/DASHRepReader.h deleted file mode 100644 index 23b4cf22ea57..000000000000 --- a/content/media/dash/DASHRepReader.h +++ /dev/null @@ -1,68 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ - -/* This Source Code Form Is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* DASH - Dynamic Adaptive Streaming over HTTP - * - * DASH is an adaptive bitrate streaming technology where a multimedia file is - * partitioned into one or more segments and delivered to a client using HTTP. - * - * see DASHDecoder.cpp for comments on DASH object interaction - */ - -#if !defined(DASHRepReader_h_) -#define DASHRepReader_h_ - -#include "VideoUtils.h" -#include "MediaDecoderReader.h" -#include "DASHReader.h" - -namespace mozilla { - -class DASHReader; - -class DASHRepReader : public MediaDecoderReader -{ -public: - DASHRepReader(AbstractMediaDecoder* aDecoder) - : MediaDecoderReader(aDecoder) { } - virtual ~DASHRepReader() { } - - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DASHRepReader) - - virtual void SetMainReader(DASHReader *aMainReader) = 0; - - // Sets range for initialization bytes; used by DASH. - virtual void SetInitByteRange(MediaByteRange &aByteRange) = 0; - - // Sets range for index frame bytes; used by DASH. - virtual void SetIndexByteRange(MediaByteRange &aByteRange) = 0; - - // Returns the index of the subsegment which contains the seek time (usecs). - virtual int64_t GetSubsegmentForSeekTime(int64_t aSeekToTime) = 0; - - // Returns list of ranges for index frame start/end offsets. Used by DASH. - virtual nsresult GetSubsegmentByteRanges(nsTArray& aByteRanges) = 0; - - // Returns true if the reader has reached a DASH switch access point. - virtual bool HasReachedSubsegment(uint32_t aSubsegmentIndex) = 0; - - // Requests a seek to the start of a particular DASH subsegment. - virtual void RequestSeekToSubsegment(uint32_t aIdx) = 0; - - // Reader should stop reading at the start of the specified subsegment, and - // should prepare for the next reader to add data to the video queue. - // Should be implemented by a sub-reader, e.g. |nsDASHWebMReader|. - virtual void RequestSwitchAtSubsegment(int32_t aCluster, - MediaDecoderReader* aNextReader) = 0; - - // Returns true if data at the end of the final subsegment has been cached. - virtual bool IsDataCachedAtEndOfSubsegments() = 0; -}; - -}// namespace mozilla - -#endif /*DASHRepReader*/ diff --git a/content/media/dash/Makefile.in b/content/media/dash/Makefile.in deleted file mode 100644 index d17d2cd9c9e4..000000000000 --- a/content/media/dash/Makefile.in +++ /dev/null @@ -1,19 +0,0 @@ -# -*- Mode: makefile; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- # -# vim: set ts=2 et sw=2 tw=80: # -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. -# -# Contributor(s): -# Steve Workman - -include $(topsrcdir)/config/rules.mk - -LOCAL_INCLUDES := \ - -I$(topsrcdir)/netwerk/dash/mpd \ - -I$(srcdir)/../webm \ - -I$(srcdir)/../../base/src \ - -I$(srcdir)/../../html/content/src \ - $(MOZ_LIBVPX_INCLUDES) \ - $(NULL) diff --git a/content/media/dash/moz.build b/content/media/dash/moz.build deleted file mode 100644 index 5bfe1d772020..000000000000 --- a/content/media/dash/moz.build +++ /dev/null @@ -1,25 +0,0 @@ -# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -MODULE = 'content' - -EXPORTS += [ - 'DASHDecoder.h', - 'DASHReader.h', - 'DASHRepDecoder.h', - 'DASHRepReader.h', -] - -SOURCES += [ - 'DASHDecoder.cpp', - 'DASHReader.cpp', - 'DASHRepDecoder.cpp', -] - -LIBRARY_NAME = 'gkcondash_s' - -LIBXUL_LIBRARY = True - diff --git a/content/media/moz.build b/content/media/moz.build index 7e2ce4543260..87b3af69d12b 100644 --- a/content/media/moz.build +++ b/content/media/moz.build @@ -26,9 +26,6 @@ if CONFIG['MOZ_WEBM']: if CONFIG['MOZ_GSTREAMER']: PARALLEL_DIRS += ['gstreamer'] -if CONFIG['MOZ_DASH']: - PARALLEL_DIRS += ['dash'] - if CONFIG['MOZ_DIRECTSHOW']: PARALLEL_DIRS += ['directshow'] diff --git a/layout/build/Makefile.in b/layout/build/Makefile.in index 972012f0f2c0..95dc5c2c59ae 100644 --- a/layout/build/Makefile.in +++ b/layout/build/Makefile.in @@ -199,12 +199,6 @@ SHARED_LIBRARY_LIBS += \ $(DEPTH)/content/media/mediasource/$(LIB_PREFIX)gkconmediasource_s.$(LIB_SUFFIX) \ $(NULL) -ifdef MOZ_DASH -SHARED_LIBRARY_LIBS += \ - $(DEPTH)/content/media/dash/$(LIB_PREFIX)gkcondash_s.$(LIB_SUFFIX) \ - $(NULL) -endif - ifdef MOZ_WEBSPEECH SHARED_LIBRARY_LIBS += \ $(DEPTH)/content/media/webspeech/recognition/$(LIB_PREFIX)gkconwebspeechrecognition_s.$(LIB_SUFFIX) \ diff --git a/layout/build/nsContentDLF.h b/layout/build/nsContentDLF.h index 87427478a55f..327915cc7c35 100644 --- a/layout/build/nsContentDLF.h +++ b/layout/build/nsContentDLF.h @@ -63,13 +63,6 @@ NS_NewContentDocumentLoaderFactory(nsIDocumentLoaderFactory** aResult); #define CONTENTDLF_WEBM_CATEGORIES #endif -#ifdef MOZ_DASH -#define CONTENTDLF_DASH_CATEGORIES \ - { "Gecko-Content-Viewers", APPLICATION_DASH, "@mozilla.org/content/document-loader-factory;1" }, -#else -#define CONTENTDLF_DASH_CATEGORIES -#endif - #define CONTENTDLF_CATEGORIES \ { "Gecko-Content-Viewers", TEXT_HTML, "@mozilla.org/content/document-loader-factory;1" }, \ { "Gecko-Content-Viewers", TEXT_PLAIN, "@mozilla.org/content/document-loader-factory;1" }, \ @@ -91,8 +84,7 @@ NS_NewContentDocumentLoaderFactory(nsIDocumentLoaderFactory** aResult); { "Gecko-Content-Viewers", VIEWSOURCE_CONTENT_TYPE, "@mozilla.org/content/document-loader-factory;1" }, \ { "Gecko-Content-Viewers", IMAGE_SVG_XML, "@mozilla.org/content/document-loader-factory;1" }, \ { "Gecko-Content-Viewers", APPLICATION_MATHML_XML, "@mozilla.org/content/document-loader-factory;1" }, \ - CONTENTDLF_WEBM_CATEGORIES \ - CONTENTDLF_DASH_CATEGORIES + CONTENTDLF_WEBM_CATEGORIES #endif diff --git a/modules/libpref/src/init/all.js b/modules/libpref/src/init/all.js index 3df16e3f28df..a38e4ee2ec71 100644 --- a/modules/libpref/src/init/all.js +++ b/modules/libpref/src/init/all.js @@ -215,9 +215,6 @@ pref("media.wave.enabled", true); #ifdef MOZ_WEBM pref("media.webm.enabled", true); #endif -#ifdef MOZ_DASH -pref("media.dash.enabled", false); -#endif #ifdef MOZ_GSTREAMER pref("media.gstreamer.enabled", true); #endif diff --git a/netwerk/build/Makefile.in b/netwerk/build/Makefile.in index f81ea6fffce8..2da4b2f3dbdc 100644 --- a/netwerk/build/Makefile.in +++ b/netwerk/build/Makefile.in @@ -55,11 +55,6 @@ ifeq (android,$(MOZ_WIDGET_TOOLKIT)) ../system/android/$(LIB_PREFIX)neckosystem_s.$(LIB_SUFFIX) endif -ifdef MOZ_DASH - SHARED_LIBRARY_LIBS += \ - ../dash/mpd/$(LIB_PREFIX)nkdashmpd_s.$(LIB_SUFFIX) -endif - LOCAL_INCLUDES = \ -I$(srcdir)/../base/src \ -I$(srcdir)/../dns \ diff --git a/netwerk/dash/moz.build b/netwerk/dash/moz.build deleted file mode 100644 index 3202d0ff2be8..000000000000 --- a/netwerk/dash/moz.build +++ /dev/null @@ -1,7 +0,0 @@ -# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -PARALLEL_DIRS += ['mpd'] diff --git a/netwerk/dash/mpd/AdaptationSet.cpp b/netwerk/dash/mpd/AdaptationSet.cpp deleted file mode 100644 index a871e269d6da..000000000000 --- a/netwerk/dash/mpd/AdaptationSet.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* - * AdaptationSet.cpp - ***************************************************************************** - * Copyright(C) 2010 - 2012 Klagenfurt University - * - * Created on: Jan 27, 2012 - * Authors: Christopher Mueller - * Christian Timmerer - * Contributors: - * Steve Workman - * - * This Source Code Form Is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. - *****************************************************************************/ - -/* DASH - Dynamic Adaptive Streaming over HTTP - * - * DASH is an adaptive bitrate streaming technology where a multimedia file is - * partitioned into one or more segments and delivered to a client using HTTP. - * - * |AdaptationSet| - * - * Describes a type of media in a |Period| of time in the media presentation, - * e.g. an audio or video stream. Direct child of |Period|, which contains 1+ - * available pieces of media, available during that time period. - * |AdaptationSet| itself contains one or more |Representations| which describe - * different versions of the media, most commonly different bitrate encodings. - * - * Common class used by all DASH Profiles. - * Populated by implementation of MPD Parser. - * Used as data source by implementation of MPD Manager. - * - * |MPD| - * --> |Period|s of time. - * --> |AdaptationSet|s for each type or group of media content. - * --> |Representation|s of media, encoded with different bitrates. - * --> |Segment|s of media, identified by URL (+optional byte - * range. - */ - -#include "AdaptationSet.h" - -namespace mozilla { -namespace net { - -int32_t -AdaptationSet::GetWidth() const -{ - return mWidth; -} - -void -AdaptationSet::SetWidth(int32_t const aWidth) -{ - mWidth = aWidth; -} - -int32_t -AdaptationSet::GetHeight() const -{ - return mHeight; -} - -void -AdaptationSet::SetHeight(int32_t const aHeight) -{ - mHeight = aHeight; -} - -void -AdaptationSet::GetMIMEType(nsAString& aMIMEType) const -{ - aMIMEType = mMIMEType; -} - -void -AdaptationSet::SetMIMEType(nsAString const &aMIMEType) -{ - NS_ENSURE_FALSE_VOID(aMIMEType.IsEmpty()); - mMIMEType = aMIMEType; -} - -Representation const * -AdaptationSet::GetRepresentation(uint32_t aIndex) const -{ - NS_ENSURE_TRUE(aIndex < mRepresentations.Length(), nullptr); - return mRepresentations[aIndex]; -} - -void -AdaptationSet::AddRepresentation(Representation* aRep) -{ - NS_ENSURE_TRUE_VOID(aRep); - // Only add if it's not already in the array. - if (!mRepresentations.Contains(aRep)) { - mRepresentations.InsertElementSorted(aRep, CompareRepresentationBitrates()); - } -} - -uint16_t -AdaptationSet::GetNumRepresentations() const -{ - return mRepresentations.Length(); -} - -void -AdaptationSet::EnableBitstreamSwitching(bool aEnable) -{ - mIsBitstreamSwitching = aEnable; -} - -bool -AdaptationSet::IsBitstreamSwitchingEnabled() const -{ - return mIsBitstreamSwitching; -} - -}//namespace net -}//namespace mozilla diff --git a/netwerk/dash/mpd/AdaptationSet.h b/netwerk/dash/mpd/AdaptationSet.h deleted file mode 100644 index 1067fcf08027..000000000000 --- a/netwerk/dash/mpd/AdaptationSet.h +++ /dev/null @@ -1,107 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* - * AdaptationSet.h - ***************************************************************************** - * Copyright(C) 2010 - 2012 Klagenfurt University - * - * Created on: Jan 27, 2012 - * Authors: Christopher Mueller - * Christian Timmerer - * Contributors: - * Steve Workman - * - * This Source Code Form Is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. - *****************************************************************************/ - -/* DASH - Dynamic Adaptive Streaming over HTTP - * - * DASH is an adaptive bitrate streaming technology where a multimedia file is - * partitioned into one or more segments and delivered to a client using HTTP. - * - * |AdaptationSet| - * - * Describes a type of media in a |Period| of time in the media presentation, - * e.g. an audio or video stream. Direct child of |Period|, which contains 1+ - * available pieces of media, available during that time period. - * |AdaptationSet| itself contains one or more |Representations| which describe - * different versions of the media, most commonly different bitrate encodings. - * - * Common class used by all DASH Profiles. - * Populated by implementation of MPD Parser. - * Used as data source by implementation of MPD Manager. - * - * |MPD| - * --> |Period|s of time. - * --> |AdaptationSet|s for each type or group of media content. - * --> |Representation|s of media, encoded with different bitrates. - * --> |Segment|s of media, identified by URL (+optional byte - * range. - */ - -#ifndef ADAPTATIONSET_H_ -#define ADAPTATIONSET_H_ - -#include "nsAutoPtr.h" -#include "nsString.h" -#include "nsTArray.h" -#include "Representation.h" - -namespace mozilla { -namespace net { - -class AdaptationSet -{ -public: - AdaptationSet() : - mWidth(0), - mHeight(0), - mIsBitstreamSwitching(false) - { - MOZ_COUNT_CTOR(AdaptationSet); - } - virtual ~AdaptationSet() { - MOZ_COUNT_DTOR(AdaptationSet); - } - - // Setters and getters for @width, @height and @mimetype. - int32_t GetWidth() const; - void SetWidth(int32_t const aWidth); - int32_t GetHeight() const; - void SetHeight(int32_t const aHeight); - void GetMIMEType(nsAString& aMIMEType) const; - void SetMIMEType(nsAString const &aMIMEType); - - // Gets a list of media |Representation| objects for this |AdaptationSet|. - Representation const * GetRepresentation(uint32_t) const; - - // Adds a media |Representation| to this |AdaptationSet|. Takes ownership to - // manage deletion. - void AddRepresentation(Representation* aRep); - - // Returns the number of media |Representations|. - uint16_t GetNumRepresentations() const; - - // En/Dis-ables switching between media |Representation|s. - void EnableBitstreamSwitching(bool const aEnable); - bool IsBitstreamSwitchingEnabled() const; - -private: - // Array of media |Representations| to switch between. - // Ordered list, ascending in order of bitrates. - nsTArray > mRepresentations; - - // @width, height and @mimetype of this media stream. - int32_t mWidth; - int32_t mHeight; - nsString mMIMEType; - - // If true, switching between media |Representation|s is allowed. - bool mIsBitstreamSwitching; -}; -} -} - -#endif /* ADAPTATIONSET_H_ */ diff --git a/netwerk/dash/mpd/IMPDManager.cpp b/netwerk/dash/mpd/IMPDManager.cpp deleted file mode 100644 index ae79b5567071..000000000000 --- a/netwerk/dash/mpd/IMPDManager.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* - * IMPDManager.cpp - ***************************************************************************** - * Copyrigh(C) 2010 - 2011 Klagenfurt University - * - * Created on: Apr 20, 2011 - * Authors: Christopher Mueller - * Christian Timmerer - * Contributors: - * Steve Workman - * - * This Source Code Form Is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. - *****************************************************************************/ - -#include "nsIDOMElement.h" -#include "IMPDManager.h" -#include "nsDASHWebMODManager.h" -#include "nsDASHWebMODParser.h" - - -namespace mozilla { -namespace net { - -/* static */ -IMPDManager* -IMPDManager::Create(DASHMPDProfile aProfile, nsIDOMElement* aRoot) -{ - switch(aProfile) - { - case WebMOnDemand: - return CreateWebMOnDemandManager(aRoot); - default: - return nullptr; - } -} - -/* static */ -IMPDManager* -IMPDManager::CreateWebMOnDemandManager(nsIDOMElement* aRoot) -{ - // Parse DOM elements into MPD objects. - nsDASHWebMODParser parser(aRoot); - - return new nsDASHWebMODManager(parser.Parse()); -} - - - -}//namespace net -}//namespace mozilla diff --git a/netwerk/dash/mpd/IMPDManager.h b/netwerk/dash/mpd/IMPDManager.h deleted file mode 100644 index 3b57f8921592..000000000000 --- a/netwerk/dash/mpd/IMPDManager.h +++ /dev/null @@ -1,133 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts =2 et sw =2 tw =80: */ -/* - * IMPDManager.h - ***************************************************************************** - * Copyrigh(C) 2010 - 2011 Klagenfurt University - * - * Created on: Aug 10, 2010 - * Authors: Christopher Mueller - * Christian Timmerer - * Contributors: - * Steve Workman - * - * This Source Code Form Is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. - *****************************************************************************/ - -/* DASH - Dynamic Adaptive Streaming over HTTP. - * - * DASH is an adaptive bitrate streaming technology where a multimedia file is - * partitioned into one or more segments and delivered to a client using HTTP. - * - * (see DASHDecoder.cpp for info on DASH interaction with the media engine). - * - * Media Presentation Description (MPD) Manager. - * - * Interface to MPD classes, populated with data from MPD XML manifest. - * Employs adaptation algorithm to determine best representation of media to - * download. - * Adaptation algorithm is separate and passed into manager. - * Interface aims to be an abstracted API for all DASH MPD Profiles - * (e.g. DASH WebM On Demand Profile). - */ - -#ifndef IMPDMANAGER_H_ -#define IMPDMANAGER_H_ - -#include "nsTArray.h" -#include "nsIURI.h" -#include "nsIDOMElement.h" - -namespace mozilla { -namespace net { - -// DASH MPD Profile Type -enum DASHMPDProfile -{ - WebMOnDemand, - NotValid - // Extend this for other types. -}; - -class Period; -class Representation; -class Segment; - -class IMPDManager -{ -public: - // Describes the media type (audio/video) of the |AdaptationSet|. - enum AdaptationSetType { - DASH_ASTYPE_INVALID = 0, - DASH_VIDEO_STREAM, - DASH_AUDIO_STREAM, - DAHS_AUDIO_VIDEO_STREAM - }; - IMPDManager() - { - MOZ_COUNT_CTOR(IMPDManager); - } - - virtual ~IMPDManager() - { - MOZ_COUNT_DTOR(IMPDManager); - } - - // Used to get the first |Period| in the presentation. - virtual Period const * GetFirstPeriod() const = 0; - - // Gets the total number of |AdaptationSet|s in the first |Period|. - // Usually, this should be 2 for audio and video. - // XXX Future versions may require a |Period| index. - // XXX Future versions may have multiple tracks for audio. - virtual uint32_t GetNumAdaptationSets() const = 0; - - // Returns the media type for the given |AdaptationSet|, audio/video. - virtual AdaptationSetType - GetAdaptationSetType(uint32_t const aAdaptSetIdx) const = 0; - - // Gets the number of media |Representation|s for the given |AdaptationSet|. - // e.g how many bitrate encodings are there of the audio stream? - virtual uint32_t - GetNumRepresentations(uint32_t const aAdaptSetIdx) const = 0; - - // Gets the specified |Representation| from the specified |AdaptationSet|, - // e.g. get metadata about the 64Kbps encoding of the video stream. - virtual Representation const * - GetRepresentation(uint32_t const aAdaptSetIdx, - uint32_t const aRepIdx) const = 0; - - // Gets the URL of the first media |Segment| for the specific media - // |Representation|, e.g. the url of the first 64Kbps video segment. - virtual nsresult GetFirstSegmentUrl(uint32_t const aAdaptSetIdx, - uint32_t const aRepIdx, - nsAString &aUrl) const = 0; - - // Returns the start time of the presentation in seconds. - virtual double GetStartTime() const = 0; - - // Returns the duration of the presentation in seconds. - virtual double GetDuration() const = 0; - - // Gets index of the |Representation| with next highest bitrate to the - // estimated bandwidth passed in. Returns true if there is at least one - // |Representation| with a bitrate lower than |aBandwidth|; otherwise returns - // false. Depends on |mRepresentations| being an ordered list. - virtual bool GetBestRepForBandwidth(uint32_t aAdaptSetIdx, - uint64_t aBandwidth, - uint32_t &aRepIdx) const = 0; -public: - // Factory method. - static IMPDManager* Create(DASHMPDProfile Profile, nsIDOMElement* aRoot); - -private: - // Used by factory method. - static IMPDManager* CreateWebMOnDemandManager(nsIDOMElement* aRoot); -}; - -}//namespace net -}//namespace mozilla - -#endif /* IMPDMANAGER_H_ */ diff --git a/netwerk/dash/mpd/IMPDParser.h b/netwerk/dash/mpd/IMPDParser.h deleted file mode 100644 index c80f1c463b32..000000000000 --- a/netwerk/dash/mpd/IMPDParser.h +++ /dev/null @@ -1,53 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* - * IMPDParser.h - ***************************************************************************** - * Copyrigh(C) 2010 - 2011 Klagenfurt University - * - * Created on: Aug 10, 2010 - * Authors: Christopher Mueller - * Christian Timmerer - * Contributors: - * Steve Workman - * - * This Source Code Form Is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. - *****************************************************************************/ - -/* DASH - Dynamic Adaptive Streaming over HTTP. - * - * DASH is an adaptive bitrate streaming technology where a multimedia file is - * partitioned into one or more segments and delivered to a client using HTTP. - * - * (see DASHDecoder.cpp for info on DASH interaction with the media engine). - * - * Media Presentation Description (MPD) Parser. - * - * Interface to MPD parser. Derived classes parse MPD XML manifest and populate - * MPD classes for use by MPD Manager. - * Interface aims to be an abstracted API for all DASH MPD Profiles - * (e.g. DASH WebM On Demand Profile). - */ - -#ifndef IMPDPARSER_H_ -#define IMPDPARSER_H_ - -#include "MPD.h" - -namespace mozilla { -namespace net { - -class IMPDParser -{ -public: - // Parses XML file to create and populate MPD classes. - // Called by MPD Manager. - virtual MPD* Parse() = 0; -}; - -}// namespace net -}// namespace mozilla - -#endif /* IMPDPARSER_H_ */ diff --git a/netwerk/dash/mpd/MPD.cpp b/netwerk/dash/mpd/MPD.cpp deleted file mode 100644 index 6723da2cd615..000000000000 --- a/netwerk/dash/mpd/MPD.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* - * MPD.cpp - ***************************************************************************** - * Copyright(C) 2010 - 2011 Klagenfurt University - * - * Created on: Aug 10, 2010 - * Authors: Christopher Mueller - * Christian Timmerer - * Contributors: - * Steve Workman - * - * This Source Code Form Is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. - *****************************************************************************/ - -/* DASH - Dynamic Adaptive Streaming over HTTP - * - * DASH is an adaptive bitrate streaming technology where a multimedia file is - * partitioned into one or more segments and delivered to a client using HTTP. - * - * |MPD| - Media Presentation Description - * - * Describes the media presentation. Top of the hierarchy in an MPD file. - * Contains one or a series of contiguous |Period|s, which contain 1+ available - * pieces of media, available during that time period, e.g. audio in various - * languages, a video component. - * - * Common class used by all DASH Profiles. - * Populated by implementation of MPD Parser. - * Used as data source by implementation of MPD Manager. - * - * |MPD| - * --> |Period|s of time. - * --> |AdaptationSet|s for each type or group of media content. - * --> |Representation|s of media, encoded with different bitrates. - * --> |Segment|s of media, identified by URL (+optional byte - * range. - */ - -#include "nsTArray.h" -#include "MPD.h" - - -namespace mozilla { -namespace net { - -void -MPD::AddPeriod(Period* aPeriod) -{ - NS_ENSURE_TRUE_VOID(aPeriod); - // Only add |Period| if it's not in the array already. - if (!mPeriods.Contains(aPeriod)) { - mPeriods.AppendElement(aPeriod); - } -} - -Period const * -MPD::GetPeriod(uint32_t aIndex) const -{ - NS_ENSURE_TRUE(aIndex < mPeriods.Length(), nullptr); - return mPeriods[aIndex]; -} - -uint32_t const -MPD::GetNumPeriods() const -{ - return mPeriods.Length(); -} - -void -MPD::AddBaseUrl(nsAString const& aUrl) -{ - NS_ENSURE_FALSE_VOID(aUrl.IsEmpty()); - // Only add |BaseUrl| string if it's not in the array already. - if (!mBaseUrls.Contains(aUrl)) { - mBaseUrls.AppendElement(aUrl); - } -} - -nsAString const& -MPD::GetBaseUrl(uint32_t aIndex) const -{ - NS_ENSURE_TRUE(aIndex < mBaseUrls.Length(), NS_LITERAL_STRING("")); - return mBaseUrls[aIndex]; -} - -}//namespace net -}//namespace mozilla diff --git a/netwerk/dash/mpd/MPD.h b/netwerk/dash/mpd/MPD.h deleted file mode 100644 index f82c075e384b..000000000000 --- a/netwerk/dash/mpd/MPD.h +++ /dev/null @@ -1,90 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* - * MPD.h - ***************************************************************************** - * Copyright(C) 2010 - 2011 Klagenfurt University - * - * Created on: Aug 10, 2010 - * Authors: Christopher Mueller - * Christian Timmerer - * Contributors: - * Steve Workman - * - * This Source Code Form Is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. - *****************************************************************************/ - -/* DASH - Dynamic Adaptive Streaming over HTTP - * - * DASH is an adaptive bitrate streaming technology where a multimedia file is - * partitioned into one or more segments and delivered to a client using HTTP. - * - * |MPD| - Media Presentation Description - * - * Describes the media presentation. Top of the hierarchy in an MPD file. - * Contains one or a series of contiguous |Period|s, which contain 1+ available - * pieces of media, available during that time period, e.g. audio in various - * languages, a video component. - * - * Common class used by all DASH Profiles. - * Populated by implementation of MPD Parser. - * Used as data source by implementation of MPD Manager. - * - * |MPD| - * --> |Period|s of time. - * --> |AdaptationSet|s for each type or group of media content. - * --> |Representation|s of media, encoded with different bitrates. - * --> |Segment|s of media, identified by URL (+optional byte - * range. - */ - -#ifndef MPD_H_ -#define MPD_H_ - -#include "nsTArray.h" -#include "nsString.h" -#include "Period.h" - -namespace mozilla { -namespace net { - -class MPD -{ -public: - MPD() - { - MOZ_COUNT_CTOR(MPD); - } - virtual ~MPD() { - MOZ_COUNT_DTOR(MPD); - } - - // At least one media content |Period|s per Media Presentation. The |MPD| - // contains 1+ available pieces of media, available during that time period - // e.g. audio in various languages, a video component. - // |MPD| takes ownership of |Period| in |AddPeriod| and will manage deletion. - void AddPeriod(Period* aPeriod); - Period const * GetPeriod(uint32_t aIndex) const; - uint32_t const GetNumPeriods() const; - - // Adds/Gets an absolute/relative |BaseURL| for the whole document. - // Note: A relative |BaseURL| for the whole document will use the URL for the - // MPD file itself as base. - void AddBaseUrl(nsAString const& aUrl); - nsAString const& GetBaseUrl(uint32_t aIndex) const; - bool HasBaseUrls() { return !mBaseUrls.IsEmpty(); } - -private: - // List of media content |Period|s in this media presentation. - nsTArray > mPeriods; - - // List of |BaseURL|s which can be used to access the media. - nsTArray mBaseUrls; -}; - -}//namespace net -}//namespace mozilla - -#endif /* MPD_H_ */ diff --git a/netwerk/dash/mpd/Makefile.in b/netwerk/dash/mpd/Makefile.in deleted file mode 100644 index 993b41e582cf..000000000000 --- a/netwerk/dash/mpd/Makefile.in +++ /dev/null @@ -1,15 +0,0 @@ -# -*- Mode: makefile; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- # -# vim: set ts=2 et sw=2 tw=80: # -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. -# -# Contributor(s): -# Steve Workman - -LOCAL_INCLUDES := \ - -I$(topsrcdir)/content/base/src \ - -I$(topsrcdir)/content/html/content/public \ - -I$(topsrcdir)/content/html/content/src \ - $(NULL) diff --git a/netwerk/dash/mpd/Period.cpp b/netwerk/dash/mpd/Period.cpp deleted file mode 100644 index aed37e42f649..000000000000 --- a/netwerk/dash/mpd/Period.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* - * Period.cpp - ***************************************************************************** - * Copyright(C) 2010 - 2011 Klagenfurt University - * - * Created on: Aug 10, 2010 - * Authors: Christopher Mueller - * Christian Timmerer - * Contributors: - * Steve Workman - * - * This Source Code Form Is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. - *****************************************************************************/ - -/* DASH - Dynamic Adaptive Streaming over HTTP - * - * DASH is an adaptive bitrate streaming technology where a multimedia file is - * partitioned into one or more segments and delivered to a client using HTTP. - * - * |Period| - * - * Describes a period of time in the media presentation. Direct child of |MPD|. - * Alone, or one of a series of contiguous |Period|s, which contain 1+ available - * pieces of media, available during that time period, e.g. audio in various - * languages, a video component. - * - * Common class used by all DASH Profiles. - * Populated by implementation of MPD Parser. - * Used as data source by implementation of MPD Manager. - * - * |MPD| - * --> |Period|s of time. - * --> |AdaptationSet|s for each type or group of media content. - * --> |Representation|s of media, encoded with different bitrates. - * --> |Segment|s of media, identified by URL (+optional byte - * range. - */ - -#include "nsAutoPtr.h" -#include "nsTArray.h" -#include "Period.h" - -namespace mozilla { -namespace net { - -AdaptationSet const * -Period::GetAdaptationSet(uint32_t aIndex) const -{ - NS_ENSURE_TRUE(aIndex < mAdaptationSets.Length(), nullptr); - return mAdaptationSets[aIndex]; -} - -void -Period::AddAdaptationSet(AdaptationSet* aAdaptationSet) -{ - NS_ENSURE_TRUE_VOID(aAdaptationSet); - // Only add |AdaptationSet| ptr if it's not in the array already. - if (!mAdaptationSets.Contains(aAdaptationSet)) { - mAdaptationSets.AppendElement(aAdaptationSet); - } -} - -uint16_t const -Period::GetNumAdaptationSets() const -{ - return mAdaptationSets.Length(); -} - -double const -Period::GetStart() const -{ - return mStart; -} - -double const -Period::GetDuration() const -{ - return mDuration; -} - -void -Period::SetStart(double const aStart) -{ - mStart = aStart; -} - -void -Period::SetDuration(double const aDuration) -{ - mDuration = aDuration; -} - -}//namespace net -}//namespace mozilla diff --git a/netwerk/dash/mpd/Period.h b/netwerk/dash/mpd/Period.h deleted file mode 100644 index 5f51f417533b..000000000000 --- a/netwerk/dash/mpd/Period.h +++ /dev/null @@ -1,96 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* - * Period.h - ***************************************************************************** - * Copyrigh(C) 2010 - 2011 Klagenfurt University - * - * Created on: Aug 10, 2010 - * Authors: Christopher Mueller - * Christian Timmerer - * Contributors: - * Steve Workman - * - * This Source Code Form Is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. - *****************************************************************************/ -#ifndef PERIOD_H_ -#define PERIOD_H_ - -#include "nsTArray.h" -#include "AdaptationSet.h" -#include "Representation.h" - -/* DASH - Dynamic Adaptive Streaming over HTTP - * - * DASH is an adaptive bitrate streaming technology where a multimedia file is - * partitioned into one or more segments and delivered to a client using HTTP. - * - * |Period| - * - * Describes a period of time in the media presentation. Direct child of |MPD|. - * Alone, or one of a series of contiguous |Period|s, which contain 1+ available - * pieces of media, available during that time period, e.g. audio in various - * languages, a video component. - * - * Common class used by all DASH Profiles. - * Populated by implementation of MPD Parser. - * Used as data source by implementation of MPD Manager. - * - * |MPD| - * --> |Period|s of time. - * --> |AdaptationSet|s for each type or group of media content. - * --> |Representation|s of media, encoded with different bitrates. - * --> |Segment|s of media, identified by URL (+optional byte - * range. - */ - -#include "nsAutoPtr.h" - -namespace mozilla { -namespace net { - -class Period -{ -public: - Period() - { - MOZ_COUNT_CTOR(Period); - } - virtual ~Period() { - MOZ_COUNT_DTOR(Period); - } - - // Gets/Adds |AdaptationSet|s of media for this media content |Period|. - AdaptationSet const * GetAdaptationSet(uint32_t aIndex) const; - // |Period| takes ownership of |AdaptationSet| here and will manage deletion. - void AddAdaptationSet(AdaptationSet* aAdaptationSet); - - // Returns the num. of |AdaptationSet|s in this media content |Period|. - uint16_t const GetNumAdaptationSets() const; - - // Gets/Sets the start time of this media content |Period| in seconds. - double const GetStart() const; - void SetStart(double const aStart); - - // Gets/Sets the duration of this media content |Period| in seconds. - double const GetDuration() const; - void SetDuration(double const aDuration); - -private: - // List of |AdaptationSet|s of media in this |Period|. - nsTArray > mAdaptationSets; - - // Start time in seconds for this |Period|. - double mStart; - - // Duration in seconds for this |Period|. - double mDuration; -}; - -}//namespace net -}//namespace mozilla - - -#endif /* PERIOD_H_ */ diff --git a/netwerk/dash/mpd/Representation.cpp b/netwerk/dash/mpd/Representation.cpp deleted file mode 100644 index efd3d7bbede4..000000000000 --- a/netwerk/dash/mpd/Representation.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* - * Representation.cpp - ***************************************************************************** - * Copyrigh(C) 2010 - 2011 Klagenfurt University - * - * Created on: Aug 10, 2010 - * Authors: Christopher Mueller - * Christian Timmerer - * Contributors: - * Steve Workman - * - * This Source Code Form Is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. - *****************************************************************************/ - -/* DASH - Dynamic Adaptive Streaming over HTTP - * - * DASH is an adaptive bitrate streaming technology where a multimedia file is - * partitioned into one or more segments and delivered to a client using HTTP. - * - * |Representation| - * - * Describes a particular version of a piece of media described in an - * |AdaptationSet|, a common example being a particular bitrate encoding for an - * audio or video stream. Direct child of |AdaptationSet|, which contains 1+ - * available |Representation|s of the media. - * - * Common class used by all DASH Profiles. - * Populated by implementation of MPD Parser. - * Used as data source by implementation of MPD Manager. - * - * |MPD| - * --> |Period|s of time. - * --> |AdaptationSet|s for each type or group of media content. - * --> |Representation|s of media, encoded with different bitrates. - * --> |Segment|s of media, identified by URL (+optional byte - * range. - */ - -#include "nsTArray.h" -#include "Representation.h" - -namespace mozilla { -namespace net { - -int64_t const -Representation::GetBitrate() const -{ - return mBitrate; -} - -void -Representation::SetBitrate(int64_t aBitrate) -{ - mBitrate = aBitrate; -} - -void -Representation::SetWidth(int32_t const aWidth) -{ - mWidth = aWidth; -} - -int32_t const -Representation::GetWidth() const -{ - return mWidth; -} - -void -Representation::SetHeight(int32_t aHeight) -{ - mHeight = aHeight; -} - -int32_t const -Representation::GetHeight() const -{ - return mHeight; -} - -void -Representation::AddBaseUrl(nsAString const& aUrl) -{ - NS_ENSURE_FALSE_VOID(aUrl.IsEmpty()); - // Only add if it's not already in the array. - if (!mBaseUrls.Contains(aUrl)) { - mBaseUrls.AppendElement(aUrl); - } -} - -nsAString const & -Representation::GetBaseUrl(uint32_t aIndex) const -{ - NS_ENSURE_TRUE(aIndex < mBaseUrls.Length(), NS_LITERAL_STRING("")); - return mBaseUrls[aIndex]; -} - -SegmentBase const* -Representation::GetSegmentBase() const -{ - return mSegmentBase; -} - -void -Representation::SetSegmentBase(SegmentBase* aBase) -{ - NS_ENSURE_TRUE_VOID(aBase); - // Don't reassign if the ptrs or contents are equal. - if (mSegmentBase != aBase - || (mSegmentBase && (*mSegmentBase != *aBase))) { - mSegmentBase = aBase; - } -} - -}//namespace net -}//namespace mozilla diff --git a/netwerk/dash/mpd/Representation.h b/netwerk/dash/mpd/Representation.h deleted file mode 100644 index d450e2c58fe5..000000000000 --- a/netwerk/dash/mpd/Representation.h +++ /dev/null @@ -1,137 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* - * Representation.h - ***************************************************************************** - * Copyrigh(C) 2010 - 2011 Klagenfurt University - * - * Created on: Aug 10, 2010 - * Authors: Christopher Mueller - * Christian Timmerer - * Contributors: - * Steve Workman - * - * This Source Code Form Is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. - *****************************************************************************/ - -/* DASH - Dynamic Adaptive Streaming over HTTP - * - * DASH is an adaptive bitrate streaming technology where a multimedia file is - * partitioned into one or more segments and delivered to a client using HTTP. - * - * |Representation| - * - * Describes a particular version of a piece of media described in an - * |AdaptationSet|, a common example being a particular bitrate encoding for an - * audio or video stream. Direct child of |AdaptationSet|, which contains 1+ - * available |Representation|s of the media. - * - * Common class used by all DASH Profiles. - * Populated by implementation of MPD Parser. - * Used as data source by implementation of MPD Manager. - * - * |MPD| - * --> |Period|s of time. - * --> |AdaptationSet|s for each type or group of media content. - * --> |Representation|s of media, encoded with different bitrates. - * --> |Segment|s of media, identified by URL (+optional byte - * range. - */ - -#ifndef REPRESENTATION_H_ -#define REPRESENTATION_H_ - -#include "nsAutoPtr.h" -#include "nsString.h" -#include "nsTArray.h" -#include "SegmentBase.h" - -namespace mozilla { -namespace net { - -class Representation -{ -public: - Representation() : - mBitrate(0), - mWidth(0), - mHeight(0), - mSegmentBase(nullptr) - { - MOZ_COUNT_CTOR(Representation); - } - virtual ~Representation() { - MOZ_COUNT_DTOR(Representation); - } - - bool operator<(const Representation &other) const { - return this->mBitrate < other.mBitrate; - } - - // Gets/Sets @bitrate in kbps. - int64_t const GetBitrate() const; - void SetBitrate(int64_t const aBitrate); - - // Gets/Sets @width and @height for the media if it's video. - void SetWidth(int32_t const aWidth); - int32_t const GetWidth() const; - void SetHeight(int32_t const aHeight); - int32_t const GetHeight() const; - - // Gets/Adds a |BaseURL| for the media files. - void AddBaseUrl(nsAString const& aUrl); - nsAString const& GetBaseUrl(uint32_t aIndex) const; - bool HasBaseUrls() const { return !mBaseUrls.IsEmpty(); } - - // Gets/Sets a base |Segment| for the |Representation|. - SegmentBase const* GetSegmentBase() const; - // Takes ownership of |SegmentBase| to manage deletion. - void SetSegmentBase(SegmentBase* aBase); - -private: - // Bitrate of the media in kbps. - int64_t mBitrate; - - // Width and height of the media if video. - int32_t mWidth; - int32_t mHeight; - - // List of absolute/relative |BaseURL|s which may be used to access the media. - nsTArray mBaseUrls; - - // The base |Segment| for the |Representation|. - nsAutoPtr mSegmentBase; -}; - -// Comparator allows comparing |Representation|s based on media stream bitrate. -class CompareRepresentationBitrates -{ -public: - // Returns true if the elements are equals; false otherwise. - // Note: |Representation| is stored as an array of |nsAutoPtr| in - // |AdaptationSet|, but needs to be compared to regular pointers. - // Hence the left hand side of the function being an - // |nsAutoPtr| and the right being a regular pointer. - bool Equals(const nsAutoPtr& a, - const Representation *b) const { - return a == b; - } - - // Returns true if (a < b); false otherwise. - // Note: |Representation| is stored as an array of |nsAutoPtr| in - // |AdaptationSet|, but needs to be compared to regular pointers. - // Hence the left hand side of the function being an - // |nsAutoPtr| and the right being a regular pointer. - bool LessThan(const nsAutoPtr& a, - const Representation *b) const { - return *a < *b; - } -}; - -}//namespace net -}//namespace mozilla - - -#endif /* REPRESENTATION_H_ */ diff --git a/netwerk/dash/mpd/SegmentBase.cpp b/netwerk/dash/mpd/SegmentBase.cpp deleted file mode 100644 index 12baf6eced5a..000000000000 --- a/netwerk/dash/mpd/SegmentBase.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* - * SegmentBase.cpp - ***************************************************************************** - * Copyrigh(C) 2010 - 2012 Klagenfurt University - * - * Created on: Jan 27, 2012 - * Authors: Christopher Mueller - * Christian Timmerer - * Contributors: - * Steve Workman - - * - * This Source Code Form Is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. - *****************************************************************************/ - -/* DASH - Dynamic Adaptive Streaming over HTTP - * - * DASH is an adaptive bitrate streaming technology where a multimedia file is - * partitioned into one or more segments and delivered to a client using HTTP. - * - * |SegmentBase| - * - * Describes common initialization information for |Segment|s in a - * |Representation|. - * - * Common class used by all DASH Profiles. - * Populated by implementation of MPD Parser. - * Used as data source by implementation of MPD Manager. - * - * |MPD| - * --> |Period|s of time. - * --> |AdaptationSet|s for each type or group of media content. - * --> |Representation|s of media, encoded with different bitrates. - * --> |Segment|s of media, identified by URL (+optional byte - * range. - */ - -#include "nsString.h" -#include "SegmentBase.h" - - -namespace mozilla { -namespace net { - -void -SegmentBase::GetIndexRange(int64_t* aStartBytes, int64_t* aEndBytes) const -{ - NS_ENSURE_TRUE_VOID(aStartBytes); - NS_ENSURE_TRUE_VOID(aEndBytes); - *aStartBytes = mIndexRangeStart; - *aEndBytes = mIndexRangeEnd; -} - -void -SegmentBase::GetInitRange(int64_t* aStartBytes, int64_t* aEndBytes) const -{ - NS_ENSURE_TRUE_VOID(aStartBytes); - NS_ENSURE_TRUE_VOID(aEndBytes); - *aStartBytes = mInitRangeStart; - *aEndBytes = mInitRangeEnd; -} - -void -SegmentBase::SetIndexRange(nsAString const &aRangeStr) -{ - SetRange(aRangeStr, mIndexRangeStart, mIndexRangeEnd); -} - -void -SegmentBase::SetInitRange(nsAString const &aRangeStr) -{ - SetRange(aRangeStr, mInitRangeStart, mInitRangeEnd); -} - -void -SegmentBase::SetRange(nsAString const &aRangeStr, - int64_t &aStart, - int64_t &aEnd) -{ - NS_ENSURE_TRUE_VOID(!aRangeStr.IsEmpty()); - - nsAString::const_iterator start, end, dashStart, dashEnd; - - aRangeStr.BeginReading(start); - aRangeStr.EndReading(end); - dashStart = start; - dashEnd = end; - - if (FindInReadable(NS_LITERAL_STRING("-"), dashStart, dashEnd)) { - nsAutoString temp(Substring(start, dashStart)); - nsresult rv; - aStart = temp.ToInteger64(&rv); - NS_ENSURE_SUCCESS_VOID(rv); - - temp = Substring(dashEnd, end); - aEnd = temp.ToInteger64(&rv); - NS_ENSURE_SUCCESS_VOID(rv); - } -} - -}//namespace net -}//namespace mozilla diff --git a/netwerk/dash/mpd/SegmentBase.h b/netwerk/dash/mpd/SegmentBase.h deleted file mode 100644 index 7d7ceb12c85b..000000000000 --- a/netwerk/dash/mpd/SegmentBase.h +++ /dev/null @@ -1,100 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* - * SegmentBase.h - ***************************************************************************** - * Copyrigh(C) 2010 - 2012 Klagenfurt University - * - * Created on: Jan 27, 2012 - * Authors: Christopher Mueller - * Christian Timmerer - * Contributors: - * Steve Workman - * - * This Source Code Form Is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. - *****************************************************************************/ - -/* DASH - Dynamic Adaptive Streaming over HTTP - * - * DASH is an adaptive bitrate streaming technology where a multimedia file is - * partitioned into one or more segments and delivered to a client using HTTP. - * - * |SegmentBase| - * - * Describes common initialization information for |Segment|s in a - * |Representation|. - * - * Common class used by all DASH Profiles. - * Populated by implementation of MPD Parser. - * Used as data source by implementation of MPD Manager. - * - * |MPD| - * --> |Period|s of time. - * --> |AdaptationSet|s for each type or group of media content. - * --> |Representation|s of media, encoded with different bitrates. - * --> |Segment|s of media, identified by URL (+optional byte - * range. - */ - -#ifndef SEGMENTBASE_H_ -#define SEGMENTBASE_H_ - -#include "nsString.h" - -namespace mozilla { -namespace net { - -class SegmentBase -{ -public: - SegmentBase() : - mInitRangeStart(0), - mInitRangeEnd(0), - mIndexRangeStart(0), - mIndexRangeEnd(0) - { - MOZ_COUNT_CTOR(SegmentBase); - } - virtual ~SegmentBase() - { - MOZ_COUNT_DTOR(SegmentBase); - } - - bool operator==(SegmentBase const & other) const { - return (mInitRangeStart == other.mInitRangeStart - && mInitRangeEnd == other.mInitRangeEnd - && mIndexRangeStart == other.mIndexRangeStart - && mIndexRangeEnd == other.mIndexRangeEnd); - } - bool operator!=(SegmentBase const & other) const { - return !(*this == other); - } - - // Get/Set the byte range for the initialization bytes. - void GetInitRange(int64_t* aStartBytes, int64_t* aEndBytes) const; - void SetInitRange(nsAString const &aRangeStr); - - // Get/Set the byte range for the index bytes. - void GetIndexRange(int64_t* aStartBytes, int64_t* aEndBytes) const; - void SetIndexRange(nsAString const &aRangeStr); - -private: - // Parses the string to get a start and end value. - void SetRange(nsAString const &aRangeStr, int64_t &aStart, int64_t &aEnd); - - // Start and end values for the init byte range. - int64_t mInitRangeStart; - int64_t mInitRangeEnd; - - // Start and end values for the index byte range. - int64_t mIndexRangeStart; - int64_t mIndexRangeEnd; -}; - - -}//namespace net -}//namespace mozilla - -#endif /* SEGMENTBASE_H_ */ diff --git a/netwerk/dash/mpd/moz.build b/netwerk/dash/mpd/moz.build deleted file mode 100644 index fd0eea98a886..000000000000 --- a/netwerk/dash/mpd/moz.build +++ /dev/null @@ -1,24 +0,0 @@ -# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -MODULE = 'necko' - -SOURCES += [ - 'AdaptationSet.cpp', - 'IMPDManager.cpp', - 'MPD.cpp', - 'nsDASHMPDParser.cpp', - 'nsDASHWebMODManager.cpp', - 'nsDASHWebMODParser.cpp', - 'Period.cpp', - 'Representation.cpp', - 'SegmentBase.cpp', -] - -LIBRARY_NAME = 'nkdashmpd_s' - -LIBXUL_LIBRARY = True - diff --git a/netwerk/dash/mpd/nsDASHMPDParser.cpp b/netwerk/dash/mpd/nsDASHMPDParser.cpp deleted file mode 100644 index 46d9ccde0275..000000000000 --- a/netwerk/dash/mpd/nsDASHMPDParser.cpp +++ /dev/null @@ -1,219 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* - * nsDASHMPDParser.cpp - ***************************************************************************** - * Copyrigh(C) 2010 - 2011 Klagenfurt University - * - * Created on: Aug 10, 2010 - * Authors: Christopher Mueller - * Christian Timmerer - * Contributors: - * Steve Workman - * - * This Source Code Form Is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. - *****************************************************************************/ - -/* DASH - Dynamic Adaptive Streaming over HTTP. - * - * DASH is an adaptive bitrate streaming technology where a multimedia file is - * partitioned into one or more segments and delivered to a client using HTTP. - * - * see DASHDecoder.cpp for info on DASH interaction with the media engine. - */ - -#include "prlog.h" -#include "nsNetUtil.h" -#include "nsIDOMAttr.h" -#include "nsIDOMDocument.h" -#include "nsIDOMElement.h" -#include "nsIDOMParser.h" -#include "nsIDOMMozNamedAttrMap.h" -#include "nsIDOMNode.h" -#include "nsString.h" -#include "IMPDManager.h" -#include "nsDASHMPDParser.h" - -#if defined(PR_LOGGING) -static PRLogModuleInfo* gDASHMPDParserLog = nullptr; -#define LOG(msg, ...) PR_LOG(gDASHMPDParserLog, PR_LOG_DEBUG, \ - ("%p [nsDASHMPDParser] " msg, this, __VA_ARGS__)) -#define LOG1(msg) PR_LOG(gDASHMPDParserLog, PR_LOG_DEBUG, \ - ("%p [nsDASHMPDParser] " msg, this)) -#else -#define LOG(msg, ...) -#define LOG1(msg) -#endif - -namespace mozilla { -namespace net { - -nsDASHMPDParser::nsDASHMPDParser(char* aMPDData, - uint32_t aDataLength, - nsIPrincipal* aPrincipal, - nsIURI* aURI) : - mData(aMPDData), - mDataLength(aDataLength), - mPrincipal(aPrincipal), - mURI(aURI) -{ - MOZ_COUNT_CTOR(nsDASHMPDParser); -#if defined(PR_LOGGING) - if(!gDASHMPDParserLog) - gDASHMPDParserLog = PR_NewLogModule("nsDASHMPDParser"); -#endif -} - -nsDASHMPDParser::~nsDASHMPDParser() -{ - MOZ_COUNT_DTOR(nsDASHMPDParser); -} - - -nsresult -nsDASHMPDParser::Parse(IMPDManager** aMPDManager, - DASHMPDProfile* aProfile) -{ - NS_ENSURE_ARG(aMPDManager); - NS_ENSURE_ARG(aProfile); - NS_ENSURE_TRUE(mData, NS_ERROR_NOT_INITIALIZED); - NS_ENSURE_TRUE(mPrincipal, NS_ERROR_NOT_INITIALIZED); - NS_ENSURE_TRUE(mURI, NS_ERROR_NOT_INITIALIZED); - -#ifdef PR_LOGGING - { - nsAutoCString spec; - nsresult rv = mURI->GetSpec(spec); - if (NS_FAILED(rv)) { - LOG1("Preparing to parse MPD: cannot get spec from URI"); - } else { - LOG("Preparing to parse MPD: mURI:\"%s\"", spec.get()); - } - } -#endif - - // Get mDoc element from mData buffer using DOMParser. - nsCOMPtr DOMParser; - DOMParser = do_CreateInstance(NS_DOMPARSER_CONTRACTID); - nsresult rv = DOMParser->Init(mPrincipal, mURI, nullptr, nullptr); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr doc; - rv = DOMParser->ParseFromBuffer(reinterpret_cast(mData.get()), - mDataLength, - "application/xml", - getter_AddRefs(doc)); - NS_ENSURE_SUCCESS(rv, rv); - if(!doc) { - LOG1("ERROR! Document not parsed as XML!"); - return NS_ERROR_NO_INTERFACE; - } - // Use root node to create MPD manager. - nsCOMPtr root; - rv = doc->GetDocumentElement(getter_AddRefs(root)); - NS_ENSURE_SUCCESS(rv, rv); - NS_ENSURE_TRUE(root, NS_ERROR_NULL_POINTER); -#ifdef PR_LOGGING - PrintDOMElements(root); -#endif - rv = GetProfile(root, *aProfile); - NS_ENSURE_SUCCESS(rv, rv); - *aMPDManager = IMPDManager::Create(*aProfile, root); - NS_ENSURE_TRUE(*aMPDManager, NS_ERROR_NULL_POINTER); - - // Get profile. - return rv; -} - -void -nsDASHMPDParser::PrintDOMElement(nsIDOMElement* aElem, int32_t offset) -{ - // Populate string ss and then print to LOG(). - nsAutoString ss; - // Indent. - for(int32_t i = 0; i < offset; i++) - ss.Append(NS_LITERAL_STRING(" ")); - // Tag name. - nsAutoString tagName; - NS_ENSURE_SUCCESS_VOID(aElem->GetTagName(tagName)); - ss += NS_LITERAL_STRING("<"); - ss += tagName; - - // Attributes. - nsCOMPtr attributes; - NS_ENSURE_SUCCESS_VOID(aElem->GetAttributes(getter_AddRefs(attributes))); - - uint32_t count; - NS_ENSURE_SUCCESS_VOID(attributes->GetLength(&count)); - - for(uint32_t i = 0; i < count; i++) - { - ss += NS_LITERAL_STRING(" "); - nsCOMPtr attr; - NS_ENSURE_SUCCESS_VOID(attributes->Item(i, getter_AddRefs(attr))); - - nsAutoString name; - NS_ENSURE_SUCCESS_VOID(attr->GetName(name)); - ss += name; - - nsAutoString value; - NS_ENSURE_SUCCESS_VOID(attr->GetValue(value)); - if (!value.IsEmpty()) { - ss += NS_LITERAL_STRING("="); - ss += value; - } - } - ss += NS_LITERAL_STRING(">"); - LOG("%s", NS_ConvertUTF16toUTF8(ss).get()); - - offset++; - - // Print for each child. - nsCOMPtr child; - NS_ENSURE_SUCCESS_VOID(aElem->GetFirstElementChild(getter_AddRefs(child))); - - while(child) - { - PrintDOMElement(child, offset); - NS_ENSURE_SUCCESS_VOID(child->GetNextElementSibling(getter_AddRefs(child))); - } -} - - -void -nsDASHMPDParser::PrintDOMElements(nsIDOMElement* aRoot) -{ - NS_ENSURE_TRUE_VOID(aRoot); - - DASHMPDProfile profile; - NS_ENSURE_SUCCESS_VOID(GetProfile(aRoot, profile)); - LOG("Profile Is %d",(int32_t)profile); - PrintDOMElement(aRoot, 0); -} - - -nsresult -nsDASHMPDParser::GetProfile(nsIDOMElement* aRoot, - DASHMPDProfile &aProfile) -{ - NS_ENSURE_ARG(aRoot); - - nsAutoString profileStr; - nsresult rv = aRoot->GetAttribute(NS_LITERAL_STRING("profiles"), profileStr); - LOG("profileStr: %s", NS_ConvertUTF16toUTF8(profileStr).get()); - NS_ENSURE_SUCCESS(rv, rv); - - if (profileStr - == NS_LITERAL_STRING("urn:webm:dash:profile:webm-on-demand:2012")) { - aProfile = WebMOnDemand; - } else { - aProfile = NotValid; - } - return NS_OK; -} - - -}// namespace net -}// namespace mozilla diff --git a/netwerk/dash/mpd/nsDASHMPDParser.h b/netwerk/dash/mpd/nsDASHMPDParser.h deleted file mode 100644 index e857ee820dbb..000000000000 --- a/netwerk/dash/mpd/nsDASHMPDParser.h +++ /dev/null @@ -1,78 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* - * nsDASHMPDParser.h - ***************************************************************************** - * Copyright(C) 2010 - 2011 Klagenfurt University - * - * Created on: Aug 10, 2010 - * Authors: Christopher Mueller - * Christian Timmerer - * Contributors: - * Steve Workman - * - * This Source Code Form Is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. - *****************************************************************************/ - -/* DASH - Dynamic Adaptive Streaming over HTTP. - * - * DASH is an adaptive bitrate streaming technology where a multimedia file is - * partitioned into one or more segments and delivered to a client using HTTP. - * - * see DASHDecoder.cpp for info on DASH interaction with the media engine. - */ - -#ifndef __DASHMPDPARSER_H__ -#define __DASHMPDPARSER_H__ - -#include "nsAutoPtr.h" -#include "nsNetUtil.h" -#include "nsIPrincipal.h" -#include "nsIDOMElement.h" -#include "IMPDManager.h" - -namespace mozilla { -namespace net { - -class nsDASHMPDParser -{ -public: - // Constructor takes pointer to MPD byte stream and length, as well as the - // current principal and URI from which the MPD download took place. - // Ownership of |aMPDData| should be transferred to this object. - nsDASHMPDParser(char* aMPDData, - uint32_t aDataLength, - nsIPrincipal* aPrincipal, - nsIURI* aURI); - - ~nsDASHMPDParser(); - - // Parses the MPD byte stream passed in the constructor. - // Returns a pointer to the MPDManager and the MPD profile type. - nsresult Parse(IMPDManager** aMPDManager, - DASHMPDProfile* aProfile); -private: - // Returns the MPD profile type given the DOM node for the root. - nsresult GetProfile(nsIDOMElement* aRoot, - DASHMPDProfile &profile); - // Debug: Prints the DOM elements. - void PrintDOMElements(nsIDOMElement* aRoot); - // Debug: Prints a single DOM element. - void PrintDOMElement(nsIDOMElement* aElem, int32_t aOffset); - - // Pointer to the MPD byte stream. - nsAutoPtr mData; - // Length in bytes of the MPD stream. - uint32_t mDataLength; - // Principal of the document. - nsCOMPtr mPrincipal; - // URI of the MPD Document downloaded. - nsCOMPtr mURI; -}; - -}//namespace net -}//namespace mozilla - -#endif /* __DASHMPDPARSER_H__ */ diff --git a/netwerk/dash/mpd/nsDASHWebMODManager.cpp b/netwerk/dash/mpd/nsDASHWebMODManager.cpp deleted file mode 100644 index 2c337e0f965e..000000000000 --- a/netwerk/dash/mpd/nsDASHWebMODManager.cpp +++ /dev/null @@ -1,236 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* - * nsDASHWebMODManager.cpp - ***************************************************************************** - * Copyrigh(C) 2010 - 2012 Klagenfurt University - * - * Created on: May 1, 2012 - * Based on IsoffMainManager.cpp by: - * Christopher Mueller - * Christian Timmerer - * Author: - * Steve Workman - * - * This Source Code Form Is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. - *****************************************************************************/ - -/* DASH - Dynamic Adaptive Streaming over HTTP. - * - * DASH is an adaptive bitrate streaming technology where a multimedia file is - * partitioned into one or more segments and delivered to a client using HTTP. - * - * (see DASHDecoder.cpp for info on DASH interaction with the media engine). - * - * Media Presentation Description (MPD) Manager for WebM On Demand Profile. - * - * Implements MPD Manager interface to use Adaptation Algorithm to determine - * which stream to download from WebM On Demand-based MPD. - * - * Note: Adaptation algorithm is separate and passed into manager. - */ - -#include "nsTArray.h" -#include "nsMimeTypes.h" -#include "nsNetUtil.h" -#include "prlog.h" -#include "SegmentBase.h" -#include "nsDASHWebMODManager.h" - -namespace mozilla { -namespace net { - -#if defined(PR_LOGGING) -static PRLogModuleInfo* gnsDASHWebMODManagerLog = nullptr; -#define LOG(msg, ...) \ - PR_LOG(gnsDASHWebMODManagerLog, PR_LOG_DEBUG, \ - ("%p [nsDASHWebMODManager] " msg, this, __VA_ARGS__)) -#define LOG1(msg) PR_LOG(gDASHMPDParserLog, PR_LOG_DEBUG, \ - ("%p [nsDASHWebMODManager] " msg, this)) -#else -#define LOG(msg, ...) -#define LOG1(msg) -#endif - -nsDASHWebMODManager::nsDASHWebMODManager(MPD* aMpd) -{ - MOZ_COUNT_CTOR(nsDASHWebMODManager); - NS_ENSURE_TRUE_VOID(aMpd); - mMpd = aMpd; -#if defined(PR_LOGGING) - if(!gnsDASHWebMODManagerLog) - gnsDASHWebMODManagerLog = PR_NewLogModule("nsDASHWebMODManager"); -#endif - LOG("Created nsDASHWebMODManager with mMpd(%p)", mMpd.get()); -} - -nsDASHWebMODManager::~nsDASHWebMODManager() -{ - MOZ_COUNT_DTOR(nsDASHWebMODManager); -} - - -Period const * -nsDASHWebMODManager::GetFirstPeriod() const -{ - NS_ENSURE_TRUE(mMpd, nullptr); - NS_ENSURE_TRUE(0 < mMpd->GetNumPeriods(), nullptr); - return mMpd->GetPeriod(0); -} - -nsresult -nsDASHWebMODManager::GetFirstSegmentUrl(uint32_t const aAdaptSetIdx, - uint32_t const aRepIdx, - nsAString &aUrl) const -{ - NS_ENSURE_TRUE(mMpd, NS_ERROR_NULL_POINTER); - // Append base URL for MPD. - if (mMpd->HasBaseUrls()) { - aUrl.Append(mMpd->GetBaseUrl(0)); - LOG("BaseUrl \"%s\"", NS_ConvertUTF16toUTF8(aUrl).get()); - } - - // Append base URL for Representation. - AdaptationSet const * adaptSet = GetAdaptationSet(aAdaptSetIdx); - NS_ENSURE_TRUE(adaptSet, NS_ERROR_NULL_POINTER); - - NS_ENSURE_TRUE(aRepIdx < adaptSet->GetNumRepresentations(), - NS_ERROR_ILLEGAL_VALUE); - Representation const * rep = adaptSet->GetRepresentation(aRepIdx); - NS_ENSURE_TRUE(rep, NS_ERROR_NULL_POINTER); - - if (rep->HasBaseUrls()) { - aUrl.Append(rep->GetBaseUrl(0)); - LOG("Appending \"%s\"", - NS_ConvertUTF16toUTF8(rep->GetBaseUrl(0)).get()); - } - - return NS_OK; -} - -uint32_t -nsDASHWebMODManager::GetNumAdaptationSets() const -{ - Period const * current = GetFirstPeriod(); - return current ? current->GetNumAdaptationSets() : 0; -} - -IMPDManager::AdaptationSetType -nsDASHWebMODManager::GetAdaptationSetType(uint32_t const aAdaptSetIdx) const -{ - AdaptationSet const * adaptSet = GetAdaptationSet(aAdaptSetIdx); - NS_ENSURE_TRUE(adaptSet, DASH_ASTYPE_INVALID); - - nsAutoString mimeType; - adaptSet->GetMIMEType(mimeType); - NS_ENSURE_TRUE(!mimeType.IsEmpty(), DASH_ASTYPE_INVALID); - - return GetAdaptationSetType(mimeType); -} - -IMPDManager::AdaptationSetType -nsDASHWebMODManager::GetAdaptationSetType(nsAString const & aMimeType) const -{ - NS_ENSURE_TRUE(!aMimeType.IsEmpty(), DASH_ASTYPE_INVALID); - - if (aMimeType == NS_LITERAL_STRING(VIDEO_WEBM)) { - return DASH_VIDEO_STREAM; - } else if (aMimeType == NS_LITERAL_STRING(AUDIO_WEBM)) { - return DASH_AUDIO_STREAM; - } else { - return DASH_ASTYPE_INVALID; - } -} - -uint32_t -nsDASHWebMODManager::GetNumRepresentations(uint32_t const aAdaptSetIdx) const -{ - AdaptationSet const * adaptSet = GetAdaptationSet(aAdaptSetIdx); - NS_ENSURE_TRUE(adaptSet, DASH_ASTYPE_INVALID); - - return adaptSet->GetNumRepresentations(); -} - -AdaptationSet const * -nsDASHWebMODManager::GetAdaptationSet(uint32_t const aAdaptSetIdx) const -{ - Period const * current = GetFirstPeriod(); - NS_ENSURE_TRUE(current, nullptr); - - NS_ENSURE_TRUE(0 < current->GetNumAdaptationSets(), nullptr); - NS_ENSURE_TRUE(aAdaptSetIdx < current->GetNumAdaptationSets(), nullptr); - AdaptationSet const * adaptSet = current->GetAdaptationSet(aAdaptSetIdx); - NS_ENSURE_TRUE(adaptSet, nullptr); - return adaptSet; -} - -Representation const * -nsDASHWebMODManager::GetRepresentation(uint32_t const aAdaptSetIdx, - uint32_t const aRepIdx) const -{ - AdaptationSet const * adaptSet = GetAdaptationSet(aAdaptSetIdx); - NS_ENSURE_TRUE(adaptSet, nullptr); - - NS_ENSURE_TRUE(aRepIdx < adaptSet->GetNumRepresentations(), nullptr); - Representation const * rep = adaptSet->GetRepresentation(aRepIdx); - NS_ENSURE_TRUE(rep, nullptr); - - return rep; -} - -double -nsDASHWebMODManager::GetStartTime() const -{ - Period const * current = GetFirstPeriod(); - NS_ENSURE_TRUE(current, -1); - - return current->GetStart(); -} - -double -nsDASHWebMODManager::GetDuration() const -{ - Period const * current = GetFirstPeriod(); - NS_ENSURE_TRUE(current, -1); - - return current->GetDuration(); -} - -bool -nsDASHWebMODManager::GetBestRepForBandwidth(uint32_t aAdaptSetIdx, - uint64_t aBandwidth, - uint32_t &aRepIdx) const -{ - NS_ENSURE_TRUE(aAdaptSetIdx < GetNumAdaptationSets(), false); - NS_ENSURE_TRUE(0 < GetNumRepresentations(aAdaptSetIdx), false); - // Return false if there isn't enough bandwidth for even the lowest bitrate. - // Let calling function decide what to do. Use 0.95 multiplier to deal with - // 5% variance in bandwidth. - // XXX Multiplier is a guess at present. - if (aBandwidth*0.95 < GetRepresentation(aAdaptSetIdx, 0)->GetBitrate()) { - aRepIdx = UINT32_MAX; - return false; - } - // Iterate until the current |Representation|'s bitrate is higher than the - // estimated available bandwidth. Use 0.95 multiplier to deal with 5% - // variance in bandwidth. - // XXX Multiplier is a guess at present. - for (uint32_t i = 1; i < GetNumRepresentations(aAdaptSetIdx); i++) { - NS_ENSURE_TRUE(GetRepresentation(aAdaptSetIdx, i), false); - if (aBandwidth*0.95 < GetRepresentation(aAdaptSetIdx, i)->GetBitrate()) { - // Pick the previous one, since this one's bitrate is too high. - aRepIdx = i-1; - return true; - } - } - // If we reach here, all of the |Representation|'s bitrates are lower than the - // available bandwidth. Just pick the highest, i.e. last in the array. - aRepIdx = GetNumRepresentations(aAdaptSetIdx)-1; - return true; -} - -}//namespace net -}//namespace mozilla - diff --git a/netwerk/dash/mpd/nsDASHWebMODManager.h b/netwerk/dash/mpd/nsDASHWebMODManager.h deleted file mode 100644 index c45f67acf3b6..000000000000 --- a/netwerk/dash/mpd/nsDASHWebMODManager.h +++ /dev/null @@ -1,104 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* - * nsDASHWebMODManager.h - ***************************************************************************** - * - * Created on: May 1, 2012 - * Based on IsoffMainManager.h by: - * Christopher Mueller - * Christian Timmerer - * Author: - * Steve Workman - * - * This Source Code Form Is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. - *****************************************************************************/ - -/* DASH - Dynamic Adaptive Streaming over HTTP. - * - * DASH is an adaptive bitrate streaming technology where a multimedia file is - * partitioned into one or more segments and delivered to a client using HTTP. - * - * (see DASHDecoder.cpp for info on DASH interaction with the media engine). - * - * - * Media Presentation Description (MPD) Manager for WebM On Demand Profile. - * ====================== - * - * Implements MPD Manager interface to use Adaptation Algorithm to determine - * which stream to download from WebM On Demand-based MPD. - * - * WebM On Demand describes a static, on demand media presentation using WebM - * encoded media files. - * Notes: - * 1 time |Period| per media presentation |MPD|. - * 1 audio stream (1 |Representation| for the audio |AdaptationSet|). - * 1 or multiple video streams for stream switching: - * (multiple |Representation|s for the video |AdaptationSet|). - * 1 file for each encoding (1 |Segment| per |Representation|). - * Stream switching allowed between clusters (clusters match DASH - * subsegments). - * - * Note: Adaptation algorithm is separate and passed into manager. - * XXX Adaptation not yet implemented. - */ - -#ifndef _NSDASHWEBMODMANAGER_H_ -#define _NSDASHWEBMODMANAGER_H_ - -#include "nsTArray.h" -#include "nsIURI.h" -#include "nsString.h" -#include "MPD.h" -#include "Period.h" -#include "AdaptationSet.h" -#include "Representation.h" -#include "IMPDManager.h" - -namespace mozilla { -namespace net { - -class nsDASHWebMODManager : public IMPDManager -{ -public: - nsDASHWebMODManager(MPD* mpd); - ~nsDASHWebMODManager(); - - // See IMPDManager.h for descriptions of following inherited functions. - Period const * GetFirstPeriod() const; - uint32_t GetNumAdaptationSets() const; - AdaptationSetType - GetAdaptationSetType(uint32_t const aAdaptSetIdx) const; - uint32_t GetNumRepresentations(uint32_t const aAdaptSetIdx) const; - Representation const * GetRepresentation(uint32_t const aAdaptSetIdx, - uint32_t const aRepIdx) const; - nsresult GetFirstSegmentUrl(uint32_t const aAdaptSetIdx, - uint32_t const aRepIdx, - nsAString &aUrl) const; - double GetStartTime() const; - double GetDuration() const; - - // Gets index of the |Representation| with next highest bitrate to the - // estimated bandwidth passed in. Returns true if there is at least one - // |Representation| with a bitrate lower than |aBandwidth|; otherwise returns - // false. Depends on |mRepresentations| being an ordered list. - bool GetBestRepForBandwidth(uint32_t aAdaptSetIdx, - uint64_t aBandwidth, - uint32_t &aRepIdx) const MOZ_OVERRIDE; - -private: - // Internal helper functions. - AdaptationSet const * GetAdaptationSet(uint32_t const aAdaptSetIdx) const; - AdaptationSetType GetAdaptationSetType(nsAString const &mimeType) const; - uint32_t GetNumSegments(Representation const* aRep) const; - - // Pointer to the MPD class structure; holds data parsed from the MPD file. - nsAutoPtr mMpd; -}; - -}//namespace net -}//namespace mozilla - -#endif /* _NSDASHWEBMODMANAGER_H_ */ diff --git a/netwerk/dash/mpd/nsDASHWebMODParser.cpp b/netwerk/dash/mpd/nsDASHWebMODParser.cpp deleted file mode 100644 index 21f5b921bc9e..000000000000 --- a/netwerk/dash/mpd/nsDASHWebMODParser.cpp +++ /dev/null @@ -1,604 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* - * nsDASHWebMODParser.cpp - ***************************************************************************** - * Copyrigh(C) 2010 - 2012 Klagenfurt University - * - * Created on: May 1, 2012 - * Based on IsoffMainParser.cpp by: - * Christopher Mueller - * Christian Timmerer - * Author: - * Steve Workman - - * - * This Source Code Form Is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. - *****************************************************************************/ - -/* DASH - Dynamic Adaptive Streaming over HTTP. - * - * DASH is an adaptive bitrate streaming technology where a multimedia file is - * partitioned into one or more segments and delivered to a client using HTTP. - * - * (see DASHDecoder.cpp for info on DASH interaction with the media engine). - * - * Media Presentation Description (MPD) Parser for WebM On Demand Profile. - * - * Parses DOM built from MPD XML to verify data and populate MPD classes. - * MPD classes used as a metadata source by WebM On Demand Manager. - */ - -#include "nsAutoPtr.h" -#include "nsTArray.h" -#include "nsMimeTypes.h" -#include "nsString.h" -#include "nsIDOMElement.h" -#include "prlog.h" -#include "nsDASHWebMODParser.h" - -#if defined(PR_LOGGING) -static PRLogModuleInfo* gnsDASHWebMODParserLog = nullptr; -#define LOG(msg, ...) \ - PR_LOG(gnsDASHWebMODParserLog, PR_LOG_DEBUG, \ - ("%p [nsDASHWebMODParser] " msg, this, __VA_ARGS__)) -#define LOG1(msg) \ - PR_LOG(gnsDASHWebMODParserLog, PR_LOG_DEBUG, \ - ("%p [nsDASHWebMODParser] " msg, this)) -#else -#define LOG(msg, ...) -#define LOG1(msg) -#endif - -namespace mozilla { -namespace net { - -nsDASHWebMODParser::nsDASHWebMODParser(nsIDOMElement* aRoot) : - mRoot(aRoot) -{ - MOZ_COUNT_CTOR(nsDASHWebMODParser); -#if defined(PR_LOGGING) - if(!gnsDASHWebMODParserLog) - gnsDASHWebMODParserLog = PR_NewLogModule("nsDASHWebMODParser"); -#endif - LOG1("Created nsDASHWebMODParser"); -} - -nsDASHWebMODParser::~nsDASHWebMODParser() -{ - MOZ_COUNT_DTOR(nsDASHWebMODParser); -} - -MPD* -nsDASHWebMODParser::Parse() -{ - LOG1("Parsing DOM into MPD objects"); - nsAutoPtr mpd(new MPD()); - - nsresult rv = VerifyMPDAttributes(); - NS_ENSURE_SUCCESS(rv, nullptr); - - rv = SetMPDBaseUrls(mpd); - NS_ENSURE_SUCCESS(rv, nullptr); - - rv = SetPeriods(mpd); - NS_ENSURE_SUCCESS(rv, nullptr); - - return mpd.forget(); -} - -nsresult -nsDASHWebMODParser::VerifyMPDAttributes() -{ - NS_ENSURE_TRUE(mRoot, NS_ERROR_NOT_INITIALIZED); - - // @|type| should be "static". - nsAutoString type; - nsresult rv = GetAttribute(mRoot, NS_LITERAL_STRING("type"), type); - NS_ENSURE_SUCCESS(rv, rv); - NS_ENSURE_TRUE(type.EqualsLiteral("static"), NS_ERROR_ILLEGAL_VALUE); - - // Note: No attributes to be set in MPD object for DASH-WebM OD. This - // function used for attribute verification only. - return NS_OK; -} - -nsresult -nsDASHWebMODParser::SetMPDBaseUrls(MPD* aMpd) -{ - NS_ENSURE_TRUE(mRoot, NS_ERROR_NOT_INITIALIZED); - - nsCOMPtr child, nextChild; - nsresult rv = mRoot->GetFirstElementChild(getter_AddRefs(child)); - NS_ENSURE_SUCCESS(rv, rv); - -#ifdef PR_LOGGING - int i = 0; -#endif - while (child) { - nsAutoString tagName; - rv = child->GetTagName(tagName); - NS_ENSURE_SUCCESS(rv, rv); - if (tagName.EqualsLiteral("BaseURL")) { - nsAutoString baseUrlStr; - rv = child->GetTextContent(baseUrlStr); - NS_ENSURE_SUCCESS(rv, rv); - - aMpd->AddBaseUrl(baseUrlStr); - LOG("MPD BaseURL #%d: \"%s\"", - i++, NS_ConvertUTF16toUTF8(baseUrlStr).get()); - } - rv = child->GetNextElementSibling(getter_AddRefs(nextChild)); - NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); - child = nextChild; - } - return NS_OK; -} - -nsresult -nsDASHWebMODParser::GetTime(nsAString& aTimeStr, double& aTime) -{ - NS_ENSURE_FALSE(aTimeStr.IsEmpty(), NS_ERROR_NOT_INITIALIZED); - // Fail if time string is not of the format "PT