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 const char *mime;
64
65 // Do not use meta if no mime.
66 if (meta == NULL || !meta->findCString(kKeyMIMEType, &mime)) {
67 return;
68 }
69
70 mFormat = meta;
71
72 if (!strncasecmp("audio/", mime, 6)) {
73 mIsAudio = true;
74 } else if (!strncasecmp("video/", mime, 6)) {
75 mIsVideo = true;
76 } else if (!strncasecmp("text/", mime, 5) || !strncasecmp("application/", mime, 12)) {
77 return;
78 } else {
79 ALOGW("Unsupported mime type: %s", mime);
80 }
81 }
82
~AnotherPacketSource()83 AnotherPacketSource::~AnotherPacketSource() {
84 }
85
start(MetaData *)86 status_t AnotherPacketSource::start(MetaData * /* params */) {
87 return OK;
88 }
89
stop()90 status_t AnotherPacketSource::stop() {
91 return OK;
92 }
93
getFormat()94 sp<MetaData> AnotherPacketSource::getFormat() {
95 Mutex::Autolock autoLock(mLock);
96 if (mFormat != NULL) {
97 return mFormat;
98 }
99
100 List<sp<ABuffer> >::iterator it = mBuffers.begin();
101 while (it != mBuffers.end()) {
102 sp<ABuffer> buffer = *it;
103 int32_t discontinuity;
104 if (!buffer->meta()->findInt32("discontinuity", &discontinuity)) {
105 sp<RefBase> object;
106 if (buffer->meta()->findObject("format", &object)) {
107 setFormat(static_cast<MetaData*>(object.get()));
108 return mFormat;
109 }
110 }
111
112 ++it;
113 }
114 return NULL;
115 }
116
dequeueAccessUnit(sp<ABuffer> * buffer)117 status_t AnotherPacketSource::dequeueAccessUnit(sp<ABuffer> *buffer) {
118 buffer->clear();
119
120 Mutex::Autolock autoLock(mLock);
121 while (mEOSResult == OK && mBuffers.empty()) {
122 mCondition.wait(mLock);
123 }
124
125 if (!mBuffers.empty()) {
126 *buffer = *mBuffers.begin();
127 mBuffers.erase(mBuffers.begin());
128
129 int32_t discontinuity;
130 if ((*buffer)->meta()->findInt32("discontinuity", &discontinuity)) {
131 if (wasFormatChange(discontinuity)) {
132 mFormat.clear();
133 }
134
135 mDiscontinuitySegments.erase(mDiscontinuitySegments.begin());
136 // CHECK(!mDiscontinuitySegments.empty());
137 return INFO_DISCONTINUITY;
138 }
139
140 // CHECK(!mDiscontinuitySegments.empty());
141 DiscontinuitySegment &seg = *mDiscontinuitySegments.begin();
142
143 int64_t timeUs;
144 mLatestDequeuedMeta = (*buffer)->meta()->dup();
145 CHECK(mLatestDequeuedMeta->findInt64("timeUs", &timeUs));
146 if (timeUs > seg.mMaxDequeTimeUs) {
147 seg.mMaxDequeTimeUs = timeUs;
148 }
149
150 sp<RefBase> object;
151 if ((*buffer)->meta()->findObject("format", &object)) {
152 setFormat(static_cast<MetaData*>(object.get()));
153 }
154
155 return OK;
156 }
157
158 return mEOSResult;
159 }
160
requeueAccessUnit(const sp<ABuffer> & buffer)161 void AnotherPacketSource::requeueAccessUnit(const sp<ABuffer> &buffer) {
162 // TODO: update corresponding book keeping info.
163 Mutex::Autolock autoLock(mLock);
164 mBuffers.push_front(buffer);
165 }
166
read(MediaBufferBase ** out,const ReadOptions *)167 status_t AnotherPacketSource::read(
168 MediaBufferBase **out, const ReadOptions *) {
169 *out = NULL;
170
171 Mutex::Autolock autoLock(mLock);
172 while (mEOSResult == OK && mBuffers.empty()) {
173 mCondition.wait(mLock);
174 }
175
176 if (!mBuffers.empty()) {
177
178 const sp<ABuffer> buffer = *mBuffers.begin();
179 mBuffers.erase(mBuffers.begin());
180
181 int32_t discontinuity;
182 if (buffer->meta()->findInt32("discontinuity", &discontinuity)) {
183 if (wasFormatChange(discontinuity)) {
184 mFormat.clear();
185 }
186
187 mDiscontinuitySegments.erase(mDiscontinuitySegments.begin());
188 // CHECK(!mDiscontinuitySegments.empty());
189 return INFO_DISCONTINUITY;
190 }
191
192 mLatestDequeuedMeta = buffer->meta()->dup();
193
194 sp<RefBase> object;
195 if (buffer->meta()->findObject("format", &object)) {
196 setFormat(static_cast<MetaData*>(object.get()));
197 }
198
199 int64_t timeUs;
200 CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
201 // CHECK(!mDiscontinuitySegments.empty());
202 DiscontinuitySegment &seg = *mDiscontinuitySegments.begin();
203 if (timeUs > seg.mMaxDequeTimeUs) {
204 seg.mMaxDequeTimeUs = timeUs;
205 }
206
207 MediaBufferBase *mediaBuffer = new MediaBuffer(buffer);
208 MetaDataBase &bufmeta = mediaBuffer->meta_data();
209
210 bufmeta.setInt64(kKeyTime, timeUs);
211
212 int32_t isSync;
213 if (buffer->meta()->findInt32("isSync", &isSync)) {
214 bufmeta.setInt32(kKeyIsSyncFrame, isSync);
215 }
216
217 sp<ABuffer> sei;
218 if (buffer->meta()->findBuffer("sei", &sei) && sei != NULL) {
219 bufmeta.setData(kKeySEI, 0, sei->data(), sei->size());
220 }
221
222 sp<ABuffer> mpegUserData;
223 if (buffer->meta()->findBuffer("mpeg-user-data", &mpegUserData) && mpegUserData != NULL) {
224 bufmeta.setData(
225 kKeyMpegUserData, 0, mpegUserData->data(), mpegUserData->size());
226 }
227
228 sp<ABuffer> ap;
229 if (buffer->meta()->findBuffer("audio-presentation-info", &ap) && ap != NULL) {
230 bufmeta.setData(
231 kKeyAudioPresentationInfo, 0, ap->data(), ap->size());
232 }
233
234 int32_t cryptoMode;
235 if (buffer->meta()->findInt32("cryptoMode", &cryptoMode)) {
236 int32_t cryptoKey;
237 int32_t pesOffset;
238 sp<ABuffer> clearBytesBuffer, encBytesBuffer;
239
240 CHECK(buffer->meta()->findInt32("cryptoKey", &cryptoKey));
241 CHECK(buffer->meta()->findBuffer("clearBytes", &clearBytesBuffer)
242 && clearBytesBuffer != NULL);
243 CHECK(buffer->meta()->findBuffer("encBytes", &encBytesBuffer)
244 && encBytesBuffer != NULL);
245 CHECK(buffer->meta()->findInt32("pesOffset", &pesOffset)
246 && (pesOffset >= 0) && (pesOffset < 65536));
247
248 bufmeta.setInt32(kKeyCryptoMode, cryptoMode);
249
250 uint8_t array[16] = {0};
251 bufmeta.setData(kKeyCryptoIV, 0, array, 16);
252
253 array[0] = (uint8_t) (cryptoKey & 0xff);
254 // array[1] contains PES header flag, which we don't use.
255 // array[2~3] contain the PES offset.
256 array[2] = (uint8_t) (pesOffset & 0xff);
257 array[3] = (uint8_t) ((pesOffset >> 8) & 0xff);
258
259 bufmeta.setData(kKeyCryptoKey, 0, array, 16);
260
261 bufmeta.setData(kKeyPlainSizes, 0,
262 clearBytesBuffer->data(), clearBytesBuffer->size());
263
264 bufmeta.setData(kKeyEncryptedSizes, 0,
265 encBytesBuffer->data(), encBytesBuffer->size());
266 }
267
268
269 *out = mediaBuffer;
270 return OK;
271 }
272
273 return mEOSResult;
274 }
275
wasFormatChange(int32_t discontinuityType) const276 bool AnotherPacketSource::wasFormatChange(
277 int32_t discontinuityType) const {
278 if (mIsAudio) {
279 return (discontinuityType & ATSParser::DISCONTINUITY_AUDIO_FORMAT) != 0;
280 }
281
282 if (mIsVideo) {
283 return (discontinuityType & ATSParser::DISCONTINUITY_VIDEO_FORMAT) != 0;
284 }
285
286 return false;
287 }
288
queueAccessUnit(const sp<ABuffer> & buffer)289 void AnotherPacketSource::queueAccessUnit(const sp<ABuffer> &buffer) {
290 int32_t damaged;
291 if (buffer->meta()->findInt32("damaged", &damaged) && damaged) {
292 // LOG(VERBOSE) << "discarding damaged AU";
293 return;
294 }
295
296 Mutex::Autolock autoLock(mLock);
297 mBuffers.push_back(buffer);
298 mCondition.signal();
299
300 int32_t discontinuity;
301 if (buffer->meta()->findInt32("discontinuity", &discontinuity)){
302 ALOGV("queueing a discontinuity with queueAccessUnit");
303
304 mLastQueuedTimeUs = 0LL;
305 mEOSResult = OK;
306 mLatestEnqueuedMeta = NULL;
307
308 mDiscontinuitySegments.push_back(DiscontinuitySegment());
309 return;
310 }
311
312 int64_t lastQueuedTimeUs;
313 CHECK(buffer->meta()->findInt64("timeUs", &lastQueuedTimeUs));
314 mLastQueuedTimeUs = lastQueuedTimeUs;
315 ALOGV("queueAccessUnit timeUs=%" PRIi64 " us (%.2f secs)",
316 mLastQueuedTimeUs, mLastQueuedTimeUs / 1E6);
317
318 // CHECK(!mDiscontinuitySegments.empty());
319 DiscontinuitySegment &tailSeg = *(--mDiscontinuitySegments.end());
320 if (lastQueuedTimeUs > tailSeg.mMaxEnqueTimeUs) {
321 tailSeg.mMaxEnqueTimeUs = lastQueuedTimeUs;
322 }
323 if (tailSeg.mMaxDequeTimeUs == -1) {
324 tailSeg.mMaxDequeTimeUs = lastQueuedTimeUs;
325 }
326
327 if (mLatestEnqueuedMeta == NULL) {
328 mLatestEnqueuedMeta = buffer->meta()->dup();
329 } else {
330 int64_t latestTimeUs = 0;
331 int64_t frameDeltaUs = 0;
332 CHECK(mLatestEnqueuedMeta->findInt64("timeUs", &latestTimeUs));
333 if (lastQueuedTimeUs > latestTimeUs) {
334 mLatestEnqueuedMeta = buffer->meta()->dup();
335 frameDeltaUs = lastQueuedTimeUs - latestTimeUs;
336 mLatestEnqueuedMeta->setInt64("durationUs", frameDeltaUs);
337 } else if (!mLatestEnqueuedMeta->findInt64("durationUs", &frameDeltaUs)) {
338 // For B frames
339 frameDeltaUs = latestTimeUs - lastQueuedTimeUs;
340 mLatestEnqueuedMeta->setInt64("durationUs", frameDeltaUs);
341 }
342 }
343 }
344
clear()345 void AnotherPacketSource::clear() {
346 Mutex::Autolock autoLock(mLock);
347
348 mBuffers.clear();
349 mEOSResult = OK;
350
351 mDiscontinuitySegments.clear();
352 mDiscontinuitySegments.push_back(DiscontinuitySegment());
353
354 mFormat = NULL;
355 mLatestEnqueuedMeta = NULL;
356
357 mEstimatedBufferDurationUs = -1;
358 }
359
queueDiscontinuity(ATSParser::DiscontinuityType type,const sp<AMessage> & extra,bool discard)360 void AnotherPacketSource::queueDiscontinuity(
361 ATSParser::DiscontinuityType type,
362 const sp<AMessage> &extra,
363 bool discard) {
364 Mutex::Autolock autoLock(mLock);
365
366 if (discard) {
367 // Leave only discontinuities in the queue.
368 List<sp<ABuffer> >::iterator it = mBuffers.begin();
369 while (it != mBuffers.end()) {
370 sp<ABuffer> oldBuffer = *it;
371
372 int32_t oldDiscontinuityType;
373 if (!oldBuffer->meta()->findInt32(
374 "discontinuity", &oldDiscontinuityType)) {
375 it = mBuffers.erase(it);
376 continue;
377 }
378
379 ++it;
380 }
381
382 for (List<DiscontinuitySegment>::iterator it2 = mDiscontinuitySegments.begin();
383 it2 != mDiscontinuitySegments.end();
384 ++it2) {
385 DiscontinuitySegment &seg = *it2;
386 seg.clear();
387 }
388
389 }
390
391 mEOSResult = OK;
392 mLastQueuedTimeUs = 0;
393 mLatestEnqueuedMeta = NULL;
394
395 if (type == ATSParser::DISCONTINUITY_NONE) {
396 return;
397 }
398
399 mDiscontinuitySegments.push_back(DiscontinuitySegment());
400
401 sp<ABuffer> buffer = new ABuffer(0);
402 buffer->meta()->setInt32("discontinuity", static_cast<int32_t>(type));
403 buffer->meta()->setMessage("extra", extra);
404
405 mBuffers.push_back(buffer);
406 mCondition.signal();
407 }
408
signalEOS(status_t result)409 void AnotherPacketSource::signalEOS(status_t result) {
410 CHECK(result != OK);
411
412 Mutex::Autolock autoLock(mLock);
413 mEOSResult = result;
414 mCondition.signal();
415 }
416
hasBufferAvailable(status_t * finalResult)417 bool AnotherPacketSource::hasBufferAvailable(status_t *finalResult) {
418 Mutex::Autolock autoLock(mLock);
419 *finalResult = OK;
420 if (!mEnabled) {
421 return false;
422 }
423 if (!mBuffers.empty()) {
424 return true;
425 }
426
427 *finalResult = mEOSResult;
428 return false;
429 }
430
hasDataBufferAvailable(status_t * finalResult)431 bool AnotherPacketSource::hasDataBufferAvailable(status_t *finalResult) {
432 Mutex::Autolock autoLock(mLock);
433 *finalResult = OK;
434 if (!mEnabled) {
435 return false;
436 }
437 List<sp<ABuffer> >::iterator it;
438 for (it = mBuffers.begin(); it != mBuffers.end(); it++) {
439 int32_t discontinuity;
440 if (!(*it)->meta()->findInt32("discontinuity", &discontinuity)) {
441 return true;
442 }
443 }
444
445 *finalResult = mEOSResult;
446 return false;
447 }
448
getAvailableBufferCount(status_t * finalResult)449 size_t AnotherPacketSource::getAvailableBufferCount(status_t *finalResult) {
450 Mutex::Autolock autoLock(mLock);
451
452 *finalResult = OK;
453 if (!mEnabled) {
454 return 0;
455 }
456 if (!mBuffers.empty()) {
457 return mBuffers.size();
458 }
459 *finalResult = mEOSResult;
460 return 0;
461 }
462
getBufferedDurationUs(status_t * finalResult)463 int64_t AnotherPacketSource::getBufferedDurationUs(status_t *finalResult) {
464 Mutex::Autolock autoLock(mLock);
465 *finalResult = mEOSResult;
466
467 int64_t durationUs = 0;
468 for (List<DiscontinuitySegment>::iterator it = mDiscontinuitySegments.begin();
469 it != mDiscontinuitySegments.end();
470 ++it) {
471 const DiscontinuitySegment &seg = *it;
472 // dequeued access units should be a subset of enqueued access units
473 // CHECK(seg.maxEnqueTimeUs >= seg.mMaxDequeTimeUs);
474 durationUs += (seg.mMaxEnqueTimeUs - seg.mMaxDequeTimeUs);
475 }
476
477 return durationUs;
478 }
479
getEstimatedBufferDurationUs()480 int64_t AnotherPacketSource::getEstimatedBufferDurationUs() {
481 Mutex::Autolock autoLock(mLock);
482 if (mEstimatedBufferDurationUs >= 0) {
483 return mEstimatedBufferDurationUs;
484 }
485
486 SortedVector<int64_t> maxTimesUs;
487 List<sp<ABuffer> >::iterator it;
488 int64_t t1 = 0, t2 = 0;
489 for (it = mBuffers.begin(); it != mBuffers.end(); ++it) {
490 int64_t timeUs = 0;
491 const sp<ABuffer> &buffer = *it;
492 if (!buffer->meta()->findInt64("timeUs", &timeUs)) {
493 continue;
494 }
495 maxTimesUs.add(timeUs);
496 while (maxTimesUs.size() > 2) {
497 maxTimesUs.removeAt(0);
498 t1 = maxTimesUs.itemAt(0);
499 t2 = maxTimesUs.itemAt(1);
500 }
501 }
502 return mEstimatedBufferDurationUs = t2 - t1;
503 }
504
nextBufferTime(int64_t * timeUs)505 status_t AnotherPacketSource::nextBufferTime(int64_t *timeUs) {
506 *timeUs = 0;
507
508 Mutex::Autolock autoLock(mLock);
509
510 if (mBuffers.empty()) {
511 return mEOSResult != OK ? mEOSResult : -EWOULDBLOCK;
512 }
513
514 sp<ABuffer> buffer = *mBuffers.begin();
515 CHECK(buffer->meta()->findInt64("timeUs", timeUs));
516
517 return OK;
518 }
519
isFinished(int64_t duration) const520 bool AnotherPacketSource::isFinished(int64_t duration) const {
521 if (duration > 0) {
522 int64_t diff = duration - mLastQueuedTimeUs;
523 if (diff < kNearEOSMarkUs && diff > -kNearEOSMarkUs) {
524 ALOGV("Detecting EOS due to near end");
525 return true;
526 }
527 }
528 return (mEOSResult != OK);
529 }
530
getLatestEnqueuedMeta()531 sp<AMessage> AnotherPacketSource::getLatestEnqueuedMeta() {
532 Mutex::Autolock autoLock(mLock);
533 return mLatestEnqueuedMeta;
534 }
535
getLatestDequeuedMeta()536 sp<AMessage> AnotherPacketSource::getLatestDequeuedMeta() {
537 Mutex::Autolock autoLock(mLock);
538 return mLatestDequeuedMeta;
539 }
540
enable(bool enable)541 void AnotherPacketSource::enable(bool enable) {
542 Mutex::Autolock autoLock(mLock);
543 mEnabled = enable;
544 }
545
546 /*
547 * returns the sample meta that's delayUs after queue head
548 * (NULL if such sample is unavailable)
549 */
getMetaAfterLastDequeued(int64_t delayUs)550 sp<AMessage> AnotherPacketSource::getMetaAfterLastDequeued(int64_t delayUs) {
551 Mutex::Autolock autoLock(mLock);
552 int64_t firstUs = -1;
553 int64_t lastUs = -1;
554 int64_t durationUs = 0;
555
556 List<sp<ABuffer> >::iterator it;
557 for (it = mBuffers.begin(); it != mBuffers.end(); ++it) {
558 const sp<ABuffer> &buffer = *it;
559 int32_t discontinuity;
560 if (buffer->meta()->findInt32("discontinuity", &discontinuity)) {
561 durationUs += lastUs - firstUs;
562 firstUs = -1;
563 lastUs = -1;
564 continue;
565 }
566 int64_t timeUs;
567 if (buffer->meta()->findInt64("timeUs", &timeUs)) {
568 if (firstUs < 0) {
569 firstUs = timeUs;
570 }
571 if (lastUs < 0 || timeUs > lastUs) {
572 lastUs = timeUs;
573 }
574 if (durationUs + (lastUs - firstUs) >= delayUs) {
575 return buffer->meta();
576 }
577 }
578 }
579 return NULL;
580 }
581
582 /*
583 * removes samples with time equal or after meta
584 */
trimBuffersAfterMeta(const sp<AMessage> & meta)585 void AnotherPacketSource::trimBuffersAfterMeta(
586 const sp<AMessage> &meta) {
587 if (meta == NULL) {
588 ALOGW("trimming with NULL meta, ignoring");
589 return;
590 }
591
592 Mutex::Autolock autoLock(mLock);
593 if (mBuffers.empty()) {
594 return;
595 }
596
597 HLSTime stopTime(meta);
598 ALOGV("trimBuffersAfterMeta: discontinuitySeq %d, timeUs %lld",
599 stopTime.mSeq, (long long)stopTime.mTimeUs);
600
601 List<sp<ABuffer> >::iterator it;
602 List<DiscontinuitySegment >::iterator it2;
603 sp<AMessage> newLatestEnqueuedMeta = NULL;
604 int64_t newLastQueuedTimeUs = 0;
605 for (it = mBuffers.begin(), it2 = mDiscontinuitySegments.begin(); it != mBuffers.end(); ++it) {
606 const sp<ABuffer> &buffer = *it;
607 int32_t discontinuity;
608 if (buffer->meta()->findInt32("discontinuity", &discontinuity)) {
609 // CHECK(it2 != mDiscontinuitySegments.end());
610 ++it2;
611 continue;
612 }
613
614 HLSTime curTime(buffer->meta());
615 if (!(curTime < stopTime)) {
616 ALOGV("trimming from %lld (inclusive) to end",
617 (long long)curTime.mTimeUs);
618 break;
619 }
620 newLatestEnqueuedMeta = buffer->meta();
621 newLastQueuedTimeUs = curTime.mTimeUs;
622 }
623
624 mBuffers.erase(it, mBuffers.end());
625 mLatestEnqueuedMeta = newLatestEnqueuedMeta;
626 mLastQueuedTimeUs = newLastQueuedTimeUs;
627
628 DiscontinuitySegment &seg = *it2;
629 if (newLatestEnqueuedMeta != NULL) {
630 seg.mMaxEnqueTimeUs = newLastQueuedTimeUs;
631 } else {
632 seg.clear();
633 }
634 mDiscontinuitySegments.erase(++it2, mDiscontinuitySegments.end());
635 }
636
637 /*
638 * removes samples with time equal or before meta;
639 * returns first sample left in the queue.
640 *
641 * (for AVC, if trim happens, the samples left will always start
642 * at next IDR.)
643 */
trimBuffersBeforeMeta(const sp<AMessage> & meta)644 sp<AMessage> AnotherPacketSource::trimBuffersBeforeMeta(
645 const sp<AMessage> &meta) {
646 HLSTime startTime(meta);
647 ALOGV("trimBuffersBeforeMeta: discontinuitySeq %d, timeUs %lld",
648 startTime.mSeq, (long long)startTime.mTimeUs);
649
650 sp<AMessage> firstMeta;
651 int64_t firstTimeUs = -1;
652 Mutex::Autolock autoLock(mLock);
653 if (mBuffers.empty()) {
654 return NULL;
655 }
656
657 sp<MetaData> format;
658 bool isAvc = false;
659
660 List<sp<ABuffer> >::iterator it;
661 for (it = mBuffers.begin(); it != mBuffers.end(); ++it) {
662 const sp<ABuffer> &buffer = *it;
663 int32_t discontinuity;
664 if (buffer->meta()->findInt32("discontinuity", &discontinuity)) {
665 mDiscontinuitySegments.erase(mDiscontinuitySegments.begin());
666 // CHECK(!mDiscontinuitySegments.empty());
667 format = NULL;
668 isAvc = false;
669 continue;
670 }
671 if (format == NULL) {
672 sp<RefBase> object;
673 if (buffer->meta()->findObject("format", &object)) {
674 const char* mime;
675 format = static_cast<MetaData*>(object.get());
676 isAvc = format != NULL
677 && format->findCString(kKeyMIMEType, &mime)
678 && !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
679 }
680 }
681 if (isAvc && !IsIDR(buffer->data(), buffer->size())) {
682 continue;
683 }
684
685 HLSTime curTime(buffer->meta());
686 if (startTime < curTime) {
687 ALOGV("trimming from beginning to %lld (not inclusive)",
688 (long long)curTime.mTimeUs);
689 firstMeta = buffer->meta();
690 firstTimeUs = curTime.mTimeUs;
691 break;
692 }
693 }
694 mBuffers.erase(mBuffers.begin(), it);
695 mLatestDequeuedMeta = NULL;
696
697 // CHECK(!mDiscontinuitySegments.empty());
698 DiscontinuitySegment &seg = *mDiscontinuitySegments.begin();
699 if (firstTimeUs >= 0) {
700 seg.mMaxDequeTimeUs = firstTimeUs;
701 } else {
702 seg.clear();
703 }
704
705 return firstMeta;
706 }
707
708 } // namespace android
709