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