• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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