OSDN Git Service

Support AMR, G.711 and vorbis audio in ACodec and friends.
authorAndreas Huber <andih@google.com>
Wed, 28 Sep 2011 19:37:36 +0000 (12:37 -0700)
committerAndreas Huber <andih@google.com>
Wed, 28 Sep 2011 19:37:36 +0000 (12:37 -0700)
Change-Id: I08c03219bf2d60fc5c6e89957bd4b4c615570983

cmds/stagefright/sf2.cpp
include/media/stagefright/ACodec.h
media/libstagefright/ACodec.cpp
media/libstagefright/OMXCodec.cpp

index 263ecd1..f547e01 100644 (file)
@@ -46,7 +46,8 @@ struct Controller : public AHandler {
           mDecodeAudio(decodeAudio),
           mSurface(surface),
           mRenderToSurface(renderToSurface),
-          mCodec(new ACodec) {
+          mCodec(new ACodec),
+          mIsVorbis(false) {
         CHECK(!mDecodeAudio || mSurface == NULL);
     }
 
@@ -85,6 +86,12 @@ protected:
                     if (!strncasecmp(mDecodeAudio ? "audio/" : "video/",
                                      mime, 6)) {
                         mSource = extractor->getTrack(i);
+
+                        if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
+                            mIsVorbis = true;
+                        } else {
+                            mIsVorbis = false;
+                        }
                         break;
                     }
                 }
@@ -227,6 +234,7 @@ private:
     bool mRenderToSurface;
     sp<ACodec> mCodec;
     sp<MediaSource> mSource;
+    bool mIsVorbis;
 
     Vector<sp<ABuffer> > mCSD;
     size_t mCSDIndex;
@@ -369,6 +377,20 @@ private:
 
             buffer->meta()->setInt32("csd", true);
             mCSD.push(buffer);
+        } else if (meta->findData(kKeyVorbisInfo, &type, &data, &size)) {
+            sp<ABuffer> buffer = new ABuffer(size);
+            memcpy(buffer->data(), data, size);
+
+            buffer->meta()->setInt32("csd", true);
+            mCSD.push(buffer);
+
+            CHECK(meta->findData(kKeyVorbisBooks, &type, &data, &size));
+
+            buffer = new ABuffer(size);
+            memcpy(buffer->data(), data, size);
+
+            buffer->meta()->setInt32("csd", true);
+            mCSD.push(buffer);
         }
 
         int32_t maxInputSize;
@@ -423,10 +445,17 @@ private:
                     }
                 }
 
-                if (inBuffer->range_length() > sizeLeft) {
+                size_t sizeNeeded = inBuffer->range_length();
+                if (mIsVorbis) {
+                    // Vorbis data is suffixed with the number of
+                    // valid samples on the page.
+                    sizeNeeded += sizeof(int32_t);
+                }
+
+                if (sizeNeeded > sizeLeft) {
                     if (outBuffer->size() == 0) {
                         LOGE("Unable to fit even a single input buffer of size %d.",
-                             inBuffer->range_length());
+                             sizeNeeded);
                     }
                     CHECK_GT(outBuffer->size(), 0u);
 
@@ -448,10 +477,22 @@ private:
                         + inBuffer->range_offset(),
                        inBuffer->range_length());
 
+                if (mIsVorbis) {
+                    int32_t numPageSamples;
+                    if (!inBuffer->meta_data()->findInt32(
+                                kKeyValidSamples, &numPageSamples)) {
+                        numPageSamples = -1;
+                    }
+
+                    memcpy(outBuffer->data()
+                            + outBuffer->size() + inBuffer->range_length(),
+                           &numPageSamples, sizeof(numPageSamples));
+                }
+
                 outBuffer->setRange(
-                        0, outBuffer->size() + inBuffer->range_length());
+                        0, outBuffer->size() + sizeNeeded);
 
-                sizeLeft -= inBuffer->range_length();
+                sizeLeft -= sizeNeeded;
 
                 inBuffer->release();
                 inBuffer = NULL;
index 9da9907..5822877 100644 (file)
@@ -151,6 +151,12 @@ private:
             OMX_VIDEO_CODINGTYPE compressionFormat);
 
     status_t setupAACDecoder(int32_t numChannels, int32_t sampleRate);
+    status_t setupAMRDecoder(bool isWAMR);
+    status_t setupG711Decoder(int32_t numChannels);
+
+    status_t setupRawAudioFormat(
+            OMX_U32 portIndex, int32_t sampleRate, int32_t numChannels);
+
     status_t setMinBufferSize(OMX_U32 portIndex, size_t size);
 
     status_t initNativeWindow();
index a3746cd..9cb18de 100644 (file)
@@ -687,6 +687,8 @@ void ACodec::setComponentRole(
             "audio_decoder.amrwb", "audio_encoder.amrwb" },
         { MEDIA_MIMETYPE_AUDIO_AAC,
             "audio_decoder.aac", "audio_encoder.aac" },
