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#include "AnotherPacketSource.h" 18 19#include <media/stagefright/foundation/ABuffer.h> 20#include <media/stagefright/foundation/ADebug.h> 21#include <media/stagefright/foundation/AMessage.h> 22#include <media/stagefright/foundation/AString.h> 23#include <media/stagefright/foundation/hexdump.h> 24#include <media/stagefright/MediaBuffer.h> 25#include <media/stagefright/MediaDefs.h> 26#include <media/stagefright/MetaData.h> 27#include <utils/Vector.h> 28 29namespace android { 30 31const int64_t kNearEOSMarkUs = 2000000ll; // 2 secs 32 33AnotherPacketSource::AnotherPacketSource(const sp<MetaData> &meta) 34 : mIsAudio(false), 35 mFormat(NULL), 36 mLastQueuedTimeUs(0), 37 mEOSResult(OK) { 38 setFormat(meta); 39} 40 41void AnotherPacketSource::setFormat(const sp<MetaData> &meta) { 42 CHECK(mFormat == NULL); 43 44 mIsAudio = false; 45 46 if (meta == NULL) { 47 return; 48 } 49 50 mFormat = meta; 51 const char *mime; 52 CHECK(meta->findCString(kKeyMIMEType, &mime)); 53 54 if (!strncasecmp("audio/", mime, 6)) { 55 mIsAudio = true; 56 } else { 57 CHECK(!strncasecmp("video/", mime, 6)); 58 } 59} 60 61AnotherPacketSource::~AnotherPacketSource() { 62} 63 64status_t AnotherPacketSource::start(MetaData *params) { 65 return OK; 66} 67 68status_t AnotherPacketSource::stop() { 69 return OK; 70} 71 72sp<MetaData> AnotherPacketSource::getFormat() { 73 return mFormat; 74} 75 76status_t AnotherPacketSource::dequeueAccessUnit(sp<ABuffer> *buffer) { 77 buffer->clear(); 78 79 Mutex::Autolock autoLock(mLock); 80 while (mEOSResult == OK && mBuffers.empty()) { 81 mCondition.wait(mLock); 82 } 83 84 if (!mBuffers.empty()) { 85 *buffer = *mBuffers.begin(); 86 mBuffers.erase(mBuffers.begin()); 87 88 int32_t discontinuity; 89 if ((*buffer)->meta()->findInt32("discontinuity", &discontinuity)) { 90 if (wasFormatChange(discontinuity)) { 91 mFormat.clear(); 92 } 93 94 return INFO_DISCONTINUITY; 95 } 96 97 return OK; 98 } 99 100 return mEOSResult; 101} 102 103status_t AnotherPacketSource::read( 104 MediaBuffer **out, const ReadOptions *) { 105 *out = NULL; 106 107 Mutex::Autolock autoLock(mLock); 108 while (mEOSResult == OK && mBuffers.empty()) { 109 mCondition.wait(mLock); 110 } 111 112 if (!mBuffers.empty()) { 113 const sp<ABuffer> buffer = *mBuffers.begin(); 114 mBuffers.erase(mBuffers.begin()); 115 116 int32_t discontinuity; 117 if (buffer->meta()->findInt32("discontinuity", &discontinuity)) { 118 if (wasFormatChange(discontinuity)) { 119 mFormat.clear(); 120 } 121 122 return INFO_DISCONTINUITY; 123 } else { 124 int64_t timeUs; 125 CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); 126 127 MediaBuffer *mediaBuffer = new MediaBuffer(buffer); 128 129 mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs); 130 131 *out = mediaBuffer; 132 return OK; 133 } 134 } 135 136 return mEOSResult; 137} 138 139bool AnotherPacketSource::wasFormatChange( 140 int32_t discontinuityType) const { 141 if (mIsAudio) { 142 return (discontinuityType & ATSParser::DISCONTINUITY_AUDIO_FORMAT) != 0; 143 } 144 145 return (discontinuityType & ATSParser::DISCONTINUITY_VIDEO_FORMAT) != 0; 146} 147 148void AnotherPacketSource::queueAccessUnit(const sp<ABuffer> &buffer) { 149 int32_t damaged; 150 if (buffer->meta()->findInt32("damaged", &damaged) && damaged) { 151 // LOG(VERBOSE) << "discarding damaged AU"; 152 return; 153 } 154 155 CHECK(buffer->meta()->findInt64("timeUs", &mLastQueuedTimeUs)); 156 ALOGV("queueAccessUnit timeUs=%lld us (%.2f secs)", mLastQueuedTimeUs, mLastQueuedTimeUs / 1E6); 157 158 Mutex::Autolock autoLock(mLock); 159 mBuffers.push_back(buffer); 160 mCondition.signal(); 161} 162 163void AnotherPacketSource::clear() { 164 Mutex::Autolock autoLock(mLock); 165 166 mBuffers.clear(); 167 mEOSResult = OK; 168 169 mFormat = NULL; 170} 171 172void AnotherPacketSource::queueDiscontinuity( 173 ATSParser::DiscontinuityType type, 174 const sp<AMessage> &extra) { 175 Mutex::Autolock autoLock(mLock); 176 177 // Leave only discontinuities in the queue. 178 List<sp<ABuffer> >::iterator it = mBuffers.begin(); 179 while (it != mBuffers.end()) { 180 sp<ABuffer> oldBuffer = *it; 181 182 int32_t oldDiscontinuityType; 183 if (!oldBuffer->meta()->findInt32( 184 "discontinuity", &oldDiscontinuityType)) { 185 it = mBuffers.erase(it); 186 continue; 187 } 188 189 ++it; 190 } 191 192 mEOSResult = OK; 193 mLastQueuedTimeUs = 0; 194 195 sp<ABuffer> buffer = new ABuffer(0); 196 buffer->meta()->setInt32("discontinuity", static_cast<int32_t>(type)); 197 buffer->meta()->setMessage("extra", extra); 198 199 mBuffers.push_back(buffer); 200 mCondition.signal(); 201} 202 203void AnotherPacketSource::signalEOS(status_t result) { 204 CHECK(result != OK); 205 206 Mutex::Autolock autoLock(mLock); 207 mEOSResult = result; 208 mCondition.signal(); 209} 210 211bool AnotherPacketSource::hasBufferAvailable(status_t *finalResult) { 212 Mutex::Autolock autoLock(mLock); 213 if (!mBuffers.empty()) { 214 return true; 215 } 216 217 *finalResult = mEOSResult; 218 return false; 219} 220 221int64_t AnotherPacketSource::getBufferedDurationUs(status_t *finalResult) { 222 Mutex::Autolock autoLock(mLock); 223 224 *finalResult = mEOSResult; 225 226 if (mBuffers.empty()) { 227 return 0; 228 } 229 230 int64_t time1 = -1; 231 int64_t time2 = -1; 232 233 List<sp<ABuffer> >::iterator it = mBuffers.begin(); 234 while (it != mBuffers.end()) { 235 const sp<ABuffer> &buffer = *it; 236 237 int64_t timeUs; 238 if (buffer->meta()->findInt64("timeUs", &timeUs)) { 239 if (time1 < 0) { 240 time1 = timeUs; 241 } 242 243 time2 = timeUs; 244 } else { 245 // This is a discontinuity, reset everything. 246 time1 = time2 = -1; 247 } 248 249 ++it; 250 } 251 252 return time2 - time1; 253} 254 255status_t AnotherPacketSource::nextBufferTime(int64_t *timeUs) { 256 *timeUs = 0; 257 258 Mutex::Autolock autoLock(mLock); 259 260 if (mBuffers.empty()) { 261 return mEOSResult != OK ? mEOSResult : -EWOULDBLOCK; 262 } 263 264 sp<ABuffer> buffer = *mBuffers.begin(); 265 CHECK(buffer->meta()->findInt64("timeUs", timeUs)); 266 267 return OK; 268} 269 270bool AnotherPacketSource::isFinished(int64_t duration) const { 271 if (duration > 0) { 272 int64_t diff = duration - mLastQueuedTimeUs; 273 if (diff < kNearEOSMarkUs && diff > -kNearEOSMarkUs) { 274 ALOGV("Detecting EOS due to near end"); 275 return true; 276 } 277 } 278 return (mEOSResult != OK); 279} 280 281} // namespace android 282