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