Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/media/encoder/MediaEncoder.h
Line
Count
Source (jump to first uncovered line)
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 MediaEncoder_h_
7
#define MediaEncoder_h_
8
9
#include "ContainerWriter.h"
10
#include "CubebUtils.h"
11
#include "MediaStreamGraph.h"
12
#include "MediaStreamListener.h"
13
#include "mozilla/DebugOnly.h"
14
#include "mozilla/MemoryReporting.h"
15
#include "mozilla/UniquePtr.h"
16
#include "nsIMemoryReporter.h"
17
#include "TrackEncoder.h"
18
19
namespace mozilla {
20
21
class TaskQueue;
22
23
namespace dom {
24
class AudioNode;
25
class AudioStreamTrack;
26
class MediaStreamTrack;
27
class VideoStreamTrack;
28
}
29
30
class MediaEncoder;
31
32
class MediaEncoderListener
33
{
34
public:
35
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaEncoderListener)
36
  virtual void Initialized() = 0;
37
  virtual void DataAvailable() = 0;
38
  virtual void Error() = 0;
39
  virtual void Shutdown() = 0;
40
protected:
41
  virtual ~MediaEncoderListener() {}
42
};
43
44
/**
45
 * MediaEncoder is the framework of encoding module, it controls and manages
46
 * procedures between ContainerWriter and TrackEncoder. ContainerWriter packs
47
 * the encoded track data with a specific container (e.g. ogg, webm).
48
 * AudioTrackEncoder and VideoTrackEncoder are subclasses of TrackEncoder, and
49
 * are responsible for encoding raw data coming from MediaStreamGraph.
50
 *
51
 * MediaEncoder solves threading issues by doing message passing to a TaskQueue
52
 * (the "encoder thread") as passed in to the constructor. Each
53
 * MediaStreamTrack to be recorded is set up with a MediaStreamTrackListener.
54
 * Typically there are a non-direct track listeners for audio, direct listeners
55
 * for video, and there is always a non-direct listener on each track for
56
 * time-keeping. The listeners forward data to their corresponding TrackEncoders
57
 * on the encoder thread.
58
 *
59
 * The MediaEncoder listens to events from all TrackEncoders, and in turn
60
 * signals events to interested parties. Typically a MediaRecorder::Session.
61
 * The event that there's data available in the TrackEncoders is what typically
62
 * drives the extraction and muxing of data.
63
 *
64
 * MediaEncoder is designed to be a passive component, neither does it own or is
65
 * in charge of managing threads. Instead this is done by its owner.
66
 *
67
 * For example, usage from MediaRecorder of this component would be:
68
 * 1) Create an encoder with a valid MIME type.
69
 *    => encoder = MediaEncoder::CreateEncoder(aMIMEType);
70
 *    It then creates a ContainerWriter according to the MIME type
71
 *
72
 * 2) Connect a MediaEncoderListener to be notified when the MediaEncoder has
73
 *    been initialized and when there's data available.
74
 *    => encoder->RegisterListener(listener);
75
 *
76
 * 3) Connect the MediaStreamTracks to be recorded.
77
 *    => encoder->ConnectMediaStreamTrack(track);
78
 *    This creates the corresponding TrackEncoder and connects the track and
79
 *    the TrackEncoder through a track listener. This also starts encoding.
80
 *
81
 * 4) When the MediaEncoderListener is notified that the MediaEncoder is
82
 *    initialized, we can encode metadata.
83
 *    => encoder->GetEncodedMetadata(...);
84
 *
85
 * 5) When the MediaEncoderListener is notified that the MediaEncoder has
86
 *    data available, we can encode data.
87
 *    => encoder->GetEncodedData(...);
88
 *
89
 * 6) To stop encoding, there are multiple options:
90
 *
91
 *    6.1) Stop() for a graceful stop.
92
 *         => encoder->Stop();
93
 *
94
 *    6.2) Cancel() for an immediate stop, if you don't need the data currently
95
 *         buffered.
96
 *         => encoder->Cancel();
97
 *
98
 *    6.3) When all input tracks end, the MediaEncoder will automatically stop
99
 *         and shut down.
100
 */
