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