• 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 
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.string();
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.isEmpty()) {
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         memcpy(buf->data(), pssh, psshsize);
302         (*format)->setBuffer("pssh", buf);
303     }
304 
305     // Copy over the slow-motion related metadata
306     const void *slomoMarkers;
307     size_t slomoMarkersSize;
308     if (meta->findData(kKeySlowMotionMarkers, &type, &slomoMarkers, &slomoMarkersSize)
309             && slomoMarkersSize > 0) {
310         sp<ABuffer> buf = new ABuffer(slomoMarkersSize);
311         memcpy(buf->data(), slomoMarkers, slomoMarkersSize);
312         (*format)->setBuffer("slow-motion-markers", buf);
313     }
314 
315     int32_t temporalLayerCount;
316     if (meta->findInt32(kKeyTemporalLayerCount, &temporalLayerCount)
317             && temporalLayerCount > 0) {
318         (*format)->setInt32("temporal-layer-count", temporalLayerCount);
319     }
320 
321     float captureFps;
322     if (meta->findFloat(kKeyCaptureFramerate, &captureFps) && captureFps > 0.0f) {
323         (*format)->setFloat("capture-rate", captureFps);
324     }
325 
326     return OK;
327 }
328 
getExifOffsetSize(off64_t * offset,size_t * size) const329 status_t NuMediaExtractor::getExifOffsetSize(off64_t *offset, size_t *size) const {
330     Mutex::Autolock autoLock(mLock);
331 
332     if (mImpl == NULL) {
333         return -EINVAL;
334     }
335 
336     sp<MetaData> meta = mImpl->getMetaData();
337 
338     if (meta == nullptr) {
339         //extractor did not publish file metadata
340         return -EINVAL;
341     }
342 
343     int64_t exifOffset, exifSize;
344     if (meta->findInt64(kKeyExifOffset, &exifOffset)
345      && meta->findInt64(kKeyExifSize, &exifSize)) {
346         *offset = (off64_t) exifOffset;
347         *size = (size_t) exifSize;
348 
349         return OK;
350     }
351     return ERROR_UNSUPPORTED;
352 }
353 
selectTrack(size_t index,int64_t startTimeUs,MediaSource::ReadOptions::SeekMode mode)354 status_t NuMediaExtractor::selectTrack(size_t index,
355         int64_t startTimeUs, MediaSource::ReadOptions::SeekMode mode) {
356     Mutex::Autolock autoLock(mLock);
357 
358     if (mImpl == NULL) {
359         return -EINVAL;
360     }
361 
362     if (index >= mImpl->countTracks()) {
363         return -ERANGE;
364     }
365 
366     for (size_t i = 0; i < mSelectedTracks.size(); ++i) {
367         TrackInfo *info = &mSelectedTracks.editItemAt(i);
368 
369         if (info->mTrackIndex == index) {
370             // This track has already been selected.
371             return OK;
372         }
373     }
374 
375     sp<IMediaSource> source = mImpl->getTrack(index);
376 
377     if (source == nullptr) {
378         ALOGE("track %zu is empty", index);
379         return ERROR_MALFORMED;
380     }
381 
382     status_t ret = source->start();
383     if (ret != OK) {
384         ALOGE("track %zu failed to start", index);
385         return ret;
386     }
387 
388     sp<MetaData> meta = source->getFormat();
389     if (meta == NULL) {
390         ALOGE("track %zu has no meta data", index);
391         return ERROR_MALFORMED;
392     }
393 
394     const char *mime;
395     if (!meta->findCString(kKeyMIMEType, &mime)) {
396         ALOGE("track %zu has no mime type in meta data", index);
397         return ERROR_MALFORMED;
398     }
399     ALOGV("selectTrack, track[%zu]: %s", index, mime);
400 
401     mSelectedTracks.push();
402     TrackInfo *info = &mSelectedTracks.editItemAt(mSelectedTracks.size() - 1);
403 
404     info->mSource = source;
405     info->mTrackIndex = index;
406     if (!strncasecmp(mime, "audio/", 6)) {
407         info->mTrackType = MEDIA_TRACK_TYPE_AUDIO;
408         info->mMaxFetchCount = 64;
409     } else if (!strncasecmp(mime, "video/", 6)) {
410         info->mTrackType = MEDIA_TRACK_TYPE_VIDEO;
411         info->mMaxFetchCount = 8;
412     } else {
413         info->mTrackType = MEDIA_TRACK_TYPE_UNKNOWN;
414         info->mMaxFetchCount = 1;
415     }
416     info->mFinalResult = OK;
417     releaseTrackSamples(info);
418     info->mTrackFlags = 0;
419 
420     if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
421         info->mTrackFlags |= kIsVorbis;
422     }
423 
424     if (startTimeUs >= 0) {
425         fetchTrackSamples(info, startTimeUs, mode);
426     }
427 
428     return OK;
429 }
430 
unselectTrack(size_t index)431 status_t NuMediaExtractor::unselectTrack(size_t index) {
432     Mutex::Autolock autoLock(mLock);
433 
434     if (mImpl == NULL) {
435         return -EINVAL;
436     }
437 
438     if (index >= mImpl->countTracks()) {
439         return -ERANGE;
440     }
441 
442     size_t i;
443     for (i = 0; i < mSelectedTracks.size(); ++i) {
444         TrackInfo *info = &mSelectedTracks.editItemAt(i);
445 
446         if (info->mTrackIndex == index) {
447             break;
448         }
449     }
450 
451     if (i == mSelectedTracks.size()) {
452         // Not selected.
453         return OK;
454     }
455 
456     TrackInfo *info = &mSelectedTracks.editItemAt(i);
457 
458     releaseTrackSamples(info);
459 
460     CHECK_EQ((status_t)OK, info->mSource->stop());
461 
462     mSelectedTracks.removeAt(i);
463 
464     return OK;
465 }
466 
releaseTrackSamples(TrackInfo * info)467 void NuMediaExtractor::releaseTrackSamples(TrackInfo *info) {
468     if (info == NULL) {
469         return;
470     }
471 
472     auto it = info->mSamples.begin();
473     while (it != info->mSamples.end()) {
474         if (it->mBuffer != NULL) {
475             it->mBuffer->release();
476         }
477         it = info->mSamples.erase(it);
478     }
479 }
480 
releaseAllTrackSamples()481 void NuMediaExtractor::releaseAllTrackSamples() {
482     for (size_t i = 0; i < mSelectedTracks.size(); ++i) {
483         releaseTrackSamples(&mSelectedTracks.editItemAt(i));
484     }
485 }
486 
setEntryPointToRemoteMediaExtractor()487 void NuMediaExtractor::setEntryPointToRemoteMediaExtractor() {
488     if (mImpl == NULL) {
489         return;
490     }
491     status_t err = mImpl->setEntryPoint(mEntryPoint);
492     if (err != OK) {
493         ALOGW("Failed to set entry point with error %d.", err);
494     }
495 }
496 
fetchAllTrackSamples(int64_t seekTimeUs,MediaSource::ReadOptions::SeekMode mode)497 ssize_t NuMediaExtractor::fetchAllTrackSamples(
498         int64_t seekTimeUs, MediaSource::ReadOptions::SeekMode mode) {
499     TrackInfo *minInfo = NULL;
500     ssize_t minIndex = ERROR_END_OF_STREAM;
501 
502     for (size_t i = 0; i < mSelectedTracks.size(); ++i) {
503         TrackInfo *info = &mSelectedTracks.editItemAt(i);
504         fetchTrackSamples(info, seekTimeUs, mode);
505 
506         status_t err = info->mFinalResult;
507         if (err != OK && err != ERROR_END_OF_STREAM && info->mSamples.empty()) {
508             return err;
509         }
510 
511         if (info->mSamples.empty()) {
512             continue;
513         }
514 
515         if (minInfo == NULL) {
516             minInfo = info;
517             minIndex = i;
518         } else {
519             auto it = info->mSamples.begin();
520             auto itMin = minInfo->mSamples.begin();
521             if (it->mSampleTimeUs < itMin->mSampleTimeUs) {
522                 minInfo = info;
523                 minIndex = i;
524             }
525         }
526     }
527 
528     return minIndex;
529 }
530 
fetchTrackSamples(TrackInfo * info,int64_t seekTimeUs,MediaSource::ReadOptions::SeekMode mode)531 void NuMediaExtractor::fetchTrackSamples(TrackInfo *info,
532         int64_t seekTimeUs, MediaSource::ReadOptions::SeekMode mode) {
533     if (info == NULL) {
534         return;
535     }
536 
537     MediaSource::ReadOptions options;
538     if (seekTimeUs >= 0LL) {
539         options.setSeekTo(seekTimeUs, mode);
540         info->mFinalResult = OK;
541         releaseTrackSamples(info);
542     } else if (info->mFinalResult != OK || !info->mSamples.empty()) {
543         return;
544     }
545 
546     status_t err = OK;
547     Vector<MediaBufferBase *> mediaBuffers;
548     if (info->mSource->supportReadMultiple()) {
549         options.setNonBlocking();
550         err = info->mSource->readMultiple(&mediaBuffers, info->mMaxFetchCount, &options);
551     } else {
552         MediaBufferBase *mbuf = NULL;
553         err = info->mSource->read(&mbuf, &options);
554         if (err == OK && mbuf != NULL) {
555             mediaBuffers.push_back(mbuf);
556         }
557     }
558 
559     info->mFinalResult = err;
560     if (err != OK && err != ERROR_END_OF_STREAM) {
561         ALOGW("read on track %zu failed with error %d", info->mTrackIndex, err);
562     }
563 
564     size_t count = mediaBuffers.size();
565     bool releaseRemaining = false;
566     for (size_t id = 0; id < count; ++id) {
567         int64_t timeUs;
568         MediaBufferBase *mbuf = mediaBuffers[id];
569         if (mbuf == NULL) {
570             continue;
571         }
572         if (releaseRemaining) {
573             mbuf->release();
574             continue;
575         }
576         if (mbuf->meta_data().findInt64(kKeyTime, &timeUs)) {
577             info->mSamples.emplace_back(mbuf, timeUs);
578         } else {
579             mbuf->meta_data().dumpToLog();
580             info->mFinalResult = ERROR_MALFORMED;
581             mbuf->release();
582             releaseRemaining = true;
583         }
584     }
585 }
586 
seekTo(int64_t timeUs,MediaSource::ReadOptions::SeekMode mode)587 status_t NuMediaExtractor::seekTo(
588         int64_t timeUs, MediaSource::ReadOptions::SeekMode mode) {
589     Mutex::Autolock autoLock(mLock);
590 
591     ssize_t minIndex = fetchAllTrackSamples(timeUs, mode);
592 
593     if (minIndex < 0) {
594         return ERROR_END_OF_STREAM;
595     }
596 
597     return OK;
598 }
599 
advance()600 status_t NuMediaExtractor::advance() {
601     Mutex::Autolock autoLock(mLock);
602 
603     ssize_t minIndex = fetchAllTrackSamples();
604 
605     if (minIndex < 0) {
606         return ERROR_END_OF_STREAM;
607     }
608 
609     TrackInfo *info = &mSelectedTracks.editItemAt(minIndex);
610 
611     if (info == NULL || info->mSamples.empty()) {
612         return ERROR_END_OF_STREAM;
613     }
614 
615     auto it = info->mSamples.begin();
616     if (it->mBuffer != NULL) {
617         it->mBuffer->release();
618     }
619     info->mSamples.erase(it);
620 
621     if (info->mSamples.empty()) {
622         minIndex = fetchAllTrackSamples();
623         if (minIndex < 0) {
624             return ERROR_END_OF_STREAM;
625         }
626         info = &mSelectedTracks.editItemAt(minIndex);
627         if (info == NULL || info->mSamples.empty()) {
628             return ERROR_END_OF_STREAM;
629         }
630     }
631     return OK;
632 }
633 
appendVorbisNumPageSamples(MediaBufferBase * mbuf,const sp<ABuffer> & buffer)634 status_t NuMediaExtractor::appendVorbisNumPageSamples(
635         MediaBufferBase *mbuf, const sp<ABuffer> &buffer) {
636     int32_t numPageSamples;
637     if (!mbuf->meta_data().findInt32(
638             kKeyValidSamples, &numPageSamples)) {
639         numPageSamples = -1;
640     }
641 
642     // insert, including accounting for the space used.
643     memcpy((uint8_t *)buffer->data() + mbuf->range_length(),
644            &numPageSamples,
645            sizeof(numPageSamples));
646     buffer->setRange(buffer->offset(), buffer->size() + sizeof(numPageSamples));
647 
648     uint32_t type;
649     const void *data;
650     size_t size, size2;
651     if (mbuf->meta_data().findData(kKeyEncryptedSizes, &type, &data, &size)) {
652         // Signal numPageSamples (a plain int32_t) is appended at the end,
653         // i.e. sizeof(numPageSamples) plain bytes + 0 encrypted bytes
654         if (SIZE_MAX - size < sizeof(int32_t)) {
655             return -ENOMEM;
656         }
657 
658         size_t newSize = size + sizeof(int32_t);
659         sp<ABuffer> abuf = new ABuffer(newSize);
660         uint8_t *adata = static_cast<uint8_t *>(abuf->data());
661         if (adata == NULL) {
662             return -ENOMEM;
663         }
664 
665         // append 0 to encrypted sizes
666         int32_t zero = 0;
667         memcpy(adata, data, size);
668         memcpy(adata + size, &zero, sizeof(zero));
669         mbuf->meta_data().setData(kKeyEncryptedSizes, type, adata, newSize);
670 
671         if (mbuf->meta_data().findData(kKeyPlainSizes, &type, &data, &size2)) {
672             if (size2 != size) {
673                 return ERROR_MALFORMED;
674             }
675             memcpy(adata, data, size);
676         } else {
677             // if sample meta data does not include plain size array, assume filled with zeros,
678             // i.e. entire buffer is encrypted
679             memset(adata, 0, size);
680         }
681         // append sizeof(numPageSamples) to plain sizes.
682         int32_t int32Size = sizeof(numPageSamples);
683         memcpy(adata + size, &int32Size, sizeof(int32Size));
684         mbuf->meta_data().setData(kKeyPlainSizes, type, adata, newSize);
685     }
686 
687     return OK;
688 }
689 
readSampleData(const sp<ABuffer> & buffer)690 status_t NuMediaExtractor::readSampleData(const sp<ABuffer> &buffer) {
691     Mutex::Autolock autoLock(mLock);
692 
693     ssize_t minIndex = fetchAllTrackSamples();
694 
695     buffer->setRange(0, 0);     // start with an empty buffer
696 
697     if (minIndex < 0) {
698         return ERROR_END_OF_STREAM;
699     }
700 
701     TrackInfo *info = &mSelectedTracks.editItemAt(minIndex);
702 
703     auto it = info->mSamples.begin();
704     size_t sampleSize = it->mBuffer->range_length();
705 
706     if (info->mTrackFlags & kIsVorbis) {
707         // Each sample's data is suffixed by the number of page samples
708         // or -1 if not available.
709         sampleSize += sizeof(int32_t);
710     }
711 
712     // capacity() is ok since we cleared out the buffer
713     if (buffer->capacity() < sampleSize) {
714         return -ENOMEM;
715     }
716 
717     const size_t srclen = it->mBuffer->range_length();
718     const uint8_t *src =
719         (const uint8_t *)it->mBuffer->data()
720             + it->mBuffer->range_offset();
721 
722     memcpy((uint8_t *)buffer->data(), src, srclen);
723     buffer->setRange(0, srclen);
724 
725     status_t err = OK;
726     if (info->mTrackFlags & kIsVorbis) {
727         // adjusts range when it inserts the extra bits
728         err = appendVorbisNumPageSamples(it->mBuffer, buffer);
729     }
730 
731     return err;
732 }
733 
getSampleSize(size_t * sampleSize)734 status_t NuMediaExtractor::getSampleSize(size_t *sampleSize) {
735     Mutex::Autolock autoLock(mLock);
736 
737     ssize_t minIndex = fetchAllTrackSamples();
738 
739     if (minIndex < 0) {
740         return ERROR_END_OF_STREAM;
741     }
742 
743     TrackInfo *info = &mSelectedTracks.editItemAt(minIndex);
744     auto it = info->mSamples.begin();
745     *sampleSize = it->mBuffer->range_length();
746 
747     if (info->mTrackFlags & kIsVorbis) {
748         // Each sample's data is suffixed by the number of page samples
749         // or -1 if not available.
750         *sampleSize += sizeof(int32_t);
751     }
752 
753     return OK;
754 }
755 
getSampleTrackIndex(size_t * trackIndex)756 status_t NuMediaExtractor::getSampleTrackIndex(size_t *trackIndex) {
757     Mutex::Autolock autoLock(mLock);
758 
759     ssize_t minIndex = fetchAllTrackSamples();
760 
761     if (minIndex < 0) {
762         return ERROR_END_OF_STREAM;
763     }
764 
765     TrackInfo *info = &mSelectedTracks.editItemAt(minIndex);
766     *trackIndex = info->mTrackIndex;
767 
768     return OK;
769 }
770 
getSampleTime(int64_t * sampleTimeUs)771 status_t NuMediaExtractor::getSampleTime(int64_t *sampleTimeUs) {
772     Mutex::Autolock autoLock(mLock);
773 
774     ssize_t minIndex = fetchAllTrackSamples();
775 
776     if (minIndex < 0) {
777         return ERROR_END_OF_STREAM;
778     }
779 
780     TrackInfo *info = &mSelectedTracks.editItemAt(minIndex);
781     *sampleTimeUs = info->mSamples.begin()->mSampleTimeUs;
782 
783     return OK;
784 }
785 
getSampleMeta(sp<MetaData> * sampleMeta)786 status_t NuMediaExtractor::getSampleMeta(sp<MetaData> *sampleMeta) {
787     Mutex::Autolock autoLock(mLock);
788 
789     *sampleMeta = NULL;
790 
791     ssize_t minIndex = fetchAllTrackSamples();
792 
793     if (minIndex < 0) {
794         status_t err = minIndex;
795         return err;
796     }
797 
798     TrackInfo *info = &mSelectedTracks.editItemAt(minIndex);
799     *sampleMeta = new MetaData(info->mSamples.begin()->mBuffer->meta_data());
800 
801     return OK;
802 }
803 
getMetrics(Parcel * reply)804 status_t NuMediaExtractor::getMetrics(Parcel *reply) {
805     if (mImpl == NULL) {
806         return -EINVAL;
807     }
808     status_t status = mImpl->getMetrics(reply);
809     return status;
810 }
811 
getTotalBitrate(int64_t * bitrate) const812 bool NuMediaExtractor::getTotalBitrate(int64_t *bitrate) const {
813     if (mTotalBitrate > 0) {
814         *bitrate = mTotalBitrate;
815         return true;
816     }
817 
818     off64_t size;
819     if (mDurationUs > 0 && mDataSource->getSize(&size) == OK) {
820         *bitrate = size * 8000000LL / mDurationUs;  // in bits/sec
821         return true;
822     }
823 
824     return false;
825 }
826 
827 // Returns true iff cached duration is available/applicable.
getCachedDuration(int64_t * durationUs,bool * eos) const828 bool NuMediaExtractor::getCachedDuration(
829         int64_t *durationUs, bool *eos) const {
830     Mutex::Autolock autoLock(mLock);
831 
832     off64_t cachedDataRemaining = -1;
833     status_t finalStatus = mDataSource->getAvailableSize(-1, &cachedDataRemaining);
834 
835     int64_t bitrate;
836     if (cachedDataRemaining >= 0
837             && getTotalBitrate(&bitrate)) {
838         *durationUs = cachedDataRemaining * 8000000ll / bitrate;
839         *eos = (finalStatus != OK);
840         return true;
841     }
842 
843     return false;
844 }
845 
846 // Return OK if we have received an audio presentation info.
847 // Return ERROR_END_OF_STREAM if no tracks are available.
848 // Return ERROR_UNSUPPORTED if the track has no audio presentation.
849 // Return INVALID_OPERATION if audio presentation metadata version does not match.
getAudioPresentations(size_t trackIndex,AudioPresentationCollection * presentations)850 status_t NuMediaExtractor::getAudioPresentations(
851         size_t trackIndex, AudioPresentationCollection *presentations) {
852     Mutex::Autolock autoLock(mLock);
853     ssize_t minIndex = fetchAllTrackSamples();
854     if (minIndex < 0) {
855         return ERROR_END_OF_STREAM;
856     }
857     for (size_t i = 0; i < mSelectedTracks.size(); ++i) {
858         TrackInfo *info = &mSelectedTracks.editItemAt(i);
859 
860         if (info->mTrackIndex == trackIndex) {
861             sp<MetaData> meta = new MetaData(info->mSamples.begin()->mBuffer->meta_data());
862 
863             uint32_t type;
864             const void *data;
865             size_t size;
866             if (meta != NULL && meta->findData(kKeyAudioPresentationInfo, &type, &data, &size)) {
867                 std::istringstream inStream(std::string(static_cast<const char*>(data), size));
868                 return deserializeAudioPresentations(&inStream, presentations);
869             }
870             ALOGV("Track %zu does not contain any audio presentation", trackIndex);
871             return ERROR_UNSUPPORTED;
872         }
873     }
874     ALOGV("Source does not contain any audio presentation");
875     return ERROR_UNSUPPORTED;
876 }
877 
setLogSessionId(const String8 & logSessionId)878 status_t NuMediaExtractor::setLogSessionId(const String8& logSessionId) {
879     if (mImpl == nullptr) {
880         return ERROR_UNSUPPORTED;
881     }
882     status_t status = mImpl->setLogSessionId(logSessionId);
883     if (status != OK) {
884         ALOGW("Failed to set log session id: %d.", status);
885     }
886     return status;
887 }
888 
889 }  // namespace android
890