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 
37 namespace android {
38 
39 const int64_t kNearEOSMarkUs = 2000000ll; // 2 secs
40 
AnotherPacketSource(const sp<MetaData> & meta)41 AnotherPacketSource::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 
setFormat(const sp<MetaData> & meta)56 void 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 
~AnotherPacketSource()82 AnotherPacketSource::~AnotherPacketSource() {
83 }
84 
start(MetaData *)85 status_t AnotherPacketSource::start(MetaData * /* params */) {
86     return OK;
87 }
88 
stop()89 status_t AnotherPacketSource::stop() {
90     return OK;
91 }
92 
getFormat()93 sp<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 
dequeueAccessUnit(sp<ABuffer> * buffer)116 status_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 
requeueAccessUnit(const sp<ABuffer> & buffer)160 void 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 
read(MediaBuffer ** out,const ReadOptions *)166 status_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 
wasFormatChange(int32_t discontinuityType) const261 bool 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 
queueAccessUnit(const sp<ABuffer> & buffer)274 void 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 
clear()330 void 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 
queueDiscontinuity(ATSParser::DiscontinuityType type,const sp<AMessage> & extra,bool discard)345 void 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 
signalEOS(status_t result)394 void AnotherPacketSource::signalEOS(status_t result) {
395     CHECK(result != OK);
396 
397     Mutex::Autolock autoLock(mLock);
398     mEOSResult = result;
399     mCondition.signal();
400 }
401 
hasBufferAvailable(status_t * finalResult)402 bool 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 
hasDataBufferAvailable(status_t * finalResult)416 bool 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 
getAvailableBufferCount(status_t * finalResult)434 size_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 
getBufferedDurationUs(status_t * finalResult)448 int64_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 
getEstimatedBufferDurationUs()465 int64_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 
nextBufferTime(int64_t * timeUs)490 status_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 
isFinished(int64_t duration) const505 bool 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 
getLatestEnqueuedMeta()516 sp<AMessage> AnotherPacketSource::getLatestEnqueuedMeta() {
517     Mutex::Autolock autoLock(mLock);
518     return mLatestEnqueuedMeta;
519 }
520 
getLatestDequeuedMeta()521 sp<AMessage> AnotherPacketSource::getLatestDequeuedMeta() {
522     Mutex::Autolock autoLock(mLock);
523     return mLatestDequeuedMeta;
524 }
525 
enable(bool enable)526 void 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  */
getMetaAfterLastDequeued(int64_t delayUs)535 sp<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  */
trimBuffersAfterMeta(const sp<AMessage> & meta)570 void 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  */
trimBuffersBeforeMeta(const sp<AMessage> & meta)629 sp<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