• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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