AnotherPacketSource.cpp revision fef808d42a9c94b0b5ef3c3d5fb0a090edbc42da
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 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 108status_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 143status_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 186bool 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 199void 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 231void 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 242void 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 if (type == ATSParser::DISCONTINUITY_NONE) { 266 return; 267 } 268 269 mEOSResult = OK; 270 mLastQueuedTimeUs = 0; 271 mLatestEnqueuedMeta = NULL; 272 ++mQueuedDiscontinuityCount; 273 274 sp<ABuffer> buffer = new ABuffer(0); 275 buffer->meta()->setInt32("discontinuity", static_cast<int32_t>(type)); 276 buffer->meta()->setMessage("extra", extra); 277 278 mBuffers.push_back(buffer); 279 mCondition.signal(); 280} 281 282void AnotherPacketSource::signalEOS(status_t result) { 283 CHECK(result != OK); 284 285 Mutex::Autolock autoLock(mLock); 286 mEOSResult = result; 287 mCondition.signal(); 288} 289 290bool AnotherPacketSource::hasBufferAvailable(status_t *finalResult) { 291 Mutex::Autolock autoLock(mLock); 292 if (!mBuffers.empty()) { 293 return true; 294 } 295 296 *finalResult = mEOSResult; 297 return false; 298} 299 300int64_t AnotherPacketSource::getBufferedDurationUs(status_t *finalResult) { 301 Mutex::Autolock autoLock(mLock); 302 return getBufferedDurationUs_l(finalResult); 303} 304 305int64_t AnotherPacketSource::getBufferedDurationUs_l(status_t *finalResult) { 306 *finalResult = mEOSResult; 307 308 if (mBuffers.empty()) { 309 return 0; 310 } 311 312 int64_t time1 = -1; 313 int64_t time2 = -1; 314 int64_t durationUs = 0; 315 316 List<sp<ABuffer> >::iterator it = mBuffers.begin(); 317 while (it != mBuffers.end()) { 318 const sp<ABuffer> &buffer = *it; 319 320 int64_t timeUs; 321 if (buffer->meta()->findInt64("timeUs", &timeUs)) { 322 if (time1 < 0 || timeUs < time1) { 323 time1 = timeUs; 324 } 325 326 if (time2 < 0 || timeUs > time2) { 327 time2 = timeUs; 328 } 329 } else { 330 // This is a discontinuity, reset everything. 331 durationUs += time2 - time1; 332 time1 = time2 = -1; 333 } 334 335 ++it; 336 } 337 338 return durationUs + (time2 - time1); 339} 340 341// A cheaper but less precise version of getBufferedDurationUs that we would like to use in 342// LiveSession::dequeueAccessUnit to trigger downwards adaptation. 343int64_t AnotherPacketSource::getEstimatedDurationUs() { 344 Mutex::Autolock autoLock(mLock); 345 if (mBuffers.empty()) { 346 return 0; 347 } 348 349 if (mQueuedDiscontinuityCount > 0) { 350 status_t finalResult; 351 return getBufferedDurationUs_l(&finalResult); 352 } 353 354 List<sp<ABuffer> >::iterator it = mBuffers.begin(); 355 sp<ABuffer> buffer = *it; 356 357 int64_t startTimeUs; 358 buffer->meta()->findInt64("timeUs", &startTimeUs); 359 if (startTimeUs < 0) { 360 return 0; 361 } 362 363 it = mBuffers.end(); 364 --it; 365 buffer = *it; 366 367 int64_t endTimeUs; 368 buffer->meta()->findInt64("timeUs", &endTimeUs); 369 if (endTimeUs < 0) { 370 return 0; 371 } 372 373 int64_t diffUs; 374 if (endTimeUs > startTimeUs) { 375 diffUs = endTimeUs - startTimeUs; 376 } else { 377 diffUs = startTimeUs - endTimeUs; 378 } 379 return diffUs; 380} 381 382status_t AnotherPacketSource::nextBufferTime(int64_t *timeUs) { 383 *timeUs = 0; 384 385 Mutex::Autolock autoLock(mLock); 386 387 if (mBuffers.empty()) { 388 return mEOSResult != OK ? mEOSResult : -EWOULDBLOCK; 389 } 390 391 sp<ABuffer> buffer = *mBuffers.begin(); 392 CHECK(buffer->meta()->findInt64("timeUs", timeUs)); 393 394 return OK; 395} 396 397bool AnotherPacketSource::isFinished(int64_t duration) const { 398 if (duration > 0) { 399 int64_t diff = duration - mLastQueuedTimeUs; 400 if (diff < kNearEOSMarkUs && diff > -kNearEOSMarkUs) { 401 ALOGV("Detecting EOS due to near end"); 402 return true; 403 } 404 } 405 return (mEOSResult != OK); 406} 407 408sp<AMessage> AnotherPacketSource::getLatestEnqueuedMeta() { 409 Mutex::Autolock autoLock(mLock); 410 return mLatestEnqueuedMeta; 411} 412 413sp<AMessage> AnotherPacketSource::getLatestDequeuedMeta() { 414 Mutex::Autolock autoLock(mLock); 415 return mLatestDequeuedMeta; 416} 417 418} // namespace android 419