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