/* * 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 "AnotherPacketSource.h" #include #include #include #include #include #include #include #include #include namespace android { const int64_t kNearEOSMarkUs = 2000000ll; // 2 secs AnotherPacketSource::AnotherPacketSource(const sp &meta) : mIsAudio(false), mFormat(NULL), mLastQueuedTimeUs(0), mEOSResult(OK), mLatestEnqueuedMeta(NULL) { setFormat(meta); } void AnotherPacketSource::setFormat(const sp &meta) { CHECK(mFormat == NULL); mIsAudio = false; if (meta == NULL) { return; } mFormat = meta; const char *mime; CHECK(meta->findCString(kKeyMIMEType, &mime)); if (!strncasecmp("audio/", mime, 6)) { mIsAudio = true; } else { CHECK(!strncasecmp("video/", mime, 6)); } } AnotherPacketSource::~AnotherPacketSource() { } status_t AnotherPacketSource::start(MetaData * /* params */) { return OK; } status_t AnotherPacketSource::stop() { return OK; } sp AnotherPacketSource::getFormat() { Mutex::Autolock autoLock(mLock); if (mFormat != NULL) { return mFormat; } List >::iterator it = mBuffers.begin(); while (it != mBuffers.end()) { sp buffer = *it; int32_t discontinuity; if (buffer->meta()->findInt32("discontinuity", &discontinuity)) { break; } sp object; if (buffer->meta()->findObject("format", &object)) { return static_cast(object.get()); } ++it; } return NULL; } status_t AnotherPacketSource::dequeueAccessUnit(sp *buffer) { buffer->clear(); Mutex::Autolock autoLock(mLock); while (mEOSResult == OK && mBuffers.empty()) { mCondition.wait(mLock); } if (!mBuffers.empty()) { *buffer = *mBuffers.begin(); mBuffers.erase(mBuffers.begin()); int32_t discontinuity; if ((*buffer)->meta()->findInt32("discontinuity", &discontinuity)) { if (wasFormatChange(discontinuity)) { mFormat.clear(); } return INFO_DISCONTINUITY; } sp object; if ((*buffer)->meta()->findObject("format", &object)) { mFormat = static_cast(object.get()); } return OK; } return mEOSResult; } status_t AnotherPacketSource::read( MediaBuffer **out, const ReadOptions *) { *out = NULL; Mutex::Autolock autoLock(mLock); while (mEOSResult == OK && mBuffers.empty()) { mCondition.wait(mLock); } if (!mBuffers.empty()) { const sp buffer = *mBuffers.begin(); mBuffers.erase(mBuffers.begin()); int32_t discontinuity; if (buffer->meta()->findInt32("discontinuity", &discontinuity)) { if (wasFormatChange(discontinuity)) { mFormat.clear(); } return INFO_DISCONTINUITY; } sp object; if (buffer->meta()->findObject("format", &object)) { mFormat = static_cast(object.get()); } int64_t timeUs; CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); MediaBuffer *mediaBuffer = new MediaBuffer(buffer); mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs); *out = mediaBuffer; return OK; } return mEOSResult; } bool AnotherPacketSource::wasFormatChange( int32_t discontinuityType) const { if (mIsAudio) { return (discontinuityType & ATSParser::DISCONTINUITY_AUDIO_FORMAT) != 0; } return (discontinuityType & ATSParser::DISCONTINUITY_VIDEO_FORMAT) != 0; } void AnotherPacketSource::queueAccessUnit(const sp &buffer) { int32_t damaged; if (buffer->meta()->findInt32("damaged", &damaged) && damaged) { // LOG(VERBOSE) << "discarding damaged AU"; return; } int64_t lastQueuedTimeUs; CHECK(buffer->meta()->findInt64("timeUs", &lastQueuedTimeUs)); mLastQueuedTimeUs = lastQueuedTimeUs; ALOGV("queueAccessUnit timeUs=%lld us (%.2f secs)", mLastQueuedTimeUs, mLastQueuedTimeUs / 1E6); Mutex::Autolock autoLock(mLock); mBuffers.push_back(buffer); mCondition.signal(); if (!mLatestEnqueuedMeta.get()) { mLatestEnqueuedMeta = buffer->meta(); } else { int64_t latestTimeUs = 0; CHECK(mLatestEnqueuedMeta->findInt64("timeUs", &latestTimeUs)); if (lastQueuedTimeUs > latestTimeUs) { mLatestEnqueuedMeta = buffer->meta(); } } } void AnotherPacketSource::clear() { Mutex::Autolock autoLock(mLock); mBuffers.clear(); mEOSResult = OK; mFormat = NULL; mLatestEnqueuedMeta = NULL; } void AnotherPacketSource::queueDiscontinuity( ATSParser::DiscontinuityType type, const sp &extra) { Mutex::Autolock autoLock(mLock); // Leave only discontinuities in the queue. List >::iterator it = mBuffers.begin(); while (it != mBuffers.end()) { sp oldBuffer = *it; int32_t oldDiscontinuityType; if (!oldBuffer->meta()->findInt32( "discontinuity", &oldDiscontinuityType)) { it = mBuffers.erase(it); continue; } ++it; } mEOSResult = OK; mLastQueuedTimeUs = 0; mLatestEnqueuedMeta = NULL; sp buffer = new ABuffer(0); buffer->meta()->setInt32("discontinuity", static_cast(type)); buffer->meta()->setMessage("extra", extra); mBuffers.push_back(buffer); mCondition.signal(); } void AnotherPacketSource::signalEOS(status_t result) { CHECK(result != OK); Mutex::Autolock autoLock(mLock); mEOSResult = result; mCondition.signal(); } bool AnotherPacketSource::hasBufferAvailable(status_t *finalResult) { Mutex::Autolock autoLock(mLock); if (!mBuffers.empty()) { return true; } *finalResult = mEOSResult; return false; } int64_t AnotherPacketSource::getBufferedDurationUs(status_t *finalResult) { Mutex::Autolock autoLock(mLock); *finalResult = mEOSResult; if (mBuffers.empty()) { return 0; } int64_t time1 = -1; int64_t time2 = -1; List >::iterator it = mBuffers.begin(); while (it != mBuffers.end()) { const sp &buffer = *it; int64_t timeUs; if (buffer->meta()->findInt64("timeUs", &timeUs)) { if (time1 < 0) { time1 = timeUs; } time2 = timeUs; } else { // This is a discontinuity, reset everything. time1 = time2 = -1; } ++it; } return time2 - time1; } status_t AnotherPacketSource::nextBufferTime(int64_t *timeUs) { *timeUs = 0; Mutex::Autolock autoLock(mLock); if (mBuffers.empty()) { return mEOSResult != OK ? mEOSResult : -EWOULDBLOCK; } sp buffer = *mBuffers.begin(); CHECK(buffer->meta()->findInt64("timeUs", timeUs)); return OK; } bool AnotherPacketSource::isFinished(int64_t duration) const { if (duration > 0) { int64_t diff = duration - mLastQueuedTimeUs; if (diff < kNearEOSMarkUs && diff > -kNearEOSMarkUs) { ALOGV("Detecting EOS due to near end"); return true; } } return (mEOSResult != OK); } sp AnotherPacketSource::getLatestMeta() { Mutex::Autolock autoLock(mLock); return mLatestEnqueuedMeta; } } // namespace android