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