Ajit Khare | 470d092 | 2013-01-21 01:11:06 -0800 | [diff] [blame] | 1 | /* |
| 2 | *Copyright (c) 2013, The Linux Foundation. All rights reserved. |
| 3 | *Not a Contribution, Apache license notifications and license are retained |
| 4 | *for attribution purposes only. |
| 5 | *Copyright (C) 2010 The Android Open Source Project |
| 6 | * |
| 7 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 8 | * you may not use this file except in compliance with the License. |
| 9 | * You may obtain a copy of the License at |
| 10 | * |
| 11 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 12 | * |
| 13 | * Unless required by applicable law or agreed to in writing, software |
| 14 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 16 | * See the License for the specific language governing permissions and |
| 17 | * limitations under the License. |
| 18 | */ |
| 19 | |
| 20 | #include "DashPacketSource.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 | namespace android { |
| 33 | |
| 34 | DashPacketSource::DashPacketSource(const sp<MetaData> &meta) |
| 35 | : mIsAudio(false), |
| 36 | mFormat(meta), |
| 37 | mEOSResult(OK), |
| 38 | mStreamPID(0), |
| 39 | mProgramPID(0), |
| 40 | mFirstPTS(0) { |
| 41 | const char *mime; |
| 42 | CHECK(meta->findCString(kKeyMIMEType, &mime)); |
| 43 | |
| 44 | if (!strncasecmp("audio/", mime, 6)) { |
| 45 | mIsAudio = true; |
| 46 | } |
| 47 | } |
| 48 | |
| 49 | void DashPacketSource::setFormat(const sp<MetaData> &meta) { |
| 50 | Mutex::Autolock autoLock(mLock); |
| 51 | CHECK(mFormat == NULL); |
| 52 | mFormat = meta; |
| 53 | } |
| 54 | |
| 55 | void DashPacketSource::updateFormat(const sp<MetaData> &meta) { |
| 56 | Mutex::Autolock autoLock(mLock); |
| 57 | mFormat = meta; |
| 58 | } |
| 59 | |
| 60 | DashPacketSource::~DashPacketSource() { |
| 61 | } |
| 62 | |
| 63 | status_t DashPacketSource::start(MetaData *params) { |
| 64 | return OK; |
| 65 | } |
| 66 | |
| 67 | status_t DashPacketSource::stop() { |
| 68 | return OK; |
| 69 | } |
| 70 | |
| 71 | void DashPacketSource::setStreamInfo(unsigned streamPID, unsigned programPID, uint64_t firstPTS){ |
| 72 | mStreamPID = streamPID; |
| 73 | mProgramPID = programPID; |
| 74 | mFirstPTS = firstPTS; |
| 75 | } |
| 76 | |
| 77 | status_t DashPacketSource::getStreamInfo(unsigned& streamPID, unsigned& programPID, uint64_t& firstPTS){ |
| 78 | streamPID = mStreamPID; |
| 79 | programPID = mProgramPID; |
| 80 | firstPTS = mFirstPTS; |
| 81 | return OK; |
| 82 | } |
| 83 | |
| 84 | sp<MetaData> DashPacketSource::getFormat() { |
| 85 | Mutex::Autolock autoLock(mLock); |
| 86 | return mFormat; |
| 87 | } |
| 88 | |
| 89 | status_t DashPacketSource::dequeueAccessUnit(sp<ABuffer> *buffer) { |
| 90 | buffer->clear(); |
| 91 | |
| 92 | Mutex::Autolock autoLock(mLock); |
| 93 | while (mEOSResult == OK && mBuffers.empty()) { |
| 94 | mCondition.wait(mLock); |
| 95 | } |
| 96 | |
| 97 | if (!mBuffers.empty()) { |
| 98 | *buffer = *mBuffers.begin(); |
| 99 | mBuffers.erase(mBuffers.begin()); |
| 100 | |
| 101 | int32_t discontinuity; |
| 102 | if ((*buffer)->meta()->findInt32("discontinuity", &discontinuity)) { |
| 103 | if (wasFormatChange(discontinuity)) { |
| 104 | mFormat.clear(); |
| 105 | } |
| 106 | |
| 107 | return INFO_DISCONTINUITY; |
| 108 | } |
| 109 | |
| 110 | return OK; |
| 111 | } |
| 112 | |
| 113 | return mEOSResult; |
| 114 | } |
| 115 | |
| 116 | status_t DashPacketSource::read( |
| 117 | MediaBuffer **out, const ReadOptions *) { |
| 118 | *out = NULL; |
| 119 | |
| 120 | Mutex::Autolock autoLock(mLock); |
| 121 | while (mEOSResult == OK && mBuffers.empty()) { |
| 122 | mCondition.wait(mLock); |
| 123 | } |
| 124 | |
| 125 | if (!mBuffers.empty()) { |
| 126 | const sp<ABuffer> buffer = *mBuffers.begin(); |
| 127 | mBuffers.erase(mBuffers.begin()); |
| 128 | |
| 129 | int32_t discontinuity; |
| 130 | if (buffer->meta()->findInt32("discontinuity", &discontinuity)) { |
| 131 | if (wasFormatChange(discontinuity)) { |
| 132 | mFormat.clear(); |
| 133 | } |
| 134 | |
| 135 | return INFO_DISCONTINUITY; |
| 136 | } else { |
| 137 | int64_t timeUs; |
| 138 | CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); |
| 139 | |
| 140 | MediaBuffer *mediaBuffer = new MediaBuffer(buffer); |
| 141 | |
| 142 | mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs); |
| 143 | |
| 144 | *out = mediaBuffer; |
| 145 | return OK; |
| 146 | } |
| 147 | } |
| 148 | |
| 149 | return mEOSResult; |
| 150 | } |
| 151 | |
| 152 | bool DashPacketSource::wasFormatChange( |
| 153 | int32_t discontinuityType) const { |
| 154 | if (mIsAudio) { |
| 155 | return (discontinuityType & ATSParser::DISCONTINUITY_AUDIO_FORMAT) != 0; |
| 156 | } |
| 157 | |
| 158 | return (discontinuityType & ATSParser::DISCONTINUITY_VIDEO_FORMAT) != 0; |
| 159 | } |
| 160 | |
| 161 | void DashPacketSource::queueAccessUnit(const sp<ABuffer> &buffer) { |
| 162 | int32_t damaged; |
| 163 | if (buffer->meta()->findInt32("damaged", &damaged) && damaged) { |
| 164 | // LOG(VERBOSE) << "discarding damaged AU"; |
| 165 | return; |
| 166 | } |
| 167 | |
| 168 | int64_t timeUs; |
| 169 | CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); |
| 170 | ALOGV("queueAccessUnit timeUs=%lld us (%.2f secs)", timeUs, timeUs / 1E6); |
| 171 | |
| 172 | Mutex::Autolock autoLock(mLock); |
| 173 | mBuffers.push_back(buffer); |
| 174 | ALOGV("@@@@:: DashPacketSource --> size is %d ",mBuffers.size() ); |
| 175 | mCondition.signal(); |
| 176 | } |
| 177 | |
| 178 | int DashPacketSource::getQueueSize() { |
| 179 | return mBuffers.size(); |
| 180 | } |
| 181 | |
| 182 | void DashPacketSource::queueDiscontinuity( |
| 183 | ATSParser::DiscontinuityType type, |
| 184 | const sp<AMessage> &extra) { |
| 185 | Mutex::Autolock autoLock(mLock); |
| 186 | |
| 187 | if (type == ATSParser::DISCONTINUITY_SEEK || |
| 188 | type == ATSParser::DISCONTINUITY_SEEK) { |
| 189 | ALOGI("Flushing all Access units for seek"); |
| 190 | mBuffers.clear(); |
| 191 | mEOSResult = OK; |
| 192 | mCondition.signal(); |
| 193 | return; |
| 194 | } |
| 195 | |
| 196 | // Leave only discontinuities in the queue. |
| 197 | List<sp<ABuffer> >::iterator it = mBuffers.begin(); |
| 198 | while (it != mBuffers.end()) { |
| 199 | sp<ABuffer> oldBuffer = *it; |
| 200 | |
| 201 | int32_t oldDiscontinuityType; |
| 202 | if (!oldBuffer->meta()->findInt32( |
| 203 | "discontinuity", &oldDiscontinuityType)) { |
| 204 | it = mBuffers.erase(it); |
| 205 | continue; |
| 206 | } |
| 207 | |
| 208 | ++it; |
| 209 | } |
| 210 | |
| 211 | mEOSResult = OK; |
| 212 | |
| 213 | sp<ABuffer> buffer = new ABuffer(0); |
| 214 | buffer->meta()->setInt32("discontinuity", static_cast<int32_t>(type)); |
| 215 | buffer->meta()->setMessage("extra", extra); |
| 216 | |
| 217 | mBuffers.push_back(buffer); |
| 218 | mCondition.signal(); |
| 219 | } |
| 220 | |
| 221 | void DashPacketSource::signalEOS(status_t result) { |
| 222 | CHECK(result != OK); |
| 223 | |
| 224 | Mutex::Autolock autoLock(mLock); |
| 225 | mEOSResult = result; |
| 226 | mCondition.signal(); |
| 227 | } |
| 228 | |
| 229 | bool DashPacketSource::hasBufferAvailable(status_t *finalResult) { |
| 230 | Mutex::Autolock autoLock(mLock); |
| 231 | if (!mBuffers.empty()) { |
| 232 | return true; |
| 233 | } |
| 234 | |
| 235 | *finalResult = mEOSResult; |
| 236 | return false; |
| 237 | } |
| 238 | |
| 239 | int64_t DashPacketSource::getBufferedDurationUs(status_t *finalResult) { |
| 240 | Mutex::Autolock autoLock(mLock); |
| 241 | |
| 242 | *finalResult = mEOSResult; |
| 243 | |
| 244 | if (mBuffers.empty()) { |
| 245 | return 0; |
| 246 | } |
| 247 | |
| 248 | int64_t time1 = -1; |
| 249 | int64_t time2 = -1; |
| 250 | |
| 251 | List<sp<ABuffer> >::iterator it = mBuffers.begin(); |
| 252 | while (it != mBuffers.end()) { |
| 253 | const sp<ABuffer> &buffer = *it; |
| 254 | |
| 255 | int64_t timeUs; |
| 256 | if (buffer->meta()->findInt64("timeUs", &timeUs)) { |
| 257 | if (time1 < 0) { |
| 258 | time1 = timeUs; |
| 259 | } |
| 260 | |
| 261 | time2 = timeUs; |
| 262 | } else { |
| 263 | // This is a discontinuity, reset everything. |
| 264 | time1 = time2 = -1; |
| 265 | } |
| 266 | |
| 267 | ++it; |
| 268 | } |
| 269 | |
| 270 | return time2 - time1; |
| 271 | } |
| 272 | |
| 273 | status_t DashPacketSource::nextBufferTime(int64_t *timeUs) { |
| 274 | *timeUs = 0; |
| 275 | |
| 276 | Mutex::Autolock autoLock(mLock); |
| 277 | |
| 278 | if (mBuffers.empty()) { |
| 279 | return mEOSResult != OK ? mEOSResult : -EWOULDBLOCK; |
| 280 | } |
| 281 | |
| 282 | sp<ABuffer> buffer = *mBuffers.begin(); |
| 283 | CHECK(buffer->meta()->findInt64("timeUs", timeUs)); |
| 284 | return OK; |
| 285 | } |
| 286 | |
| 287 | status_t DashPacketSource::nextBufferIsSync(bool* isSyncFrame) { |
| 288 | Mutex::Autolock autoLock(mLock); |
| 289 | CHECK(isSyncFrame != NULL); |
| 290 | |
| 291 | if (mBuffers.empty()) { |
| 292 | return mEOSResult != OK ? mEOSResult : -EWOULDBLOCK; |
| 293 | } |
| 294 | |
| 295 | sp<ABuffer> buffer = *mBuffers.begin(); |
| 296 | |
| 297 | *isSyncFrame = false; |
| 298 | int32_t value = 0; |
| 299 | if (buffer->meta()->findInt32("isSync", &value) && (value == 1)) { |
| 300 | *isSyncFrame = true; |
| 301 | } |
| 302 | return OK; |
| 303 | } |
| 304 | |
| 305 | } // namespace android |