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 
36 namespace android {
37 
38 const int64_t kNearEOSMarkUs = 2000000ll; // 2 secs
39 
AnotherPacketSource(const sp<MetaData> & meta)40 AnotherPacketSource::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 
setFormat(const sp<MetaData> & meta)55 void 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 
~AnotherPacketSource()81 AnotherPacketSource::~AnotherPacketSource() {
82 }
83 
start(MetaData *)84 status_t AnotherPacketSource::start(MetaData * /* params */) {
85     return OK;
86 }
87 
stop()88 status_t AnotherPacketSource::stop() {
89     return OK;
90 }
91 
getFormat()92 sp<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 
dequeueAccessUnit(sp<ABuffer> * buffer)115 status_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 
requeueAccessUnit(const sp<ABuffer> & buffer)159 void 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 
read(MediaBufferBase ** out,const ReadOptions *)165 status_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 
wasFormatChange(int32_t discontinuityType) const260 bool 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 
queueAccessUnit(const sp<ABuffer> & buffer)273 void 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 
clear()329 void 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 
queueDiscontinuity(ATSParser::DiscontinuityType type,const sp<AMessage> & extra,bool discard)344 void 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 
signalEOS(status_t result)393 void AnotherPacketSource::signalEOS(status_t result) {
394     CHECK(result != OK);
395 
396     Mutex::Autolock autoLock(mLock);
397     mEOSResult = result;
398     mCondition.signal();
399 }
400 
hasBufferAvailable(status_t * finalResult)401 bool 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 
hasDataBufferAvailable(status_t * finalResult)415 bool 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 
getAvailableBufferCount(status_t * finalResult)433 size_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 
getBufferedDurationUs(status_t * finalResult)447 int64_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 
getEstimatedBufferDurationUs()464 int64_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 
nextBufferTime(int64_t * timeUs)489 status_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 
isFinished(int64_t duration) const504 bool 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 
getLatestEnqueuedMeta()515 sp<AMessage> AnotherPacketSource::getLatestEnqueuedMeta() {
516     Mutex::Autolock autoLock(mLock);
517     return mLatestEnqueuedMeta;
518 }
519 
getLatestDequeuedMeta()520 sp<AMessage> AnotherPacketSource::getLatestDequeuedMeta() {
521     Mutex::Autolock autoLock(mLock);
522     return mLatestDequeuedMeta;
523 }
524 
enable(bool enable)525 void 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  */
getMetaAfterLastDequeued(int64_t delayUs)534 sp<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  */
trimBuffersAfterMeta(const sp<AMessage> & meta)569 void 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  */
trimBuffersBeforeMeta(const sp<AMessage> & meta)628 sp<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