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.
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 #include "OMXCodecWrapper.h"
7 #include "OMXCodecDescriptorUtil.h"
8 #include "TrackEncoder.h"
10 #include <binder/ProcessState.h>
11 #include <cutils/properties.h>
12 #include <media/ICrypto.h>
13 #include <media/IOMX.h>
14 #include <OMX_Component.h>
15 #include <stagefright/MediaDefs.h>
16 #include <stagefright/MediaErrors.h>
18 #include "AudioChannelFormat.h"
19 #include <mozilla/Monitor.h>
20 #include "mozilla/layers/GrallocTextureClient.h"
22 using namespace mozilla;
23 using namespace mozilla::gfx;
24 using namespace mozilla::layers;
26 #define ENCODER_CONFIG_BITRATE 2000000 // bps
27 // How many seconds between I-frames.
28 #define ENCODER_CONFIG_I_FRAME_INTERVAL 1
29 // Wait up to 5ms for input buffers.
30 #define INPUT_BUFFER_TIMEOUT_US (5 * 1000ll)
31 // AMR NB kbps
32 #define AMRNB_BITRATE 12200
34 #define CODEC_ERROR(args...) \
35 do { \
36 __android_log_print(ANDROID_LOG_ERROR, "OMXCodecWrapper", ##args); \
37 } while (0)
39 namespace android {
41 OMXAudioEncoder*
42 OMXCodecWrapper::CreateAACEncoder()
43 {
44 nsAutoPtr<OMXAudioEncoder> aac(new OMXAudioEncoder(CodecType::AAC_ENC));
45 // Return the object only when media codec is valid.
46 NS_ENSURE_TRUE(aac->IsValid(), nullptr);
48 return aac.forget();
49 }
51 OMXAudioEncoder*
52 OMXCodecWrapper::CreateAMRNBEncoder()
53 {
54 nsAutoPtr<OMXAudioEncoder> amr(new OMXAudioEncoder(CodecType::AMR_NB_ENC));
55 // Return the object only when media codec is valid.
56 NS_ENSURE_TRUE(amr->IsValid(), nullptr);
58 return amr.forget();
59 }
61 OMXVideoEncoder*
62 OMXCodecWrapper::CreateAVCEncoder()
63 {
64 nsAutoPtr<OMXVideoEncoder> avc(new OMXVideoEncoder(CodecType::AVC_ENC));
65 // Return the object only when media codec is valid.
66 NS_ENSURE_TRUE(avc->IsValid(), nullptr);
68 return avc.forget();
69 }
71 OMXCodecWrapper::OMXCodecWrapper(CodecType aCodecType)
72 : mCodecType(aCodecType)
73 , mStarted(false)
74 , mAMRCSDProvided(false)
75 {
76 ProcessState::self()->startThreadPool();
78 mLooper = new ALooper();
79 mLooper->start();
81 if (aCodecType == CodecType::AVC_ENC) {
82 mCodec = MediaCodec::CreateByType(mLooper, MEDIA_MIMETYPE_VIDEO_AVC, true);
83 } else if (aCodecType == CodecType::AMR_NB_ENC) {
84 mCodec = MediaCodec::CreateByType(mLooper, MEDIA_MIMETYPE_AUDIO_AMR_NB, true);
85 } else if (aCodecType == CodecType::AAC_ENC) {
86 mCodec = MediaCodec::CreateByType(mLooper, MEDIA_MIMETYPE_AUDIO_AAC, true);
87 } else {
88 NS_ERROR("Unknown codec type.");
89 }
90 }
92 OMXCodecWrapper::~OMXCodecWrapper()
93 {
94 if (mCodec.get()) {
95 Stop();
96 mCodec->release();
97 }
98 mLooper->stop();
99 }
101 status_t
102 OMXCodecWrapper::Start()
103 {
104 // Already started.
105 NS_ENSURE_FALSE(mStarted, OK);
107 status_t result = mCodec->start();
108 mStarted = (result == OK);
110 // Get references to MediaCodec buffers.
111 if (result == OK) {
112 mCodec->getInputBuffers(&mInputBufs);
113 mCodec->getOutputBuffers(&mOutputBufs);
114 }
116 return result;
117 }
119 status_t
120 OMXCodecWrapper::Stop()
121 {
122 // Already stopped.
123 NS_ENSURE_TRUE(mStarted, OK);
125 status_t result = mCodec->stop();
126 mStarted = !(result == OK);
128 return result;
129 }
131 // Check system property to see if we're running on emulator.
132 static bool
133 IsRunningOnEmulator()
134 {
135 char qemu[PROPERTY_VALUE_MAX];
136 property_get("ro.kernel.qemu", qemu, "");
137 return strncmp(qemu, "1", 1) == 0;
138 }
140 nsresult
141 OMXVideoEncoder::Configure(int aWidth, int aHeight, int aFrameRate,
142 BlobFormat aBlobFormat)
143 {
144 MOZ_ASSERT(!mStarted, "Configure() was called already.");
146 NS_ENSURE_TRUE(aWidth > 0 && aHeight > 0 && aFrameRate > 0,
147 NS_ERROR_INVALID_ARG);
149 OMX_VIDEO_AVCLEVELTYPE level = OMX_VIDEO_AVCLevel3;
150 OMX_VIDEO_CONTROLRATETYPE bitrateMode = OMX_Video_ControlRateConstant;
151 // Limitation of soft AVC/H.264 encoder running on emulator in stagefright.
152 static bool emu = IsRunningOnEmulator();
153 if (emu) {
154 if (aWidth > 352 || aHeight > 288) {
155 CODEC_ERROR("SoftAVCEncoder doesn't support resolution larger than CIF");
156 return NS_ERROR_INVALID_ARG;
157 }
158 level = OMX_VIDEO_AVCLevel2;
159 bitrateMode = OMX_Video_ControlRateVariable;
160 }
162 // Set up configuration parameters for AVC/H.264 encoder.
163 sp<AMessage> format = new AMessage;
164 // Fixed values
165 format->setString("mime", MEDIA_MIMETYPE_VIDEO_AVC);
166 format->setInt32("bitrate", ENCODER_CONFIG_BITRATE);
167 format->setInt32("i-frame-interval", ENCODER_CONFIG_I_FRAME_INTERVAL);
168 // See mozilla::layers::GrallocImage, supports YUV 4:2:0, CbCr width and
169 // height is half that of Y
170 format->setInt32("color-format", OMX_COLOR_FormatYUV420SemiPlanar);
171 format->setInt32("profile", OMX_VIDEO_AVCProfileBaseline);
172 format->setInt32("level", level);
173 format->setInt32("bitrate-mode", bitrateMode);
174 format->setInt32("store-metadata-in-buffers", 0);
175 format->setInt32("prepend-sps-pps-to-idr-frames", 0);
176 // Input values.
177 format->setInt32("width", aWidth);
178 format->setInt32("height", aHeight);
179 format->setInt32("stride", aWidth);
180 format->setInt32("slice-height", aHeight);
181 format->setInt32("frame-rate", aFrameRate);
183 status_t result = mCodec->configure(format, nullptr, nullptr,
184 MediaCodec::CONFIGURE_FLAG_ENCODE);
185 NS_ENSURE_TRUE(result == OK, NS_ERROR_FAILURE);
187 mWidth = aWidth;
188 mHeight = aHeight;
189 mBlobFormat = aBlobFormat;
191 result = Start();
193 return result == OK ? NS_OK : NS_ERROR_FAILURE;
194 }
196 // Copy pixels from planar YUV (4:4:4/4:2:2/4:2:0) or NV21 (semi-planar 4:2:0)
197 // format to NV12 (semi-planar 4:2:0) format for QCOM HW encoder.
198 // Planar YUV: YYY...UUU...VVV...
199 // NV21: YYY...VUVU...
200 // NV12: YYY...UVUV...
201 // For 4:4:4/4:2:2 -> 4:2:0, subsample using odd row/column without
202 // interpolation.
203 // aSource contains info about source image data, and the result will be stored
204 // in aDestination, whose size needs to be >= Y plane size * 3 / 2.
205 static void
206 ConvertPlanarYCbCrToNV12(const PlanarYCbCrData* aSource, uint8_t* aDestination)
207 {
208 // Fill Y plane.
209 uint8_t* y = aSource->mYChannel;
210 IntSize ySize = aSource->mYSize;
212 // Y plane.
213 for (int i = 0; i < ySize.height; i++) {
214 memcpy(aDestination, y, ySize.width);
215 aDestination += ySize.width;
216 y += aSource->mYStride;
217 }
219 // Fill interleaved UV plane.
220 uint8_t* u = aSource->mCbChannel;
221 uint8_t* v = aSource->mCrChannel;
222 IntSize uvSize = aSource->mCbCrSize;
223 // Subsample to 4:2:0 if source is 4:4:4 or 4:2:2.
224 // Y plane width & height should be multiple of U/V plane width & height.
225 MOZ_ASSERT(ySize.width % uvSize.width == 0 &&
226 ySize.height % uvSize.height == 0);
227 size_t uvWidth = ySize.width / 2;
228 size_t uvHeight = ySize.height / 2;
229 size_t horiSubsample = uvSize.width / uvWidth;
230 size_t uPixStride = horiSubsample * (1 + aSource->mCbSkip);
231 size_t vPixStride = horiSubsample * (1 + aSource->mCrSkip);
232 size_t lineStride = uvSize.height / uvHeight * aSource->mCbCrStride;
234 for (int i = 0; i < uvHeight; i++) {
235 // 1st pixel per line.
236 uint8_t* uSrc = u;
237 uint8_t* vSrc = v;
238 for (int j = 0; j < uvWidth; j++) {
239 *aDestination++ = *uSrc;
240 *aDestination++ = *vSrc;
241 // Pick next source pixel.
242 uSrc += uPixStride;
243 vSrc += vPixStride;
244 }
245 // Pick next source line.
246 u += lineStride;
247 v += lineStride;
248 }
249 }
251 // Convert pixels in graphic buffer to NV12 format. aSource is the layer image
252 // containing source graphic buffer, and aDestination is the destination of
253 // conversion. Currently only 2 source format are supported:
254 // - NV21/HAL_PIXEL_FORMAT_YCrCb_420_SP (from camera preview window).
255 // - YV12/HAL_PIXEL_FORMAT_YV12 (from video decoder).
256 static void
257 ConvertGrallocImageToNV12(GrallocImage* aSource, uint8_t* aDestination)
258 {
259 // Get graphic buffer.
260 sp<GraphicBuffer> graphicBuffer = aSource->GetGraphicBuffer();
262 int pixelFormat = graphicBuffer->getPixelFormat();
263 // Only support NV21 (from camera) or YV12 (from HW decoder output) for now.
264 NS_ENSURE_TRUE_VOID(pixelFormat == HAL_PIXEL_FORMAT_YCrCb_420_SP ||
265 pixelFormat == HAL_PIXEL_FORMAT_YV12);
267 void* imgPtr = nullptr;
268 graphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_MASK, &imgPtr);
269 // Build PlanarYCbCrData for NV21 or YV12 buffer.
270 PlanarYCbCrData yuv;
271 switch (pixelFormat) {
272 case HAL_PIXEL_FORMAT_YCrCb_420_SP: // From camera.
273 yuv.mYChannel = static_cast<uint8_t*>(imgPtr);
274 yuv.mYSkip = 0;
275 yuv.mYSize.width = graphicBuffer->getWidth();
276 yuv.mYSize.height = graphicBuffer->getHeight();
277 yuv.mYStride = graphicBuffer->getStride();
278 // 4:2:0.
279 yuv.mCbCrSize.width = yuv.mYSize.width / 2;
280 yuv.mCbCrSize.height = yuv.mYSize.height / 2;
281 // Interleaved VU plane.
282 yuv.mCrChannel = yuv.mYChannel + (yuv.mYStride * yuv.mYSize.height);
283 yuv.mCrSkip = 1;
284 yuv.mCbChannel = yuv.mCrChannel + 1;
285 yuv.mCbSkip = 1;
286 yuv.mCbCrStride = yuv.mYStride;
287 ConvertPlanarYCbCrToNV12(&yuv, aDestination);
288 break;
289 case HAL_PIXEL_FORMAT_YV12: // From video decoder.
290 // Android YV12 format is defined in system/core/include/system/graphics.h
291 yuv.mYChannel = static_cast<uint8_t*>(imgPtr);
292 yuv.mYSkip = 0;
293 yuv.mYSize.width = graphicBuffer->getWidth();
294 yuv.mYSize.height = graphicBuffer->getHeight();
295 yuv.mYStride = graphicBuffer->getStride();
296 // 4:2:0.
297 yuv.mCbCrSize.width = yuv.mYSize.width / 2;
298 yuv.mCbCrSize.height = yuv.mYSize.height / 2;
299 yuv.mCrChannel = yuv.mYChannel + (yuv.mYStride * yuv.mYSize.height);
300 // Aligned to 16 bytes boundary.
301 yuv.mCbCrStride = (yuv.mYStride / 2 + 15) & ~0x0F;
302 yuv.mCrSkip = 0;
303 yuv.mCbChannel = yuv.mCrChannel + (yuv.mCbCrStride * yuv.mCbCrSize.height);
304 yuv.mCbSkip = 0;
305 ConvertPlanarYCbCrToNV12(&yuv, aDestination);
306 break;
307 default:
308 NS_ERROR("Unsupported input gralloc image type. Should never be here.");
309 }
311 graphicBuffer->unlock();
312 }
314 nsresult
315 OMXVideoEncoder::Encode(const Image* aImage, int aWidth, int aHeight,
316 int64_t aTimestamp, int aInputFlags)
317 {
318 MOZ_ASSERT(mStarted, "Configure() should be called before Encode().");
320 NS_ENSURE_TRUE(aWidth == mWidth && aHeight == mHeight && aTimestamp >= 0,
321 NS_ERROR_INVALID_ARG);
323 status_t result;
325 // Dequeue an input buffer.
326 uint32_t index;
327 result = mCodec->dequeueInputBuffer(&index, INPUT_BUFFER_TIMEOUT_US);
328 NS_ENSURE_TRUE(result == OK, NS_ERROR_FAILURE);
330 const sp<ABuffer>& inBuf = mInputBufs.itemAt(index);
331 uint8_t* dst = inBuf->data();
332 size_t dstSize = inBuf->capacity();
334 size_t yLen = aWidth * aHeight;
335 size_t uvLen = yLen / 2;
336 // Buffer should be large enough to hold input image data.
337 MOZ_ASSERT(dstSize >= yLen + uvLen);
339 inBuf->setRange(0, yLen + uvLen);
341 if (!aImage) {
342 // Generate muted/black image directly in buffer.
343 dstSize = yLen + uvLen;
344 // Fill Y plane.
345 memset(dst, 0x10, yLen);
346 // Fill UV plane.
347 memset(dst + yLen, 0x80, uvLen);
348 } else {
349 Image* img = const_cast<Image*>(aImage);
350 ImageFormat format = img->GetFormat();
352 MOZ_ASSERT(aWidth == img->GetSize().width &&
353 aHeight == img->GetSize().height);
355 if (format == ImageFormat::GRALLOC_PLANAR_YCBCR) {
356 ConvertGrallocImageToNV12(static_cast<GrallocImage*>(img), dst);
357 } else if (format == ImageFormat::PLANAR_YCBCR) {
358 ConvertPlanarYCbCrToNV12(static_cast<PlanarYCbCrImage*>(img)->GetData(),
359 dst);
360 } else {
361 // TODO: support RGB to YUV color conversion.
362 NS_ERROR("Unsupported input image type.");
363 }
364 }
366 // Queue this input buffer.
367 result = mCodec->queueInputBuffer(index, 0, dstSize, aTimestamp, aInputFlags);
369 return result == OK ? NS_OK : NS_ERROR_FAILURE;
370 }
372 status_t
373 OMXVideoEncoder::AppendDecoderConfig(nsTArray<uint8_t>* aOutputBuf,
374 ABuffer* aData)
375 {
376 // Codec already parsed aData. Using its result makes generating config blob
377 // much easier.
378 sp<AMessage> format;
379 mCodec->getOutputFormat(&format);
381 // NAL unit format is needed by WebRTC for RTP packets; AVC/H.264 decoder
382 // config descriptor is needed to construct MP4 'avcC' box.
383 status_t result = GenerateAVCDescriptorBlob(format, aOutputBuf, mBlobFormat);
384 mHasConfigBlob = (result == OK);
386 return result;
387 }
389 // Override to replace NAL unit start code with 4-bytes unit length.
390 // See ISO/IEC 14496-15 5.2.3.
391 void
392 OMXVideoEncoder::AppendFrame(nsTArray<uint8_t>* aOutputBuf,
393 const uint8_t* aData, size_t aSize)
394 {
395 aOutputBuf->SetCapacity(aSize);
397 if (mBlobFormat == BlobFormat::AVC_NAL) {
398 // Append NAL format data without modification.
399 aOutputBuf->AppendElements(aData, aSize);
400 return;
401 }
402 // Replace start code with data length.
403 uint8_t length[] = {
404 (aSize >> 24) & 0xFF,
405 (aSize >> 16) & 0xFF,
406 (aSize >> 8) & 0xFF,
407 aSize & 0xFF,
408 };
409 aOutputBuf->AppendElements(length, sizeof(length));
410 aOutputBuf->AppendElements(aData + sizeof(length), aSize);
411 }
413 nsresult
414 OMXVideoEncoder::GetCodecConfig(nsTArray<uint8_t>* aOutputBuf)
415 {
416 MOZ_ASSERT(mHasConfigBlob, "Haven't received codec config yet.");
418 return AppendDecoderConfig(aOutputBuf, nullptr) == OK ? NS_OK : NS_ERROR_FAILURE;
419 }
421 // MediaCodec::setParameters() is available only after API level 18.
422 #if ANDROID_VERSION >= 18
423 nsresult
424 OMXVideoEncoder::SetBitrate(int32_t aKbps)
425 {
426 sp<AMessage> msg = new AMessage();
427 msg->setInt32("videoBitrate", aKbps * 1000 /* kbps -> bps */);
428 status_t result = mCodec->setParameters(msg);
429 MOZ_ASSERT(result == OK);
430 return result == OK ? NS_OK : NS_ERROR_FAILURE;
431 }
432 #endif
434 nsresult
435 OMXAudioEncoder::Configure(int aChannels, int aInputSampleRate,
436 int aEncodedSampleRate)
437 {
438 MOZ_ASSERT(!mStarted);
440 NS_ENSURE_TRUE(aChannels > 0 && aInputSampleRate > 0 && aEncodedSampleRate >= 0,
441 NS_ERROR_INVALID_ARG);
443 if (aInputSampleRate != aEncodedSampleRate) {
444 int error;
445 mResampler = speex_resampler_init(aChannels,
446 aInputSampleRate,
447 aEncodedSampleRate,
448 SPEEX_RESAMPLER_QUALITY_DEFAULT,
449 &error);
451 if (error != RESAMPLER_ERR_SUCCESS) {
452 return NS_ERROR_FAILURE;
453 }
454 speex_resampler_skip_zeros(mResampler);
455 }
456 // Set up configuration parameters for AAC encoder.
457 sp<AMessage> format = new AMessage;
458 // Fixed values.
459 if (mCodecType == AAC_ENC) {
460 format->setString("mime", MEDIA_MIMETYPE_AUDIO_AAC);
461 format->setInt32("aac-profile", OMX_AUDIO_AACObjectLC);
462 format->setInt32("bitrate", kAACBitrate);
463 format->setInt32("sample-rate", aInputSampleRate);
464 } else if (mCodecType == AMR_NB_ENC) {
465 format->setString("mime", MEDIA_MIMETYPE_AUDIO_AMR_NB);
466 format->setInt32("bitrate", AMRNB_BITRATE);
467 format->setInt32("sample-rate", aEncodedSampleRate);
468 } else {
469 MOZ_ASSERT(false, "Can't support this codec type!!");
470 }
471 // Input values.
472 format->setInt32("channel-count", aChannels);
474 status_t result = mCodec->configure(format, nullptr, nullptr,
475 MediaCodec::CONFIGURE_FLAG_ENCODE);
476 NS_ENSURE_TRUE(result == OK, NS_ERROR_FAILURE);
478 mChannels = aChannels;
479 mSampleDuration = 1000000 / aInputSampleRate;
480 mResamplingRatio = aEncodedSampleRate > 0 ? 1.0 *
481 aEncodedSampleRate / aInputSampleRate : 1.0;
482 result = Start();
484 return result == OK ? NS_OK : NS_ERROR_FAILURE;
485 }
487 class InputBufferHelper MOZ_FINAL {
488 public:
489 InputBufferHelper(sp<MediaCodec>& aCodec, Vector<sp<ABuffer> >& aBuffers)
490 : mCodec(aCodec)
491 , mBuffers(aBuffers)
492 , mIndex(0)
493 , mData(nullptr)
494 , mOffset(0)
495 , mCapicity(0)
496 {}
498 ~InputBufferHelper()
499 {
500 // Unflushed data in buffer.
501 MOZ_ASSERT(!mData);
502 }
504 status_t Dequeue()
505 {
506 // Shouldn't have dequeued buffer.
507 MOZ_ASSERT(!mData);
509 status_t result = mCodec->dequeueInputBuffer(&mIndex,
510 INPUT_BUFFER_TIMEOUT_US);
511 NS_ENSURE_TRUE(result == OK, result);
512 sp<ABuffer> inBuf = mBuffers.itemAt(mIndex);
513 mData = inBuf->data();
514 mCapicity = inBuf->capacity();
515 mOffset = 0;
517 return OK;
518 }
520 uint8_t* GetPointer() { return mData + mOffset; }
522 const size_t AvailableSize() { return mCapicity - mOffset; }
524 void IncreaseOffset(size_t aValue)
525 {
526 // Should never out of bound.
527 MOZ_ASSERT(mOffset + aValue <= mCapicity);
528 mOffset += aValue;
529 }
531 status_t Enqueue(int64_t aTimestamp, int aFlags)
532 {
533 // Should have dequeued buffer.
534 MOZ_ASSERT(mData);
536 // Queue this buffer.
537 status_t result = mCodec->queueInputBuffer(mIndex, 0, mOffset, aTimestamp,
538 aFlags);
539 NS_ENSURE_TRUE(result == OK, result);
540 mData = nullptr;
542 return OK;
543 }
545 private:
546 sp<MediaCodec>& mCodec;
547 Vector<sp<ABuffer> >& mBuffers;
548 size_t mIndex;
549 uint8_t* mData;
550 size_t mCapicity;
551 size_t mOffset;
552 };
554 OMXAudioEncoder::~OMXAudioEncoder()
555 {
556 if (mResampler) {
557 speex_resampler_destroy(mResampler);
558 mResampler = nullptr;
559 }
560 }
562 nsresult
563 OMXAudioEncoder::Encode(AudioSegment& aSegment, int aInputFlags)
564 {
565 #ifndef MOZ_SAMPLE_TYPE_S16
566 #error MediaCodec accepts only 16-bit PCM data.
567 #endif
569 MOZ_ASSERT(mStarted, "Configure() should be called before Encode().");
571 size_t numSamples = aSegment.GetDuration();
573 // Get input buffer.
574 InputBufferHelper buffer(mCodec, mInputBufs);
575 status_t result = buffer.Dequeue();
576 if (result == -EAGAIN) {
577 // All input buffers are full. Caller can try again later after consuming
578 // some output buffers.
579 return NS_OK;
580 }
581 NS_ENSURE_TRUE(result == OK, NS_ERROR_FAILURE);
583 size_t sourceSamplesCopied = 0; // Number of copied samples.
585 if (numSamples > 0) {
586 // Copy input PCM data to input buffer until queue is empty.
587 AudioSegment::ChunkIterator iter(const_cast<AudioSegment&>(aSegment));
588 while (!iter.IsEnded()) {
589 AudioChunk chunk = *iter;
590 size_t sourceSamplesToCopy = chunk.GetDuration(); // Number of samples to copy.
591 size_t bytesToCopy = sourceSamplesToCopy * mChannels *
592 sizeof(AudioDataValue) * mResamplingRatio;
593 if (bytesToCopy > buffer.AvailableSize()) {
594 // Not enough space left in input buffer. Send it to encoder and get a
595 // new one.
596 result = buffer.Enqueue(mTimestamp, aInputFlags & ~BUFFER_EOS);
597 NS_ENSURE_TRUE(result == OK, NS_ERROR_FAILURE);
599 result = buffer.Dequeue();
600 if (result == -EAGAIN) {
601 // All input buffers are full. Caller can try again later after
602 // consuming some output buffers.
603 aSegment.RemoveLeading(sourceSamplesCopied);
604 return NS_OK;
605 }
607 mTimestamp += sourceSamplesCopied * mSampleDuration;
608 sourceSamplesCopied = 0;
610 NS_ENSURE_TRUE(result == OK, NS_ERROR_FAILURE);
611 }
613 AudioDataValue* dst = reinterpret_cast<AudioDataValue*>(buffer.GetPointer());
614 uint32_t dstSamplesCopied = sourceSamplesToCopy;
615 if (!chunk.IsNull()) {
616 if (mResampler) {
617 nsAutoTArray<AudioDataValue, 9600> pcm;
618 pcm.SetLength(bytesToCopy);
619 // Append the interleaved data to input buffer.
620 AudioTrackEncoder::InterleaveTrackData(chunk, sourceSamplesToCopy,
621 mChannels,
622 pcm.Elements());
623 uint32_t inframes = sourceSamplesToCopy;
624 short* in = reinterpret_cast<short*>(pcm.Elements());
625 speex_resampler_process_interleaved_int(mResampler, in, &inframes,
626 dst, &dstSamplesCopied);
627 } else {
628 AudioTrackEncoder::InterleaveTrackData(chunk, sourceSamplesToCopy,
629 mChannels,
630 dst);
631 dstSamplesCopied = sourceSamplesToCopy * mChannels;
632 }
633 } else {
634 // Silence.
635 memset(dst, 0, mResamplingRatio * sourceSamplesToCopy * sizeof(AudioDataValue));
636 }
638 sourceSamplesCopied += sourceSamplesToCopy;
639 buffer.IncreaseOffset(dstSamplesCopied * sizeof(AudioDataValue));
640 iter.Next();
641 }
642 if (sourceSamplesCopied > 0) {
643 aSegment.RemoveLeading(sourceSamplesCopied);
644 }
645 } else if (aInputFlags & BUFFER_EOS) {
646 // No audio data left in segment but we still have to feed something to
647 // MediaCodec in order to notify EOS.
648 size_t bytesToCopy = mChannels * sizeof(AudioDataValue);
649 memset(buffer.GetPointer(), 0, bytesToCopy);
650 buffer.IncreaseOffset(bytesToCopy);
651 sourceSamplesCopied = 1;
652 }
654 if (sourceSamplesCopied > 0) {
655 int flags = aInputFlags;
656 if (aSegment.GetDuration() > 0) {
657 // Don't signal EOS until source segment is empty.
658 flags &= ~BUFFER_EOS;
659 }
660 result = buffer.Enqueue(mTimestamp, flags);
661 NS_ENSURE_TRUE(result == OK, NS_ERROR_FAILURE);
663 mTimestamp += sourceSamplesCopied * mSampleDuration;
664 }
666 return NS_OK;
667 }
669 // Generate decoder config descriptor (defined in ISO/IEC 14496-1 8.3.4.1) for
670 // AAC. The hard-coded bytes are copied from
671 // MPEG4Writer::Track::writeMp4aEsdsBox() implementation in libstagefright.
672 status_t
673 OMXAudioEncoder::AppendDecoderConfig(nsTArray<uint8_t>* aOutputBuf,
674 ABuffer* aData)
675 {
676 MOZ_ASSERT(aData);
678 const size_t csdSize = aData->size();
680 // See
681 // http://wiki.multimedia.cx/index.php?title=Understanding_AAC#Packaging.2FEncapsulation_And_Setup_Data
682 // AAC decoder specific descriptor contains 2 bytes.
683 NS_ENSURE_TRUE(csdSize == 2, ERROR_MALFORMED);
684 // Encoder output must be consistent with kAACFrameDuration:
685 // 14th bit (frame length flag) == 0 => 1024 (kAACFrameDuration) samples.
686 NS_ENSURE_TRUE((aData->data()[1] & 0x04) == 0, ERROR_MALFORMED);
688 // Decoder config descriptor
689 const uint8_t decConfig[] = {
690 0x04, // Decoder config descriptor tag.
691 15 + csdSize, // Size: following bytes + csd size.
692 0x40, // Object type: MPEG-4 audio.
693 0x15, // Stream type: audio, reserved: 1.
694 0x00, 0x03, 0x00, // Buffer size: 768 (kAACFrameSize).
695 0x00, 0x01, 0x77, 0x00, // Max bitrate: 96000 (kAACBitrate).
696 0x00, 0x01, 0x77, 0x00, // Avg bitrate: 96000 (kAACBitrate).
697 0x05, // Decoder specific descriptor tag.
698 csdSize, // Data size.
699 };
700 // SL config descriptor.
701 const uint8_t slConfig[] = {
702 0x06, // SL config descriptor tag.
703 0x01, // Size.
704 0x02, // Fixed value.
705 };
707 aOutputBuf->SetCapacity(sizeof(decConfig) + csdSize + sizeof(slConfig));
708 aOutputBuf->AppendElements(decConfig, sizeof(decConfig));
709 aOutputBuf->AppendElements(aData->data(), csdSize);
710 aOutputBuf->AppendElements(slConfig, sizeof(slConfig));
712 return OK;
713 }
715 nsresult
716 OMXCodecWrapper::GetNextEncodedFrame(nsTArray<uint8_t>* aOutputBuf,
717 int64_t* aOutputTimestamp,
718 int* aOutputFlags, int64_t aTimeOut)
719 {
720 MOZ_ASSERT(mStarted,
721 "Configure() should be called before GetNextEncodedFrame().");
723 // Dequeue a buffer from output buffers.
724 size_t index = 0;
725 size_t outOffset = 0;
726 size_t outSize = 0;
727 int64_t outTimeUs = 0;
728 uint32_t outFlags = 0;
729 bool retry = false;
730 do {
731 status_t result = mCodec->dequeueOutputBuffer(&index, &outOffset, &outSize,
732 &outTimeUs, &outFlags,
733 aTimeOut);
734 switch (result) {
735 case OK:
736 break;
737 case INFO_OUTPUT_BUFFERS_CHANGED:
738 // Update our references to new buffers.
739 result = mCodec->getOutputBuffers(&mOutputBufs);
740 // Get output from a new buffer.
741 retry = true;
742 break;
743 case INFO_FORMAT_CHANGED:
744 // It's okay: for encoder, MediaCodec reports this only to inform caller
745 // that there will be a codec config buffer next.
746 return NS_OK;
747 case -EAGAIN:
748 // Output buffer not available. Caller can try again later.
749 return NS_OK;
750 default:
751 CODEC_ERROR("MediaCodec error:%d", result);
752 MOZ_ASSERT(false, "MediaCodec error.");
753 return NS_ERROR_FAILURE;
754 }
755 } while (retry);
757 if (aOutputBuf) {
758 aOutputBuf->Clear();
759 const sp<ABuffer> omxBuf = mOutputBufs.itemAt(index);
760 if (outFlags & MediaCodec::BUFFER_FLAG_CODECCONFIG) {
761 // Codec specific data.
762 if (AppendDecoderConfig(aOutputBuf, omxBuf.get()) != OK) {
763 mCodec->releaseOutputBuffer(index);
764 return NS_ERROR_FAILURE;
765 }
766 } else if ((mCodecType == AMR_NB_ENC) && !mAMRCSDProvided){
767 // OMX AMR codec won't provide csd data, need to generate a fake one.
768 nsRefPtr<EncodedFrame> audiodata = new EncodedFrame();
769 // Decoder config descriptor
770 const uint8_t decConfig[] = {
771 0x0, 0x0, 0x0, 0x0, // vendor: 4 bytes
772 0x0, // decoder version
773 0x83, 0xFF, // mode set: all enabled
774 0x00, // mode change period
775 0x01, // frames per sample
776 };
777 aOutputBuf->AppendElements(decConfig, sizeof(decConfig));
778 outFlags |= MediaCodec::BUFFER_FLAG_CODECCONFIG;
779 mAMRCSDProvided = true;
780 } else {
781 AppendFrame(aOutputBuf, omxBuf->data(), omxBuf->size());
782 }
783 }
784 mCodec->releaseOutputBuffer(index);
786 if (aOutputTimestamp) {
787 *aOutputTimestamp = outTimeUs;
788 }
790 if (aOutputFlags) {
791 *aOutputFlags = outFlags;
792 }
794 return NS_OK;
795 }
797 }