summaryrefslogtreecommitdiffstats
path: root/dom/media/encoder/MediaEncoder.h
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/encoder/MediaEncoder.h')
-rw-r--r--dom/media/encoder/MediaEncoder.h258
1 files changed, 258 insertions, 0 deletions
diff --git a/dom/media/encoder/MediaEncoder.h b/dom/media/encoder/MediaEncoder.h
new file mode 100644
index 000000000..41d7e71e2
--- /dev/null
+++ b/dom/media/encoder/MediaEncoder.h
@@ -0,0 +1,258 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef MediaEncoder_h_
+#define MediaEncoder_h_
+
+#include "mozilla/DebugOnly.h"
+#include "TrackEncoder.h"
+#include "ContainerWriter.h"
+#include "CubebUtils.h"
+#include "MediaStreamGraph.h"
+#include "MediaStreamListener.h"
+#include "nsAutoPtr.h"
+#include "MediaStreamVideoSink.h"
+#include "nsIMemoryReporter.h"
+#include "mozilla/MemoryReporting.h"
+#include "mozilla/Atomics.h"
+
+namespace mozilla {
+
+class MediaStreamVideoRecorderSink : public MediaStreamVideoSink
+{
+public:
+ explicit MediaStreamVideoRecorderSink(VideoTrackEncoder* aEncoder)
+ : mVideoEncoder(aEncoder) {}
+
+ // MediaStreamVideoSink methods
+ virtual void SetCurrentFrames(const VideoSegment& aSegment) override;
+ virtual void ClearFrames() override {}
+
+private:
+ virtual ~MediaStreamVideoRecorderSink() {}
+ VideoTrackEncoder* mVideoEncoder;
+};
+
+/**
+ * MediaEncoder is the framework of encoding module, it controls and manages
+ * procedures between ContainerWriter and TrackEncoder. ContainerWriter packs
+ * the encoded track data with a specific container (e.g. ogg, mp4).
+ * AudioTrackEncoder and VideoTrackEncoder are subclasses of TrackEncoder, and
+ * are responsible for encoding raw data coming from MediaStreamGraph.
+ *
+ * Also, MediaEncoder is a type of MediaStreamListener, it starts to receive raw
+ * segments after itself is added to the source stream. In the mean time,
+ * encoded track data is pulled by its owner periodically on a worker thread. A
+ * reentrant monitor is used to protect the push and pull of resource.
+ *
+ * MediaEncoder is designed to be a passive component, neither it owns nor in
+ * charge of managing threads. However, a monitor is used in function
+ * TrackEncoder::GetEncodedTrack() for the purpose of thread safety (e.g.
+ * between callbacks of MediaStreamListener and others), a call to this function
+ * might block. Therefore, MediaEncoder should not run on threads that forbid
+ * blocking, such as main thread or I/O thread.
+ *
+ * For example, an usage from MediaRecorder of this component would be:
+ * 1) Create an encoder with a valid MIME type.
+ * => encoder = MediaEncoder::CreateEncoder(aMIMEType);
+ * It then generate a ContainerWriter according to the MIME type, and an
+ * AudioTrackEncoder (or a VideoTrackEncoder too) associated with the media
+ * type.
+ *
+ * 2) Dispatch the task GetEncodedData() to a worker thread.
+ *
+ * 3) To start encoding, add this component to its source stream.
+ * => sourceStream->AddListener(encoder);
+ *
+ * 4) To stop encoding, remove this component from its source stream.
+ * => sourceStream->RemoveListener(encoder);
+ */
+class MediaEncoder : public DirectMediaStreamListener
+{
+ friend class MediaStreamVideoRecorderSink;
+public :
+ enum {
+ ENCODE_METADDATA,
+ ENCODE_TRACK,
+ ENCODE_DONE,
+ ENCODE_ERROR,
+ };
+
+ MediaEncoder(ContainerWriter* aWriter,
+ AudioTrackEncoder* aAudioEncoder,
+ VideoTrackEncoder* aVideoEncoder,
+ const nsAString& aMIMEType,
+ uint32_t aAudioBitrate,
+ uint32_t aVideoBitrate,
+ uint32_t aBitrate)
+ : mWriter(aWriter)
+ , mAudioEncoder(aAudioEncoder)
+ , mVideoEncoder(aVideoEncoder)
+ , mVideoSink(new MediaStreamVideoRecorderSink(mVideoEncoder))
+ , mStartTime(TimeStamp::Now())
+ , mMIMEType(aMIMEType)
+ , mSizeOfBuffer(0)
+ , mState(MediaEncoder::ENCODE_METADDATA)
+ , mShutdown(false)
+ , mDirectConnected(false)
+ , mSuspended(false)
+{}
+
+ ~MediaEncoder() {};
+
+ enum SuspendState {
+ RECORD_NOT_SUSPENDED,
+ RECORD_SUSPENDED,
+ RECORD_RESUMED
+ };
+
+ /* Note - called from control code, not on MSG threads. */
+ void Suspend()
+ {
+ mSuspended = RECORD_SUSPENDED;
+ }
+
+ /**
+ * Note - called from control code, not on MSG threads.
+ * Arm to collect the Duration of the next video frame and give it
+ * to the next frame, in order to avoid any possible loss of sync. */
+ void Resume()
+ {
+ if (mSuspended == RECORD_SUSPENDED) {
+ mSuspended = RECORD_RESUMED;
+ }
+ }
+
+ /**
+ * Tells us which Notify to pay attention to for media
+ */
+ void SetDirectConnect(bool aConnected);
+
+ /**
+ * Notified by the AppendToTrack in MediaStreamGraph; aRealtimeMedia is the raw
+ * track data in form of MediaSegment.
+ */
+ void NotifyRealtimeData(MediaStreamGraph* aGraph, TrackID aID,
+ StreamTime aTrackOffset,
+ uint32_t aTrackEvents,
+ const MediaSegment& aRealtimeMedia) override;
+
+ /**
+ * Notified by the control loop of MediaStreamGraph; aQueueMedia is the raw
+ * track data in form of MediaSegment.
+ */
+ void NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, TrackID aID,
+ StreamTime aTrackOffset,
+ TrackEventCommand aTrackEvents,
+ const MediaSegment& aQueuedMedia,
+ MediaStream* aInputStream,
+ TrackID aInputTrackID) override;
+
+ /**
+ * Notifed by the control loop of MediaStreamGraph; aQueueMedia is the audio
+ * data in the form of an AudioSegment.
+ */
+ void NotifyQueuedAudioData(MediaStreamGraph* aGraph, TrackID aID,
+ StreamTime aTrackOffset,
+ const AudioSegment& aQueuedMedia,
+ MediaStream* aInputStream,
+ TrackID aInputTrackID) override;
+
+ /**
+ * * Notified the stream is being removed.
+ */
+ void NotifyEvent(MediaStreamGraph* aGraph,
+ MediaStreamGraphEvent event) override;
+
+ /**
+ * Creates an encoder with a given MIME type. Returns null if we are unable
+ * to create the encoder. For now, default aMIMEType to "audio/ogg" and use
+ * Ogg+Opus if it is empty.
+ */
+ static already_AddRefed<MediaEncoder> CreateEncoder(const nsAString& aMIMEType,
+ uint32_t aAudioBitrate, uint32_t aVideoBitrate,
+ uint32_t aBitrate,
+ uint8_t aTrackTypes = ContainerWriter::CREATE_AUDIO_TRACK,
+ TrackRate aTrackRate = CubebUtils::PreferredSampleRate());
+ /**
+ * Encodes the raw track data and returns the final container data. Assuming
+ * it is called on a single worker thread. The buffer of container data is
+ * allocated in ContainerWriter::GetContainerData(), and is appended to
+ * aOutputBufs. aMIMEType is the valid mime-type of this returned container
+ * data.
+ */
+ void GetEncodedData(nsTArray<nsTArray<uint8_t> >* aOutputBufs,
+ nsAString& aMIMEType);
+
+ /**
+ * Return true if MediaEncoder has been shutdown. Reasons are encoding
+ * complete, encounter an error, or being canceled by its caller.
+ */
+ bool IsShutdown()
+ {
+ return mShutdown;
+ }
+
+ /**
+ * Cancel the encoding, and wakes up the lock of reentrant monitor in encoder.
+ */
+ void Cancel()
+ {
+ if (mAudioEncoder) {
+ mAudioEncoder->NotifyCancel();
+ }
+ if (mVideoEncoder) {
+ mVideoEncoder->NotifyCancel();
+ }
+ }
+
+ bool HasError()
+ {
+ return mState == ENCODE_ERROR;
+ }
+
+#ifdef MOZ_WEBM_ENCODER
+ static bool IsWebMEncoderEnabled();
+#endif
+
+ MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
+ /*
+ * Measure the size of the buffer, and memory occupied by mAudioEncoder
+ * and mVideoEncoder
+ */
+ size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
+
+ MediaStreamVideoRecorderSink* GetVideoSink() {
+ return mVideoSink.get();
+ }
+
+private:
+ // Get encoded data from trackEncoder and write to muxer
+ nsresult WriteEncodedDataToMuxer(TrackEncoder *aTrackEncoder);
+ // Get metadata from trackEncoder and copy to muxer
+ nsresult CopyMetadataToMuxer(TrackEncoder* aTrackEncoder);
+ nsAutoPtr<ContainerWriter> mWriter;
+ nsAutoPtr<AudioTrackEncoder> mAudioEncoder;
+ nsAutoPtr<VideoTrackEncoder> mVideoEncoder;
+ RefPtr<MediaStreamVideoRecorderSink> mVideoSink;
+ TimeStamp mStartTime;
+ nsString mMIMEType;
+ int64_t mSizeOfBuffer;
+ int mState;
+ bool mShutdown;
+ bool mDirectConnected;
+ Atomic<int> mSuspended;
+ // Get duration from create encoder, for logging purpose
+ double GetEncodeTimeStamp()
+ {
+ TimeDuration decodeTime;
+ decodeTime = TimeStamp::Now() - mStartTime;
+ return decodeTime.ToMilliseconds();
+ }
+};
+
+} // namespace mozilla
+
+#endif