/* * 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. */ //#define LOG_NDEBUG 0 #define LOG_TAG "AAVCAssembler" #include #include "AAVCAssembler.h" #include "ARTPSource.h" #include #include #include #include #include namespace android { // static AAVCAssembler::AAVCAssembler(const sp ¬ify) : mNotifyMsg(notify), mAccessUnitRTPTime(0), mNextExpectedSeqNoValid(false), mNextExpectedSeqNo(0), mAccessUnitDamaged(false) { } AAVCAssembler::~AAVCAssembler() { } ARTPAssembler::AssemblyStatus AAVCAssembler::addNALUnit( 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) { ALOGV("Not the sequence number I expected"); return WRONG_SEQUENCE_NUMBER; } const uint8_t *data = buffer->data(); size_t size = buffer->size(); if (size < 1 || (data[0] & 0x80)) { // Corrupt. ALOGV("Ignoring corrupt buffer."); queue->erase(queue->begin()); ++mNextExpectedSeqNo; return MALFORMED_PACKET; } unsigned nalType = data[0] & 0x1f; if (nalType >= 1 && nalType <= 23) { addSingleNALUnit(buffer); queue->erase(queue->begin()); ++mNextExpectedSeqNo; return OK; } else if (nalType == 28) { // FU-A return addFragmentedNALUnit(queue); } else if (nalType == 24) { // STAP-A bool success = addSingleTimeAggregationPacket(buffer); queue->erase(queue->begin()); ++mNextExpectedSeqNo; return success ? OK : MALFORMED_PACKET; } else if (nalType == 0) { ALOGV("Ignoring undefined nal type."); queue->erase(queue->begin()); ++mNextExpectedSeqNo; return OK; } else { ALOGV("Ignoring unsupported buffer (nalType=%d)", nalType); queue->erase(queue->begin()); ++mNextExpectedSeqNo; return MALFORMED_PACKET; } } void AAVCAssembler::addSingleNALUnit(const sp &buffer) { ALOGV("addSingleNALUnit of size %zu", buffer->size()); #if !LOG_NDEBUG hexdump(buffer->data(), buffer->size()); #endif uint32_t rtpTime; CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime)); if (!mNALUnits.empty() && rtpTime != mAccessUnitRTPTime) { submitAccessUnit(); } mAccessUnitRTPTime = rtpTime; mNALUnits.push_back(buffer); } bool AAVCAssembler::addSingleTimeAggregationPacket(const sp &buffer) { const uint8_t *data = buffer->data(); size_t size = buffer->size(); if (size < 3) { ALOGV("Discarding too small STAP-A packet."); return false; } ++data; --size; while (size >= 2) { size_t nalSize = (data[0] << 8) | data[1]; if (size < nalSize + 2) { ALOGV("Discarding malformed STAP-A packet."); return false; } sp unit = new ABuffer(nalSize); memcpy(unit->data(), &data[2], nalSize); CopyTimes(unit, buffer); addSingleNALUnit(unit); data += 2 + nalSize; size -= 2 + nalSize; } if (size != 0) { ALOGV("Unexpected padding at end of STAP-A packet."); } return true; } ARTPAssembler::AssemblyStatus AAVCAssembler::addFragmentedNALUnit( List > *queue) { CHECK(!queue->empty()); sp buffer = *queue->begin(); const uint8_t *data = buffer->data(); size_t size = buffer->size(); CHECK(size > 0); unsigned indicator = data[0]; CHECK((indicator & 0x1f) == 28); if (size < 2) { ALOGV("Ignoring malformed FU buffer (size = %zu)", size); queue->erase(queue->begin()); ++mNextExpectedSeqNo; return MALFORMED_PACKET; } if (!(data[1] & 0x80)) { // Start bit not set on the first buffer. ALOGV("Start bit not set on first buffer"); queue->erase(queue->begin()); ++mNextExpectedSeqNo; return MALFORMED_PACKET; } uint32_t nalType = data[1] & 0x1f; uint32_t nri = (data[0] >> 5) & 3; uint32_t expectedSeqNo = (uint32_t)buffer->int32Data() + 1; size_t totalSize = size - 2; size_t totalCount = 1; bool complete = false; if (data[1] & 0x40) { // Huh? End bit also set on the first buffer. ALOGV("Grrr. This isn't fragmented at all."); complete = true; } else { List >::iterator it = ++queue->begin(); while (it != queue->end()) { ALOGV("sequence length %zu", totalCount); const sp &buffer = *it; const uint8_t *data = buffer->data(); size_t size = buffer->size(); if ((uint32_t)buffer->int32Data() != expectedSeqNo) { ALOGV("sequence not complete, expected seqNo %d, got %d", expectedSeqNo, (uint32_t)buffer->int32Data()); return WRONG_SEQUENCE_NUMBER; } if (size < 2 || data[0] != indicator || (data[1] & 0x1f) != nalType || (data[1] & 0x80)) { ALOGV("Ignoring malformed FU buffer."); // Delete the whole start of the FU. it = queue->begin(); for (size_t i = 0; i <= totalCount; ++i) { it = queue->erase(it); } mNextExpectedSeqNo = expectedSeqNo + 1; return MALFORMED_PACKET; } totalSize += size - 2; ++totalCount; expectedSeqNo = expectedSeqNo + 1; if (data[1] & 0x40) { // This is the last fragment. complete = true; break; } ++it; } } if (!complete) { return NOT_ENOUGH_DATA; } mNextExpectedSeqNo = expectedSeqNo; // We found all the fragments that make up the complete NAL unit. // Leave room for the header. So far totalSize did not include the // header byte. ++totalSize; sp unit = new ABuffer(totalSize); CopyTimes(unit, *queue->begin()); unit->data()[0] = (nri << 5) | nalType; size_t offset = 1; List >::iterator it = queue->begin(); for (size_t i = 0; i < totalCount; ++i) { const sp &buffer = *it; ALOGV("piece #%zu/%zu", i + 1, totalCount); #if !LOG_NDEBUG hexdump(buffer->data(), buffer->size()); #endif memcpy(unit->data() + offset, buffer->data() + 2, buffer->size() - 2); offset += buffer->size() - 2; it = queue->erase(it); } unit->setRange(0, totalSize); addSingleNALUnit(unit); ALOGV("successfully assembled a NAL unit from fragments."); return OK; } void AAVCAssembler::submitAccessUnit() { CHECK(!mNALUnits.empty()); ALOGV("Access unit complete (%zu nal units)", mNALUnits.size()); size_t totalSize = 0; for (List >::iterator it = mNALUnits.begin(); it != mNALUnits.end(); ++it) { totalSize += 4 + (*it)->size(); } sp accessUnit = new ABuffer(totalSize); size_t offset = 0; for (List >::iterator it = mNALUnits.begin(); it != mNALUnits.end(); ++it) { memcpy(accessUnit->data() + offset, "\x00\x00\x00\x01", 4); offset += 4; sp nal = *it; memcpy(accessUnit->data() + offset, nal->data(), nal->size()); offset += nal->size(); } CopyTimes(accessUnit, *mNALUnits.begin()); #if 0 printf(mAccessUnitDamaged ? "X" : "."); fflush(stdout); #endif if (mAccessUnitDamaged) { accessUnit->meta()->setInt32("damaged", true); } mNALUnits.clear(); mAccessUnitDamaged = false; sp msg = mNotifyMsg->dup(); msg->setBuffer("access-unit", accessUnit); msg->post(); } ARTPAssembler::AssemblyStatus AAVCAssembler::assembleMore( const sp &source) { AssemblyStatus status = addNALUnit(source); if (status == MALFORMED_PACKET) { mAccessUnitDamaged = true; } return status; } void AAVCAssembler::packetLost() { CHECK(mNextExpectedSeqNoValid); ALOGV("packetLost (expected %d)", mNextExpectedSeqNo); ++mNextExpectedSeqNo; mAccessUnitDamaged = true; } void AAVCAssembler::onByeReceived() { sp msg = mNotifyMsg->dup(); msg->setInt32("eos", true); msg->post(); } } // namespace android