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