mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-07 08:18:41 +09:00
Media: harden TrackID handling.
This commit is contained in:
parent
bfe6f25a2d
commit
0bdecfc6ea
9 changed files with 183 additions and 37 deletions
|
|
@ -817,6 +817,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLMediaElement, nsGenericHTM
|
|||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mErrorSink->mError)
|
||||
for (uint32_t i = 0; i < tmp->mOutputStreams.Length(); ++i) {
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOutputStreams[i].mStream);
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOutputStreams[i].mPreCreatedTracks);
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPlayed);
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTextTrackManager)
|
||||
|
|
@ -1020,6 +1021,17 @@ void HTMLMediaElement::ShutdownDecoder()
|
|||
RemoveMediaElementFromURITable();
|
||||
NS_ASSERTION(mDecoder, "Must have decoder to shut down");
|
||||
mWaitingForKeyListener.DisconnectIfExists();
|
||||
for (OutputMediaStream& out : mOutputStreams) {
|
||||
if (!out.mCapturingDecoder) {
|
||||
continue;
|
||||
}
|
||||
if (!out.mStream) {
|
||||
continue;
|
||||
}
|
||||
out.mNextAvailableTrackID = std::max<TrackID>(
|
||||
mDecoder->NextAvailableTrackIDFor(out.mStream->GetInputStream()),
|
||||
out.mNextAvailableTrackID);
|
||||
}
|
||||
mDecoder->Shutdown();
|
||||
mDecoder = nullptr;
|
||||
}
|
||||
|
|
@ -2730,6 +2742,7 @@ HTMLMediaElement::CaptureStreamInternal(bool aFinishWhenEnded,
|
|||
if (mDecoder) {
|
||||
out->mCapturingDecoder = true;
|
||||
mDecoder->AddOutputStream(out->mStream->GetInputStream()->AsProcessedStream(),
|
||||
out->mNextAvailableTrackID,
|
||||
aFinishWhenEnded);
|
||||
} else if (mSrcStream) {
|
||||
out->mCapturingMediaStream = true;
|
||||
|
|
@ -2743,23 +2756,26 @@ HTMLMediaElement::CaptureStreamInternal(bool aFinishWhenEnded,
|
|||
|
||||
if (mDecoder) {
|
||||
if (HasAudio()) {
|
||||
TrackID audioTrackId = mMediaInfo.mAudio.mTrackId;
|
||||
TrackID audioTrackId = out->mNextAvailableTrackID++;
|
||||
RefPtr<MediaStreamTrackSource> trackSource =
|
||||
getter->GetMediaStreamTrackSource(audioTrackId);
|
||||
RefPtr<MediaStreamTrack> track =
|
||||
out->mStream->CreateDOMTrack(audioTrackId, MediaSegment::AUDIO,
|
||||
out->mStream->CreateDOMTrack(audioTrackId,
|
||||
MediaSegment::AUDIO,
|
||||
trackSource);
|
||||
out->mPreCreatedTracks.AppendElement(track);
|
||||
out->mStream->AddTrackInternal(track);
|
||||
LOG(LogLevel::Debug,
|
||||
("Created audio track %d for captured decoder", audioTrackId));
|
||||
}
|
||||
if (IsVideo() && HasVideo() && !out->mCapturingAudioOnly) {
|
||||
TrackID videoTrackId = mMediaInfo.mVideo.mTrackId;
|
||||
TrackID videoTrackId = out->mNextAvailableTrackID++;
|
||||
RefPtr<MediaStreamTrackSource> trackSource =
|
||||
getter->GetMediaStreamTrackSource(videoTrackId);
|
||||
RefPtr<MediaStreamTrack> track =
|
||||
out->mStream->CreateDOMTrack(videoTrackId, MediaSegment::VIDEO,
|
||||
trackSource);
|
||||
out->mPreCreatedTracks.AppendElement(track);
|
||||
out->mStream->AddTrackInternal(track);
|
||||
LOG(LogLevel::Debug,
|
||||
("Created video track %d for captured decoder", videoTrackId));
|
||||
|
|
@ -2848,6 +2864,25 @@ NS_IMETHODIMP HTMLMediaElement::GetMozAudioCaptured(bool* aCaptured)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLMediaElement::EndPreCreatedCapturedDecoderTracks()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
for (OutputMediaStream& ms : mOutputStreams) {
|
||||
if (!ms.mCapturingDecoder) {
|
||||
continue;
|
||||
}
|
||||
for (RefPtr<MediaStreamTrack>& t : ms.mPreCreatedTracks) {
|
||||
if (t->Ended()) {
|
||||
continue;
|
||||
}
|
||||
NS_DispatchToMainThread(NewRunnableMethod(
|
||||
t, &MediaStreamTrack::OverrideEnded));
|
||||
}
|
||||
ms.mPreCreatedTracks.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
class MediaElementSetForURI : public nsURIHashKey {
|
||||
public:
|
||||
explicit MediaElementSetForURI(const nsIURI* aKey) : nsURIHashKey(aKey) {}
|
||||
|
|
@ -3380,11 +3415,12 @@ HTMLMediaElement::WakeLockRelease()
|
|||
}
|
||||
|
||||
HTMLMediaElement::OutputMediaStream::OutputMediaStream()
|
||||
: mFinishWhenEnded(false)
|
||||
: mNextAvailableTrackID(1)
|
||||
, mFinishWhenEnded(false)
|
||||
, mCapturingAudioOnly(false)
|
||||
, mCapturingDecoder(false)
|
||||
, mCapturingMediaStream(false)
|
||||
, mNextAvailableTrackID(1) {}
|
||||
{}
|
||||
|
||||
HTMLMediaElement::OutputMediaStream::~OutputMediaStream()
|
||||
{
|
||||
|
|
@ -4008,6 +4044,7 @@ nsresult HTMLMediaElement::FinishDecoderSetup(MediaDecoder* aDecoder,
|
|||
|
||||
ms.mCapturingDecoder = true;
|
||||
aDecoder->AddOutputStream(ms.mStream->GetInputStream()->AsProcessedStream(),
|
||||
ms.mNextAvailableTrackID,
|
||||
ms.mFinishWhenEnded);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -675,6 +675,11 @@ public:
|
|||
return mAudioCaptured;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures any MediaStreamTracks captured from a MediaDecoder are ended.
|
||||
*/
|
||||
void EndPreCreatedCapturedDecoderTracks();
|
||||
|
||||
void MozGetMetadata(JSContext* aCx, JS::MutableHandle<JSObject*> aResult,
|
||||
ErrorResult& aRv);
|
||||
|
||||
|
|
@ -815,13 +820,18 @@ protected:
|
|||
~OutputMediaStream();
|
||||
|
||||
RefPtr<DOMMediaStream> mStream;
|
||||
TrackID mNextAvailableTrackID;
|
||||
bool mFinishWhenEnded;
|
||||
bool mCapturingAudioOnly;
|
||||
bool mCapturingDecoder;
|
||||
bool mCapturingMediaStream;
|
||||
|
||||
// The following members are keeping state for a captured MediaDecoder.
|
||||
// Tracks that were created on main thread before MediaDecoder fed them
|
||||
// to the MediaStreamGraph.
|
||||
nsTArray<RefPtr<MediaStreamTrack>> mPreCreatedTracks;
|
||||
|
||||
// The following members are keeping state for a captured MediaStream.
|
||||
TrackID mNextAvailableTrackID;
|
||||
nsTArray<Pair<nsString, RefPtr<MediaInputPort>>> mTrackPorts;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -327,11 +327,13 @@ MediaDecoder::SetVolume(double aVolume)
|
|||
|
||||
void
|
||||
MediaDecoder::AddOutputStream(ProcessedMediaStream* aStream,
|
||||
TrackID aNextAvailableTrackID,
|
||||
bool aFinishWhenEnded)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mDecoderStateMachine, "Must be called after Load().");
|
||||
mDecoderStateMachine->AddOutputStream(aStream, aFinishWhenEnded);
|
||||
mDecoderStateMachine->AddOutputStream(
|
||||
aStream, aNextAvailableTrackID, aFinishWhenEnded);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -342,6 +344,14 @@ MediaDecoder::RemoveOutputStream(MediaStream* aStream)
|
|||
mDecoderStateMachine->RemoveOutputStream(aStream);
|
||||
}
|
||||
|
||||
TrackID
|
||||
MediaDecoder::NextAvailableTrackIDFor(MediaStream* aOutputStream) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mDecoderStateMachine, "Must be called after Load().");
|
||||
return mDecoderStateMachine->NextAvailableTrackIDFor(aOutputStream);
|
||||
}
|
||||
|
||||
double
|
||||
MediaDecoder::GetDuration()
|
||||
{
|
||||
|
|
@ -1736,6 +1746,8 @@ MediaDecoder::RemoveMediaTracks()
|
|||
videoList->RemoveTracks();
|
||||
}
|
||||
|
||||
element->EndPreCreatedCapturedDecoderTracks();
|
||||
|
||||
mMediaTracksConstructed = false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -210,9 +210,13 @@ public:
|
|||
// Add an output stream. All decoder output will be sent to the stream.
|
||||
// The stream is initially blocked. The decoder is responsible for unblocking
|
||||
// it while it is playing back.
|
||||
virtual void AddOutputStream(ProcessedMediaStream* aStream, bool aFinishWhenEnded);
|
||||
virtual void AddOutputStream(ProcessedMediaStream* aStream,
|
||||
TrackID aNextAvailableTrackID,
|
||||
bool aFinishWhenEnded);
|
||||
// Remove an output stream added with AddOutputStream.
|
||||
virtual void RemoveOutputStream(MediaStream* aStream);
|
||||
// The next TrackID that can be used without risk of a collision.
|
||||
virtual TrackID NextAvailableTrackIDFor(MediaStream* aOutputStream) const;
|
||||
|
||||
// Return the duration of the video in seconds.
|
||||
virtual double GetDuration();
|
||||
|
|
|
|||
|
|
@ -2835,6 +2835,10 @@ MediaDecoderStateMachine::FinishDecodeFirstFrame()
|
|||
RefPtr<ShutdownPromise>
|
||||
MediaDecoderStateMachine::BeginShutdown()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (mOutputStreamManager) {
|
||||
mOutputStreamManager->Clear();
|
||||
}
|
||||
return InvokeAsync(OwnerThread(), this, __func__,
|
||||
&MediaDecoderStateMachine::Shutdown);
|
||||
}
|
||||
|
|
@ -3250,11 +3254,12 @@ MediaDecoderStateMachine::DumpDebugInfo()
|
|||
}
|
||||
|
||||
void MediaDecoderStateMachine::AddOutputStream(ProcessedMediaStream* aStream,
|
||||
TrackID aNextAvailableTrackID,
|
||||
bool aFinishWhenEnded)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
DECODER_LOG("AddOutputStream aStream=%p!", aStream);
|
||||
mOutputStreamManager->Add(aStream, aFinishWhenEnded);
|
||||
mOutputStreamManager->Add(aStream, aNextAvailableTrackID, aFinishWhenEnded);
|
||||
nsCOMPtr<nsIRunnable> r = NewRunnableMethod<bool>(
|
||||
this, &MediaDecoderStateMachine::SetAudioCaptured, true);
|
||||
OwnerThread()->Dispatch(r.forget());
|
||||
|
|
@ -3269,9 +3274,17 @@ void MediaDecoderStateMachine::RemoveOutputStream(MediaStream* aStream)
|
|||
nsCOMPtr<nsIRunnable> r = NewRunnableMethod<bool>(
|
||||
this, &MediaDecoderStateMachine::SetAudioCaptured, false);
|
||||
OwnerThread()->Dispatch(r.forget());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
TrackID
|
||||
MediaDecoderStateMachine::NextAvailableTrackIDFor(MediaStream* aOutputStream) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
return mOutputStreamManager->NextAvailableTrackIDFor(aOutputStream);
|
||||
}
|
||||
|
||||
size_t
|
||||
MediaDecoderStateMachine::SizeOfVideoQueue() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -168,9 +168,12 @@ public:
|
|||
|
||||
void DumpDebugInfo();
|
||||
|
||||
void AddOutputStream(ProcessedMediaStream* aStream, bool aFinishWhenEnded);
|
||||
void AddOutputStream(ProcessedMediaStream* aStream,
|
||||
TrackID aNextAvailableTrackID,
|
||||
bool aFinishWhenEnded);
|
||||
// Remove an output stream added with AddOutputStream.
|
||||
void RemoveOutputStream(MediaStream* aStream);
|
||||
TrackID NextAvailableTrackIDFor(MediaStream* aOutputStream) const;
|
||||
|
||||
// Seeks to the decoder to aTarget asynchronously.
|
||||
RefPtr<MediaDecoder::SeekPromise> InvokeSeek(SeekTarget aTarget);
|
||||
|
|
|
|||
|
|
@ -181,17 +181,22 @@ DecodedStreamData::DecodedStreamData(OutputStreamManager* aOutputStreamManager,
|
|||
, mOutputStreamManager(aOutputStreamManager)
|
||||
{
|
||||
mStream->AddListener(mListener);
|
||||
mOutputStreamManager->Connect(mStream);
|
||||
TrackID audioTrack = TRACK_NONE;
|
||||
TrackID videoTrack = TRACK_NONE;
|
||||
|
||||
// Initialize tracks.
|
||||
if (aInit.mInfo.HasAudio()) {
|
||||
mStream->AddAudioTrack(aInit.mInfo.mAudio.mTrackId,
|
||||
audioTrack = aInit.mInfo.mAudio.mTrackId;
|
||||
mStream->AddAudioTrack(audioTrack,
|
||||
aInit.mInfo.mAudio.mRate,
|
||||
0, new AudioSegment());
|
||||
}
|
||||
if (aInit.mInfo.HasVideo()) {
|
||||
mStream->AddTrack(aInit.mInfo.mVideo.mTrackId, 0, new VideoSegment());
|
||||
videoTrack = aInit.mInfo.mVideo.mTrackId;
|
||||
mStream->AddTrack(videoTrack, 0, new VideoSegment());
|
||||
}
|
||||
|
||||
mOutputStreamManager->Connect(mStream, audioTrack, videoTrack);
|
||||
}
|
||||
|
||||
DecodedStreamData::~DecodedStreamData()
|
||||
|
|
|
|||
|
|
@ -13,29 +13,41 @@ OutputStreamData::~OutputStreamData()
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
// Break the connection to the input stream if necessary.
|
||||
if (mPort) {
|
||||
mPort->Destroy();
|
||||
for (RefPtr<MediaInputPort>& port : mPorts) {
|
||||
port->Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
OutputStreamData::Init(OutputStreamManager* aOwner, ProcessedMediaStream* aStream)
|
||||
OutputStreamData::Init(OutputStreamManager* aOwner,
|
||||
ProcessedMediaStream* aStream,
|
||||
TrackID aNextAvailableTrackID)
|
||||
{
|
||||
mOwner = aOwner;
|
||||
mStream = aStream;
|
||||
mNextAvailableTrackID = aNextAvailableTrackID;
|
||||
}
|
||||
|
||||
bool
|
||||
OutputStreamData::Connect(MediaStream* aStream)
|
||||
OutputStreamData::Connect(MediaStream* aStream,
|
||||
TrackID aInputAudioTrackID,
|
||||
TrackID aInputVideoTrackID)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!mPort, "Already connected?");
|
||||
MOZ_ASSERT(mPorts.IsEmpty(), "Already connected?");
|
||||
|
||||
if (mStream->IsDestroyed()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mPort = mStream->AllocateInputPort(aStream);
|
||||
for (TrackID tid : {aInputAudioTrackID, aInputVideoTrackID}) {
|
||||
if (tid == TRACK_NONE) {
|
||||
continue;
|
||||
}
|
||||
MOZ_ASSERT(IsTrackIDExplicit(tid));
|
||||
mPorts.AppendElement(mStream->AllocateInputPort(
|
||||
aStream, tid, mNextAvailableTrackID++));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -51,11 +63,11 @@ OutputStreamData::Disconnect()
|
|||
return false;
|
||||
}
|
||||
|
||||
// Disconnect the existing port if necessary.
|
||||
if (mPort) {
|
||||
mPort->Destroy();
|
||||
mPort = nullptr;
|
||||
// Disconnect any existing port.
|
||||
for (RefPtr<MediaInputPort>& port : mPorts) {
|
||||
port->Destroy();
|
||||
}
|
||||
mPorts.Clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -71,8 +83,16 @@ OutputStreamData::Graph() const
|
|||
return mStream->Graph();
|
||||
}
|
||||
|
||||
TrackID
|
||||
OutputStreamData::NextAvailableTrackID() const
|
||||
{
|
||||
return mNextAvailableTrackID;
|
||||
}
|
||||
|
||||
void
|
||||
OutputStreamManager::Add(ProcessedMediaStream* aStream, bool aFinishWhenEnded)
|
||||
OutputStreamManager::Add(ProcessedMediaStream* aStream,
|
||||
TrackID aNextAvailableTrackID,
|
||||
bool aFinishWhenEnded)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
// All streams must belong to the same graph.
|
||||
|
|
@ -84,12 +104,12 @@ OutputStreamManager::Add(ProcessedMediaStream* aStream, bool aFinishWhenEnded)
|
|||
}
|
||||
|
||||
OutputStreamData* p = mStreams.AppendElement();
|
||||
p->Init(this, aStream);
|
||||
p->Init(this, aStream, aNextAvailableTrackID);
|
||||
|
||||
// Connect to the input stream if we have one. Otherwise the output stream
|
||||
// will be connected in Connect().
|
||||
if (mInputStream) {
|
||||
p->Connect(mInputStream);
|
||||
p->Connect(mInputStream, mInputAudioTrackID, mInputVideoTrackID);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -106,12 +126,35 @@ OutputStreamManager::Remove(MediaStream* aStream)
|
|||
}
|
||||
|
||||
void
|
||||
OutputStreamManager::Connect(MediaStream* aStream)
|
||||
OutputStreamManager::Clear()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mStreams.Clear();
|
||||
}
|
||||
|
||||
TrackID
|
||||
OutputStreamManager::NextAvailableTrackIDFor(MediaStream* aOutputStream) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
for (const OutputStreamData& out : mStreams) {
|
||||
if (out.Equals(aOutputStream)) {
|
||||
return out.NextAvailableTrackID();
|
||||
}
|
||||
}
|
||||
return TRACK_INVALID;
|
||||
}
|
||||
|
||||
void
|
||||
OutputStreamManager::Connect(MediaStream* aStream,
|
||||
TrackID aAudioTrackID,
|
||||
TrackID aVideoTrackID)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mInputStream = aStream;
|
||||
mInputAudioTrackID = aAudioTrackID;
|
||||
mInputVideoTrackID = aVideoTrackID;
|
||||
for (int32_t i = mStreams.Length() - 1; i >= 0; --i) {
|
||||
if (!mStreams[i].Connect(aStream)) {
|
||||
if (!mStreams[i].Connect(aStream, mInputAudioTrackID, mInputVideoTrackID)) {
|
||||
// Probably the DOMMediaStream was GCed. Clean up.
|
||||
mStreams.RemoveElementAt(i);
|
||||
}
|
||||
|
|
@ -123,6 +166,8 @@ OutputStreamManager::Disconnect()
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mInputStream = nullptr;
|
||||
mInputAudioTrackID = TRACK_INVALID;
|
||||
mInputVideoTrackID = TRACK_INVALID;
|
||||
for (int32_t i = mStreams.Length() - 1; i >= 0; --i) {
|
||||
if (!mStreams[i].Disconnect()) {
|
||||
// Probably the DOMMediaStream was GCed. Clean up.
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsTArray.h"
|
||||
#include "MediaSegment.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
|
@ -21,11 +22,13 @@ class ProcessedMediaStream;
|
|||
class OutputStreamData {
|
||||
public:
|
||||
~OutputStreamData();
|
||||
void Init(OutputStreamManager* aOwner, ProcessedMediaStream* aStream);
|
||||
void Init(OutputStreamManager* aOwner,
|
||||
ProcessedMediaStream* aStream,
|
||||
TrackID aNextAvailableTrackID);
|
||||
|
||||
// Connect mStream to the input stream.
|
||||
// Connect the given input stream's audio and video tracks to mStream.
|
||||
// Return false is mStream is already destroyed, otherwise true.
|
||||
bool Connect(MediaStream* aStream);
|
||||
bool Connect(MediaStream* aStream, TrackID aAudioTrackID, TrackID aVideoTrackID);
|
||||
// Disconnect mStream from its input stream.
|
||||
// Return false is mStream is already destroyed, otherwise true.
|
||||
bool Disconnect();
|
||||
|
|
@ -34,12 +37,16 @@ public:
|
|||
bool Equals(MediaStream* aStream) const;
|
||||
// Return the graph mStream belongs to.
|
||||
MediaStreamGraph* Graph() const;
|
||||
// The next TrackID that will not cause a collision in mStream.
|
||||
TrackID NextAvailableTrackID() const;
|
||||
|
||||
private:
|
||||
OutputStreamManager* mOwner;
|
||||
RefPtr<ProcessedMediaStream> mStream;
|
||||
// mPort connects our mStream to an input stream.
|
||||
RefPtr<MediaInputPort> mPort;
|
||||
// mPort connects an input stream to our mStream.
|
||||
nsTArray<RefPtr<MediaInputPort>> mPorts;
|
||||
// For guaranteeing TrackID uniqueness in our mStream.
|
||||
TrackID mNextAvailableTrackID = TRACK_INVALID;
|
||||
};
|
||||
|
||||
class OutputStreamManager {
|
||||
|
|
@ -47,18 +54,26 @@ class OutputStreamManager {
|
|||
|
||||
public:
|
||||
// Add the output stream to the collection.
|
||||
void Add(ProcessedMediaStream* aStream, bool aFinishWhenEnded);
|
||||
void Add(ProcessedMediaStream* aStream,
|
||||
TrackID aNextAvailableTrackID,
|
||||
bool aFinishWhenEnded);
|
||||
// Remove the output stream from the collection.
|
||||
void Remove(MediaStream* aStream);
|
||||
// Clear all output streams from the collection.
|
||||
void Clear();
|
||||
// The next TrackID that will not cause a collision in aOutputStream.
|
||||
TrackID NextAvailableTrackIDFor(MediaStream* aOutputStream) const;
|
||||
// Return true if the collection empty.
|
||||
bool IsEmpty() const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
return mStreams.IsEmpty();
|
||||
}
|
||||
// Connect all output streams in the collection to the input stream.
|
||||
void Connect(MediaStream* aStream);
|
||||
// Disconnect all output streams from the input stream.
|
||||
// Connect the given input stream's tracks to all output streams.
|
||||
void Connect(MediaStream* aStream,
|
||||
TrackID aAudioTrackID,
|
||||
TrackID aVideoTrackID);
|
||||
// Disconnect the input stream to all output streams.
|
||||
void Disconnect();
|
||||
// Return the graph these streams belong to or null if empty.
|
||||
MediaStreamGraph* Graph() const
|
||||
|
|
@ -72,6 +87,8 @@ private:
|
|||
// Keep the input stream so we can connect the output streams that
|
||||
// are added after Connect().
|
||||
RefPtr<MediaStream> mInputStream;
|
||||
TrackID mInputAudioTrackID = TRACK_INVALID;
|
||||
TrackID mInputVideoTrackID = TRACK_INVALID;
|
||||
nsTArray<OutputStreamData> mStreams;
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue