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