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 sp<ABuffer> ap;
227 if (buffer->meta()->findBuffer("audio-presentation-info", &ap) && ap != NULL) {
228 bufmeta.setData(
229 kKeyAudioPresentationInfo, 0, ap->data(), ap->size());
230 }
231
232 int32_t cryptoMode;
233 if (buffer->meta()->findInt32("cryptoMode", &cryptoMode)) {
234 int32_t cryptoKey;
235 int32_t pesOffset;
236 sp<ABuffer> clearBytesBuffer, encBytesBuffer;
237
238 CHECK(buffer->meta()->findInt32("cryptoKey", &cryptoKey));
239 CHECK(buffer->meta()->findBuffer("clearBytes", &clearBytesBuffer)
240 && clearBytesBuffer != NULL);
241 CHECK(buffer->meta()->findBuffer("encBytes", &encBytesBuffer)
242 && encBytesBuffer != NULL);
243 CHECK(buffer->meta()->findInt32("pesOffset", &pesOffset)
244 && (pesOffset >= 0) && (pesOffset < 65536));
245
246 bufmeta.setInt32(kKeyCryptoMode, cryptoMode);
247
248 uint8_t array[16] = {0};
249 bufmeta.setData(kKeyCryptoIV, 0, array, 16);
250
251 array[0] = (uint8_t) (cryptoKey & 0xff);
252 // array[1] contains PES header flag, which we don't use.
253 // array[2~3] contain the PES offset.
254 array[2] = (uint8_t) (pesOffset & 0xff);
255 array[3] = (uint8_t) ((pesOffset >> 8) & 0xff);
256
257 bufmeta.setData(kKeyCryptoKey, 0, array, 16);
258
259 bufmeta.setData(kKeyPlainSizes, 0,
260 clearBytesBuffer->data(), clearBytesBuffer->size());
261
262 bufmeta.setData(kKeyEncryptedSizes, 0,
263 encBytesBuffer->data(), encBytesBuffer->size());
264 }
265
266
267 *out = mediaBuffer;
268 return OK;
269 }
270
271 return mEOSResult;
272 }
273
wasFormatChange(int32_t discontinuityType) const274 bool AnotherPacketSource::wasFormatChange(
275 int32_t discontinuityType) const {
276 if (mIsAudio) {
277 return (discontinuityType & ATSParser::DISCONTINUITY_AUDIO_FORMAT) != 0;
278 }
279
280 if (mIsVideo) {
281 return (discontinuityType & ATSParser::DISCONTINUITY_VIDEO_FORMAT) != 0;
282 }
283
284 return false;
285 }
286
queueAccessUnit(const sp<ABuffer> & buffer)287 void AnotherPacketSource::queueAccessUnit(const sp<ABuffer> &buffer) {
288 int32_t damaged;
289 if (buffer->meta()->findInt32("damaged", &damaged) && damaged) {
290 // LOG(VERBOSE) << "discarding damaged AU";
291 return;
292 }
293
294 Mutex::Autolock autoLock(mLock);
295 mBuffers.push_back(buffer);
296 mCondition.signal();
297
298 int32_t discontinuity;
299 if (buffer->meta()->findInt32("discontinuity", &discontinuity)){
300 ALOGV("queueing a discontinuity with queueAccessUnit");
301
302 mLastQueuedTimeUs = 0LL;
303 mEOSResult = OK;
304 mLatestEnqueuedMeta = NULL;
305
306 mDiscontinuitySegments.push_back(DiscontinuitySegment());
307 return;
308 }
309
310 int64_t lastQueuedTimeUs;
311 CHECK(buffer->meta()->findInt64("timeUs", &lastQueuedTimeUs));
312 mLastQueuedTimeUs = lastQueuedTimeUs;
313 ALOGV("queueAccessUnit timeUs=%" PRIi64 " us (%.2f secs)",
314 mLastQueuedTimeUs, mLastQueuedTimeUs / 1E6);
315
316 // CHECK(!mDiscontinuitySegments.empty());
317 DiscontinuitySegment &tailSeg = *(--mDiscontinuitySegments.end());
318 if (lastQueuedTimeUs > tailSeg.mMaxEnqueTimeUs) {
319 tailSeg.mMaxEnqueTimeUs = lastQueuedTimeUs;
320 }
321 if (tailSeg.mMaxDequeTimeUs == -1) {
322 tailSeg.mMaxDequeTimeUs = lastQueuedTimeUs;
323 }
324
325 if (mLatestEnqueuedMeta == NULL) {
326 mLatestEnqueuedMeta = buffer->meta()->dup();
327 } else {
328 int64_t latestTimeUs = 0;
329 int64_t frameDeltaUs = 0;
330 CHECK(mLatestEnqueuedMeta->findInt64("timeUs", &latestTimeUs));
331 if (lastQueuedTimeUs > latestTimeUs) {
332 mLatestEnqueuedMeta = buffer->meta()->dup();
333 frameDeltaUs = lastQueuedTimeUs - latestTimeUs;
334 mLatestEnqueuedMeta->setInt64("durationUs", frameDeltaUs);
335 } else if (!mLatestEnqueuedMeta->findInt64("durationUs", &frameDeltaUs)) {
336 // For B frames
337 frameDeltaUs = latestTimeUs - lastQueuedTimeUs;
338 mLatestEnqueuedMeta->setInt64("durationUs", frameDeltaUs);
339 }
340 }
341 }
342
clear()343 void AnotherPacketSource::clear() {
344 Mutex::Autolock autoLock(mLock);
345
346 mBuffers.clear();
347 mEOSResult = OK;
348
349 mDiscontinuitySegments.clear();
350 mDiscontinuitySegments.push_back(DiscontinuitySegment());
351
352 mFormat = NULL;
353 mLatestEnqueuedMeta = NULL;
354
355 mEstimatedBufferDurationUs = -1;
356 }
357
queueDiscontinuity(ATSParser::DiscontinuityType type,const sp<AMessage> & extra,bool discard)358 void AnotherPacketSource::queueDiscontinuity(
359 ATSParser::DiscontinuityType type,
360 const sp<AMessage> &extra,
361 bool discard) {
362 Mutex::Autolock autoLock(mLock);
363
364 if (discard) {
365 // Leave only discontinuities in the queue.
366 List<sp<ABuffer> >::iterator it = mBuffers.begin();
367 while (it != mBuffers.end()) {
368 sp<ABuffer> oldBuffer = *it;
369
370 int32_t oldDiscontinuityType;
371 if (!oldBuffer->meta()->findInt32(
372 "discontinuity", &oldDiscontinuityType)) {
373 it = mBuffers.erase(it);
374 continue;
375 }
376
377 ++it;
378 }
379
380 for (List<DiscontinuitySegment>::iterator it2 = mDiscontinuitySegments.begin();
381 it2 != mDiscontinuitySegments.end();
382 ++it2) {
383 DiscontinuitySegment &seg = *it2;
384 seg.clear();
385 }
386
387 }
388
389 mEOSResult = OK;
390 mLastQueuedTimeUs = 0;
391 mLatestEnqueuedMeta = NULL;
392
393 if (type == ATSParser::DISCONTINUITY_NONE) {
394 return;
395 }
396
397 mDiscontinuitySegments.push_back(DiscontinuitySegment());
398
399 sp<ABuffer> buffer = new ABuffer(0);
400 buffer->meta()->setInt32("discontinuity", static_cast<int32_t>(type));
401 buffer->meta()->setMessage("extra", extra);
402
403 mBuffers.push_back(buffer);
404 mCondition.signal();
405 }
406
signalEOS(status_t result)407 void AnotherPacketSource::signalEOS(status_t result) {
408 CHECK(result != OK);
409
410 Mutex::Autolock autoLock(mLock);
411 mEOSResult = result;
412 mCondition.signal();
413 }
414
hasBufferAvailable(status_t * finalResult)415 bool AnotherPacketSource::hasBufferAvailable(status_t *finalResult) {
416 Mutex::Autolock autoLock(mLock);
417 *finalResult = OK;
418 if (!mEnabled) {
419 return false;
420 }
421 if (!mBuffers.empty()) {
422 return true;
423 }
424
425 *finalResult = mEOSResult;
426 return false;
427 }
428
hasDataBufferAvailable(status_t * finalResult)429 bool AnotherPacketSource::hasDataBufferAvailable(status_t *finalResult) {
430 Mutex::Autolock autoLock(mLock);
431 *finalResult = OK;
432 if (!mEnabled) {
433 return false;
434 }
435 List<sp<ABuffer> >::iterator it;
436 for (it = mBuffers.begin(); it != mBuffers.end(); it++) {
437 int32_t discontinuity;
438 if (!(*it)->meta()->findInt32("discontinuity", &discontinuity)) {
439 return true;
440 }
441 }
442
443 *finalResult = mEOSResult;
444 return false;
445 }
446
getAvailableBufferCount(status_t * finalResult)447 size_t AnotherPacketSource::getAvailableBufferCount(status_t *finalResult) {
448 Mutex::Autolock autoLock(mLock);
449
450 *finalResult = OK;
451 if (!mEnabled) {
452 return 0;
453 }
454 if (!mBuffers.empty()) {
455 return mBuffers.size();
456 }
457 *finalResult = mEOSResult;
458 return 0;
459 }
460
getBufferedDurationUs(status_t * finalResult)461 int64_t AnotherPacketSource::getBufferedDurationUs(status_t *finalResult) {
462 Mutex::Autolock autoLock(mLock);
463 *finalResult = mEOSResult;
464
465 int64_t durationUs = 0;
466 for (List<DiscontinuitySegment>::iterator it = mDiscontinuitySegments.begin();
467 it != mDiscontinuitySegments.end();
468 ++it) {
469 const DiscontinuitySegment &seg = *it;
470 // dequeued access units should be a subset of enqueued access units
471 // CHECK(seg.maxEnqueTimeUs >= seg.mMaxDequeTimeUs);
472 durationUs += (seg.mMaxEnqueTimeUs - seg.mMaxDequeTimeUs);
473 }
474
475 return durationUs;
476 }
477
getEstimatedBufferDurationUs()478 int64_t AnotherPacketSource::getEstimatedBufferDurationUs() {
479 Mutex::Autolock autoLock(mLock);
480 if (mEstimatedBufferDurationUs >= 0) {
481 return mEstimatedBufferDurationUs;
482 }
483
484 SortedVector<int64_t> maxTimesUs;
485 List<sp<ABuffer> >::iterator it;
486 int64_t t1 = 0, t2 = 0;
487 for (it = mBuffers.begin(); it != mBuffers.end(); ++it) {
488 int64_t timeUs = 0;
489 const sp<ABuffer> &buffer = *it;
490 if (!buffer->meta()->findInt64("timeUs", &timeUs)) {
491 continue;
492 }
493 maxTimesUs.add(timeUs);
494 while (maxTimesUs.size() > 2) {
495 maxTimesUs.removeAt(0);
496 t1 = maxTimesUs.itemAt(0);
497 t2 = maxTimesUs.itemAt(1);
498 }
499 }
500 return mEstimatedBufferDurationUs = t2 - t1;
501 }
502
nextBufferTime(int64_t * timeUs)503 status_t AnotherPacketSource::nextBufferTime(int64_t *timeUs) {
504 *timeUs = 0;
505
506 Mutex::Autolock autoLock(mLock);
507
508 if (mBuffers.empty()) {
509 return mEOSResult != OK ? mEOSResult : -EWOULDBLOCK;
510 }
511
512 sp<ABuffer> buffer = *mBuffers.begin();
513 CHECK(buffer->meta()->findInt64("timeUs", timeUs));
514
515 return OK;
516 }
517
isFinished(int64_t duration) const518 bool AnotherPacketSource::isFinished(int64_t duration) const {
519 if (duration > 0) {
520 int64_t diff = duration - mLastQueuedTimeUs;
521 if (diff < kNearEOSMarkUs && diff > -kNearEOSMarkUs) {
522 ALOGV("Detecting EOS due to near end");
523 return true;
524 }
525 }
526 return (mEOSResult != OK);
527 }
528
getLatestEnqueuedMeta()529 sp<AMessage> AnotherPacketSource::getLatestEnqueuedMeta() {
530 Mutex::Autolock autoLock(mLock);
531 return mLatestEnqueuedMeta;
532 }
533
getLatestDequeuedMeta()534 sp<AMessage> AnotherPacketSource::getLatestDequeuedMeta() {
535 Mutex::Autolock autoLock(mLock);
536 return mLatestDequeuedMeta;
537 }
538
enable(bool enable)539 void AnotherPacketSource::enable(bool enable) {
540 Mutex::Autolock autoLock(mLock);
541 mEnabled = enable;
542 }
543
544 /*
545 * returns the sample meta that's delayUs after queue head
546 * (NULL if such sample is unavailable)
547 */
getMetaAfterLastDequeued(int64_t delayUs)548 sp<AMessage> AnotherPacketSource::getMetaAfterLastDequeued(int64_t delayUs) {
549 Mutex::Autolock autoLock(mLock);
550 int64_t firstUs = -1;
551 int64_t lastUs = -1;
552 int64_t durationUs = 0;
553
554 List<sp<ABuffer> >::iterator it;
555 for (it = mBuffers.begin(); it != mBuffers.end(); ++it) {
556 const sp<ABuffer> &buffer = *it;
557 int32_t discontinuity;
558 if (buffer->meta()->findInt32("discontinuity", &discontinuity)) {
559 durationUs += lastUs - firstUs;
560 firstUs = -1;
561 lastUs = -1;
562 continue;
563 }
564 int64_t timeUs;
565 if (buffer->meta()->findInt64("timeUs", &timeUs)) {
566 if (firstUs < 0) {
567 firstUs = timeUs;
568 }
569 if (lastUs < 0 || timeUs > lastUs) {
570 lastUs = timeUs;
571 }
572 if (durationUs + (lastUs - firstUs) >= delayUs) {
573 return buffer->meta();
574 }
575 }
576 }
577 return NULL;
578 }
579
580 /*
581 * removes samples with time equal or after meta
582 */
trimBuffersAfterMeta(const sp<AMessage> & meta)583 void AnotherPacketSource::trimBuffersAfterMeta(
584 const sp<AMessage> &meta) {
585 if (meta == NULL) {
586 ALOGW("trimming with NULL meta, ignoring");
587 return;
588 }
589
590 Mutex::Autolock autoLock(mLock);
591 if (mBuffers.empty()) {
592 return;
593 }
594
595 HLSTime stopTime(meta);
596 ALOGV("trimBuffersAfterMeta: discontinuitySeq %d, timeUs %lld",
597 stopTime.mSeq, (long long)stopTime.mTimeUs);
598
599 List<sp<ABuffer> >::iterator it;
600 List<DiscontinuitySegment >::iterator it2;
601 sp<AMessage> newLatestEnqueuedMeta = NULL;
602 int64_t newLastQueuedTimeUs = 0;
603 for (it = mBuffers.begin(), it2 = mDiscontinuitySegments.begin(); it != mBuffers.end(); ++it) {
604 const sp<ABuffer> &buffer = *it;
605 int32_t discontinuity;
606 if (buffer->meta()->findInt32("discontinuity", &discontinuity)) {
607 // CHECK(it2 != mDiscontinuitySegments.end());
608 ++it2;
609 continue;
610 }
611
612 HLSTime curTime(buffer->meta());
613 if (!(curTime < stopTime)) {
614 ALOGV("trimming from %lld (inclusive) to end",
615 (long long)curTime.mTimeUs);
616 break;
617 }
618 newLatestEnqueuedMeta = buffer->meta();
619 newLastQueuedTimeUs = curTime.mTimeUs;
620 }
621
622 mBuffers.erase(it, mBuffers.end());
623 mLatestEnqueuedMeta = newLatestEnqueuedMeta;
624 mLastQueuedTimeUs = newLastQueuedTimeUs;
625
626 DiscontinuitySegment &seg = *it2;
627 if (newLatestEnqueuedMeta != NULL) {
628 seg.mMaxEnqueTimeUs = newLastQueuedTimeUs;
629 } else {
630 seg.clear();
631 }
632 mDiscontinuitySegments.erase(++it2, mDiscontinuitySegments.end());
633 }
634
635 /*
636 * removes samples with time equal or before meta;
637 * returns first sample left in the queue.
638 *
639 * (for AVC, if trim happens, the samples left will always start
640 * at next IDR.)
641 */
trimBuffersBeforeMeta(const sp<AMessage> & meta)642 sp<AMessage> AnotherPacketSource::trimBuffersBeforeMeta(
643 const sp<AMessage> &meta) {
644 HLSTime startTime(meta);
645 ALOGV("trimBuffersBeforeMeta: discontinuitySeq %d, timeUs %lld",
646 startTime.mSeq, (long long)startTime.mTimeUs);
647
648 sp<AMessage> firstMeta;
649 int64_t firstTimeUs = -1;
650 Mutex::Autolock autoLock(mLock);
651 if (mBuffers.empty()) {
652 return NULL;
653 }
654
655 sp<MetaData> format;
656 bool isAvc = false;
657
658 List<sp<ABuffer> >::iterator it;
659 for (it = mBuffers.begin(); it != mBuffers.end(); ++it) {
660 const sp<ABuffer> &buffer = *it;
661 int32_t discontinuity;
662 if (buffer->meta()->findInt32("discontinuity", &discontinuity)) {
663 mDiscontinuitySegments.erase(mDiscontinuitySegments.begin());
664 // CHECK(!mDiscontinuitySegments.empty());
665 format = NULL;
666 isAvc = false;
667 continue;
668 }
669 if (format == NULL) {
670 sp<RefBase> object;
671 if (buffer->meta()->findObject("format", &object)) {
672 const char* mime;
673 format = static_cast<MetaData*>(object.get());
674 isAvc = format != NULL
675 && format->findCString(kKeyMIMEType, &mime)
676 && !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
677 }
678 }
679 if (isAvc && !IsIDR(buffer->data(), buffer->size())) {
680 continue;
681 }
682
683 HLSTime curTime(buffer->meta());
684 if (startTime < curTime) {
685 ALOGV("trimming from beginning to %lld (not inclusive)",
686 (long long)curTime.mTimeUs);
687 firstMeta = buffer->meta();
688 firstTimeUs = curTime.mTimeUs;
689 break;
690 }
691 }
692 mBuffers.erase(mBuffers.begin(), it);
693 mLatestDequeuedMeta = NULL;
694
695 // CHECK(!mDiscontinuitySegments.empty());
696 DiscontinuitySegment &seg = *mDiscontinuitySegments.begin();
697 if (firstTimeUs >= 0) {
698 seg.mMaxDequeTimeUs = firstTimeUs;
699 } else {
700 seg.clear();
701 }
702
703 return firstMeta;
704 }
705
706 } // namespace android
707