1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/media/omx/OMXCodecWrapper.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,319 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.7 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#ifndef OMXCodecWrapper_h_ 1.10 +#define OMXCodecWrapper_h_ 1.11 + 1.12 +#include <gui/Surface.h> 1.13 +#include <stagefright/foundation/ABuffer.h> 1.14 +#include <stagefright/foundation/AMessage.h> 1.15 +#include <stagefright/MediaCodec.h> 1.16 + 1.17 +#include "AudioSegment.h" 1.18 +#include "GonkNativeWindow.h" 1.19 +#include "GonkNativeWindowClient.h" 1.20 + 1.21 +#include <speex/speex_resampler.h> 1.22 + 1.23 +namespace android { 1.24 + 1.25 +class OMXAudioEncoder; 1.26 +class OMXVideoEncoder; 1.27 + 1.28 +/** 1.29 + * This class (and its subclasses) wraps the video and audio codec from 1.30 + * MediaCodec API in libstagefright. Currently only AVC/H.264 video encoder and 1.31 + * AAC audio encoder are supported. 1.32 + * 1.33 + * OMXCodecWrapper has static creator functions that returns actual codec 1.34 + * instances for different types of codec supported and serves as superclass to 1.35 + * provide a function to read encoded data as byte array from codec. Two 1.36 + * subclasses, OMXAudioEncoder and OMXVideoEncoder, respectively provides 1.37 + * functions for encoding data from audio and video track. 1.38 + * 1.39 + * A typical usage is as follows: 1.40 + * - Call one of the creator function Create...() to get either a 1.41 + * OMXAudioEncoder or OMXVideoEncoder object. 1.42 + * - Configure codec by providing characteristics of input raw data, such as 1.43 + * video frame width and height, using Configure(). 1.44 + * - Send raw data (and notify end of stream) with Encode(). 1.45 + * - Get encoded data through GetNextEncodedFrame(). 1.46 + * - Repeat previous 2 steps until end of stream. 1.47 + * - Destroy the object. 1.48 + * 1.49 + * The lifecycle of underlying OMX codec is binded with construction and 1.50 + * destruction of OMXCodecWrapper and subclass objects. For some types of 1.51 + * codecs, such as HW accelerated AVC/H.264 encoder, there can be only one 1.52 + * instance system-wise at a time, attempting to create another instance will 1.53 + * fail. 1.54 + */ 1.55 +class OMXCodecWrapper 1.56 +{ 1.57 +public: 1.58 + // Codec types. 1.59 + enum CodecType { 1.60 + AAC_ENC, // AAC encoder. 1.61 + AMR_NB_ENC, // AMR_NB encoder. 1.62 + AVC_ENC, // AVC/H.264 encoder. 1.63 + TYPE_COUNT 1.64 + }; 1.65 + 1.66 + // Input and output flags. 1.67 + enum { 1.68 + // For Encode() and Encode, it indicates the end of input stream; 1.69 + // For GetNextEncodedFrame(), it indicates the end of output 1.70 + // stream. 1.71 + BUFFER_EOS = MediaCodec::BUFFER_FLAG_EOS, 1.72 + // For GetNextEncodedFrame(). It indicates the output buffer is an I-frame. 1.73 + BUFFER_SYNC_FRAME = MediaCodec::BUFFER_FLAG_SYNCFRAME, 1.74 + // For GetNextEncodedFrame(). It indicates that the output buffer contains 1.75 + // codec specific configuration info. (SPS & PPS for AVC/H.264; 1.76 + // DecoderSpecificInfo for AAC) 1.77 + BUFFER_CODEC_CONFIG = MediaCodec::BUFFER_FLAG_CODECCONFIG, 1.78 + }; 1.79 + 1.80 + // Hard-coded values for AAC DecoderConfigDescriptor in libstagefright. 1.81 + // See MPEG4Writer::Track::writeMp4aEsdsBox() 1.82 + // Exposed for the need of MP4 container writer. 1.83 + enum { 1.84 + kAACBitrate = 96000, // kbps 1.85 + kAACFrameSize = 768, // bytes 1.86 + kAACFrameDuration = 1024, // How many samples per AAC frame. 1.87 + }; 1.88 + 1.89 + /** Create a AAC audio encoder. Returns nullptr when failed. */ 1.90 + static OMXAudioEncoder* CreateAACEncoder(); 1.91 + 1.92 + /** Create a AMR audio encoder. Returns nullptr when failed. */ 1.93 + static OMXAudioEncoder* CreateAMRNBEncoder(); 1.94 + 1.95 + /** Create a AVC/H.264 video encoder. Returns nullptr when failed. */ 1.96 + static OMXVideoEncoder* CreateAVCEncoder(); 1.97 + 1.98 + virtual ~OMXCodecWrapper(); 1.99 + 1.100 + /** 1.101 + * Get the next available encoded data from MediaCodec. The data will be 1.102 + * copied into aOutputBuf array, with its timestamp (in microseconds) in 1.103 + * aOutputTimestamp. 1.104 + * Wait at most aTimeout microseconds to dequeue a output buffer. 1.105 + */ 1.106 + nsresult GetNextEncodedFrame(nsTArray<uint8_t>* aOutputBuf, 1.107 + int64_t* aOutputTimestamp, int* aOutputFlags, 1.108 + int64_t aTimeOut); 1.109 + /* 1.110 + * Get the codec type 1.111 + */ 1.112 + int GetCodecType() { return mCodecType; } 1.113 +protected: 1.114 + /** 1.115 + * See whether the object has been initialized successfully and is ready to 1.116 + * use. 1.117 + */ 1.118 + virtual bool IsValid() { return mCodec != nullptr; } 1.119 + 1.120 + /** 1.121 + * Construct codec specific configuration blob with given data aData generated 1.122 + * by media codec and append it into aOutputBuf. Needed by MP4 container 1.123 + * writer for generating decoder config box, or WebRTC for generating RTP 1.124 + * packets. Returns OK if succeed. 1.125 + */ 1.126 + virtual status_t AppendDecoderConfig(nsTArray<uint8_t>* aOutputBuf, 1.127 + ABuffer* aData) = 0; 1.128 + 1.129 + /** 1.130 + * Append encoded frame data generated by media codec (stored in aData and 1.131 + * is aSize bytes long) into aOutputBuf. Subclasses can override this function 1.132 + * to process the data for specific container writer. 1.133 + */ 1.134 + virtual void AppendFrame(nsTArray<uint8_t>* aOutputBuf, 1.135 + const uint8_t* aData, size_t aSize) 1.136 + { 1.137 + aOutputBuf->AppendElements(aData, aSize); 1.138 + } 1.139 + 1.140 +private: 1.141 + // Hide these. User should always use creator functions to get a media codec. 1.142 + OMXCodecWrapper() MOZ_DELETE; 1.143 + OMXCodecWrapper(const OMXCodecWrapper&) MOZ_DELETE; 1.144 + OMXCodecWrapper& operator=(const OMXCodecWrapper&) MOZ_DELETE; 1.145 + 1.146 + /** 1.147 + * Create a media codec of given type. It will be a AVC/H.264 video encoder if 1.148 + * aCodecType is CODEC_AVC_ENC, or AAC audio encoder if aCodecType is 1.149 + * CODEC_AAC_ENC. 1.150 + */ 1.151 + OMXCodecWrapper(CodecType aCodecType); 1.152 + 1.153 + // For subclasses to access hidden constructor and implementation details. 1.154 + friend class OMXAudioEncoder; 1.155 + friend class OMXVideoEncoder; 1.156 + 1.157 + /** 1.158 + * Start the media codec. 1.159 + */ 1.160 + status_t Start(); 1.161 + 1.162 + /** 1.163 + * Stop the media codec. 1.164 + */ 1.165 + status_t Stop(); 1.166 + 1.167 + // The actual codec instance provided by libstagefright. 1.168 + sp<MediaCodec> mCodec; 1.169 + 1.170 + // A dedicate message loop with its own thread used by MediaCodec. 1.171 + sp<ALooper> mLooper; 1.172 + 1.173 + Vector<sp<ABuffer> > mInputBufs; // MediaCodec buffers to hold input data. 1.174 + Vector<sp<ABuffer> > mOutputBufs; // MediaCodec buffers to hold output data. 1.175 + 1.176 + int mCodecType; 1.177 + bool mStarted; // Has MediaCodec been started? 1.178 + bool mAMRCSDProvided; 1.179 +}; 1.180 + 1.181 +/** 1.182 + * Audio encoder. 1.183 + */ 1.184 +class OMXAudioEncoder MOZ_FINAL : public OMXCodecWrapper 1.185 +{ 1.186 +public: 1.187 + /** 1.188 + * Configure audio codec parameters and start media codec. It must be called 1.189 + * before calling Encode() and GetNextEncodedFrame(). 1.190 + * aReSamplingRate = 0 means no resampler required 1.191 + */ 1.192 + nsresult Configure(int aChannelCount, int aInputSampleRate, int aEncodedSampleRate); 1.193 + 1.194 + /** 1.195 + * Encode 16-bit PCM audio samples stored in aSegment. To notify end of 1.196 + * stream, set aInputFlags to BUFFER_EOS. Since encoder has limited buffers, 1.197 + * this function might not be able to encode all chunks in one call, however 1.198 + * it will remove chunks it consumes from aSegment. 1.199 + */ 1.200 + nsresult Encode(mozilla::AudioSegment& aSegment, int aInputFlags = 0); 1.201 + 1.202 + ~OMXAudioEncoder(); 1.203 +protected: 1.204 + virtual status_t AppendDecoderConfig(nsTArray<uint8_t>* aOutputBuf, 1.205 + ABuffer* aData) MOZ_OVERRIDE; 1.206 +private: 1.207 + // Hide these. User should always use creator functions to get a media codec. 1.208 + OMXAudioEncoder() MOZ_DELETE; 1.209 + OMXAudioEncoder(const OMXAudioEncoder&) MOZ_DELETE; 1.210 + OMXAudioEncoder& operator=(const OMXAudioEncoder&) MOZ_DELETE; 1.211 + 1.212 + /** 1.213 + * Create a audio codec. It will be a AAC encoder if aCodecType is 1.214 + * CODEC_AAC_ENC. 1.215 + */ 1.216 + OMXAudioEncoder(CodecType aCodecType) 1.217 + : OMXCodecWrapper(aCodecType) 1.218 + , mResampler(nullptr) 1.219 + , mChannels(0) 1.220 + , mTimestamp(0) 1.221 + , mSampleDuration(0) 1.222 + , mResamplingRatio(0) {} 1.223 + 1.224 + // For creator function to access hidden constructor. 1.225 + friend class OMXCodecWrapper; 1.226 + 1.227 + /** 1.228 + * If the input sample rate does not divide 48kHz evenly, the input data are 1.229 + * resampled. 1.230 + */ 1.231 + SpeexResamplerState* mResampler; 1.232 + // Number of audio channels. 1.233 + size_t mChannels; 1.234 + 1.235 + float mResamplingRatio; 1.236 + // The total duration of audio samples that have been encoded in microseconds. 1.237 + int64_t mTimestamp; 1.238 + // Time per audio sample in microseconds. 1.239 + int64_t mSampleDuration; 1.240 +}; 1.241 + 1.242 +/** 1.243 + * Video encoder. 1.244 + */ 1.245 +class OMXVideoEncoder MOZ_FINAL : public OMXCodecWrapper 1.246 +{ 1.247 + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(OMXVideoEncoder) 1.248 +public: 1.249 + // Types of output blob format. 1.250 + enum BlobFormat { 1.251 + AVC_MP4, // MP4 file config descripter (defined in ISO/IEC 14496-15 5.2.4.1.1) 1.252 + AVC_NAL // NAL (Network Abstract Layer) (defined in ITU-T H.264 7.4.1) 1.253 + }; 1.254 + 1.255 + /** 1.256 + * Configure video codec parameters and start media codec. It must be called 1.257 + * before calling Encode() and GetNextEncodedFrame(). 1.258 + * aBlobFormat specifies output blob format provided by encoder. It can be 1.259 + * AVC_MP4 or AVC_NAL. 1.260 + */ 1.261 + nsresult Configure(int aWidth, int aHeight, int aFrameRate, 1.262 + BlobFormat aBlobFormat = BlobFormat::AVC_MP4); 1.263 + 1.264 + /** 1.265 + * Encode a aWidth pixels wide and aHeight pixels tall video frame of 1.266 + * semi-planar YUV420 format stored in the buffer of aImage. aTimestamp gives 1.267 + * the frame timestamp/presentation time (in microseconds). To notify end of 1.268 + * stream, set aInputFlags to BUFFER_EOS. 1.269 + */ 1.270 + nsresult Encode(const mozilla::layers::Image* aImage, int aWidth, int aHeight, 1.271 + int64_t aTimestamp, int aInputFlags = 0); 1.272 + 1.273 +#if ANDROID_VERSION >= 18 1.274 + /** Set encoding bitrate (in kbps). */ 1.275 + nsresult SetBitrate(int32_t aKbps); 1.276 +#endif 1.277 + 1.278 + /** 1.279 + * Get current AVC codec config blob. The output format depends on the 1.280 + * aBlobFormat argument given when Configure() was called. 1.281 + */ 1.282 + nsresult GetCodecConfig(nsTArray<uint8_t>* aOutputBuf); 1.283 + 1.284 +protected: 1.285 + virtual status_t AppendDecoderConfig(nsTArray<uint8_t>* aOutputBuf, 1.286 + ABuffer* aData) MOZ_OVERRIDE; 1.287 + 1.288 + // If configured to output MP4 format blob, AVC/H.264 encoder has to replace 1.289 + // NAL unit start code with the unit length as specified in 1.290 + // ISO/IEC 14496-15 5.2.3. 1.291 + virtual void AppendFrame(nsTArray<uint8_t>* aOutputBuf, 1.292 + const uint8_t* aData, size_t aSize) MOZ_OVERRIDE; 1.293 + 1.294 +private: 1.295 + // Hide these. User should always use creator functions to get a media codec. 1.296 + OMXVideoEncoder() MOZ_DELETE; 1.297 + OMXVideoEncoder(const OMXVideoEncoder&) MOZ_DELETE; 1.298 + OMXVideoEncoder& operator=(const OMXVideoEncoder&) MOZ_DELETE; 1.299 + 1.300 + /** 1.301 + * Create a video codec. It will be a AVC/H.264 encoder if aCodecType is 1.302 + * CODEC_AVC_ENC. 1.303 + */ 1.304 + OMXVideoEncoder(CodecType aCodecType) 1.305 + : OMXCodecWrapper(aCodecType) 1.306 + , mWidth(0) 1.307 + , mHeight(0) 1.308 + , mBlobFormat(BlobFormat::AVC_MP4) 1.309 + , mHasConfigBlob(false) 1.310 + {} 1.311 + 1.312 + // For creator function to access hidden constructor. 1.313 + friend class OMXCodecWrapper; 1.314 + 1.315 + int mWidth; 1.316 + int mHeight; 1.317 + BlobFormat mBlobFormat; 1.318 + bool mHasConfigBlob; 1.319 +}; 1.320 + 1.321 +} // namespace android 1.322 +#endif // OMXCodecWrapper_h_