зеркало из https://github.com/mozilla/gecko-dev.git
Bug 879669 - Part 3: Start recording when tracks have been added. r=roc
This commit is contained in:
Родитель
f64409a83b
Коммит
87ed7d5945
|
@ -17,12 +17,16 @@
|
|||
#include "nsIDOMFile.h"
|
||||
#include "mozilla/dom/BlobEvent.h"
|
||||
|
||||
|
||||
#include "mozilla/dom/AudioStreamTrack.h"
|
||||
#include "mozilla/dom/VideoStreamTrack.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED_1(MediaRecorder, nsDOMEventTargetHelper,
|
||||
mStream)
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED_2(MediaRecorder, nsDOMEventTargetHelper,
|
||||
mStream, mSession)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MediaRecorder)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
|
||||
|
@ -45,7 +49,7 @@ NS_IMPL_RELEASE_INHERITED(MediaRecorder, nsDOMEventTargetHelper)
|
|||
*
|
||||
* Life cycle of a Session object.
|
||||
* 1) Initialization Stage (in main thread)
|
||||
* Setup media streams in MSG, and bind MediaEncoder with Source Stream.
|
||||
* Setup media streams in MSG, and bind MediaEncoder with Source Stream when mStream is available.
|
||||
* Resource allocation, such as encoded data cache buffer and MediaEncoder.
|
||||
* Create read thread.
|
||||
* Automatically switch to Extract stage in the end of this stage.
|
||||
|
@ -90,7 +94,7 @@ class MediaRecorder::Session: public nsIObserver
|
|||
}
|
||||
|
||||
private:
|
||||
Session *mSession;
|
||||
nsRefPtr<Session> mSession;
|
||||
};
|
||||
|
||||
// Record thread task.
|
||||
|
@ -110,7 +114,36 @@ class MediaRecorder::Session: public nsIObserver
|
|||
}
|
||||
|
||||
private:
|
||||
Session *mSession;
|
||||
nsRefPtr<Session> mSession;
|
||||
};
|
||||
|
||||
// For Ensure recorder has tracks to record.
|
||||
class TracksAvailableCallback : public DOMMediaStream::OnTracksAvailableCallback
|
||||
{
|
||||
public:
|
||||
TracksAvailableCallback(Session *aSession)
|
||||
: mSession(aSession) {}
|
||||
virtual void NotifyTracksAvailable(DOMMediaStream* aStream)
|
||||
{
|
||||
uint8_t trackType = aStream->GetHintContents();
|
||||
// ToDo: GetHintContents return 0 when recording media tags.
|
||||
if (trackType == 0) {
|
||||
nsTArray<nsRefPtr<mozilla::dom::AudioStreamTrack> > audioTracks;
|
||||
aStream->GetAudioTracks(audioTracks);
|
||||
nsTArray<nsRefPtr<mozilla::dom::VideoStreamTrack> > videoTracks;
|
||||
aStream->GetVideoTracks(videoTracks);
|
||||
// What is inside the track
|
||||
if (videoTracks.Length() > 0) {
|
||||
trackType |= DOMMediaStream::HINT_CONTENTS_VIDEO;
|
||||
}
|
||||
if (audioTracks.Length() > 0) {
|
||||
trackType |= DOMMediaStream::HINT_CONTENTS_AUDIO;
|
||||
}
|
||||
}
|
||||
mSession->AfterTracksAdded(trackType);
|
||||
}
|
||||
private:
|
||||
nsRefPtr<Session> mSession;
|
||||
};
|
||||
|
||||
// Main thread task.
|
||||
|
@ -154,6 +187,7 @@ class MediaRecorder::Session: public nsIObserver
|
|||
friend class PushBlobRunnable;
|
||||
friend class ExtractRunnable;
|
||||
friend class DestroyRunnable;
|
||||
friend class TracksAvailableCallback;
|
||||
|
||||
public:
|
||||
Session(MediaRecorder* aRecorder, int32_t aTimeSlice)
|
||||
|
@ -169,8 +203,6 @@ public:
|
|||
// Only DestroyRunnable is allowed to delete Session object.
|
||||
virtual ~Session()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
CleanupStreams();
|
||||
}
|
||||
|
||||
|
@ -179,22 +211,6 @@ public:
|
|||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
SetupStreams();
|
||||
|
||||
// Create a thread to read encode media data from MediaEncoder.
|
||||
if (!mReadThread) {
|
||||
nsresult rv = NS_NewNamedThread("Media Encoder", getter_AddRefs(mReadThread));
|
||||
if (NS_FAILED(rv)) {
|
||||
CleanupStreams();
|
||||
mRecorder->NotifyError(rv);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// In case source media stream does not notify track end, recieve
|
||||
// shutdown notification and stop Read Thread.
|
||||
nsContentUtils::RegisterShutdownObserver(this);
|
||||
|
||||
mReadThread->Dispatch(new ExtractRunnable(this), NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
void Stop()
|
||||
|
@ -290,14 +306,57 @@ private:
|
|||
mInputPort = mTrackUnionStream->AllocateInputPort(mRecorder->mStream->GetStream(), MediaInputPort::FLAG_BLOCK_OUTPUT);
|
||||
|
||||
// Allocate encoder and bind with the Track Union Stream.
|
||||
mEncoder = MediaEncoder::CreateEncoder(NS_LITERAL_STRING(""));
|
||||
MOZ_ASSERT(mEncoder, "CreateEncoder failed");
|
||||
|
||||
if (mEncoder) {
|
||||
mTrackUnionStream->AddListener(mEncoder);
|
||||
}
|
||||
TracksAvailableCallback* tracksAvailableCallback = new TracksAvailableCallback(mRecorder->mSession);
|
||||
mRecorder->mStream->OnTracksAvailable(tracksAvailableCallback);
|
||||
}
|
||||
|
||||
void AfterTracksAdded(uint8_t aTrackTypes)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// Allocate encoder and bind with union stream.
|
||||
// At this stage, the API doesn't allow UA to choose the output mimeType format.
|
||||
mEncoder = MediaEncoder::CreateEncoder(NS_LITERAL_STRING(""), aTrackTypes);
|
||||
|
||||
if (!mEncoder) {
|
||||
DoSessionEndTask(NS_ERROR_ABORT);
|
||||
return;
|
||||
}
|
||||
|
||||
// media stream is ready but has been issued stop command
|
||||
if (mRecorder->mState == RecordingState::Inactive) {
|
||||
DoSessionEndTask(NS_OK);
|
||||
return;
|
||||
}
|
||||
mTrackUnionStream->AddListener(mEncoder);
|
||||
// Create a thread to read encode media data from MediaEncoder.
|
||||
if (!mReadThread) {
|
||||
nsresult rv = NS_NewNamedThread("Media Encoder", getter_AddRefs(mReadThread));
|
||||
if (NS_FAILED(rv)) {
|
||||
DoSessionEndTask(rv);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// In case source media stream does not notify track end, recieve
|
||||
// shutdown notification and stop Read Thread.
|
||||
nsContentUtils::RegisterShutdownObserver(this);
|
||||
|
||||
mReadThread->Dispatch(new ExtractRunnable(this), NS_DISPATCH_NORMAL);
|
||||
}
|
||||
// application should get blob and onstop event
|
||||
void DoSessionEndTask(nsresult rv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
mRecorder->NotifyError(rv);
|
||||
}
|
||||
CleanupStreams();
|
||||
// Destroy this session object in main thread.
|
||||
NS_DispatchToMainThread(new PushBlobRunnable(this));
|
||||
NS_DispatchToMainThread(new DestroyRunnable(already_AddRefed<Session>(this)));
|
||||
}
|
||||
void CleanupStreams()
|
||||
{
|
||||
if (mInputPort.get()) {
|
||||
|
@ -430,11 +489,10 @@ MediaRecorder::Stop(ErrorResult& aResult)
|
|||
aResult.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
mState = RecordingState::Inactive;
|
||||
|
||||
mSession->Stop();
|
||||
mSession = nullptr;
|
||||
|
||||
mState = RecordingState::Inactive;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -104,7 +104,7 @@ protected:
|
|||
// The current state of the MediaRecorder object.
|
||||
RecordingState mState;
|
||||
// Current recording session.
|
||||
Session *mSession;
|
||||
nsRefPtr<Session> mSession;
|
||||
// Thread safe for mMimeType.
|
||||
Mutex mMutex;
|
||||
// It specifies the container format as well as the audio and video capture formats.
|
||||
|
|
Загрузка…
Ссылка в новой задаче