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