Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this file,
4 : * You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #ifndef TrackEncoder_h_
7 : #define TrackEncoder_h_
8 :
9 : #include "mozilla/ReentrantMonitor.h"
10 :
11 : #include "AudioSegment.h"
12 : #include "EncodedFrameContainer.h"
13 : #include "StreamTracks.h"
14 : #include "TrackMetadataBase.h"
15 : #include "VideoSegment.h"
16 : #include "MediaStreamGraph.h"
17 :
18 : namespace mozilla {
19 :
20 : /**
21 : * Base class of AudioTrackEncoder and VideoTrackEncoder. Lifetimes managed by
22 : * MediaEncoder. Most methods can only be called on the MediaEncoder's thread,
23 : * but some subclass methods can be called on other threads when noted.
24 : *
25 : * NotifyQueuedTrackChanges is called on subclasses of this class from the
26 : * MediaStreamGraph thread, and AppendAudioSegment/AppendVideoSegment is then
27 : * called to store media data in the TrackEncoder. Later on, GetEncodedTrack is
28 : * called on MediaEncoder's thread to encode and retrieve the encoded data.
29 : */
30 : class TrackEncoder
31 : {
32 : public:
33 : TrackEncoder();
34 :
35 0 : virtual ~TrackEncoder() {}
36 :
37 : /**
38 : * Notified by the same callbcak of MediaEncoder when it has received a track
39 : * change from MediaStreamGraph. Called on the MediaStreamGraph thread.
40 : */
41 : virtual void NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, TrackID aID,
42 : StreamTime aTrackOffset,
43 : uint32_t aTrackEvents,
44 : const MediaSegment& aQueuedMedia) = 0;
45 :
46 : /**
47 : * Notified by the same callback of MediaEncoder when it has been removed from
48 : * MediaStreamGraph. Called on the MediaStreamGraph thread.
49 : */
50 : void NotifyEvent(MediaStreamGraph* aGraph,
51 : MediaStreamGraphEvent event);
52 :
53 : /**
54 : * Creates and sets up meta data for a specific codec, called on the worker
55 : * thread.
56 : */
57 : virtual already_AddRefed<TrackMetadataBase> GetMetadata() = 0;
58 :
59 : /**
60 : * Encodes raw segments. Result data is returned in aData, and called on the
61 : * worker thread.
62 : */
63 : virtual nsresult GetEncodedTrack(EncodedFrameContainer& aData) = 0;
64 :
65 : /**
66 : * True if the track encoder has encoded all source segments coming from
67 : * MediaStreamGraph. Call on the worker thread.
68 : */
69 0 : bool IsEncodingComplete() { return mEncodingComplete; }
70 :
71 : /**
72 : * Notifies from MediaEncoder to cancel the encoding, and wakes up
73 : * mReentrantMonitor if encoder is waiting on it.
74 : */
75 0 : void NotifyCancel()
76 : {
77 0 : ReentrantMonitorAutoEnter mon(mReentrantMonitor);
78 0 : mCanceled = true;
79 0 : NotifyEndOfStream();
80 0 : }
81 :
82 0 : virtual void SetBitrate(const uint32_t aBitrate) {}
83 :
84 : protected:
85 : /**
86 : * Notifies track encoder that we have reached the end of source stream, and
87 : * wakes up mReentrantMonitor if encoder is waiting for any source data.
88 : */
89 : virtual void NotifyEndOfStream() = 0;
90 :
91 : /**
92 : * A ReentrantMonitor to protect the pushing and pulling of mRawSegment which
93 : * is declared in its subclasses, and the following flags: mInitialized,
94 : * EndOfStream and mCanceled. The control of protection is managed by its
95 : * subclasses.
96 : */
97 : ReentrantMonitor mReentrantMonitor;
98 :
99 : /**
100 : * True if the track encoder has encoded all source data.
101 : */
102 : bool mEncodingComplete;
103 :
104 : /**
105 : * True if flag of EOS or any form of indicating EOS has set in the codec-
106 : * encoder.
107 : */
108 : bool mEosSetInEncoder;
109 :
110 : /**
111 : * True if the track encoder has initialized successfully, protected by
112 : * mReentrantMonitor.
113 : */
114 : bool mInitialized;
115 :
116 : /**
117 : * True if the TrackEncoder has received an event of TRACK_EVENT_ENDED from
118 : * MediaStreamGraph, or the MediaEncoder is removed from its source stream,
119 : * protected by mReentrantMonitor.
120 : */
121 : bool mEndOfStream;
122 :
123 : /**
124 : * True if a cancellation of encoding is sent from MediaEncoder, protected by
125 : * mReentrantMonitor.
126 : */
127 : bool mCanceled;
128 :
129 : // How many times we have tried to initialize the encoder.
130 : uint32_t mInitCounter;
131 : StreamTime mNotInitDuration;
132 : };
133 :
134 0 : class AudioTrackEncoder : public TrackEncoder
135 : {
136 : public:
137 0 : AudioTrackEncoder()
138 0 : : TrackEncoder()
139 : , mChannels(0)
140 : , mSamplingRate(0)
141 0 : , mAudioBitrate(0)
142 0 : {}
143 :
144 : void NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, TrackID aID,
145 : StreamTime aTrackOffset,
146 : uint32_t aTrackEvents,
147 : const MediaSegment& aQueuedMedia) override;
148 :
149 : template<typename T>
150 : static
151 0 : void InterleaveTrackData(nsTArray<const T*>& aInput,
152 : int32_t aDuration,
153 : uint32_t aOutputChannels,
154 : AudioDataValue* aOutput,
155 : float aVolume)
156 : {
157 0 : if (aInput.Length() < aOutputChannels) {
158 : // Up-mix. This might make the mChannelData have more than aChannels.
159 0 : AudioChannelsUpMix(&aInput, aOutputChannels, SilentChannel::ZeroChannel<T>());
160 : }
161 :
162 0 : if (aInput.Length() > aOutputChannels) {
163 0 : DownmixAndInterleave(aInput, aDuration,
164 : aVolume, aOutputChannels, aOutput);
165 : } else {
166 0 : InterleaveAndConvertBuffer(aInput.Elements(), aDuration, aVolume,
167 : aOutputChannels, aOutput);
168 : }
169 0 : }
170 :
171 : /**
172 : * Interleaves the track data and stores the result into aOutput. Might need
173 : * to up-mix or down-mix the channel data if the channels number of this chunk
174 : * is different from aOutputChannels. The channel data from aChunk might be
175 : * modified by up-mixing.
176 : */
177 : static void InterleaveTrackData(AudioChunk& aChunk, int32_t aDuration,
178 : uint32_t aOutputChannels,
179 : AudioDataValue* aOutput);
180 :
181 : /**
182 : * De-interleaves the aInput data and stores the result into aOutput.
183 : * No up-mix or down-mix operations inside.
184 : */
185 : static void DeInterleaveTrackData(AudioDataValue* aInput, int32_t aDuration,
186 : int32_t aChannels, AudioDataValue* aOutput);
187 : /**
188 : * Measure size of mRawSegment
189 : */
190 : size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
191 :
192 0 : void SetBitrate(const uint32_t aBitrate) override
193 : {
194 0 : mAudioBitrate = aBitrate;
195 0 : }
196 : protected:
197 : /**
198 : * Number of samples per channel in a pcm buffer. This is also the value of
199 : * frame size required by audio encoder, and mReentrantMonitor will be
200 : * notified when at least this much data has been added to mRawSegment.
201 : */
202 0 : virtual int GetPacketDuration() { return 0; }
203 :
204 : /**
205 : * Initializes the audio encoder. The call of this method is delayed until we
206 : * have received the first valid track from MediaStreamGraph, and the
207 : * mReentrantMonitor will be notified if other methods is waiting for encoder
208 : * to be completely initialized. This method is called on the MediaStreamGraph
209 : * thread.
210 : */
211 : virtual nsresult Init(int aChannels, int aSamplingRate) = 0;
212 :
213 : /**
214 : * Appends and consumes track data from aSegment, this method is called on
215 : * the MediaStreamGraph thread. mReentrantMonitor will be notified when at
216 : * least GetPacketDuration() data has been added to mRawSegment, wake up other
217 : * method which is waiting for more data from mRawSegment.
218 : */
219 : nsresult AppendAudioSegment(const AudioSegment& aSegment);
220 :
221 : /**
222 : * Notifies the audio encoder that we have reached the end of source stream,
223 : * and wakes up mReentrantMonitor if encoder is waiting for more track data.
224 : */
225 : void NotifyEndOfStream() override;
226 :
227 : /**
228 : * The number of channels are used for processing PCM data in the audio encoder.
229 : * This value comes from the first valid audio chunk. If encoder can't support
230 : * the channels in the chunk, downmix PCM stream can be performed.
231 : * This value also be used to initialize the audio encoder.
232 : */
233 : int mChannels;
234 :
235 : /**
236 : * The sampling rate of source audio data.
237 : */
238 : int mSamplingRate;
239 :
240 : /**
241 : * A segment queue of audio track data, protected by mReentrantMonitor.
242 : */
243 : AudioSegment mRawSegment;
244 :
245 : uint32_t mAudioBitrate;
246 : };
247 :
248 0 : class VideoTrackEncoder : public TrackEncoder
249 : {
250 : public:
251 0 : explicit VideoTrackEncoder(TrackRate aTrackRate)
252 0 : : TrackEncoder()
253 : , mFrameWidth(0)
254 : , mFrameHeight(0)
255 : , mDisplayWidth(0)
256 : , mDisplayHeight(0)
257 : , mTrackRate(aTrackRate)
258 : , mEncodedTicks(0)
259 0 : , mVideoBitrate(0)
260 : {
261 0 : mLastChunk.mDuration = 0;
262 0 : }
263 :
264 : /**
265 : * Notified by the same callback of MediaEncoder when it has received a track
266 : * change from MediaStreamGraph. Called on the MediaStreamGraph thread.
267 : */
268 : void NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, TrackID aID,
269 : StreamTime aTrackOffset,
270 : uint32_t aTrackEvents,
271 : const MediaSegment& aQueuedMedia) override;
272 : /**
273 : * Measure size of mRawSegment
274 : */
275 : size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
276 :
277 0 : void SetBitrate(const uint32_t aBitrate) override
278 : {
279 0 : mVideoBitrate = aBitrate;
280 0 : }
281 :
282 : void Init(const VideoSegment& aSegment);
283 :
284 : void SetCurrentFrames(const VideoSegment& aSegment);
285 :
286 : StreamTime SecondsToMediaTime(double aS) const
287 : {
288 : NS_ASSERTION(0 <= aS && aS <= TRACK_TICKS_MAX/TRACK_RATE_MAX,
289 : "Bad seconds");
290 : return mTrackRate * aS;
291 : }
292 :
293 : protected:
294 : /**
295 : * Initialized the video encoder. In order to collect the value of width and
296 : * height of source frames, this initialization is delayed until we have
297 : * received the first valid video frame from MediaStreamGraph;
298 : * mReentrantMonitor will be notified after it has successfully initialized,
299 : * and this method is called on the MediaStramGraph thread.
300 : */
301 : virtual nsresult Init(int aWidth, int aHeight, int aDisplayWidth,
302 : int aDisplayHeight) = 0;
303 :
304 : /**
305 : * Appends source video frames to mRawSegment. We only append the source chunk
306 : * if it is unique to mLastChunk. Called on the MediaStreamGraph thread.
307 : */
308 : nsresult AppendVideoSegment(const VideoSegment& aSegment);
309 :
310 : /**
311 : * Tells the video track encoder that we've reached the end of source stream,
312 : * and wakes up mReentrantMonitor if encoder is waiting for more track data.
313 : * Called on the MediaStreamGraph thread.
314 : */
315 : void NotifyEndOfStream() override;
316 :
317 : /**
318 : * The width of source video frame, ceiled if the source width is odd.
319 : */
320 : int mFrameWidth;
321 :
322 : /**
323 : * The height of source video frame, ceiled if the source height is odd.
324 : */
325 : int mFrameHeight;
326 :
327 : /**
328 : * The display width of source video frame.
329 : */
330 : int mDisplayWidth;
331 :
332 : /**
333 : * The display height of source video frame.
334 : */
335 : int mDisplayHeight;
336 :
337 : /**
338 : * The track rate of source video.
339 : */
340 : TrackRate mTrackRate;
341 :
342 : /**
343 : * The last unique frame and duration we've sent to track encoder,
344 : * kept track of in subclasses.
345 : */
346 : VideoChunk mLastChunk;
347 :
348 : /**
349 : * A segment queue of audio track data, protected by mReentrantMonitor.
350 : */
351 : VideoSegment mRawSegment;
352 :
353 : /**
354 : * The number of mTrackRate ticks we have passed to the encoder.
355 : * Only accessed in AppendVideoSegment().
356 : */
357 : StreamTime mEncodedTicks;
358 :
359 : /**
360 : * The time of the first real video frame passed to the encoder.
361 : * Only accessed in AppendVideoSegment().
362 : */
363 : TimeStamp mStartOffset;
364 :
365 : uint32_t mVideoBitrate;
366 : };
367 :
368 : } // namespace mozilla
369 :
370 : #endif
|