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