GenericSource.cpp revision f0b72b509ab1147a2a0925aced970dd68fd7fa4f
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
40namespace android {
41
42NuPlayer::GenericSource::GenericSource(
43        const sp<AMessage> &notify,
44        bool uidValid,
45        uid_t uid)
46    : Source(notify),
47      mFetchSubtitleDataGeneration(0),
48      mFetchTimedTextDataGeneration(0),
49      mDurationUs(0ll),
50      mAudioIsVorbis(false),
51      mIsWidevine(false),
52      mUIDValid(uidValid),
53      mUID(uid),
54      mDrmManagerClient(NULL),
55      mMetaDataSize(-1ll),
56      mBitrate(-1ll),
57      mPollBufferingGeneration(0),
58      mPendingReadBufferTypes(0) {
59    resetDataSource();
60    DataSource::RegisterDefaultSniffers();
61}
62
63void NuPlayer::GenericSource::resetDataSource() {
64    mAudioTimeUs = 0;
65    mVideoTimeUs = 0;
66    mHTTPService.clear();
67    mUri.clear();
68    mUriHeaders.clear();
69    mFd = -1;
70    mOffset = 0;
71    mLength = 0;
72    setDrmPlaybackStatusIfNeeded(Playback::STOP, 0);
73    mDecryptHandle = NULL;
74    mDrmManagerClient = NULL;
75    mStarted = false;
76}
77
78status_t NuPlayer::GenericSource::setDataSource(
79        const sp<IMediaHTTPService> &httpService,
80        const char *url,
81        const KeyedVector<String8, String8> *headers) {
82    resetDataSource();
83
84    mHTTPService = httpService;
85    mUri = url;
86
87    if (headers) {
88        mUriHeaders = *headers;
89    }
90
91    // delay data source creation to prepareAsync() to avoid blocking
92    // the calling thread in setDataSource for any significant time.
93    return OK;
94}
95
96status_t NuPlayer::GenericSource::setDataSource(
97        int fd, int64_t offset, int64_t length) {
98    resetDataSource();
99
100    mFd = dup(fd);
101    mOffset = offset;
102    mLength = length;
103
104    // delay data source creation to prepareAsync() to avoid blocking
105    // the calling thread in setDataSource for any significant time.
106    return OK;
107}
108
109sp<MetaData> NuPlayer::GenericSource::getFileFormatMeta() const {
110    return mFileMeta;
111}
112
113status_t NuPlayer::GenericSource::initFromDataSource() {
114    sp<MediaExtractor> extractor;
115
116    CHECK(mDataSource != NULL);
117
118    if (mIsWidevine) {
119        String8 mimeType;
120        float confidence;
121        sp<AMessage> dummy;
122        bool success;
123
124        success = SniffWVM(mDataSource, &mimeType, &confidence, &dummy);
125        if (!success
126                || strcasecmp(
127                    mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) {
128            ALOGE("unsupported widevine mime: %s", mimeType.string());
129            return UNKNOWN_ERROR;
130        }
131
132        mWVMExtractor = new WVMExtractor(mDataSource);
133        mWVMExtractor->setAdaptiveStreamingMode(true);
134        if (mUIDValid) {
135            mWVMExtractor->setUID(mUID);
136        }
137        extractor = mWVMExtractor;
138    } else {
139        extractor = MediaExtractor::Create(mDataSource,
140                mSniffedMIME.empty() ? NULL: mSniffedMIME.c_str());
141    }
142
143    if (extractor == NULL) {
144        return UNKNOWN_ERROR;
145    }
146
147    if (extractor->getDrmFlag()) {
148        checkDrmStatus(mDataSource);
149    }
150
151    mFileMeta = extractor->getMetaData();
152    if (mFileMeta != NULL) {
153        int64_t duration;
154        if (mFileMeta->findInt64(kKeyDuration, &duration)) {
155            mDurationUs = duration;
156        }
157    }
158
159    int32_t totalBitrate = 0;
160
161    for (size_t i = 0; i < extractor->countTracks(); ++i) {
162        sp<MediaSource> track = extractor->getTrack(i);
163
164        sp<MetaData> meta = extractor->getTrackMetaData(i);
165
166        const char *mime;
167        CHECK(meta->findCString(kKeyMIMEType, &mime));
168
169        // Do the string compare immediately with "mime",
170        // we can't assume "mime" would stay valid after another
171        // extractor operation, some extractors might modify meta
172        // during getTrack() and make it invalid.
173        if (!strncasecmp(mime, "audio/", 6)) {
174            if (mAudioTrack.mSource == NULL) {
175                mAudioTrack.mIndex = i;
176                mAudioTrack.mSource = track;
177                mAudioTrack.mPackets =
178                    new AnotherPacketSource(mAudioTrack.mSource->getFormat());
179
180                if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
181                    mAudioIsVorbis = true;
182                } else {
183                    mAudioIsVorbis = false;
184                }
185            }
186        } else if (!strncasecmp(mime, "video/", 6)) {
187            if (mVideoTrack.mSource == NULL) {
188                mVideoTrack.mIndex = i;
189                mVideoTrack.mSource = track;
190                mVideoTrack.mPackets =
191                    new AnotherPacketSource(mVideoTrack.mSource->getFormat());
192
193                // check if the source requires secure buffers
194                int32_t secure;
195                if (meta->findInt32(kKeyRequiresSecureBuffers, &secure)
196                        && secure) {
197                    mIsWidevine = true;
198                    if (mUIDValid) {
199                        extractor->setUID(mUID);
200                    }
201                }
202            }
203        }
204
205        if (track != NULL) {
206            mSources.push(track);
207            int64_t durationUs;
208            if (meta->findInt64(kKeyDuration, &durationUs)) {
209                if (durationUs > mDurationUs) {
210                    mDurationUs = durationUs;
211                }
212            }
213
214            int32_t bitrate;
215            if (totalBitrate >= 0 && meta->findInt32(kKeyBitRate, &bitrate)) {
216                totalBitrate += bitrate;
217            } else {
218                totalBitrate = -1;
219            }
220        }
221    }
222
223    mBitrate = totalBitrate;
224
225    return OK;
226}
227
228void NuPlayer::GenericSource::checkDrmStatus(const sp<DataSource>& dataSource) {
229    dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
230    if (mDecryptHandle != NULL) {
231        CHECK(mDrmManagerClient);
232        if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
233            sp<AMessage> msg = dupNotify();
234            msg->setInt32("what", kWhatDrmNoLicense);
235            msg->post();
236        }
237    }
238}
239
240int64_t NuPlayer::GenericSource::getLastReadPosition() {
241    if (mAudioTrack.mSource != NULL) {
242        return mAudioTimeUs;
243    } else if (mVideoTrack.mSource != NULL) {
244        return mVideoTimeUs;
245    } else {
246        return 0;
247    }
248}
249
250status_t NuPlayer::GenericSource::setBuffers(
251        bool audio, Vector<MediaBuffer *> &buffers) {
252    if (mIsWidevine && !audio) {
253        return mVideoTrack.mSource->setBuffers(buffers);
254    }
255    return INVALID_OPERATION;
256}
257
258NuPlayer::GenericSource::~GenericSource() {
259    if (mLooper != NULL) {
260        mLooper->unregisterHandler(id());
261        mLooper->stop();
262    }
263}
264
265void NuPlayer::GenericSource::prepareAsync() {
266    if (mLooper == NULL) {
267        mLooper = new ALooper;
268        mLooper->setName("generic");
269        mLooper->start();
270
271        mLooper->registerHandler(this);
272    }
273
274    sp<AMessage> msg = new AMessage(kWhatPrepareAsync, id());
275    msg->post();
276}
277
278void NuPlayer::GenericSource::onPrepareAsync() {
279    // delayed data source creation
280    if (mDataSource == NULL) {
281        if (!mUri.empty()) {
282            mIsWidevine = !strncasecmp(mUri.c_str(), "widevine://", 11);
283
284            mDataSource = DataSource::CreateFromURI(
285                   mHTTPService, mUri.c_str(), &mUriHeaders, &mContentType);
286        } else {
287            // set to false first, if the extractor
288            // comes back as secure, set it to true then.
289            mIsWidevine = false;
290
291            mDataSource = new FileSource(mFd, mOffset, mLength);
292        }
293
294        if (mDataSource == NULL) {
295            ALOGE("Failed to create data source!");
296            notifyPreparedAndCleanup(UNKNOWN_ERROR);
297            return;
298        }
299
300        if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
301            mCachedSource = static_cast<NuCachedSource2 *>(mDataSource.get());
302        }
303
304        if (mIsWidevine || mCachedSource != NULL) {
305            schedulePollBuffering();
306        }
307    }
308
309    // check initial caching status
310    status_t err = prefillCacheIfNecessary();
311    if (err != OK) {
312        if (err == -EAGAIN) {
313            (new AMessage(kWhatPrepareAsync, id()))->post(200000);
314        } else {
315            ALOGE("Failed to prefill data cache!");
316            notifyPreparedAndCleanup(UNKNOWN_ERROR);
317        }
318        return;
319    }
320
321    // init extrator from data source
322    err = initFromDataSource();
323
324    if (err != OK) {
325        ALOGE("Failed to init from data source!");
326        notifyPreparedAndCleanup(err);
327        return;
328    }
329
330    if (mVideoTrack.mSource != NULL) {
331        sp<MetaData> meta = doGetFormatMeta(false /* audio */);
332        sp<AMessage> msg = new AMessage;
333        err = convertMetaDataToMessage(meta, &msg);
334        if(err != OK) {
335            notifyPreparedAndCleanup(err);
336            return;
337        }
338        notifyVideoSizeChanged(msg);
339    }
340
341    notifyFlagsChanged(
342            (mIsWidevine ? FLAG_SECURE : 0)
343            | FLAG_CAN_PAUSE
344            | FLAG_CAN_SEEK_BACKWARD
345            | FLAG_CAN_SEEK_FORWARD
346            | FLAG_CAN_SEEK);
347
348    notifyPrepared();
349}
350
351void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) {
352    if (err != OK) {
353        mMetaDataSize = -1ll;
354        mContentType = "";
355        mSniffedMIME = "";
356        mDataSource.clear();
357        mCachedSource.clear();
358
359        cancelPollBuffering();
360    }
361    notifyPrepared(err);
362}
363
364status_t NuPlayer::GenericSource::prefillCacheIfNecessary() {
365    CHECK(mDataSource != NULL);
366
367    if (mCachedSource == NULL) {
368        // no prefill if the data source is not cached
369        return OK;
370    }
371
372    // We're not doing this for streams that appear to be audio-only
373    // streams to ensure that even low bandwidth streams start
374    // playing back fairly instantly.
375    if (!strncasecmp(mContentType.string(), "audio/", 6)) {
376        return OK;
377    }
378
379    // We're going to prefill the cache before trying to instantiate
380    // the extractor below, as the latter is an operation that otherwise
381    // could block on the datasource for a significant amount of time.
382    // During that time we'd be unable to abort the preparation phase
383    // without this prefill.
384
385    // Initially make sure we have at least 192 KB for the sniff
386    // to complete without blocking.
387    static const size_t kMinBytesForSniffing = 192 * 1024;
388    static const size_t kDefaultMetaSize = 200000;
389
390    status_t finalStatus;
391
392    size_t cachedDataRemaining =
393            mCachedSource->approxDataRemaining(&finalStatus);
394
395    if (finalStatus != OK || (mMetaDataSize >= 0
396            && (off64_t)cachedDataRemaining >= mMetaDataSize)) {
397        ALOGV("stop caching, status %d, "
398                "metaDataSize %lld, cachedDataRemaining %zu",
399                finalStatus, mMetaDataSize, cachedDataRemaining);
400        return OK;
401    }
402
403    ALOGV("now cached %zu bytes of data", cachedDataRemaining);
404
405    if (mMetaDataSize < 0
406            && cachedDataRemaining >= kMinBytesForSniffing) {
407        String8 tmp;
408        float confidence;
409        sp<AMessage> meta;
410        if (!mCachedSource->sniff(&tmp, &confidence, &meta)) {
411            return UNKNOWN_ERROR;
412        }
413
414        // We successfully identified the file's extractor to
415        // be, remember this mime type so we don't have to
416        // sniff it again when we call MediaExtractor::Create()
417        mSniffedMIME = tmp.string();
418
419        if (meta == NULL
420                || !meta->findInt64("meta-data-size",
421                        reinterpret_cast<int64_t*>(&mMetaDataSize))) {
422            mMetaDataSize = kDefaultMetaSize;
423        }
424
425        if (mMetaDataSize < 0ll) {
426            ALOGE("invalid metaDataSize = %lld bytes", mMetaDataSize);
427            return UNKNOWN_ERROR;
428        }
429    }
430
431    return -EAGAIN;
432}
433
434void NuPlayer::GenericSource::start() {
435    ALOGI("start");
436
437    if (mAudioTrack.mSource != NULL) {
438        CHECK_EQ(mAudioTrack.mSource->start(), (status_t)OK);
439
440        postReadBuffer(MEDIA_TRACK_TYPE_AUDIO);
441    }
442
443    if (mVideoTrack.mSource != NULL) {
444        CHECK_EQ(mVideoTrack.mSource->start(), (status_t)OK);
445
446        postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
447    }
448
449    setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000);
450    mStarted = true;
451}
452
453void NuPlayer::GenericSource::stop() {
454    // nothing to do, just account for DRM playback status
455    setDrmPlaybackStatusIfNeeded(Playback::STOP, 0);
456    mStarted = false;
457}
458
459void NuPlayer::GenericSource::pause() {
460    // nothing to do, just account for DRM playback status
461    setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0);
462    mStarted = false;
463}
464
465void NuPlayer::GenericSource::resume() {
466    // nothing to do, just account for DRM playback status
467    setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000);
468    mStarted = true;
469}
470
471void NuPlayer::GenericSource::setDrmPlaybackStatusIfNeeded(int playbackStatus, int64_t position) {
472    if (mDecryptHandle != NULL) {
473        mDrmManagerClient->setPlaybackStatus(mDecryptHandle, playbackStatus, position);
474    }
475    mSubtitleTrack.mPackets = new AnotherPacketSource(NULL);
476    mTimedTextTrack.mPackets = new AnotherPacketSource(NULL);
477}
478
479status_t NuPlayer::GenericSource::feedMoreTSData() {
480    return OK;
481}
482
483void NuPlayer::GenericSource::schedulePollBuffering() {
484    sp<AMessage> msg = new AMessage(kWhatPollBuffering, id());
485    msg->setInt32("generation", mPollBufferingGeneration);
486    msg->post(1000000ll);
487}
488
489void NuPlayer::GenericSource::cancelPollBuffering() {
490    ++mPollBufferingGeneration;
491}
492
493void NuPlayer::GenericSource::notifyBufferingUpdate(int percentage) {
494    sp<AMessage> msg = dupNotify();
495    msg->setInt32("what", kWhatBufferingUpdate);
496    msg->setInt32("percentage", percentage);
497    msg->post();
498}
499
500void NuPlayer::GenericSource::onPollBuffering() {
501    status_t finalStatus = UNKNOWN_ERROR;
502    int64_t cachedDurationUs = 0ll;
503
504    if (mCachedSource != NULL) {
505        size_t cachedDataRemaining =
506                mCachedSource->approxDataRemaining(&finalStatus);
507
508        if (finalStatus == OK) {
509            off64_t size;
510            int64_t bitrate = 0ll;
511            if (mDurationUs > 0 && mCachedSource->getSize(&size) == OK) {
512                bitrate = size * 8000000ll / mDurationUs;
513            } else if (mBitrate > 0) {
514                bitrate = mBitrate;
515            }
516            if (bitrate > 0) {
517                cachedDurationUs = cachedDataRemaining * 8000000ll / bitrate;
518            }
519        }
520    } else if (mWVMExtractor != NULL) {
521        cachedDurationUs
522            = mWVMExtractor->getCachedDurationUs(&finalStatus);
523    }
524
525    if (finalStatus == ERROR_END_OF_STREAM) {
526        notifyBufferingUpdate(100);
527        cancelPollBuffering();
528        return;
529    } else if (cachedDurationUs > 0ll && mDurationUs > 0ll) {
530        int percentage = 100.0 * cachedDurationUs / mDurationUs;
531        if (percentage > 100) {
532            percentage = 100;
533        }
534
535        notifyBufferingUpdate(percentage);
536    }
537
538    schedulePollBuffering();
539}
540
541
542void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) {
543    switch (msg->what()) {
544      case kWhatPrepareAsync:
545      {
546          onPrepareAsync();
547          break;
548      }
549      case kWhatFetchSubtitleData:
550      {
551          fetchTextData(kWhatSendSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
552                  mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
553          break;
554      }
555
556      case kWhatFetchTimedTextData:
557      {
558          fetchTextData(kWhatSendTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
559                  mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
560          break;
561      }
562
563      case kWhatSendSubtitleData:
564      {
565          sendTextData(kWhatSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
566                  mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
567          break;
568      }
569
570      case kWhatSendTimedTextData:
571      {
572          sendTextData(kWhatTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
573                  mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
574          break;
575      }
576
577      case kWhatChangeAVSource:
578      {
579          int32_t trackIndex;
580          CHECK(msg->findInt32("trackIndex", &trackIndex));
581          const sp<MediaSource> source = mSources.itemAt(trackIndex);
582
583          Track* track;
584          const char *mime;
585          media_track_type trackType, counterpartType;
586          sp<MetaData> meta = source->getFormat();
587          meta->findCString(kKeyMIMEType, &mime);
588          if (!strncasecmp(mime, "audio/", 6)) {
589              track = &mAudioTrack;
590              trackType = MEDIA_TRACK_TYPE_AUDIO;
591              counterpartType = MEDIA_TRACK_TYPE_VIDEO;;
592          } else {
593              CHECK(!strncasecmp(mime, "video/", 6));
594              track = &mVideoTrack;
595              trackType = MEDIA_TRACK_TYPE_VIDEO;
596              counterpartType = MEDIA_TRACK_TYPE_AUDIO;;
597          }
598
599
600          if (track->mSource != NULL) {
601              track->mSource->stop();
602          }
603          track->mSource = source;
604          track->mSource->start();
605          track->mIndex = trackIndex;
606
607          status_t avail;
608          if (!track->mPackets->hasBufferAvailable(&avail)) {
609              // sync from other source
610              TRESPASS();
611              break;
612          }
613
614          int64_t timeUs, actualTimeUs;
615          const bool formatChange = true;
616          sp<AMessage> latestMeta = track->mPackets->getLatestEnqueuedMeta();
617          CHECK(latestMeta != NULL && latestMeta->findInt64("timeUs", &timeUs));
618          readBuffer(trackType, timeUs, &actualTimeUs, formatChange);
619          readBuffer(counterpartType, -1, NULL, formatChange);
620          ALOGV("timeUs %lld actualTimeUs %lld", timeUs, actualTimeUs);
621
622          break;
623      }
624      case kWhatPollBuffering:
625      {
626          int32_t generation;
627          CHECK(msg->findInt32("generation", &generation));
628          if (generation == mPollBufferingGeneration) {
629              onPollBuffering();
630          }
631          break;
632      }
633
634      case kWhatGetFormat:
635      {
636          onGetFormatMeta(msg);
637          break;
638      }
639
640      case kWhatGetSelectedTrack:
641      {
642          onGetSelectedTrack(msg);
643          break;
644      }
645
646      case kWhatSelectTrack:
647      {
648          onSelectTrack(msg);
649          break;
650      }
651
652      case kWhatSeek:
653      {
654          onSeek(msg);
655          break;
656      }
657
658      case kWhatReadBuffer:
659      {
660          onReadBuffer(msg);
661          break;
662      }
663
664      default:
665          Source::onMessageReceived(msg);
666          break;
667    }
668}
669
670void NuPlayer::GenericSource::fetchTextData(
671        uint32_t sendWhat,
672        media_track_type type,
673        int32_t curGen,
674        sp<AnotherPacketSource> packets,
675        sp<AMessage> msg) {
676    int32_t msgGeneration;
677    CHECK(msg->findInt32("generation", &msgGeneration));
678    if (msgGeneration != curGen) {
679        // stale
680        return;
681    }
682
683    int32_t avail;
684    if (packets->hasBufferAvailable(&avail)) {
685        return;
686    }
687
688    int64_t timeUs;
689    CHECK(msg->findInt64("timeUs", &timeUs));
690
691    int64_t subTimeUs;
692    readBuffer(type, timeUs, &subTimeUs);
693
694    int64_t delayUs = subTimeUs - timeUs;
695    if (msg->what() == kWhatFetchSubtitleData) {
696        const int64_t oneSecUs = 1000000ll;
697        delayUs -= oneSecUs;
698    }
699    sp<AMessage> msg2 = new AMessage(sendWhat, id());
700    msg2->setInt32("generation", msgGeneration);
701    msg2->post(delayUs < 0 ? 0 : delayUs);
702}
703
704void NuPlayer::GenericSource::sendTextData(
705        uint32_t what,
706        media_track_type type,
707        int32_t curGen,
708        sp<AnotherPacketSource> packets,
709        sp<AMessage> msg) {
710    int32_t msgGeneration;
711    CHECK(msg->findInt32("generation", &msgGeneration));
712    if (msgGeneration != curGen) {
713        // stale
714        return;
715    }
716
717    int64_t subTimeUs;
718    if (packets->nextBufferTime(&subTimeUs) != OK) {
719        return;
720    }
721
722    int64_t nextSubTimeUs;
723    readBuffer(type, -1, &nextSubTimeUs);
724
725    sp<ABuffer> buffer;
726    status_t dequeueStatus = packets->dequeueAccessUnit(&buffer);
727    if (dequeueStatus == OK) {
728        sp<AMessage> notify = dupNotify();
729        notify->setInt32("what", what);
730        notify->setBuffer("buffer", buffer);
731        notify->post();
732
733        const int64_t delayUs = nextSubTimeUs - subTimeUs;
734        msg->post(delayUs < 0 ? 0 : delayUs);
735    }
736}
737
738sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
739    sp<AMessage> msg = new AMessage(kWhatGetFormat, id());
740    msg->setInt32("audio", audio);
741
742    sp<AMessage> response;
743    void *format;
744    status_t err = msg->postAndAwaitResponse(&response);
745    if (err == OK && response != NULL) {
746        CHECK(response->findPointer("format", &format));
747        return (MetaData *)format;
748    } else {
749        return NULL;
750    }
751}
752
753void NuPlayer::GenericSource::onGetFormatMeta(sp<AMessage> msg) const {
754    int32_t audio;
755    CHECK(msg->findInt32("audio", &audio));
756
757    sp<AMessage> response = new AMessage;
758    sp<MetaData> format = doGetFormatMeta(audio);
759    response->setPointer("format", format.get());
760
761    uint32_t replyID;
762    CHECK(msg->senderAwaitsResponse(&replyID));
763    response->postReply(replyID);
764}
765
766sp<MetaData> NuPlayer::GenericSource::doGetFormatMeta(bool audio) const {
767    sp<MediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
768
769    if (source == NULL) {
770        return NULL;
771    }
772
773    return source->getFormat();
774}
775
776status_t NuPlayer::GenericSource::dequeueAccessUnit(
777        bool audio, sp<ABuffer> *accessUnit) {
778    Track *track = audio ? &mAudioTrack : &mVideoTrack;
779
780    if (track->mSource == NULL) {
781        return -EWOULDBLOCK;
782    }
783
784    if (mIsWidevine && !audio) {
785        // try to read a buffer as we may not have been able to the last time
786        postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
787    }
788
789    status_t finalResult;
790    if (!track->mPackets->hasBufferAvailable(&finalResult)) {
791        return (finalResult == OK ? -EWOULDBLOCK : finalResult);
792    }
793
794    status_t result = track->mPackets->dequeueAccessUnit(accessUnit);
795
796    if (!track->mPackets->hasBufferAvailable(&finalResult)) {
797        postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
798    }
799
800    if (result != OK) {
801        if (mSubtitleTrack.mSource != NULL) {
802            mSubtitleTrack.mPackets->clear();
803            mFetchSubtitleDataGeneration++;
804        }
805        if (mTimedTextTrack.mSource != NULL) {
806            mTimedTextTrack.mPackets->clear();
807            mFetchTimedTextDataGeneration++;
808        }
809        return result;
810    }
811
812    int64_t timeUs;
813    status_t eosResult; // ignored
814    CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs));
815
816    if (mSubtitleTrack.mSource != NULL
817            && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
818        sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, id());
819        msg->setInt64("timeUs", timeUs);
820        msg->setInt32("generation", mFetchSubtitleDataGeneration);
821        msg->post();
822    }
823
824    if (mTimedTextTrack.mSource != NULL
825            && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
826        sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, id());
827        msg->setInt64("timeUs", timeUs);
828        msg->setInt32("generation", mFetchTimedTextDataGeneration);
829        msg->post();
830    }
831
832    return result;
833}
834
835status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) {
836    *durationUs = mDurationUs;
837    return OK;
838}
839
840size_t NuPlayer::GenericSource::getTrackCount() const {
841    return mSources.size();
842}
843
844sp<AMessage> NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const {
845    size_t trackCount = mSources.size();
846    if (trackIndex >= trackCount) {
847        return NULL;
848    }
849
850    sp<AMessage> format = new AMessage();
851    sp<MetaData> meta = mSources.itemAt(trackIndex)->getFormat();
852
853    const char *mime;
854    CHECK(meta->findCString(kKeyMIMEType, &mime));
855
856    int32_t trackType;
857    if (!strncasecmp(mime, "video/", 6)) {
858        trackType = MEDIA_TRACK_TYPE_VIDEO;
859    } else if (!strncasecmp(mime, "audio/", 6)) {
860        trackType = MEDIA_TRACK_TYPE_AUDIO;
861    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
862        trackType = MEDIA_TRACK_TYPE_TIMEDTEXT;
863    } else {
864        trackType = MEDIA_TRACK_TYPE_UNKNOWN;
865    }
866    format->setInt32("type", trackType);
867
868    const char *lang;
869    if (!meta->findCString(kKeyMediaLanguage, &lang)) {
870        lang = "und";
871    }
872    format->setString("language", lang);
873
874    if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
875        format->setString("mime", mime);
876
877        int32_t isAutoselect = 1, isDefault = 0, isForced = 0;
878        meta->findInt32(kKeyTrackIsAutoselect, &isAutoselect);
879        meta->findInt32(kKeyTrackIsDefault, &isDefault);
880        meta->findInt32(kKeyTrackIsForced, &isForced);
881
882        format->setInt32("auto", !!isAutoselect);
883        format->setInt32("default", !!isDefault);
884        format->setInt32("forced", !!isForced);
885    }
886
887    return format;
888}
889
890ssize_t NuPlayer::GenericSource::getSelectedTrack(media_track_type type) const {
891    sp<AMessage> msg = new AMessage(kWhatGetSelectedTrack, id());
892    msg->setInt32("type", type);
893
894    sp<AMessage> response;
895    int32_t index;
896    status_t err = msg->postAndAwaitResponse(&response);
897    if (err == OK && response != NULL) {
898        CHECK(response->findInt32("index", &index));
899        return index;
900    } else {
901        return -1;
902    }
903}
904
905void NuPlayer::GenericSource::onGetSelectedTrack(sp<AMessage> msg) const {
906    int32_t tmpType;
907    CHECK(msg->findInt32("type", &tmpType));
908    media_track_type type = (media_track_type)tmpType;
909
910    sp<AMessage> response = new AMessage;
911    ssize_t index = doGetSelectedTrack(type);
912    response->setInt32("index", index);
913
914    uint32_t replyID;
915    CHECK(msg->senderAwaitsResponse(&replyID));
916    response->postReply(replyID);
917}
918
919ssize_t NuPlayer::GenericSource::doGetSelectedTrack(media_track_type type) const {
920    const Track *track = NULL;
921    switch (type) {
922    case MEDIA_TRACK_TYPE_VIDEO:
923        track = &mVideoTrack;
924        break;
925    case MEDIA_TRACK_TYPE_AUDIO:
926        track = &mAudioTrack;
927        break;
928    case MEDIA_TRACK_TYPE_TIMEDTEXT:
929        track = &mTimedTextTrack;
930        break;
931    case MEDIA_TRACK_TYPE_SUBTITLE:
932        track = &mSubtitleTrack;
933        break;
934    default:
935        break;
936    }
937
938    if (track != NULL && track->mSource != NULL) {
939        return track->mIndex;
940    }
941
942    return -1;
943}
944
945status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select) {
946    ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex);
947    sp<AMessage> msg = new AMessage(kWhatSelectTrack, id());
948    msg->setInt32("trackIndex", trackIndex);
949    msg->setInt32("select", trackIndex);
950
951    sp<AMessage> response;
952    status_t err = msg->postAndAwaitResponse(&response);
953    if (err == OK && response != NULL) {
954        CHECK(response->findInt32("err", &err));
955    }
956
957    return err;
958}
959
960void NuPlayer::GenericSource::onSelectTrack(sp<AMessage> msg) {
961    int32_t trackIndex, select;
962    CHECK(msg->findInt32("trackIndex", &trackIndex));
963    CHECK(msg->findInt32("select", &select));
964
965    sp<AMessage> response = new AMessage;
966    status_t err = doSelectTrack(trackIndex, select);
967    response->setInt32("err", err);
968
969    uint32_t replyID;
970    CHECK(msg->senderAwaitsResponse(&replyID));
971    response->postReply(replyID);
972}
973
974status_t NuPlayer::GenericSource::doSelectTrack(size_t trackIndex, bool select) {
975    if (trackIndex >= mSources.size()) {
976        return BAD_INDEX;
977    }
978
979    if (!select) {
980        Track* track = NULL;
981        if (mSubtitleTrack.mSource != NULL && trackIndex == mSubtitleTrack.mIndex) {
982            track = &mSubtitleTrack;
983            mFetchSubtitleDataGeneration++;
984        } else if (mTimedTextTrack.mSource != NULL && trackIndex == mTimedTextTrack.mIndex) {
985            track = &mTimedTextTrack;
986            mFetchTimedTextDataGeneration++;
987        }
988        if (track == NULL) {
989            return INVALID_OPERATION;
990        }
991        track->mSource->stop();
992        track->mSource = NULL;
993        track->mPackets->clear();
994        return OK;
995    }
996
997    const sp<MediaSource> source = mSources.itemAt(trackIndex);
998    sp<MetaData> meta = source->getFormat();
999    const char *mime;
1000    CHECK(meta->findCString(kKeyMIMEType, &mime));
1001    if (!strncasecmp(mime, "text/", 5)) {
1002        bool isSubtitle = strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP);
1003        Track *track = isSubtitle ? &mSubtitleTrack : &mTimedTextTrack;
1004        if (track->mSource != NULL && track->mIndex == trackIndex) {
1005            return OK;
1006        }
1007        track->mIndex = trackIndex;
1008        if (track->mSource != NULL) {
1009            track->mSource->stop();
1010        }
1011        track->mSource = mSources.itemAt(trackIndex);
1012        track->mSource->start();
1013        if (track->mPackets == NULL) {
1014            track->mPackets = new AnotherPacketSource(track->mSource->getFormat());
1015        } else {
1016            track->mPackets->clear();
1017            track->mPackets->setFormat(track->mSource->getFormat());
1018
1019        }
1020
1021        if (isSubtitle) {
1022            mFetchSubtitleDataGeneration++;
1023        } else {
1024            mFetchTimedTextDataGeneration++;
1025        }
1026
1027        return OK;
1028    } else if (!strncasecmp(mime, "audio/", 6) || !strncasecmp(mime, "video/", 6)) {
1029        bool audio = !strncasecmp(mime, "audio/", 6);
1030        Track *track = audio ? &mAudioTrack : &mVideoTrack;
1031        if (track->mSource != NULL && track->mIndex == trackIndex) {
1032            return OK;
1033        }
1034
1035        sp<AMessage> msg = new AMessage(kWhatChangeAVSource, id());
1036        msg->setInt32("trackIndex", trackIndex);
1037        msg->post();
1038        return OK;
1039    }
1040
1041    return INVALID_OPERATION;
1042}
1043
1044status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) {
1045    sp<AMessage> msg = new AMessage(kWhatSeek, id());
1046    msg->setInt64("seekTimeUs", seekTimeUs);
1047
1048    sp<AMessage> response;
1049    status_t err = msg->postAndAwaitResponse(&response);
1050    if (err == OK && response != NULL) {
1051        CHECK(response->findInt32("err", &err));
1052    }
1053
1054    return err;
1055}
1056
1057void NuPlayer::GenericSource::onSeek(sp<AMessage> msg) {
1058    int64_t seekTimeUs;
1059    CHECK(msg->findInt64("seekTimeUs", &seekTimeUs));
1060
1061    sp<AMessage> response = new AMessage;
1062    status_t err = doSeek(seekTimeUs);
1063    response->setInt32("err", err);
1064
1065    uint32_t replyID;
1066    CHECK(msg->senderAwaitsResponse(&replyID));
1067    response->postReply(replyID);
1068}
1069
1070status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs) {
1071    if (mVideoTrack.mSource != NULL) {
1072        int64_t actualTimeUs;
1073        readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, &actualTimeUs);
1074
1075        seekTimeUs = actualTimeUs;
1076    }
1077
1078    if (mAudioTrack.mSource != NULL) {
1079        readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs);
1080    }
1081
1082    setDrmPlaybackStatusIfNeeded(Playback::START, seekTimeUs / 1000);
1083    if (!mStarted) {
1084        setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0);
1085    }
1086    return OK;
1087}
1088
1089sp<ABuffer> NuPlayer::GenericSource::mediaBufferToABuffer(
1090        MediaBuffer* mb,
1091        media_track_type trackType,
1092        int64_t *actualTimeUs) {
1093    bool audio = trackType == MEDIA_TRACK_TYPE_AUDIO;
1094    size_t outLength = mb->range_length();
1095
1096    if (audio && mAudioIsVorbis) {
1097        outLength += sizeof(int32_t);
1098    }
1099
1100    sp<ABuffer> ab;
1101    if (mIsWidevine && !audio) {
1102        // data is already provided in the buffer
1103        ab = new ABuffer(NULL, mb->range_length());
1104        ab->meta()->setPointer("mediaBuffer", mb);
1105        mb->add_ref();
1106    } else {
1107        ab = new ABuffer(outLength);
1108        memcpy(ab->data(),
1109               (const uint8_t *)mb->data() + mb->range_offset(),
1110               mb->range_length());
1111    }
1112
1113    if (audio && mAudioIsVorbis) {
1114        int32_t numPageSamples;
1115        if (!mb->meta_data()->findInt32(kKeyValidSamples, &numPageSamples)) {
1116            numPageSamples = -1;
1117        }
1118
1119        uint8_t* abEnd = ab->data() + mb->range_length();
1120        memcpy(abEnd, &numPageSamples, sizeof(numPageSamples));
1121    }
1122
1123    sp<AMessage> meta = ab->meta();
1124
1125    int64_t timeUs;
1126    CHECK(mb->meta_data()->findInt64(kKeyTime, &timeUs));
1127    meta->setInt64("timeUs", timeUs);
1128
1129    if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) {
1130        const char *mime;
1131        CHECK(mTimedTextTrack.mSource != NULL
1132                && mTimedTextTrack.mSource->getFormat()->findCString(kKeyMIMEType, &mime));
1133        meta->setString("mime", mime);
1134    }
1135
1136    int64_t durationUs;
1137    if (mb->meta_data()->findInt64(kKeyDuration, &durationUs)) {
1138        meta->setInt64("durationUs", durationUs);
1139    }
1140
1141    if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
1142        meta->setInt32("trackIndex", mSubtitleTrack.mIndex);
1143    }
1144
1145    if (actualTimeUs) {
1146        *actualTimeUs = timeUs;
1147    }
1148
1149    mb->release();
1150    mb = NULL;
1151
1152    return ab;
1153}
1154
1155void NuPlayer::GenericSource::postReadBuffer(media_track_type trackType) {
1156    Mutex::Autolock _l(mReadBufferLock);
1157
1158    if ((mPendingReadBufferTypes & (1 << trackType)) == 0) {
1159        mPendingReadBufferTypes |= (1 << trackType);
1160        sp<AMessage> msg = new AMessage(kWhatReadBuffer, id());
1161        msg->setInt32("trackType", trackType);
1162        msg->post();
1163    }
1164}
1165
1166void NuPlayer::GenericSource::onReadBuffer(sp<AMessage> msg) {
1167    int32_t tmpType;
1168    CHECK(msg->findInt32("trackType", &tmpType));
1169    media_track_type trackType = (media_track_type)tmpType;
1170    {
1171        // only protect the variable change, as readBuffer may
1172        // take considerable time.  This may result in one extra
1173        // read being processed, but that is benign.
1174        Mutex::Autolock _l(mReadBufferLock);
1175        mPendingReadBufferTypes &= ~(1 << trackType);
1176    }
1177    readBuffer(trackType);
1178}
1179
1180void NuPlayer::GenericSource::readBuffer(
1181        media_track_type trackType, int64_t seekTimeUs, int64_t *actualTimeUs, bool formatChange) {
1182    Track *track;
1183    size_t maxBuffers = 1;
1184    switch (trackType) {
1185        case MEDIA_TRACK_TYPE_VIDEO:
1186            track = &mVideoTrack;
1187            break;
1188        case MEDIA_TRACK_TYPE_AUDIO:
1189            track = &mAudioTrack;
1190            maxBuffers = 64;
1191            break;
1192        case MEDIA_TRACK_TYPE_SUBTITLE:
1193            track = &mSubtitleTrack;
1194            break;
1195        case MEDIA_TRACK_TYPE_TIMEDTEXT:
1196            track = &mTimedTextTrack;
1197            break;
1198        default:
1199            TRESPASS();
1200    }
1201
1202    if (track->mSource == NULL) {
1203        return;
1204    }
1205
1206    if (actualTimeUs) {
1207        *actualTimeUs = seekTimeUs;
1208    }
1209
1210    MediaSource::ReadOptions options;
1211
1212    bool seeking = false;
1213
1214    if (seekTimeUs >= 0) {
1215        options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
1216        seeking = true;
1217    }
1218
1219    if (mIsWidevine && trackType != MEDIA_TRACK_TYPE_AUDIO) {
1220        options.setNonBlocking();
1221    }
1222
1223    for (size_t numBuffers = 0; numBuffers < maxBuffers; ) {
1224        MediaBuffer *mbuf;
1225        status_t err = track->mSource->read(&mbuf, &options);
1226
1227        options.clearSeekTo();
1228
1229        if (err == OK) {
1230            int64_t timeUs;
1231            CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs));
1232            if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
1233                mAudioTimeUs = timeUs;
1234            } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
1235                mVideoTimeUs = timeUs;
1236            }
1237
1238            // formatChange && seeking: track whose source is changed during selection
1239            // formatChange && !seeking: track whose source is not changed during selection
1240            // !formatChange: normal seek
1241            if ((seeking || formatChange)
1242                    && (trackType == MEDIA_TRACK_TYPE_AUDIO
1243                    || trackType == MEDIA_TRACK_TYPE_VIDEO)) {
1244                ATSParser::DiscontinuityType type = formatChange
1245                        ? (seeking
1246                                ? ATSParser::DISCONTINUITY_FORMATCHANGE
1247                                : ATSParser::DISCONTINUITY_NONE)
1248                        : ATSParser::DISCONTINUITY_SEEK;
1249                track->mPackets->queueDiscontinuity( type, NULL, true /* discard */);
1250            }
1251
1252            sp<ABuffer> buffer = mediaBufferToABuffer(mbuf, trackType, actualTimeUs);
1253            track->mPackets->queueAccessUnit(buffer);
1254            ++numBuffers;
1255        } else if (err == WOULD_BLOCK) {
1256            break;
1257        } else if (err == INFO_FORMAT_CHANGED) {
1258#if 0
1259            track->mPackets->queueDiscontinuity(
1260                    ATSParser::DISCONTINUITY_FORMATCHANGE,
1261                    NULL,
1262                    false /* discard */);
1263#endif
1264        } else {
1265            track->mPackets->signalEOS(err);
1266            break;
1267        }
1268    }
1269}
1270
1271}  // namespace android
1272