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