AnotherPacketSource.cpp revision 5bb7e181d9156135e56ce44a3d0bd42eb31a9ee8
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            sp<RefBase> object;
96            if (buffer->meta()->findObject("format", &object)) {
97                return mFormat = static_cast<MetaData*>(object.get());
98            }
99        }
100
101        ++it;
102    }
103    return NULL;
104}
105
106status_t AnotherPacketSource::dequeueAccessUnit(sp<ABuffer> *buffer) {
107    buffer->clear();
108
109    Mutex::Autolock autoLock(mLock);
110    while (mEOSResult == OK && mBuffers.empty()) {
111        mCondition.wait(mLock);
112    }
113
114    if (!mBuffers.empty()) {
115        *buffer = *mBuffers.begin();
116        mBuffers.erase(mBuffers.begin());
117
118        int32_t discontinuity;
119        if ((*buffer)->meta()->findInt32("discontinuity", &discontinuity)) {
120            if (wasFormatChange(discontinuity)) {
121                mFormat.clear();
122            }
123
124            --mQueuedDiscontinuityCount;
125            return INFO_DISCONTINUITY;
126        }
127
128        mLatestDequeuedMeta = (*buffer)->meta()->dup();
129
130        sp<RefBase> object;
131        if ((*buffer)->meta()->findObject("format", &object)) {
132            mFormat = static_cast<MetaData*>(object.get());
133        }
134
135        return OK;
136    }
137
138    return mEOSResult;
139}
140
141status_t AnotherPacketSource::read(
142        MediaBuffer **out, const ReadOptions *) {
143    *out = NULL;
144
145    Mutex::Autolock autoLock(mLock);
146    while (mEOSResult == OK && mBuffers.empty()) {
147        mCondition.wait(mLock);
148    }
149
150    if (!mBuffers.empty()) {
151
152        const sp<ABuffer> buffer = *mBuffers.begin();
153        mBuffers.erase(mBuffers.begin());
154        mLatestDequeuedMeta = buffer->meta()->dup();
155
156        int32_t discontinuity;
157        if (buffer->meta()->findInt32("discontinuity", &discontinuity)) {
158            if (wasFormatChange(discontinuity)) {
159                mFormat.clear();
160            }
161
162            return INFO_DISCONTINUITY;
163        }
164
165        sp<RefBase> object;
166        if (buffer->meta()->findObject("format", &object)) {
167            mFormat = static_cast<MetaData*>(object.get());
168        }
169
170        int64_t timeUs;
171        CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
172
173        MediaBuffer *mediaBuffer = new MediaBuffer(buffer);
174
175        mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs);
176
177        *out = mediaBuffer;
178        return OK;
179    }
180
181    return mEOSResult;
182}
183
184bool AnotherPacketSource::wasFormatChange(
185        int32_t discontinuityType) const {
186    if (mIsAudio) {
187        return (discontinuityType & ATSParser::DISCONTINUITY_AUDIO_FORMAT) != 0;
188    }
189
190    if (mIsVideo) {
191        return (discontinuityType & ATSParser::DISCONTINUITY_VIDEO_FORMAT) != 0;
192    }
193
194    return false;
195}
196
197void AnotherPacketSource::queueAccessUnit(const sp<ABuffer> &buffer) {
198    int32_t damaged;
199    if (buffer->meta()->findInt32("damaged", &damaged) && damaged) {
200        // LOG(VERBOSE) << "discarding damaged AU";
201        return;
202    }
203
204    int64_t lastQueuedTimeUs;
205    CHECK(buffer->meta()->findInt64("timeUs", &lastQueuedTimeUs));
206    mLastQueuedTimeUs = lastQueuedTimeUs;
207    ALOGV("queueAccessUnit timeUs=%" PRIi64 " us (%.2f secs)", mLastQueuedTimeUs, mLastQueuedTimeUs / 1E6);
208
209    Mutex::Autolock autoLock(mLock);
210    mBuffers.push_back(buffer);
211    mCondition.signal();
212
213    int32_t discontinuity;
214    if (buffer->meta()->findInt32("discontinuity", &discontinuity)) {
215        ++mQueuedDiscontinuityCount;
216    }
217
218    if (mLatestEnqueuedMeta == NULL) {
219        mLatestEnqueuedMeta = buffer->meta()->dup();
220    } else {
221        int64_t latestTimeUs = 0;
222        int64_t frameDeltaUs = 0;
223        CHECK(mLatestEnqueuedMeta->findInt64("timeUs", &latestTimeUs));
224        if (lastQueuedTimeUs > latestTimeUs) {
225            mLatestEnqueuedMeta = buffer->meta()->dup();
226            frameDeltaUs = lastQueuedTimeUs - latestTimeUs;
227            mLatestEnqueuedMeta->setInt64("durationUs", frameDeltaUs);
228        } else if (!mLatestEnqueuedMeta->findInt64("durationUs", &frameDeltaUs)) {
229            // For B frames
230            frameDeltaUs = latestTimeUs - lastQueuedTimeUs;
231            mLatestEnqueuedMeta->setInt64("durationUs", frameDeltaUs);
232        }
233    }
234}
235
236void AnotherPacketSource::clear() {
237    Mutex::Autolock autoLock(mLock);
238
239    mBuffers.clear();
240    mEOSResult = OK;
241    mQueuedDiscontinuityCount = 0;
242
243    mFormat = NULL;
244    mLatestEnqueuedMeta = NULL;
245}
246
247void AnotherPacketSource::queueDiscontinuity(
248        ATSParser::DiscontinuityType type,
249        const sp<AMessage> &extra,
250        bool discard) {
251    Mutex::Autolock autoLock(mLock);
252
253    if (discard) {
254        // Leave only discontinuities in the queue.
255        List<sp<ABuffer> >::iterator it = mBuffers.begin();
256        while (it != mBuffers.end()) {
257            sp<ABuffer> oldBuffer = *it;
258
259            int32_t oldDiscontinuityType;
260            if (!oldBuffer->meta()->findInt32(
261                        "discontinuity", &oldDiscontinuityType)) {
262                it = mBuffers.erase(it);
263                continue;
264            }
265
266            ++it;
267        }
268    }
269
270    mEOSResult = OK;
271    mLastQueuedTimeUs = 0;
272    mLatestEnqueuedMeta = NULL;
273
274    if (type == ATSParser::DISCONTINUITY_NONE) {
275        return;
276    }
277
278    ++mQueuedDiscontinuityCount;
279    sp<ABuffer> buffer = new ABuffer(0);
280    buffer->meta()->setInt32("discontinuity", static_cast<int32_t>(type));
281    buffer->meta()->setMessage("extra", extra);
282
283    mBuffers.push_back(buffer);
284    mCondition.signal();
285}
286
287void AnotherPacketSource::signalEOS(status_t result) {
288    CHECK(result != OK);
289
290    Mutex::Autolock autoLock(mLock);
291    mEOSResult = result;
292    mCondition.signal();
293}
294
295bool AnotherPacketSource::hasBufferAvailable(status_t *finalResult) {
296    Mutex::Autolock autoLock(mLock);
297    if (!mBuffers.empty()) {
298        return true;
299    }
300
301    *finalResult = mEOSResult;
302    return false;
303}
304
305int64_t AnotherPacketSource::getBufferedDurationUs(status_t *finalResult) {
306    Mutex::Autolock autoLock(mLock);
307    return getBufferedDurationUs_l(finalResult);
308}
309
310int64_t AnotherPacketSource::getBufferedDurationUs_l(status_t *finalResult) {
311    *finalResult = mEOSResult;
312
313    if (mBuffers.empty()) {
314        return 0;
315    }
316
317    int64_t time1 = -1;
318    int64_t time2 = -1;
319    int64_t durationUs = 0;
320
321    List<sp<ABuffer> >::iterator it = mBuffers.begin();
322    while (it != mBuffers.end()) {
323        const sp<ABuffer> &buffer = *it;
324
325        int64_t timeUs;
326        if (buffer->meta()->findInt64("timeUs", &timeUs)) {
327            if (time1 < 0 || timeUs < time1) {
328                time1 = timeUs;
329            }
330
331            if (time2 < 0 || timeUs > time2) {
332                time2 = timeUs;
333            }
334        } else {
335            // This is a discontinuity, reset everything.
336            durationUs += time2 - time1;
337            time1 = time2 = -1;
338        }
339
340        ++it;
341    }
342
343    return durationUs + (time2 - time1);
344}
345
346// A cheaper but less precise version of getBufferedDurationUs that we would like to use in
347// LiveSession::dequeueAccessUnit to trigger downwards adaptation.
348int64_t AnotherPacketSource::getEstimatedDurationUs() {
349    Mutex::Autolock autoLock(mLock);
350    if (mBuffers.empty()) {
351        return 0;
352    }
353
354    if (mQueuedDiscontinuityCount > 0) {
355        status_t finalResult;
356        return getBufferedDurationUs_l(&finalResult);
357    }
358
359    List<sp<ABuffer> >::iterator it = mBuffers.begin();
360    sp<ABuffer> buffer = *it;
361
362    int64_t startTimeUs;
363    buffer->meta()->findInt64("timeUs", &startTimeUs);
364    if (startTimeUs < 0) {
365        return 0;
366    }
367
368    it = mBuffers.end();
369    --it;
370    buffer = *it;
371
372    int64_t endTimeUs;
373    buffer->meta()->findInt64("timeUs", &endTimeUs);
374    if (endTimeUs < 0) {
375        return 0;
376    }
377
378    int64_t diffUs;
379    if (endTimeUs > startTimeUs) {
380        diffUs = endTimeUs - startTimeUs;
381    } else {
382        diffUs = startTimeUs - endTimeUs;
383    }
384    return diffUs;
385}
386
387status_t AnotherPacketSource::nextBufferTime(int64_t *timeUs) {
388    *timeUs = 0;
389
390    Mutex::Autolock autoLock(mLock);
391
392    if (mBuffers.empty()) {
393        return mEOSResult != OK ? mEOSResult : -EWOULDBLOCK;
394    }
395
396    sp<ABuffer> buffer = *mBuffers.begin();
397    CHECK(buffer->meta()->findInt64("timeUs", timeUs));
398
399    return OK;
400}
401
402bool AnotherPacketSource::isFinished(int64_t duration) const {
403    if (duration > 0) {
404        int64_t diff = duration - mLastQueuedTimeUs;
405        if (diff < kNearEOSMarkUs && diff > -kNearEOSMarkUs) {
406            ALOGV("Detecting EOS due to near end");
407            return true;
408        }
409    }
410    return (mEOSResult != OK);
411}
412
413sp<AMessage> AnotherPacketSource::getLatestEnqueuedMeta() {
414    Mutex::Autolock autoLock(mLock);
415    return mLatestEnqueuedMeta;
416}
417
418sp<AMessage> AnotherPacketSource::getLatestDequeuedMeta() {
419    Mutex::Autolock autoLock(mLock);
420    return mLatestDequeuedMeta;
421}
422
423}  // namespace android
424