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 OMXCodecWrapper_h_
7 #define OMXCodecWrapper_h_
9 #include <gui/Surface.h>
10 #include <stagefright/foundation/ABuffer.h>
11 #include <stagefright/foundation/AMessage.h>
12 #include <stagefright/MediaCodec.h>
14 #include "AudioSegment.h"
15 #include "GonkNativeWindow.h"
16 #include "GonkNativeWindowClient.h"
18 #include <speex/speex_resampler.h>
20 namespace android {
22 class OMXAudioEncoder;
23 class OMXVideoEncoder;
25 /**
26 * This class (and its subclasses) wraps the video and audio codec from
27 * MediaCodec API in libstagefright. Currently only AVC/H.264 video encoder and
28 * AAC audio encoder are supported.
29 *
30 * OMXCodecWrapper has static creator functions that returns actual codec
31 * instances for different types of codec supported and serves as superclass to
32 * provide a function to read encoded data as byte array from codec. Two
33 * subclasses, OMXAudioEncoder and OMXVideoEncoder, respectively provides
34 * functions for encoding data from audio and video track.
35 *
36 * A typical usage is as follows:
37 * - Call one of the creator function Create...() to get either a
38 * OMXAudioEncoder or OMXVideoEncoder object.
39 * - Configure codec by providing characteristics of input raw data, such as
40 * video frame width and height, using Configure().
41 * - Send raw data (and notify end of stream) with Encode().
42 * - Get encoded data through GetNextEncodedFrame().
43 * - Repeat previous 2 steps until end of stream.
44 * - Destroy the object.
45 *
46 * The lifecycle of underlying OMX codec is binded with construction and
47 * destruction of OMXCodecWrapper and subclass objects. For some types of
48 * codecs, such as HW accelerated AVC/H.264 encoder, there can be only one
49 * instance system-wise at a time, attempting to create another instance will
50 * fail.
51 */
52 class OMXCodecWrapper
53 {
54 public:
55 // Codec types.
56 enum CodecType {
57 AAC_ENC, // AAC encoder.
58 AMR_NB_ENC, // AMR_NB encoder.
59 AVC_ENC, // AVC/H.264 encoder.
60 TYPE_COUNT
61 };
63 // Input and output flags.
64 enum {
65 // For Encode() and Encode, it indicates the end of input stream;
66 // For GetNextEncodedFrame(), it indicates the end of output
67 // stream.
68 BUFFER_EOS = MediaCodec::BUFFER_FLAG_EOS,
69 // For GetNextEncodedFrame(). It indicates the output buffer is an I-frame.
70 BUFFER_SYNC_FRAME = MediaCodec::BUFFER_FLAG_SYNCFRAME,
71 // For GetNextEncodedFrame(). It indicates that the output buffer contains
72 // codec specific configuration info. (SPS & PPS for AVC/H.264;
73 // DecoderSpecificInfo for AAC)
74 BUFFER_CODEC_CONFIG = MediaCodec::BUFFER_FLAG_CODECCONFIG,
75 };
77 // Hard-coded values for AAC DecoderConfigDescriptor in libstagefright.
78 // See MPEG4Writer::Track::writeMp4aEsdsBox()
79 // Exposed for the need of MP4 container writer.
80 enum {
81 kAACBitrate = 96000, // kbps
82 kAACFrameSize = 768, // bytes
83 kAACFrameDuration = 1024, // How many samples per AAC frame.
84 };
86 /** Create a AAC audio encoder. Returns nullptr when failed. */
87 static OMXAudioEncoder* CreateAACEncoder();
89 /** Create a AMR audio encoder. Returns nullptr when failed. */
90 static OMXAudioEncoder* CreateAMRNBEncoder();
92 /** Create a AVC/H.264 video encoder. Returns nullptr when failed. */
93 static OMXVideoEncoder* CreateAVCEncoder();
95 virtual ~OMXCodecWrapper();
97 /**
98 * Get the next available encoded data from MediaCodec. The data will be
99 * copied into aOutputBuf array, with its timestamp (in microseconds) in
100 * aOutputTimestamp.
101 * Wait at most aTimeout microseconds to dequeue a output buffer.
102 */
103 nsresult GetNextEncodedFrame(nsTArray<uint8_t>* aOutputBuf,
104 int64_t* aOutputTimestamp, int* aOutputFlags,
105 int64_t aTimeOut);
106 /*
107 * Get the codec type
108 */
109 int GetCodecType() { return mCodecType; }
110 protected:
111 /**
112 * See whether the object has been initialized successfully and is ready to
113 * use.
114 */
115 virtual bool IsValid() { return mCodec != nullptr; }
117 /**
118 * Construct codec specific configuration blob with given data aData generated
119 * by media codec and append it into aOutputBuf. Needed by MP4 container
120 * writer for generating decoder config box, or WebRTC for generating RTP
121 * packets. Returns OK if succeed.
122 */
123 virtual status_t AppendDecoderConfig(nsTArray<uint8_t>* aOutputBuf,
124 ABuffer* aData) = 0;
126 /**
127 * Append encoded frame data generated by media codec (stored in aData and
128 * is aSize bytes long) into aOutputBuf. Subclasses can override this function
129 * to process the data for specific container writer.
130 */
131 virtual void AppendFrame(nsTArray<uint8_t>* aOutputBuf,
132 const uint8_t* aData, size_t aSize)
133 {
134 aOutputBuf->AppendElements(aData, aSize);
135 }
137 private:
138 // Hide these. User should always use creator functions to get a media codec.
139 OMXCodecWrapper() MOZ_DELETE;
140 OMXCodecWrapper(const OMXCodecWrapper&) MOZ_DELETE;
141 OMXCodecWrapper& operator=(const OMXCodecWrapper&) MOZ_DELETE;
143 /**
144 * Create a media codec of given type. It will be a AVC/H.264 video encoder if
145 * aCodecType is CODEC_AVC_ENC, or AAC audio encoder if aCodecType is
146 * CODEC_AAC_ENC.
147 */
148 OMXCodecWrapper(CodecType aCodecType);
150 // For subclasses to access hidden constructor and implementation details.
151 friend class OMXAudioEncoder;
152 friend class OMXVideoEncoder;
154 /**
155 * Start the media codec.
156 */
157 status_t Start();
159 /**
160 * Stop the media codec.
161 */
162 status_t Stop();
164 // The actual codec instance provided by libstagefright.
165 sp<MediaCodec> mCodec;
167 // A dedicate message loop with its own thread used by MediaCodec.
168 sp<ALooper> mLooper;
170 Vector<sp<ABuffer> > mInputBufs; // MediaCodec buffers to hold input data.
171 Vector<sp<ABuffer> > mOutputBufs; // MediaCodec buffers to hold output data.
173 int mCodecType;
174 bool mStarted; // Has MediaCodec been started?
175 bool mAMRCSDProvided;
176 };
178 /**
179 * Audio encoder.
180 */
181 class OMXAudioEncoder MOZ_FINAL : public OMXCodecWrapper
182 {
183 public:
184 /**
185 * Configure audio codec parameters and start media codec. It must be called
186 * before calling Encode() and GetNextEncodedFrame().
187 * aReSamplingRate = 0 means no resampler required
188 */
189 nsresult Configure(int aChannelCount, int aInputSampleRate, int aEncodedSampleRate);
191 /**
192 * Encode 16-bit PCM audio samples stored in aSegment. To notify end of
193 * stream, set aInputFlags to BUFFER_EOS. Since encoder has limited buffers,
194 * this function might not be able to encode all chunks in one call, however
195 * it will remove chunks it consumes from aSegment.
196 */
197 nsresult Encode(mozilla::AudioSegment& aSegment, int aInputFlags = 0);
199 ~OMXAudioEncoder();
200 protected:
201 virtual status_t AppendDecoderConfig(nsTArray<uint8_t>* aOutputBuf,
202 ABuffer* aData) MOZ_OVERRIDE;
203 private:
204 // Hide these. User should always use creator functions to get a media codec.
205 OMXAudioEncoder() MOZ_DELETE;
206 OMXAudioEncoder(const OMXAudioEncoder&) MOZ_DELETE;
207 OMXAudioEncoder& operator=(const OMXAudioEncoder&) MOZ_DELETE;
209 /**
210 * Create a audio codec. It will be a AAC encoder if aCodecType is
211 * CODEC_AAC_ENC.
212 */
213 OMXAudioEncoder(CodecType aCodecType)
214 : OMXCodecWrapper(aCodecType)
215 , mResampler(nullptr)
216 , mChannels(0)
217 , mTimestamp(0)
218 , mSampleDuration(0)
219 , mResamplingRatio(0) {}
221 // For creator function to access hidden constructor.
222 friend class OMXCodecWrapper;
224 /**
225 * If the input sample rate does not divide 48kHz evenly, the input data are
226 * resampled.
227 */
228 SpeexResamplerState* mResampler;
229 // Number of audio channels.
230 size_t mChannels;
232 float mResamplingRatio;
233 // The total duration of audio samples that have been encoded in microseconds.
234 int64_t mTimestamp;
235 // Time per audio sample in microseconds.
236 int64_t mSampleDuration;
237 };
239 /**
240 * Video encoder.
241 */
242 class OMXVideoEncoder MOZ_FINAL : public OMXCodecWrapper
243 {
244 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(OMXVideoEncoder)
245 public:
246 // Types of output blob format.
247 enum BlobFormat {
248 AVC_MP4, // MP4 file config descripter (defined in ISO/IEC 14496-15 5.2.4.1.1)
249 AVC_NAL // NAL (Network Abstract Layer) (defined in ITU-T H.264 7.4.1)
250 };
252 /**
253 * Configure video codec parameters and start media codec. It must be called
254 * before calling Encode() and GetNextEncodedFrame().
255 * aBlobFormat specifies output blob format provided by encoder. It can be
256 * AVC_MP4 or AVC_NAL.
257 */
258 nsresult Configure(int aWidth, int aHeight, int aFrameRate,
259 BlobFormat aBlobFormat = BlobFormat::AVC_MP4);
261 /**
262 * Encode a aWidth pixels wide and aHeight pixels tall video frame of
263 * semi-planar YUV420 format stored in the buffer of aImage. aTimestamp gives
264 * the frame timestamp/presentation time (in microseconds). To notify end of
265 * stream, set aInputFlags to BUFFER_EOS.
266 */
267 nsresult Encode(const mozilla::layers::Image* aImage, int aWidth, int aHeight,
268 int64_t aTimestamp, int aInputFlags = 0);
270 #if ANDROID_VERSION >= 18
271 /** Set encoding bitrate (in kbps). */
272 nsresult SetBitrate(int32_t aKbps);
273 #endif
275 /**
276 * Get current AVC codec config blob. The output format depends on the
277 * aBlobFormat argument given when Configure() was called.
278 */
279 nsresult GetCodecConfig(nsTArray<uint8_t>* aOutputBuf);
281 protected:
282 virtual status_t AppendDecoderConfig(nsTArray<uint8_t>* aOutputBuf,
283 ABuffer* aData) MOZ_OVERRIDE;
285 // If configured to output MP4 format blob, AVC/H.264 encoder has to replace
286 // NAL unit start code with the unit length as specified in
287 // ISO/IEC 14496-15 5.2.3.
288 virtual void AppendFrame(nsTArray<uint8_t>* aOutputBuf,
289 const uint8_t* aData, size_t aSize) MOZ_OVERRIDE;
291 private:
292 // Hide these. User should always use creator functions to get a media codec.
293 OMXVideoEncoder() MOZ_DELETE;
294 OMXVideoEncoder(const OMXVideoEncoder&) MOZ_DELETE;
295 OMXVideoEncoder& operator=(const OMXVideoEncoder&) MOZ_DELETE;
297 /**
298 * Create a video codec. It will be a AVC/H.264 encoder if aCodecType is
299 * CODEC_AVC_ENC.
300 */
301 OMXVideoEncoder(CodecType aCodecType)
302 : OMXCodecWrapper(aCodecType)
303 , mWidth(0)
304 , mHeight(0)
305 , mBlobFormat(BlobFormat::AVC_MP4)
306 , mHasConfigBlob(false)
307 {}
309 // For creator function to access hidden constructor.
310 friend class OMXCodecWrapper;
312 int mWidth;
313 int mHeight;
314 BlobFormat mBlobFormat;
315 bool mHasConfigBlob;
316 };
318 } // namespace android
319 #endif // OMXCodecWrapper_h_