Skip to content
This repository has been archived by the owner on Jun 20, 2023. It is now read-only.

SourceBuffer implementation #126

Open
wants to merge 23 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
17e81fe
Implement SourceBuffer::GetTimeIntervals
ferjm Dec 5, 2017
be18a3c
Remove unused SourceBuffer::Detach method
ferjm Dec 5, 2017
fd6e7cd
Implement SourceBuffer::EvictData
ferjm Dec 5, 2017
889496a
Introduce impl_simple_ffi_setter_wrapper! macro
ferjm Dec 7, 2017
b875eba
Implement SourceBufferAttributes and GeckoMediaSourceBufferImpl
ferjm Dec 7, 2017
438b61f
Cache source buffer parent
ferjm Dec 13, 2017
8e0cad0
Implement MediaSource::SourceBuffers and MediaSource::ActiveSourceBuf…
ferjm Dec 13, 2017
f719a66
Implement MediaSource::SetReadyState
ferjm Dec 17, 2017
5eba808
Implement MediaSource::Attach and MediaSource::Detach
ferjm Dec 17, 2017
18dd922
Make MediaSourceDecoder inherit from GeckoMediaDecoder
ferjm Dec 18, 2017
d5e7c19
Clear source buffers when detaching from media decoder
ferjm Dec 18, 2017
8d22f47
Fix tests
ferjm Dec 19, 2017
f218752
Implement SourceBuffer::AppendData
ferjm Dec 20, 2017
2ad67d1
Ignore .DS_Store
ferjm Dec 20, 2017
39ec946
Add append and clear hooks to SourceBufferList
ferjm Dec 20, 2017
e54d133
Set source buffer as active when init segment is received
ferjm Dec 21, 2017
b879db4
Reset parser state on append data error
ferjm Dec 21, 2017
644bae8
Implement SourceBuffer::AbortBufferAppend and expose ResetParserState…
ferjm Dec 21, 2017
9547ee8
rustfmt
ferjm Dec 21, 2017
1c6a2ea
Implement SourceBuffer::RangeRemoval
ferjm Dec 22, 2017
71490b2
Fix tests: do not send more messages through Sink channel after playb…
ferjm Dec 22, 2017
b5d3c91
Use struct callbacks instead of closures for AppendData and RangeRemoval
ferjm Dec 22, 2017
136ddce
Introduce create_media_source_player
ferjm Dec 28, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ Cargo.lock
glue_diffs/
*~
.cargo/
/NDK/
/NDK/
**/.DS_Store
2 changes: 0 additions & 2 deletions gecko-media/data/header_files.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,6 @@
"MediaResult.h": "dom/media/MediaResult.h",
"MediaSegment.h": "dom/media/MediaSegment.h",
"MediaShutdownManager.h": "dom/media/MediaShutdownManager.h",
"MediaSourceDecoder.h": "dom/media/mediasource/MediaSourceDecoder.h",
"MediaSourceDemuxer.h": "dom/media/mediasource/MediaSourceDemuxer.h",
"MediaSourceUtils.h": "dom/media/mediasource/MediaSourceUtils.h",
"MediaStatistics.h": "dom/media/MediaStatistics.h",
Expand Down Expand Up @@ -140,7 +139,6 @@
"SharedBuffer.h": "dom/media/SharedBuffer.h",
"SimpleMap.h": "dom/media/platforms/SimpleMap.h",
"SinfParser.h": "dom/media/mp4/SinfParser.h",
"SourceBufferAttributes.h": "dom/media/mediasource/SourceBufferAttributes.h",
"SourceBufferResource.h": "dom/media/mediasource/SourceBufferResource.h",
"SourceBufferTask.h": "dom/media/mediasource/SourceBufferTask.h",
"SpecialSystemDirectory.h": "xpcom/io/SpecialSystemDirectory.h",
Expand Down
1 change: 0 additions & 1 deletion gecko-media/gecko/glue/GeckoMediaDecoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ GeckoMediaDecoder::GeckoMediaDecoder(MediaDecoderInit& aInit)
: MediaDecoder(aInit)
, mGeckoWatchManager(this, aInit.mOwner->AbstractMainThread())
{
mExplicitDuration.emplace(UnspecifiedNaN<double>());
mGeckoWatchManager.Watch(mBuffered, &GeckoMediaDecoder::NotifyBuffered);
}

