summaryrefslogtreecommitdiffstats
path: root/media/libaah_rtp/aah_rx_player_substream.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'media/libaah_rtp/aah_rx_player_substream.cpp')
-rw-r--r--media/libaah_rtp/aah_rx_player_substream.cpp677
1 files changed, 0 insertions, 677 deletions
diff --git a/media/libaah_rtp/aah_rx_player_substream.cpp b/media/libaah_rtp/aah_rx_player_substream.cpp
deleted file mode 100644
index 18b0e2b..0000000
--- a/media/libaah_rtp/aah_rx_player_substream.cpp
+++ /dev/null
@@ -1,677 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "LibAAH_RTP"
-//#define LOG_NDEBUG 0
-
-#include <utils/Log.h>
-
-#include <include/avc_utils.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/OMXCodec.h>
-#include <media/stagefright/Utils.h>
-
-#include "aah_rx_player.h"
-#include "aah_tx_packet.h"
-
-inline uint32_t min(uint32_t a, uint32_t b) {
- return (a < b ? a : b);
-}
-
-namespace android {
-
-int64_t AAH_RXPlayer::Substream::kAboutToUnderflowThreshold =
- 50ull * 1000;
-
-AAH_RXPlayer::Substream::Substream(uint32_t ssrc, OMXClient& omx) {
- ssrc_ = ssrc;
- substream_details_known_ = false;
- buffer_in_progress_ = NULL;
- status_ = OK;
- codec_mime_type_ = "";
-
- decoder_ = new AAH_DecoderPump(omx);
- if (decoder_ == NULL) {
- ALOGE("%s failed to allocate decoder pump!", __PRETTY_FUNCTION__);
- }
- if (OK != decoder_->initCheck()) {
- ALOGE("%s failed to initialize decoder pump!", __PRETTY_FUNCTION__);
- }
-
- // cleanupBufferInProgress will reset most of the internal state variables.
- // Just need to make sure that buffer_in_progress_ is NULL before calling.
- cleanupBufferInProgress();
-}
-
-AAH_RXPlayer::Substream::~Substream() {
- shutdown();
-}
-
-void AAH_RXPlayer::Substream::shutdown() {
- substream_meta_ = NULL;
- status_ = OK;
- cleanupBufferInProgress();
- cleanupDecoder();
-}
-
-void AAH_RXPlayer::Substream::cleanupBufferInProgress() {
- if (NULL != buffer_in_progress_) {
- buffer_in_progress_->release();
- buffer_in_progress_ = NULL;
- }
-
- 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() {
- if (decoder_ != NULL) {
- decoder_->shutdown();
- }
-}
-
-bool AAH_RXPlayer::Substream::shouldAbort(const char* log_tag) {
- // If we have already encountered a fatal error, do nothing. We are just
- // waiting for our owner to shut us down now.
- if (OK != status_) {
- ALOGV("Skipping %s, substream has encountered fatal error (%d).",
- log_tag, status_);
- return true;
- }
-
- return false;
-}
-
-void AAH_RXPlayer::Substream::processPayloadStart(uint8_t* buf,
- uint32_t amt,
- int32_t ts_lower) {
- uint32_t min_length = 6;
-
- if (shouldAbort(__PRETTY_FUNCTION__)) {
- return;
- }
-
- // Do we have a buffer in progress already? If so, abort the buffer. In
- // theory, this should never happen. If there were a discontinutity in the
- // stream, the discon in the seq_nos at the RTP level should have already
- // triggered a cleanup of the buffer in progress. To see a problem at this
- // level is an indication either of a bug in the transmitter, or some form
- // of terrible corruption/tampering on the wire.
- if (NULL != buffer_in_progress_) {
- ALOGE("processPayloadStart is aborting payload already in progress.");
- cleanupBufferInProgress();
- }
-
- // Parse enough of the header to know where we stand. Since this is a
- // payload start, it should begin with a TRTP header which has to be at
- // least 6 bytes long.
- if (amt < min_length) {
- ALOGV("Discarding payload too short to contain TRTP header (len = %u)",
- amt);
- return;
- }
-
- // Check the TRTP version number.
- if (0x01 != buf[0]) {
- ALOGV("Unexpected TRTP version (%u) in header. Expected %u.",
- buf[0], 1);
- return;
- }
-
- // Extract the substream type field and make sure its one we understand (and
- // one that does not conflict with any previously received substream type.
- uint8_t header_type = (buf[1] >> 4) & 0xF;
- switch (header_type) {
- case TRTPPacket::kHeaderTypeAudio:
- // Audio, yay! Just break. We understand audio payloads.
- break;
- case TRTPPacket::kHeaderTypeVideo:
- ALOGV("RXed packet with unhandled TRTP header type (Video).");
- return;
- case TRTPPacket::kHeaderTypeSubpicture:
- ALOGV("RXed packet with unhandled TRTP header type (Subpicture).");
- return;
- case TRTPPacket::kHeaderTypeControl:
- ALOGV("RXed packet with unhandled TRTP header type (Control).");
- return;
- default:
- ALOGV("RXed packet with unhandled TRTP header type (%u).",
- header_type);
- return;
- }
-
- if (substream_details_known_ && (header_type != substream_type_)) {
- ALOGV("RXed TRTP Payload for SSRC=0x%08x where header type (%u) does"
- " not match previously received header type (%u)",
- ssrc_, header_type, substream_type_);
- return;
- }
-
- // Check the flags to see if there is another 32 bits of timestamp present.
- uint32_t trtp_header_len = 6;
- bool ts_valid = buf[1] & TRTPPacket::kFlag_TSValid;
- if (ts_valid) {
- min_length += 4;
- trtp_header_len += 4;
- if (amt < min_length) {
- ALOGV("Discarding payload too short to contain TRTP timestamp"
- " (len = %u)", amt);
- return;
- }
- }
-
- // Extract the TRTP length field and sanity check it.
- uint32_t trtp_len = U32_AT(buf + 2);
- if (trtp_len < min_length) {
- ALOGV("TRTP length (%u) is too short to be valid. Must be at least %u"
- " bytes.", trtp_len, min_length);
- return;
- }
-
- // Extract the rest of the timestamp field if valid.
- int64_t ts = 0;
- uint32_t parse_offset = 6;
- if (ts_valid) {
- 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
- // transformation present.
- if (buf[1] & TRTPPacket::kFlag_TSTransformPresent) {
- min_length += 24;
- parse_offset += 24;
- trtp_header_len += 24;
- if (amt < min_length) {
- ALOGV("Discarding payload too short to contain TRTP timestamp"
- " transformation (len = %u)", amt);
- return;
- }
- }
-
- // TODO : break the parsing into individual parsers for the different
- // payload types (audio, video, etc).
- //
- // At this point in time, we know that this is audio. Go ahead and parse
- // the basic header, check the codec type, and find the payload portion of
- // the packet.
- min_length += 3;
- if (trtp_len < min_length) {
- ALOGV("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) {
- ALOGV("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;
- }
-
- uint8_t codec_type = buf[parse_offset ];
- uint8_t flags = buf[parse_offset + 1];
- uint8_t volume = buf[parse_offset + 2];
- parse_offset += 3;
- trtp_header_len += 3;
-
- if (!setupSubstreamType(header_type, codec_type)) {
- return;
- }
-
- if (decoder_ != NULL) {
- decoder_->setRenderVolume(volume);
- }
-
- if (waiting_for_rap_ && !(flags & TRTPAudioPacket::kFlag_RandomAccessPoint)) {
- ALOGV("Dropping non-RAP TRTP Audio Payload while waiting for RAP.");
- return;
- }
-
- // Check for the presence of codec aux data.
- if (flags & TRTPAudioPacket::kFlag_AuxLengthPresent) {
- min_length += 4;
- trtp_header_len += 4;
-
- if (trtp_len < min_length) {
- ALOGV("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) {
- ALOGV("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) {
- ALOGV("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;
- }
-
- // OK - everything left is just payload. Compute the payload size, start
- // 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
- - aux_data_expected_size_;
- if (!expected_buffer_size_) {
- ALOGV("Dropping TRTP Audio Payload with 0 Access Unit length");
- return;
- }
-
- CHECK(amt >= trtp_header_len);
- uint32_t todo = amt - trtp_header_len;
- if ((expected_buffer_size_ + aux_data_expected_size_) < todo) {
- ALOGV("Extra data (%u > %u) present in initial TRTP Audio Payload;"
- " dropping payload.", todo,
- expected_buffer_size_ + aux_data_expected_size_);
- return;
- }
-
- buffer_filled_ = 0;
- buffer_in_progress_ = new MediaBuffer(expected_buffer_size_);
- if ((NULL == buffer_in_progress_) ||
- (NULL == buffer_in_progress_->data())) {
- ALOGV("Failed to allocate MediaBuffer of length %u",
- expected_buffer_size_);
- cleanupBufferInProgress();
- return;
- }
-
- sp<MetaData> meta = buffer_in_progress_->meta_data();
- if (meta == NULL) {
- ALOGV("Missing metadata structure in allocated MediaBuffer; dropping"
- " payload");
- cleanupBufferInProgress();
- return;
- }
-
- meta->setCString(kKeyMIMEType, codec_mime_type_);
- if (ts_valid) {
- meta->setInt64(kKeyTime, ts);
- }
-
- // 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, buf, todo);
- buffer_filled_ = amt;
- buf += todo;
- amt -= todo;
- }
-
- if (buffer_filled_ >= expected_buffer_size_) {
- processCompletedBuffer();
- }
-}
-
-void AAH_RXPlayer::Substream::processPayloadCont(uint8_t* buf,
- uint32_t amt) {
- if (shouldAbort(__PRETTY_FUNCTION__)) {
- return;
- }
-
- if (NULL == buffer_in_progress_) {
- ALOGV("TRTP Receiver skipping payload continuation; no buffer currently"
- " in progress.");
- 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) {
- ALOGV("Extra data (%u > %u) present in continued TRTP Audio Payload;"
- " dropping payload.", amt, buffer_left);
- cleanupBufferInProgress();
- return;
- }
-
- if (amt > 0) {
- uint8_t* tgt =
- reinterpret_cast<uint8_t*>(buffer_in_progress_->data());
- memcpy(tgt + buffer_filled_, buf, amt);
- buffer_filled_ += amt;
- }
-
- if (buffer_filled_ >= expected_buffer_size_) {
- processCompletedBuffer();
- }
-}
-
-void AAH_RXPlayer::Substream::processCompletedBuffer() {
- status_t res;
-
- CHECK(NULL != buffer_in_progress_);
-
- if (decoder_ == NULL) {
- ALOGV("Dropping complete buffer, no decoder pump allocated");
- 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) {
- ALOGE("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) {
- ALOGD("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:
- ALOGV("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) {
- ALOGV("MP3 payload too short to contain header, dropping payload.");
- return false;
- }
-
- // Extract the channel count and the sample rate from the MP3 header. The
- // stagefright MP3 requires that these be delivered before decoing can
- // begin.
- if (!GetMPEGAudioFrameSize(U32_AT(buffer_data),
- &frame_size,
- &sample_rate,
- &channel_count,
- NULL,
- NULL)) {
- ALOGV("Failed to parse MP3 header in payload, droping payload.");
- return false;
- }
-
-
- // Make sure that our substream metadata is set up properly. If there has
- // been a format change, be sure to reset the underlying decoder. In
- // stagefright, it seems like the only way to do this is to destroy and
- // recreate the decoder.
- if (substream_meta_ == NULL) {
- substream_meta_ = new MetaData();
-
- if (substream_meta_ == NULL) {
- ALOGE("Failed to allocate MetaData structure for MP3 substream");
- return false;
- }
-
- substream_meta_->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
- substream_meta_->setInt32 (kKeyChannelCount, channel_count);
- substream_meta_->setInt32 (kKeySampleRate, sample_rate);
- } else {
- 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 ((prev_channel_count != channel_count) ||
- (prev_sample_rate != sample_rate)) {
- ALOGW("MP3 format change detected, forcing decoder reset.");
- cleanupDecoder();
-
- substream_meta_->setInt32(kKeyChannelCount, channel_count);
- substream_meta_->setInt32(kKeySampleRate, sample_rate);
- }
- }
-
- 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) {
- ALOGE("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;
- bool res;
-
- res = substream_meta_->findInt32(kKeySampleRate, &prev_sample_rate);
- CHECK(res);
- res = substream_meta_->findInt32(kKeyChannelCount, &prev_channel_count);
- CHECK(res);
-
- // 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.
- }
-
- ALOGW("AAC format change detected, forcing decoder reset.");
- cleanupDecoder();
- substream_meta_ = NULL;
- }
-
- CHECK(substream_meta_ == NULL);
-
- substream_meta_ = new MetaData();
- if (substream_meta_ == NULL) {
- ALOGE("Failed to allocate MetaData structure for AAC substream");
- return false;
- }
-
- substream_meta_->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
- substream_meta_->setInt32 (kKeySampleRate, sample_rate);
- substream_meta_->setInt32 (kKeyChannelCount, channel_cnt);
-
- 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) {
- decoder_->setRenderTSTransform(trans);
- }
-}
-
-bool AAH_RXPlayer::Substream::isAboutToUnderflow() {
- if (decoder_ == NULL) {
- return false;
- }
-
- return decoder_->isAboutToUnderflow(kAboutToUnderflowThreshold);
-}
-
-bool AAH_RXPlayer::Substream::setupSubstreamType(uint8_t substream_type,
- uint8_t codec_type) {
- // 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_) {
- ALOGV("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;
- }
-
- return true;
- }
-
- switch (codec_type) {
- // MP3 and AAC are all we support right now.
- case TRTPAudioPacket::kCodecMPEG1Audio:
- case TRTPAudioPacket::kCodecAACAudio:
- break;
-
- default:
- ALOGV("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;
-}
-
-} // namespace android