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