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