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