mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 905513 - Rework MediaSource/MediaElement integration and implement limited initial multiple-decoder support. r=doublec
This commit is contained in:
parent
6220f18ff6
commit
e44caba3d4
@ -68,6 +68,7 @@
|
||||
#include "nsHostObjectProtocolHandler.h"
|
||||
#include "mozilla/dom/MediaSource.h"
|
||||
#include "MediaMetadataManager.h"
|
||||
#include "MediaSourceDecoder.h"
|
||||
|
||||
#include "AudioChannelService.h"
|
||||
|
||||
@ -601,7 +602,7 @@ void HTMLMediaElement::AbortExistingLoads()
|
||||
EndSrcMediaStreamPlayback();
|
||||
}
|
||||
if (mMediaSource) {
|
||||
mMediaSource->DetachElement();
|
||||
mMediaSource->Detach();
|
||||
mMediaSource = nullptr;
|
||||
}
|
||||
if (mAudioStream) {
|
||||
@ -1135,16 +1136,15 @@ nsresult HTMLMediaElement::LoadResource()
|
||||
return rv;
|
||||
}
|
||||
mMediaSource = source.forget();
|
||||
if (!mMediaSource->AttachElement(this)) {
|
||||
// XXX(kinetik): Handle failure: run "If the media data cannot be
|
||||
// fetched at all, due to network errors, causing the user agent to
|
||||
// give up trying to fetch the resource" section of resource fetch
|
||||
// algorithm.
|
||||
nsRefPtr<MediaSourceDecoder> decoder = new MediaSourceDecoder(this);
|
||||
if (!mMediaSource->Attach(decoder)) {
|
||||
// TODO: Handle failure: run "If the media data cannot be fetched at
|
||||
// all, due to network errors, causing the user agent to give up
|
||||
// trying to fetch the resource" section of resource fetch algorithm.
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
// XXX(kinetik): Bug 881512. Wire this up properly; return from here (as
|
||||
// MediaStreams setup does) rather than relying on mediasource->channel
|
||||
// conversion.
|
||||
nsRefPtr<MediaResource> resource = new MediaSourceResource();
|
||||
return FinishDecoderSetup(decoder, resource, nullptr, nullptr);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
|
||||
@ -1989,7 +1989,7 @@ HTMLMediaElement::~HTMLMediaElement()
|
||||
EndSrcMediaStreamPlayback();
|
||||
}
|
||||
if (mMediaSource) {
|
||||
mMediaSource->DetachElement();
|
||||
mMediaSource->Detach();
|
||||
mMediaSource = nullptr;
|
||||
}
|
||||
|
||||
|
@ -6,12 +6,27 @@
|
||||
|
||||
#include "MediaSource.h"
|
||||
|
||||
#include "mozilla/dom/HTMLMediaElement.h"
|
||||
#include "MediaSourceInputAdapter.h"
|
||||
#include "AsyncEventRunner.h"
|
||||
#include "DecoderTraits.h"
|
||||
#include "SourceBuffer.h"
|
||||
#include "SourceBufferList.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/FloatingPoint.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/HTMLMediaElement.h"
|
||||
#include "mozilla/mozalloc.h"
|
||||
#include "nsContentTypeParser.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsDebug.h"
|
||||
#include "nsError.h"
|
||||
#include "nsIEventTarget.h"
|
||||
#include "nsIRunnable.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsStringGlue.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "prlog.h"
|
||||
|
||||
struct JSContext;
|
||||
class JSObject;
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
PRLogModuleInfo* gMediaSourceLog;
|
||||
@ -20,16 +35,12 @@ PRLogModuleInfo* gMediaSourceLog;
|
||||
#define LOG(type, msg)
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
// Arbitrary limit.
|
||||
static const unsigned int MAX_SOURCE_BUFFERS = 16;
|
||||
|
||||
already_AddRefed<nsIInputStream>
|
||||
MediaSource::CreateInternalStream()
|
||||
{
|
||||
nsRefPtr<MediaSourceInputAdapter> adapter = new MediaSourceInputAdapter(this);
|
||||
mAdapters.AppendElement(adapter);
|
||||
return adapter.forget();
|
||||
}
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
|
||||
/* static */ already_AddRefed<MediaSource>
|
||||
MediaSource::Constructor(const GlobalObject& aGlobal,
|
||||
@ -95,8 +106,7 @@ MediaSource::AddSourceBuffer(const nsAString& aType, ErrorResult& aRv)
|
||||
if (!IsTypeSupportedInternal(aType, aRv)) {
|
||||
return nullptr;
|
||||
}
|
||||
// TODO: Temporary limit until multiple decoders are supported. Bug 881512.
|
||||
if (mSourceBuffers->Length() >= 1) {
|
||||
if (mSourceBuffers->Length() >= MAX_SOURCE_BUFFERS) {
|
||||
aRv.Throw(NS_ERROR_DOM_QUOTA_EXCEEDED_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
@ -104,10 +114,17 @@ MediaSource::AddSourceBuffer(const nsAString& aType, ErrorResult& aRv)
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
mContentType = aType;
|
||||
nsRefPtr<SourceBuffer> sourceBuffer = new SourceBuffer(this);
|
||||
nsContentTypeParser parser(aType);
|
||||
nsAutoString mimeType;
|
||||
nsresult rv = parser.GetType(mimeType);
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
nsRefPtr<SourceBuffer> sourceBuffer = new SourceBuffer(this, NS_ConvertUTF16toUTF8(mimeType));
|
||||
mSourceBuffers->Append(sourceBuffer);
|
||||
sourceBuffer->Attach();
|
||||
LOG(PR_LOG_DEBUG, ("%p AddSourceBuffer(Type=%s) -> %p", this,
|
||||
NS_ConvertUTF16toUTF8(mimeType).get(), sourceBuffer.get()));
|
||||
return sourceBuffer.forget();
|
||||
}
|
||||
|
||||
@ -137,7 +154,6 @@ MediaSource::RemoveSourceBuffer(SourceBuffer& aSourceBuffer, ErrorResult& aRv)
|
||||
mActiveSourceBuffers->Remove(sourceBuffer);
|
||||
}
|
||||
mSourceBuffers->Remove(sourceBuffer);
|
||||
sourceBuffer->Detach();
|
||||
// TODO: Free all resources associated with sourceBuffer
|
||||
}
|
||||
|
||||
@ -160,49 +176,37 @@ MediaSource::IsTypeSupported(const GlobalObject& aGlobal,
|
||||
return IsTypeSupportedInternal(aType, unused);
|
||||
}
|
||||
|
||||
void
|
||||
MediaSource::AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aRv)
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
LOG(PR_LOG_DEBUG, ("%p Append(ArrayBuffer=%u) mData=%u", this, aLength, mData.Length()));
|
||||
mData.AppendElements(aData, aLength);
|
||||
NotifyListeners();
|
||||
}
|
||||
|
||||
bool
|
||||
MediaSource::AttachElement(HTMLMediaElement* aElement)
|
||||
MediaSource::Attach(MediaSourceDecoder* aDecoder)
|
||||
{
|
||||
LOG(PR_LOG_DEBUG, ("%p Attaching element %p", this, aElement));
|
||||
MOZ_ASSERT(aElement);
|
||||
mElement = aElement;
|
||||
LOG(PR_LOG_DEBUG, ("%p Attaching decoder %p owner %p", this, aDecoder, aDecoder->GetOwner()));
|
||||
MOZ_ASSERT(aDecoder);
|
||||
if (mReadyState != MediaSourceReadyState::Closed) {
|
||||
return false;
|
||||
}
|
||||
mDecoder = aDecoder;
|
||||
mDecoder->AttachMediaSource(this);
|
||||
SetReadyState(MediaSourceReadyState::Open);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
MediaSource::DetachElement()
|
||||
MediaSource::Detach()
|
||||
{
|
||||
LOG(PR_LOG_DEBUG, ("%p Detaching element %p", this, mElement.get()));
|
||||
MOZ_ASSERT(mElement);
|
||||
mElement = nullptr;
|
||||
LOG(PR_LOG_DEBUG, ("%p Detaching decoder %p owner %p", this, mDecoder.get(), mDecoder->GetOwner()));
|
||||
MOZ_ASSERT(mDecoder);
|
||||
mDecoder->DetachMediaSource();
|
||||
mDecoder = nullptr;
|
||||
mDuration = UnspecifiedNaN();
|
||||
mActiveSourceBuffers->Clear();
|
||||
mSourceBuffers->DetachAndClear();
|
||||
mSourceBuffers->Clear();
|
||||
SetReadyState(MediaSourceReadyState::Closed);
|
||||
|
||||
for (uint32_t i = 0; i < mAdapters.Length(); ++i) {
|
||||
mAdapters[i]->Close();
|
||||
}
|
||||
mAdapters.Clear();
|
||||
}
|
||||
|
||||
MediaSource::MediaSource(nsPIDOMWindow* aWindow)
|
||||
: nsDOMEventTargetHelper(aWindow)
|
||||
, mDuration(UnspecifiedNaN())
|
||||
, mMonitor("mozilla::dom::MediaSource::mMonitor")
|
||||
, mDecoder(nullptr)
|
||||
, mReadyState(MediaSourceReadyState::Closed)
|
||||
{
|
||||
mSourceBuffers = new SourceBufferList(this);
|
||||
@ -219,9 +223,6 @@ void
|
||||
MediaSource::SetReadyState(MediaSourceReadyState aState)
|
||||
{
|
||||
MOZ_ASSERT(aState != mReadyState);
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
|
||||
NotifyListeners();
|
||||
|
||||
if ((mReadyState == MediaSourceReadyState::Closed ||
|
||||
mReadyState == MediaSourceReadyState::Ended) &&
|
||||
@ -273,14 +274,6 @@ MediaSource::QueueAsyncSimpleEvent(const char* aName)
|
||||
NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
void
|
||||
MediaSource::NotifyListeners()
|
||||
{
|
||||
for (uint32_t i = 0; i < mAdapters.Length(); ++i) {
|
||||
mAdapters[i]->NotifyListener();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MediaSource::DurationChange(double aNewDuration, ErrorResult& aRv)
|
||||
{
|
||||
@ -303,6 +296,7 @@ void
|
||||
MediaSource::EndOfStreamInternal(const Optional<MediaSourceEndOfStreamError>& aError, ErrorResult& aRv)
|
||||
{
|
||||
SetReadyState(MediaSourceReadyState::Ended);
|
||||
mSourceBuffers->Ended();
|
||||
if (!aError.WasPassed()) {
|
||||
// TODO:
|
||||
// Run duration change algorithm.
|
||||
@ -385,8 +379,8 @@ MediaSource::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
|
||||
return MediaSourceBinding::Wrap(aCx, aScope, this);
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED_4(MediaSource, nsDOMEventTargetHelper,
|
||||
mSourceBuffers, mActiveSourceBuffers, mAdapters, mElement)
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED_2(MediaSource, nsDOMEventTargetHelper,
|
||||
mSourceBuffers, mActiveSourceBuffers)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(MediaSource, nsDOMEventTargetHelper)
|
||||
NS_IMPL_RELEASE_INHERITED(MediaSource, nsDOMEventTargetHelper)
|
||||
@ -396,4 +390,5 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MediaSource)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
|
||||
|
||||
} // namespace dom
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -7,18 +7,23 @@
|
||||
#ifndef mozilla_dom_MediaSource_h_
|
||||
#define mozilla_dom_MediaSource_h_
|
||||
|
||||
#include "AsyncEventRunner.h"
|
||||
#include "MediaSourceDecoder.h"
|
||||
#include "js/RootingAPI.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
#include "mozilla/dom/MediaSourceBinding.h"
|
||||
#include "mozilla/dom/TypedArray.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsCycleCollectionNoteChild.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsDOMEventTargetHelper.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsID.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nscore.h"
|
||||
|
||||
class nsIInputStream;
|
||||
struct JSContext;
|
||||
class JSObject;
|
||||
class nsPIDOMWindow;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -27,11 +32,11 @@ template <typename T> class AsyncEventRunner;
|
||||
|
||||
namespace dom {
|
||||
|
||||
class HTMLMediaElement;
|
||||
class MediaSourceInputAdapter;
|
||||
class SourceBufferList;
|
||||
class GlobalObject;
|
||||
class SourceBuffer;
|
||||
class SourceBufferList;
|
||||
class TimeRanges;
|
||||
template <typename T> class Optional;
|
||||
|
||||
#define MOZILLA_DOM_MEDIASOURCE_IMPLEMENTATION_IID \
|
||||
{ 0x3839d699, 0x22c5, 0x439f, \
|
||||
@ -68,41 +73,21 @@ public:
|
||||
|
||||
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
|
||||
|
||||
const nsString& GetType()
|
||||
{
|
||||
return mContentType;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIInputStream> CreateInternalStream();
|
||||
|
||||
|
||||
void AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aRv);
|
||||
|
||||
// Semi-private, for MediaSourceInputAdapter only.
|
||||
nsTArray<uint8_t> const& GetData()
|
||||
{
|
||||
return mData;
|
||||
}
|
||||
|
||||
Monitor& GetMonitor()
|
||||
{
|
||||
return mMonitor;
|
||||
}
|
||||
|
||||
bool AppendDone() const
|
||||
{
|
||||
return mReadyState == MediaSourceReadyState::Closed || mReadyState == MediaSourceReadyState::Ended;
|
||||
}
|
||||
|
||||
// Attach this MediaSource to MediaElement aElement. Returns false if already attached.
|
||||
bool AttachElement(HTMLMediaElement* aElement);
|
||||
void DetachElement();
|
||||
// Attach this MediaSource to Decoder aDecoder. Returns false if already attached.
|
||||
bool Attach(MediaSourceDecoder* aDecoder);
|
||||
void Detach();
|
||||
|
||||
// Set mReadyState to aState and fire the required events at the MediaSource.
|
||||
void SetReadyState(MediaSourceReadyState aState);
|
||||
|
||||
void GetBuffered(TimeRanges* aRanges);
|
||||
|
||||
// Used by SourceBuffer to call CreateSubDecoder.
|
||||
MediaSourceDecoder* GetDecoder()
|
||||
{
|
||||
return mDecoder;
|
||||
}
|
||||
|
||||
private:
|
||||
explicit MediaSource(nsPIDOMWindow* aWindow);
|
||||
|
||||
@ -110,8 +95,6 @@ private:
|
||||
void DispatchSimpleEvent(const char* aName);
|
||||
void QueueAsyncSimpleEvent(const char* aName);
|
||||
|
||||
void NotifyListeners();
|
||||
|
||||
void DurationChange(double aNewDuration, ErrorResult& aRv);
|
||||
void EndOfStreamInternal(const Optional<MediaSourceEndOfStreamError>& aError, ErrorResult& aRv);
|
||||
|
||||
@ -119,25 +102,17 @@ private:
|
||||
|
||||
double mDuration;
|
||||
|
||||
nsTArray<nsRefPtr<MediaSourceInputAdapter> > mAdapters;
|
||||
|
||||
// Protected by monitor.
|
||||
nsTArray<uint8_t> mData;
|
||||
|
||||
// Protects access to mData.
|
||||
Monitor mMonitor;
|
||||
|
||||
nsRefPtr<SourceBufferList> mSourceBuffers;
|
||||
nsRefPtr<SourceBufferList> mActiveSourceBuffers;
|
||||
|
||||
nsRefPtr<HTMLMediaElement> mElement;
|
||||
nsRefPtr<MediaSourceDecoder> mDecoder;
|
||||
|
||||
nsString mContentType;
|
||||
MediaSourceReadyState mReadyState;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(MediaSource, MOZILLA_DOM_MEDIASOURCE_IMPLEMENTATION_IID)
|
||||
|
||||
} // namespace dom
|
||||
|
||||
} // namespace mozilla
|
||||
#endif /* mozilla_dom_MediaSource_h_ */
|
||||
|
215
content/media/mediasource/MediaSourceDecoder.cpp
Normal file
215
content/media/mediasource/MediaSourceDecoder.cpp
Normal file
@ -0,0 +1,215 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=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/. */
|
||||
|
||||
#include "MediaSourceDecoder.h"
|
||||
|
||||
#include "AbstractMediaDecoder.h"
|
||||
#include "MediaDecoderReader.h"
|
||||
#include "MediaDecoderStateMachine.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/dom/HTMLMediaElement.h"
|
||||
#include "mozilla/mozalloc.h"
|
||||
#include "nsISupports.h"
|
||||
#include "prlog.h"
|
||||
#include "SubBufferDecoder.h"
|
||||
#include "SourceBufferResource.h"
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
extern PRLogModuleInfo* gMediaSourceLog;
|
||||
#define LOG(type, msg) PR_LOG(gMediaSourceLog, type, msg)
|
||||
#else
|
||||
#define LOG(type, msg)
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
|
||||
class TimeRanges;
|
||||
|
||||
} // namespace dom
|
||||
|
||||
class MediaSourceReader : public MediaDecoderReader
|
||||
{
|
||||
public:
|
||||
MediaSourceReader(AbstractMediaDecoder* aDecoder)
|
||||
: MediaDecoderReader(aDecoder)
|
||||
{
|
||||
}
|
||||
|
||||
nsresult Init(MediaDecoderReader* aCloneDonor) MOZ_OVERRIDE
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
bool DecodeAudioData() MOZ_OVERRIDE
|
||||
{
|
||||
if (GetAudioReader()) {
|
||||
return GetAudioReader()->DecodeAudioData();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DecodeVideoFrame(bool& aKeyFrameSkip, int64_t aTimeThreshold) MOZ_OVERRIDE
|
||||
{
|
||||
if (GetVideoReader()) {
|
||||
return GetVideoReader()->DecodeVideoFrame(aKeyFrameSkip, aTimeThreshold);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HasVideo() MOZ_OVERRIDE
|
||||
{
|
||||
return mInfo.mHasVideo;
|
||||
}
|
||||
|
||||
bool HasAudio() MOZ_OVERRIDE
|
||||
{
|
||||
return mInfo.mHasAudio;
|
||||
}
|
||||
|
||||
nsresult ReadMetadata(VideoInfo* aInfo, MetadataTags** aTags) MOZ_OVERRIDE;
|
||||
|
||||
nsresult Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime,
|
||||
int64_t aCurrentTime) MOZ_OVERRIDE
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsresult GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime) MOZ_OVERRIDE
|
||||
{
|
||||
// XXX: Merge result with audio reader.
|
||||
return GetVideoReader()->GetBuffered(aBuffered, aStartTime);
|
||||
}
|
||||
|
||||
MediaQueue<AudioData>& AudioQueue() MOZ_OVERRIDE
|
||||
{
|
||||
// TODO: Share AudioQueue with SubReaders.
|
||||
if (GetAudioReader()) {
|
||||
return GetAudioReader()->AudioQueue();
|
||||
}
|
||||
return MediaDecoderReader::AudioQueue();
|
||||
}
|
||||
|
||||
MediaQueue<VideoData>& VideoQueue() MOZ_OVERRIDE
|
||||
{
|
||||
// TODO: Share VideoQueue with SubReaders.
|
||||
if (GetVideoReader()) {
|
||||
return GetVideoReader()->VideoQueue();
|
||||
}
|
||||
return MediaDecoderReader::VideoQueue();
|
||||
}
|
||||
|
||||
private:
|
||||
MediaDecoderReader* GetVideoReader()
|
||||
{
|
||||
MediaSourceDecoder* decoder = static_cast<MediaSourceDecoder*>(mDecoder);
|
||||
return decoder->GetVideoReader();
|
||||
}
|
||||
|
||||
MediaDecoderReader* GetAudioReader()
|
||||
{
|
||||
MediaSourceDecoder* decoder = static_cast<MediaSourceDecoder*>(mDecoder);
|
||||
return decoder->GetAudioReader();
|
||||
}
|
||||
};
|
||||
|
||||
MediaSourceDecoder::MediaSourceDecoder(HTMLMediaElement* aElement)
|
||||
: mMediaSource(nullptr)
|
||||
, mVideoReader(nullptr),
|
||||
mAudioReader(nullptr)
|
||||
{
|
||||
Init(aElement);
|
||||
}
|
||||
|
||||
MediaDecoder*
|
||||
MediaSourceDecoder::Clone()
|
||||
{
|
||||
// TODO: Sort out cloning.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MediaDecoderStateMachine*
|
||||
MediaSourceDecoder::CreateStateMachine()
|
||||
{
|
||||
return new MediaDecoderStateMachine(this, new MediaSourceReader(this));
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaSourceDecoder::Load(nsIStreamListener**, MediaDecoder*)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceDecoder::AttachMediaSource(MediaSource* aMediaSource)
|
||||
{
|
||||
MOZ_ASSERT(!mMediaSource && !mDecoderStateMachine);
|
||||
mMediaSource = aMediaSource;
|
||||
mDecoderStateMachine = CreateStateMachine();
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceDecoder::DetachMediaSource()
|
||||
{
|
||||
mMediaSource = nullptr;
|
||||
}
|
||||
|
||||
SubBufferDecoder*
|
||||
MediaSourceDecoder::CreateSubDecoder(const nsACString& aType)
|
||||
{
|
||||
MediaResource* resource = new SourceBufferResource(nullptr, aType);
|
||||
nsRefPtr<SubBufferDecoder> decoder = new SubBufferDecoder(resource, this);
|
||||
nsAutoPtr<MediaDecoderReader> reader(DecoderTraits::CreateReader(aType, decoder));
|
||||
reader->Init(nullptr);
|
||||
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
mDecoders.AppendElement(decoder);
|
||||
mReaders.AppendElement(reader);
|
||||
LOG(PR_LOG_DEBUG, ("Registered subdecoder %p subreader %p", decoder.get(), reader.get()));
|
||||
mon.NotifyAll();
|
||||
|
||||
decoder->SetReader(reader.forget());
|
||||
return decoder;
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaSourceReader::ReadMetadata(VideoInfo* aInfo, MetadataTags** aTags)
|
||||
{
|
||||
mDecoder->SetMediaSeekable(true);
|
||||
mDecoder->SetTransportSeekable(false);
|
||||
|
||||
MediaSourceDecoder* decoder = static_cast<MediaSourceDecoder*>(mDecoder);
|
||||
const nsTArray<MediaDecoderReader*>& readers = decoder->GetReaders();
|
||||
bool gotVideo = false;
|
||||
bool gotAudio = false;
|
||||
for (uint32_t i = 0; i < readers.Length(); ++i) {
|
||||
MediaDecoderReader* reader = readers[i];
|
||||
VideoInfo vi;
|
||||
nsresult rv = reader->ReadMetadata(&vi, aTags);
|
||||
LOG(PR_LOG_DEBUG, ("ReadMetadata on SB reader %p", reader));
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (vi.mHasVideo && !gotVideo) {
|
||||
mInfo = vi;
|
||||
decoder->SetVideoReader(reader);
|
||||
gotVideo = true;
|
||||
}
|
||||
if (vi.mHasAudio && !gotAudio) {
|
||||
mInfo.mAudioRate = vi.mAudioRate;
|
||||
mInfo.mAudioChannels = vi.mAudioChannels;
|
||||
mInfo.mHasAudio = true;
|
||||
decoder->SetAudioReader(reader);
|
||||
gotAudio = true;
|
||||
}
|
||||
}
|
||||
*aInfo = mInfo;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
246
content/media/mediasource/MediaSourceDecoder.h
Normal file
246
content/media/mediasource/MediaSourceDecoder.h
Normal file
@ -0,0 +1,246 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=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/. */
|
||||
|
||||
#ifndef MOZILLA_MEDIASOURCEDECODER_H_
|
||||
#define MOZILLA_MEDIASOURCEDECODER_H_
|
||||
|
||||
#include "MediaCache.h"
|
||||
#include "MediaDecoder.h"
|
||||
#include "MediaResource.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsError.h"
|
||||
#include "nsStringGlue.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
class nsIPrincipal;
|
||||
class nsIStreamListener;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class MediaDecoderReader;
|
||||
class MediaDecoderStateMachine;
|
||||
class SubBufferDecoder;
|
||||
|
||||
namespace dom {
|
||||
|
||||
class HTMLMediaElement;
|
||||
class MediaSource;
|
||||
|
||||
} // namespace dom
|
||||
|
||||
class MediaSourceDecoder : public MediaDecoder
|
||||
{
|
||||
public:
|
||||
MediaSourceDecoder(HTMLMediaElement* aElement);
|
||||
|
||||
MediaDecoder* Clone() MOZ_OVERRIDE;
|
||||
MediaDecoderStateMachine* CreateStateMachine() MOZ_OVERRIDE;
|
||||
nsresult Load(nsIStreamListener**, MediaDecoder*) MOZ_OVERRIDE;
|
||||
|
||||
void AttachMediaSource(MediaSource* aMediaSource);
|
||||
void DetachMediaSource();
|
||||
|
||||
SubBufferDecoder* CreateSubDecoder(const nsACString& aType);
|
||||
|
||||
const nsTArray<MediaDecoderReader*>& GetReaders()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
while (mReaders.Length() == 0) {
|
||||
mon.Wait();
|
||||
}
|
||||
return mReaders;
|
||||
}
|
||||
|
||||
void SetVideoReader(MediaDecoderReader* aReader)
|
||||
{
|
||||
MOZ_ASSERT(aReader && !mVideoReader);
|
||||
mVideoReader = aReader;
|
||||
}
|
||||
|
||||
void SetAudioReader(MediaDecoderReader* aReader)
|
||||
{
|
||||
MOZ_ASSERT(aReader && !mAudioReader);
|
||||
mAudioReader = aReader;
|
||||
}
|
||||
|
||||
MediaDecoderReader* GetVideoReader()
|
||||
{
|
||||
return mVideoReader;
|
||||
}
|
||||
|
||||
MediaDecoderReader* GetAudioReader()
|
||||
{
|
||||
return mAudioReader;
|
||||
}
|
||||
|
||||
private:
|
||||
MediaSource* mMediaSource;
|
||||
|
||||
nsTArray<nsRefPtr<SubBufferDecoder> > mDecoders;
|
||||
nsTArray<MediaDecoderReader*> mReaders; // Readers owned by Decoders.
|
||||
|
||||
MediaDecoderReader* mVideoReader;
|
||||
MediaDecoderReader* mAudioReader;
|
||||
};
|
||||
|
||||
class MediaSourceResource MOZ_FINAL : public MediaResource
|
||||
{
|
||||
public:
|
||||
MediaSourceResource()
|
||||
{
|
||||
}
|
||||
|
||||
nsresult Close()
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void Suspend(bool aCloseImmediately)
|
||||
{
|
||||
}
|
||||
|
||||
void Resume()
|
||||
{
|
||||
}
|
||||
|
||||
already_AddRefed<nsIPrincipal> GetCurrentPrincipal()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool CanClone()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
already_AddRefed<MediaResource> CloneData(MediaDecoder* aDecoder)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void SetReadMode(MediaCacheStream::ReadMode aMode)
|
||||
{
|
||||
}
|
||||
|
||||
void SetPlaybackRate(uint32_t aBytesPerSecond)
|
||||
{
|
||||
}
|
||||
|
||||
nsresult Read(char* aBuffer, uint32_t aCount, uint32_t* aBytes)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult ReadAt(int64_t aOffset, char* aBuffer, uint32_t aCount, uint32_t* aBytes)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult Seek(int32_t aWhence, int64_t aOffset)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
void StartSeekingForMetadata()
|
||||
{
|
||||
}
|
||||
|
||||
void EndSeekingForMetadata()
|
||||
{
|
||||
}
|
||||
|
||||
int64_t Tell()
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Pin()
|
||||
{
|
||||
}
|
||||
|
||||
void Unpin()
|
||||
{
|
||||
}
|
||||
|
||||
double GetDownloadRate(bool* aIsReliable)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int64_t GetLength()
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int64_t GetNextCachedData(int64_t aOffset)
|
||||
{
|
||||
return aOffset;
|
||||
}
|
||||
|
||||
int64_t GetCachedDataEnd(int64_t aOffset)
|
||||
{
|
||||
return GetLength();
|
||||
}
|
||||
|
||||
bool IsDataCachedToEndOfResource(int64_t aOffset)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsSuspendedByCache()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsSuspended()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
nsresult ReadFromCache(char* aBuffer, int64_t aOffset, uint32_t aCount)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
nsresult Open(nsIStreamListener** aStreamListener)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
#ifdef MOZ_DASH
|
||||
nsresult OpenByteRange(nsIStreamListener** aStreamListener,
|
||||
const MediaByteRange& aByteRange)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
#endif
|
||||
|
||||
nsresult GetCachedRanges(nsTArray<MediaByteRange>& aRanges)
|
||||
{
|
||||
aRanges.AppendElement(MediaByteRange(0, GetLength()));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool IsTransportSeekable() MOZ_OVERRIDE
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
const nsCString& GetContentType() const MOZ_OVERRIDE
|
||||
{
|
||||
return mType;
|
||||
}
|
||||
|
||||
private:
|
||||
const nsAutoCString mType;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* MOZILLA_MEDIASOURCEDECODER_H_ */
|
@ -1,176 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=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/. */
|
||||
|
||||
#include "MediaSourceInputAdapter.h"
|
||||
|
||||
#include "nsStreamUtils.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
extern PRLogModuleInfo* gMediaSourceLog;
|
||||
#define LOG(type, msg) PR_LOG(gMediaSourceLog, type, msg)
|
||||
#else
|
||||
#define LOG(type, msg)
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMETHODIMP
|
||||
MediaSourceInputAdapter::Close()
|
||||
{
|
||||
MonitorAutoLock mon(mMediaSource->GetMonitor());
|
||||
LOG(PR_LOG_DEBUG, ("%p IA::Close", this));
|
||||
//MOZ_ASSERT(!mClosed);
|
||||
mClosed = true;
|
||||
NotifyListener();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MediaSourceInputAdapter::Available(uint64_t* aAvailable)
|
||||
{
|
||||
MonitorAutoLock mon(mMediaSource->GetMonitor());
|
||||
if (mClosed) {
|
||||
LOG(PR_LOG_DEBUG, ("%p IA::Available (closed)", this));
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
*aAvailable = Available();
|
||||
LOG(PR_LOG_DEBUG, ("%p IA::Available available=%llu", this, *aAvailable));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MediaSourceInputAdapter::Read(char* aBuf, uint32_t aCount, uint32_t* aWriteCount)
|
||||
{
|
||||
return ReadSegments(NS_CopySegmentToBuffer, aBuf, aCount, aWriteCount);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MediaSourceInputAdapter::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
|
||||
uint32_t aCount, uint32_t* aWriteCount)
|
||||
{
|
||||
MonitorAutoLock mon(mMediaSource->GetMonitor());
|
||||
|
||||
uint32_t available = Available();
|
||||
LOG(PR_LOG_DEBUG, ("%p IA::ReadSegments aCount=%u available=%u appendDone=%d rv=%x",
|
||||
this, aCount, available, mMediaSource->AppendDone(),
|
||||
mMediaSource->AppendDone() ? NS_OK : NS_BASE_STREAM_WOULD_BLOCK));
|
||||
if (available == 0) {
|
||||
*aWriteCount = 0;
|
||||
return mMediaSource->AppendDone() ? NS_OK : NS_BASE_STREAM_WOULD_BLOCK;
|
||||
}
|
||||
|
||||
uint32_t count = std::min(aCount, available);
|
||||
nsresult rv = aWriter(this, aClosure,
|
||||
reinterpret_cast<const char*>(&mMediaSource->GetData()[mOffset]),
|
||||
0, count, aWriteCount);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
MOZ_ASSERT(*aWriteCount <= count);
|
||||
mOffset += *aWriteCount;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MediaSourceInputAdapter::IsNonBlocking(bool* aNonBlocking)
|
||||
{
|
||||
LOG(PR_LOG_DEBUG, ("%p IA::IsNonBlocking", this));
|
||||
*aNonBlocking = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MediaSourceInputAdapter::CloseWithStatus(nsresult aStatus)
|
||||
{
|
||||
return Close();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MediaSourceInputAdapter::AsyncWait(nsIInputStreamCallback* aCallback, uint32_t aFlags,
|
||||
uint32_t aRequestedCount, nsIEventTarget* aTarget)
|
||||
{
|
||||
LOG(PR_LOG_DEBUG, ("%p IA::AsyncWait aCallback=%p aFlags=%u aRequestedCount=%u aTarget=%p",
|
||||
this, aCallback, aFlags, aRequestedCount, aTarget));
|
||||
|
||||
if (aFlags != 0) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
if (mCallback || mCallbackTarget) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
mCallback = aCallback;
|
||||
mCallbackTarget = aTarget;
|
||||
mNotifyThreshold = aRequestedCount;
|
||||
if (!aRequestedCount) {
|
||||
mNotifyThreshold = 1024;
|
||||
}
|
||||
|
||||
NotifyListener();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceInputAdapter::NotifyListener()
|
||||
{
|
||||
if (!mCallback) {
|
||||
return;
|
||||
}
|
||||
// Don't notify unless more data is available than the threshold, except
|
||||
// in the case that there's no more data coming.
|
||||
if (Available() < mNotifyThreshold && !mClosed && !mMediaSource->AppendDone()) {
|
||||
return;
|
||||
}
|
||||
nsCOMPtr<nsIInputStreamCallback> callback;
|
||||
if (mCallbackTarget) {
|
||||
callback = NS_NewInputStreamReadyEvent(mCallback, mCallbackTarget);
|
||||
} else {
|
||||
callback = mCallback;
|
||||
}
|
||||
MOZ_ASSERT(callback);
|
||||
mCallback = nullptr;
|
||||
mCallbackTarget = nullptr;
|
||||
mNotifyThreshold = 0;
|
||||
LOG(PR_LOG_DEBUG, ("%p IA::NotifyListener", this));
|
||||
callback->OnInputStreamReady(this);
|
||||
|
||||
}
|
||||
|
||||
uint64_t
|
||||
MediaSourceInputAdapter::Available()
|
||||
{
|
||||
return mMediaSource->GetData().Length() - mOffset;
|
||||
}
|
||||
|
||||
MediaSourceInputAdapter::~MediaSourceInputAdapter()
|
||||
{
|
||||
LOG(PR_LOG_DEBUG, ("%p Destroy input adapter", this));
|
||||
}
|
||||
|
||||
MediaSourceInputAdapter::MediaSourceInputAdapter(MediaSource* aMediaSource)
|
||||
: mMediaSource(aMediaSource)
|
||||
, mOffset(0)
|
||||
, mClosed(false)
|
||||
{
|
||||
LOG(PR_LOG_DEBUG, ("%p Create input adapter for %p", this, aMediaSource));
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_1(MediaSourceInputAdapter, mMediaSource)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(MediaSourceInputAdapter)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(MediaSourceInputAdapter)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaSourceInputAdapter)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIInputStream)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIAsyncInputStream)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
@ -1,43 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=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/. */
|
||||
|
||||
#ifndef MOZILLA_MEDIASOURCEINPUTADAPTER_H_
|
||||
#define MOZILLA_MEDIASOURCEINPUTADAPTER_H_
|
||||
|
||||
#include "nsIAsyncInputStream.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "MediaSource.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class MediaSourceInputAdapter MOZ_FINAL : public nsIAsyncInputStream
|
||||
{
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS(MediaSourceInputAdapter)
|
||||
NS_DECL_NSIINPUTSTREAM
|
||||
NS_DECL_NSIASYNCINPUTSTREAM
|
||||
|
||||
MediaSourceInputAdapter(MediaSource* aMediaSource);
|
||||
~MediaSourceInputAdapter();
|
||||
|
||||
void NotifyListener();
|
||||
|
||||
private:
|
||||
uint64_t Available();
|
||||
|
||||
nsRefPtr<MediaSource> mMediaSource;
|
||||
nsCOMPtr<nsIInputStreamCallback> mCallback;
|
||||
nsCOMPtr<nsIEventTarget> mCallbackTarget;
|
||||
int64_t mOffset;
|
||||
uint32_t mNotifyThreshold;
|
||||
bool mClosed;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
#endif /* MOZILLA_MEDIASOURCEINPUTADAPTER_H_ */
|
@ -5,6 +5,25 @@
|
||||
|
||||
#include "SourceBuffer.h"
|
||||
|
||||
#include "AsyncEventRunner.h"
|
||||
#include "DecoderTraits.h"
|
||||
#include "MediaDecoder.h"
|
||||
#include "MediaSourceDecoder.h"
|
||||
#include "SourceBufferResource.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/FloatingPoint.h"
|
||||
#include "mozilla/dom/MediaSourceBinding.h"
|
||||
#include "mozilla/dom/TimeRanges.h"
|
||||
#include "nsError.h"
|
||||
#include "nsIEventTarget.h"
|
||||
#include "nsIRunnable.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "prlog.h"
|
||||
#include "SubBufferDecoder.h"
|
||||
|
||||
struct JSContext;
|
||||
class JSObject;
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
extern PRLogModuleInfo* gMediaSourceLog;
|
||||
#define LOG(type, msg) PR_LOG(gMediaSourceLog, type, msg)
|
||||
@ -13,30 +32,90 @@ extern PRLogModuleInfo* gMediaSourceLog;
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class MediaResource;
|
||||
class ReentrantMonitor;
|
||||
|
||||
namespace layers {
|
||||
|
||||
class ImageContainer;
|
||||
|
||||
} // namespace layers
|
||||
|
||||
ReentrantMonitor&
|
||||
SubBufferDecoder::GetReentrantMonitor()
|
||||
{
|
||||
return mParentDecoder->GetReentrantMonitor();
|
||||
}
|
||||
|
||||
bool
|
||||
SubBufferDecoder::OnStateMachineThread() const
|
||||
{
|
||||
return mParentDecoder->OnStateMachineThread();
|
||||
}
|
||||
|
||||
bool
|
||||
SubBufferDecoder::OnDecodeThread() const
|
||||
{
|
||||
return mParentDecoder->OnDecodeThread();
|
||||
}
|
||||
|
||||
void
|
||||
SubBufferDecoder::SetMediaDuration(int64_t aDuration)
|
||||
{
|
||||
mParentDecoder->SetMediaDuration(aDuration);
|
||||
}
|
||||
|
||||
void
|
||||
SubBufferDecoder::UpdateEstimatedMediaDuration(int64_t aDuration)
|
||||
{
|
||||
mParentDecoder->UpdateEstimatedMediaDuration(aDuration);
|
||||
}
|
||||
|
||||
void
|
||||
SubBufferDecoder::SetMediaSeekable(bool aMediaSeekable)
|
||||
{
|
||||
mParentDecoder->SetMediaSeekable(aMediaSeekable);
|
||||
}
|
||||
|
||||
void
|
||||
SubBufferDecoder::SetTransportSeekable(bool aTransportSeekable)
|
||||
{
|
||||
mParentDecoder->SetTransportSeekable(aTransportSeekable);
|
||||
}
|
||||
|
||||
layers::ImageContainer*
|
||||
SubBufferDecoder::GetImageContainer()
|
||||
{
|
||||
return mParentDecoder->GetImageContainer();
|
||||
}
|
||||
|
||||
namespace dom {
|
||||
|
||||
void
|
||||
SourceBuffer::SetMode(SourceBufferAppendMode aMode, ErrorResult& aRv)
|
||||
{
|
||||
if (!mAttached || mUpdating) {
|
||||
if (!IsAttached() || mUpdating) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(mMediaSource->ReadyState() != MediaSourceReadyState::Closed);
|
||||
if (mMediaSource->ReadyState() == MediaSourceReadyState::Ended) {
|
||||
mMediaSource->SetReadyState(MediaSourceReadyState::Open);
|
||||
}
|
||||
// TODO:: Test append state.
|
||||
// TODO:: If aMode is "sequence", set sequence start time.
|
||||
// TODO: Test append state.
|
||||
// TODO: If aMode is "sequence", set sequence start time.
|
||||
mAppendMode = aMode;
|
||||
}
|
||||
|
||||
void
|
||||
SourceBuffer::SetTimestampOffset(double aTimestampOffset, ErrorResult& aRv)
|
||||
{
|
||||
if (!mAttached || mUpdating) {
|
||||
if (!IsAttached() || mUpdating) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(mMediaSource->ReadyState() != MediaSourceReadyState::Closed);
|
||||
if (mMediaSource->ReadyState() == MediaSourceReadyState::Ended) {
|
||||
mMediaSource->SetReadyState(MediaSourceReadyState::Open);
|
||||
}
|
||||
@ -48,19 +127,19 @@ SourceBuffer::SetTimestampOffset(double aTimestampOffset, ErrorResult& aRv)
|
||||
already_AddRefed<TimeRanges>
|
||||
SourceBuffer::GetBuffered(ErrorResult& aRv)
|
||||
{
|
||||
if (!mAttached) {
|
||||
if (!IsAttached()) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
nsRefPtr<TimeRanges> ranges = new TimeRanges();
|
||||
// TODO: Populate ranges.
|
||||
mDecoder->GetBuffered(ranges);
|
||||
return ranges.forget();
|
||||
}
|
||||
|
||||
void
|
||||
SourceBuffer::SetAppendWindowStart(double aAppendWindowStart, ErrorResult& aRv)
|
||||
{
|
||||
if (!mAttached || mUpdating) {
|
||||
if (!IsAttached() || mUpdating) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
@ -74,7 +153,7 @@ SourceBuffer::SetAppendWindowStart(double aAppendWindowStart, ErrorResult& aRv)
|
||||
void
|
||||
SourceBuffer::SetAppendWindowEnd(double aAppendWindowEnd, ErrorResult& aRv)
|
||||
{
|
||||
if (!mAttached || mUpdating) {
|
||||
if (!IsAttached() || mUpdating) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
@ -101,7 +180,7 @@ SourceBuffer::AppendBuffer(const ArrayBufferView& aData, ErrorResult& aRv)
|
||||
void
|
||||
SourceBuffer::Abort(ErrorResult& aRv)
|
||||
{
|
||||
if (!mAttached) {
|
||||
if (!IsAttached()) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
@ -114,7 +193,6 @@ SourceBuffer::Abort(ErrorResult& aRv)
|
||||
AbortUpdating();
|
||||
}
|
||||
// TODO: Run reset parser algorithm.
|
||||
// XXX: Need to run these two resets through setters?
|
||||
mAppendWindowStart = 0;
|
||||
mAppendWindowEnd = PositiveInfinity();
|
||||
}
|
||||
@ -122,36 +200,36 @@ SourceBuffer::Abort(ErrorResult& aRv)
|
||||
void
|
||||
SourceBuffer::Remove(double aStart, double aEnd, ErrorResult& aRv)
|
||||
{
|
||||
if (!IsAttached() || mUpdating ||
|
||||
mMediaSource->ReadyState() != MediaSourceReadyState::Open) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
if (aStart < 0 || aStart > mMediaSource->Duration() ||
|
||||
aEnd <= aStart) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
return;
|
||||
}
|
||||
if (!mAttached || mUpdating ||
|
||||
mMediaSource->ReadyState() != MediaSourceReadyState::Open) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
StartUpdating();
|
||||
/// TODO: Run coded frame removal algorithm asynchronously (would call StopUpdating()).
|
||||
StopUpdating();
|
||||
}
|
||||
|
||||
void
|
||||
SourceBuffer::Attach()
|
||||
SourceBuffer::Detach()
|
||||
{
|
||||
MOZ_ASSERT(!mAttached);
|
||||
mAttached = true;
|
||||
Ended();
|
||||
mDecoder = nullptr;
|
||||
mMediaSource = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
SourceBuffer::Detach()
|
||||
SourceBuffer::Ended()
|
||||
{
|
||||
MOZ_ASSERT(mAttached);
|
||||
mAttached = false;
|
||||
static_cast<SourceBufferResource*>(mDecoder->GetResource())->Ended();
|
||||
}
|
||||
|
||||
SourceBuffer::SourceBuffer(MediaSource* aMediaSource)
|
||||
SourceBuffer::SourceBuffer(MediaSource* aMediaSource, const nsACString& aType)
|
||||
: nsDOMEventTargetHelper(aMediaSource->GetParentObject())
|
||||
, mMediaSource(aMediaSource)
|
||||
, mAppendWindowStart(0)
|
||||
@ -159,9 +237,18 @@ SourceBuffer::SourceBuffer(MediaSource* aMediaSource)
|
||||
, mTimestampOffset(0)
|
||||
, mAppendMode(SourceBufferAppendMode::Segments)
|
||||
, mUpdating(false)
|
||||
, mAttached(false)
|
||||
{
|
||||
MOZ_ASSERT(aMediaSource);
|
||||
MediaSourceDecoder* parentDecoder = aMediaSource->GetDecoder();
|
||||
mDecoder = parentDecoder->CreateSubDecoder(aType);
|
||||
MOZ_ASSERT(mDecoder);
|
||||
}
|
||||
|
||||
SourceBuffer::~SourceBuffer()
|
||||
{
|
||||
if (mDecoder) {
|
||||
static_cast<SourceBufferResource*>(mDecoder->GetResource())->Ended();
|
||||
}
|
||||
}
|
||||
|
||||
MediaSource*
|
||||
@ -220,7 +307,7 @@ SourceBuffer::AbortUpdating()
|
||||
void
|
||||
SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aRv)
|
||||
{
|
||||
if (!mAttached || mUpdating) {
|
||||
if (!IsAttached() || mUpdating) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
@ -229,9 +316,14 @@ SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aR
|
||||
}
|
||||
// TODO: Run coded frame eviction algorithm.
|
||||
// TODO: Test buffer full flag.
|
||||
mMediaSource->AppendData(aData, aLength, aRv); // XXX: Appending to input buffer.
|
||||
LOG(PR_LOG_DEBUG, ("%p Append(ArrayBuffer=%u)", this, aLength));
|
||||
StartUpdating();
|
||||
// XXX: For future reference: NDA call must run on the main thread.
|
||||
mDecoder->NotifyDataArrived(reinterpret_cast<const char*>(aData),
|
||||
aLength,
|
||||
static_cast<SourceBufferResource*>(mDecoder->GetResource())->GetLength());
|
||||
// TODO: Run buffer append algorithm asynchronously (would call StopUpdating()).
|
||||
static_cast<SourceBufferResource*>(mDecoder->GetResource())->AppendData(aData, aLength);
|
||||
StopUpdating();
|
||||
}
|
||||
|
||||
@ -244,4 +336,5 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(SourceBuffer)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
|
||||
|
||||
} // namespace dom
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -7,25 +7,37 @@
|
||||
#ifndef mozilla_dom_SourceBuffer_h_
|
||||
#define mozilla_dom_SourceBuffer_h_
|
||||
|
||||
#include "AsyncEventRunner.h"
|
||||
#include "MediaDecoderReader.h"
|
||||
#include "MediaSource.h"
|
||||
#include "js/RootingAPI.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/SourceBufferBinding.h"
|
||||
#include "mozilla/dom/TimeRanges.h"
|
||||
#include "mozilla/dom/TypedArray.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/mozalloc.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nscore.h"
|
||||
#include "nsCycleCollectionNoteChild.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsDOMEventTargetHelper.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsStringGlue.h"
|
||||
#include "nscore.h"
|
||||
|
||||
class JSObject;
|
||||
struct JSContext;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ErrorResult;
|
||||
class SourceBufferResource;
|
||||
class SubBufferDecoder;
|
||||
template <typename T> class AsyncEventRunner;
|
||||
|
||||
namespace dom {
|
||||
|
||||
class TimeRanges;
|
||||
|
||||
class SourceBuffer MOZ_FINAL : public nsDOMEventTargetHelper
|
||||
{
|
||||
public:
|
||||
@ -76,16 +88,22 @@ public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(SourceBuffer, nsDOMEventTargetHelper)
|
||||
|
||||
explicit SourceBuffer(MediaSource* aMediaSource);
|
||||
explicit SourceBuffer(MediaSource* aMediaSource, const nsACString& aType);
|
||||
~SourceBuffer();
|
||||
|
||||
MediaSource* GetParentObject() const;
|
||||
|
||||
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
|
||||
|
||||
// Notify the SourceBuffer that it has been attached to or detached from
|
||||
// the MediaSource's sourceBuffer list.
|
||||
void Attach();
|
||||
// Notify the SourceBuffer that it has been detached from the
|
||||
// MediaSource's sourceBuffer list.
|
||||
void Detach();
|
||||
bool IsAttached() const
|
||||
{
|
||||
return mMediaSource != nullptr;
|
||||
}
|
||||
|
||||
void Ended();
|
||||
|
||||
private:
|
||||
friend class AsyncEventRunner<SourceBuffer>;
|
||||
@ -102,6 +120,8 @@ private:
|
||||
|
||||
nsRefPtr<MediaSource> mMediaSource;
|
||||
|
||||
nsRefPtr<SubBufferDecoder> mDecoder;
|
||||
|
||||
double mAppendWindowStart;
|
||||
double mAppendWindowEnd;
|
||||
|
||||
@ -109,10 +129,9 @@ private:
|
||||
|
||||
SourceBufferAppendMode mAppendMode;
|
||||
bool mUpdating;
|
||||
|
||||
bool mAttached;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
||||
} // namespace mozilla
|
||||
#endif /* mozilla_dom_SourceBuffer_h_ */
|
||||
|
@ -6,7 +6,19 @@
|
||||
|
||||
#include "SourceBufferList.h"
|
||||
|
||||
#include "AsyncEventRunner.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/dom/SourceBufferListBinding.h"
|
||||
#include "mozilla/mozalloc.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIEventTarget.h"
|
||||
#include "nsIRunnable.h"
|
||||
#include "nsStringGlue.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "prlog.h"
|
||||
|
||||
struct JSContext;
|
||||
class JSObject;
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
extern PRLogModuleInfo* gMediaSourceLog;
|
||||
@ -16,6 +28,7 @@ extern PRLogModuleInfo* gMediaSourceLog;
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
|
||||
SourceBuffer*
|
||||
@ -42,6 +55,7 @@ void
|
||||
SourceBufferList::Remove(SourceBuffer* aSourceBuffer)
|
||||
{
|
||||
MOZ_ALWAYS_TRUE(mSourceBuffers.RemoveElement(aSourceBuffer));
|
||||
aSourceBuffer->Detach();
|
||||
QueueAsyncSimpleEvent("removesourcebuffer");
|
||||
}
|
||||
|
||||
@ -54,6 +68,9 @@ SourceBufferList::Contains(SourceBuffer* aSourceBuffer)
|
||||
void
|
||||
SourceBufferList::Clear()
|
||||
{
|
||||
for (uint32_t i = 0; i < mSourceBuffers.Length(); ++i) {
|
||||
mSourceBuffers[i]->Detach();
|
||||
}
|
||||
mSourceBuffers.Clear();
|
||||
QueueAsyncSimpleEvent("removesourcebuffer");
|
||||
}
|
||||
@ -64,15 +81,6 @@ SourceBufferList::IsEmpty()
|
||||
return mSourceBuffers.IsEmpty();
|
||||
}
|
||||
|
||||
void
|
||||
SourceBufferList::DetachAndClear()
|
||||
{
|
||||
for (uint32_t i = 0; i < mSourceBuffers.Length(); ++i) {
|
||||
mSourceBuffers[i]->Detach();
|
||||
}
|
||||
Clear();
|
||||
}
|
||||
|
||||
bool
|
||||
SourceBufferList::AnyUpdating()
|
||||
{
|
||||
@ -95,6 +103,14 @@ SourceBufferList::Remove(double aStart, double aEnd, ErrorResult& aRv)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SourceBufferList::Ended()
|
||||
{
|
||||
for (uint32_t i = 0; i < mSourceBuffers.Length(); ++i) {
|
||||
mSourceBuffers[i]->Ended();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SourceBufferList::DispatchSimpleEvent(const char* aName)
|
||||
{
|
||||
@ -139,4 +155,5 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(SourceBufferList)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
|
||||
|
||||
} // namespace dom
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -7,15 +7,19 @@
|
||||
#ifndef mozilla_dom_SourceBufferList_h_
|
||||
#define mozilla_dom_SourceBufferList_h_
|
||||
|
||||
#include "AsyncEventRunner.h"
|
||||
#include "MediaSource.h"
|
||||
#include "SourceBuffer.h"
|
||||
#include "js/RootingAPI.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCycleCollectionNoteChild.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsDOMEventTargetHelper.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nscore.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
struct JSContext;
|
||||
class JSObject;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -59,9 +63,6 @@ public:
|
||||
// True if list has zero entries.
|
||||
bool IsEmpty();
|
||||
|
||||
// Detach and remove all SourceBuffers and fire a single "removesourcebuffer" at the list.
|
||||
void DetachAndClear();
|
||||
|
||||
// Returns true if updating is true on any SourceBuffers in the list.
|
||||
bool AnyUpdating();
|
||||
|
||||
@ -69,6 +70,9 @@ public:
|
||||
// first error, with result returned in aRv.
|
||||
void Remove(double aStart, double aEnd, ErrorResult& aRv);
|
||||
|
||||
// Mark all SourceBuffers input buffers as ended.
|
||||
void Ended();
|
||||
|
||||
private:
|
||||
friend class AsyncEventRunner<SourceBufferList>;
|
||||
void DispatchSimpleEvent(const char* aName);
|
||||
@ -79,5 +83,6 @@ private:
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
||||
} // namespace mozilla
|
||||
#endif /* mozilla_dom_SourceBufferList_h_ */
|
||||
|
162
content/media/mediasource/SourceBufferResource.cpp
Normal file
162
content/media/mediasource/SourceBufferResource.cpp
Normal file
@ -0,0 +1,162 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=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/. */
|
||||
|
||||
#include "SourceBufferResource.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <algorithm>
|
||||
|
||||
#include "nsISeekableStream.h"
|
||||
#include "nsTraceRefcnt.h"
|
||||
#include "prenv.h"
|
||||
#include "prlog.h"
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
extern PRLogModuleInfo* gMediaSourceLog;
|
||||
#define LOG(type, msg) PR_LOG(gMediaSourceLog, type, msg)
|
||||
#else
|
||||
#define LOG(type, msg)
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
|
||||
class SourceBuffer;
|
||||
|
||||
} // namespace dom
|
||||
|
||||
nsresult
|
||||
SourceBufferResource::Close()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mMonitor);
|
||||
LOG(PR_LOG_DEBUG, ("%p SBR::Close", this));
|
||||
//MOZ_ASSERT(!mClosed);
|
||||
mClosed = true;
|
||||
mon.NotifyAll();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
SourceBufferResource::Read(char* aBuffer, uint32_t aCount, uint32_t* aBytes)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mMonitor);
|
||||
bool blockingRead = !!aBytes;
|
||||
|
||||
while (blockingRead && !mEnded && mOffset + aCount > GetLength()) {
|
||||
LOG(PR_LOG_DEBUG, ("%p SBR::Read waiting for data", this));
|
||||
mon.Wait();
|
||||
}
|
||||
|
||||
uint32_t available = GetLength() - mOffset;
|
||||
uint32_t count = std::min(aCount, available);
|
||||
if (!PR_GetEnv("MOZ_QUIET")) {
|
||||
LOG(PR_LOG_DEBUG, ("%p SBR::Read aCount=%u length=%u offset=%u "
|
||||
"available=%u count=%u, blocking=%d bufComplete=%d",
|
||||
this, aCount, GetLength(), mOffset, available, count,
|
||||
blockingRead, mEnded));
|
||||
}
|
||||
if (available == 0) {
|
||||
LOG(PR_LOG_DEBUG, ("%p SBR::Read EOF", this));
|
||||
*aBytes = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
memcpy(aBuffer, &mInputBuffer[mOffset], count);
|
||||
*aBytes = count;
|
||||
mOffset += count;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
SourceBufferResource::ReadAt(int64_t aOffset, char* aBuffer, uint32_t aCount, uint32_t* aBytes)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mMonitor);
|
||||
nsresult rv = Seek(nsISeekableStream::NS_SEEK_SET, aOffset);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
return Read(aBuffer, aCount, aBytes);
|
||||
}
|
||||
|
||||
nsresult
|
||||
SourceBufferResource::Seek(int32_t aWhence, int64_t aOffset)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mMonitor);
|
||||
if (mClosed) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
int64_t newOffset = mOffset;
|
||||
switch (aWhence) {
|
||||
case nsISeekableStream::NS_SEEK_END:
|
||||
newOffset = GetLength() - aOffset;
|
||||
break;
|
||||
case nsISeekableStream::NS_SEEK_CUR:
|
||||
newOffset += aOffset;
|
||||
break;
|
||||
case nsISeekableStream::NS_SEEK_SET:
|
||||
newOffset = aOffset;
|
||||
break;
|
||||
}
|
||||
|
||||
if (newOffset < 0 || newOffset > GetLength()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mOffset = newOffset;
|
||||
mon.NotifyAll();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
SourceBufferResource::ReadFromCache(char* aBuffer, int64_t aOffset, uint32_t aCount)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mMonitor);
|
||||
nsresult rv = Seek(nsISeekableStream::NS_SEEK_SET, aOffset);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
return Read(aBuffer, aCount, nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
SourceBufferResource::AppendData(const uint8_t* aData, uint32_t aLength)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mMonitor);
|
||||
mInputBuffer.AppendElements(aData, aLength);
|
||||
mon.NotifyAll();
|
||||
}
|
||||
|
||||
void
|
||||
SourceBufferResource::Ended()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mMonitor);
|
||||
mEnded = true;
|
||||
mon.NotifyAll();
|
||||
}
|
||||
|
||||
SourceBufferResource::~SourceBufferResource()
|
||||
{
|
||||
MOZ_COUNT_DTOR(SourceBufferResource);
|
||||
LOG(PR_LOG_DEBUG, ("%p SBR::~SBR", this));
|
||||
}
|
||||
|
||||
SourceBufferResource::SourceBufferResource(nsIPrincipal* aPrincipal,
|
||||
const nsACString& aType)
|
||||
: mPrincipal(aPrincipal)
|
||||
, mType(aType)
|
||||
, mMonitor("mozilla::SourceBufferResource::mMonitor")
|
||||
, mOffset(0)
|
||||
, mClosed(false)
|
||||
, mEnded(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(SourceBufferResource);
|
||||
LOG(PR_LOG_DEBUG, ("%p SBR::SBR()", this));
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
145
content/media/mediasource/SourceBufferResource.h
Normal file
145
content/media/mediasource/SourceBufferResource.h
Normal file
@ -0,0 +1,145 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=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/. */
|
||||
|
||||
#ifndef MOZILLA_SOURCEBUFFERRESOURCE_H_
|
||||
#define MOZILLA_SOURCEBUFFERRESOURCE_H_
|
||||
|
||||
#include "MediaCache.h"
|
||||
#include "MediaResource.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsError.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsStringGlue.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nscore.h"
|
||||
|
||||
class nsIStreamListener;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class MediaDecoder;
|
||||
|
||||
namespace dom {
|
||||
|
||||
class SourceBuffer;
|
||||
|
||||
} // namespace dom
|
||||
|
||||
class SourceBufferResource MOZ_FINAL : public MediaResource
|
||||
{
|
||||
public:
|
||||
SourceBufferResource(nsIPrincipal* aPrincipal,
|
||||
const nsACString& aType);
|
||||
~SourceBufferResource();
|
||||
|
||||
nsresult Close();
|
||||
void Suspend(bool aCloseImmediately) {}
|
||||
void Resume() {}
|
||||
|
||||
already_AddRefed<nsIPrincipal> GetCurrentPrincipal()
|
||||
{
|
||||
return nsCOMPtr<nsIPrincipal>(mPrincipal).forget();
|
||||
}
|
||||
|
||||
bool CanClone()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
already_AddRefed<MediaResource> CloneData(MediaDecoder* aDecoder)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void SetReadMode(MediaCacheStream::ReadMode aMode)
|
||||
{
|
||||
}
|
||||
|
||||
void SetPlaybackRate(uint32_t aBytesPerSecond)
|
||||
{
|
||||
}
|
||||
|
||||
nsresult Read(char* aBuffer, uint32_t aCount, uint32_t* aBytes);
|
||||
nsresult ReadAt(int64_t aOffset, char* aBuffer, uint32_t aCount, uint32_t* aBytes);
|
||||
nsresult Seek(int32_t aWhence, int64_t aOffset);
|
||||
|
||||
void StartSeekingForMetadata()
|
||||
{
|
||||
}
|
||||
|
||||
void EndSeekingForMetadata()
|
||||
{
|
||||
}
|
||||
|
||||
int64_t Tell()
|
||||
{
|
||||
return mOffset;
|
||||
}
|
||||
|
||||
void Pin()
|
||||
{
|
||||
}
|
||||
|
||||
void Unpin()
|
||||
{
|
||||
}
|
||||
|
||||
double GetDownloadRate(bool* aIsReliable) { return 0; }
|
||||
int64_t GetLength() { return mInputBuffer.Length(); }
|
||||
int64_t GetNextCachedData(int64_t aOffset) { return aOffset; }
|
||||
int64_t GetCachedDataEnd(int64_t aOffset) { return GetLength(); }
|
||||
bool IsDataCachedToEndOfResource(int64_t aOffset) { return true; }
|
||||
bool IsSuspendedByCache() { return false; }
|
||||
bool IsSuspended() { return false; }
|
||||
nsresult ReadFromCache(char* aBuffer, int64_t aOffset, uint32_t aCount);
|
||||
|
||||
nsresult Open(nsIStreamListener** aStreamListener)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
#ifdef MOZ_DASH
|
||||
nsresult OpenByteRange(nsIStreamListener** aStreamListener,
|
||||
const MediaByteRange& aByteRange)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
#endif
|
||||
|
||||
nsresult GetCachedRanges(nsTArray<MediaByteRange>& aRanges)
|
||||
{
|
||||
aRanges.AppendElement(MediaByteRange(0, GetLength()));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool IsTransportSeekable() MOZ_OVERRIDE { return true; }
|
||||
|
||||
const nsCString& GetContentType() const MOZ_OVERRIDE
|
||||
{
|
||||
return mType;
|
||||
}
|
||||
|
||||
// Used by SourceBuffer.
|
||||
void AppendData(const uint8_t* aData, uint32_t aLength);
|
||||
void Ended();
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
const nsAutoCString mType;
|
||||
|
||||
// Provides synchronization between SourceBuffers and InputAdapters.
|
||||
ReentrantMonitor mMonitor;
|
||||
nsTArray<uint8_t> mInputBuffer;
|
||||
|
||||
int64_t mOffset;
|
||||
bool mClosed;
|
||||
bool mEnded;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
#endif /* MOZILLA_SOURCEBUFFERRESOURCE_H_ */
|
62
content/media/mediasource/SubBufferDecoder.h
Normal file
62
content/media/mediasource/SubBufferDecoder.h
Normal file
@ -0,0 +1,62 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=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/. */
|
||||
|
||||
#ifndef MOZILLA_SUBBUFFERDECODER_H_
|
||||
#define MOZILLA_SUBBUFFERDECODER_H_
|
||||
|
||||
#include "BufferDecoder.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class MediaSourceDecoder;
|
||||
|
||||
class SubBufferDecoder : public BufferDecoder
|
||||
{
|
||||
public:
|
||||
// This class holds a weak pointer to MediaResource. It's the responsibility
|
||||
// of the caller to manage the memory of the MediaResource object.
|
||||
SubBufferDecoder(MediaResource* aResource, MediaSourceDecoder* aParentDecoder)
|
||||
: BufferDecoder(aResource), mParentDecoder(aParentDecoder), mReader(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
void SetReader(MediaDecoderReader* aReader)
|
||||
{
|
||||
MOZ_ASSERT(!mReader);
|
||||
mReader = aReader;
|
||||
}
|
||||
|
||||
ReentrantMonitor& GetReentrantMonitor() MOZ_OVERRIDE;
|
||||
bool OnStateMachineThread() const MOZ_OVERRIDE;
|
||||
bool OnDecodeThread() const MOZ_OVERRIDE;
|
||||
void SetMediaDuration(int64_t aDuration) MOZ_OVERRIDE;
|
||||
void UpdateEstimatedMediaDuration(int64_t aDuration) MOZ_OVERRIDE;
|
||||
void SetMediaSeekable(bool aMediaSeekable) MOZ_OVERRIDE;
|
||||
void SetTransportSeekable(bool aTransportSeekable) MOZ_OVERRIDE;
|
||||
layers::ImageContainer* GetImageContainer() MOZ_OVERRIDE;
|
||||
|
||||
void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset)
|
||||
{
|
||||
mReader->NotifyDataArrived(aBuffer, aLength, aOffset);
|
||||
|
||||
// XXX: aOffset makes no sense here, need view of "data timeline".
|
||||
mParentDecoder->NotifyDataArrived(aBuffer, aLength, aOffset);
|
||||
}
|
||||
|
||||
nsresult GetBuffered(TimeRanges* aBuffered)
|
||||
{
|
||||
// XXX: Need mStartTime (from StateMachine) instead of passing 0.
|
||||
return mReader->GetBuffered(aBuffered, 0);
|
||||
}
|
||||
|
||||
private:
|
||||
MediaSourceDecoder* mParentDecoder;
|
||||
nsAutoPtr<MediaDecoderReader> mReader;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* MOZILLA_SUBBUFFERDECODER_H_ */
|
@ -11,6 +11,7 @@ MODULE = 'content'
|
||||
|
||||
EXPORTS += [
|
||||
'AsyncEventRunner.h',
|
||||
'MediaSourceDecoder.h',
|
||||
]
|
||||
|
||||
EXPORTS.mozilla.dom += [
|
||||
@ -21,9 +22,10 @@ EXPORTS.mozilla.dom += [
|
||||
|
||||
CPP_SOURCES += [
|
||||
'MediaSource.cpp',
|
||||
'MediaSourceInputAdapter.cpp',
|
||||
'MediaSourceDecoder.cpp',
|
||||
'SourceBuffer.cpp',
|
||||
'SourceBufferList.cpp',
|
||||
'SourceBufferResource.cpp',
|
||||
]
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
Loading…
Reference in New Issue
Block a user