mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-06-10 02:18:57 +00:00
Use MediaPromise to read MSE TrackBuffer metadata
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user