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