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