1 /*
2 * Copyright 2012, 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 "NuMediaExtractor"
19 #include <utils/Log.h>
20
21 #include <media/stagefright/NuMediaExtractor.h>
22
23 #include "include/ESDS.h"
24
25 #include <media/DataSource.h>
26 #include <media/MediaSource.h>
27 #include <media/stagefright/foundation/ABuffer.h>
28 #include <media/stagefright/foundation/ADebug.h>
29 #include <media/stagefright/foundation/AMessage.h>
30 #include <media/stagefright/DataSourceFactory.h>
31 #include <media/stagefright/FileSource.h>
32 #include <media/stagefright/MediaBuffer.h>
33 #include <media/stagefright/MediaDefs.h>
34 #include <media/stagefright/MediaErrors.h>
35 #include <media/stagefright/MediaExtractor.h>
36 #include <media/stagefright/MediaExtractorFactory.h>
37 #include <media/stagefright/MetaData.h>
38 #include <media/stagefright/Utils.h>
39
40 namespace android {
41
Sample()42 NuMediaExtractor::Sample::Sample()
43 : mBuffer(NULL),
44 mSampleTimeUs(-1LL) {
45 }
46
Sample(MediaBufferBase * buffer,int64_t timeUs)47 NuMediaExtractor::Sample::Sample(MediaBufferBase *buffer, int64_t timeUs)
48 : mBuffer(buffer),
49 mSampleTimeUs(timeUs) {
50 }
51
NuMediaExtractor()52 NuMediaExtractor::NuMediaExtractor()
53 : mTotalBitrate(-1LL),
54 mDurationUs(-1LL) {
55 }
56
~NuMediaExtractor()57 NuMediaExtractor::~NuMediaExtractor() {
58 releaseAllTrackSamples();
59
60 for (size_t i = 0; i < mSelectedTracks.size(); ++i) {
61 TrackInfo *info = &mSelectedTracks.editItemAt(i);
62
63 status_t err = info->mSource->stop();
64 ALOGE_IF(err != OK, "error %d stopping track %zu", err, i);
65 }
66
67 mSelectedTracks.clear();
68 if (mDataSource != NULL) {
69 mDataSource->close();
70 }
71 }
72
setDataSource(const sp<MediaHTTPService> & httpService,const char * path,const KeyedVector<String8,String8> * headers)73 status_t NuMediaExtractor::setDataSource(
74 const sp<MediaHTTPService> &httpService,
75 const char *path,
76 const KeyedVector<String8, String8> *headers) {
77 Mutex::Autolock autoLock(mLock);
78
79 if (mImpl != NULL || path == NULL) {
80 return -EINVAL;
81 }
82
83 sp<DataSource> dataSource =
84 DataSourceFactory::CreateFromURI(httpService, path, headers);
85
86 if (dataSource == NULL) {
87 return -ENOENT;
88 }
89
90 mImpl = MediaExtractorFactory::Create(dataSource);
91
92 if (mImpl == NULL) {
93 return ERROR_UNSUPPORTED;
94 }
95
96 if (!mCasToken.empty()) {
97 mImpl->setMediaCas(mCasToken);
98 }
99
100 status_t err = updateDurationAndBitrate();
101 if (err == OK) {
102 mDataSource = dataSource;
103 }
104
105 return OK;
106 }
107
setDataSource(int fd,off64_t offset,off64_t size)108 status_t NuMediaExtractor::setDataSource(int fd, off64_t offset, off64_t size) {
109
110 ALOGV("setDataSource fd=%d (%s), offset=%lld, length=%lld",
111 fd, nameForFd(fd).c_str(), (long long) offset, (long long) size);
112
113 Mutex::Autolock autoLock(mLock);
114
115 if (mImpl != NULL) {
116 return -EINVAL;
117 }
118
119 sp<FileSource> fileSource = new FileSource(dup(fd), offset, size);
120
121 status_t err = fileSource->initCheck();
122 if (err != OK) {
123 return err;
124 }
125
126 mImpl = MediaExtractorFactory::Create(fileSource);
127
128 if (mImpl == NULL) {
129 return ERROR_UNSUPPORTED;
130 }
131
132 if (!mCasToken.empty()) {
133 mImpl->setMediaCas(mCasToken);
134 }
135
136 err = updateDurationAndBitrate();
137 if (err == OK) {
138 mDataSource = fileSource;
139 }
140
141 return OK;
142 }
143
setDataSource(const sp<DataSource> & source)144 status_t NuMediaExtractor::setDataSource(const sp<DataSource> &source) {
145 Mutex::Autolock autoLock(mLock);
146
147 if (mImpl != NULL) {
148 return -EINVAL;
149 }
150
151 status_t err = source->initCheck();
152 if (err != OK) {
153 return err;
154 }
155
156 mImpl = MediaExtractorFactory::Create(source);
157
158 if (mImpl == NULL) {
159 return ERROR_UNSUPPORTED;
160 }
161
162 if (!mCasToken.empty()) {
163 mImpl->setMediaCas(mCasToken);
164 }
165
166 err = updateDurationAndBitrate();
167 if (err == OK) {
168 mDataSource = source;
169 }
170
171 return err;
172 }
173
arrayToString(const std::vector<uint8_t> & array)174 static String8 arrayToString(const std::vector<uint8_t> &array) {
175 String8 result;
176 for (size_t i = 0; i < array.size(); i++) {
177 result.appendFormat("%02x ", array[i]);
178 }
179 if (result.isEmpty()) {
180 result.append("(null)");
181 }
182 return result;
183 }
184
setMediaCas(const HInterfaceToken & casToken)185 status_t NuMediaExtractor::setMediaCas(const HInterfaceToken &casToken) {
186 ALOGV("setMediaCas: casToken={%s}", arrayToString(casToken).c_str());
187
188 Mutex::Autolock autoLock(mLock);
189
190 if (casToken.empty()) {
191 return BAD_VALUE;
192 }
193
194 mCasToken = casToken;
195
196 if (mImpl != NULL) {
197 mImpl->setMediaCas(casToken);
198 status_t err = updateDurationAndBitrate();
199 if (err != OK) {
200 return err;
201 }
202 }
203
204 return OK;
205 }
206
updateDurationAndBitrate()207 status_t NuMediaExtractor::updateDurationAndBitrate() {
208 if (mImpl->countTracks() > kMaxTrackCount) {
209 return ERROR_UNSUPPORTED;
210 }
211
212 mTotalBitrate = 0LL;
213 mDurationUs = -1LL;
214
215 for (size_t i = 0; i < mImpl->countTracks(); ++i) {
216 sp<MetaData> meta = mImpl->getTrackMetaData(i);
217 if (meta == NULL) {
218 ALOGW("no metadata for track %zu", i);
219 continue;
220 }
221
222 int32_t bitrate;
223 if (!meta->findInt32(kKeyBitRate, &bitrate)) {
224 const char *mime;
225 CHECK(meta->findCString(kKeyMIMEType, &mime));
226 ALOGV("track of type '%s' does not publish bitrate", mime);
227
228 mTotalBitrate = -1LL;
229 } else if (mTotalBitrate >= 0LL) {
230 mTotalBitrate += bitrate;
231 }
232
233 int64_t durationUs;
234 if (meta->findInt64(kKeyDuration, &durationUs)
235 && durationUs > mDurationUs) {
236 mDurationUs = durationUs;
237 }
238 }
239 return OK;
240 }
241
countTracks() const242 size_t NuMediaExtractor::countTracks() const {
243 Mutex::Autolock autoLock(mLock);
244
245 return mImpl == NULL ? 0 : mImpl->countTracks();
246 }
247
getTrackFormat(size_t index,sp<AMessage> * format,uint32_t flags) const248 status_t NuMediaExtractor::getTrackFormat(
249 size_t index, sp<AMessage> *format, uint32_t flags) const {
250 Mutex::Autolock autoLock(mLock);
251
252 *format = NULL;
253
254 if (mImpl == NULL) {
255 return -EINVAL;
256 }
257
258 if (index >= mImpl->countTracks()) {
259 return -ERANGE;
260 }
261
262 sp<MetaData> meta = mImpl->getTrackMetaData(index, flags);
263 // Extractors either support trackID-s or not, so either all tracks have trackIDs or none.
264 // Generate trackID if missing.
265 int32_t trackID;
266 if (meta != NULL && !meta->findInt32(kKeyTrackID, &trackID)) {
267 meta->setInt32(kKeyTrackID, (int32_t)index + 1);
268 }
269 return convertMetaDataToMessage(meta, format);
270 }
271
getFileFormat(sp<AMessage> * format) const272 status_t NuMediaExtractor::getFileFormat(sp<AMessage> *format) const {
273 Mutex::Autolock autoLock(mLock);
274
275 *format = NULL;
276
277 if (mImpl == NULL) {
278 return -EINVAL;
279 }
280
281 sp<MetaData> meta = mImpl->getMetaData();
282
283 const char *mime;
284 CHECK(meta->findCString(kKeyMIMEType, &mime));
285 *format = new AMessage();
286 (*format)->setString("mime", mime);
287
288 uint32_t type;
289 const void *pssh;
290 size_t psshsize;
291 if (meta->findData(kKeyPssh, &type, &pssh, &psshsize)) {
292 sp<ABuffer> buf = new ABuffer(psshsize);
293 memcpy(buf->data(), pssh, psshsize);
294 (*format)->setBuffer("pssh", buf);
295 }
296
297 return OK;
298 }
299
getExifOffsetSize(off64_t * offset,size_t * size) const300 status_t NuMediaExtractor::getExifOffsetSize(off64_t *offset, size_t *size) const {
301 Mutex::Autolock autoLock(mLock);
302
303 if (mImpl == NULL) {
304 return -EINVAL;
305 }
306
307 sp<MetaData> meta = mImpl->getMetaData();
308
309 int64_t exifOffset, exifSize;
310 if (meta->findInt64(kKeyExifOffset, &exifOffset)
311 && meta->findInt64(kKeyExifSize, &exifSize)) {
312 *offset = (off64_t) exifOffset;
313 *size = (size_t) exifSize;
314
315 return OK;
316 }
317 return ERROR_UNSUPPORTED;
318 }
319
selectTrack(size_t index,int64_t startTimeUs,MediaSource::ReadOptions::SeekMode mode)320 status_t NuMediaExtractor::selectTrack(size_t index,
321 int64_t startTimeUs, MediaSource::ReadOptions::SeekMode mode) {
322 Mutex::Autolock autoLock(mLock);
323
324 if (mImpl == NULL) {
325 return -EINVAL;
326 }
327
328 if (index >= mImpl->countTracks()) {
329 return -ERANGE;
330 }
331
332 for (size_t i = 0; i < mSelectedTracks.size(); ++i) {
333 TrackInfo *info = &mSelectedTracks.editItemAt(i);
334
335 if (info->mTrackIndex == index) {
336 // This track has already been selected.
337 return OK;
338 }
339 }
340
341 sp<IMediaSource> source = mImpl->getTrack(index);
342
343 if (source == nullptr) {
344 ALOGE("track %zu is empty", index);
345 return ERROR_MALFORMED;
346 }
347
348 status_t ret = source->start();
349 if (ret != OK) {
350 ALOGE("track %zu failed to start", index);
351 return ret;
352 }
353
354 sp<MetaData> meta = source->getFormat();
355 if (meta == NULL) {
356 ALOGE("track %zu has no meta data", index);
357 return ERROR_MALFORMED;
358 }
359
360 const char *mime;
361 if (!meta->findCString(kKeyMIMEType, &mime)) {
362 ALOGE("track %zu has no mime type in meta data", index);
363 return ERROR_MALFORMED;
364 }
365 ALOGV("selectTrack, track[%zu]: %s", index, mime);
366
367 mSelectedTracks.push();
368 TrackInfo *info = &mSelectedTracks.editItemAt(mSelectedTracks.size() - 1);
369
370 info->mSource = source;
371 info->mTrackIndex = index;
372 if (!strncasecmp(mime, "audio/", 6)) {
373 info->mTrackType = MEDIA_TRACK_TYPE_AUDIO;
374 info->mMaxFetchCount = 64;
375 } else if (!strncasecmp(mime, "video/", 6)) {
376 info->mTrackType = MEDIA_TRACK_TYPE_VIDEO;
377 info->mMaxFetchCount = 8;
378 } else {
379 info->mTrackType = MEDIA_TRACK_TYPE_UNKNOWN;
380 info->mMaxFetchCount = 1;
381 }
382 info->mFinalResult = OK;
383 releaseTrackSamples(info);
384 info->mTrackFlags = 0;
385
386 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
387 info->mTrackFlags |= kIsVorbis;
388 }
389
390 if (startTimeUs >= 0) {
391 fetchTrackSamples(info, startTimeUs, mode);
392 }
393
394 return OK;
395 }
396
unselectTrack(size_t index)397 status_t NuMediaExtractor::unselectTrack(size_t index) {
398 Mutex::Autolock autoLock(mLock);
399
400 if (mImpl == NULL) {
401 return -EINVAL;
402 }
403
404 if (index >= mImpl->countTracks()) {
405 return -ERANGE;
406 }
407
408 size_t i;
409 for (i = 0; i < mSelectedTracks.size(); ++i) {
410 TrackInfo *info = &mSelectedTracks.editItemAt(i);
411
412 if (info->mTrackIndex == index) {
413 break;
414 }
415 }
416
417 if (i == mSelectedTracks.size()) {
418 // Not selected.
419 return OK;
420 }
421
422 TrackInfo *info = &mSelectedTracks.editItemAt(i);
423
424 releaseTrackSamples(info);
425
426 CHECK_EQ((status_t)OK, info->mSource->stop());
427
428 mSelectedTracks.removeAt(i);
429
430 return OK;
431 }
432
releaseTrackSamples(TrackInfo * info)433 void NuMediaExtractor::releaseTrackSamples(TrackInfo *info) {
434 if (info == NULL) {
435 return;
436 }
437
438 auto it = info->mSamples.begin();
439 while (it != info->mSamples.end()) {
440 if (it->mBuffer != NULL) {
441 it->mBuffer->release();
442 }
443 it = info->mSamples.erase(it);
444 }
445 }
446
releaseAllTrackSamples()447 void NuMediaExtractor::releaseAllTrackSamples() {
448 for (size_t i = 0; i < mSelectedTracks.size(); ++i) {
449 releaseTrackSamples(&mSelectedTracks.editItemAt(i));
450 }
451 }
452
fetchAllTrackSamples(int64_t seekTimeUs,MediaSource::ReadOptions::SeekMode mode)453 ssize_t NuMediaExtractor::fetchAllTrackSamples(
454 int64_t seekTimeUs, MediaSource::ReadOptions::SeekMode mode) {
455 TrackInfo *minInfo = NULL;
456 ssize_t minIndex = ERROR_END_OF_STREAM;
457
458 for (size_t i = 0; i < mSelectedTracks.size(); ++i) {
459 TrackInfo *info = &mSelectedTracks.editItemAt(i);
460 fetchTrackSamples(info, seekTimeUs, mode);
461
462 status_t err = info->mFinalResult;
463 if (err != OK && err != ERROR_END_OF_STREAM && info->mSamples.empty()) {
464 return err;
465 }
466
467 if (info->mSamples.empty()) {
468 continue;
469 }
470
471 if (minInfo == NULL) {
472 minInfo = info;
473 minIndex = i;
474 } else {
475 auto it = info->mSamples.begin();
476 auto itMin = minInfo->mSamples.begin();
477 if (it->mSampleTimeUs < itMin->mSampleTimeUs) {
478 minInfo = info;
479 minIndex = i;
480 }
481 }
482 }
483
484 return minIndex;
485 }
486
fetchTrackSamples(TrackInfo * info,int64_t seekTimeUs,MediaSource::ReadOptions::SeekMode mode)487 void NuMediaExtractor::fetchTrackSamples(TrackInfo *info,
488 int64_t seekTimeUs, MediaSource::ReadOptions::SeekMode mode) {
489 if (info == NULL) {
490 return;
491 }
492
493 MediaSource::ReadOptions options;
494 if (seekTimeUs >= 0LL) {
495 options.setSeekTo(seekTimeUs, mode);
496 info->mFinalResult = OK;
497 releaseTrackSamples(info);
498 } else if (info->mFinalResult != OK || !info->mSamples.empty()) {
499 return;
500 }
501
502 status_t err = OK;
503 Vector<MediaBufferBase *> mediaBuffers;
504 if (info->mSource->supportReadMultiple()) {
505 options.setNonBlocking();
506 err = info->mSource->readMultiple(&mediaBuffers, info->mMaxFetchCount, &options);
507 } else {
508 MediaBufferBase *mbuf = NULL;
509 err = info->mSource->read(&mbuf, &options);
510 if (err == OK && mbuf != NULL) {
511 mediaBuffers.push_back(mbuf);
512 }
513 }
514
515 info->mFinalResult = err;
516 if (err != OK && err != ERROR_END_OF_STREAM) {
517 ALOGW("read on track %zu failed with error %d", info->mTrackIndex, err);
518 }
519
520 size_t count = mediaBuffers.size();
521 bool releaseRemaining = false;
522 for (size_t id = 0; id < count; ++id) {
523 int64_t timeUs;
524 MediaBufferBase *mbuf = mediaBuffers[id];
525 if (mbuf == NULL) {
526 continue;
527 }
528 if (releaseRemaining) {
529 mbuf->release();
530 continue;
531 }
532 if (mbuf->meta_data().findInt64(kKeyTime, &timeUs)) {
533 info->mSamples.emplace_back(mbuf, timeUs);
534 } else {
535 mbuf->meta_data().dumpToLog();
536 info->mFinalResult = ERROR_MALFORMED;
537 mbuf->release();
538 releaseRemaining = true;
539 }
540 }
541 }
542
seekTo(int64_t timeUs,MediaSource::ReadOptions::SeekMode mode)543 status_t NuMediaExtractor::seekTo(
544 int64_t timeUs, MediaSource::ReadOptions::SeekMode mode) {
545 Mutex::Autolock autoLock(mLock);
546
547 ssize_t minIndex = fetchAllTrackSamples(timeUs, mode);
548
549 if (minIndex < 0) {
550 return ERROR_END_OF_STREAM;
551 }
552
553 return OK;
554 }
555
advance()556 status_t NuMediaExtractor::advance() {
557 Mutex::Autolock autoLock(mLock);
558
559 ssize_t minIndex = fetchAllTrackSamples();
560
561 if (minIndex < 0) {
562 return ERROR_END_OF_STREAM;
563 }
564
565 TrackInfo *info = &mSelectedTracks.editItemAt(minIndex);
566
567 if (info == NULL || info->mSamples.empty()) {
568 return ERROR_END_OF_STREAM;
569 }
570
571 auto it = info->mSamples.begin();
572 if (it->mBuffer != NULL) {
573 it->mBuffer->release();
574 }
575 info->mSamples.erase(it);
576
577 if (info->mSamples.empty()) {
578 minIndex = fetchAllTrackSamples();
579 if (minIndex < 0) {
580 return ERROR_END_OF_STREAM;
581 }
582 info = &mSelectedTracks.editItemAt(minIndex);
583 if (info == NULL || info->mSamples.empty()) {
584 return ERROR_END_OF_STREAM;
585 }
586 }
587 return OK;
588 }
589
appendVorbisNumPageSamples(MediaBufferBase * mbuf,const sp<ABuffer> & buffer)590 status_t NuMediaExtractor::appendVorbisNumPageSamples(
591 MediaBufferBase *mbuf, const sp<ABuffer> &buffer) {
592 int32_t numPageSamples;
593 if (!mbuf->meta_data().findInt32(
594 kKeyValidSamples, &numPageSamples)) {
595 numPageSamples = -1;
596 }
597
598 memcpy((uint8_t *)buffer->data() + mbuf->range_length(),
599 &numPageSamples,
600 sizeof(numPageSamples));
601
602 uint32_t type;
603 const void *data;
604 size_t size, size2;
605 if (mbuf->meta_data().findData(kKeyEncryptedSizes, &type, &data, &size)) {
606 // Signal numPageSamples (a plain int32_t) is appended at the end,
607 // i.e. sizeof(numPageSamples) plain bytes + 0 encrypted bytes
608 if (SIZE_MAX - size < sizeof(int32_t)) {
609 return -ENOMEM;
610 }
611
612 size_t newSize = size + sizeof(int32_t);
613 sp<ABuffer> abuf = new ABuffer(newSize);
614 uint8_t *adata = static_cast<uint8_t *>(abuf->data());
615 if (adata == NULL) {
616 return -ENOMEM;
617 }
618
619 // append 0 to encrypted sizes
620 int32_t zero = 0;
621 memcpy(adata, data, size);
622 memcpy(adata + size, &zero, sizeof(zero));
623 mbuf->meta_data().setData(kKeyEncryptedSizes, type, adata, newSize);
624
625 if (mbuf->meta_data().findData(kKeyPlainSizes, &type, &data, &size2)) {
626 if (size2 != size) {
627 return ERROR_MALFORMED;
628 }
629 memcpy(adata, data, size);
630 } else {
631 // if sample meta data does not include plain size array, assume filled with zeros,
632 // i.e. entire buffer is encrypted
633 memset(adata, 0, size);
634 }
635 // append sizeof(numPageSamples) to plain sizes.
636 int32_t int32Size = sizeof(numPageSamples);
637 memcpy(adata + size, &int32Size, sizeof(int32Size));
638 mbuf->meta_data().setData(kKeyPlainSizes, type, adata, newSize);
639 }
640
641 return OK;
642 }
643
readSampleData(const sp<ABuffer> & buffer)644 status_t NuMediaExtractor::readSampleData(const sp<ABuffer> &buffer) {
645 Mutex::Autolock autoLock(mLock);
646
647 ssize_t minIndex = fetchAllTrackSamples();
648
649 if (minIndex < 0) {
650 return ERROR_END_OF_STREAM;
651 }
652
653 TrackInfo *info = &mSelectedTracks.editItemAt(minIndex);
654
655 auto it = info->mSamples.begin();
656 size_t sampleSize = it->mBuffer->range_length();
657
658 if (info->mTrackFlags & kIsVorbis) {
659 // Each sample's data is suffixed by the number of page samples
660 // or -1 if not available.
661 sampleSize += sizeof(int32_t);
662 }
663
664 if (buffer->capacity() < sampleSize) {
665 return -ENOMEM;
666 }
667
668 const uint8_t *src =
669 (const uint8_t *)it->mBuffer->data()
670 + it->mBuffer->range_offset();
671
672 memcpy((uint8_t *)buffer->data(), src, it->mBuffer->range_length());
673
674 status_t err = OK;
675 if (info->mTrackFlags & kIsVorbis) {
676 err = appendVorbisNumPageSamples(it->mBuffer, buffer);
677 }
678
679 if (err == OK) {
680 buffer->setRange(0, sampleSize);
681 }
682
683 return err;
684 }
685
getSampleSize(size_t * sampleSize)686 status_t NuMediaExtractor::getSampleSize(size_t *sampleSize) {
687 Mutex::Autolock autoLock(mLock);
688
689 ssize_t minIndex = fetchAllTrackSamples();
690
691 if (minIndex < 0) {
692 return ERROR_END_OF_STREAM;
693 }
694
695 TrackInfo *info = &mSelectedTracks.editItemAt(minIndex);
696 auto it = info->mSamples.begin();
697 *sampleSize = it->mBuffer->range_length();
698
699 if (info->mTrackFlags & kIsVorbis) {
700 // Each sample's data is suffixed by the number of page samples
701 // or -1 if not available.
702 *sampleSize += sizeof(int32_t);
703 }
704
705 return OK;
706 }
707
getSampleTrackIndex(size_t * trackIndex)708 status_t NuMediaExtractor::getSampleTrackIndex(size_t *trackIndex) {
709 Mutex::Autolock autoLock(mLock);
710
711 ssize_t minIndex = fetchAllTrackSamples();
712
713 if (minIndex < 0) {
714 return ERROR_END_OF_STREAM;
715 }
716
717 TrackInfo *info = &mSelectedTracks.editItemAt(minIndex);
718 *trackIndex = info->mTrackIndex;
719
720 return OK;
721 }
722
getSampleTime(int64_t * sampleTimeUs)723 status_t NuMediaExtractor::getSampleTime(int64_t *sampleTimeUs) {
724 Mutex::Autolock autoLock(mLock);
725
726 ssize_t minIndex = fetchAllTrackSamples();
727
728 if (minIndex < 0) {
729 return ERROR_END_OF_STREAM;
730 }
731
732 TrackInfo *info = &mSelectedTracks.editItemAt(minIndex);
733 *sampleTimeUs = info->mSamples.begin()->mSampleTimeUs;
734
735 return OK;
736 }
737
getSampleMeta(sp<MetaData> * sampleMeta)738 status_t NuMediaExtractor::getSampleMeta(sp<MetaData> *sampleMeta) {
739 Mutex::Autolock autoLock(mLock);
740
741 *sampleMeta = NULL;
742
743 ssize_t minIndex = fetchAllTrackSamples();
744
745 if (minIndex < 0) {
746 status_t err = minIndex;
747 return err;
748 }
749
750 TrackInfo *info = &mSelectedTracks.editItemAt(minIndex);
751 *sampleMeta = new MetaData(info->mSamples.begin()->mBuffer->meta_data());
752
753 return OK;
754 }
755
getMetrics(Parcel * reply)756 status_t NuMediaExtractor::getMetrics(Parcel *reply) {
757 if (mImpl == NULL) {
758 return -EINVAL;
759 }
760 status_t status = mImpl->getMetrics(reply);
761 return status;
762 }
763
getTotalBitrate(int64_t * bitrate) const764 bool NuMediaExtractor::getTotalBitrate(int64_t *bitrate) const {
765 if (mTotalBitrate > 0) {
766 *bitrate = mTotalBitrate;
767 return true;
768 }
769
770 off64_t size;
771 if (mDurationUs > 0 && mDataSource->getSize(&size) == OK) {
772 *bitrate = size * 8000000LL / mDurationUs; // in bits/sec
773 return true;
774 }
775
776 return false;
777 }
778
779 // Returns true iff cached duration is available/applicable.
getCachedDuration(int64_t * durationUs,bool * eos) const780 bool NuMediaExtractor::getCachedDuration(
781 int64_t *durationUs, bool *eos) const {
782 Mutex::Autolock autoLock(mLock);
783
784 off64_t cachedDataRemaining = -1;
785 status_t finalStatus = mDataSource->getAvailableSize(-1, &cachedDataRemaining);
786
787 int64_t bitrate;
788 if (cachedDataRemaining >= 0
789 && getTotalBitrate(&bitrate)) {
790 *durationUs = cachedDataRemaining * 8000000ll / bitrate;
791 *eos = (finalStatus != OK);
792 return true;
793 }
794
795 return false;
796 }
797
798 // Return OK if we have received an audio presentation info.
799 // Return ERROR_END_OF_STREAM if no tracks are available.
800 // Return ERROR_UNSUPPORTED if the track has no audio presentation.
801 // Return INVALID_OPERATION if audio presentation metadata version does not match.
getAudioPresentations(size_t trackIndex,AudioPresentationCollection * presentations)802 status_t NuMediaExtractor::getAudioPresentations(
803 size_t trackIndex, AudioPresentationCollection *presentations) {
804 Mutex::Autolock autoLock(mLock);
805 ssize_t minIndex = fetchAllTrackSamples();
806 if (minIndex < 0) {
807 return ERROR_END_OF_STREAM;
808 }
809 for (size_t i = 0; i < mSelectedTracks.size(); ++i) {
810 TrackInfo *info = &mSelectedTracks.editItemAt(i);
811
812 if (info->mTrackIndex == trackIndex) {
813 sp<MetaData> meta = new MetaData(info->mSamples.begin()->mBuffer->meta_data());
814
815 uint32_t type;
816 const void *data;
817 size_t size;
818 if (meta != NULL && meta->findData(kKeyAudioPresentationInfo, &type, &data, &size)) {
819 std::istringstream inStream(std::string(static_cast<const char*>(data), size));
820 return deserializeAudioPresentations(&inStream, presentations);
821 }
822 ALOGV("Track %zu does not contain any audio presentation", trackIndex);
823 return ERROR_UNSUPPORTED;
824 }
825 }
826 ALOGV("Source does not contain any audio presentation");
827 return ERROR_UNSUPPORTED;
828 }
829
830 } // namespace android
831