/* * 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 "AMPEG4AudioAssembler.h" #include "ARTPSource.h" #include #include #include namespace android { AMPEG4AudioAssembler::AMPEG4AudioAssembler(const sp ¬ify) : mNotifyMsg(notify), mAccessUnitRTPTime(0), mNextExpectedSeqNoValid(false), mNextExpectedSeqNo(0), mAccessUnitDamaged(false) { } AMPEG4AudioAssembler::~AMPEG4AudioAssembler() { } ARTPAssembler::AssemblyStatus AMPEG4AudioAssembler::assembleMore( const sp &source) { AssemblyStatus status = addPacket(source); if (status == MALFORMED_PACKET) { mAccessUnitDamaged = true; } return status; } ARTPAssembler::AssemblyStatus AMPEG4AudioAssembler::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; } uint32_t rtpTime; CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime)); if (mPackets.size() > 0 && rtpTime != mAccessUnitRTPTime) { submitAccessUnit(); } mAccessUnitRTPTime = rtpTime; mPackets.push_back(buffer); queue->erase(queue->begin()); ++mNextExpectedSeqNo; return OK; } void AMPEG4AudioAssembler::submitAccessUnit() { CHECK(!mPackets.empty()); #if VERBOSE LOG(VERBOSE) << "Access unit complete (" << mPackets.size() << " packets)"; #endif size_t totalSize = 0; List >::iterator it = mPackets.begin(); while (it != mPackets.end()) { const sp &unit = *it; size_t n = 0; while (unit->data()[n] == 0xff) { ++n; } ++n; totalSize += unit->size() - n; ++it; } sp accessUnit = new ABuffer(totalSize); size_t offset = 0; it = mPackets.begin(); while (it != mPackets.end()) { const sp &unit = *it; size_t n = 0; while (unit->data()[n] == 0xff) { ++n; } ++n; memcpy((uint8_t *)accessUnit->data() + offset, unit->data() + n, unit->size() - n); offset += unit->size() - n; ++it; } CopyTimes(accessUnit, *mPackets.begin()); #if 0 printf(mAccessUnitDamaged ? "X" : "."); fflush(stdout); #endif if (mAccessUnitDamaged) { accessUnit->meta()->setInt32("damaged", true); } mPackets.clear(); mAccessUnitDamaged = false; sp msg = mNotifyMsg->dup(); msg->setObject("access-unit", accessUnit); msg->post(); } void AMPEG4AudioAssembler::packetLost() { CHECK(mNextExpectedSeqNoValid); ++mNextExpectedSeqNo; mAccessUnitDamaged = true; } void AMPEG4AudioAssembler::onByeReceived() { sp msg = mNotifyMsg->dup(); msg->setInt32("eos", true); msg->post(); } } // namespace android