Use MediaPromise to read MSE TrackBuffer metadata

This commit is contained in:
trav90
2016-11-04 11:59:06 -05:00
committed by roytam1
parent 92235ac152
commit 3bbb18eb37
2 changed files with 121 additions and 38 deletions
+111 -37
View File
@@ -16,6 +16,7 @@
#include "VideoUtils.h"
#include "mozilla/dom/TimeRanges.h"
#include "mozilla/Preferences.h"
#include "mozilla/TypeTraits.h"
#include "nsError.h"
#include "nsIRunnable.h"
#include "nsThreadUtils.h"
@@ -108,6 +109,7 @@ TrackBuffer::Shutdown()
mParentDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
mShutdown = true;
mInitializationPromise.RejectIfExists(NS_ERROR_ABORT, __func__);
mMetadataRequest.DisconnectIfExists();
MOZ_ASSERT(mShutdownPromise.IsEmpty());
nsRefPtr<ShutdownPromise> p = mShutdownPromise.Ensure(__func__);
@@ -548,31 +550,56 @@ TrackBuffer::NewDecoder(int64_t aTimestampOffset)
mLastEndTimestamp.reset();
mLastTimestampOffset = aTimestampOffset;
decoder->SetTaskQueue(mTaskQueue);
decoder->SetTaskQueue(decoder->GetReader()->GetTaskQueue());
return decoder.forget();
}
bool
TrackBuffer::QueueInitializeDecoder(SourceBufferDecoder* aDecoder)
{
if (NS_WARN_IF(!mTaskQueue)) {
mInitializationPromise.RejectIfExists(NS_ERROR_FAILURE, __func__);
return false;
}
// Bug 1153295: We must ensure that the nsIRunnable hold a strong reference
// to aDecoder.
static_assert(mozilla::IsBaseOf<nsISupports, SourceBufferDecoder>::value,
"SourceBufferDecoder must be inheriting from nsISupports");
RefPtr<nsIRunnable> task =
NS_NewRunnableMethodWithArg<SourceBufferDecoder*>(this,
&TrackBuffer::InitializeDecoder,
aDecoder);
if (NS_FAILED(mTaskQueue->Dispatch(task))) {
MSE_DEBUG("failed to enqueue decoder initialization task");
RemoveDecoder(aDecoder);
mInitializationPromise.RejectIfExists(NS_ERROR_FAILURE, __func__);
return false;
}
// We need to initialize the reader on its own task queue
aDecoder->GetReader()->GetTaskQueue()->Dispatch(task);
return true;
}
// MetadataRecipient is a is used to pass extra values required by the
// MetadataPromise's target methods
class MetadataRecipient {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MetadataRecipient);
MetadataRecipient(TrackBuffer* aOwner,
SourceBufferDecoder* aDecoder,
bool aWasEnded)
: mOwner(aOwner)
, mDecoder(aDecoder)
, mWasEnded(aWasEnded) { }
void OnMetadataRead(MetadataHolder* aMetadata)
{
mOwner->OnMetadataRead(aMetadata, mDecoder, mWasEnded);
}
void OnMetadataNotRead(ReadMetadataFailureReason aReason)
{
mOwner->OnMetadataNotRead(aReason, mDecoder);
}
private:
~MetadataRecipient() {}
nsRefPtr<TrackBuffer> mOwner;
nsRefPtr<SourceBufferDecoder> mDecoder;
bool mWasEnded;
};
void
TrackBuffer::InitializeDecoder(SourceBufferDecoder* aDecoder)
{
@@ -600,19 +627,16 @@ TrackBuffer::InitializeDecoder(SourceBufferDecoder* aDecoder)
// important pieces of our state (like mTaskQueue) have also been torn down.
if (mShutdown) {
MSE_DEBUG("was shut down. Aborting initialization.");
RemoveDecoder(aDecoder);
return;
}
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
MOZ_ASSERT(aDecoder->GetReader()->GetTaskQueue()->IsCurrentThreadIn());
MediaDecoderReader* reader = aDecoder->GetReader();
MSE_DEBUG("Initializing subdecoder %p reader %p",
aDecoder, reader);
MediaInfo mi;
nsAutoPtr<MetadataTags> tags; // TODO: Handle metadata.
nsresult rv;
// HACK WARNING:
// We only reach this point once we know that we have a complete init segment.
// We don't want the demuxer to do a blocking read as no more data can be
@@ -624,18 +648,13 @@ TrackBuffer::InitializeDecoder(SourceBufferDecoder* aDecoder)
if (!wasEnded) {
aDecoder->GetResource()->Ended();
}
nsRefPtr<MetadataRecipient> recipient =
new MetadataRecipient(this, aDecoder, wasEnded);
nsRefPtr<MediaDecoderReader::MetadataPromise> promise;
{
ReentrantMonitorAutoExit mon(mParentDecoder->GetReentrantMonitor());
rv = reader->ReadMetadata(&mi, getter_Transfers(tags));
promise = reader->AsyncReadMetadata();
}
if (!wasEnded) {
// Adding an empty buffer will reopen the SourceBufferResource
nsRefPtr<MediaLargeByteBuffer> emptyBuffer = new MediaLargeByteBuffer;
aDecoder->GetResource()->AppendData(emptyBuffer);
}
// HACK END.
reader->SetIdle();
if (mShutdown) {
MSE_DEBUG("was shut down while reading metadata. Aborting initialization.");
return;
@@ -645,20 +664,43 @@ TrackBuffer::InitializeDecoder(SourceBufferDecoder* aDecoder)
return;
}
if (NS_SUCCEEDED(rv) && reader->IsWaitingOnCDMResource()) {
mMetadataRequest.Begin(promise
->RefableThen(reader->GetTaskQueue(), __func__,
recipient.get(),
&MetadataRecipient::OnMetadataRead,
&MetadataRecipient::OnMetadataNotRead));
}
void
TrackBuffer::OnMetadataRead(MetadataHolder* aMetadata,
SourceBufferDecoder* aDecoder,
bool aWasEnded)
{
MOZ_ASSERT(aDecoder->GetReader()->GetTaskQueue()->IsCurrentThreadIn());
mParentDecoder->GetReentrantMonitor().AssertNotCurrentThreadIn();
ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
mMetadataRequest.Complete();
// Adding an empty buffer will reopen the SourceBufferResource
if (!aWasEnded) {
nsRefPtr<MediaLargeByteBuffer> emptyBuffer = new MediaLargeByteBuffer;
aDecoder->GetResource()->AppendData(emptyBuffer);
}
// HACK END.
MediaDecoderReader* reader = aDecoder->GetReader();
reader->SetIdle();
if (reader->IsWaitingOnCDMResource()) {
mIsWaitingOnCDM = true;
}
aDecoder->SetTaskQueue(nullptr);
if (NS_FAILED(rv) || (!mi.HasVideo() && !mi.HasAudio())) {
// XXX: Need to signal error back to owning SourceBuffer.
MSE_DEBUG("Reader %p failed to initialize rv=%x audio=%d video=%d",
reader, rv, mi.HasAudio(), mi.HasVideo());
RemoveDecoder(aDecoder);
mInitializationPromise.RejectIfExists(NS_ERROR_FAILURE, __func__);
return;
}
// A MediaDataPromise is only resolved if MediaInfo.HasValidMedia() is true.
MediaInfo mi = aMetadata->mInfo;
if (mi.HasVideo()) {
MSE_DEBUG("Reader %p video resolution=%dx%d",
@@ -681,9 +723,33 @@ TrackBuffer::InitializeDecoder(SourceBufferDecoder* aDecoder)
}
}
void
TrackBuffer::OnMetadataNotRead(ReadMetadataFailureReason aReason,
SourceBufferDecoder* aDecoder)
{
MOZ_ASSERT(aDecoder->GetReader()->GetTaskQueue()->IsCurrentThreadIn());
mParentDecoder->GetReentrantMonitor().AssertNotCurrentThreadIn();
ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
mMetadataRequest.Complete();
MediaDecoderReader* reader = aDecoder->GetReader();
reader->SetIdle();
aDecoder->SetTaskQueue(nullptr);
MSE_DEBUG("Reader %p failed to initialize", reader);
RemoveDecoder(aDecoder);
mInitializationPromise.RejectIfExists(NS_ERROR_FAILURE, __func__);
}
void
TrackBuffer::CompleteInitializeDecoder(SourceBufferDecoder* aDecoder)
{
MOZ_ASSERT(NS_IsMainThread());
if (!mParentDecoder) {
MSE_DEBUG("was shutdown. Aborting initialization.");
return;
@@ -698,7 +764,6 @@ TrackBuffer::CompleteInitializeDecoder(SourceBufferDecoder* aDecoder)
if (mShutdown) {
MSE_DEBUG("was shut down. Aborting initialization.");
RemoveDecoder(aDecoder);
return;
}
@@ -861,7 +926,16 @@ TrackBuffer::ResetParserState()
void
TrackBuffer::AbortAppendData()
{
ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
nsRefPtr<SourceBufferDecoder> current = mCurrentDecoder;
DiscardCurrentDecoder();
if (mMetadataRequest.Exists() || !mInitializationPromise.IsEmpty()) {
MOZ_ASSERT(current);
RemoveDecoder(current);
}
mMetadataRequest.DisconnectIfExists();
// The SourceBuffer would have disconnected its promise.
// However we must ensure that the MediaPromiseHolder handle all pending
// promises.
+10 -1
View File
@@ -118,6 +118,7 @@ public:
private:
friend class DecodersToInitialize;
friend class MetadataRecipient;
~TrackBuffer();
// Create a new decoder, set mCurrentDecoder to the new decoder and
@@ -163,6 +164,13 @@ private:
// Remove all empty decoders from the provided list;
void RemoveEmptyDecoders(nsTArray<SourceBufferDecoder*>& aDecoders);
void OnMetadataRead(MetadataHolder* aMetadata,
SourceBufferDecoder* aDecoder,
bool aWasEnded);
void OnMetadataNotRead(ReadMetadataFailureReason aReason,
SourceBufferDecoder* aDecoder);
nsAutoPtr<ContainerParser> mParser;
// A task queue using the shared media thread pool. Used exclusively to
@@ -213,7 +221,8 @@ private:
bool mShutdown;
MediaPromiseHolder<TrackBufferAppendPromise> mInitializationPromise;
// Track our request for metadata from the reader.
MediaPromiseConsumerHolder<MediaDecoderReader::MetadataPromise> mMetadataRequest;
};
} // namespace mozilla