101
class MediaEncoder
102
{
103
private:
104
  class AudioTrackListener;
105
  class VideoTrackListener;
106
  class EncoderListener;
107
108
public :
109
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaEncoder)
110
111
  MediaEncoder(TaskQueue* aEncoderThread,
112
               UniquePtr<ContainerWriter> aWriter,
113
               AudioTrackEncoder* aAudioEncoder,
114
               VideoTrackEncoder* aVideoEncoder,
115
               const nsAString& aMIMEType);
116
117
  /* Note - called from control code, not on MSG threads. */
118
  void Suspend(TimeStamp aTime);
119
120
  /**
121
   * Note - called from control code, not on MSG threads.
122
   * Calculates time spent paused in order to offset frames. */
123
  void Resume(TimeStamp aTime);
124
125
  /**
126
   * Stops the current encoding, and disconnects the input tracks.
127
   */
128
  void Stop();
129
130
  /**
131
   * Connects an AudioNode with the appropriate encoder.
132
   */
133
  void ConnectAudioNode(dom::AudioNode* aNode, uint32_t aOutput);
134
135
  /**
136
   * Connects a MediaStreamTrack with the appropriate encoder.
137
   */
138
  void ConnectMediaStreamTrack(dom::MediaStreamTrack* aTrack);
139
140
  /**
141
   * Removes a connected MediaStreamTrack.
142
   */
143
  void RemoveMediaStreamTrack(dom::MediaStreamTrack* aTrack);
144
145
  /**
146
   * Creates an encoder with a given MIME type. Returns null if we are unable
147
   * to create the encoder. For now, default aMIMEType to "audio/ogg" and use
148
   * Ogg+Opus if it is empty.
149
   */
150
  static already_AddRefed<MediaEncoder>
151
  CreateEncoder(TaskQueue* aEncoderThread,
152
                const nsAString& aMIMEType,
153
                uint32_t aAudioBitrate,
154
                uint32_t aVideoBitrate,
155
                uint8_t aTrackTypes,
156
                TrackRate aTrackRate);
157
158
  /**
159
   * Encodes raw metadata for all tracks to aOutputBufs. aMIMEType is the valid
160
   * mime-type for the returned container data. The buffer of container data is
161
   * allocated in ContainerWriter::GetContainerData().
162
   *
163
   * Should there be insufficient input data for either track encoder to infer
164
   * the metadata, or if metadata has already been encoded, we return an error
165
   * and the output arguments are undefined. Otherwise we return NS_OK.
166
   */
167
  nsresult GetEncodedMetadata(nsTArray<nsTArray<uint8_t> >* aOutputBufs,
168
                              nsAString& aMIMEType);
169
  /**
170
   * Encodes raw data for all tracks to aOutputBufs. The buffer of container
171
   * data is allocated in ContainerWriter::GetContainerData().
172
   *
173
   * This implies that metadata has already been encoded and that all track
174
   * encoders are still active. Should either implication break, we return an
175
   * error and the output argument is undefined. Otherwise we return NS_OK.
176
   */
177
  nsresult GetEncodedData(nsTArray<nsTArray<uint8_t> >* aOutputBufs);
178
179
  /**
180
   * Return true if MediaEncoder has been shutdown. Reasons are encoding
181
   * complete, encounter an error, or being canceled by its caller.
182
   */
183
  bool IsShutdown();
184
185
  /**
186
   * Cancels the encoding and shuts down the encoder using Shutdown().
187
   * Listeners are not notified of the shutdown.
188
   */
189
  void Cancel();
190
191
  bool HasError();
192
193
#ifdef MOZ_WEBM_ENCODER
194
  static bool IsWebMEncoderEnabled();
195
#endif
196
197
  /**
198
   * Notifies listeners that this MediaEncoder has been initialized.
199
   */
