mirror of
https://github.com/classilla/tenfourfox.git
synced 2025-01-01 06:33:22 +00:00
M1256520 + M1248314
This commit is contained in:
parent
41a7492086
commit
027a6309b0
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include "mozilla/CheckedInt.h"
|
#include "mozilla/CheckedInt.h"
|
||||||
#include "mozilla/gfx/Point.h"
|
#include "mozilla/gfx/Point.h"
|
||||||
|
#include "mozilla/SyncRunnable.h"
|
||||||
|
|
||||||
#include "AudioSegment.h"
|
#include "AudioSegment.h"
|
||||||
#include "DecodedStream.h"
|
#include "DecodedStream.h"
|
||||||
@ -18,6 +19,15 @@
|
|||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A container class to make it easier to pass the playback info all the
|
||||||
|
* way to DecodedStreamGraphListener from DecodedStream.
|
||||||
|
*/
|
||||||
|
struct PlaybackInfoInit {
|
||||||
|
int64_t mStartTime;
|
||||||
|
MediaInfo mInfo;
|
||||||
|
};
|
||||||
|
|
||||||
class DecodedStreamGraphListener : public MediaStreamListener {
|
class DecodedStreamGraphListener : public MediaStreamListener {
|
||||||
typedef MediaStreamListener::MediaStreamGraphEvent MediaStreamGraphEvent;
|
typedef MediaStreamListener::MediaStreamGraphEvent MediaStreamGraphEvent;
|
||||||
public:
|
public:
|
||||||
@ -116,7 +126,8 @@ UpdateStreamSuspended(MediaStream* aStream, bool aBlocking)
|
|||||||
*/
|
*/
|
||||||
class DecodedStreamData {
|
class DecodedStreamData {
|
||||||
public:
|
public:
|
||||||
DecodedStreamData(SourceMediaStream* aStream,
|
DecodedStreamData(OutputStreamManager aOutputStreamManager,
|
||||||
|
PlaybackInfoInit&& aInit,
|
||||||
MozPromiseHolder<GenericPromise>&& aPromise);
|
MozPromiseHolder<GenericPromise>&& aPromise);
|
||||||
~DecodedStreamData();
|
~DecodedStreamData();
|
||||||
bool IsFinished() const;
|
bool IsFinished() const;
|
||||||
@ -137,45 +148,56 @@ public:
|
|||||||
// the image.
|
// the image.
|
||||||
RefPtr<layers::Image> mLastVideoImage;
|
RefPtr<layers::Image> mLastVideoImage;
|
||||||
gfx::IntSize mLastVideoImageDisplaySize;
|
gfx::IntSize mLastVideoImageDisplaySize;
|
||||||
// This is set to true when the stream is initialized (audio and
|
|
||||||
// video tracks added).
|
|
||||||
bool mStreamInitialized;
|
|
||||||
bool mHaveSentFinish;
|
bool mHaveSentFinish;
|
||||||
bool mHaveSentFinishAudio;
|
bool mHaveSentFinishAudio;
|
||||||
bool mHaveSentFinishVideo;
|
bool mHaveSentFinishVideo;
|
||||||
|
|
||||||
// The decoder is responsible for calling Destroy() on this stream.
|
// The decoder is responsible for calling Destroy() on this stream.
|
||||||
const RefPtr<SourceMediaStream> mStream;
|
const RefPtr<SourceMediaStream> mStream;
|
||||||
RefPtr<DecodedStreamGraphListener> mListener;
|
const RefPtr<DecodedStreamGraphListener> mListener;
|
||||||
bool mPlaying;
|
bool mPlaying;
|
||||||
// True if we need to send a compensation video frame to ensure the
|
// True if we need to send a compensation video frame to ensure the
|
||||||
// StreamTime going forward.
|
// StreamTime going forward.
|
||||||
bool mEOSVideoCompensation;
|
bool mEOSVideoCompensation;
|
||||||
|
|
||||||
|
OutputStreamManager mOutputStreamManager;
|
||||||
};
|
};
|
||||||
|
|
||||||
DecodedStreamData::DecodedStreamData(SourceMediaStream* aStream,
|
DecodedStreamData::DecodedStreamData(OutputStreamManager aOutputStreamManager,
|
||||||
|
PlaybackInfoInit&& aInit,
|
||||||
MozPromiseHolder<GenericPromise>&& aPromise)
|
MozPromiseHolder<GenericPromise>&& aPromise)
|
||||||
: mAudioFramesWritten(0)
|
: mAudioFramesWritten(0)
|
||||||
, mNextVideoTime(-1)
|
, mNextVideoTime(aInit.mStartTime)
|
||||||
, mNextAudioTime(-1)
|
, mNextAudioTime(aInit.mStartTime)
|
||||||
, mStreamInitialized(false)
|
|
||||||
, mHaveSentFinish(false)
|
, mHaveSentFinish(false)
|
||||||
, mHaveSentFinishAudio(false)
|
, mHaveSentFinishAudio(false)
|
||||||
, mHaveSentFinishVideo(false)
|
, mHaveSentFinishVideo(false)
|
||||||
, mStream(aStream)
|
, mStream(aOutputStreamManager.Graph()->CreateSourceStream(nullptr))
|
||||||
, mPlaying(true)
|
|
||||||
, mEOSVideoCompensation(false)
|
|
||||||
{
|
|
||||||
// DecodedStreamGraphListener will resolve this promise.
|
// DecodedStreamGraphListener will resolve this promise.
|
||||||
mListener = new DecodedStreamGraphListener(mStream, Move(aPromise));
|
, mListener(new DecodedStreamGraphListener(mStream, Move(aPromise)))
|
||||||
mStream->AddListener(mListener);
|
|
||||||
|
|
||||||
// mPlaying is initially true because MDSM won't start playback until playing
|
// mPlaying is initially true because MDSM won't start playback until playing
|
||||||
// becomes true. This is consistent with the settings of AudioSink.
|
// becomes true. This is consistent with the settings of AudioSink.
|
||||||
|
, mPlaying(true)
|
||||||
|
, mEOSVideoCompensation(false)
|
||||||
|
, mOutputStreamManager(aOutputStreamManager)
|
||||||
|
{
|
||||||
|
mStream->AddListener(mListener);
|
||||||
|
mOutputStreamManager.Connect(mStream);
|
||||||
|
|
||||||
|
// Initialize tracks.
|
||||||
|
if (aInit.mInfo.HasAudio()) {
|
||||||
|
mStream->AddAudioTrack(aInit.mInfo.mAudio.mTrackId,
|
||||||
|
aInit.mInfo.mAudio.mRate,
|
||||||
|
0, new AudioSegment());
|
||||||
|
}
|
||||||
|
if (aInit.mInfo.HasVideo()) {
|
||||||
|
mStream->AddTrack(aInit.mInfo.mVideo.mTrackId, 0, new VideoSegment());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DecodedStreamData::~DecodedStreamData()
|
DecodedStreamData::~DecodedStreamData()
|
||||||
{
|
{
|
||||||
|
mOutputStreamManager.Disconnect();
|
||||||
mListener->Forget();
|
mListener->Forget();
|
||||||
mStream->Destroy();
|
mStream->Destroy();
|
||||||
}
|
}
|
||||||
@ -377,28 +399,51 @@ DecodedStream::Start(int64_t aStartTime, const MediaInfo& aInfo)
|
|||||||
|
|
||||||
class R : public nsRunnable {
|
class R : public nsRunnable {
|
||||||
typedef MozPromiseHolder<GenericPromise> Promise;
|
typedef MozPromiseHolder<GenericPromise> Promise;
|
||||||
typedef void(DecodedStream::*Method)(Promise&&);
|
|
||||||
public:
|
public:
|
||||||
R(DecodedStream* aThis, Method aMethod, Promise&& aPromise)
|
R(PlaybackInfoInit&& aInit, Promise&& aPromise, OutputStreamManager aManager)
|
||||||
: mThis(aThis), mMethod(aMethod)
|
: mInit(Move(aInit)), mOutputStreamManager(aManager)
|
||||||
{
|
{
|
||||||
mPromise = Move(aPromise);
|
mPromise = Move(aPromise);
|
||||||
}
|
}
|
||||||
NS_IMETHOD Run() override
|
NS_IMETHOD Run() override
|
||||||
{
|
{
|
||||||
(mThis->*mMethod)(Move(mPromise));
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
// No need to create a source stream when there are no output streams. This
|
||||||
|
// happens when RemoveOutput() is called immediately after StartPlayback().
|
||||||
|
if (!mOutputStreamManager.Graph()) {
|
||||||
|
// Resolve the promise to indicate the end of playback.
|
||||||
|
mPromise.Resolve(true, __func__);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
mData = MakeUnique<DecodedStreamData>(
|
||||||
|
mOutputStreamManager, Move(mInit), Move(mPromise));
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
UniquePtr<DecodedStreamData> ReleaseData()
|
||||||
|
{
|
||||||
|
return Move(mData);
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
RefPtr<DecodedStream> mThis;
|
PlaybackInfoInit mInit;
|
||||||
Method mMethod;
|
|
||||||
Promise mPromise;
|
Promise mPromise;
|
||||||
|
OutputStreamManager mOutputStreamManager;
|
||||||
|
UniquePtr<DecodedStreamData> mData;
|
||||||
};
|
};
|
||||||
|
|
||||||
MozPromiseHolder<GenericPromise> promise;
|
MozPromiseHolder<GenericPromise> promise;
|
||||||
mFinishPromise = promise.Ensure(__func__);
|
mFinishPromise = promise.Ensure(__func__);
|
||||||
nsCOMPtr<nsIRunnable> r = new R(this, &DecodedStream::CreateData, Move(promise));
|
PlaybackInfoInit init {
|
||||||
AbstractThread::MainThread()->Dispatch(r.forget());
|
aStartTime, aInfo
|
||||||
|
};
|
||||||
|
nsCOMPtr<nsIRunnable> r = new R(Move(init), Move(promise), mOutputStreamManager);
|
||||||
|
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
|
||||||
|
SyncRunnable::DispatchToThread(mainThread, r);
|
||||||
|
mData = static_cast<R*>(r.get())->ReleaseData();
|
||||||
|
|
||||||
|
if (mData) {
|
||||||
|
mData->SetPlaying(mPlaying);
|
||||||
|
SendData();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -440,54 +485,13 @@ DecodedStream::DestroyData(UniquePtr<DecodedStreamData> aData)
|
|||||||
}
|
}
|
||||||
|
|
||||||
DecodedStreamData* data = aData.release();
|
DecodedStreamData* data = aData.release();
|
||||||
RefPtr<DecodedStream> self = this;
|
|
||||||
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([=] () {
|
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([=] () {
|
||||||
self->mOutputStreamManager.Disconnect();
|
|
||||||
delete data;
|
delete data;
|
||||||
});
|
});
|
||||||
AbstractThread::MainThread()->Dispatch(r.forget());
|
AbstractThread::MainThread()->Dispatch(r.forget());
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
DecodedStream::CreateData(MozPromiseHolder<GenericPromise>&& aPromise)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
|
|
||||||
// No need to create a source stream when there are no output streams. This
|
|
||||||
// happens when RemoveOutput() is called immediately after StartPlayback().
|
|
||||||
// Also we don't create a source stream when MDSM has begun shutdown.
|
|
||||||
if (!mOutputStreamManager.Graph() || mShuttingDown) {
|
|
||||||
// Resolve the promise to indicate the end of playback.
|
|
||||||
aPromise.Resolve(true, __func__);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto source = mOutputStreamManager.Graph()->CreateSourceStream(nullptr);
|
|
||||||
auto data = new DecodedStreamData(source, Move(aPromise));
|
|
||||||
mOutputStreamManager.Connect(data->mStream);
|
|
||||||
|
|
||||||
class R : public nsRunnable {
|
|
||||||
typedef void(DecodedStream::*Method)(UniquePtr<DecodedStreamData>);
|
|
||||||
public:
|
|
||||||
R(DecodedStream* aThis, Method aMethod, DecodedStreamData* aData)
|
|
||||||
: mThis(aThis), mMethod(aMethod), mData(aData) {}
|
|
||||||
NS_IMETHOD Run() override
|
|
||||||
{
|
|
||||||
(mThis->*mMethod)(Move(mData));
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
RefPtr<DecodedStream> mThis;
|
|
||||||
Method mMethod;
|
|
||||||
UniquePtr<DecodedStreamData> mData;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Post a message to ensure |mData| is only updated on the worker thread.
|
|
||||||
// Note this must be done before MDSM's shutdown since dispatch could fail
|
|
||||||
// when the worker thread is shut down.
|
|
||||||
nsCOMPtr<nsIRunnable> r = new R(this, &DecodedStream::OnDataCreated, data);
|
|
||||||
mOwnerThread->Dispatch(r.forget());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
DecodedStream::HasConsumers() const
|
DecodedStream::HasConsumers() const
|
||||||
@ -495,23 +499,7 @@ DecodedStream::HasConsumers() const
|
|||||||
return !mOutputStreamManager.IsEmpty();
|
return !mOutputStreamManager.IsEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
DecodedStream::OnDataCreated(UniquePtr<DecodedStreamData> aData)
|
|
||||||
{
|
|
||||||
AssertOwnerThread();
|
|
||||||
MOZ_ASSERT(!mData, "Already created.");
|
|
||||||
|
|
||||||
// Start to send data to the stream immediately
|
|
||||||
if (mStartTime.isSome()) {
|
|
||||||
aData->SetPlaying(mPlaying);
|
|
||||||
mData = Move(aData);
|
|
||||||
SendData();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Playback has ended. Destroy aData which is not needed anymore.
|
|
||||||
DestroyData(Move(aData));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
DecodedStream::AddOutput(ProcessedMediaStream* aStream, bool aFinishWhenEnded)
|
DecodedStream::AddOutput(ProcessedMediaStream* aStream, bool aFinishWhenEnded)
|
||||||
@ -569,37 +557,6 @@ DecodedStream::SetSameOrigin(bool aSameOrigin)
|
|||||||
mSameOrigin = aSameOrigin;
|
mSameOrigin = aSameOrigin;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
DecodedStream::InitTracks()
|
|
||||||
{
|
|
||||||
AssertOwnerThread();
|
|
||||||
|
|
||||||
if (mData->mStreamInitialized) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SourceMediaStream* sourceStream = mData->mStream;
|
|
||||||
|
|
||||||
if (mInfo.HasAudio()) {
|
|
||||||
TrackID audioTrackId = mInfo.mAudio.mTrackId;
|
|
||||||
AudioSegment* audio = new AudioSegment();
|
|
||||||
sourceStream->AddAudioTrack(audioTrackId, mInfo.mAudio.mRate, 0, audio,
|
|
||||||
SourceMediaStream::ADDTRACK_QUEUED);
|
|
||||||
mData->mNextAudioTime = mStartTime.ref();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mInfo.HasVideo()) {
|
|
||||||
TrackID videoTrackId = mInfo.mVideo.mTrackId;
|
|
||||||
VideoSegment* video = new VideoSegment();
|
|
||||||
sourceStream->AddTrack(videoTrackId, 0, video,
|
|
||||||
SourceMediaStream::ADDTRACK_QUEUED);
|
|
||||||
mData->mNextVideoTime = mStartTime.ref();
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceStream->FinishAddTracks();
|
|
||||||
mData->mStreamInitialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
SendStreamAudio(DecodedStreamData* aStream, int64_t aStartTime,
|
SendStreamAudio(DecodedStreamData* aStream, int64_t aStartTime,
|
||||||
MediaData* aData, AudioSegment* aOutput,
|
MediaData* aData, AudioSegment* aOutput,
|
||||||
@ -832,7 +789,6 @@ DecodedStream::SendData()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
InitTracks();
|
|
||||||
SendAudio(mParams.mVolume, mSameOrigin);
|
SendAudio(mParams.mVolume, mSameOrigin);
|
||||||
SendVideo(mSameOrigin);
|
SendVideo(mSameOrigin);
|
||||||
AdvanceTracks();
|
AdvanceTracks();
|
||||||
|
@ -27,6 +27,7 @@ class MediaInputPort;
|
|||||||
class MediaStream;
|
class MediaStream;
|
||||||
class MediaStreamGraph;
|
class MediaStreamGraph;
|
||||||
class OutputStreamManager;
|
class OutputStreamManager;
|
||||||
|
struct PlaybackInfoInit;
|
||||||
class ProcessedMediaStream;
|
class ProcessedMediaStream;
|
||||||
class TimeStamp;
|
class TimeStamp;
|
||||||
|
|
||||||
@ -131,10 +132,7 @@ protected:
|
|||||||
virtual ~DecodedStream();
|
virtual ~DecodedStream();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void CreateData(MozPromiseHolder<GenericPromise>&& aPromise);
|
|
||||||
void DestroyData(UniquePtr<DecodedStreamData> aData);
|
void DestroyData(UniquePtr<DecodedStreamData> aData);
|
||||||
void OnDataCreated(UniquePtr<DecodedStreamData> aData);
|
|
||||||
void InitTracks();
|
|
||||||
void AdvanceTracks();
|
void AdvanceTracks();
|
||||||
void SendAudio(double aVolume, bool aIsSameOrigin);
|
void SendAudio(double aVolume, bool aIsSameOrigin);
|
||||||
void SendVideo(bool aIsSameOrigin);
|
void SendVideo(bool aIsSameOrigin);
|
||||||
|
Loading…
Reference in New Issue
Block a user