Expand Down
56 changes: 52 additions & 4 deletions gecko-media/gecko/glue/GeckoMediaSourceBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ struct GeckoMediaSourceBuffer
GeckoMediaSourceBuffer(size_t aId,
GeckoMediaSourceBufferImpl aImpl,
size_t aParentId,
const char* aMimeType)
: mSourceBuffer(new SourceBuffer(aImpl, aParentId, aMimeType))
const char* aMimeType,
bool aGenerateTimestamps)
: mSourceBuffer(
new SourceBuffer(aImpl, aParentId, aMimeType, aGenerateTimestamps))
, mId(aId)
{
}
Expand All @@ -35,13 +37,59 @@ void
GeckoMedia_SourceBuffer_Create(size_t aId,
GeckoMediaSourceBufferImpl aImpl,
size_t aParentId,
const char* aMimeType)
const char* aMimeType,
bool aGenerateTimestamps)
{
GeckoMediaSourceBuffer* reflector =
sReflectors.AppendElement(GeckoMediaSourceBuffer(aId, aImpl, aParentId, aMimeType));
sReflectors.AppendElement(GeckoMediaSourceBuffer(
aId, aImpl, aParentId, aMimeType, aGenerateTimestamps));
MOZ_ASSERT(GetReflector(aId) == reflector);
}

void
GeckoMedia_SourceBuffer_EvictData(size_t aId, size_t aLength, bool* aBufferFull)
{
IMPL_GECKO_MEDIA_REFLECTOR_GET(GeckoMediaSourceBuffer)

reflector->mSourceBuffer->EvictData(aLength, aBufferFull);
}

void
GeckoMedia_SourceBuffer_AppendData(size_t aId,
const uint8_t* aData,
size_t aLength)
{
IMPL_GECKO_MEDIA_REFLECTOR_GET(GeckoMediaSourceBuffer)

reflector->mSourceBuffer->AppendData(aData, aLength);
}

void
GeckoMedia_SourceBuffer_AbortBufferAppend(size_t aId)
{
IMPL_GECKO_MEDIA_REFLECTOR_GET(GeckoMediaSourceBuffer)

reflector->mSourceBuffer->AbortBufferAppend();
}

void
GeckoMedia_SourceBuffer_ResetParserState(size_t aId)
{
IMPL_GECKO_MEDIA_REFLECTOR_GET(GeckoMediaSourceBuffer)

reflector->mSourceBuffer->ResetParserState();
}

void
GeckoMedia_SourceBuffer_RangeRemoval(size_t aId,
double aStart,
double aEnd)
{
IMPL_GECKO_MEDIA_REFLECTOR_GET(GeckoMediaSourceBuffer)

reflector->mSourceBuffer->RangeRemoval(aStart, aEnd);
}

SourceBuffer*
GetSourceBuffer(const size_t aId)
{
Expand Down
145 changes: 133 additions & 12 deletions gecko-media/gecko/glue/MediaSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "mozilla/Logging.h"
#include "mozilla/Preferences.h"
#include "nsThreadManager.h"
#include "SourceBuffer.h"

mozilla::LogModule*
GetMediaSourceLog()
Expand Down Expand Up @@ -61,6 +62,8 @@ namespace dom {

MediaSource::MediaSource(GeckoMediaSourceImpl aImpl)
: mImpl(aImpl)
, mSourceBuffers(GetSourceBuffers())
, mActiveSourceBuffers(GetActiveSourceBuffers())
, mDecoder(nullptr)
{
}
Expand All @@ -79,14 +82,56 @@ MediaSource::~MediaSource()
(*mImpl.mFree)(mImpl.mContext);
}

SourceBufferList*
MediaSource::SourceBuffers()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT_IF(ReadyState() == MediaSourceReadyState::Closed, mSourceBuffers->Length() == 0);
return mSourceBuffers;
}

SourceBufferList*
MediaSource::GetSourceBuffers()
{
MOZ_ASSERT(NS_IsMainThread());

CALLBACK_GUARD(GetSourceBuffers, nullptr);
size_t* id = CALLBACK_CALL(GetSourceBuffers);
if (NS_WARN_IF(!id)) {
return nullptr;
}

return GetSourceBufferList(*id);
}

