OSDN Git Service

LibAAH_RTP: Add support for AAC in MP4.
authorJohn Grossman <johngro@google.com>
Sun, 19 Feb 2012 01:46:40 +0000 (17:46 -0800)
committerJohn Grossman <johngro@google.com>
Tue, 21 Feb 2012 19:13:32 +0000 (11:13 -0800)
Change-Id: Ie8298eb9d253fc6ede448da87660a60d23170987

media/libaah_rtp/aah_rx_player.h
media/libaah_rtp/aah_rx_player_substream.cpp
media/libaah_rtp/aah_tx_packet.cpp
media/libaah_rtp/aah_tx_packet.h
media/libaah_rtp/aah_tx_player.cpp
media/libaah_rtp/aah_tx_player.h

index 28665ff..53361b4 100644 (file)
@@ -198,14 +198,15 @@ class AAH_RXPlayer : public MediaPlayerInterface {
         status_t getStatus() const { return status_; }
 
       protected:
-        virtual ~Substream() {
-            shutdown();
-        }
+        virtual ~Substream();
 
       private:
         void                cleanupDecoder();
         bool                shouldAbort(const char* log_tag);
         void                processCompletedBuffer();
+        bool                setupSubstreamMeta();
+        bool                setupMP3SubstreamMeta();
+        bool                setupAACSubstreamMeta();
         bool                setupSubstreamType(uint8_t substream_type,
                                                uint8_t codec_type);
 
@@ -216,12 +217,16 @@ class AAH_RXPlayer : public MediaPlayerInterface {
         bool                substream_details_known_;
         uint8_t             substream_type_;
         uint8_t             codec_type_;
+        const char*         codec_mime_type_;
         sp<MetaData>        substream_meta_;
 
         MediaBuffer*        buffer_in_progress_;
         uint32_t            expected_buffer_size_;
         uint32_t            buffer_filled_;
 
+        Vector<uint8_t>     aux_data_in_progress_;
+        uint32_t            aux_data_expected_size_;
+
         sp<AAH_DecoderPump> decoder_;
 
         static int64_t      kAboutToUnderflowThreshold;
index 698b3f9..3e3a95c 100644 (file)
@@ -27,6 +27,9 @@
 #include <media/stagefright/Utils.h>
 
 #include "aah_rx_player.h"
+#include "aah_tx_packet.h"
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
 
 namespace android {
 
@@ -38,6 +41,7 @@ AAH_RXPlayer::Substream::Substream(uint32_t ssrc, OMXClient& omx) {
     substream_details_known_ = false;
     buffer_in_progress_ = NULL;
     status_ = OK;
+    codec_mime_type_ = "";
 
     decoder_ = new AAH_DecoderPump(omx);
     if (decoder_ == NULL) {
@@ -52,6 +56,9 @@ AAH_RXPlayer::Substream::Substream(uint32_t ssrc, OMXClient& omx) {
     cleanupBufferInProgress();
 }
 
+AAH_RXPlayer::Substream::~Substream() {
+    shutdown();
+}
 
 void AAH_RXPlayer::Substream::shutdown() {
     substream_meta_ = NULL;
@@ -69,6 +76,9 @@ void AAH_RXPlayer::Substream::cleanupBufferInProgress() {
     expected_buffer_size_ = 0;
     buffer_filled_ = 0;
     waiting_for_rap_ = true;
+
+    aux_data_in_progress_.clear();
+    aux_data_expected_size_ = 0;
 }
 
 void AAH_RXPlayer::Substream::cleanupDecoder() {
@@ -168,11 +178,7 @@ void AAH_RXPlayer::Substream::processPayloadStart(uint8_t* buf,
     }
 
     // Extract the TRTP length field and sanity check it.
-    uint32_t trtp_len;
-    trtp_len = (static_cast<uint32_t>(buf[2]) << 24) |
-        (static_cast<uint32_t>(buf[3]) << 16) |
-        (static_cast<uint32_t>(buf[4]) <<  8) |
-        static_cast<uint32_t>(buf[5]);
+    uint32_t trtp_len = U32_AT(buf + 2);
     if (trtp_len < min_length) {
         LOGV("TRTP length (%u) is too short to be valid.  Must be at least %u"
                 " bytes.", trtp_len, min_length);
@@ -183,12 +189,9 @@ void AAH_RXPlayer::Substream::processPayloadStart(uint8_t* buf,
     int64_t ts = 0;
     uint32_t parse_offset = 6;
     if (ts_valid) {
-        ts = (static_cast<int64_t>(buf[parse_offset    ]) << 56) |
-            (static_cast<int64_t>(buf[parse_offset + 1]) << 48) |
-            (static_cast<int64_t>(buf[parse_offset + 2]) << 40) |
-            (static_cast<int64_t>(buf[parse_offset + 3]) << 32);
-        ts |= ts_lower;
+        uint32_t ts_upper = U32_AT(buf + parse_offset);
         parse_offset += 4;
+        ts = (static_cast<int64_t>(ts_upper) << 32) | ts_lower;
     }
 
     // Check the flags to see if there is another 24 bytes of timestamp
@@ -245,9 +248,37 @@ void AAH_RXPlayer::Substream::processPayloadStart(uint8_t* buf,
         return;
     }
 
+    // Check for the presence of codec aux data.
     if (flags & 0x10) {
-        LOGV("Dropping TRTP Audio Payload with aux codec data present (only"
-             " handle MP3 right now, and it has no aux data)");
+        min_length += 4;
+        trtp_header_len += 4;
+
+        if (trtp_len < min_length) {
+            LOGV("TRTP length (%u) is too short to be a valid audio payload.  "
+                 "Must be at least %u bytes.", trtp_len, min_length);
+            return;
+        }
+
+        if (amt < min_length) {
+            LOGV("TRTP porttion of RTP payload (%u bytes) too small to contain"
+                 " entire TRTP header.  TRTP does not currently support"
+                 " fragmenting TRTP headers across RTP payloads", amt);
+            return;
+        }
+
+        aux_data_expected_size_ = U32_AT(buf + parse_offset);
+        aux_data_in_progress_.clear();
+        if (aux_data_in_progress_.capacity() < aux_data_expected_size_) {
+            aux_data_in_progress_.setCapacity(aux_data_expected_size_);
+        }
+    } else {
+        aux_data_expected_size_ = 0;
+    }
+
+    if ((aux_data_expected_size_ + trtp_header_len) > trtp_len) {
+        LOGV("Expected codec aux data length (%u) and TRTP header overhead (%u)"
+             " too large for total TRTP payload length (%u).",
+             aux_data_expected_size_, trtp_header_len, trtp_len);
         return;
     }
 
@@ -255,7 +286,9 @@ void AAH_RXPlayer::Substream::processPayloadStart(uint8_t* buf,
     // the buffer in progress and pack as much payload as we can into it.  If
     // the payload is finished once we are done, go ahead and send the payload
     // to the decoder.
-    expected_buffer_size_ = trtp_len - trtp_header_len;
+    expected_buffer_size_ = trtp_len
+                          - trtp_header_len
+                          - aux_data_expected_size_;
     if (!expected_buffer_size_) {
         LOGV("Dropping TRTP Audio Payload with 0 Access Unit length");
         return;
@@ -263,9 +296,10 @@ void AAH_RXPlayer::Substream::processPayloadStart(uint8_t* buf,
 
     CHECK(amt >= trtp_header_len);
     uint32_t todo = amt - trtp_header_len;
-    if (expected_buffer_size_ < todo) {
+    if ((expected_buffer_size_ + aux_data_expected_size_) < todo) {
         LOGV("Extra data (%u > %u) present in initial TRTP Audio Payload;"
-             " dropping payload.", todo, expected_buffer_size_);
+             " dropping payload.", todo,
+             expected_buffer_size_ + aux_data_expected_size_);
         return;
     }
 
@@ -289,16 +323,32 @@ void AAH_RXPlayer::Substream::processPayloadStart(uint8_t* buf,
 
     // TODO : set this based on the codec type indicated in the TRTP stream.
     // Right now, we only support MP3, so the choice is obvious.
-    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
+    meta->setCString(kKeyMIMEType, codec_mime_type_);
     if (ts_valid) {
         meta->setInt64(kKeyTime, ts);
     }
 
-    if (amt > 0) {
+    // Skip over the header we have already extracted.
+    amt -= trtp_header_len;
+    buf += trtp_header_len;
+
+    // Extract as much of the expected aux data as we can.
+    todo = MIN(aux_data_expected_size_, amt);
+    if (todo) {
+        aux_data_in_progress_.appendArray(buf, todo);
+        buf += todo;
+        amt -= todo;
+    }
+
+    // Extract as much of the expected payload as we can.
+    todo = MIN(expected_buffer_size_, amt);
+    if (todo > 0) {
         uint8_t* tgt =
             reinterpret_cast<uint8_t*>(buffer_in_progress_->data());
-        memcpy(tgt + buffer_filled_, buf + trtp_header_len, todo);
-        buffer_filled_ += amt;
+        memcpy(tgt, buf, todo);
+        buffer_filled_ = amt;
+        buf += todo;
+        amt -= todo;
     }
 
     if (buffer_filled_ >= expected_buffer_size_) {
@@ -318,6 +368,18 @@ void AAH_RXPlayer::Substream::processPayloadCont(uint8_t* buf,
         return;
     }
 
+    CHECK(aux_data_in_progress_.size() <= aux_data_expected_size_);
+    uint32_t aux_left = aux_data_expected_size_ - aux_data_in_progress_.size();
+    if (aux_left) {
+        uint32_t todo = MIN(aux_left, amt);
+        aux_data_in_progress_.appendArray(buf, todo);
+        amt -= todo;
+        buf += todo;
+
+        if (!amt)
+            return;
+    }
+
     CHECK(buffer_filled_ < expected_buffer_size_);
     uint32_t buffer_left = expected_buffer_size_ - buffer_filled_;
     if (amt > buffer_left) {
@@ -340,10 +402,6 @@ void AAH_RXPlayer::Substream::processPayloadCont(uint8_t* buf,
 }
 
 void AAH_RXPlayer::Substream::processCompletedBuffer() {
-    const uint8_t* buffer_data = NULL;
-    int sample_rate;
-    int channel_count;
-    size_t frame_size;
     status_t res;
 
     CHECK(NULL != buffer_in_progress_);
@@ -353,10 +411,91 @@ void AAH_RXPlayer::Substream::processCompletedBuffer() {
         goto bailout;
     }
 
+    // Make sure our metadata used to initialize the decoder has been properly
+    // set up.
+    if (!setupSubstreamMeta())
+        goto bailout;
+
+    // If our decoder has not be set up, do so now.
+    res = decoder_->init(substream_meta_);
+    if (OK != res) {
+        LOGE("Failed to init decoder (res = %d)", res);
+        cleanupDecoder();
+        substream_meta_ = NULL;
+        goto bailout;
+    }
+
+    // Queue the payload for decode.
+    res = decoder_->queueForDecode(buffer_in_progress_);
+
+    if (res != OK) {
+        LOGD("Failed to queue payload for decode, resetting decoder pump!"
+             " (res = %d)", res);
+        status_ = res;
+        cleanupDecoder();
+        cleanupBufferInProgress();
+    }
+
+    // NULL out buffer_in_progress before calling the cleanup helper.
+    //
+    // MediaBuffers use something of a hybrid ref-counting pattern which prevent
+    // the AAH_DecoderPump's input queue from adding their own reference to the
+    // MediaBuffer.  MediaBuffers start life with a reference count of 0, as
+    // well as an observer which starts as NULL.  Before being given an
+    // observer, the ref count cannot be allowed to become non-zero as it will
+    // cause calls to release() to assert.  Basically, before a MediaBuffer has
+    // an observer, they behave like non-ref counted obects where release()
+    // serves the roll of delete.  After a MediaBuffer has an observer, they
+    // become more like ref counted objects where add ref and release can be
+    // used, and when the ref count hits zero, the MediaBuffer is handed off to
+    // the observer.
+    //
+    // Given all of this, when we give the buffer to the decoder pump to wait in
+    // the to-be-processed queue, the decoder cannot add a ref to the buffer as
+    // it would in a traditional ref counting system.  Instead it needs to
+    // "steal" the non-existent ref.  In the case of queue failure, we need to
+    // make certain to release this non-existent reference so that the buffer is
+    // cleaned up during the cleanupBufferInProgress helper.  In the case of a
+    // successful queue operation, we need to make certain that the
+    // cleanupBufferInProgress helper does not release the buffer since it needs
+    // to remain alive in the queue.  We acomplish this by NULLing out the
+    // buffer pointer before calling the cleanup helper.
+    buffer_in_progress_ = NULL;
+
+bailout:
+    cleanupBufferInProgress();
+}
+
+bool AAH_RXPlayer::Substream::setupSubstreamMeta() {
+    switch (codec_type_) {
+        case TRTPAudioPacket::kCodecMPEG1Audio:
+            codec_mime_type_ = MEDIA_MIMETYPE_AUDIO_MPEG;
+            return setupMP3SubstreamMeta();
+
+        case TRTPAudioPacket::kCodecAACAudio:
+            codec_mime_type_ = MEDIA_MIMETYPE_AUDIO_AAC;
+            return setupAACSubstreamMeta();
+
+        default:
+            LOGV("Failed to setup substream metadata for unsupported codec type"
+                 " (%u)", codec_type_);
+            break;
+    }
+
+    return false;
+}
+
+bool AAH_RXPlayer::Substream::setupMP3SubstreamMeta() {
+    const uint8_t* buffer_data = NULL;
+    int sample_rate;
+    int channel_count;
+    size_t frame_size;
+    status_t res;
+
     buffer_data = reinterpret_cast<const uint8_t*>(buffer_in_progress_->data());
     if (buffer_in_progress_->size() < 4) {
         LOGV("MP3 payload too short to contain header, dropping payload.");
-        goto bailout;
+        return false;
     }
 
     // Extract the channel count and the sample rate from the MP3 header.  The
@@ -369,7 +508,7 @@ void AAH_RXPlayer::Substream::processCompletedBuffer() {
                                NULL,
                                NULL)) {
         LOGV("Failed to parse MP3 header in payload, droping payload.");
-        goto bailout;
+        return false;
     }
 
 
@@ -381,8 +520,8 @@ void AAH_RXPlayer::Substream::processCompletedBuffer() {
         substream_meta_ = new MetaData();
 
         if (substream_meta_ == NULL) {
-            LOGE("Failed to allocate MetaData structure for substream");
-            goto bailout;
+            LOGE("Failed to allocate MetaData structure for MP3 substream");
+            return false;
         }
 
         substream_meta_->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
@@ -396,7 +535,7 @@ void AAH_RXPlayer::Substream::processCompletedBuffer() {
 
         if ((prev_channel_count != channel_count) ||
             (prev_sample_rate   != sample_rate)) {
-            LOGW("Format change detected, forcing decoder reset.");
+            LOGW("MP3 format change detected, forcing decoder reset.");
             cleanupDecoder();
 
             substream_meta_->setInt32(kKeyChannelCount, channel_count);
@@ -404,56 +543,87 @@ void AAH_RXPlayer::Substream::processCompletedBuffer() {
         }
     }
 
-    // If our decoder has not be set up, do so now.
-    res = decoder_->init(substream_meta_);
-    if (OK != res) {
-        LOGE("Failed to init decoder (res = %d)", res);
+    return true;
+}
+
+bool AAH_RXPlayer::Substream::setupAACSubstreamMeta() {
+    int32_t sample_rate, channel_cnt;
+    static const size_t overhead = sizeof(sample_rate)
+                                 + sizeof(channel_cnt);
+
+    if (aux_data_in_progress_.size() < overhead) {
+        LOGE("Not enough aux data (%u) to initialize AAC substream decoder",
+                aux_data_in_progress_.size());
+        return false;
+    }
+
+    const uint8_t* aux_data = aux_data_in_progress_.array();
+    size_t aux_data_size = aux_data_in_progress_.size();
+    sample_rate = U32_AT(aux_data);
+    channel_cnt = U32_AT(aux_data + sizeof(sample_rate));
+
+    const uint8_t* esds_data = NULL;
+    size_t esds_data_size = 0;
+    if (aux_data_size > overhead) {
+        esds_data = aux_data + overhead;
+        esds_data_size = aux_data_size - overhead;
+    }
+
+    // Do we already have metadata?  If so, has it changed at all?  If not, then
+    // there should be nothing else to do.  Otherwise, release our old stream
+    // metadata and make new metadata.
+    if (substream_meta_ != NULL) {
+        uint32_t type;
+        const void* data;
+        size_t size;
+        int32_t prev_sample_rate;
+        int32_t prev_channel_count;
+
+        substream_meta_->findInt32(kKeySampleRate,   &prev_sample_rate);
+        substream_meta_->findInt32(kKeyChannelCount, &prev_channel_count);
+
+        // If nothing has changed about the codec aux data (esds, sample rate,
+        // channel count), then we can just do nothing and get out.  Otherwise,
+        // we will need to reset the decoder and make a new metadata object to
+        // deal with the format change.
+        bool hasData = (esds_data != NULL);
+        bool hadData = substream_meta_->findData(kKeyESDS, &type, &data, &size);
+        bool esds_change = (hadData != hasData);
+
+        if (!esds_change && hasData)
+            esds_change = ((size != esds_data_size) ||
+                           memcmp(data, esds_data, size));
+
+        if (!esds_change &&
+            (prev_sample_rate   == sample_rate) &&
+            (prev_channel_count == channel_cnt)) {
+            return true;  // no change, just get out.
+        }
+
+        LOGW("AAC format change detected, forcing decoder reset.");
         cleanupDecoder();
         substream_meta_ = NULL;
-        goto bailout;
     }
 
-    // Queue the payload for decode.
-    res = decoder_->queueForDecode(buffer_in_progress_);
+    CHECK(substream_meta_ == NULL);
 
-    if (res != OK) {
-        LOGD("Failed to queue payload for decode, resetting decoder pump!"
-             " (res = %d)", res);
-        status_ = res;
-        cleanupDecoder();
-        cleanupBufferInProgress();
+    substream_meta_ = new MetaData();
+    if (substream_meta_ == NULL) {
+        LOGE("Failed to allocate MetaData structure for AAC substream");
+        return false;
     }
 
-    // NULL out buffer_in_progress before calling the cleanup helper.
-    //
-    // MediaBuffers use something of a hybrid ref-counting pattern which prevent
-    // the AAH_DecoderPump's input queue from adding their own reference to the
-    // MediaBuffer.  MediaBuffers start life with a reference count of 0, as
-    // well as an observer which starts as NULL.  Before being given an
-    // observer, the ref count cannot be allowed to become non-zero as it will
-    // cause calls to release() to assert.  Basically, before a MediaBuffer has
-    // an observer, they behave like non-ref counted obects where release()
-    // serves the roll of delete.  After a MediaBuffer has an observer, they
-    // become more like ref counted objects where add ref and release can be
-    // used, and when the ref count hits zero, the MediaBuffer is handed off to
-    // the observer.
-    //
-    // Given all of this, when we give the buffer to the decoder pump to wait in
-    // the to-be-processed queue, the decoder cannot add a ref to the buffer as
-    // it would in a traditional ref counting system.  Instead it needs to
-    // "steal" the non-existent ref.  In the case of queue failure, we need to
-    // make certain to release this non-existent reference so that the buffer is
-    // cleaned up during the cleanupBufferInProgress helper.  In the case of a
-    // successful queue operation, we need to make certain that the
-    // cleanupBufferInProgress helper does not release the buffer since it needs
-    // to remain alive in the queue.  We acomplish this by NULLing out the
-    // buffer pointer before calling the cleanup helper.
-    buffer_in_progress_ = NULL;
+    substream_meta_->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
+    substream_meta_->setInt32  (kKeySampleRate,   sample_rate);
+    substream_meta_->setInt32  (kKeyChannelCount, channel_cnt);
 
-bailout:
-    cleanupBufferInProgress();
-}
+    if (esds_data) {
+        substream_meta_->setData(kKeyESDS, kTypeESDS,
+                                 esds_data, esds_data_size);
+    }
 
+    return true;
+}
 
 void AAH_RXPlayer::Substream::processTSTransform(const LinearTransform& trans) {
     if (decoder_ != NULL) {
@@ -471,27 +641,35 @@ bool AAH_RXPlayer::Substream::isAboutToUnderflow() {
 
 bool AAH_RXPlayer::Substream::setupSubstreamType(uint8_t substream_type,
                                                  uint8_t codec_type) {
-    // Sanity check the codec type.  Right now we only support MP3.  Also check
-    // for conflicts with previously delivered codec types.
-    if (substream_details_known_ && (codec_type != codec_type_)) {
-        LOGV("RXed TRTP Payload for SSRC=0x%08x where codec type (%u) does not"
-                " match previously received codec type (%u)",
-                ssrc_, codec_type, codec_type_);
-        return false;
-    }
+    // Sanity check the codec type.  Right now we only support MP3 and AAC.
+    // Also check for conflicts with previously delivered codec types.
+    if (substream_details_known_) {
+        if (codec_type != codec_type_) {
+            LOGV("RXed TRTP Payload for SSRC=0x%08x where codec type (%u) does "
+                 "not match previously received codec type (%u)",
+                 ssrc_, codec_type, codec_type_);
+            return false;
+        }
 
-    if (codec_type != 0x03) {
-        LOGV("RXed TRTP Audio Payload for SSRC=0x%08x with unsupported codec"
-             " type (%u)", ssrc_, codec_type);
-        return false;
+        return true;
     }
 
-    if (!substream_details_known_) {
-        substream_type_ = substream_type;
-        codec_type_ = codec_type;
-        substream_details_known_ = true;
+    switch (codec_type) {
+        // MP3 and AAC are all we support right now.
+        case TRTPAudioPacket::kCodecMPEG1Audio:
+        case TRTPAudioPacket::kCodecAACAudio:
+            break;
+
+        default:
+            LOGV("RXed TRTP Audio Payload for SSRC=0x%08x with unsupported"
+                 " codec type (%u)", ssrc_, codec_type);
+            return false;
     }
 
+    substream_type_ = substream_type;
+    codec_type_ = codec_type;
+    substream_details_known_ = true;
+
     return true;
 }
 
index f3e15e2..c7ad3e0 100644 (file)
@@ -142,12 +142,18 @@ void TRTPAudioPacket::setVolume(uint8_t val) {
     mVolume = val;
 }
 
-void TRTPAudioPacket::setAccessUnitData(void* data, int len) {
+void TRTPAudioPacket::setAccessUnitData(const void* data, size_t len) {
     CHECK(!mIsPacked);
     mAccessUnitData = data;
     mAccessUnitLen = len;
 }
 
+void TRTPAudioPacket::setAuxData(const void* data, size_t len) {
+    CHECK(!mIsPacked);
+    mAuxData = data;
+    mAuxDataLen = len;
+}
+
 /*** TRTP control packet properties ***/
 
 void TRTPControlPacket::setCommandID(TRTPCommandID val) {
@@ -232,6 +238,7 @@ bool TRTPAudioPacket::pack() {
     }
 
     int packetLen = kRTPHeaderLen +
+                    mAuxDataLen +
                     mAccessUnitLen +
                     TRTPHeaderLen();
 
@@ -249,16 +256,24 @@ bool TRTPAudioPacket::pack() {
     mPacketLen = packetLen;
 
     uint8_t* cur = mPacket;
+    bool hasAux = mAuxData && mAuxDataLen;
+    uint8_t flags = (static_cast<int>(hasAux) << 4) |
+                    (static_cast<int>(mRandomAccessPoint) << 3) |
+                    (static_cast<int>(mDropable) << 2) |
+                    (static_cast<int>(mDiscontinuity) << 1) |
+                    (static_cast<int>(mEndOfStream));
 
     writeTRTPHeader(cur, true, packetLen);
     writeU8(cur, mCodecType);
-    writeU8(cur,
-            (static_cast<int>(mRandomAccessPoint) << 3) |
-            (static_cast<int>(mDropable) << 2) |
-            (static_cast<int>(mDiscontinuity) << 1) |
-            (static_cast<int>(mEndOfStream)));
+    writeU8(cur, flags);
     writeU8(cur, mVolume);
 
+    if (hasAux) {
+        writeU32(cur, mAuxDataLen);
+        memcpy(cur, mAuxData, mAuxDataLen);
+        cur += mAuxDataLen;
+    }
+
     memcpy(cur, mAccessUnitData, mAccessUnitLen);
 
     mIsPacked = true;
@@ -293,12 +308,10 @@ int TRTPAudioPacket::TRTPHeaderLen() const {
     }
 
 
-    // TODO : properly compute aux data length.  Currently, nothing
-    // uses aux data, so its length is always 0.
-    int auxDataLength = 0;
+    int auxDataLenField = (NULL != mAuxData) ? sizeof(uint32_t) : 0;
     return TRTPPacket::TRTPHeaderLen() +
            3 +
-           auxDataLength +
+           auxDataLenField +
            pcmParamLength;
 }
 
index c5f6285..62436a0 100644 (file)
@@ -126,13 +126,17 @@ class TRTPAudioPacket : public TRTPPacket {
         , mDiscontinuity(false)
         , mEndOfStream(false)
         , mVolume(0)
-        , mAccessUnitData(NULL) { }
+        , mAccessUnitData(NULL)
+        , mAccessUnitLen(0)
+        , mAuxData(NULL)
+        , mAuxDataLen(0) { }
 
     enum TRTPAudioCodecType {
         kCodecInvalid = 0,
         kCodecPCMBigEndian = 1,
         kCodecPCMLittleEndian = 2,
         kCodecMPEG1Audio = 3,
+        kCodecAACAudio = 4,
     };
 
     void setCodecType(TRTPAudioCodecType val);
@@ -141,7 +145,8 @@ class TRTPAudioPacket : public TRTPPacket {
     void setDiscontinuity(bool val);
     void setEndOfStream(bool val);
     void setVolume(uint8_t val);
-    void setAccessUnitData(void* data, int len);
+    void setAccessUnitData(const void* data, size_t len);
+    void setAuxData(const void* data, size_t len);
 
     virtual bool pack();
 
@@ -155,8 +160,10 @@ class TRTPAudioPacket : public TRTPPacket {
     bool mDiscontinuity;
     bool mEndOfStream;
     uint8_t mVolume;
-    void* mAccessUnitData;
-    int mAccessUnitLen;
+    const void* mAccessUnitData;
+    size_t mAccessUnitLen;
+    const void* mAuxData;
+    size_t mAuxDataLen;
 };
 
 class TRTPControlPacket : public TRTPPacket {
index 7b1d658..6407074 100644 (file)
@@ -28,6 +28,7 @@
 #include <media/stagefright/FileSource.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
 #include <utils/Timers.h>
 
@@ -98,6 +99,8 @@ AAH_TXPlayer::AAH_TXPlayer()
     mPumpAudioEvent = new AAH_TXEvent(this, &AAH_TXPlayer::onPumpAudio);
     mPumpAudioEventPending = false;
 
+    mAudioCodecData = NULL;
+
     reset();
 }
 
@@ -398,7 +401,76 @@ void AAH_TXPlayer::onPrepareAsyncEvent() {
         }
     }
 
-    mAudioSource->getFormat()->findInt64(kKeyDuration, &mDurationUs);
+    mAudioFormat = mAudioSource->getFormat();
+    if (!mAudioFormat->findInt64(kKeyDuration, &mDurationUs))
+        mDurationUs = 1;
+
+    const char* mime_type = NULL;
+    if (!mAudioFormat->findCString(kKeyMIMEType, &mime_type)) {
+        LOGE("Failed to find audio substream MIME type during prepare.");
+        abortPrepare(BAD_VALUE);
+        return;
+    }
+
+    if (!strcmp(mime_type, MEDIA_MIMETYPE_AUDIO_MPEG)) {
+        mAudioCodec = TRTPAudioPacket::kCodecMPEG1Audio;
+    } else
+    if (!strcmp(mime_type, MEDIA_MIMETYPE_AUDIO_AAC)) {
+        mAudioCodec = TRTPAudioPacket::kCodecAACAudio;
+
+        uint32_t type;
+        int32_t  sample_rate;
+        int32_t  channel_count;
+        const void* esds_data;
+        size_t esds_len;
+
+        if (!mAudioFormat->findInt32(kKeySampleRate, &sample_rate)) {
+            LOGE("Failed to find sample rate for AAC substream.");
+            abortPrepare(BAD_VALUE);
+            return;
+        }
+
+        if (!mAudioFormat->findInt32(kKeyChannelCount, &channel_count)) {
+            LOGE("Failed to find channel count for AAC substream.");
+            abortPrepare(BAD_VALUE);
+            return;
+        }
+
+        if (!mAudioFormat->findData(kKeyESDS, &type, &esds_data, &esds_len)) {
+            LOGE("Failed to find codec init data for AAC substream.");
+            abortPrepare(BAD_VALUE);
+            return;
+        }
+
+        CHECK(NULL == mAudioCodecData);
+        mAudioCodecDataSize = esds_len
+                            + sizeof(sample_rate)
+                            + sizeof(channel_count);
+        mAudioCodecData = new uint8_t[mAudioCodecDataSize];
+        if (NULL == mAudioCodecData) {
+            LOGE("Failed to allocate %u bytes for AAC substream codec aux"
+                 " data.", mAudioCodecDataSize);
+            mAudioCodecDataSize = 0;
+            abortPrepare(BAD_VALUE);
+            return;
+        }
+
+        uint8_t* tmp = mAudioCodecData;
+        tmp[0] = static_cast<uint8_t>((sample_rate   >> 24) & 0xFF);
+        tmp[1] = static_cast<uint8_t>((sample_rate   >> 16) & 0xFF);
+        tmp[2] = static_cast<uint8_t>((sample_rate   >>  8) & 0xFF);
+        tmp[3] = static_cast<uint8_t>((sample_rate        ) & 0xFF);
+        tmp[4] = static_cast<uint8_t>((channel_count >> 24) & 0xFF);
+        tmp[5] = static_cast<uint8_t>((channel_count >> 16) & 0xFF);
+        tmp[6] = static_cast<uint8_t>((channel_count >>  8) & 0xFF);
+        tmp[7] = static_cast<uint8_t>((channel_count      ) & 0xFF);
+
+        memcpy(tmp + 8, esds_data, esds_len);
+    } else {
+        LOGE("Unsupported MIME type \"%s\" in audio substream", mime_type);
+        abortPrepare(BAD_VALUE);
+        return;
+    }
 
     status_t err = mAudioSource->start();
     if (err != OK) {
@@ -666,6 +738,11 @@ void AAH_TXPlayer::reset_l() {
         mAudioSource->stop();
     }
     mAudioSource.clear();
+    mAudioCodec = TRTPAudioPacket::kCodecInvalid;
+    mAudioFormat = NULL;
+    delete[] mAudioCodecData;
+    mAudioCodecData = NULL;
+    mAudioCodecDataSize = 0;
 
     mFlags = 0;
     mExtractorFlags = 0;
@@ -1078,14 +1155,24 @@ void AAH_TXPlayer::onPumpAudio() {
         packet->setPTS(mediaTimeUs);
         packet->setSubstreamID(1);
 
-        packet->setCodecType(TRTPAudioPacket::kCodecMPEG1Audio);
+        packet->setCodecType(mAudioCodec);
         packet->setVolume(mTRTPVolume);
         // TODO : introduce a throttle for this so we can control the
         // frequency with which transforms get sent.
         packet->setClockTransform(mCurrentClockTransform);
         packet->setAccessUnitData(data, mediaBuffer->range_length());
+
+        // TODO : while its pretty much universally true that audio ES payloads
+        // are all RAPs across all codecs, it might be a good idea to throttle
+        // the frequency with which we send codec out of band data to the RXers.
+        // If/when we do, we need to flag only those payloads which have
+        // required out of band data attached to them as RAPs.
         packet->setRandomAccessPoint(true);
 
+        if (mAudioCodecData && mAudioCodecDataSize) {
+            packet->setAuxData(mAudioCodecData, mAudioCodecDataSize);
+        }
+
         queuePacketToSender_l(packet);
         mediaBuffer->release();
 
index 6bae5f0..b45a661 100644 (file)
@@ -153,6 +153,11 @@ class AAH_TXPlayer : public MediaPlayerHWInterface {
     sp<NuCachedSource2> mCachedSource;
 
     sp<MediaSource> mAudioSource;
+    TRTPAudioPacket::TRTPAudioCodecType mAudioCodec;
+    sp<MetaData> mAudioFormat;
+    uint8_t* mAudioCodecData;
+    size_t mAudioCodecDataSize;
+
     int64_t mDurationUs;
     int64_t mBitrate;