summaryrefslogtreecommitdiffstats
path: root/dom/media/encoder/TrackEncoder.h
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/encoder/TrackEncoder.h')
-rw-r--r--dom/media/encoder/TrackEncoder.h364
1 files changed, 364 insertions, 0 deletions
diff --git a/dom/media/encoder/TrackEncoder.h b/dom/media/encoder/TrackEncoder.h
new file mode 100644
index 000000000..33f20e899
--- /dev/null
+++ b/dom/media/encoder/TrackEncoder.h
@@ -0,0 +1,364 @@
+/* -*- 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 TrackEncoder_h_
+#define TrackEncoder_h_
+
+#include "mozilla/ReentrantMonitor.h"
+
+#include "AudioSegment.h"
+#include "EncodedFrameContainer.h"
+#include "StreamTracks.h"
+#include "TrackMetadataBase.h"
+#include "VideoSegment.h"
+#include "MediaStreamGraph.h"
+
+namespace mozilla {
+
+/**
+ * Base class of AudioTrackEncoder and VideoTrackEncoder. Lifetimes managed by
+ * MediaEncoder. Most methods can only be called on the MediaEncoder's thread,
+ * but some subclass methods can be called on other threads when noted.
+ *
+ * NotifyQueuedTrackChanges is called on subclasses of this class from the
+ * MediaStreamGraph thread, and AppendAudioSegment/AppendVideoSegment is then
+ * called to store media data in the TrackEncoder. Later on, GetEncodedTrack is
+ * called on MediaEncoder's thread to encode and retrieve the encoded data.
+ */
+class TrackEncoder
+{
+public:
+ TrackEncoder();
+
+ virtual ~TrackEncoder() {}
+
+ /**
+ * Notified by the same callbcak of MediaEncoder when it has received a track
+ * change from MediaStreamGraph. Called on the MediaStreamGraph thread.
+ */
+ virtual void NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, TrackID aID,
+ StreamTime aTrackOffset,
+ uint32_t aTrackEvents,
+ const MediaSegment& aQueuedMedia) = 0;
+
+ /**
+ * Notified by the same callback of MediaEncoder when it has been removed from
+ * MediaStreamGraph. Called on the MediaStreamGraph thread.
+ */
+ void NotifyEvent(MediaStreamGraph* aGraph,
+ MediaStreamGraphEvent event);
+
+ /**
+ * Creates and sets up meta data for a specific codec, called on the worker
+ * thread.
+ */
+ virtual already_AddRefed<TrackMetadataBase> GetMetadata() = 0;
+
+ /**
+ * Encodes raw segments. Result data is returned in aData, and called on the
+ * worker thread.
+ */
+ virtual nsresult GetEncodedTrack(EncodedFrameContainer& aData) = 0;
+
+ /**
+ * True if the track encoder has encoded all source segments coming from
+ * MediaStreamGraph. Call on the worker thread.
+ */
+ bool IsEncodingComplete() { return mEncodingComplete; }
+
+ /**
+ * Notifies from MediaEncoder to cancel the encoding, and wakes up
+ * mReentrantMonitor if encoder is waiting on it.
+ */
+ void NotifyCancel()
+ {
+ ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+ mCanceled = true;
+ mReentrantMonitor.NotifyAll();
+ }
+
+ virtual void SetBitrate(const uint32_t aBitrate) {}
+
+protected:
+ /**
+ * Notifies track encoder that we have reached the end of source stream, and
+ * wakes up mReentrantMonitor if encoder is waiting for any source data.
+ */
+ virtual void NotifyEndOfStream() = 0;
+
+ /**
+ * A ReentrantMonitor to protect the pushing and pulling of mRawSegment which
+ * is declared in its subclasses, and the following flags: mInitialized,
+ * EndOfStream and mCanceled. The control of protection is managed by its
+ * subclasses.
+ */
+ ReentrantMonitor mReentrantMonitor;
+
+ /**
+ * True if the track encoder has encoded all source data.
+ */
+ bool mEncodingComplete;
+
+ /**
+ * True if flag of EOS or any form of indicating EOS has set in the codec-
+ * encoder.
+ */
+ bool mEosSetInEncoder;
+
+ /**
+ * True if the track encoder has initialized successfully, protected by
+ * mReentrantMonitor.
+ */
+ bool mInitialized;
+
+ /**
+ * True if the TrackEncoder has received an event of TRACK_EVENT_ENDED from
+ * MediaStreamGraph, or the MediaEncoder is removed from its source stream,
+ * protected by mReentrantMonitor.
+ */
+ bool mEndOfStream;
+
+ /**
+ * True if a cancellation of encoding is sent from MediaEncoder, protected by
+ * mReentrantMonitor.
+ */
+ bool mCanceled;
+
+ // How many times we have tried to initialize the encoder.
+ uint32_t mInitCounter;
+ StreamTime mNotInitDuration;
+};
+
+class AudioTrackEncoder : public TrackEncoder
+{
+public:
+ AudioTrackEncoder()
+ : TrackEncoder()
+ , mChannels(0)
+ , mSamplingRate(0)
+ , mAudioBitrate(0)
+ {}
+
+ void NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, TrackID aID,
+ StreamTime aTrackOffset,
+ uint32_t aTrackEvents,
+ const MediaSegment& aQueuedMedia) override;
+
+ template<typename T>
+ static
+ void InterleaveTrackData(nsTArray<const T*>& aInput,
+ int32_t aDuration,
+ uint32_t aOutputChannels,
+ AudioDataValue* aOutput,
+ float aVolume)
+ {
+ if (aInput.Length() < aOutputChannels) {
+ // Up-mix. This might make the mChannelData have more than aChannels.
+ AudioChannelsUpMix(&aInput, aOutputChannels, SilentChannel::ZeroChannel<T>());
+ }
+
+ if (aInput.Length() > aOutputChannels) {
+ DownmixAndInterleave(aInput, aDuration,
+ aVolume, aOutputChannels, aOutput);
+ } else {
+ InterleaveAndConvertBuffer(aInput.Elements(), aDuration, aVolume,
+ aOutputChannels, aOutput);
+ }
+ }
+
+ /**
+ * Interleaves the track data and stores the result into aOutput. Might need
+ * to up-mix or down-mix the channel data if the channels number of this chunk
+ * is different from aOutputChannels. The channel data from aChunk might be
+ * modified by up-mixing.
+ */
+ static void InterleaveTrackData(AudioChunk& aChunk, int32_t aDuration,
+ uint32_t aOutputChannels,
+ AudioDataValue* aOutput);
+
+ /**
+ * De-interleaves the aInput data and stores the result into aOutput.
+ * No up-mix or down-mix operations inside.
+ */
+ static void DeInterleaveTrackData(AudioDataValue* aInput, int32_t aDuration,
+ int32_t aChannels, AudioDataValue* aOutput);
+ /**
+ * Measure size of mRawSegment
+ */
+ size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
+
+ void SetBitrate(const uint32_t aBitrate) override
+ {
+ mAudioBitrate = aBitrate;
+ }
+protected:
+ /**
+ * Number of samples per channel in a pcm buffer. This is also the value of
+ * frame size required by audio encoder, and mReentrantMonitor will be
+ * notified when at least this much data has been added to mRawSegment.
+ */
+ virtual int GetPacketDuration() { return 0; }
+
+ /**
+ * Initializes the audio encoder. The call of this method is delayed until we
+ * have received the first valid track from MediaStreamGraph, and the
+ * mReentrantMonitor will be notified if other methods is waiting for encoder
+ * to be completely initialized. This method is called on the MediaStreamGraph
+ * thread.
+ */
+ virtual nsresult Init(int aChannels, int aSamplingRate) = 0;
+
+ /**
+ * Appends and consumes track data from aSegment, this method is called on
+ * the MediaStreamGraph thread. mReentrantMonitor will be notified when at
+ * least GetPacketDuration() data has been added to mRawSegment, wake up other
+ * method which is waiting for more data from mRawSegment.
+ */
+ nsresult AppendAudioSegment(const AudioSegment& aSegment);
+
+ /**
+ * Notifies the audio encoder that we have reached the end of source stream,
+ * and wakes up mReentrantMonitor if encoder is waiting for more track data.
+ */
+ void NotifyEndOfStream() override;
+
+ /**
+ * The number of channels are used for processing PCM data in the audio encoder.
+ * This value comes from the first valid audio chunk. If encoder can't support
+ * the channels in the chunk, downmix PCM stream can be performed.
+ * This value also be used to initialize the audio encoder.
+ */
+ int mChannels;
+
+ /**
+ * The sampling rate of source audio data.
+ */
+ int mSamplingRate;
+
+ /**
+ * A segment queue of audio track data, protected by mReentrantMonitor.
+ */
+ AudioSegment mRawSegment;
+
+ uint32_t mAudioBitrate;
+};
+
+class VideoTrackEncoder : public TrackEncoder
+{
+public:
+ explicit VideoTrackEncoder(TrackRate aTrackRate)
+ : TrackEncoder()
+ , mFrameWidth(0)
+ , mFrameHeight(0)
+ , mDisplayWidth(0)
+ , mDisplayHeight(0)
+ , mTrackRate(aTrackRate)
+ , mTotalFrameDuration(0)
+ , mLastFrameDuration(0)
+ , mVideoBitrate(0)
+ {}
+
+ /**
+ * Notified by the same callback of MediaEncoder when it has received a track
+ * change from MediaStreamGraph. Called on the MediaStreamGraph thread.
+ */
+ void NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, TrackID aID,
+ StreamTime aTrackOffset,
+ uint32_t aTrackEvents,
+ const MediaSegment& aQueuedMedia) override;
+ /**
+ * Measure size of mRawSegment
+ */
+ size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
+
+ void SetBitrate(const uint32_t aBitrate) override
+ {
+ mVideoBitrate = aBitrate;
+ }
+
+ void Init(const VideoSegment& aSegment);
+
+ void SetCurrentFrames(const VideoSegment& aSegment);
+
+ StreamTime SecondsToMediaTime(double aS) const
+ {
+ NS_ASSERTION(0 <= aS && aS <= TRACK_TICKS_MAX/TRACK_RATE_MAX,
+ "Bad seconds");
+ return mTrackRate * aS;
+ }
+
+protected:
+ /**
+ * Initialized the video encoder. In order to collect the value of width and
+ * height of source frames, this initialization is delayed until we have
+ * received the first valid video frame from MediaStreamGraph;
+ * mReentrantMonitor will be notified after it has successfully initialized,
+ * and this method is called on the MediaStramGraph thread.
+ */
+ virtual nsresult Init(int aWidth, int aHeight, int aDisplayWidth,
+ int aDisplayHeight) = 0;
+
+ /**
+ * Appends source video frames to mRawSegment. We only append the source chunk
+ * if it is unique to mLastChunk. Called on the MediaStreamGraph thread.
+ */
+ nsresult AppendVideoSegment(const VideoSegment& aSegment);
+
+ /**
+ * Tells the video track encoder that we've reached the end of source stream,
+ * and wakes up mReentrantMonitor if encoder is waiting for more track data.
+ * Called on the MediaStreamGraph thread.
+ */
+ void NotifyEndOfStream() override;
+
+ /**
+ * The width of source video frame, ceiled if the source width is odd.
+ */
+ int mFrameWidth;
+
+ /**
+ * The height of source video frame, ceiled if the source height is odd.
+ */
+ int mFrameHeight;
+
+ /**
+ * The display width of source video frame.
+ */
+ int mDisplayWidth;
+
+ /**
+ * The display height of source video frame.
+ */
+ int mDisplayHeight;
+
+ /**
+ * The track rate of source video.
+ */
+ TrackRate mTrackRate;
+
+ /**
+ * The total duration of frames in encoded video in StreamTime, kept track of
+ * in subclasses.
+ */
+ StreamTime mTotalFrameDuration;
+
+ /**
+ * The last unique frame and duration we've sent to track encoder,
+ * kept track of in subclasses.
+ */
+ VideoFrame mLastFrame;
+ StreamTime mLastFrameDuration;
+
+ /**
+ * A segment queue of audio track data, protected by mReentrantMonitor.
+ */
+ VideoSegment mRawSegment;
+
+ uint32_t mVideoBitrate;
+};
+
+} // namespace mozilla
+
+#endif