|
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 OMXCodecWrapper_h_ |
|
7 #define OMXCodecWrapper_h_ |
|
8 |
|
9 #include <gui/Surface.h> |
|
10 #include <stagefright/foundation/ABuffer.h> |
|
11 #include <stagefright/foundation/AMessage.h> |
|
12 #include <stagefright/MediaCodec.h> |
|
13 |
|
14 #include "AudioSegment.h" |
|
15 #include "GonkNativeWindow.h" |
|
16 #include "GonkNativeWindowClient.h" |
|
17 |
|
18 #include <speex/speex_resampler.h> |
|
19 |
|
20 namespace android { |
|
21 |
|
22 class OMXAudioEncoder; |
|
23 class OMXVideoEncoder; |
|
24 |
|
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 }; |
|
62 |
|
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 }; |
|
76 |
|
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 }; |
|
85 |
|
86 /** Create a AAC audio encoder. Returns nullptr when failed. */ |
|
87 static OMXAudioEncoder* CreateAACEncoder(); |
|
88 |
|
89 /** Create a AMR audio encoder. Returns nullptr when failed. */ |
|
90 static OMXAudioEncoder* CreateAMRNBEncoder(); |
|
91 |
|
92 /** Create a AVC/H.264 video encoder. Returns nullptr when failed. */ |
|
93 static OMXVideoEncoder* CreateAVCEncoder(); |
|
94 |
|
95 virtual ~OMXCodecWrapper(); |
|
96 |
|
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; } |
|
116 |
|
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; |
|
125 |
|
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 } |
|
136 |
|
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; |
|
142 |
|
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); |
|
149 |
|
150 // For subclasses to access hidden constructor and implementation details. |
|
151 friend class OMXAudioEncoder; |
|
152 friend class OMXVideoEncoder; |
|
153 |
|
154 /** |
|
155 * Start the media codec. |
|
156 */ |
|
157 status_t Start(); |
|
158 |
|
159 /** |
|
160 * Stop the media codec. |
|
161 */ |
|
162 status_t Stop(); |
|
163 |
|
164 // The actual codec instance provided by libstagefright. |
|
165 sp<MediaCodec> mCodec; |
|
166 |
|
167 // A dedicate message loop with its own thread used by MediaCodec. |
|
168 sp<ALooper> mLooper; |
|
169 |
|
170 Vector<sp<ABuffer> > mInputBufs; // MediaCodec buffers to hold input data. |
|
171 Vector<sp<ABuffer> > mOutputBufs; // MediaCodec buffers to hold output data. |
|
172 |
|
173 int mCodecType; |
|
174 bool mStarted; // Has MediaCodec been started? |
|
175 bool mAMRCSDProvided; |
|
176 }; |
|
177 |
|
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); |
|
190 |
|
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); |
|
198 |
|
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; |
|
208 |
|
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) {} |
|
220 |
|
221 // For creator function to access hidden constructor. |
|
222 friend class OMXCodecWrapper; |
|
223 |
|
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; |
|
231 |
|
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 }; |
|
238 |
|
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 }; |
|
251 |
|
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); |
|
260 |
|
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); |
|
269 |
|
270 #if ANDROID_VERSION >= 18 |
|
271 /** Set encoding bitrate (in kbps). */ |
|
272 nsresult SetBitrate(int32_t aKbps); |
|
273 #endif |
|
274 |
|
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); |
|
280 |
|
281 protected: |
|
282 virtual status_t AppendDecoderConfig(nsTArray<uint8_t>* aOutputBuf, |
|
283 ABuffer* aData) MOZ_OVERRIDE; |
|
284 |
|
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; |
|
290 |
|
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; |
|
296 |
|
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 {} |
|
308 |
|
309 // For creator function to access hidden constructor. |
|
310 friend class OMXCodecWrapper; |
|
311 |
|
312 int mWidth; |
|
313 int mHeight; |
|
314 BlobFormat mBlobFormat; |
|
315 bool mHasConfigBlob; |
|
316 }; |
|
317 |
|
318 } // namespace android |
|
319 #endif // OMXCodecWrapper_h_ |