• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 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 
22 #include "AnotherPacketSource.h"
23 
24 #include <media/IMediaHTTPService.h>
25 #include <media/stagefright/foundation/ABuffer.h>
26 #include <media/stagefright/foundation/ADebug.h>
27 #include <media/stagefright/foundation/AMessage.h>
28 #include <media/stagefright/DataSource.h>
29 #include <media/stagefright/FileSource.h>
30 #include <media/stagefright/MediaBuffer.h>
31 #include <media/stagefright/MediaDefs.h>
32 #include <media/stagefright/MediaExtractor.h>
33 #include <media/stagefright/MediaSource.h>
34 #include <media/stagefright/MetaData.h>
35 #include <media/stagefright/Utils.h>
36 #include "../../libstagefright/include/DRMExtractor.h"
37 #include "../../libstagefright/include/NuCachedSource2.h"
38 #include "../../libstagefright/include/WVMExtractor.h"
39 #include "../../libstagefright/include/HTTPBase.h"
40 
41 namespace android {
42 
43 static int64_t kLowWaterMarkUs = 2000000ll;  // 2secs
44 static int64_t kHighWaterMarkUs = 5000000ll;  // 5secs
45 static const ssize_t kLowWaterMarkBytes = 40000;
46 static const ssize_t kHighWaterMarkBytes = 200000;
47 
GenericSource(const sp<AMessage> & notify,bool uidValid,uid_t uid)48 NuPlayer::GenericSource::GenericSource(
49         const sp<AMessage> &notify,
50         bool uidValid,
51         uid_t uid)
52     : Source(notify),
53       mAudioTimeUs(0),
54       mAudioLastDequeueTimeUs(0),
55       mVideoTimeUs(0),
56       mVideoLastDequeueTimeUs(0),
57       mFetchSubtitleDataGeneration(0),
58       mFetchTimedTextDataGeneration(0),
59       mDurationUs(-1ll),
60       mAudioIsVorbis(false),
61       mIsWidevine(false),
62       mIsSecure(false),
63       mIsStreaming(false),
64       mUIDValid(uidValid),
65       mUID(uid),
66       mFd(-1),
67       mDrmManagerClient(NULL),
68       mBitrate(-1ll),
69       mPollBufferingGeneration(0),
70       mPendingReadBufferTypes(0),
71       mBuffering(false),
72       mPrepareBuffering(false),
73       mPrevBufferPercentage(-1) {
74     resetDataSource();
75     DataSource::RegisterDefaultSniffers();
76 }
77 
resetDataSource()78 void NuPlayer::GenericSource::resetDataSource() {
79     mHTTPService.clear();
80     mHttpSource.clear();
81     mUri.clear();
82     mUriHeaders.clear();
83     if (mFd >= 0) {
84         close(mFd);
85         mFd = -1;
86     }
87     mOffset = 0;
88     mLength = 0;
89     setDrmPlaybackStatusIfNeeded(Playback::STOP, 0);
90     mDecryptHandle = NULL;
91     mDrmManagerClient = NULL;
92     mStarted = false;
93     mStopRead = true;
94 }
95 
setDataSource(const sp<IMediaHTTPService> & httpService,const char * url,const KeyedVector<String8,String8> * headers)96 status_t NuPlayer::GenericSource::setDataSource(
97         const sp<IMediaHTTPService> &httpService,
98         const char *url,
99         const KeyedVector<String8, String8> *headers) {
100     resetDataSource();
101 
102     mHTTPService = httpService;
103     mUri = url;
104 
105     if (headers) {
106         mUriHeaders = *headers;
107     }
108 
109     // delay data source creation to prepareAsync() to avoid blocking
110     // the calling thread in setDataSource for any significant time.
111     return OK;
112 }
113 
setDataSource(int fd,int64_t offset,int64_t length)114 status_t NuPlayer::GenericSource::setDataSource(
115         int fd, int64_t offset, int64_t length) {
116     resetDataSource();
117 
118     mFd = dup(fd);
119     mOffset = offset;
120     mLength = length;
121 
122     // delay data source creation to prepareAsync() to avoid blocking
123     // the calling thread in setDataSource for any significant time.
124     return OK;
125 }
126 
setDataSource(const sp<DataSource> & source)127 status_t NuPlayer::GenericSource::setDataSource(const sp<DataSource>& source) {
128     resetDataSource();
129     mDataSource = source;
130     return OK;
131 }
132 
getFileFormatMeta() const133 sp<MetaData> NuPlayer::GenericSource::getFileFormatMeta() const {
134     return mFileMeta;
135 }
136 
initFromDataSource()137 status_t NuPlayer::GenericSource::initFromDataSource() {
138     sp<MediaExtractor> extractor;
139     String8 mimeType;
140     float confidence;
141     sp<AMessage> dummy;
142     bool isWidevineStreaming = false;
143 
144     CHECK(mDataSource != NULL);
145 
146     if (mIsWidevine) {
147         isWidevineStreaming = SniffWVM(
148                 mDataSource, &mimeType, &confidence, &dummy);
149         if (!isWidevineStreaming ||
150                 strcasecmp(
151                     mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) {
152             ALOGE("unsupported widevine mime: %s", mimeType.string());
153             return UNKNOWN_ERROR;
154         }
155     } else if (mIsStreaming) {
156         if (!mDataSource->sniff(&mimeType, &confidence, &dummy)) {
157             return UNKNOWN_ERROR;
158         }
159         isWidevineStreaming = !strcasecmp(
160                 mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM);
161     }
162 
163     if (isWidevineStreaming) {
164         // we don't want cached source for widevine streaming.
165         mCachedSource.clear();
166         mDataSource = mHttpSource;
167         mWVMExtractor = new WVMExtractor(mDataSource);
168         mWVMExtractor->setAdaptiveStreamingMode(true);
169         if (mUIDValid) {
170             mWVMExtractor->setUID(mUID);
171         }
172         extractor = mWVMExtractor;
173     } else {
174         extractor = MediaExtractor::Create(mDataSource,
175                 mimeType.isEmpty() ? NULL : mimeType.string());
176     }
177 
178     if (extractor == NULL) {
179         return UNKNOWN_ERROR;
180     }
181 
182     if (extractor->getDrmFlag()) {
183         checkDrmStatus(mDataSource);
184     }
185 
186     mFileMeta = extractor->getMetaData();
187     if (mFileMeta != NULL) {
188         int64_t duration;
189         if (mFileMeta->findInt64(kKeyDuration, &duration)) {
190             mDurationUs = duration;
191         }
192 
193         if (!mIsWidevine) {
194             // Check mime to see if we actually have a widevine source.
195             // If the data source is not URL-type (eg. file source), we
196             // won't be able to tell until now.
197             const char *fileMime;
198             if (mFileMeta->findCString(kKeyMIMEType, &fileMime)
199                     && !strncasecmp(fileMime, "video/wvm", 9)) {
200                 mIsWidevine = true;
201             }
202         }
203     }
204 
205     int32_t totalBitrate = 0;
206 
207     size_t numtracks = extractor->countTracks();
208     if (numtracks == 0) {
209         return UNKNOWN_ERROR;
210     }
211 
212     for (size_t i = 0; i < numtracks; ++i) {
213         sp<MediaSource> track = extractor->getTrack(i);
214         if (track == NULL) {
215             continue;
216         }
217 
218         sp<MetaData> meta = extractor->getTrackMetaData(i);
219 
220         const char *mime;
221         CHECK(meta->findCString(kKeyMIMEType, &mime));
222 
223         // Do the string compare immediately with "mime",
224         // we can't assume "mime" would stay valid after another
225         // extractor operation, some extractors might modify meta
226         // during getTrack() and make it invalid.
227         if (!strncasecmp(mime, "audio/", 6)) {
228             if (mAudioTrack.mSource == NULL) {
229                 mAudioTrack.mIndex = i;
230                 mAudioTrack.mSource = track;
231                 mAudioTrack.mPackets =
232                     new AnotherPacketSource(mAudioTrack.mSource->getFormat());
233 
234                 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
235                     mAudioIsVorbis = true;
236                 } else {
237                     mAudioIsVorbis = false;
238                 }
239             }
240         } else if (!strncasecmp(mime, "video/", 6)) {
241             if (mVideoTrack.mSource == NULL) {
242                 mVideoTrack.mIndex = i;
243                 mVideoTrack.mSource = track;
244                 mVideoTrack.mPackets =
245                     new AnotherPacketSource(mVideoTrack.mSource->getFormat());
246 
247                 // check if the source requires secure buffers
248                 int32_t secure;
249                 if (meta->findInt32(kKeyRequiresSecureBuffers, &secure)
250                         && secure) {
251                     mIsSecure = true;
252                     if (mUIDValid) {
253                         extractor->setUID(mUID);
254                     }
255                 }
256             }
257         }
258 
259         mSources.push(track);
260         int64_t durationUs;
261         if (meta->findInt64(kKeyDuration, &durationUs)) {
262             if (durationUs > mDurationUs) {
263                 mDurationUs = durationUs;
264             }
265         }
266 
267         int32_t bitrate;
268         if (totalBitrate >= 0 && meta->findInt32(kKeyBitRate, &bitrate)) {
269             totalBitrate += bitrate;
270         } else {
271             totalBitrate = -1;
272         }
273     }
274 
275     if (mSources.size() == 0) {
276         ALOGE("b/23705695");
277         return UNKNOWN_ERROR;
278     }
279 
280     mBitrate = totalBitrate;
281 
282     return OK;
283 }
284 
startSources()285 status_t NuPlayer::GenericSource::startSources() {
286     // Start the selected A/V tracks now before we start buffering.
287     // Widevine sources might re-initialize crypto when starting, if we delay
288     // this to start(), all data buffered during prepare would be wasted.
289     // (We don't actually start reading until start().)
290     if (mAudioTrack.mSource != NULL && mAudioTrack.mSource->start() != OK) {
291         ALOGE("failed to start audio track!");
292         return UNKNOWN_ERROR;
293     }
294 
295     if (mVideoTrack.mSource != NULL && mVideoTrack.mSource->start() != OK) {
296         ALOGE("failed to start video track!");
297         return UNKNOWN_ERROR;
298     }
299 
300     return OK;
301 }
302 
checkDrmStatus(const sp<DataSource> & dataSource)303 void NuPlayer::GenericSource::checkDrmStatus(const sp<DataSource>& dataSource) {
304     dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
305     if (mDecryptHandle != NULL) {
306         CHECK(mDrmManagerClient);
307         if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
308             sp<AMessage> msg = dupNotify();
309             msg->setInt32("what", kWhatDrmNoLicense);
310             msg->post();
311         }
312     }
313 }
314 
getLastReadPosition()315 int64_t NuPlayer::GenericSource::getLastReadPosition() {
316     if (mAudioTrack.mSource != NULL) {
317         return mAudioTimeUs;
318     } else if (mVideoTrack.mSource != NULL) {
319         return mVideoTimeUs;
320     } else {
321         return 0;
322     }
323 }
324 
setBuffers(bool audio,Vector<MediaBuffer * > & buffers)325 status_t NuPlayer::GenericSource::setBuffers(
326         bool audio, Vector<MediaBuffer *> &buffers) {
327     if (mIsSecure && !audio && mVideoTrack.mSource != NULL) {
328         return mVideoTrack.mSource->setBuffers(buffers);
329     }
330     return INVALID_OPERATION;
331 }
332 
isStreaming() const333 bool NuPlayer::GenericSource::isStreaming() const {
334     return mIsStreaming;
335 }
336 
~GenericSource()337 NuPlayer::GenericSource::~GenericSource() {
338     if (mLooper != NULL) {
339         mLooper->unregisterHandler(id());
340         mLooper->stop();
341     }
342     resetDataSource();
343 }
344 
prepareAsync()345 void NuPlayer::GenericSource::prepareAsync() {
346     if (mLooper == NULL) {
347         mLooper = new ALooper;
348         mLooper->setName("generic");
349         mLooper->start();
350 
351         mLooper->registerHandler(this);
352     }
353 
354     sp<AMessage> msg = new AMessage(kWhatPrepareAsync, this);
355     msg->post();
356 }
357 
onPrepareAsync()358 void NuPlayer::GenericSource::onPrepareAsync() {
359     // delayed data source creation
360     if (mDataSource == NULL) {
361         // set to false first, if the extractor
362         // comes back as secure, set it to true then.
363         mIsSecure = false;
364 
365         if (!mUri.empty()) {
366             const char* uri = mUri.c_str();
367             String8 contentType;
368             mIsWidevine = !strncasecmp(uri, "widevine://", 11);
369 
370             if (!strncasecmp("http://", uri, 7)
371                     || !strncasecmp("https://", uri, 8)
372                     || mIsWidevine) {
373                 mHttpSource = DataSource::CreateMediaHTTP(mHTTPService);
374                 if (mHttpSource == NULL) {
375                     ALOGE("Failed to create http source!");
376                     notifyPreparedAndCleanup(UNKNOWN_ERROR);
377                     return;
378                 }
379             }
380 
381             mDataSource = DataSource::CreateFromURI(
382                    mHTTPService, uri, &mUriHeaders, &contentType,
383                    static_cast<HTTPBase *>(mHttpSource.get()));
384         } else {
385             mIsWidevine = false;
386 
387             mDataSource = new FileSource(mFd, mOffset, mLength);
388             mFd = -1;
389         }
390 
391         if (mDataSource == NULL) {
392             ALOGE("Failed to create data source!");
393             notifyPreparedAndCleanup(UNKNOWN_ERROR);
394             return;
395         }
396     }
397 
398     if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
399         mCachedSource = static_cast<NuCachedSource2 *>(mDataSource.get());
400     }
401 
402     // For widevine or other cached streaming cases, we need to wait for
403     // enough buffering before reporting prepared.
404     // Note that even when URL doesn't start with widevine://, mIsWidevine
405     // could still be set to true later, if the streaming or file source
406     // is sniffed to be widevine. We don't want to buffer for file source
407     // in that case, so must check the flag now.
408     mIsStreaming = (mIsWidevine || mCachedSource != NULL);
409 
410     // init extractor from data source
411     status_t err = initFromDataSource();
412 
413     if (err != OK) {
414         ALOGE("Failed to init from data source!");
415         notifyPreparedAndCleanup(err);
416         return;
417     }
418 
419     if (mVideoTrack.mSource != NULL) {
420         sp<MetaData> meta = doGetFormatMeta(false /* audio */);
421         sp<AMessage> msg = new AMessage;
422         err = convertMetaDataToMessage(meta, &msg);
423         if(err != OK) {
424             notifyPreparedAndCleanup(err);
425             return;
426         }
427         notifyVideoSizeChanged(msg);
428     }
429 
430     notifyFlagsChanged(
431             (mIsSecure ? FLAG_SECURE : 0)
432             | (mDecryptHandle != NULL ? FLAG_PROTECTED : 0)
433             | FLAG_CAN_PAUSE
434             | FLAG_CAN_SEEK_BACKWARD
435             | FLAG_CAN_SEEK_FORWARD
436             | FLAG_CAN_SEEK);
437 
438     if (mIsSecure) {
439         // secure decoders must be instantiated before starting widevine source
440         sp<AMessage> reply = new AMessage(kWhatSecureDecodersInstantiated, this);
441         notifyInstantiateSecureDecoders(reply);
442     } else {
443         finishPrepareAsync();
444     }
445 }
446 
onSecureDecodersInstantiated(status_t err)447 void NuPlayer::GenericSource::onSecureDecodersInstantiated(status_t err) {
448     if (err != OK) {
449         ALOGE("Failed to instantiate secure decoders!");
450         notifyPreparedAndCleanup(err);
451         return;
452     }
453     finishPrepareAsync();
454 }
455 
finishPrepareAsync()456 void NuPlayer::GenericSource::finishPrepareAsync() {
457     status_t err = startSources();
458     if (err != OK) {
459         ALOGE("Failed to init start data source!");
460         notifyPreparedAndCleanup(err);
461         return;
462     }
463 
464     if (mIsStreaming) {
465         mPrepareBuffering = true;
466 
467         ensureCacheIsFetching();
468         restartPollBuffering();
469     } else {
470         notifyPrepared();
471     }
472 }
473 
notifyPreparedAndCleanup(status_t err)474 void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) {
475     if (err != OK) {
476         {
477             sp<DataSource> dataSource = mDataSource;
478             sp<NuCachedSource2> cachedSource = mCachedSource;
479             sp<DataSource> httpSource = mHttpSource;
480             {
481                 Mutex::Autolock _l(mDisconnectLock);
482                 mDataSource.clear();
483                 mDecryptHandle = NULL;
484                 mDrmManagerClient = NULL;
485                 mCachedSource.clear();
486                 mHttpSource.clear();
487             }
488         }
489         mBitrate = -1;
490 
491         cancelPollBuffering();
492     }
493     notifyPrepared(err);
494 }
495 
start()496 void NuPlayer::GenericSource::start() {
497     ALOGI("start");
498 
499     mStopRead = false;
500     if (mAudioTrack.mSource != NULL) {
501         postReadBuffer(MEDIA_TRACK_TYPE_AUDIO);
502     }
503 
504     if (mVideoTrack.mSource != NULL) {
505         postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
506     }
507 
508     setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000);
509     mStarted = true;
510 
511     (new AMessage(kWhatStart, this))->post();
512 }
513 
stop()514 void NuPlayer::GenericSource::stop() {
515     // nothing to do, just account for DRM playback status
516     setDrmPlaybackStatusIfNeeded(Playback::STOP, 0);
517     mStarted = false;
518     if (mIsWidevine || mIsSecure) {
519         // For widevine or secure sources we need to prevent any further reads.
520         sp<AMessage> msg = new AMessage(kWhatStopWidevine, this);
521         sp<AMessage> response;
522         (void) msg->postAndAwaitResponse(&response);
523     }
524 }
525 
pause()526 void NuPlayer::GenericSource::pause() {
527     // nothing to do, just account for DRM playback status
528     setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0);
529     mStarted = false;
530 }
531 
resume()532 void NuPlayer::GenericSource::resume() {
533     // nothing to do, just account for DRM playback status
534     setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000);
535     mStarted = true;
536 
537     (new AMessage(kWhatResume, this))->post();
538 }
539 
disconnect()540 void NuPlayer::GenericSource::disconnect() {
541     sp<DataSource> dataSource, httpSource;
542     {
543         Mutex::Autolock _l(mDisconnectLock);
544         dataSource = mDataSource;
545         httpSource = mHttpSource;
546     }
547 
548     if (dataSource != NULL) {
549         // disconnect data source
550         if (dataSource->flags() & DataSource::kIsCachingDataSource) {
551             static_cast<NuCachedSource2 *>(dataSource.get())->disconnect();
552         }
553     } else if (httpSource != NULL) {
554         static_cast<HTTPBase *>(httpSource.get())->disconnect();
555     }
556 }
557 
setDrmPlaybackStatusIfNeeded(int playbackStatus,int64_t position)558 void NuPlayer::GenericSource::setDrmPlaybackStatusIfNeeded(int playbackStatus, int64_t position) {
559     if (mDecryptHandle != NULL) {
560         mDrmManagerClient->setPlaybackStatus(mDecryptHandle, playbackStatus, position);
561     }
562     mSubtitleTrack.mPackets = new AnotherPacketSource(NULL);
563     mTimedTextTrack.mPackets = new AnotherPacketSource(NULL);
564 }
565 
feedMoreTSData()566 status_t NuPlayer::GenericSource::feedMoreTSData() {
567     return OK;
568 }
569 
schedulePollBuffering()570 void NuPlayer::GenericSource::schedulePollBuffering() {
571     sp<AMessage> msg = new AMessage(kWhatPollBuffering, this);
572     msg->setInt32("generation", mPollBufferingGeneration);
573     msg->post(1000000ll);
574 }
575 
cancelPollBuffering()576 void NuPlayer::GenericSource::cancelPollBuffering() {
577     mBuffering = false;
578     ++mPollBufferingGeneration;
579     mPrevBufferPercentage = -1;
580 }
581 
restartPollBuffering()582 void NuPlayer::GenericSource::restartPollBuffering() {
583     if (mIsStreaming) {
584         cancelPollBuffering();
585         onPollBuffering();
586     }
587 }
588 
notifyBufferingUpdate(int32_t percentage)589 void NuPlayer::GenericSource::notifyBufferingUpdate(int32_t percentage) {
590     // Buffering percent could go backward as it's estimated from remaining
591     // data and last access time. This could cause the buffering position
592     // drawn on media control to jitter slightly. Remember previously reported
593     // percentage and don't allow it to go backward.
594     if (percentage < mPrevBufferPercentage) {
595         percentage = mPrevBufferPercentage;
596     } else if (percentage > 100) {
597         percentage = 100;
598     }
599 
600     mPrevBufferPercentage = percentage;
601 
602     ALOGV("notifyBufferingUpdate: buffering %d%%", percentage);
603 
604     sp<AMessage> msg = dupNotify();
605     msg->setInt32("what", kWhatBufferingUpdate);
606     msg->setInt32("percentage", percentage);
607     msg->post();
608 }
609 
startBufferingIfNecessary()610 void NuPlayer::GenericSource::startBufferingIfNecessary() {
611     ALOGV("startBufferingIfNecessary: mPrepareBuffering=%d, mBuffering=%d",
612             mPrepareBuffering, mBuffering);
613 
614     if (mPrepareBuffering) {
615         return;
616     }
617 
618     if (!mBuffering) {
619         mBuffering = true;
620 
621         ensureCacheIsFetching();
622         sendCacheStats();
623 
624         sp<AMessage> notify = dupNotify();
625         notify->setInt32("what", kWhatPauseOnBufferingStart);
626         notify->post();
627     }
628 }
629 
stopBufferingIfNecessary()630 void NuPlayer::GenericSource::stopBufferingIfNecessary() {
631     ALOGV("stopBufferingIfNecessary: mPrepareBuffering=%d, mBuffering=%d",
632             mPrepareBuffering, mBuffering);
633 
634     if (mPrepareBuffering) {
635         mPrepareBuffering = false;
636         notifyPrepared();
637         return;
638     }
639 
640     if (mBuffering) {
641         mBuffering = false;
642 
643         sendCacheStats();
644 
645         sp<AMessage> notify = dupNotify();
646         notify->setInt32("what", kWhatResumeOnBufferingEnd);
647         notify->post();
648     }
649 }
650 
sendCacheStats()651 void NuPlayer::GenericSource::sendCacheStats() {
652     int32_t kbps = 0;
653     status_t err = UNKNOWN_ERROR;
654 
655     if (mWVMExtractor != NULL) {
656         err = mWVMExtractor->getEstimatedBandwidthKbps(&kbps);
657     } else if (mCachedSource != NULL) {
658         err = mCachedSource->getEstimatedBandwidthKbps(&kbps);
659     }
660 
661     if (err == OK) {
662         sp<AMessage> notify = dupNotify();
663         notify->setInt32("what", kWhatCacheStats);
664         notify->setInt32("bandwidth", kbps);
665         notify->post();
666     }
667 }
668 
ensureCacheIsFetching()669 void NuPlayer::GenericSource::ensureCacheIsFetching() {
670     if (mCachedSource != NULL) {
671         mCachedSource->resumeFetchingIfNecessary();
672     }
673 }
674 
onPollBuffering()675 void NuPlayer::GenericSource::onPollBuffering() {
676     status_t finalStatus = UNKNOWN_ERROR;
677     int64_t cachedDurationUs = -1ll;
678     ssize_t cachedDataRemaining = -1;
679 
680     ALOGW_IF(mWVMExtractor != NULL && mCachedSource != NULL,
681             "WVMExtractor and NuCachedSource both present");
682 
683     if (mWVMExtractor != NULL) {
684         cachedDurationUs =
685                 mWVMExtractor->getCachedDurationUs(&finalStatus);
686     } else if (mCachedSource != NULL) {
687         cachedDataRemaining =
688                 mCachedSource->approxDataRemaining(&finalStatus);
689 
690         if (finalStatus == OK) {
691             off64_t size;
692             int64_t bitrate = 0ll;
693             if (mDurationUs > 0 && mCachedSource->getSize(&size) == OK) {
694                 bitrate = size * 8000000ll / mDurationUs;
695             } else if (mBitrate > 0) {
696                 bitrate = mBitrate;
697             }
698             if (bitrate > 0) {
699                 cachedDurationUs = cachedDataRemaining * 8000000ll / bitrate;
700             }
701         }
702     }
703 
704     if (finalStatus != OK) {
705         ALOGV("onPollBuffering: EOS (finalStatus = %d)", finalStatus);
706 
707         if (finalStatus == ERROR_END_OF_STREAM) {
708             notifyBufferingUpdate(100);
709         }
710 
711         stopBufferingIfNecessary();
712         return;
713     } else if (cachedDurationUs >= 0ll) {
714         if (mDurationUs > 0ll) {
715             int64_t cachedPosUs = getLastReadPosition() + cachedDurationUs;
716             int percentage = 100.0 * cachedPosUs / mDurationUs;
717             if (percentage > 100) {
718                 percentage = 100;
719             }
720 
721             notifyBufferingUpdate(percentage);
722         }
723 
724         ALOGV("onPollBuffering: cachedDurationUs %.1f sec",
725                 cachedDurationUs / 1000000.0f);
726 
727         if (cachedDurationUs < kLowWaterMarkUs) {
728             startBufferingIfNecessary();
729         } else if (cachedDurationUs > kHighWaterMarkUs) {
730             stopBufferingIfNecessary();
731         }
732     } else if (cachedDataRemaining >= 0) {
733         ALOGV("onPollBuffering: cachedDataRemaining %zd bytes",
734                 cachedDataRemaining);
735 
736         if (cachedDataRemaining < kLowWaterMarkBytes) {
737             startBufferingIfNecessary();
738         } else if (cachedDataRemaining > kHighWaterMarkBytes) {
739             stopBufferingIfNecessary();
740         }
741     }
742 
743     schedulePollBuffering();
744 }
745 
onMessageReceived(const sp<AMessage> & msg)746 void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) {
747     switch (msg->what()) {
748       case kWhatPrepareAsync:
749       {
750           onPrepareAsync();
751           break;
752       }
753       case kWhatFetchSubtitleData:
754       {
755           fetchTextData(kWhatSendSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
756                   mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
757           break;
758       }
759 
760       case kWhatFetchTimedTextData:
761       {
762           fetchTextData(kWhatSendTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
763                   mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
764           break;
765       }
766 
767       case kWhatSendSubtitleData:
768       {
769           sendTextData(kWhatSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
770                   mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
771           break;
772       }
773 
774       case kWhatSendTimedTextData:
775       {
776           sendTextData(kWhatTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
777                   mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
778           break;
779       }
780 
781       case kWhatChangeAVSource:
782       {
783           int32_t trackIndex;
784           CHECK(msg->findInt32("trackIndex", &trackIndex));
785           const sp<MediaSource> source = mSources.itemAt(trackIndex);
786 
787           Track* track;
788           const char *mime;
789           media_track_type trackType, counterpartType;
790           sp<MetaData> meta = source->getFormat();
791           meta->findCString(kKeyMIMEType, &mime);
792           if (!strncasecmp(mime, "audio/", 6)) {
793               track = &mAudioTrack;
794               trackType = MEDIA_TRACK_TYPE_AUDIO;
795               counterpartType = MEDIA_TRACK_TYPE_VIDEO;;
796           } else {
797               CHECK(!strncasecmp(mime, "video/", 6));
798               track = &mVideoTrack;
799               trackType = MEDIA_TRACK_TYPE_VIDEO;
800               counterpartType = MEDIA_TRACK_TYPE_AUDIO;;
801           }
802 
803 
804           if (track->mSource != NULL) {
805               track->mSource->stop();
806           }
807           track->mSource = source;
808           track->mSource->start();
809           track->mIndex = trackIndex;
810 
811           int64_t timeUs, actualTimeUs;
812           const bool formatChange = true;
813           if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
814               timeUs = mAudioLastDequeueTimeUs;
815           } else {
816               timeUs = mVideoLastDequeueTimeUs;
817           }
818           readBuffer(trackType, timeUs, &actualTimeUs, formatChange);
819           readBuffer(counterpartType, -1, NULL, formatChange);
820           ALOGV("timeUs %lld actualTimeUs %lld", (long long)timeUs, (long long)actualTimeUs);
821 
822           break;
823       }
824 
825       case kWhatStart:
826       case kWhatResume:
827       {
828           restartPollBuffering();
829           break;
830       }
831 
832       case kWhatPollBuffering:
833       {
834           int32_t generation;
835           CHECK(msg->findInt32("generation", &generation));
836           if (generation == mPollBufferingGeneration) {
837               onPollBuffering();
838           }
839           break;
840       }
841 
842       case kWhatGetFormat:
843       {
844           onGetFormatMeta(msg);
845           break;
846       }
847 
848       case kWhatGetSelectedTrack:
849       {
850           onGetSelectedTrack(msg);
851           break;
852       }
853 
854       case kWhatSelectTrack:
855       {
856           onSelectTrack(msg);
857           break;
858       }
859 
860       case kWhatSeek:
861       {
862           onSeek(msg);
863           break;
864       }
865 
866       case kWhatReadBuffer:
867       {
868           onReadBuffer(msg);
869           break;
870       }
871 
872       case kWhatSecureDecodersInstantiated:
873       {
874           int32_t err;
875           CHECK(msg->findInt32("err", &err));
876           onSecureDecodersInstantiated(err);
877           break;
878       }
879 
880       case kWhatStopWidevine:
881       {
882           // mStopRead is only used for Widevine to prevent the video source
883           // from being read while the associated video decoder is shutting down.
884           mStopRead = true;
885           if (mVideoTrack.mSource != NULL) {
886               mVideoTrack.mPackets->clear();
887           }
888           sp<AMessage> response = new AMessage;
889           sp<AReplyToken> replyID;
890           CHECK(msg->senderAwaitsResponse(&replyID));
891           response->postReply(replyID);
892           break;
893       }
894       default:
895           Source::onMessageReceived(msg);
896           break;
897     }
898 }
899 
fetchTextData(uint32_t sendWhat,media_track_type type,int32_t curGen,sp<AnotherPacketSource> packets,sp<AMessage> msg)900 void NuPlayer::GenericSource::fetchTextData(
901         uint32_t sendWhat,
902         media_track_type type,
903         int32_t curGen,
904         sp<AnotherPacketSource> packets,
905         sp<AMessage> msg) {
906     int32_t msgGeneration;
907     CHECK(msg->findInt32("generation", &msgGeneration));
908     if (msgGeneration != curGen) {
909         // stale
910         return;
911     }
912 
913     int32_t avail;
914     if (packets->hasBufferAvailable(&avail)) {
915         return;
916     }
917 
918     int64_t timeUs;
919     CHECK(msg->findInt64("timeUs", &timeUs));
920 
921     int64_t subTimeUs;
922     readBuffer(type, timeUs, &subTimeUs);
923 
924     int64_t delayUs = subTimeUs - timeUs;
925     if (msg->what() == kWhatFetchSubtitleData) {
926         const int64_t oneSecUs = 1000000ll;
927         delayUs -= oneSecUs;
928     }
929     sp<AMessage> msg2 = new AMessage(sendWhat, this);
930     msg2->setInt32("generation", msgGeneration);
931     msg2->post(delayUs < 0 ? 0 : delayUs);
932 }
933 
sendTextData(uint32_t what,media_track_type type,int32_t curGen,sp<AnotherPacketSource> packets,sp<AMessage> msg)934 void NuPlayer::GenericSource::sendTextData(
935         uint32_t what,
936         media_track_type type,
937         int32_t curGen,
938         sp<AnotherPacketSource> packets,
939         sp<AMessage> msg) {
940     int32_t msgGeneration;
941     CHECK(msg->findInt32("generation", &msgGeneration));
942     if (msgGeneration != curGen) {
943         // stale
944         return;
945     }
946 
947     int64_t subTimeUs;
948     if (packets->nextBufferTime(&subTimeUs) != OK) {
949         return;
950     }
951 
952     int64_t nextSubTimeUs;
953     readBuffer(type, -1, &nextSubTimeUs);
954 
955     sp<ABuffer> buffer;
956     status_t dequeueStatus = packets->dequeueAccessUnit(&buffer);
957     if (dequeueStatus == OK) {
958         sp<AMessage> notify = dupNotify();
959         notify->setInt32("what", what);
960         notify->setBuffer("buffer", buffer);
961         notify->post();
962 
963         const int64_t delayUs = nextSubTimeUs - subTimeUs;
964         msg->post(delayUs < 0 ? 0 : delayUs);
965     }
966 }
967 
getFormatMeta(bool audio)968 sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
969     sp<AMessage> msg = new AMessage(kWhatGetFormat, this);
970     msg->setInt32("audio", audio);
971 
972     sp<AMessage> response;
973     void *format;
974     status_t err = msg->postAndAwaitResponse(&response);
975     if (err == OK && response != NULL) {
976         CHECK(response->findPointer("format", &format));
977         return (MetaData *)format;
978     } else {
979         return NULL;
980     }
981 }
982 
onGetFormatMeta(sp<AMessage> msg) const983 void NuPlayer::GenericSource::onGetFormatMeta(sp<AMessage> msg) const {
984     int32_t audio;
985     CHECK(msg->findInt32("audio", &audio));
986 
987     sp<AMessage> response = new AMessage;
988     sp<MetaData> format = doGetFormatMeta(audio);
989     response->setPointer("format", format.get());
990 
991     sp<AReplyToken> replyID;
992     CHECK(msg->senderAwaitsResponse(&replyID));
993     response->postReply(replyID);
994 }
995 
doGetFormatMeta(bool audio) const996 sp<MetaData> NuPlayer::GenericSource::doGetFormatMeta(bool audio) const {
997     sp<MediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
998 
999     if (source == NULL) {
1000         return NULL;
1001     }
1002 
1003     return source->getFormat();
1004 }
1005 
dequeueAccessUnit(bool audio,sp<ABuffer> * accessUnit)1006 status_t NuPlayer::GenericSource::dequeueAccessUnit(
1007         bool audio, sp<ABuffer> *accessUnit) {
1008     Track *track = audio ? &mAudioTrack : &mVideoTrack;
1009 
1010     if (track->mSource == NULL) {
1011         return -EWOULDBLOCK;
1012     }
1013 
1014     if (mIsWidevine && !audio) {
1015         // try to read a buffer as we may not have been able to the last time
1016         postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
1017     }
1018 
1019     status_t finalResult;
1020     if (!track->mPackets->hasBufferAvailable(&finalResult)) {
1021         if (finalResult == OK) {
1022             postReadBuffer(
1023                     audio ? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
1024             return -EWOULDBLOCK;
1025         }
1026         return finalResult;
1027     }
1028 
1029     status_t result = track->mPackets->dequeueAccessUnit(accessUnit);
1030 
1031     // start pulling in more buffers if we only have one (or no) buffer left
1032     // so that decoder has less chance of being starved
1033     if (track->mPackets->getAvailableBufferCount(&finalResult) < 2) {
1034         postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
1035     }
1036 
1037     if (result != OK) {
1038         if (mSubtitleTrack.mSource != NULL) {
1039             mSubtitleTrack.mPackets->clear();
1040             mFetchSubtitleDataGeneration++;
1041         }
1042         if (mTimedTextTrack.mSource != NULL) {
1043             mTimedTextTrack.mPackets->clear();
1044             mFetchTimedTextDataGeneration++;
1045         }
1046         return result;
1047     }
1048 
1049     int64_t timeUs;
1050     status_t eosResult; // ignored
1051     CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs));
1052     if (audio) {
1053         mAudioLastDequeueTimeUs = timeUs;
1054     } else {
1055         mVideoLastDequeueTimeUs = timeUs;
1056     }
1057 
1058     if (mSubtitleTrack.mSource != NULL
1059             && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
1060         sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, this);
1061         msg->setInt64("timeUs", timeUs);
1062         msg->setInt32("generation", mFetchSubtitleDataGeneration);
1063         msg->post();
1064     }
1065 
1066     if (mTimedTextTrack.mSource != NULL
1067             && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
1068         sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, this);
1069         msg->setInt64("timeUs", timeUs);
1070         msg->setInt32("generation", mFetchTimedTextDataGeneration);
1071         msg->post();
1072     }
1073 
1074     return result;
1075 }
1076 
getDuration(int64_t * durationUs)1077 status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) {
1078     *durationUs = mDurationUs;
1079     return OK;
1080 }
1081 
getTrackCount() const1082 size_t NuPlayer::GenericSource::getTrackCount() const {
1083     return mSources.size();
1084 }
1085 
getTrackInfo(size_t trackIndex) const1086 sp<AMessage> NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const {
1087     size_t trackCount = mSources.size();
1088     if (trackIndex >= trackCount) {
1089         return NULL;
1090     }
1091 
1092     sp<AMessage> format = new AMessage();
1093     sp<MetaData> meta = mSources.itemAt(trackIndex)->getFormat();
1094 
1095     const char *mime;
1096     CHECK(meta->findCString(kKeyMIMEType, &mime));
1097     format->setString("mime", mime);
1098 
1099     int32_t trackType;
1100     if (!strncasecmp(mime, "video/", 6)) {
1101         trackType = MEDIA_TRACK_TYPE_VIDEO;
1102     } else if (!strncasecmp(mime, "audio/", 6)) {
1103         trackType = MEDIA_TRACK_TYPE_AUDIO;
1104     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
1105         trackType = MEDIA_TRACK_TYPE_TIMEDTEXT;
1106     } else {
1107         trackType = MEDIA_TRACK_TYPE_UNKNOWN;
1108     }
1109     format->setInt32("type", trackType);
1110 
1111     const char *lang;
1112     if (!meta->findCString(kKeyMediaLanguage, &lang)) {
1113         lang = "und";
1114     }
1115     format->setString("language", lang);
1116 
1117     if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
1118         int32_t isAutoselect = 1, isDefault = 0, isForced = 0;
1119         meta->findInt32(kKeyTrackIsAutoselect, &isAutoselect);
1120         meta->findInt32(kKeyTrackIsDefault, &isDefault);
1121         meta->findInt32(kKeyTrackIsForced, &isForced);
1122 
1123         format->setInt32("auto", !!isAutoselect);
1124         format->setInt32("default", !!isDefault);
1125         format->setInt32("forced", !!isForced);
1126     }
1127 
1128     return format;
1129 }
1130 
getSelectedTrack(media_track_type type) const1131 ssize_t NuPlayer::GenericSource::getSelectedTrack(media_track_type type) const {
1132     sp<AMessage> msg = new AMessage(kWhatGetSelectedTrack, this);
1133     msg->setInt32("type", type);
1134 
1135     sp<AMessage> response;
1136     int32_t index;
1137     status_t err = msg->postAndAwaitResponse(&response);
1138     if (err == OK && response != NULL) {
1139         CHECK(response->findInt32("index", &index));
1140         return index;
1141     } else {
1142         return -1;
1143     }
1144 }
1145 
onGetSelectedTrack(sp<AMessage> msg) const1146 void NuPlayer::GenericSource::onGetSelectedTrack(sp<AMessage> msg) const {
1147     int32_t tmpType;
1148     CHECK(msg->findInt32("type", &tmpType));
1149     media_track_type type = (media_track_type)tmpType;
1150 
1151     sp<AMessage> response = new AMessage;
1152     ssize_t index = doGetSelectedTrack(type);
1153     response->setInt32("index", index);
1154 
1155     sp<AReplyToken> replyID;
1156     CHECK(msg->senderAwaitsResponse(&replyID));
1157     response->postReply(replyID);
1158 }
1159 
doGetSelectedTrack(media_track_type type) const1160 ssize_t NuPlayer::GenericSource::doGetSelectedTrack(media_track_type type) const {
1161     const Track *track = NULL;
1162     switch (type) {
1163     case MEDIA_TRACK_TYPE_VIDEO:
1164         track = &mVideoTrack;
1165         break;
1166     case MEDIA_TRACK_TYPE_AUDIO:
1167         track = &mAudioTrack;
1168         break;
1169     case MEDIA_TRACK_TYPE_TIMEDTEXT:
1170         track = &mTimedTextTrack;
1171         break;
1172     case MEDIA_TRACK_TYPE_SUBTITLE:
1173         track = &mSubtitleTrack;
1174         break;
1175     default:
1176         break;
1177     }
1178 
1179     if (track != NULL && track->mSource != NULL) {
1180         return track->mIndex;
1181     }
1182 
1183     return -1;
1184 }
1185 
selectTrack(size_t trackIndex,bool select,int64_t timeUs)1186 status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select, int64_t timeUs) {
1187     ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex);
1188     sp<AMessage> msg = new AMessage(kWhatSelectTrack, this);
1189     msg->setInt32("trackIndex", trackIndex);
1190     msg->setInt32("select", select);
1191     msg->setInt64("timeUs", timeUs);
1192 
1193     sp<AMessage> response;
1194     status_t err = msg->postAndAwaitResponse(&response);
1195     if (err == OK && response != NULL) {
1196         CHECK(response->findInt32("err", &err));
1197     }
1198 
1199     return err;
1200 }
1201 
onSelectTrack(sp<AMessage> msg)1202 void NuPlayer::GenericSource::onSelectTrack(sp<AMessage> msg) {
1203     int32_t trackIndex, select;
1204     int64_t timeUs;
1205     CHECK(msg->findInt32("trackIndex", &trackIndex));
1206     CHECK(msg->findInt32("select", &select));
1207     CHECK(msg->findInt64("timeUs", &timeUs));
1208 
1209     sp<AMessage> response = new AMessage;
1210     status_t err = doSelectTrack(trackIndex, select, timeUs);
1211     response->setInt32("err", err);
1212 
1213     sp<AReplyToken> replyID;
1214     CHECK(msg->senderAwaitsResponse(&replyID));
1215     response->postReply(replyID);
1216 }
1217 
doSelectTrack(size_t trackIndex,bool select,int64_t timeUs)1218 status_t NuPlayer::GenericSource::doSelectTrack(size_t trackIndex, bool select, int64_t timeUs) {
1219     if (trackIndex >= mSources.size()) {
1220         return BAD_INDEX;
1221     }
1222 
1223     if (!select) {
1224         Track* track = NULL;
1225         if (mSubtitleTrack.mSource != NULL && trackIndex == mSubtitleTrack.mIndex) {
1226             track = &mSubtitleTrack;
1227             mFetchSubtitleDataGeneration++;
1228         } else if (mTimedTextTrack.mSource != NULL && trackIndex == mTimedTextTrack.mIndex) {
1229             track = &mTimedTextTrack;
1230             mFetchTimedTextDataGeneration++;
1231         }
1232         if (track == NULL) {
1233             return INVALID_OPERATION;
1234         }
1235         track->mSource->stop();
1236         track->mSource = NULL;
1237         track->mPackets->clear();
1238         return OK;
1239     }
1240 
1241     const sp<MediaSource> source = mSources.itemAt(trackIndex);
1242     sp<MetaData> meta = source->getFormat();
1243     const char *mime;
1244     CHECK(meta->findCString(kKeyMIMEType, &mime));
1245     if (!strncasecmp(mime, "text/", 5)) {
1246         bool isSubtitle = strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP);
1247         Track *track = isSubtitle ? &mSubtitleTrack : &mTimedTextTrack;
1248         if (track->mSource != NULL && track->mIndex == trackIndex) {
1249             return OK;
1250         }
1251         track->mIndex = trackIndex;
1252         if (track->mSource != NULL) {
1253             track->mSource->stop();
1254         }
1255         track->mSource = mSources.itemAt(trackIndex);
1256         track->mSource->start();
1257         if (track->mPackets == NULL) {
1258             track->mPackets = new AnotherPacketSource(track->mSource->getFormat());
1259         } else {
1260             track->mPackets->clear();
1261             track->mPackets->setFormat(track->mSource->getFormat());
1262 
1263         }
1264 
1265         if (isSubtitle) {
1266             mFetchSubtitleDataGeneration++;
1267         } else {
1268             mFetchTimedTextDataGeneration++;
1269         }
1270 
1271         status_t eosResult; // ignored
1272         if (mSubtitleTrack.mSource != NULL
1273                 && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
1274             sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, this);
1275             msg->setInt64("timeUs", timeUs);
1276             msg->setInt32("generation", mFetchSubtitleDataGeneration);
1277             msg->post();
1278         }
1279 
1280         if (mTimedTextTrack.mSource != NULL
1281                 && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
1282             sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, this);
1283             msg->setInt64("timeUs", timeUs);
1284             msg->setInt32("generation", mFetchTimedTextDataGeneration);
1285             msg->post();
1286         }
1287 
1288         return OK;
1289     } else if (!strncasecmp(mime, "audio/", 6) || !strncasecmp(mime, "video/", 6)) {
1290         bool audio = !strncasecmp(mime, "audio/", 6);
1291         Track *track = audio ? &mAudioTrack : &mVideoTrack;
1292         if (track->mSource != NULL && track->mIndex == trackIndex) {
1293             return OK;
1294         }
1295 
1296         sp<AMessage> msg = new AMessage(kWhatChangeAVSource, this);
1297         msg->setInt32("trackIndex", trackIndex);
1298         msg->post();
1299         return OK;
1300     }
1301 
1302     return INVALID_OPERATION;
1303 }
1304 
seekTo(int64_t seekTimeUs)1305 status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) {
1306     sp<AMessage> msg = new AMessage(kWhatSeek, this);
1307     msg->setInt64("seekTimeUs", seekTimeUs);
1308 
1309     sp<AMessage> response;
1310     status_t err = msg->postAndAwaitResponse(&response);
1311     if (err == OK && response != NULL) {
1312         CHECK(response->findInt32("err", &err));
1313     }
1314 
1315     return err;
1316 }
1317 
onSeek(sp<AMessage> msg)1318 void NuPlayer::GenericSource::onSeek(sp<AMessage> msg) {
1319     int64_t seekTimeUs;
1320     CHECK(msg->findInt64("seekTimeUs", &seekTimeUs));
1321 
1322     sp<AMessage> response = new AMessage;
1323     status_t err = doSeek(seekTimeUs);
1324     response->setInt32("err", err);
1325 
1326     sp<AReplyToken> replyID;
1327     CHECK(msg->senderAwaitsResponse(&replyID));
1328     response->postReply(replyID);
1329 }
1330 
doSeek(int64_t seekTimeUs)1331 status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs) {
1332     // If the Widevine source is stopped, do not attempt to read any
1333     // more buffers.
1334     if (mStopRead) {
1335         return INVALID_OPERATION;
1336     }
1337     if (mVideoTrack.mSource != NULL) {
1338         int64_t actualTimeUs;
1339         readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, &actualTimeUs);
1340 
1341         seekTimeUs = actualTimeUs;
1342         mVideoLastDequeueTimeUs = seekTimeUs;
1343     }
1344 
1345     if (mAudioTrack.mSource != NULL) {
1346         readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs);
1347         mAudioLastDequeueTimeUs = seekTimeUs;
1348     }
1349 
1350     setDrmPlaybackStatusIfNeeded(Playback::START, seekTimeUs / 1000);
1351     if (!mStarted) {
1352         setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0);
1353     }
1354 
1355     // If currently buffering, post kWhatBufferingEnd first, so that
1356     // NuPlayer resumes. Otherwise, if cache hits high watermark
1357     // before new polling happens, no one will resume the playback.
1358     stopBufferingIfNecessary();
1359     restartPollBuffering();
1360 
1361     return OK;
1362 }
1363 
mediaBufferToABuffer(MediaBuffer * mb,media_track_type trackType,int64_t,int64_t * actualTimeUs)1364 sp<ABuffer> NuPlayer::GenericSource::mediaBufferToABuffer(
1365         MediaBuffer* mb,
1366         media_track_type trackType,
1367         int64_t /* seekTimeUs */,
1368         int64_t *actualTimeUs) {
1369     bool audio = trackType == MEDIA_TRACK_TYPE_AUDIO;
1370     size_t outLength = mb->range_length();
1371 
1372     if (audio && mAudioIsVorbis) {
1373         outLength += sizeof(int32_t);
1374     }
1375 
1376     sp<ABuffer> ab;
1377     if (mIsSecure && !audio) {
1378         // data is already provided in the buffer
1379         ab = new ABuffer(NULL, mb->range_length());
1380         mb->add_ref();
1381         ab->setMediaBufferBase(mb);
1382     } else {
1383         ab = new ABuffer(outLength);
1384         memcpy(ab->data(),
1385                (const uint8_t *)mb->data() + mb->range_offset(),
1386                mb->range_length());
1387     }
1388 
1389     if (audio && mAudioIsVorbis) {
1390         int32_t numPageSamples;
1391         if (!mb->meta_data()->findInt32(kKeyValidSamples, &numPageSamples)) {
1392             numPageSamples = -1;
1393         }
1394 
1395         uint8_t* abEnd = ab->data() + mb->range_length();
1396         memcpy(abEnd, &numPageSamples, sizeof(numPageSamples));
1397     }
1398 
1399     sp<AMessage> meta = ab->meta();
1400 
1401     int64_t timeUs;
1402     CHECK(mb->meta_data()->findInt64(kKeyTime, &timeUs));
1403     meta->setInt64("timeUs", timeUs);
1404 
1405 #if 0
1406     // Temporarily disable pre-roll till we have a full solution to handle
1407     // both single seek and continous seek gracefully.
1408     if (seekTimeUs > timeUs) {
1409         sp<AMessage> extra = new AMessage;
1410         extra->setInt64("resume-at-mediaTimeUs", seekTimeUs);
1411         meta->setMessage("extra", extra);
1412     }
1413 #endif
1414 
1415     if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) {
1416         const char *mime;
1417         CHECK(mTimedTextTrack.mSource != NULL
1418                 && mTimedTextTrack.mSource->getFormat()->findCString(kKeyMIMEType, &mime));
1419         meta->setString("mime", mime);
1420     }
1421 
1422     int64_t durationUs;
1423     if (mb->meta_data()->findInt64(kKeyDuration, &durationUs)) {
1424         meta->setInt64("durationUs", durationUs);
1425     }
1426 
1427     if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
1428         meta->setInt32("trackIndex", mSubtitleTrack.mIndex);
1429     }
1430 
1431     uint32_t dataType; // unused
1432     const void *seiData;
1433     size_t seiLength;
1434     if (mb->meta_data()->findData(kKeySEI, &dataType, &seiData, &seiLength)) {
1435         sp<ABuffer> sei = ABuffer::CreateAsCopy(seiData, seiLength);;
1436         meta->setBuffer("sei", sei);
1437     }
1438 
1439     if (actualTimeUs) {
1440         *actualTimeUs = timeUs;
1441     }
1442 
1443     mb->release();
1444     mb = NULL;
1445 
1446     return ab;
1447 }
1448 
postReadBuffer(media_track_type trackType)1449 void NuPlayer::GenericSource::postReadBuffer(media_track_type trackType) {
1450     Mutex::Autolock _l(mReadBufferLock);
1451 
1452     if ((mPendingReadBufferTypes & (1 << trackType)) == 0) {
1453         mPendingReadBufferTypes |= (1 << trackType);
1454         sp<AMessage> msg = new AMessage(kWhatReadBuffer, this);
1455         msg->setInt32("trackType", trackType);
1456         msg->post();
1457     }
1458 }
1459 
onReadBuffer(sp<AMessage> msg)1460 void NuPlayer::GenericSource::onReadBuffer(sp<AMessage> msg) {
1461     int32_t tmpType;
1462     CHECK(msg->findInt32("trackType", &tmpType));
1463     media_track_type trackType = (media_track_type)tmpType;
1464     readBuffer(trackType);
1465     {
1466         // only protect the variable change, as readBuffer may
1467         // take considerable time.
1468         Mutex::Autolock _l(mReadBufferLock);
1469         mPendingReadBufferTypes &= ~(1 << trackType);
1470     }
1471 }
1472 
readBuffer(media_track_type trackType,int64_t seekTimeUs,int64_t * actualTimeUs,bool formatChange)1473 void NuPlayer::GenericSource::readBuffer(
1474         media_track_type trackType, int64_t seekTimeUs, int64_t *actualTimeUs, bool formatChange) {
1475     // Do not read data if Widevine source is stopped
1476     if (mStopRead) {
1477         return;
1478     }
1479     Track *track;
1480     size_t maxBuffers = 1;
1481     switch (trackType) {
1482         case MEDIA_TRACK_TYPE_VIDEO:
1483             track = &mVideoTrack;
1484             if (mIsWidevine) {
1485                 maxBuffers = 2;
1486             } else {
1487                 maxBuffers = 4;
1488             }
1489             break;
1490         case MEDIA_TRACK_TYPE_AUDIO:
1491             track = &mAudioTrack;
1492             if (mIsWidevine) {
1493                 maxBuffers = 8;
1494             } else {
1495                 maxBuffers = 64;
1496             }
1497             break;
1498         case MEDIA_TRACK_TYPE_SUBTITLE:
1499             track = &mSubtitleTrack;
1500             break;
1501         case MEDIA_TRACK_TYPE_TIMEDTEXT:
1502             track = &mTimedTextTrack;
1503             break;
1504         default:
1505             TRESPASS();
1506     }
1507 
1508     if (track->mSource == NULL) {
1509         return;
1510     }
1511 
1512     if (actualTimeUs) {
1513         *actualTimeUs = seekTimeUs;
1514     }
1515 
1516     MediaSource::ReadOptions options;
1517 
1518     bool seeking = false;
1519 
1520     if (seekTimeUs >= 0) {
1521         options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
1522         seeking = true;
1523     }
1524 
1525     if (mIsWidevine) {
1526         options.setNonBlocking();
1527     }
1528 
1529     for (size_t numBuffers = 0; numBuffers < maxBuffers; ) {
1530         MediaBuffer *mbuf;
1531         status_t err = track->mSource->read(&mbuf, &options);
1532 
1533         options.clearSeekTo();
1534 
1535         if (err == OK) {
1536             int64_t timeUs;
1537             CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs));
1538             if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
1539                 mAudioTimeUs = timeUs;
1540             } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
1541                 mVideoTimeUs = timeUs;
1542             }
1543 
1544             queueDiscontinuityIfNeeded(seeking, formatChange, trackType, track);
1545 
1546             sp<ABuffer> buffer = mediaBufferToABuffer(
1547                     mbuf, trackType, seekTimeUs, actualTimeUs);
1548             track->mPackets->queueAccessUnit(buffer);
1549             formatChange = false;
1550             seeking = false;
1551             ++numBuffers;
1552         } else if (err == WOULD_BLOCK) {
1553             break;
1554         } else if (err == INFO_FORMAT_CHANGED) {
1555 #if 0
1556             track->mPackets->queueDiscontinuity(
1557                     ATSParser::DISCONTINUITY_FORMATCHANGE,
1558                     NULL,
1559                     false /* discard */);
1560 #endif
1561         } else {
1562             queueDiscontinuityIfNeeded(seeking, formatChange, trackType, track);
1563             track->mPackets->signalEOS(err);
1564             break;
1565         }
1566     }
1567 }
1568 
queueDiscontinuityIfNeeded(bool seeking,bool formatChange,media_track_type trackType,Track * track)1569 void NuPlayer::GenericSource::queueDiscontinuityIfNeeded(
1570         bool seeking, bool formatChange, media_track_type trackType, Track *track) {
1571     // formatChange && seeking: track whose source is changed during selection
1572     // formatChange && !seeking: track whose source is not changed during selection
1573     // !formatChange: normal seek
1574     if ((seeking || formatChange)
1575             && (trackType == MEDIA_TRACK_TYPE_AUDIO
1576             || trackType == MEDIA_TRACK_TYPE_VIDEO)) {
1577         ATSParser::DiscontinuityType type = (formatChange && seeking)
1578                 ? ATSParser::DISCONTINUITY_FORMATCHANGE
1579                 : ATSParser::DISCONTINUITY_NONE;
1580         track->mPackets->queueDiscontinuity(type, NULL /* extra */, true /* discard */);
1581     }
1582 }
1583 
1584 }  // namespace android
1585