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/foundation/avc_utils.h>
28#include <media/stagefright/MediaBuffer.h>
29#include <media/stagefright/MediaDefs.h>
30#include <media/stagefright/MetaData.h>
31#include <media/stagefright/Utils.h>
32#include <utils/Vector.h>
33
34#include <inttypes.h>
35
36namespace android {
37
38const int64_t kNearEOSMarkUs = 2000000ll; // 2 secs
39
40AnotherPacketSource::AnotherPacketSource(const sp<MetaData> &meta)
41    : mIsAudio(false),
42      mIsVideo(false),
43      mEnabled(true),
44      mFormat(NULL),
45      mLastQueuedTimeUs(0),
46      mEstimatedBufferDurationUs(-1),
47      mEOSResult(OK),
48      mLatestEnqueuedMeta(NULL),
49      mLatestDequeuedMeta(NULL) {
50    setFormat(meta);
51
52    mDiscontinuitySegments.push_back(DiscontinuitySegment());
53}
54
55void AnotherPacketSource::setFormat(const sp<MetaData> &meta) {
56    if (mFormat != NULL) {
57        // Only allowed to be set once. Requires explicit clear to reset.
58        return;
59    }
60
61    mIsAudio = false;
62    mIsVideo = false;
63
64    if (meta == NULL) {
65        return;
66    }
67
68    mFormat = meta;
69    const char *mime;
70    CHECK(meta->findCString(kKeyMIMEType, &mime));
71
72    if (!strncasecmp("audio/", mime, 6)) {
73        mIsAudio = true;
74    } else  if (!strncasecmp("video/", mime, 6)) {
75        mIsVideo = true;
76    } else {
77        CHECK(!strncasecmp("text/", mime, 5) || !strncasecmp("application/", mime, 12));
78    }
79}
80
81AnotherPacketSource::~AnotherPacketSource() {
82}
83
84status_t AnotherPacketSource::start(MetaData * /* params */) {
85    return OK;
86}
87
88status_t AnotherPacketSource::stop() {
89    return OK;
90}
91
92sp<MetaData> AnotherPacketSource::getFormat() {
93    Mutex::Autolock autoLock(mLock);
94    if (mFormat != NULL) {
95        return mFormat;
96    }
97
98    List<sp<ABuffer> >::iterator it = mBuffers.begin();
99    while (it != mBuffers.end()) {
100        sp<ABuffer> buffer = *it;
101        int32_t discontinuity;
102        if (!buffer->meta()->findInt32("discontinuity", &discontinuity)) {
103            sp<RefBase> object;
104            if (buffer->meta()->findObject("format", &object)) {
105                setFormat(static_cast<MetaData*>(object.get()));
106                return mFormat;
107            }
108        }
109
110        ++it;
111    }
112    return NULL;
113}
114
115status_t AnotherPacketSource::dequeueAccessUnit(sp<ABuffer> *buffer) {
116    buffer->clear();
117
118    Mutex::Autolock autoLock(mLock);
119    while (mEOSResult == OK && mBuffers.empty()) {
120        mCondition.wait(mLock);
121    }
122
123    if (!mBuffers.empty()) {
124        *buffer = *mBuffers.begin();
125        mBuffers.erase(mBuffers.begin());
126
127        int32_t discontinuity;
128        if ((*buffer)->meta()->findInt32("discontinuity", &discontinuity)) {
129            if (wasFormatChange(discontinuity)) {
130                mFormat.clear();
131            }
132
133            mDiscontinuitySegments.erase(mDiscontinuitySegments.begin());
134            // CHECK(!mDiscontinuitySegments.empty());
135            return INFO_DISCONTINUITY;
136        }
137
138        // CHECK(!mDiscontinuitySegments.empty());
139        DiscontinuitySegment &seg = *mDiscontinuitySegments.begin();
140
141        int64_t timeUs;
142        mLatestDequeuedMeta = (*buffer)->meta()->dup();
143        CHECK(mLatestDequeuedMeta->findInt64("timeUs", &timeUs));
144        if (timeUs > seg.mMaxDequeTimeUs) {
145            seg.mMaxDequeTimeUs = timeUs;
146        }
147
148        sp<RefBase> object;
149        if ((*buffer)->meta()->findObject("format", &object)) {
150            setFormat(static_cast<MetaData*>(object.get()));
151        }
152
153        return OK;
154    }
155
156    return mEOSResult;
157}
158
159void AnotherPacketSource::requeueAccessUnit(const sp<ABuffer> &buffer) {
160    // TODO: update corresponding book keeping info.
161    Mutex::Autolock autoLock(mLock);
162    mBuffers.push_front(buffer);
163}
164
165status_t AnotherPacketSource::read(
166        MediaBufferBase **out, const ReadOptions *) {
167    *out = NULL;
168
169    Mutex::Autolock autoLock(mLock);
170    while (mEOSResult == OK && mBuffers.empty()) {
171        mCondition.wait(mLock);
172    }
173
174    if (!mBuffers.empty()) {
175
176        const sp<ABuffer> buffer = *mBuffers.begin();
177        mBuffers.erase(mBuffers.begin());
178
179        int32_t discontinuity;
180        if (buffer->meta()->findInt32("discontinuity", &discontinuity)) {
181            if (wasFormatChange(discontinuity)) {
182                mFormat.clear();
183            }
184
185            mDiscontinuitySegments.erase(mDiscontinuitySegments.begin());
186            // CHECK(!mDiscontinuitySegments.empty());
187            return INFO_DISCONTINUITY;
188        }
189
190        mLatestDequeuedMeta = buffer->meta()->dup();
191
192        sp<RefBase> object;
193        if (buffer->meta()->findObject("format", &object)) {
194            setFormat(static_cast<MetaData*>(object.get()));
195        }
196
197        int64_t timeUs;
198        CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
199        // CHECK(!mDiscontinuitySegments.empty());
200        DiscontinuitySegment &seg = *mDiscontinuitySegments.begin();
201        if (timeUs > seg.mMaxDequeTimeUs) {
202            seg.mMaxDequeTimeUs = timeUs;
203        }
204
205        MediaBufferBase *mediaBuffer = new MediaBuffer(buffer);
206        MetaDataBase &bufmeta = mediaBuffer->meta_data();
207
208        bufmeta.setInt64(kKeyTime, timeUs);
209
210        int32_t isSync;
211        if (buffer->meta()->findInt32("isSync", &isSync)) {
212            bufmeta.setInt32(kKeyIsSyncFrame, isSync);
213        }
214
215        sp<ABuffer> sei;
216        if (buffer->meta()->findBuffer("sei", &sei) && sei != NULL) {
217            bufmeta.setData(kKeySEI, 0, sei->data(), sei->size());
218        }
219
220        sp<ABuffer> mpegUserData;
221        if (buffer->meta()->findBuffer("mpeg-user-data", &mpegUserData) && mpegUserData != NULL) {
222            bufmeta.setData(
223                    kKeyMpegUserData, 0, mpegUserData->data(), mpegUserData->size());
224        }
225
226        int32_t cryptoMode;
227        if (buffer->meta()->findInt32("cryptoMode", &cryptoMode)) {
228            int32_t cryptoKey;
229            sp<ABuffer> clearBytesBuffer, encBytesBuffer;
230
231            CHECK(buffer->meta()->findInt32("cryptoKey", &cryptoKey));
232            CHECK(buffer->meta()->findBuffer("clearBytes", &clearBytesBuffer)
233                    && clearBytesBuffer != NULL);
234            CHECK(buffer->meta()->findBuffer("encBytes", &encBytesBuffer)
235                    && encBytesBuffer != NULL);
236
237            bufmeta.setInt32(kKeyCryptoMode, cryptoMode);
238
239            uint8_t array[16] = {0};
240            bufmeta.setData(kKeyCryptoIV, 0, array, 16);
241
242            array[0] = (uint8_t) (cryptoKey & 0xff);
243            bufmeta.setData(kKeyCryptoKey, 0, array, 16);
244
245            bufmeta.setData(kKeyPlainSizes, 0,
246                    clearBytesBuffer->data(), clearBytesBuffer->size());
247
248            bufmeta.setData(kKeyEncryptedSizes, 0,
249                    encBytesBuffer->data(), encBytesBuffer->size());
250        }
251
252
253        *out = mediaBuffer;
254        return OK;
255    }
256
257    return mEOSResult;
258}
259
260bool AnotherPacketSource::wasFormatChange(
261        int32_t discontinuityType) const {
262    if (mIsAudio) {
263        return (discontinuityType & ATSParser::DISCONTINUITY_AUDIO_FORMAT) != 0;
264    }
265
266    if (mIsVideo) {
267        return (discontinuityType & ATSParser::DISCONTINUITY_VIDEO_FORMAT) != 0;
268    }
269
270    return false;
271}
272
273void AnotherPacketSource::queueAccessUnit(const sp<ABuffer> &buffer) {
274    int32_t damaged;
275    if (buffer->meta()->findInt32("damaged", &damaged) && damaged) {
276        // LOG(VERBOSE) << "discarding damaged AU";
277        return;
278    }
279
280    Mutex::Autolock autoLock(mLock);
281    mBuffers.push_back(buffer);
282    mCondition.signal();
283
284    int32_t discontinuity;
285    if (buffer->meta()->findInt32("discontinuity", &discontinuity)){
286        ALOGV("queueing a discontinuity with queueAccessUnit");
287
288        mLastQueuedTimeUs = 0ll;
289        mEOSResult = OK;
290        mLatestEnqueuedMeta = NULL;
291
292        mDiscontinuitySegments.push_back(DiscontinuitySegment());
293        return;
294    }
295
296    int64_t lastQueuedTimeUs;
297    CHECK(buffer->meta()->findInt64("timeUs", &lastQueuedTimeUs));
298    mLastQueuedTimeUs = lastQueuedTimeUs;
299    ALOGV("queueAccessUnit timeUs=%" PRIi64 " us (%.2f secs)",
300            mLastQueuedTimeUs, mLastQueuedTimeUs / 1E6);
301
302    // CHECK(!mDiscontinuitySegments.empty());
303    DiscontinuitySegment &tailSeg = *(--mDiscontinuitySegments.end());
304    if (lastQueuedTimeUs > tailSeg.mMaxEnqueTimeUs) {
305        tailSeg.mMaxEnqueTimeUs = lastQueuedTimeUs;
306    }
307    if (tailSeg.mMaxDequeTimeUs == -1) {
308        tailSeg.mMaxDequeTimeUs = lastQueuedTimeUs;
309    }
310
311    if (mLatestEnqueuedMeta == NULL) {
312        mLatestEnqueuedMeta = buffer->meta()->dup();
313    } else {
314        int64_t latestTimeUs = 0;
315        int64_t frameDeltaUs = 0;
316        CHECK(mLatestEnqueuedMeta->findInt64("timeUs", &latestTimeUs));
317        if (lastQueuedTimeUs > latestTimeUs) {
318            mLatestEnqueuedMeta = buffer->meta()->dup();
319            frameDeltaUs = lastQueuedTimeUs - latestTimeUs;
320            mLatestEnqueuedMeta->setInt64("durationUs", frameDeltaUs);
321        } else if (!mLatestEnqueuedMeta->findInt64("durationUs", &frameDeltaUs)) {
322            // For B frames
323            frameDeltaUs = latestTimeUs - lastQueuedTimeUs;
324            mLatestEnqueuedMeta->setInt64("durationUs", frameDeltaUs);
325        }
326    }
327}
328
329void AnotherPacketSource::clear() {
330    Mutex::Autolock autoLock(mLock);
331
332    mBuffers.clear();
333    mEOSResult = OK;
334
335    mDiscontinuitySegments.clear();
336    mDiscontinuitySegments.push_back(DiscontinuitySegment());
337
338    mFormat = NULL;
339    mLatestEnqueuedMeta = NULL;
340
341    mEstimatedBufferDurationUs = -1;
342}
343
344void AnotherPacketSource::queueDiscontinuity(
345        ATSParser::DiscontinuityType type,
346        const sp<AMessage> &extra,
347        bool discard) {
348    Mutex::Autolock autoLock(mLock);
349
350    if (discard) {
351        // Leave only discontinuities in the queue.
352        List<sp<ABuffer> >::iterator it = mBuffers.begin();
353        while (it != mBuffers.end()) {
354            sp<ABuffer> oldBuffer = *it;
355
356            int32_t oldDiscontinuityType;
357            if (!oldBuffer->meta()->findInt32(
358                        "discontinuity", &oldDiscontinuityType)) {
359                it = mBuffers.erase(it);
360                continue;
361            }
362
363            ++it;
364        }
365
366        for (List<DiscontinuitySegment>::iterator it2 = mDiscontinuitySegments.begin();
367                it2 != mDiscontinuitySegments.end();
368                ++it2) {
369            DiscontinuitySegment &seg = *it2;
370            seg.clear();
371        }
372
373    }
374
375    mEOSResult = OK;
376    mLastQueuedTimeUs = 0;
377    mLatestEnqueuedMeta = NULL;
378
379    if (type == ATSParser::DISCONTINUITY_NONE) {
380        return;
381    }
382
383    mDiscontinuitySegments.push_back(DiscontinuitySegment());
384
385    sp<ABuffer> buffer = new ABuffer(0);
386    buffer->meta()->setInt32("discontinuity", static_cast<int32_t>(type));
387    buffer->meta()->setMessage("extra", extra);
388
389    mBuffers.push_back(buffer);
390    mCondition.signal();
391}
392
393void AnotherPacketSource::signalEOS(status_t result) {
394    CHECK(result != OK);
395
396    Mutex::Autolock autoLock(mLock);
397    mEOSResult = result;
398    mCondition.signal();
399}
400
401bool AnotherPacketSource::hasBufferAvailable(status_t *finalResult) {
402    Mutex::Autolock autoLock(mLock);
403    *finalResult = OK;
404    if (!mEnabled) {
405        return false;
406    }
407    if (!mBuffers.empty()) {
408        return true;
409    }
410
411    *finalResult = mEOSResult;
412    return false;
413}
414
415bool AnotherPacketSource::hasDataBufferAvailable(status_t *finalResult) {
416    Mutex::Autolock autoLock(mLock);
417    *finalResult = OK;
418    if (!mEnabled) {
419        return false;
420    }
421    List<sp<ABuffer> >::iterator it;
422    for (it = mBuffers.begin(); it != mBuffers.end(); it++) {
423        int32_t discontinuity;
424        if (!(*it)->meta()->findInt32("discontinuity", &discontinuity)) {
425            return true;
426        }
427    }
428
429    *finalResult = mEOSResult;
430    return false;
431}
432
433size_t AnotherPacketSource::getAvailableBufferCount(status_t *finalResult) {
434    Mutex::Autolock autoLock(mLock);
435
436    *finalResult = OK;
437    if (!mEnabled) {
438        return 0;
439    }
440    if (!mBuffers.empty()) {
441        return mBuffers.size();
442    }
443    *finalResult = mEOSResult;
444    return 0;
445}
446
447int64_t AnotherPacketSource::getBufferedDurationUs(status_t *finalResult) {
448    Mutex::Autolock autoLock(mLock);
449    *finalResult = mEOSResult;
450
451    int64_t durationUs = 0;
452    for (List<DiscontinuitySegment>::iterator it = mDiscontinuitySegments.begin();
453            it != mDiscontinuitySegments.end();
454            ++it) {
455        const DiscontinuitySegment &seg = *it;
456        // dequeued access units should be a subset of enqueued access units
457        // CHECK(seg.maxEnqueTimeUs >= seg.mMaxDequeTimeUs);
458        durationUs += (seg.mMaxEnqueTimeUs - seg.mMaxDequeTimeUs);
459    }
460
461    return durationUs;
462}
463
464int64_t AnotherPacketSource::getEstimatedBufferDurationUs() {
465    Mutex::Autolock autoLock(mLock);
466    if (mEstimatedBufferDurationUs >= 0) {
467        return mEstimatedBufferDurationUs;
468    }
469
470    SortedVector<int64_t> maxTimesUs;
471    List<sp<ABuffer> >::iterator it;
472    int64_t t1 = 0, t2 = 0;
473    for (it = mBuffers.begin(); it != mBuffers.end(); ++it) {
474        int64_t timeUs = 0;
475        const sp<ABuffer> &buffer = *it;
476        if (!buffer->meta()->findInt64("timeUs", &timeUs)) {
477            continue;
478        }
479        maxTimesUs.add(timeUs);
480        while (maxTimesUs.size() > 2) {
481            maxTimesUs.removeAt(0);
482            t1 = maxTimesUs.itemAt(0);
483            t2 = maxTimesUs.itemAt(1);
484        }
485    }
486    return mEstimatedBufferDurationUs = t2 - t1;
487}
488
489status_t AnotherPacketSource::nextBufferTime(int64_t *timeUs) {
490    *timeUs = 0;
491
492    Mutex::Autolock autoLock(mLock);
493
494    if (mBuffers.empty()) {
495        return mEOSResult != OK ? mEOSResult : -EWOULDBLOCK;
496    }
497
498    sp<ABuffer> buffer = *mBuffers.begin();
499    CHECK(buffer->meta()->findInt64("timeUs", timeUs));
500
501    return OK;
502}
503
504bool AnotherPacketSource::isFinished(int64_t duration) const {
505    if (duration > 0) {
506        int64_t diff = duration - mLastQueuedTimeUs;
507        if (diff < kNearEOSMarkUs && diff > -kNearEOSMarkUs) {
508            ALOGV("Detecting EOS due to near end");
509            return true;
510        }
511    }
512    return (mEOSResult != OK);
513}
514
515sp<AMessage> AnotherPacketSource::getLatestEnqueuedMeta() {
516    Mutex::Autolock autoLock(mLock);
517    return mLatestEnqueuedMeta;
518}
519
520sp<AMessage> AnotherPacketSource::getLatestDequeuedMeta() {
521    Mutex::Autolock autoLock(mLock);
522    return mLatestDequeuedMeta;
523}
524
525void AnotherPacketSource::enable(bool enable) {
526    Mutex::Autolock autoLock(mLock);
527    mEnabled = enable;
528}
529
530/*
531 * returns the sample meta that's delayUs after queue head
532 * (NULL if such sample is unavailable)
533 */
534sp<AMessage> AnotherPacketSource::getMetaAfterLastDequeued(int64_t delayUs) {
535    Mutex::Autolock autoLock(mLock);
536    int64_t firstUs = -1;
537    int64_t lastUs = -1;
538    int64_t durationUs = 0;
539
540    List<sp<ABuffer> >::iterator it;
541    for (it = mBuffers.begin(); it != mBuffers.end(); ++it) {
542        const sp<ABuffer> &buffer = *it;
543        int32_t discontinuity;
544        if (buffer->meta()->findInt32("discontinuity", &discontinuity)) {
545            durationUs += lastUs - firstUs;
546            firstUs = -1;
547            lastUs = -1;
548            continue;
549        }
550        int64_t timeUs;
551        if (buffer->meta()->findInt64("timeUs", &timeUs)) {
552            if (firstUs < 0) {
553                firstUs = timeUs;
554            }
555            if (lastUs < 0 || timeUs > lastUs) {
556                lastUs = timeUs;
557            }
558            if (durationUs + (lastUs - firstUs) >= delayUs) {
559                return buffer->meta();
560            }
561        }
562    }
563    return NULL;
564}
565
566/*
567 * removes samples with time equal or after meta
568 */
569void AnotherPacketSource::trimBuffersAfterMeta(
570        const sp<AMessage> &meta) {
571    if (meta == NULL) {
572        ALOGW("trimming with NULL meta, ignoring");
573        return;
574    }
575
576    Mutex::Autolock autoLock(mLock);
577    if (mBuffers.empty()) {
578        return;
579    }
580
581    HLSTime stopTime(meta);
582    ALOGV("trimBuffersAfterMeta: discontinuitySeq %d, timeUs %lld",
583            stopTime.mSeq, (long long)stopTime.mTimeUs);
584
585    List<sp<ABuffer> >::iterator it;
586    List<DiscontinuitySegment >::iterator it2;
587    sp<AMessage> newLatestEnqueuedMeta = NULL;
588    int64_t newLastQueuedTimeUs = 0;
589    for (it = mBuffers.begin(), it2 = mDiscontinuitySegments.begin(); it != mBuffers.end(); ++it) {
590        const sp<ABuffer> &buffer = *it;
591        int32_t discontinuity;
592        if (buffer->meta()->findInt32("discontinuity", &discontinuity)) {
593            // CHECK(it2 != mDiscontinuitySegments.end());
594            ++it2;
595            continue;
596        }
597
598        HLSTime curTime(buffer->meta());
599        if (!(curTime < stopTime)) {
600            ALOGV("trimming from %lld (inclusive) to end",
601                    (long long)curTime.mTimeUs);
602            break;
603        }
604        newLatestEnqueuedMeta = buffer->meta();
605        newLastQueuedTimeUs = curTime.mTimeUs;
606    }
607
608    mBuffers.erase(it, mBuffers.end());
609    mLatestEnqueuedMeta = newLatestEnqueuedMeta;
610    mLastQueuedTimeUs = newLastQueuedTimeUs;
611
612    DiscontinuitySegment &seg = *it2;
613    if (newLatestEnqueuedMeta != NULL) {
614        seg.mMaxEnqueTimeUs = newLastQueuedTimeUs;
615    } else {
616        seg.clear();
617    }
618    mDiscontinuitySegments.erase(++it2, mDiscontinuitySegments.end());
619}
620
621/*
622 * removes samples with time equal or before meta;
623 * returns first sample left in the queue.
624 *
625 * (for AVC, if trim happens, the samples left will always start
626 * at next IDR.)
627 */
628sp<AMessage> AnotherPacketSource::trimBuffersBeforeMeta(
629        const sp<AMessage> &meta) {
630    HLSTime startTime(meta);
631    ALOGV("trimBuffersBeforeMeta: discontinuitySeq %d, timeUs %lld",
632            startTime.mSeq, (long long)startTime.mTimeUs);
633
634    sp<AMessage> firstMeta;
635    int64_t firstTimeUs = -1;
636    Mutex::Autolock autoLock(mLock);
637    if (mBuffers.empty()) {
638        return NULL;
639    }
640
641    sp<MetaData> format;
642    bool isAvc = false;
643
644    List<sp<ABuffer> >::iterator it;
645    for (it = mBuffers.begin(); it != mBuffers.end(); ++it) {
646        const sp<ABuffer> &buffer = *it;
647        int32_t discontinuity;
648        if (buffer->meta()->findInt32("discontinuity", &discontinuity)) {
649            mDiscontinuitySegments.erase(mDiscontinuitySegments.begin());
650            // CHECK(!mDiscontinuitySegments.empty());
651            format = NULL;
652            isAvc = false;
653            continue;
654        }
655        if (format == NULL) {
656            sp<RefBase> object;
657            if (buffer->meta()->findObject("format", &object)) {
658                const char* mime;
659                format = static_cast<MetaData*>(object.get());
660                isAvc = format != NULL
661                        && format->findCString(kKeyMIMEType, &mime)
662                        && !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
663            }
664        }
665        if (isAvc && !IsIDR(buffer->data(), buffer->size())) {
666            continue;
667        }
668
669        HLSTime curTime(buffer->meta());
670        if (startTime < curTime) {
671            ALOGV("trimming from beginning to %lld (not inclusive)",
672                    (long long)curTime.mTimeUs);
673            firstMeta = buffer->meta();
674            firstTimeUs = curTime.mTimeUs;
675            break;
676        }
677    }
678    mBuffers.erase(mBuffers.begin(), it);
679    mLatestDequeuedMeta = NULL;
680
681    // CHECK(!mDiscontinuitySegments.empty());
682    DiscontinuitySegment &seg = *mDiscontinuitySegments.begin();
683    if (firstTimeUs >= 0) {
684        seg.mMaxDequeTimeUs = firstTimeUs;
685    } else {
686        seg.clear();
687    }
688
689    return firstMeta;
690}
691
692}  // namespace android
693