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