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 "AnotherPacketSource" 19 20 #include "AnotherPacketSource.h" 21 22 #include <media/stagefright/foundation/ABuffer.h> 23 #include <media/stagefright/foundation/ADebug.h> 24 #include <media/stagefright/foundation/AMessage.h> 25 #include <media/stagefright/foundation/AString.h> 26 #include <media/stagefright/foundation/hexdump.h> 27 #include <media/stagefright/MediaBuffer.h> 28 #include <media/stagefright/MediaDefs.h> 29 #include <media/stagefright/MetaData.h> 30 #include <utils/Vector.h> 31 32 #include <inttypes.h> 33 34 namespace android { 35 36 const int64_t kNearEOSMarkUs = 2000000ll; // 2 secs 37 38 AnotherPacketSource::AnotherPacketSource(const sp<MetaData> &meta) 39 : mIsAudio(false), 40 mIsVideo(false), 41 mFormat(NULL), 42 mLastQueuedTimeUs(0), 43 mEOSResult(OK), 44 mLatestEnqueuedMeta(NULL), 45 mLatestDequeuedMeta(NULL), 46 mQueuedDiscontinuityCount(0) { 47 setFormat(meta); 48 } 49 50 void AnotherPacketSource::setFormat(const sp<MetaData> &meta) { 51 CHECK(mFormat == NULL); 52 53 mIsAudio = false; 54 mIsVideo = false; 55 56 if (meta == NULL) { 57 return; 58 } 59 60 mFormat = meta; 61 const char *mime; 62 CHECK(meta->findCString(kKeyMIMEType, &mime)); 63 64 if (!strncasecmp("audio/", mime, 6)) { 65 mIsAudio = true; 66 } else if (!strncasecmp("video/", mime, 6)) { 67 mIsVideo = true; 68 } else { 69 CHECK(!strncasecmp("text/", mime, 5)); 70 } 71 } 72 73 AnotherPacketSource::~AnotherPacketSource() { 74 } 75 76 status_t AnotherPacketSource::start(MetaData * /* params */) { 77 return OK; 78 } 79 80 status_t AnotherPacketSource::stop() { 81 return OK; 82 } 83 84 sp<MetaData> AnotherPacketSource::getFormat() { 85 Mutex::Autolock autoLock(mLock); 86 if (mFormat != NULL) { 87 return mFormat; 88 } 89 90 List<sp<ABuffer> >::iterator it = mBuffers.begin(); 91 while (it != mBuffers.end()) { 92 sp<ABuffer> buffer = *it; 93 int32_t discontinuity; 94 if (buffer->meta()->findInt32("discontinuity", &discontinuity)) { 95 break; 96 } 97 98 sp<RefBase> object; 99 if (buffer->meta()->findObject("format", &object)) { 100 return mFormat = static_cast<MetaData*>(object.get()); 101 } 102 103 ++it; 104 } 105 return NULL; 106 } 107 108 status_t AnotherPacketSource::dequeueAccessUnit(sp<ABuffer> *buffer) { 109 buffer->clear(); 110 111 Mutex::Autolock autoLock(mLock); 112 while (mEOSResult == OK && mBuffers.empty()) { 113 mCondition.wait(mLock); 114 } 115 116 if (!mBuffers.empty()) { 117 *buffer = *mBuffers.begin(); 118 mBuffers.erase(mBuffers.begin()); 119 120 int32_t discontinuity; 121 if ((*buffer)->meta()->findInt32("discontinuity", &discontinuity)) { 122 if (wasFormatChange(discontinuity)) { 123 mFormat.clear(); 124 } 125 126 --mQueuedDiscontinuityCount; 127 return INFO_DISCONTINUITY; 128 } 129 130 mLatestDequeuedMeta = (*buffer)->meta()->dup(); 131 132 sp<RefBase> object; 133 if ((*buffer)->meta()->findObject("format", &object)) { 134 mFormat = static_cast<MetaData*>(object.get()); 135 } 136 137 return OK; 138 } 139 140 return mEOSResult; 141 } 142 143 status_t AnotherPacketSource::read( 144 MediaBuffer **out, const ReadOptions *) { 145 *out = NULL; 146 147 Mutex::Autolock autoLock(mLock); 148 while (mEOSResult == OK && mBuffers.empty()) { 149 mCondition.wait(mLock); 150 } 151 152 if (!mBuffers.empty()) { 153 154 const sp<ABuffer> buffer = *mBuffers.begin(); 155 mBuffers.erase(mBuffers.begin()); 156 mLatestDequeuedMeta = buffer->meta()->dup(); 157 158 int32_t discontinuity; 159 if (buffer->meta()->findInt32("discontinuity", &discontinuity)) { 160 if (wasFormatChange(discontinuity)) { 161 mFormat.clear(); 162 } 163 164 return INFO_DISCONTINUITY; 165 } 166 167 sp<RefBase> object; 168 if (buffer->meta()->findObject("format", &object)) { 169 mFormat = static_cast<MetaData*>(object.get()); 170 } 171 172 int64_t timeUs; 173 CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); 174 175 MediaBuffer *mediaBuffer = new MediaBuffer(buffer); 176 177 mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs); 178 179 *out = mediaBuffer; 180 return OK; 181 } 182 183 return mEOSResult; 184 } 185 186 bool AnotherPacketSource::wasFormatChange( 187 int32_t discontinuityType) const { 188 if (mIsAudio) { 189 return (discontinuityType & ATSParser::DISCONTINUITY_AUDIO_FORMAT) != 0; 190 } 191 192 if (mIsVideo) { 193 return (discontinuityType & ATSParser::DISCONTINUITY_VIDEO_FORMAT) != 0; 194 } 195 196 return false; 197 } 198 199 void AnotherPacketSource::queueAccessUnit(const sp<ABuffer> &buffer) { 200 int32_t damaged; 201 if (buffer->meta()->findInt32("damaged", &damaged) && damaged) { 202 // LOG(VERBOSE) << "discarding damaged AU"; 203 return; 204 } 205 206 int64_t lastQueuedTimeUs; 207 CHECK(buffer->meta()->findInt64("timeUs", &lastQueuedTimeUs)); 208 mLastQueuedTimeUs = lastQueuedTimeUs; 209 ALOGV("queueAccessUnit timeUs=%" PRIi64 " us (%.2f secs)", mLastQueuedTimeUs, mLastQueuedTimeUs / 1E6); 210 211 Mutex::Autolock autoLock(mLock); 212 mBuffers.push_back(buffer); 213 mCondition.signal(); 214 215 int32_t discontinuity; 216 if (buffer->meta()->findInt32("discontinuity", &discontinuity)) { 217 ++mQueuedDiscontinuityCount; 218 } 219 220 if (mLatestEnqueuedMeta == NULL) { 221 mLatestEnqueuedMeta = buffer->meta(); 222 } else { 223 int64_t latestTimeUs = 0; 224 CHECK(mLatestEnqueuedMeta->findInt64("timeUs", &latestTimeUs)); 225 if (lastQueuedTimeUs > latestTimeUs) { 226 mLatestEnqueuedMeta = buffer->meta(); 227 } 228 } 229 } 230 231 void AnotherPacketSource::clear() { 232 Mutex::Autolock autoLock(mLock); 233 234 mBuffers.clear(); 235 mEOSResult = OK; 236 mQueuedDiscontinuityCount = 0; 237 238 mFormat = NULL; 239 mLatestEnqueuedMeta = NULL; 240 } 241 242 void AnotherPacketSource::queueDiscontinuity( 243 ATSParser::DiscontinuityType type, 244 const sp<AMessage> &extra, 245 bool discard) { 246 Mutex::Autolock autoLock(mLock); 247 248 if (discard) { 249 // Leave only discontinuities in the queue. 250 List<sp<ABuffer> >::iterator it = mBuffers.begin(); 251 while (it != mBuffers.end()) { 252 sp<ABuffer> oldBuffer = *it; 253 254 int32_t oldDiscontinuityType; 255 if (!oldBuffer->meta()->findInt32( 256 "discontinuity", &oldDiscontinuityType)) { 257 it = mBuffers.erase(it); 258 continue; 259 } 260 261 ++it; 262 } 263 } 264 265 mEOSResult = OK; 266 mLastQueuedTimeUs = 0; 267 mLatestEnqueuedMeta = NULL; 268 ++mQueuedDiscontinuityCount; 269 270 sp<ABuffer> buffer = new ABuffer(0); 271 buffer->meta()->setInt32("discontinuity", static_cast<int32_t>(type)); 272 buffer->meta()->setMessage("extra", extra); 273 274 mBuffers.push_back(buffer); 275 mCondition.signal(); 276 } 277 278 void AnotherPacketSource::signalEOS(status_t result) { 279 CHECK(result != OK); 280 281 Mutex::Autolock autoLock(mLock); 282 mEOSResult = result; 283 mCondition.signal(); 284 } 285 286 bool AnotherPacketSource::hasBufferAvailable(status_t *finalResult) { 287 Mutex::Autolock autoLock(mLock); 288 if (!mBuffers.empty()) { 289 return true; 290 } 291 292 *finalResult = mEOSResult; 293 return false; 294 } 295 296 int64_t AnotherPacketSource::getBufferedDurationUs(status_t *finalResult) { 297 Mutex::Autolock autoLock(mLock); 298 return getBufferedDurationUs_l(finalResult); 299 } 300 301 int64_t AnotherPacketSource::getBufferedDurationUs_l(status_t *finalResult) { 302 *finalResult = mEOSResult; 303 304 if (mBuffers.empty()) { 305 return 0; 306 } 307 308 int64_t time1 = -1; 309 int64_t time2 = -1; 310 int64_t durationUs = 0; 311 312 List<sp<ABuffer> >::iterator it = mBuffers.begin(); 313 while (it != mBuffers.end()) { 314 const sp<ABuffer> &buffer = *it; 315 316 int64_t timeUs; 317 if (buffer->meta()->findInt64("timeUs", &timeUs)) { 318 if (time1 < 0 || timeUs < time1) { 319 time1 = timeUs; 320 } 321 322 if (time2 < 0 || timeUs > time2) { 323 time2 = timeUs; 324 } 325 } else { 326 // This is a discontinuity, reset everything. 327 durationUs += time2 - time1; 328 time1 = time2 = -1; 329 } 330 331 ++it; 332 } 333 334 return durationUs + (time2 - time1); 335 } 336 337 // A cheaper but less precise version of getBufferedDurationUs that we would like to use in 338 // LiveSession::dequeueAccessUnit to trigger downwards adaptation. 339 int64_t AnotherPacketSource::getEstimatedDurationUs() { 340 Mutex::Autolock autoLock(mLock); 341 if (mBuffers.empty()) { 342 return 0; 343 } 344 345 if (mQueuedDiscontinuityCount > 0) { 346 status_t finalResult; 347 return getBufferedDurationUs_l(&finalResult); 348 } 349 350 List<sp<ABuffer> >::iterator it = mBuffers.begin(); 351 sp<ABuffer> buffer = *it; 352 353 int64_t startTimeUs; 354 buffer->meta()->findInt64("timeUs", &startTimeUs); 355 if (startTimeUs < 0) { 356 return 0; 357 } 358 359 it = mBuffers.end(); 360 --it; 361 buffer = *it; 362 363 int64_t endTimeUs; 364 buffer->meta()->findInt64("timeUs", &endTimeUs); 365 if (endTimeUs < 0) { 366 return 0; 367 } 368 369 int64_t diffUs; 370 if (endTimeUs > startTimeUs) { 371 diffUs = endTimeUs - startTimeUs; 372 } else { 373 diffUs = startTimeUs - endTimeUs; 374 } 375 return diffUs; 376 } 377 378 status_t AnotherPacketSource::nextBufferTime(int64_t *timeUs) { 379 *timeUs = 0; 380 381 Mutex::Autolock autoLock(mLock); 382 383 if (mBuffers.empty()) { 384 return mEOSResult != OK ? mEOSResult : -EWOULDBLOCK; 385 } 386 387 sp<ABuffer> buffer = *mBuffers.begin(); 388 CHECK(buffer->meta()->findInt64("timeUs", timeUs)); 389 390 return OK; 391 } 392 393 bool AnotherPacketSource::isFinished(int64_t duration) const { 394 if (duration > 0) { 395 int64_t diff = duration - mLastQueuedTimeUs; 396 if (diff < kNearEOSMarkUs && diff > -kNearEOSMarkUs) { 397 ALOGV("Detecting EOS due to near end"); 398 return true; 399 } 400 } 401 return (mEOSResult != OK); 402 } 403 404 sp<AMessage> AnotherPacketSource::getLatestEnqueuedMeta() { 405 Mutex::Autolock autoLock(mLock); 406 return mLatestEnqueuedMeta; 407 } 408 409 sp<AMessage> AnotherPacketSource::getLatestDequeuedMeta() { 410 Mutex::Autolock autoLock(mLock); 411 return mLatestDequeuedMeta; 412 } 413 414 } // namespace android 415