200
  void NotifyInitialized();
201
202
  /**
203
   * Notifies listeners that this MediaEncoder has data available in some
204
   * TrackEncoders.
205
   */
206
  void NotifyDataAvailable();
207
208
  /**
209
   * Registers a listener to events from this MediaEncoder.
210
   * We hold a strong reference to the listener.
211
   */
212
  void RegisterListener(MediaEncoderListener* aListener);
213
214
  /**
215
   * Unregisters a listener from events from this MediaEncoder.
216
   * The listener will stop receiving events synchronously.
217
   */
218
  bool UnregisterListener(MediaEncoderListener* aListener);
219
220
  MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
221
  /*
222
   * Measure the size of the buffer, and heap memory in bytes occupied by
223
   * mAudioEncoder and mVideoEncoder.
224
   */
225
  size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf);
226
227
  /**
228
   * Set desired video keyframe interval defined in milliseconds.
229
   */
230
  void SetVideoKeyFrameInterval(int32_t aVideoKeyFrameInterval);
231
232
protected:
233
  ~MediaEncoder();
234
235
private:
236
  /**
237
   * Shuts down the MediaEncoder and cleans up track encoders.
238
   * Listeners will be notified of the shutdown unless we were Cancel()ed first.
239
   */
240
  void Shutdown();
241
242
  /**
243
   * Sets mError to true, notifies listeners of the error if mError changed,
244
   * and stops encoding.
245
   */
246
  void SetError();
247
248
  // Get encoded data from trackEncoder and write to muxer
249
  nsresult WriteEncodedDataToMuxer(TrackEncoder *aTrackEncoder);
250
  // Get metadata from trackEncoder and copy to muxer
251
  nsresult CopyMetadataToMuxer(TrackEncoder* aTrackEncoder);
252
253
  const RefPtr<TaskQueue> mEncoderThread;
254
255
  UniquePtr<ContainerWriter> mWriter;
256
  RefPtr<AudioTrackEncoder> mAudioEncoder;
257
  RefPtr<AudioTrackListener> mAudioListener;
258
  RefPtr<VideoTrackEncoder> mVideoEncoder;
259
  RefPtr<VideoTrackListener> mVideoListener;
260
  RefPtr<EncoderListener> mEncoderListener;
261
  nsTArray<RefPtr<MediaEncoderListener>> mListeners;
262
263
  // The AudioNode we are encoding.
264
  // Will be null when input is media stream or destination node.
265
  RefPtr<dom::AudioNode> mAudioNode;
266
  // Pipe-stream for allowing a track listener on a non-destination AudioNode.
267
  // Will be null when input is media stream or destination node.
268
  RefPtr<AudioNodeStream> mPipeStream;
269
  // Input port that connect mAudioNode to mPipeStream.
270
  // Will be null when input is media stream or destination node.
271
  RefPtr<MediaInputPort> mInputPort;
272
  // An audio track that we are encoding. Will be null if the input stream
273
  // doesn't contain audio on start() or if the input is an AudioNode.
274
  RefPtr<dom::AudioStreamTrack> mAudioTrack;
275
  // A video track that we are encoding. Will be null if the input stream
276
  // doesn't contain video on start() or if the input is an AudioNode.
277
  RefPtr<dom::VideoStreamTrack> mVideoTrack;
278
  TimeStamp mStartTime;
279
  nsString mMIMEType;
280
  bool mInitialized;
281
  bool mMetadataEncoded;
282
  bool mCompleted;
283
  bool mError;
284
  bool mCanceled;
285
  bool mShutdown;
286
  // Get duration from create encoder, for logging purpose
287
  double GetEncodeTimeStamp()
288
0
  {
289
0
    TimeDuration decodeTime;
290
0
    decodeTime = TimeStamp::Now() - mStartTime;
291
0
    return decodeTime.ToMilliseconds();
292
0
  }
293
};
294
295
} // namespace mozilla
296
297
#endif