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