summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/rtsp/AAMRAssembler.cpp
diff options
context:
space:
mode:
authorAndreas Huber <andih@google.com>2010-08-04 10:14:30 -0700
committerAndreas Huber <andih@google.com>2010-08-04 11:49:24 -0700
commit39ddf8e0f18766f7ba1e3246b774aa6ebd93eea8 (patch)
tree87f5d0d68c1779f113843e939c41440ff6b00389 /media/libstagefright/rtsp/AAMRAssembler.cpp
parent610959a52fe22a88e50d158f5f5f492fee4f1921 (diff)
downloadframeworks_av-39ddf8e0f18766f7ba1e3246b774aa6ebd93eea8.zip
frameworks_av-39ddf8e0f18766f7ba1e3246b774aa6ebd93eea8.tar.gz
frameworks_av-39ddf8e0f18766f7ba1e3246b774aa6ebd93eea8.tar.bz2
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
Diffstat (limited to 'media/libstagefright/rtsp/AAMRAssembler.cpp')
-rw-r--r--media/libstagefright/rtsp/AAMRAssembler.cpp232
1 files changed, 232 insertions, 0 deletions
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 <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/hexdump.h>
+#include <media/stagefright/Utils.h>
+
+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<AMessage> &notify, bool isWide, const AString &params)
+ : 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<ARTPSource> &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<ARTPSource> &source) {
+ List<sp<ABuffer> > *queue = source->queue();
+
+ if (queue->empty()) {
+ return NOT_ENOUGH_DATA;
+ }
+
+ if (mNextExpectedSeqNoValid) {
+ List<sp<ABuffer> >::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<ABuffer> 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<uint8_t> 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<ABuffer> 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<AMessage> 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<AMessage> msg = mNotifyMsg->dup();
+ msg->setInt32("eos", true);
+ msg->post();
+}
+
+} // namespace android