SourceBufferList*
MediaSource::ActiveSourceBuffers()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT_IF(ReadyState() == MediaSourceReadyState::Closed, mActiveSourceBuffers->Length() == 0);
return mActiveSourceBuffers;
}

SourceBufferList*
MediaSource::GetActiveSourceBuffers()
{
MOZ_ASSERT(NS_IsMainThread());

CALLBACK_GUARD(GetActiveSourceBuffers, nullptr);
size_t* id = (*mImpl.mGetActiveSourceBuffers)(mImpl.mContext);
if (NS_WARN_IF(!id)) {
return nullptr;
}

return GetSourceBufferList(*id);
}

double
MediaSource::Duration()
{
MOZ_ASSERT(NS_IsMainThread());
if (NS_WARN_IF(!mImpl.mContext || !mImpl.mGetDuration)) {
return 0;
}
return (*mImpl.mGetDuration)(mImpl.mContext);
CALLBACK_GUARD(GetDuration, 0);
return CALLBACK_CALL(GetDuration);
}

void
Expand All @@ -104,22 +149,54 @@ MediaSourceReadyState
MediaSource::ReadyState()
{
MOZ_ASSERT(NS_IsMainThread());
if (NS_WARN_IF(!mImpl.mContext || !mImpl.mGetReadyState)) {
return MediaSourceReadyState::Unknown;
}

return (*mImpl.mGetReadyState)(mImpl.mContext);
CALLBACK_GUARD(GetReadyState, MediaSourceReadyState::Unknown);
return CALLBACK_CALL(GetReadyState);
}

bool
MediaSource::HasLiveSeekableRange()
MediaSource::Attach(MediaSourceDecoder* aDecoder)
{
MOZ_ASSERT(NS_IsMainThread());
if (NS_WARN_IF(!mImpl.mContext || !mImpl.mHasLiveSeekableRange)) {
MSE_DEBUG("Attach(aDecoder=%p) owner=%p", aDecoder, aDecoder->GetOwner());
MOZ_ASSERT(aDecoder);
MOZ_ASSERT(aDecoder->GetOwner());
if (ReadyState() != MediaSourceReadyState::Closed) {
return false;
}
MOZ_ASSERT(!mDecoder);
mDecoder = aDecoder;
mDecoder->AttachMediaSource(this);
SetReadyState(MediaSourceReadyState::Open);
return true;
}

return (*mImpl.mHasLiveSeekableRange)(mImpl.mContext);
void
MediaSource::Detach()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(mCompletionPromises.IsEmpty());
MSE_DEBUG("mDecoder=%p owner=%p",
mDecoder.get(),
mDecoder ? mDecoder->GetOwner() : nullptr);
if (!mDecoder) {
MOZ_ASSERT(ReadyState() == MediaSourceReadyState::Closed);
MOZ_ASSERT(mActiveSourceBuffers->Length() == 0 &&
mSourceBuffers->Length() == 0);
return;
}
SetReadyState(MediaSourceReadyState::Closed);
mSourceBuffers->Clear();
mActiveSourceBuffers->Clear();
mDecoder->DetachMediaSource();
mDecoder = nullptr;
}

bool
MediaSource::HasLiveSeekableRange()
{
MOZ_ASSERT(NS_IsMainThread());
CALLBACK_GUARD(HasLiveSeekableRange, false);
return CALLBACK_CALL(HasLiveSeekableRange);
}

media::TimeInterval
Expand Down Expand Up @@ -167,6 +244,50 @@ MediaSource::EndOfStreamError(const GeckoMediaEndOfStreamError aError)
}
}

RefPtr<MediaSource::ActiveCompletionPromise>
MediaSource::SourceBufferIsActive(SourceBuffer* aSourceBuffer)
{
MOZ_ASSERT(NS_IsMainThread());

bool initMissing = false;
bool found = false;
for (uint32_t i = 0; i < mSourceBuffers->Length() ; i++) {
SourceBuffer* sourceBuffer = mSourceBuffers->IndexedGetter(i, found);
MOZ_ALWAYS_TRUE(found);
if (sourceBuffer == aSourceBuffer) {
sourceBuffer->SetActive(true);
} else if (!sourceBuffer->GetActive()) {
// Some source buffers haven't yet received an init segment.
// There's nothing more we can do at this stage.
initMissing = true;
}
}

if (initMissing || !mDecoder) {
return ActiveCompletionPromise::CreateAndResolve(true, __func__);
}

mDecoder->NotifyInitDataArrived();

// Add our promise to the queue.
// It will be resolved once the HTMLMediaElement modifies its readyState.
MozPromiseHolder<ActiveCompletionPromise> holder;
RefPtr<ActiveCompletionPromise> promise = holder.Ensure(__func__);
mCompletionPromises.AppendElement(Move(holder));
return promise;
}

