From 39ddf8e0f18766f7ba1e3246b774aa6ebd93eea8 Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Wed, 4 Aug 2010 10:14:30 -0700 Subject: Support for Gtalk video, includes AMR/H.263 assembler and packetization support, extensions to MediaRecorder to stream via RTP over a pair of UDP sockets as well as various fixes to the RTP implementation. Change-Id: I95b8dd487061add9bade15749e563b01cd99d9a6 --- media/libstagefright/rtsp/AAMRAssembler.cpp | 232 ++++++++++++++++++++++++++++ 1 file changed, 232 insertions(+) create mode 100644 media/libstagefright/rtsp/AAMRAssembler.cpp (limited to 'media/libstagefright/rtsp/AAMRAssembler.cpp') diff --git a/media/libstagefright/rtsp/AAMRAssembler.cpp b/media/libstagefright/rtsp/AAMRAssembler.cpp new file mode 100644 index 0000000..c56578b --- /dev/null +++ b/media/libstagefright/rtsp/AAMRAssembler.cpp @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2010 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. + */ + +#include "AAMRAssembler.h" + +#include "ARTPSource.h" + +#include +#include +#include +#include +#include + +namespace android { + +static bool GetAttribute(const char *s, const char *key, AString *value) { + value->clear(); + + size_t keyLen = strlen(key); + + for (;;) { + const char *colonPos = strchr(s, ';'); + + size_t len = + (colonPos == NULL) ? strlen(s) : colonPos - s; + + if (len >= keyLen + 1 && s[keyLen] == '=' && !strncmp(s, key, keyLen)) { + value->setTo(&s[keyLen + 1], len - keyLen - 1); + return true; + } + if (len == keyLen && !strncmp(s, key, keyLen)) { + value->setTo("1"); + return true; + } + + if (colonPos == NULL) { + return false; + } + + s = colonPos + 1; + } +} + +AAMRAssembler::AAMRAssembler( + const sp ¬ify, bool isWide, const AString ¶ms) + : mIsWide(isWide), + mNotifyMsg(notify), + mNextExpectedSeqNoValid(false), + mNextExpectedSeqNo(0) { + AString value; + CHECK(GetAttribute(params.c_str(), "octet-align", &value) && value == "1"); + CHECK(!GetAttribute(params.c_str(), "crc", &value) || value == "0"); + CHECK(!GetAttribute(params.c_str(), "interleaving", &value)); +} + +AAMRAssembler::~AAMRAssembler() { +} + +ARTPAssembler::AssemblyStatus AAMRAssembler::assembleMore( + const sp &source) { + return addPacket(source); +} + +static size_t getFrameSize(bool isWide, unsigned FT) { + static const size_t kFrameSizeNB[8] = { + 95, 103, 118, 134, 148, 159, 204, 244 + }; + static const size_t kFrameSizeWB[9] = { + 132, 177, 253, 285, 317, 365, 397, 461, 477 + }; + + size_t frameSize = isWide ? kFrameSizeWB[FT] : kFrameSizeNB[FT]; + + // Round up bits to bytes and add 1 for the header byte. + frameSize = (frameSize + 7) / 8 + 1; + + return frameSize; +} + +ARTPAssembler::AssemblyStatus AAMRAssembler::addPacket( + const sp &source) { + List > *queue = source->queue(); + + if (queue->empty()) { + return NOT_ENOUGH_DATA; + } + + if (mNextExpectedSeqNoValid) { + List >::iterator it = queue->begin(); + while (it != queue->end()) { + if ((uint32_t)(*it)->int32Data() >= mNextExpectedSeqNo) { + break; + } + + it = queue->erase(it); + } + + if (queue->empty()) { + return NOT_ENOUGH_DATA; + } + } + + sp buffer = *queue->begin(); + + if (!mNextExpectedSeqNoValid) { + mNextExpectedSeqNoValid = true; + mNextExpectedSeqNo = (uint32_t)buffer->int32Data(); + } else if ((uint32_t)buffer->int32Data() != mNextExpectedSeqNo) { +#if VERBOSE + LOG(VERBOSE) << "Not the sequence number I expected"; +#endif + + return WRONG_SEQUENCE_NUMBER; + } + + // hexdump(buffer->data(), buffer->size()); + + if (buffer->size() < 1) { + queue->erase(queue->begin()); + ++mNextExpectedSeqNo; + + LOG(VERBOSE) << "AMR packet too short."; + + return MALFORMED_PACKET; + } + + unsigned payloadHeader = buffer->data()[0]; + unsigned CMR = payloadHeader >> 4; + CHECK_EQ(payloadHeader & 0x0f, 0u); // RR + + Vector tableOfContents; + + size_t offset = 1; + size_t totalSize = 0; + for (;;) { + if (offset >= buffer->size()) { + queue->erase(queue->begin()); + ++mNextExpectedSeqNo; + + LOG(VERBOSE) << "Unable to parse TOC."; + + return MALFORMED_PACKET; + } + + uint8_t toc = buffer->data()[offset++]; + + unsigned FT = (toc >> 3) & 0x0f; + if ((toc & 3) != 0 + || (mIsWide && FT > 8) + || (!mIsWide && FT > 7)) { + queue->erase(queue->begin()); + ++mNextExpectedSeqNo; + + LOG(VERBOSE) << "Illegal TOC entry."; + + return MALFORMED_PACKET; + } + + totalSize += getFrameSize(mIsWide, (toc >> 3) & 0x0f); + + tableOfContents.push(toc); + + if (0 == (toc & 0x80)) { + break; + } + } + + uint64_t ntpTime; + CHECK(buffer->meta()->findInt64( + "ntp-time", (int64_t *)&ntpTime)); + + sp accessUnit = new ABuffer(totalSize); + accessUnit->meta()->setInt64("ntp-time", ntpTime); + + size_t dstOffset = 0; + for (size_t i = 0; i < tableOfContents.size(); ++i) { + uint8_t toc = tableOfContents[i]; + + size_t frameSize = getFrameSize(mIsWide, (toc >> 3) & 0x0f); + + if (offset + frameSize - 1 > buffer->size()) { + queue->erase(queue->begin()); + ++mNextExpectedSeqNo; + + LOG(VERBOSE) << "AMR packet too short."; + + return MALFORMED_PACKET; + } + + accessUnit->data()[dstOffset++] = toc; + memcpy(accessUnit->data() + dstOffset, + buffer->data() + offset, frameSize - 1); + + offset += frameSize - 1; + dstOffset += frameSize - 1; + } + + sp msg = mNotifyMsg->dup(); + msg->setObject("access-unit", accessUnit); + msg->post(); + + queue->erase(queue->begin()); + ++mNextExpectedSeqNo; + + return OK; +} + +void AAMRAssembler::packetLost() { + CHECK(mNextExpectedSeqNoValid); + ++mNextExpectedSeqNo; +} + +void AAMRAssembler::onByeReceived() { + sp msg = mNotifyMsg->dup(); + msg->setInt32("eos", true); + msg->post(); +} + +} // namespace android -- cgit v1.1