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