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