void
MediaSource::CompletePendingTransactions()
{
MOZ_ASSERT(NS_IsMainThread());
MSE_DEBUG("Resolving %u promises", unsigned(mCompletionPromises.Length()));
for (auto& promise : mCompletionPromises) {
promise.Resolve(true, __func__);
}
mCompletionPromises.Clear();
}

/* static */
bool
MediaSource::IsTypeSupported(const char* aType)
Expand Down
14 changes: 12 additions & 2 deletions gecko-media/gecko/glue/MediaSourceDecoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ using namespace mozilla::media;
namespace mozilla {

MediaSourceDecoder::MediaSourceDecoder(MediaDecoderInit& aInit)
: MediaDecoder(aInit)
: GeckoMediaDecoder(aInit)
, mMediaSource(nullptr)
, mEnded(false)
{
Expand Down Expand Up @@ -177,7 +177,7 @@ MediaSourceDecoder::Shutdown()
}
mDemuxer = nullptr;

MediaDecoder::Shutdown();
GeckoMediaDecoder::Shutdown();
}

void
Expand Down Expand Up @@ -354,6 +354,16 @@ MediaSourceDecoder::NotifyInitDataArrived()
}
}

void
MediaSourceDecoder::NotifyDataArrived()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
AbstractThread::AutoEnter context(AbstractMainThread());
NotifyReaderDataArrived();
GetOwner()->DownloadProgressed();
}

already_AddRefed<nsIPrincipal>
MediaSourceDecoder::GetCurrentPrincipal()
{
Expand Down
41 changes: 40 additions & 1 deletion gecko-media/gecko/glue/Player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
#include "GeckoMediaDecoder.h"
#include "GeckoMediaDecoderOwner.h"
#include "GeckoMediaMacros.h"
#include "GeckoMediaSource.h"
#include "MediaSource.h"
#include "MediaSourceDecoder.h"
#include "RustMediaResource.h"
#include "UniquePtr.h"
#include "mozilla/RefPtr.h"
Expand Down Expand Up @@ -111,6 +114,42 @@ GeckoMedia_Player_CreateNetworkPlayer(size_t aId,
resource->SetDecoder(reflector->mDecoder);
}

bool
GeckoMedia_Player_CreateMediaSourcePlayer(size_t aId,
size_t aMediaSourceId,
PlayerCallbackObject aCallback,
FrameAllocatorObject aAllocator)
{
Player* reflector =
sReflectors.AppendElement(Player(aId, aCallback, aAllocator));
MOZ_ASSERT(GetReflector(aId) == reflector);

MediaDecoderInit decoderInit(
reflector->mDecoderOwner.get(),
1.0, // volume
true, // mPreservesPitch
1.0, // mPlaybackRate
false, // mMinimizePreroll
false, // mHasSuspendTaint
false, // mLooping
MediaContainerType(MEDIAMIMETYPE("application/x.mediasource")));
RefPtr<MediaSourceDecoder> decoder = new MediaSourceDecoder(decoderInit);
reflector->mDecoder = static_cast<GeckoMediaDecoder*>(decoder);
reflector->mDecoderOwner->SetDecoder(reflector->mDecoder);

RefPtr<mozilla::dom::MediaSource> mediaSource =
GetMediaSource(aMediaSourceId);
if (NS_WARN_IF(!mediaSource || !mediaSource->Attach(decoder))) {
return false;
}

if (NS_WARN_IF(reflector->mDecoder->Load(nullptr) != NS_OK)) {
return false;
}

return true;
}

void
GeckoMedia_Player_Play(size_t aId)
{
Expand Down Expand Up @@ -144,5 +183,5 @@ void
GeckoMedia_Player_SetPlaybackRate(size_t aId, double rate)
{
IMPL_GECKO_MEDIA_REFLECTOR_GET(Player)
reflector->mDecoder->SetPlaybackRate(rate);
reflector->mDecoder->SetPlaybackRate(rate);
}
Loading