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
AnotherPacketSource(const sp<MetaData> & meta)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
setFormat(const sp<MetaData> & meta)48 void AnotherPacketSource::setFormat(const sp<MetaData> &meta) {
49 CHECK(mFormat == NULL);
50 mFormat = meta;
51 }
52
~AnotherPacketSource()53 AnotherPacketSource::~AnotherPacketSource() {
54 }
55
start(MetaData * params)56 status_t AnotherPacketSource::start(MetaData *params) {
57 return OK;
58 }
59
stop()60 status_t AnotherPacketSource::stop() {
61 return OK;
62 }
63
getFormat()64 sp<MetaData> AnotherPacketSource::getFormat() {
65 return mFormat;
66 }
67
dequeueAccessUnit(sp<ABuffer> * buffer)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
read(MediaBuffer ** out,const ReadOptions *)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
wasFormatChange(int32_t discontinuityType) const131 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
queueAccessUnit(const sp<ABuffer> & buffer)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
queueDiscontinuity(ATSParser::DiscontinuityType type,const sp<AMessage> & extra)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
signalEOS(status_t result)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
hasBufferAvailable(status_t * finalResult)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
getBufferedDurationUs(status_t * finalResult)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
nextBufferTime(int64_t * timeUs)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
isFinished(int64_t duration) const253 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