+        { MEDIA_MIMETYPE_AUDIO_VORBIS,
+            "audio_decoder.vorbis", "audio_encoder.vorbis" },
         { MEDIA_MIMETYPE_VIDEO_AVC,
             "video_decoder.avc", "video_encoder.avc" },
         { MEDIA_MIMETYPE_VIDEO_MPEG4,
@@ -750,9 +752,19 @@ void ACodec::configureCodec(
         CHECK(msg->findInt32("sample-rate", &sampleRate));
 
         CHECK_EQ(setupAACDecoder(numChannels, sampleRate), (status_t)OK);
-    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
-    } else {
-        TRESPASS();
+    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)) {
+        CHECK_EQ(setupAMRDecoder(false /* isWAMR */), (status_t)OK);
+    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) {
+        CHECK_EQ(setupAMRDecoder(true /* isWAMR */), (status_t)OK);
+    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_G711_ALAW)
+            || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_G711_MLAW)) {
+        // These are PCM-like formats with a fixed sample rate but
+        // a variable number of channels.
+
+        int32_t numChannels;
+        CHECK(msg->findInt32("channel-count", &numChannels));
+
+        CHECK_EQ(setupG711Decoder(numChannels), (status_t)OK);
     }
 
     int32_t maxInputSize;
@@ -824,6 +836,84 @@ status_t ACodec::setupAACDecoder(int32_t numChannels, int32_t sampleRate) {
     return err;
 }
 
+status_t ACodec::setupAMRDecoder(bool isWAMR) {
+    OMX_AUDIO_PARAM_AMRTYPE def;
+    InitOMXParams(&def);
+    def.nPortIndex = kPortIndexInput;
+
+    status_t err =
+        mOMX->getParameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
+
+    if (err != OK) {
+        return err;
+    }
+
+    def.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
+
+    def.eAMRBandMode =
+        isWAMR ? OMX_AUDIO_AMRBandModeWB0 : OMX_AUDIO_AMRBandModeNB0;
+
+    return mOMX->setParameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
+}
+
+status_t ACodec::setupG711Decoder(int32_t numChannels) {
+    return setupRawAudioFormat(
+            kPortIndexInput, 8000 /* sampleRate */, numChannels);
+}
+
+status_t ACodec::setupRawAudioFormat(
+        OMX_U32 portIndex, int32_t sampleRate, int32_t numChannels) {
+    OMX_PARAM_PORTDEFINITIONTYPE def;
+    InitOMXParams(&def);
+    def.nPortIndex = portIndex;
+
+    status_t err = mOMX->getParameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+
+    if (err != OK) {
+        return err;
+    }
+
+    def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
+
+    err = mOMX->setParameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+
+    if (err != OK) {
+        return err;
+    }
+
+    OMX_AUDIO_PARAM_PCMMODETYPE pcmParams;
+    InitOMXParams(&pcmParams);
+    pcmParams.nPortIndex = portIndex;
+
+    err = mOMX->getParameter(
+            mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
+
+    if (err != OK) {
+        return err;
+    }
+
+    pcmParams.nChannels = numChannels;
+    pcmParams.eNumData = OMX_NumericalDataSigned;
+    pcmParams.bInterleaved = OMX_TRUE;
+    pcmParams.nBitPerSample = 16;
+    pcmParams.nSamplingRate = sampleRate;
+    pcmParams.ePCMMode = OMX_AUDIO_PCMModeLinear;
+
+    if (numChannels == 1) {
+        pcmParams.eChannelMapping[0] = OMX_AUDIO_ChannelCF;
+    } else {
+        CHECK_EQ(numChannels, 2);
+
+        pcmParams.eChannelMapping[0] = OMX_AUDIO_ChannelLF;
+        pcmParams.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
+    }
+
+    return mOMX->setParameter(
+            mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
+}
+
 status_t ACodec::setVideoPortFormatType(
         OMX_U32 portIndex,
         OMX_VIDEO_CODINGTYPE compressionFormat,
index 9eb1469..e94a8d7 100755 (executable)
@@ -1485,6 +1485,8 @@ void OMXCodec::setComponentRole(
             "audio_decoder.amrwb", "audio_encoder.amrwb" },
         { MEDIA_MIMETYPE_AUDIO_AAC,
             "audio_decoder.aac", "audio_encoder.aac" },
+        { MEDIA_MIMETYPE_AUDIO_VORBIS,
+            "audio_decoder.vorbis", "audio_encoder.vorbis" },
         { MEDIA_MIMETYPE_VIDEO_AVC,
             "video_decoder.avc", "video_encoder.avc" },
         { MEDIA_MIMETYPE_VIDEO_MPEG4,