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