content/media/omx/OMXCodecWrapper.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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 }

mercurial