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