Fri, 16 Jan 2015 04:50:19 +0100
Replace accessor implementation with direct member state manipulation, by
request https://trac.torproject.org/projects/tor/ticket/9701#comment:32
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/. */
6 #ifndef MediaEncoder_h_
7 #define MediaEncoder_h_
9 #include "mozilla/DebugOnly.h"
10 #include "TrackEncoder.h"
11 #include "ContainerWriter.h"
12 #include "MediaStreamGraph.h"
14 namespace mozilla {
16 /**
17 * MediaEncoder is the framework of encoding module, it controls and manages
18 * procedures between ContainerWriter and TrackEncoder. ContainerWriter packs
19 * the encoded track data with a specific container (e.g. ogg, mp4).
20 * AudioTrackEncoder and VideoTrackEncoder are subclasses of TrackEncoder, and
21 * are responsible for encoding raw data coming from MediaStreamGraph.
22 *
23 * Also, MediaEncoder is a type of MediaStreamListener, it starts to receive raw
24 * segments after itself is added to the source stream. In the mean time,
25 * encoded track data is pulled by its owner periodically on a worker thread. A
26 * reentrant monitor is used to protect the push and pull of resource.
27 *
28 * MediaEncoder is designed to be a passive component, neither it owns nor in
29 * charge of managing threads. However, a monitor is used in function
30 * TrackEncoder::GetEncodedTrack() for the purpose of thread safety (e.g.
31 * between callbacks of MediaStreamListener and others), a call to this function
32 * might block. Therefore, MediaEncoder should not run on threads that forbid
33 * blocking, such as main thread or I/O thread.
34 *
35 * For example, an usage from MediaRecorder of this component would be:
36 * 1) Create an encoder with a valid MIME type.
37 * => encoder = MediaEncoder::CreateEncoder(aMIMEType);
38 * It then generate a ContainerWriter according to the MIME type, and an
39 * AudioTrackEncoder (or a VideoTrackEncoder too) associated with the media
40 * type.
41 *
42 * 2) Dispatch the task GetEncodedData() to a worker thread.
43 *
44 * 3) To start encoding, add this component to its source stream.
45 * => sourceStream->AddListener(encoder);
46 *
47 * 4) To stop encoding, remove this component from its source stream.
48 * => sourceStream->RemoveListener(encoder);
49 */
50 class MediaEncoder : public MediaStreamListener
51 {
52 public :
53 enum {
54 ENCODE_METADDATA,
55 ENCODE_TRACK,
56 ENCODE_DONE,
57 ENCODE_ERROR,
58 };
60 MediaEncoder(ContainerWriter* aWriter,
61 AudioTrackEncoder* aAudioEncoder,
62 VideoTrackEncoder* aVideoEncoder,
63 const nsAString& aMIMEType)
64 : mWriter(aWriter)
65 , mAudioEncoder(aAudioEncoder)
66 , mVideoEncoder(aVideoEncoder)
67 , mStartTime(TimeStamp::Now())
68 , mMIMEType(aMIMEType)
69 , mState(MediaEncoder::ENCODE_METADDATA)
70 , mShutdown(false)
71 {}
73 ~MediaEncoder() {};
75 /**
76 * Notified by the control loop of MediaStreamGraph; aQueueMedia is the raw
77 * track data in form of MediaSegment.
78 */
79 virtual void NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, TrackID aID,
80 TrackRate aTrackRate,
81 TrackTicks aTrackOffset,
82 uint32_t aTrackEvents,
83 const MediaSegment& aQueuedMedia);
85 /**
86 * Notified the stream is being removed.
87 */
88 virtual void NotifyRemoved(MediaStreamGraph* aGraph);
90 /**
91 * Creates an encoder with a given MIME type. Returns null if we are unable
92 * to create the encoder. For now, default aMIMEType to "audio/ogg" and use
93 * Ogg+Opus if it is empty.
94 */
95 static already_AddRefed<MediaEncoder> CreateEncoder(const nsAString& aMIMEType,
96 uint8_t aTrackTypes = ContainerWriter::CREATE_AUDIO_TRACK);
97 /**
98 * Encodes the raw track data and returns the final container data. Assuming
99 * it is called on a single worker thread. The buffer of container data is
100 * allocated in ContainerWriter::GetContainerData(), and is appended to
101 * aOutputBufs. aMIMEType is the valid mime-type of this returned container
102 * data.
103 */
104 void GetEncodedData(nsTArray<nsTArray<uint8_t> >* aOutputBufs,
105 nsAString& aMIMEType);
107 /**
108 * Return true if MediaEncoder has been shutdown. Reasons are encoding
109 * complete, encounter an error, or being canceled by its caller.
110 */
111 bool IsShutdown()
112 {
113 return mShutdown;
114 }
116 /**
117 * Cancel the encoding, and wakes up the lock of reentrant monitor in encoder.
118 */
119 void Cancel()
120 {
121 if (mAudioEncoder) {
122 mAudioEncoder->NotifyCancel();
123 }
124 if (mVideoEncoder) {
125 mVideoEncoder->NotifyCancel();
126 }
127 }
129 bool HasError()
130 {
131 return mState == ENCODE_ERROR;
132 }
134 #ifdef MOZ_WEBM_ENCODER
135 static bool IsWebMEncoderEnabled();
136 #endif
138 #ifdef MOZ_OMX_ENCODER
139 static bool IsOMXEncoderEnabled();
140 #endif
142 private:
143 // Get encoded data from trackEncoder and write to muxer
144 nsresult WriteEncodedDataToMuxer(TrackEncoder *aTrackEncoder);
145 // Get metadata from trackEncoder and copy to muxer
146 nsresult CopyMetadataToMuxer(TrackEncoder* aTrackEncoder);
147 nsAutoPtr<ContainerWriter> mWriter;
148 nsAutoPtr<AudioTrackEncoder> mAudioEncoder;
149 nsAutoPtr<VideoTrackEncoder> mVideoEncoder;
150 TimeStamp mStartTime;
151 nsString mMIMEType;
152 int mState;
153 bool mShutdown;
154 // Get duration from create encoder, for logging purpose
155 double GetEncodeTimeStamp()
156 {
157 TimeDuration decodeTime;
158 decodeTime = TimeStamp::Now() - mStartTime;
159 return decodeTime.ToMilliseconds();
160 }
161 };
163 }
164 #endif