AAMRAssembler.cpp revision 6e4c5c499999c04c2477b987f9e64f3ff2bf1a06
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17//#define LOG_NDEBUG 0 18#define LOG_TAG "AAMRAssembler" 19#include <utils/Log.h> 20 21#include "AAMRAssembler.h" 22 23#include "ARTPSource.h" 24 25#include <media/stagefright/foundation/ABuffer.h> 26#include <media/stagefright/foundation/ADebug.h> 27#include <media/stagefright/foundation/AMessage.h> 28#include <media/stagefright/foundation/hexdump.h> 29#include <media/stagefright/Utils.h> 30 31namespace android { 32 33static bool GetAttribute(const char *s, const char *key, AString *value) { 34 value->clear(); 35 36 size_t keyLen = strlen(key); 37 38 for (;;) { 39 const char *colonPos = strchr(s, ';'); 40 41 size_t len = 42 (colonPos == NULL) ? strlen(s) : colonPos - s; 43 44 if (len >= keyLen + 1 && s[keyLen] == '=' && !strncmp(s, key, keyLen)) { 45 value->setTo(&s[keyLen + 1], len - keyLen - 1); 46 return true; 47 } 48 if (len == keyLen && !strncmp(s, key, keyLen)) { 49 value->setTo("1"); 50 return true; 51 } 52 53 if (colonPos == NULL) { 54 return false; 55 } 56 57 s = colonPos + 1; 58 } 59} 60 61AAMRAssembler::AAMRAssembler( 62 const sp<AMessage> ¬ify, bool isWide, const AString ¶ms) 63 : mIsWide(isWide), 64 mNotifyMsg(notify), 65 mNextExpectedSeqNoValid(false), 66 mNextExpectedSeqNo(0) { 67 AString value; 68 CHECK(GetAttribute(params.c_str(), "octet-align", &value) && value == "1"); 69 CHECK(!GetAttribute(params.c_str(), "crc", &value) || value == "0"); 70 CHECK(!GetAttribute(params.c_str(), "interleaving", &value)); 71} 72 73AAMRAssembler::~AAMRAssembler() { 74} 75 76ARTPAssembler::AssemblyStatus AAMRAssembler::assembleMore( 77 const sp<ARTPSource> &source) { 78 return addPacket(source); 79} 80 81static size_t getFrameSize(bool isWide, unsigned FT) { 82 static const size_t kFrameSizeNB[8] = { 83 95, 103, 118, 134, 148, 159, 204, 244 84 }; 85 static const size_t kFrameSizeWB[9] = { 86 132, 177, 253, 285, 317, 365, 397, 461, 477 87 }; 88 89 size_t frameSize = isWide ? kFrameSizeWB[FT] : kFrameSizeNB[FT]; 90 91 // Round up bits to bytes and add 1 for the header byte. 92 frameSize = (frameSize + 7) / 8 + 1; 93 94 return frameSize; 95} 96 97ARTPAssembler::AssemblyStatus AAMRAssembler::addPacket( 98 const sp<ARTPSource> &source) { 99 List<sp<ABuffer> > *queue = source->queue(); 100 101 if (queue->empty()) { 102 return NOT_ENOUGH_DATA; 103 } 104 105 if (mNextExpectedSeqNoValid) { 106 List<sp<ABuffer> >::iterator it = queue->begin(); 107 while (it != queue->end()) { 108 if ((uint32_t)(*it)->int32Data() >= mNextExpectedSeqNo) { 109 break; 110 } 111 112 it = queue->erase(it); 113 } 114 115 if (queue->empty()) { 116 return NOT_ENOUGH_DATA; 117 } 118 } 119 120 sp<ABuffer> buffer = *queue->begin(); 121 122 if (!mNextExpectedSeqNoValid) { 123 mNextExpectedSeqNoValid = true; 124 mNextExpectedSeqNo = (uint32_t)buffer->int32Data(); 125 } else if ((uint32_t)buffer->int32Data() != mNextExpectedSeqNo) { 126 LOGV("Not the sequence number I expected"); 127 128 return WRONG_SEQUENCE_NUMBER; 129 } 130 131 // hexdump(buffer->data(), buffer->size()); 132 133 if (buffer->size() < 1) { 134 queue->erase(queue->begin()); 135 ++mNextExpectedSeqNo; 136 137 LOGV("AMR packet too short."); 138 139 return MALFORMED_PACKET; 140 } 141 142 unsigned payloadHeader = buffer->data()[0]; 143 unsigned CMR = payloadHeader >> 4; 144 CHECK_EQ(payloadHeader & 0x0f, 0u); // RR 145 146 Vector<uint8_t> tableOfContents; 147 148 size_t offset = 1; 149 size_t totalSize = 0; 150 for (;;) { 151 if (offset >= buffer->size()) { 152 queue->erase(queue->begin()); 153 ++mNextExpectedSeqNo; 154 155 LOGV("Unable to parse TOC."); 156 157 return MALFORMED_PACKET; 158 } 159 160 uint8_t toc = buffer->data()[offset++]; 161 162 unsigned FT = (toc >> 3) & 0x0f; 163 if ((toc & 3) != 0 164 || (mIsWide && FT > 8) 165 || (!mIsWide && FT > 7)) { 166 queue->erase(queue->begin()); 167 ++mNextExpectedSeqNo; 168 169 LOGV("Illegal TOC entry."); 170 171 return MALFORMED_PACKET; 172 } 173 174 totalSize += getFrameSize(mIsWide, (toc >> 3) & 0x0f); 175 176 tableOfContents.push(toc); 177 178 if (0 == (toc & 0x80)) { 179 break; 180 } 181 } 182 183 sp<ABuffer> accessUnit = new ABuffer(totalSize); 184 CopyTimes(accessUnit, buffer); 185 186 size_t dstOffset = 0; 187 for (size_t i = 0; i < tableOfContents.size(); ++i) { 188 uint8_t toc = tableOfContents[i]; 189 190 size_t frameSize = getFrameSize(mIsWide, (toc >> 3) & 0x0f); 191 192 if (offset + frameSize - 1 > buffer->size()) { 193 queue->erase(queue->begin()); 194 ++mNextExpectedSeqNo; 195 196 LOGV("AMR packet too short."); 197 198 return MALFORMED_PACKET; 199 } 200 201 accessUnit->data()[dstOffset++] = toc; 202 memcpy(accessUnit->data() + dstOffset, 203 buffer->data() + offset, frameSize - 1); 204 205 offset += frameSize - 1; 206 dstOffset += frameSize - 1; 207 } 208 209 sp<AMessage> msg = mNotifyMsg->dup(); 210 msg->setObject("access-unit", accessUnit); 211 msg->post(); 212 213 queue->erase(queue->begin()); 214 ++mNextExpectedSeqNo; 215 216 return OK; 217} 218 219void AAMRAssembler::packetLost() { 220 CHECK(mNextExpectedSeqNoValid); 221 ++mNextExpectedSeqNo; 222} 223 224void AAMRAssembler::onByeReceived() { 225 sp<AMessage> msg = mNotifyMsg->dup(); 226 msg->setInt32("eos", true); 227 msg->post(); 228} 229 230} // namespace android 231