blob: 8142767027d2ce5fe394834d30233f35b3e56435 [file] [log] [blame]
Wei Jia53692fa2017-12-11 10:33:46 -08001/*
2 * Copyright 2017 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 "GenericSource"
19
20#include "GenericSource.h"
21#include "NdkWrapper.h"
22#include "NuPlayer2Drm.h"
23
24#include "AnotherPacketSource.h"
25#include <binder/IServiceManager.h>
26#include <cutils/properties.h>
27#include <media/DataSource.h>
28#include <media/IMediaExtractorService.h>
29#include <media/MediaHTTPService.h>
30#include <media/MediaExtractor.h>
31#include <media/MediaSource.h>
32#include <media/stagefright/foundation/ABuffer.h>
33#include <media/stagefright/foundation/ADebug.h>
34#include <media/stagefright/foundation/AMessage.h>
35#include <media/stagefright/DataSourceFactory.h>
36#include <media/stagefright/FileSource.h>
37#include <media/stagefright/InterfaceUtils.h>
38#include <media/stagefright/MediaBuffer.h>
39#include <media/stagefright/MediaClock.h>
40#include <media/stagefright/MediaDefs.h>
41#include <media/stagefright/MediaExtractorFactory.h>
42#include <media/stagefright/MetaData.h>
43#include <media/stagefright/Utils.h>
44#include "../../libstagefright/include/NuCachedSource2.h"
45#include "../../libstagefright/include/HTTPBase.h"
46
47namespace android {
48
49static const int kInitialMarkMs = 5000; // 5secs
50
51//static const int kPausePlaybackMarkMs = 2000; // 2secs
52static const int kResumePlaybackMarkMs = 15000; // 15secs
53
54NuPlayer2::GenericSource::GenericSource(
55 const sp<AMessage> &notify,
56 bool uidValid,
57 uid_t uid,
58 const sp<MediaClock> &mediaClock)
59 : Source(notify),
60 mAudioTimeUs(0),
61 mAudioLastDequeueTimeUs(0),
62 mVideoTimeUs(0),
63 mVideoLastDequeueTimeUs(0),
64 mPrevBufferPercentage(-1),
65 mPollBufferingGeneration(0),
66 mSentPauseOnBuffering(false),
67 mAudioDataGeneration(0),
68 mVideoDataGeneration(0),
69 mFetchSubtitleDataGeneration(0),
70 mFetchTimedTextDataGeneration(0),
71 mDurationUs(-1ll),
72 mAudioIsVorbis(false),
73 mIsSecure(false),
74 mIsStreaming(false),
75 mUIDValid(uidValid),
76 mUID(uid),
77 mMediaClock(mediaClock),
78 mFd(-1),
79 mBitrate(-1ll),
80 mPendingReadBufferTypes(0) {
81 ALOGV("GenericSource");
82 CHECK(mediaClock != NULL);
83
84 mBufferingSettings.mInitialMarkMs = kInitialMarkMs;
85 mBufferingSettings.mResumePlaybackMarkMs = kResumePlaybackMarkMs;
86 resetDataSource();
87}
88
89void NuPlayer2::GenericSource::resetDataSource() {
90 ALOGV("resetDataSource");
91
92 mHTTPService.clear();
93 mHttpSource.clear();
94 mDisconnected = false;
95 mUri.clear();
96 mUriHeaders.clear();
97 if (mFd >= 0) {
98 close(mFd);
99 mFd = -1;
100 }
101 mOffset = 0;
102 mLength = 0;
103 mStarted = false;
104 mPreparing = false;
105
106 mIsDrmProtected = false;
107 mIsDrmReleased = false;
108 mIsSecure = false;
109 mMimes.clear();
110}
111
112status_t NuPlayer2::GenericSource::setDataSource(
113 const sp<MediaHTTPService> &httpService,
114 const char *url,
115 const KeyedVector<String8, String8> *headers) {
116 Mutex::Autolock _l(mLock);
117 ALOGV("setDataSource url: %s", url);
118
119 resetDataSource();
120
121 mHTTPService = httpService;
122 mUri = url;
123
124 if (headers) {
125 mUriHeaders = *headers;
126 }
127
128 // delay data source creation to prepareAsync() to avoid blocking
129 // the calling thread in setDataSource for any significant time.
130 return OK;
131}
132
133status_t NuPlayer2::GenericSource::setDataSource(
134 int fd, int64_t offset, int64_t length) {
135 Mutex::Autolock _l(mLock);
136 ALOGV("setDataSource %d/%lld/%lld", fd, (long long)offset, (long long)length);
137
138 resetDataSource();
139
140 mFd = dup(fd);
141 mOffset = offset;
142 mLength = length;
143
144 // delay data source creation to prepareAsync() to avoid blocking
145 // the calling thread in setDataSource for any significant time.
146 return OK;
147}
148
149status_t NuPlayer2::GenericSource::setDataSource(const sp<DataSource>& source) {
150 Mutex::Autolock _l(mLock);
151 ALOGV("setDataSource (source: %p)", source.get());
152
153 resetDataSource();
154 mDataSource = source;
155 return OK;
156}
157
158sp<MetaData> NuPlayer2::GenericSource::getFileFormatMeta() const {
159 Mutex::Autolock _l(mLock);
160 return mFileMeta;
161}
162
163status_t NuPlayer2::GenericSource::initFromDataSource() {
164 sp<IMediaExtractor> extractor;
Dongwon Kang51467422017-12-08 06:07:16 -0800165 CHECK(mDataSource != NULL || mFd != -1);
Wei Jia53692fa2017-12-11 10:33:46 -0800166 sp<DataSource> dataSource = mDataSource;
Dongwon Kang51467422017-12-08 06:07:16 -0800167 const int fd = mFd;
168 const int64_t offset = mOffset;
169 const int64_t length = mLength;
Wei Jia53692fa2017-12-11 10:33:46 -0800170
171 mLock.unlock();
172 // This might take long time if data source is not reliable.
Dongwon Kang51467422017-12-08 06:07:16 -0800173 if (dataSource != nullptr) {
174 extractor = MediaExtractorFactory::Create(dataSource, NULL /* mime */);
175 } else {
176 extractor = MediaExtractorFactory::CreateFromFd(
177 fd, offset, length, NULL /* mime */, &dataSource);
178 }
179
180 if (dataSource == nullptr) {
181 ALOGE("initFromDataSource, failed to create data source!");
182 mLock.lock();
183 return UNKNOWN_ERROR;
184 }
Wei Jia53692fa2017-12-11 10:33:46 -0800185
186 if (extractor == NULL) {
187 ALOGE("initFromDataSource, cannot create extractor!");
Dongwon Kang51467422017-12-08 06:07:16 -0800188 mLock.lock();
Wei Jia53692fa2017-12-11 10:33:46 -0800189 return UNKNOWN_ERROR;
190 }
191
192 sp<MetaData> fileMeta = extractor->getMetaData();
193
194 size_t numtracks = extractor->countTracks();
195 if (numtracks == 0) {
196 ALOGE("initFromDataSource, source has no track!");
Dongwon Kang51467422017-12-08 06:07:16 -0800197 mLock.lock();
Wei Jia53692fa2017-12-11 10:33:46 -0800198 return UNKNOWN_ERROR;
199 }
200
201 mLock.lock();
Dongwon Kang51467422017-12-08 06:07:16 -0800202 mFd = -1;
203 mDataSource = dataSource;
Wei Jia53692fa2017-12-11 10:33:46 -0800204 mFileMeta = fileMeta;
205 if (mFileMeta != NULL) {
206 int64_t duration;
207 if (mFileMeta->findInt64(kKeyDuration, &duration)) {
208 mDurationUs = duration;
209 }
210 }
211
212 int32_t totalBitrate = 0;
213
214 mMimes.clear();
215
216 for (size_t i = 0; i < numtracks; ++i) {
217 sp<IMediaSource> track = extractor->getTrack(i);
218 if (track == NULL) {
219 continue;
220 }
221
222 sp<MetaData> meta = extractor->getTrackMetaData(i);
223 if (meta == NULL) {
224 ALOGE("no metadata for track %zu", i);
225 return UNKNOWN_ERROR;
226 }
227
228 const char *mime;
229 CHECK(meta->findCString(kKeyMIMEType, &mime));
230
231 ALOGV("initFromDataSource track[%zu]: %s", i, mime);
232
233 // Do the string compare immediately with "mime",
234 // we can't assume "mime" would stay valid after another
235 // extractor operation, some extractors might modify meta
236 // during getTrack() and make it invalid.
237 if (!strncasecmp(mime, "audio/", 6)) {
238 if (mAudioTrack.mSource == NULL) {
239 mAudioTrack.mIndex = i;
240 mAudioTrack.mSource = track;
241 mAudioTrack.mPackets =
242 new AnotherPacketSource(mAudioTrack.mSource->getFormat());
243
244 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
245 mAudioIsVorbis = true;
246 } else {
247 mAudioIsVorbis = false;
248 }
249
250 mMimes.add(String8(mime));
251 }
252 } else if (!strncasecmp(mime, "video/", 6)) {
253 if (mVideoTrack.mSource == NULL) {
254 mVideoTrack.mIndex = i;
255 mVideoTrack.mSource = track;
256 mVideoTrack.mPackets =
257 new AnotherPacketSource(mVideoTrack.mSource->getFormat());
258
259 // video always at the beginning
260 mMimes.insertAt(String8(mime), 0);
261 }
262 }
263
264 mSources.push(track);
265 int64_t durationUs;
266 if (meta->findInt64(kKeyDuration, &durationUs)) {
267 if (durationUs > mDurationUs) {
268 mDurationUs = durationUs;
269 }
270 }
271
272 int32_t bitrate;
273 if (totalBitrate >= 0 && meta->findInt32(kKeyBitRate, &bitrate)) {
274 totalBitrate += bitrate;
275 } else {
276 totalBitrate = -1;
277 }
278 }
279
280 ALOGV("initFromDataSource mSources.size(): %zu mIsSecure: %d mime[0]: %s", mSources.size(),
281 mIsSecure, (mMimes.isEmpty() ? "NONE" : mMimes[0].string()));
282
283 if (mSources.size() == 0) {
284 ALOGE("b/23705695");
285 return UNKNOWN_ERROR;
286 }
287
288 // Modular DRM: The return value doesn't affect source initialization.
289 (void)checkDrmInfo();
290
291 mBitrate = totalBitrate;
292
293 return OK;
294}
295
296status_t NuPlayer2::GenericSource::getBufferingSettings(
297 BufferingSettings* buffering /* nonnull */) {
298 {
299 Mutex::Autolock _l(mLock);
300 *buffering = mBufferingSettings;
301 }
302
303 ALOGV("getBufferingSettings{%s}", buffering->toString().string());
304 return OK;
305}
306
307status_t NuPlayer2::GenericSource::setBufferingSettings(const BufferingSettings& buffering) {
308 ALOGV("setBufferingSettings{%s}", buffering.toString().string());
309
310 Mutex::Autolock _l(mLock);
311 mBufferingSettings = buffering;
312 return OK;
313}
314
315status_t NuPlayer2::GenericSource::startSources() {
316 // Start the selected A/V tracks now before we start buffering.
317 // Widevine sources might re-initialize crypto when starting, if we delay
318 // this to start(), all data buffered during prepare would be wasted.
319 // (We don't actually start reading until start().)
320 //
321 // TODO: this logic may no longer be relevant after the removal of widevine
322 // support
323 if (mAudioTrack.mSource != NULL && mAudioTrack.mSource->start() != OK) {
324 ALOGE("failed to start audio track!");
325 return UNKNOWN_ERROR;
326 }
327
328 if (mVideoTrack.mSource != NULL && mVideoTrack.mSource->start() != OK) {
329 ALOGE("failed to start video track!");
330 return UNKNOWN_ERROR;
331 }
332
333 return OK;
334}
335
336int64_t NuPlayer2::GenericSource::getLastReadPosition() {
337 if (mAudioTrack.mSource != NULL) {
338 return mAudioTimeUs;
339 } else if (mVideoTrack.mSource != NULL) {
340 return mVideoTimeUs;
341 } else {
342 return 0;
343 }
344}
345
Wei Jia53692fa2017-12-11 10:33:46 -0800346bool NuPlayer2::GenericSource::isStreaming() const {
347 Mutex::Autolock _l(mLock);
348 return mIsStreaming;
349}
350
351NuPlayer2::GenericSource::~GenericSource() {
352 ALOGV("~GenericSource");
353 if (mLooper != NULL) {
354 mLooper->unregisterHandler(id());
355 mLooper->stop();
356 }
357 resetDataSource();
358}
359
360void NuPlayer2::GenericSource::prepareAsync() {
361 Mutex::Autolock _l(mLock);
362 ALOGV("prepareAsync: (looper: %d)", (mLooper != NULL));
363
364 if (mLooper == NULL) {
365 mLooper = new ALooper;
366 mLooper->setName("generic");
367 mLooper->start();
368
369 mLooper->registerHandler(this);
370 }
371
372 sp<AMessage> msg = new AMessage(kWhatPrepareAsync, this);
373 msg->post();
374}
375
376void NuPlayer2::GenericSource::onPrepareAsync() {
377 ALOGV("onPrepareAsync: mDataSource: %d", (mDataSource != NULL));
378
379 // delayed data source creation
380 if (mDataSource == NULL) {
381 // set to false first, if the extractor
382 // comes back as secure, set it to true then.
383 mIsSecure = false;
384
385 if (!mUri.empty()) {
386 const char* uri = mUri.c_str();
387 String8 contentType;
388
389 if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) {
390 mHttpSource = DataSourceFactory::CreateMediaHTTP(mHTTPService);
391 if (mHttpSource == NULL) {
392 ALOGE("Failed to create http source!");
393 notifyPreparedAndCleanup(UNKNOWN_ERROR);
394 return;
395 }
396 }
397
398 mLock.unlock();
399 // This might take long time if connection has some issue.
400 sp<DataSource> dataSource = DataSourceFactory::CreateFromURI(
401 mHTTPService, uri, &mUriHeaders, &contentType,
402 static_cast<HTTPBase *>(mHttpSource.get()));
403 mLock.lock();
404 if (!mDisconnected) {
405 mDataSource = dataSource;
406 }
Wei Jia53692fa2017-12-11 10:33:46 -0800407 }
408
Dongwon Kang51467422017-12-08 06:07:16 -0800409 if (mFd == -1 && mDataSource == NULL) {
Wei Jia53692fa2017-12-11 10:33:46 -0800410 ALOGE("Failed to create data source!");
411 notifyPreparedAndCleanup(UNKNOWN_ERROR);
412 return;
413 }
414 }
415
Dongwon Kang51467422017-12-08 06:07:16 -0800416 if (mDataSource != nullptr && mDataSource->flags() & DataSource::kIsCachingDataSource) {
Wei Jia53692fa2017-12-11 10:33:46 -0800417 mCachedSource = static_cast<NuCachedSource2 *>(mDataSource.get());
418 }
419
420 // For cached streaming cases, we need to wait for enough
421 // buffering before reporting prepared.
422 mIsStreaming = (mCachedSource != NULL);
423
424 // init extractor from data source
425 status_t err = initFromDataSource();
426
427 if (err != OK) {
428 ALOGE("Failed to init from data source!");
429 notifyPreparedAndCleanup(err);
430 return;
431 }
432
433 if (mVideoTrack.mSource != NULL) {
434 sp<MetaData> meta = getFormatMeta_l(false /* audio */);
435 sp<AMessage> msg = new AMessage;
436 err = convertMetaDataToMessage(meta, &msg);
437 if(err != OK) {
438 notifyPreparedAndCleanup(err);
439 return;
440 }
441 notifyVideoSizeChanged(msg);
442 }
443
444 notifyFlagsChanged(
445 // FLAG_SECURE will be known if/when prepareDrm is called by the app
446 // FLAG_PROTECTED will be known if/when prepareDrm is called by the app
447 FLAG_CAN_PAUSE |
448 FLAG_CAN_SEEK_BACKWARD |
449 FLAG_CAN_SEEK_FORWARD |
450 FLAG_CAN_SEEK);
451
452 finishPrepareAsync();
453
454 ALOGV("onPrepareAsync: Done");
455}
456
457void NuPlayer2::GenericSource::finishPrepareAsync() {
458 ALOGV("finishPrepareAsync");
459
460 status_t err = startSources();
461 if (err != OK) {
462 ALOGE("Failed to init start data source!");
463 notifyPreparedAndCleanup(err);
464 return;
465 }
466
467 if (mIsStreaming) {
468 mCachedSource->resumeFetchingIfNecessary();
469 mPreparing = true;
470 schedulePollBuffering();
471 } else {
472 notifyPrepared();
473 }
474
475 if (mAudioTrack.mSource != NULL) {
476 postReadBuffer(MEDIA_TRACK_TYPE_AUDIO);
477 }
478
479 if (mVideoTrack.mSource != NULL) {
480 postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
481 }
482}
483
484void NuPlayer2::GenericSource::notifyPreparedAndCleanup(status_t err) {
485 if (err != OK) {
486 mDataSource.clear();
487 mCachedSource.clear();
488 mHttpSource.clear();
489
490 mBitrate = -1;
491 mPrevBufferPercentage = -1;
492 ++mPollBufferingGeneration;
493 }
494 notifyPrepared(err);
495}
496
497void NuPlayer2::GenericSource::start() {
498 Mutex::Autolock _l(mLock);
499 ALOGI("start");
500
501 if (mAudioTrack.mSource != NULL) {
502 postReadBuffer(MEDIA_TRACK_TYPE_AUDIO);
503 }
504
505 if (mVideoTrack.mSource != NULL) {
506 postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
507 }
508
509 mStarted = true;
510}
511
512void NuPlayer2::GenericSource::stop() {
513 Mutex::Autolock _l(mLock);
514 mStarted = false;
515}
516
517void NuPlayer2::GenericSource::pause() {
518 Mutex::Autolock _l(mLock);
519 mStarted = false;
520}
521
522void NuPlayer2::GenericSource::resume() {
523 Mutex::Autolock _l(mLock);
524 mStarted = true;
525}
526
527void NuPlayer2::GenericSource::disconnect() {
528 sp<DataSource> dataSource, httpSource;
529 {
530 Mutex::Autolock _l(mLock);
531 dataSource = mDataSource;
532 httpSource = mHttpSource;
533 mDisconnected = true;
534 }
535
536 if (dataSource != NULL) {
537 // disconnect data source
538 if (dataSource->flags() & DataSource::kIsCachingDataSource) {
539 static_cast<NuCachedSource2 *>(dataSource.get())->disconnect();
540 }
541 } else if (httpSource != NULL) {
542 static_cast<HTTPBase *>(httpSource.get())->disconnect();
543 }
544}
545
546status_t NuPlayer2::GenericSource::feedMoreTSData() {
547 return OK;
548}
549
550void NuPlayer2::GenericSource::sendCacheStats() {
551 int32_t kbps = 0;
552 status_t err = UNKNOWN_ERROR;
553
554 if (mCachedSource != NULL) {
555 err = mCachedSource->getEstimatedBandwidthKbps(&kbps);
556 }
557
558 if (err == OK) {
559 sp<AMessage> notify = dupNotify();
560 notify->setInt32("what", kWhatCacheStats);
561 notify->setInt32("bandwidth", kbps);
562 notify->post();
563 }
564}
565
566void NuPlayer2::GenericSource::onMessageReceived(const sp<AMessage> &msg) {
567 Mutex::Autolock _l(mLock);
568 switch (msg->what()) {
569 case kWhatPrepareAsync:
570 {
571 onPrepareAsync();
572 break;
573 }
574 case kWhatFetchSubtitleData:
575 {
576 fetchTextData(kWhatSendSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
577 mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
578 break;
579 }
580
581 case kWhatFetchTimedTextData:
582 {
583 fetchTextData(kWhatSendTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
584 mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
585 break;
586 }
587
588 case kWhatSendSubtitleData:
589 {
590 sendTextData(kWhatSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
591 mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
592 break;
593 }
594
595 case kWhatSendGlobalTimedTextData:
596 {
597 sendGlobalTextData(kWhatTimedTextData, mFetchTimedTextDataGeneration, msg);
598 break;
599 }
600 case kWhatSendTimedTextData:
601 {
602 sendTextData(kWhatTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
603 mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
604 break;
605 }
606
607 case kWhatChangeAVSource:
608 {
609 int32_t trackIndex;
610 CHECK(msg->findInt32("trackIndex", &trackIndex));
611 const sp<IMediaSource> source = mSources.itemAt(trackIndex);
612
613 Track* track;
614 const char *mime;
615 media_track_type trackType, counterpartType;
616 sp<MetaData> meta = source->getFormat();
617 meta->findCString(kKeyMIMEType, &mime);
618 if (!strncasecmp(mime, "audio/", 6)) {
619 track = &mAudioTrack;
620 trackType = MEDIA_TRACK_TYPE_AUDIO;
621 counterpartType = MEDIA_TRACK_TYPE_VIDEO;;
622 } else {
623 CHECK(!strncasecmp(mime, "video/", 6));
624 track = &mVideoTrack;
625 trackType = MEDIA_TRACK_TYPE_VIDEO;
626 counterpartType = MEDIA_TRACK_TYPE_AUDIO;;
627 }
628
629
630 if (track->mSource != NULL) {
631 track->mSource->stop();
632 }
633 track->mSource = source;
634 track->mSource->start();
635 track->mIndex = trackIndex;
636 ++mAudioDataGeneration;
637 ++mVideoDataGeneration;
638
639 int64_t timeUs, actualTimeUs;
640 const bool formatChange = true;
641 if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
642 timeUs = mAudioLastDequeueTimeUs;
643 } else {
644 timeUs = mVideoLastDequeueTimeUs;
645 }
646 readBuffer(trackType, timeUs, MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC /* mode */,
647 &actualTimeUs, formatChange);
648 readBuffer(counterpartType, -1, MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC /* mode */,
649 NULL, !formatChange);
650 ALOGV("timeUs %lld actualTimeUs %lld", (long long)timeUs, (long long)actualTimeUs);
651
652 break;
653 }
654
655 case kWhatSeek:
656 {
657 onSeek(msg);
658 break;
659 }
660
661 case kWhatReadBuffer:
662 {
663 onReadBuffer(msg);
664 break;
665 }
666
667 case kWhatPollBuffering:
668 {
669 int32_t generation;
670 CHECK(msg->findInt32("generation", &generation));
671 if (generation == mPollBufferingGeneration) {
672 onPollBuffering();
673 }
674 break;
675 }
676
677 default:
678 Source::onMessageReceived(msg);
679 break;
680 }
681}
682
683void NuPlayer2::GenericSource::fetchTextData(
684 uint32_t sendWhat,
685 media_track_type type,
686 int32_t curGen,
687 const sp<AnotherPacketSource>& packets,
688 const sp<AMessage>& msg) {
689 int32_t msgGeneration;
690 CHECK(msg->findInt32("generation", &msgGeneration));
691 if (msgGeneration != curGen) {
692 // stale
693 return;
694 }
695
696 int32_t avail;
697 if (packets->hasBufferAvailable(&avail)) {
698 return;
699 }
700
701 int64_t timeUs;
702 CHECK(msg->findInt64("timeUs", &timeUs));
703
704 int64_t subTimeUs = 0;
705 readBuffer(type, timeUs, MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC /* mode */, &subTimeUs);
706
707 status_t eosResult;
708 if (!packets->hasBufferAvailable(&eosResult)) {
709 return;
710 }
711
712 if (msg->what() == kWhatFetchSubtitleData) {
713 subTimeUs -= 1000000ll; // send subtile data one second earlier
714 }
715 sp<AMessage> msg2 = new AMessage(sendWhat, this);
716 msg2->setInt32("generation", msgGeneration);
717 mMediaClock->addTimer(msg2, subTimeUs);
718}
719
720void NuPlayer2::GenericSource::sendTextData(
721 uint32_t what,
722 media_track_type type,
723 int32_t curGen,
724 const sp<AnotherPacketSource>& packets,
725 const sp<AMessage>& msg) {
726 int32_t msgGeneration;
727 CHECK(msg->findInt32("generation", &msgGeneration));
728 if (msgGeneration != curGen) {
729 // stale
730 return;
731 }
732
733 int64_t subTimeUs;
734 if (packets->nextBufferTime(&subTimeUs) != OK) {
735 return;
736 }
737
738 int64_t nextSubTimeUs;
739 readBuffer(type, -1, MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC /* mode */, &nextSubTimeUs);
740
741 sp<ABuffer> buffer;
742 status_t dequeueStatus = packets->dequeueAccessUnit(&buffer);
743 if (dequeueStatus == OK) {
744 sp<AMessage> notify = dupNotify();
745 notify->setInt32("what", what);
746 notify->setBuffer("buffer", buffer);
747 notify->post();
748
749 if (msg->what() == kWhatSendSubtitleData) {
750 nextSubTimeUs -= 1000000ll; // send subtile data one second earlier
751 }
752 mMediaClock->addTimer(msg, nextSubTimeUs);
753 }
754}
755
756void NuPlayer2::GenericSource::sendGlobalTextData(
757 uint32_t what,
758 int32_t curGen,
759 sp<AMessage> msg) {
760 int32_t msgGeneration;
761 CHECK(msg->findInt32("generation", &msgGeneration));
762 if (msgGeneration != curGen) {
763 // stale
764 return;
765 }
766
767 uint32_t textType;
768 const void *data;
769 size_t size = 0;
770 if (mTimedTextTrack.mSource->getFormat()->findData(
771 kKeyTextFormatData, &textType, &data, &size)) {
772 mGlobalTimedText = new ABuffer(size);
773 if (mGlobalTimedText->data()) {
774 memcpy(mGlobalTimedText->data(), data, size);
775 sp<AMessage> globalMeta = mGlobalTimedText->meta();
776 globalMeta->setInt64("timeUs", 0);
777 globalMeta->setString("mime", MEDIA_MIMETYPE_TEXT_3GPP);
778 globalMeta->setInt32("global", 1);
779 sp<AMessage> notify = dupNotify();
780 notify->setInt32("what", what);
781 notify->setBuffer("buffer", mGlobalTimedText);
782 notify->post();
783 }
784 }
785}
786
787sp<MetaData> NuPlayer2::GenericSource::getFormatMeta(bool audio) {
788 Mutex::Autolock _l(mLock);
789 return getFormatMeta_l(audio);
790}
791
792sp<MetaData> NuPlayer2::GenericSource::getFormatMeta_l(bool audio) {
793 sp<IMediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
794
795 if (source == NULL) {
796 return NULL;
797 }
798
799 return source->getFormat();
800}
801
802status_t NuPlayer2::GenericSource::dequeueAccessUnit(
803 bool audio, sp<ABuffer> *accessUnit) {
804 Mutex::Autolock _l(mLock);
805 // If has gone through stop/releaseDrm sequence, we no longer send down any buffer b/c
806 // the codec's crypto object has gone away (b/37960096).
807 // Note: This will be unnecessary when stop() changes behavior and releases codec (b/35248283).
808 if (!mStarted && mIsDrmReleased) {
809 return -EWOULDBLOCK;
810 }
811
812 Track *track = audio ? &mAudioTrack : &mVideoTrack;
813
814 if (track->mSource == NULL) {
815 return -EWOULDBLOCK;
816 }
817
818 status_t finalResult;
819 if (!track->mPackets->hasBufferAvailable(&finalResult)) {
820 if (finalResult == OK) {
821 postReadBuffer(
822 audio ? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
823 return -EWOULDBLOCK;
824 }
825 return finalResult;
826 }
827
828 status_t result = track->mPackets->dequeueAccessUnit(accessUnit);
829
830 // start pulling in more buffers if cache is running low
831 // so that decoder has less chance of being starved
832 if (!mIsStreaming) {
833 if (track->mPackets->getAvailableBufferCount(&finalResult) < 2) {
834 postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
835 }
836 } else {
837 int64_t durationUs = track->mPackets->getBufferedDurationUs(&finalResult);
838 // TODO: maxRebufferingMarkMs could be larger than
839 // mBufferingSettings.mResumePlaybackMarkMs
840 int64_t restartBufferingMarkUs =
841 mBufferingSettings.mResumePlaybackMarkMs * 1000ll / 2;
842 if (finalResult == OK) {
843 if (durationUs < restartBufferingMarkUs) {
844 postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
845 }
846 if (track->mPackets->getAvailableBufferCount(&finalResult) < 2
847 && !mSentPauseOnBuffering && !mPreparing) {
848 mCachedSource->resumeFetchingIfNecessary();
849 sendCacheStats();
850 mSentPauseOnBuffering = true;
851 sp<AMessage> notify = dupNotify();
852 notify->setInt32("what", kWhatPauseOnBufferingStart);
853 notify->post();
854 }
855 }
856 }
857
858 if (result != OK) {
859 if (mSubtitleTrack.mSource != NULL) {
860 mSubtitleTrack.mPackets->clear();
861 mFetchSubtitleDataGeneration++;
862 }
863 if (mTimedTextTrack.mSource != NULL) {
864 mTimedTextTrack.mPackets->clear();
865 mFetchTimedTextDataGeneration++;
866 }
867 return result;
868 }
869
870 int64_t timeUs;
871 status_t eosResult; // ignored
872 CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs));
873 if (audio) {
874 mAudioLastDequeueTimeUs = timeUs;
875 } else {
876 mVideoLastDequeueTimeUs = timeUs;
877 }
878
879 if (mSubtitleTrack.mSource != NULL
880 && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
881 sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, this);
882 msg->setInt64("timeUs", timeUs);
883 msg->setInt32("generation", mFetchSubtitleDataGeneration);
884 msg->post();
885 }
886
887 if (mTimedTextTrack.mSource != NULL
888 && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
889 sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, this);
890 msg->setInt64("timeUs", timeUs);
891 msg->setInt32("generation", mFetchTimedTextDataGeneration);
892 msg->post();
893 }
894
895 return result;
896}
897
898status_t NuPlayer2::GenericSource::getDuration(int64_t *durationUs) {
899 Mutex::Autolock _l(mLock);
900 *durationUs = mDurationUs;
901 return OK;
902}
903
904size_t NuPlayer2::GenericSource::getTrackCount() const {
905 Mutex::Autolock _l(mLock);
906 return mSources.size();
907}
908
909sp<AMessage> NuPlayer2::GenericSource::getTrackInfo(size_t trackIndex) const {
910 Mutex::Autolock _l(mLock);
911 size_t trackCount = mSources.size();
912 if (trackIndex >= trackCount) {
913 return NULL;
914 }
915
916 sp<AMessage> format = new AMessage();
917 sp<MetaData> meta = mSources.itemAt(trackIndex)->getFormat();
918 if (meta == NULL) {
919 ALOGE("no metadata for track %zu", trackIndex);
920 return NULL;
921 }
922
923 const char *mime;
924 CHECK(meta->findCString(kKeyMIMEType, &mime));
925 format->setString("mime", mime);
926
927 int32_t trackType;
928 if (!strncasecmp(mime, "video/", 6)) {
929 trackType = MEDIA_TRACK_TYPE_VIDEO;
930 } else if (!strncasecmp(mime, "audio/", 6)) {
931 trackType = MEDIA_TRACK_TYPE_AUDIO;
932 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
933 trackType = MEDIA_TRACK_TYPE_TIMEDTEXT;
934 } else {
935 trackType = MEDIA_TRACK_TYPE_UNKNOWN;
936 }
937 format->setInt32("type", trackType);
938
939 const char *lang;
940 if (!meta->findCString(kKeyMediaLanguage, &lang)) {
941 lang = "und";
942 }
943 format->setString("language", lang);
944
945 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
946 int32_t isAutoselect = 1, isDefault = 0, isForced = 0;
947 meta->findInt32(kKeyTrackIsAutoselect, &isAutoselect);
948 meta->findInt32(kKeyTrackIsDefault, &isDefault);
949 meta->findInt32(kKeyTrackIsForced, &isForced);
950
951 format->setInt32("auto", !!isAutoselect);
952 format->setInt32("default", !!isDefault);
953 format->setInt32("forced", !!isForced);
954 }
955
956 return format;
957}
958
959ssize_t NuPlayer2::GenericSource::getSelectedTrack(media_track_type type) const {
960 Mutex::Autolock _l(mLock);
961 const Track *track = NULL;
962 switch (type) {
963 case MEDIA_TRACK_TYPE_VIDEO:
964 track = &mVideoTrack;
965 break;
966 case MEDIA_TRACK_TYPE_AUDIO:
967 track = &mAudioTrack;
968 break;
969 case MEDIA_TRACK_TYPE_TIMEDTEXT:
970 track = &mTimedTextTrack;
971 break;
972 case MEDIA_TRACK_TYPE_SUBTITLE:
973 track = &mSubtitleTrack;
974 break;
975 default:
976 break;
977 }
978
979 if (track != NULL && track->mSource != NULL) {
980 return track->mIndex;
981 }
982
983 return -1;
984}
985
986status_t NuPlayer2::GenericSource::selectTrack(size_t trackIndex, bool select, int64_t timeUs) {
987 Mutex::Autolock _l(mLock);
988 ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex);
989
990 if (trackIndex >= mSources.size()) {
991 return BAD_INDEX;
992 }
993
994 if (!select) {
995 Track* track = NULL;
996 if (mSubtitleTrack.mSource != NULL && trackIndex == mSubtitleTrack.mIndex) {
997 track = &mSubtitleTrack;
998 mFetchSubtitleDataGeneration++;
999 } else if (mTimedTextTrack.mSource != NULL && trackIndex == mTimedTextTrack.mIndex) {
1000 track = &mTimedTextTrack;
1001 mFetchTimedTextDataGeneration++;
1002 }
1003 if (track == NULL) {
1004 return INVALID_OPERATION;
1005 }
1006 track->mSource->stop();
1007 track->mSource = NULL;
1008 track->mPackets->clear();
1009 return OK;
1010 }
1011
1012 const sp<IMediaSource> source = mSources.itemAt(trackIndex);
1013 sp<MetaData> meta = source->getFormat();
1014 const char *mime;
1015 CHECK(meta->findCString(kKeyMIMEType, &mime));
1016 if (!strncasecmp(mime, "text/", 5)) {
1017 bool isSubtitle = strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP);
1018 Track *track = isSubtitle ? &mSubtitleTrack : &mTimedTextTrack;
1019 if (track->mSource != NULL && track->mIndex == trackIndex) {
1020 return OK;
1021 }
1022 track->mIndex = trackIndex;
1023 if (track->mSource != NULL) {
1024 track->mSource->stop();
1025 }
1026 track->mSource = mSources.itemAt(trackIndex);
1027 track->mSource->start();
1028 if (track->mPackets == NULL) {
1029 track->mPackets = new AnotherPacketSource(track->mSource->getFormat());
1030 } else {
1031 track->mPackets->clear();
1032 track->mPackets->setFormat(track->mSource->getFormat());
1033
1034 }
1035
1036 if (isSubtitle) {
1037 mFetchSubtitleDataGeneration++;
1038 } else {
1039 mFetchTimedTextDataGeneration++;
1040 }
1041
1042 status_t eosResult; // ignored
1043 if (mSubtitleTrack.mSource != NULL
1044 && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
1045 sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, this);
1046 msg->setInt64("timeUs", timeUs);
1047 msg->setInt32("generation", mFetchSubtitleDataGeneration);
1048 msg->post();
1049 }
1050
1051 sp<AMessage> msg2 = new AMessage(kWhatSendGlobalTimedTextData, this);
1052 msg2->setInt32("generation", mFetchTimedTextDataGeneration);
1053 msg2->post();
1054
1055 if (mTimedTextTrack.mSource != NULL
1056 && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
1057 sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, this);
1058 msg->setInt64("timeUs", timeUs);
1059 msg->setInt32("generation", mFetchTimedTextDataGeneration);
1060 msg->post();
1061 }
1062
1063 return OK;
1064 } else if (!strncasecmp(mime, "audio/", 6) || !strncasecmp(mime, "video/", 6)) {
1065 bool audio = !strncasecmp(mime, "audio/", 6);
1066 Track *track = audio ? &mAudioTrack : &mVideoTrack;
1067 if (track->mSource != NULL && track->mIndex == trackIndex) {
1068 return OK;
1069 }
1070
1071 sp<AMessage> msg = new AMessage(kWhatChangeAVSource, this);
1072 msg->setInt32("trackIndex", trackIndex);
1073 msg->post();
1074 return OK;
1075 }
1076
1077 return INVALID_OPERATION;
1078}
1079
1080status_t NuPlayer2::GenericSource::seekTo(int64_t seekTimeUs, MediaPlayer2SeekMode mode) {
1081 ALOGV("seekTo: %lld, %d", (long long)seekTimeUs, mode);
1082 sp<AMessage> msg = new AMessage(kWhatSeek, this);
1083 msg->setInt64("seekTimeUs", seekTimeUs);
1084 msg->setInt32("mode", mode);
1085
1086 // Need to call readBuffer on |mLooper| to ensure the calls to
1087 // IMediaSource::read* are serialized. Note that IMediaSource::read*
1088 // is called without |mLock| acquired and MediaSource is not thread safe.
1089 sp<AMessage> response;
1090 status_t err = msg->postAndAwaitResponse(&response);
1091 if (err == OK && response != NULL) {
1092 CHECK(response->findInt32("err", &err));
1093 }
1094
1095 return err;
1096}
1097
1098void NuPlayer2::GenericSource::onSeek(const sp<AMessage>& msg) {
1099 int64_t seekTimeUs;
1100 int32_t mode;
1101 CHECK(msg->findInt64("seekTimeUs", &seekTimeUs));
1102 CHECK(msg->findInt32("mode", &mode));
1103
1104 sp<AMessage> response = new AMessage;
1105 status_t err = doSeek(seekTimeUs, (MediaPlayer2SeekMode)mode);
1106 response->setInt32("err", err);
1107
1108 sp<AReplyToken> replyID;
1109 CHECK(msg->senderAwaitsResponse(&replyID));
1110 response->postReply(replyID);
1111}
1112
1113status_t NuPlayer2::GenericSource::doSeek(int64_t seekTimeUs, MediaPlayer2SeekMode mode) {
1114 if (mVideoTrack.mSource != NULL) {
1115 ++mVideoDataGeneration;
1116
1117 int64_t actualTimeUs;
1118 readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, mode, &actualTimeUs);
1119
1120 if (mode != MediaPlayer2SeekMode::SEEK_CLOSEST) {
1121 seekTimeUs = actualTimeUs;
1122 }
1123 mVideoLastDequeueTimeUs = actualTimeUs;
1124 }
1125
1126 if (mAudioTrack.mSource != NULL) {
1127 ++mAudioDataGeneration;
1128 readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs, MediaPlayer2SeekMode::SEEK_CLOSEST);
1129 mAudioLastDequeueTimeUs = seekTimeUs;
1130 }
1131
1132 if (mSubtitleTrack.mSource != NULL) {
1133 mSubtitleTrack.mPackets->clear();
1134 mFetchSubtitleDataGeneration++;
1135 }
1136
1137 if (mTimedTextTrack.mSource != NULL) {
1138 mTimedTextTrack.mPackets->clear();
1139 mFetchTimedTextDataGeneration++;
1140 }
1141
1142 ++mPollBufferingGeneration;
1143 schedulePollBuffering();
1144 return OK;
1145}
1146
1147sp<ABuffer> NuPlayer2::GenericSource::mediaBufferToABuffer(
1148 MediaBuffer* mb,
1149 media_track_type trackType) {
1150 bool audio = trackType == MEDIA_TRACK_TYPE_AUDIO;
1151 size_t outLength = mb->range_length();
1152
1153 if (audio && mAudioIsVorbis) {
1154 outLength += sizeof(int32_t);
1155 }
1156
1157 sp<ABuffer> ab;
1158
1159 if (mIsDrmProtected) {
1160 // Modular DRM
1161 // Enabled for both video/audio so 1) media buffer is reused without extra copying
1162 // 2) meta data can be retrieved in onInputBufferFetched for calling queueSecureInputBuffer.
1163
1164 // data is already provided in the buffer
1165 ab = new ABuffer(NULL, mb->range_length());
1166 mb->add_ref();
1167 ab->setMediaBufferBase(mb);
1168
1169 // Modular DRM: Required b/c of the above add_ref.
1170 // If ref>0, there must be an observer, or it'll crash at release().
1171 // TODO: MediaBuffer might need to be revised to ease such need.
1172 mb->setObserver(this);
1173 // setMediaBufferBase() interestingly doesn't increment the ref count on its own.
1174 // Extra increment (since we want to keep mb alive and attached to ab beyond this function
1175 // call. This is to counter the effect of mb->release() towards the end.
1176 mb->add_ref();
1177
1178 } else {
1179 ab = new ABuffer(outLength);
1180 memcpy(ab->data(),
1181 (const uint8_t *)mb->data() + mb->range_offset(),
1182 mb->range_length());
1183 }
1184
1185 if (audio && mAudioIsVorbis) {
1186 int32_t numPageSamples;
1187 if (!mb->meta_data()->findInt32(kKeyValidSamples, &numPageSamples)) {
1188 numPageSamples = -1;
1189 }
1190
1191 uint8_t* abEnd = ab->data() + mb->range_length();
1192 memcpy(abEnd, &numPageSamples, sizeof(numPageSamples));
1193 }
1194
1195 sp<AMessage> meta = ab->meta();
1196
1197 int64_t timeUs;
1198 CHECK(mb->meta_data()->findInt64(kKeyTime, &timeUs));
1199 meta->setInt64("timeUs", timeUs);
1200
1201 if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
1202 int32_t layerId;
1203 if (mb->meta_data()->findInt32(kKeyTemporalLayerId, &layerId)) {
1204 meta->setInt32("temporal-layer-id", layerId);
1205 }
1206 }
1207
1208 if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) {
1209 const char *mime;
1210 CHECK(mTimedTextTrack.mSource != NULL
1211 && mTimedTextTrack.mSource->getFormat()->findCString(kKeyMIMEType, &mime));
1212 meta->setString("mime", mime);
1213 }
1214
1215 int64_t durationUs;
1216 if (mb->meta_data()->findInt64(kKeyDuration, &durationUs)) {
1217 meta->setInt64("durationUs", durationUs);
1218 }
1219
1220 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
1221 meta->setInt32("trackIndex", mSubtitleTrack.mIndex);
1222 }
1223
1224 uint32_t dataType; // unused
1225 const void *seiData;
1226 size_t seiLength;
1227 if (mb->meta_data()->findData(kKeySEI, &dataType, &seiData, &seiLength)) {
1228 sp<ABuffer> sei = ABuffer::CreateAsCopy(seiData, seiLength);;
1229 meta->setBuffer("sei", sei);
1230 }
1231
1232 const void *mpegUserDataPointer;
1233 size_t mpegUserDataLength;
1234 if (mb->meta_data()->findData(
1235 kKeyMpegUserData, &dataType, &mpegUserDataPointer, &mpegUserDataLength)) {
1236 sp<ABuffer> mpegUserData = ABuffer::CreateAsCopy(mpegUserDataPointer, mpegUserDataLength);
1237 meta->setBuffer("mpegUserData", mpegUserData);
1238 }
1239
1240 mb->release();
1241 mb = NULL;
1242
1243 return ab;
1244}
1245
1246int32_t NuPlayer2::GenericSource::getDataGeneration(media_track_type type) const {
1247 int32_t generation = -1;
1248 switch (type) {
1249 case MEDIA_TRACK_TYPE_VIDEO:
1250 generation = mVideoDataGeneration;
1251 break;
1252 case MEDIA_TRACK_TYPE_AUDIO:
1253 generation = mAudioDataGeneration;
1254 break;
1255 case MEDIA_TRACK_TYPE_TIMEDTEXT:
1256 generation = mFetchTimedTextDataGeneration;
1257 break;
1258 case MEDIA_TRACK_TYPE_SUBTITLE:
1259 generation = mFetchSubtitleDataGeneration;
1260 break;
1261 default:
1262 break;
1263 }
1264
1265 return generation;
1266}
1267
1268void NuPlayer2::GenericSource::postReadBuffer(media_track_type trackType) {
1269 if ((mPendingReadBufferTypes & (1 << trackType)) == 0) {
1270 mPendingReadBufferTypes |= (1 << trackType);
1271 sp<AMessage> msg = new AMessage(kWhatReadBuffer, this);
1272 msg->setInt32("trackType", trackType);
1273 msg->post();
1274 }
1275}
1276
1277void NuPlayer2::GenericSource::onReadBuffer(const sp<AMessage>& msg) {
1278 int32_t tmpType;
1279 CHECK(msg->findInt32("trackType", &tmpType));
1280 media_track_type trackType = (media_track_type)tmpType;
1281 mPendingReadBufferTypes &= ~(1 << trackType);
1282 readBuffer(trackType);
1283}
1284
1285void NuPlayer2::GenericSource::readBuffer(
1286 media_track_type trackType, int64_t seekTimeUs, MediaPlayer2SeekMode mode,
1287 int64_t *actualTimeUs, bool formatChange) {
1288 Track *track;
1289 size_t maxBuffers = 1;
1290 switch (trackType) {
1291 case MEDIA_TRACK_TYPE_VIDEO:
1292 track = &mVideoTrack;
1293 maxBuffers = 8; // too large of a number may influence seeks
1294 break;
1295 case MEDIA_TRACK_TYPE_AUDIO:
1296 track = &mAudioTrack;
1297 maxBuffers = 64;
1298 break;
1299 case MEDIA_TRACK_TYPE_SUBTITLE:
1300 track = &mSubtitleTrack;
1301 break;
1302 case MEDIA_TRACK_TYPE_TIMEDTEXT:
1303 track = &mTimedTextTrack;
1304 break;
1305 default:
1306 TRESPASS();
1307 }
1308
1309 if (track->mSource == NULL) {
1310 return;
1311 }
1312
1313 if (actualTimeUs) {
1314 *actualTimeUs = seekTimeUs;
1315 }
1316
1317 MediaSource::ReadOptions options;
1318
1319 bool seeking = false;
1320 if (seekTimeUs >= 0) {
1321 options.setSeekTo(seekTimeUs, mode);
1322 seeking = true;
1323 }
1324
1325 const bool couldReadMultiple = (track->mSource->supportReadMultiple());
1326
1327 if (couldReadMultiple) {
1328 options.setNonBlocking();
1329 }
1330
1331 int32_t generation = getDataGeneration(trackType);
1332 for (size_t numBuffers = 0; numBuffers < maxBuffers; ) {
1333 Vector<MediaBuffer *> mediaBuffers;
1334 status_t err = NO_ERROR;
1335
1336 sp<IMediaSource> source = track->mSource;
1337 mLock.unlock();
1338 if (couldReadMultiple) {
1339 err = source->readMultiple(
1340 &mediaBuffers, maxBuffers - numBuffers, &options);
1341 } else {
1342 MediaBuffer *mbuf = NULL;
1343 err = source->read(&mbuf, &options);
1344 if (err == OK && mbuf != NULL) {
1345 mediaBuffers.push_back(mbuf);
1346 }
1347 }
1348 mLock.lock();
1349
1350 options.clearNonPersistent();
1351
1352 size_t id = 0;
1353 size_t count = mediaBuffers.size();
1354
1355 // in case track has been changed since we don't have lock for some time.
1356 if (generation != getDataGeneration(trackType)) {
1357 for (; id < count; ++id) {
1358 mediaBuffers[id]->release();
1359 }
1360 break;
1361 }
1362
1363 for (; id < count; ++id) {
1364 int64_t timeUs;
1365 MediaBuffer *mbuf = mediaBuffers[id];
1366 if (!mbuf->meta_data()->findInt64(kKeyTime, &timeUs)) {
1367 mbuf->meta_data()->dumpToLog();
1368 track->mPackets->signalEOS(ERROR_MALFORMED);
1369 break;
1370 }
1371 if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
1372 mAudioTimeUs = timeUs;
1373 } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
1374 mVideoTimeUs = timeUs;
1375 }
1376
1377 queueDiscontinuityIfNeeded(seeking, formatChange, trackType, track);
1378
1379 sp<ABuffer> buffer = mediaBufferToABuffer(mbuf, trackType);
1380 if (numBuffers == 0 && actualTimeUs != nullptr) {
1381 *actualTimeUs = timeUs;
1382 }
1383 if (seeking && buffer != nullptr) {
1384 sp<AMessage> meta = buffer->meta();
1385 if (meta != nullptr && mode == MediaPlayer2SeekMode::SEEK_CLOSEST
1386 && seekTimeUs > timeUs) {
1387 sp<AMessage> extra = new AMessage;
1388 extra->setInt64("resume-at-mediaTimeUs", seekTimeUs);
1389 meta->setMessage("extra", extra);
1390 }
1391 }
1392
1393 track->mPackets->queueAccessUnit(buffer);
1394 formatChange = false;
1395 seeking = false;
1396 ++numBuffers;
1397 }
1398 if (id < count) {
1399 // Error, some mediaBuffer doesn't have kKeyTime.
1400 for (; id < count; ++id) {
1401 mediaBuffers[id]->release();
1402 }
1403 break;
1404 }
1405
1406 if (err == WOULD_BLOCK) {
1407 break;
1408 } else if (err == INFO_FORMAT_CHANGED) {
1409#if 0
1410 track->mPackets->queueDiscontinuity(
1411 ATSParser::DISCONTINUITY_FORMATCHANGE,
1412 NULL,
1413 false /* discard */);
1414#endif
1415 } else if (err != OK) {
1416 queueDiscontinuityIfNeeded(seeking, formatChange, trackType, track);
1417 track->mPackets->signalEOS(err);
1418 break;
1419 }
1420 }
1421
1422 if (mIsStreaming
1423 && (trackType == MEDIA_TRACK_TYPE_VIDEO || trackType == MEDIA_TRACK_TYPE_AUDIO)) {
1424 status_t finalResult;
1425 int64_t durationUs = track->mPackets->getBufferedDurationUs(&finalResult);
1426
1427 // TODO: maxRebufferingMarkMs could be larger than
1428 // mBufferingSettings.mResumePlaybackMarkMs
1429 int64_t markUs = (mPreparing ? mBufferingSettings.mInitialMarkMs
1430 : mBufferingSettings.mResumePlaybackMarkMs) * 1000ll;
1431 if (finalResult == ERROR_END_OF_STREAM || durationUs >= markUs) {
1432 if (mPreparing || mSentPauseOnBuffering) {
1433 Track *counterTrack =
1434 (trackType == MEDIA_TRACK_TYPE_VIDEO ? &mAudioTrack : &mVideoTrack);
1435 if (counterTrack->mSource != NULL) {
1436 durationUs = counterTrack->mPackets->getBufferedDurationUs(&finalResult);
1437 }
1438 if (finalResult == ERROR_END_OF_STREAM || durationUs >= markUs) {
1439 if (mPreparing) {
1440 notifyPrepared();
1441 mPreparing = false;
1442 } else {
1443 sendCacheStats();
1444 mSentPauseOnBuffering = false;
1445 sp<AMessage> notify = dupNotify();
1446 notify->setInt32("what", kWhatResumeOnBufferingEnd);
1447 notify->post();
1448 }
1449 }
1450 }
1451 return;
1452 }
1453
1454 postReadBuffer(trackType);
1455 }
1456}
1457
1458void NuPlayer2::GenericSource::queueDiscontinuityIfNeeded(
1459 bool seeking, bool formatChange, media_track_type trackType, Track *track) {
1460 // formatChange && seeking: track whose source is changed during selection
1461 // formatChange && !seeking: track whose source is not changed during selection
1462 // !formatChange: normal seek
1463 if ((seeking || formatChange)
1464 && (trackType == MEDIA_TRACK_TYPE_AUDIO
1465 || trackType == MEDIA_TRACK_TYPE_VIDEO)) {
1466 ATSParser::DiscontinuityType type = (formatChange && seeking)
1467 ? ATSParser::DISCONTINUITY_FORMATCHANGE
1468 : ATSParser::DISCONTINUITY_NONE;
1469 track->mPackets->queueDiscontinuity(type, NULL /* extra */, true /* discard */);
1470 }
1471}
1472
1473void NuPlayer2::GenericSource::notifyBufferingUpdate(int32_t percentage) {
1474 // Buffering percent could go backward as it's estimated from remaining
1475 // data and last access time. This could cause the buffering position
1476 // drawn on media control to jitter slightly. Remember previously reported
1477 // percentage and don't allow it to go backward.
1478 if (percentage < mPrevBufferPercentage) {
1479 percentage = mPrevBufferPercentage;
1480 } else if (percentage > 100) {
1481 percentage = 100;
1482 }
1483
1484 mPrevBufferPercentage = percentage;
1485
1486 ALOGV("notifyBufferingUpdate: buffering %d%%", percentage);
1487
1488 sp<AMessage> notify = dupNotify();
1489 notify->setInt32("what", kWhatBufferingUpdate);
1490 notify->setInt32("percentage", percentage);
1491 notify->post();
1492}
1493
1494void NuPlayer2::GenericSource::schedulePollBuffering() {
1495 sp<AMessage> msg = new AMessage(kWhatPollBuffering, this);
1496 msg->setInt32("generation", mPollBufferingGeneration);
1497 // Enquires buffering status every second.
1498 msg->post(1000000ll);
1499}
1500
1501void NuPlayer2::GenericSource::onPollBuffering() {
1502 status_t finalStatus = UNKNOWN_ERROR;
1503 int64_t cachedDurationUs = -1ll;
1504 ssize_t cachedDataRemaining = -1;
1505
1506 if (mCachedSource != NULL) {
1507 cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus);
1508
1509 if (finalStatus == OK) {
1510 off64_t size;
1511 int64_t bitrate = 0ll;
1512 if (mDurationUs > 0 && mCachedSource->getSize(&size) == OK) {
1513 // |bitrate| uses bits/second unit, while size is number of bytes.
1514 bitrate = size * 8000000ll / mDurationUs;
1515 } else if (mBitrate > 0) {
1516 bitrate = mBitrate;
1517 }
1518 if (bitrate > 0) {
1519 cachedDurationUs = cachedDataRemaining * 8000000ll / bitrate;
1520 }
1521 }
1522 }
1523
1524 if (finalStatus != OK) {
1525 ALOGV("onPollBuffering: EOS (finalStatus = %d)", finalStatus);
1526
1527 if (finalStatus == ERROR_END_OF_STREAM) {
1528 notifyBufferingUpdate(100);
1529 }
1530
1531 return;
1532 }
1533
1534 if (cachedDurationUs >= 0ll) {
1535 if (mDurationUs > 0ll) {
1536 int64_t cachedPosUs = getLastReadPosition() + cachedDurationUs;
1537 int percentage = 100.0 * cachedPosUs / mDurationUs;
1538 if (percentage > 100) {
1539 percentage = 100;
1540 }
1541
1542 notifyBufferingUpdate(percentage);
1543 }
1544
1545 ALOGV("onPollBuffering: cachedDurationUs %.1f sec", cachedDurationUs / 1000000.0f);
1546 }
1547
1548 schedulePollBuffering();
1549}
1550
1551// Modular DRM
1552status_t NuPlayer2::GenericSource::prepareDrm(
1553 const uint8_t uuid[16],
1554 const Vector<uint8_t> &drmSessionId,
1555 sp<AMediaCryptoWrapper> *outCrypto) {
1556 Mutex::Autolock _l(mLock);
1557 ALOGV("prepareDrm");
1558
1559 mIsDrmProtected = false;
1560 mIsDrmReleased = false;
1561 mIsSecure = false;
1562
1563 status_t status = OK;
1564 sp<AMediaCryptoWrapper> crypto =
1565 new AMediaCryptoWrapper(uuid, drmSessionId.array(), drmSessionId.size());
1566 if (crypto == NULL) {
1567 ALOGE("prepareDrm: failed to create crypto.");
1568 return UNKNOWN_ERROR;
1569 }
1570 ALOGV("prepareDrm: crypto created for uuid: %s",
1571 DrmUUID::toHexString(uuid).string());
1572
1573 *outCrypto = crypto;
1574 // as long a there is an active crypto
1575 mIsDrmProtected = true;
1576
1577 if (mMimes.size() == 0) {
1578 status = UNKNOWN_ERROR;
1579 ALOGE("prepareDrm: Unexpected. Must have at least one track. status: %d", status);
1580 return status;
1581 }
1582
1583 // first mime in this list is either the video track, or the first audio track
1584 const char *mime = mMimes[0].string();
1585 mIsSecure = crypto->requiresSecureDecoderComponent(mime);
1586 ALOGV("prepareDrm: requiresSecureDecoderComponent mime: %s isSecure: %d",
1587 mime, mIsSecure);
1588
1589 // Checking the member flags while in the looper to send out the notification.
1590 // The legacy mDecryptHandle!=NULL check (for FLAG_PROTECTED) is equivalent to mIsDrmProtected.
1591 notifyFlagsChanged(
1592 (mIsSecure ? FLAG_SECURE : 0) |
1593 // Setting "protected screen" only for L1: b/38390836
1594 (mIsSecure ? FLAG_PROTECTED : 0) |
1595 FLAG_CAN_PAUSE |
1596 FLAG_CAN_SEEK_BACKWARD |
1597 FLAG_CAN_SEEK_FORWARD |
1598 FLAG_CAN_SEEK);
1599
1600 if (status == OK) {
1601 ALOGV("prepareDrm: mCrypto: %p", outCrypto->get());
1602 ALOGD("prepareDrm ret: %d ", status);
1603 } else {
1604 ALOGE("prepareDrm err: %d", status);
1605 }
1606 return status;
1607}
1608
1609status_t NuPlayer2::GenericSource::releaseDrm() {
1610 Mutex::Autolock _l(mLock);
1611 ALOGV("releaseDrm");
1612
1613 if (mIsDrmProtected) {
1614 mIsDrmProtected = false;
1615 // to prevent returning any more buffer after stop/releaseDrm (b/37960096)
1616 mIsDrmReleased = true;
1617 ALOGV("releaseDrm: mIsDrmProtected is reset.");
1618 } else {
1619 ALOGE("releaseDrm: mIsDrmProtected is already false.");
1620 }
1621
1622 return OK;
1623}
1624
1625status_t NuPlayer2::GenericSource::checkDrmInfo()
1626{
1627 // clearing the flag at prepare in case the player is reused after stop/releaseDrm with the
1628 // same source without being reset (called by prepareAsync/initFromDataSource)
1629 mIsDrmReleased = false;
1630
1631 if (mFileMeta == NULL) {
1632 ALOGI("checkDrmInfo: No metadata");
1633 return OK; // letting the caller responds accordingly
1634 }
1635
1636 uint32_t type;
1637 const void *pssh;
1638 size_t psshsize;
1639
1640 if (!mFileMeta->findData(kKeyPssh, &type, &pssh, &psshsize)) {
1641 ALOGV("checkDrmInfo: No PSSH");
1642 return OK; // source without DRM info
1643 }
1644
1645 Parcel parcel;
1646 NuPlayer2Drm::retrieveDrmInfo(pssh, psshsize, &parcel);
1647 ALOGV("checkDrmInfo: MEDIA2_DRM_INFO PSSH size: %d Parcel size: %d objects#: %d",
1648 (int)psshsize, (int)parcel.dataSize(), (int)parcel.objectsCount());
1649
1650 if (parcel.dataSize() == 0) {
1651 ALOGE("checkDrmInfo: Unexpected parcel size: 0");
1652 return UNKNOWN_ERROR;
1653 }
1654
1655 // Can't pass parcel as a message to the player. Converting Parcel->ABuffer to pass it
1656 // to the Player's onSourceNotify then back to Parcel for calling driver's notifyListener.
1657 sp<ABuffer> drmInfoBuffer = ABuffer::CreateAsCopy(parcel.data(), parcel.dataSize());
1658 notifyDrmInfo(drmInfoBuffer);
1659
1660 return OK;
1661}
1662
1663void NuPlayer2::GenericSource::signalBufferReturned(MediaBuffer *buffer)
1664{
1665 //ALOGV("signalBufferReturned %p refCount: %d", buffer, buffer->localRefcount());
1666
1667 buffer->setObserver(NULL);
1668 buffer->release(); // this leads to delete since that there is no observor
1669}
1670
1671} // namespace android