GenericSource.cpp revision d354d8d1b09503c0166c1f3e626cda72a3eeb83c
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 "../../libstagefright/include/NuCachedSource2.h"
36#include "../../libstagefright/include/WVMExtractor.h"
37
38namespace android {
39
40NuPlayer::GenericSource::GenericSource(
41        const sp<AMessage> &notify,
42        bool uidValid,
43        uid_t uid)
44    : Source(notify),
45      mFetchSubtitleDataGeneration(0),
46      mFetchTimedTextDataGeneration(0),
47      mDurationUs(0ll),
48      mAudioIsVorbis(false),
49      mIsWidevine(false),
50      mUIDValid(uidValid),
51      mUID(uid),
52      mMetaDataSize(-1ll) {
53    resetDataSource();
54    DataSource::RegisterDefaultSniffers();
55}
56
57void NuPlayer::GenericSource::resetDataSource() {
58    mHTTPService.clear();
59    mUri.clear();
60    mUriHeaders.clear();
61    mFd = -1;
62    mOffset = 0;
63    mLength = 0;
64}
65
66status_t NuPlayer::GenericSource::setDataSource(
67        const sp<IMediaHTTPService> &httpService,
68        const char *url,
69        const KeyedVector<String8, String8> *headers) {
70    resetDataSource();
71
72    mHTTPService = httpService;
73    mUri = url;
74
75    if (headers) {
76        mUriHeaders = *headers;
77    }
78
79    // delay data source creation to prepareAsync() to avoid blocking
80    // the calling thread in setDataSource for any significant time.
81    return OK;
82}
83
84status_t NuPlayer::GenericSource::setDataSource(
85        int fd, int64_t offset, int64_t length) {
86    resetDataSource();
87
88    mFd = dup(fd);
89    mOffset = offset;
90    mLength = length;
91
92    // delay data source creation to prepareAsync() to avoid blocking
93    // the calling thread in setDataSource for any significant time.
94    return OK;
95}
96
97status_t NuPlayer::GenericSource::initFromDataSource() {
98    sp<MediaExtractor> extractor;
99
100    CHECK(mDataSource != NULL);
101
102    if (mIsWidevine) {
103        String8 mimeType;
104        float confidence;
105        sp<AMessage> dummy;
106        bool success;
107
108        success = SniffWVM(mDataSource, &mimeType, &confidence, &dummy);
109        if (!success
110                || strcasecmp(
111                    mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) {
112            ALOGE("unsupported widevine mime: %s", mimeType.string());
113            return UNKNOWN_ERROR;
114        }
115
116        sp<WVMExtractor> wvmExtractor = new WVMExtractor(mDataSource);
117        wvmExtractor->setAdaptiveStreamingMode(true);
118        if (mUIDValid) {
119            wvmExtractor->setUID(mUID);
120        }
121        extractor = wvmExtractor;
122    } else {
123        extractor = MediaExtractor::Create(mDataSource,
124                mSniffedMIME.empty() ? NULL: mSniffedMIME.c_str());
125    }
126
127    if (extractor == NULL) {
128        return UNKNOWN_ERROR;
129    }
130
131    sp<MetaData> fileMeta = extractor->getMetaData();
132    if (fileMeta != NULL) {
133        int64_t duration;
134        if (fileMeta->findInt64(kKeyDuration, &duration)) {
135            mDurationUs = duration;
136        }
137    }
138
139    for (size_t i = 0; i < extractor->countTracks(); ++i) {
140        sp<MetaData> meta = extractor->getTrackMetaData(i);
141
142        const char *mime;
143        CHECK(meta->findCString(kKeyMIMEType, &mime));
144
145        sp<MediaSource> track = extractor->getTrack(i);
146
147        if (!strncasecmp(mime, "audio/", 6)) {
148            if (mAudioTrack.mSource == NULL) {
149                mAudioTrack.mIndex = i;
150                mAudioTrack.mSource = track;
151
152                if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
153                    mAudioIsVorbis = true;
154                } else {
155                    mAudioIsVorbis = false;
156                }
157            }
158        } else if (!strncasecmp(mime, "video/", 6)) {
159            if (mVideoTrack.mSource == NULL) {
160                mVideoTrack.mIndex = i;
161                mVideoTrack.mSource = track;
162
163                // check if the source requires secure buffers
164                int32_t secure;
165                if (meta->findInt32(kKeyRequiresSecureBuffers, &secure)
166                        && secure) {
167                    mIsWidevine = true;
168                    if (mUIDValid) {
169                        extractor->setUID(mUID);
170                    }
171                }
172            }
173        }
174
175        if (track != NULL) {
176            mSources.push(track);
177            int64_t durationUs;
178            if (meta->findInt64(kKeyDuration, &durationUs)) {
179                if (durationUs > mDurationUs) {
180                    mDurationUs = durationUs;
181                }
182            }
183        }
184    }
185
186    return OK;
187}
188
189status_t NuPlayer::GenericSource::setBuffers(
190        bool audio, Vector<MediaBuffer *> &buffers) {
191    if (mIsWidevine && !audio) {
192        return mVideoTrack.mSource->setBuffers(buffers);
193    }
194    return INVALID_OPERATION;
195}
196
197NuPlayer::GenericSource::~GenericSource() {
198    if (mLooper != NULL) {
199        mLooper->unregisterHandler(id());
200        mLooper->stop();
201    }
202}
203
204void NuPlayer::GenericSource::prepareAsync() {
205    if (mLooper == NULL) {
206        mLooper = new ALooper;
207        mLooper->setName("generic");
208        mLooper->start();
209
210        mLooper->registerHandler(this);
211    }
212
213    sp<AMessage> msg = new AMessage(kWhatPrepareAsync, id());
214    msg->post();
215}
216
217void NuPlayer::GenericSource::onPrepareAsync() {
218    // delayed data source creation
219    if (mDataSource == NULL) {
220        if (!mUri.empty()) {
221            mIsWidevine = !strncasecmp(mUri.c_str(), "widevine://", 11);
222
223            mDataSource = DataSource::CreateFromURI(
224                   mHTTPService, mUri.c_str(), &mUriHeaders, &mContentType);
225        } else {
226            // set to false first, if the extractor
227            // comes back as secure, set it to true then.
228            mIsWidevine = false;
229
230            mDataSource = new FileSource(mFd, mOffset, mLength);
231        }
232
233        if (mDataSource == NULL) {
234            ALOGE("Failed to create data source!");
235            notifyPreparedAndCleanup(UNKNOWN_ERROR);
236            return;
237        }
238
239        if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
240            mCachedSource = static_cast<NuCachedSource2 *>(mDataSource.get());
241        }
242    }
243
244    // check initial caching status
245    status_t err = prefillCacheIfNecessary();
246    if (err != OK) {
247        if (err == -EAGAIN) {
248            (new AMessage(kWhatPrepareAsync, id()))->post(200000);
249        } else {
250            ALOGE("Failed to prefill data cache!");
251            notifyPreparedAndCleanup(UNKNOWN_ERROR);
252        }
253        return;
254    }
255
256    // init extrator from data source
257    err = initFromDataSource();
258
259    if (err != OK) {
260        ALOGE("Failed to init from data source!");
261        notifyPreparedAndCleanup(err);
262        return;
263    }
264
265    if (mVideoTrack.mSource != NULL) {
266        notifyVideoSizeChanged(getFormat(false /* audio */));
267    }
268
269    notifyFlagsChanged(
270            (mIsWidevine ? FLAG_SECURE : 0)
271            | FLAG_CAN_PAUSE
272            | FLAG_CAN_SEEK_BACKWARD
273            | FLAG_CAN_SEEK_FORWARD
274            | FLAG_CAN_SEEK);
275
276    notifyPrepared();
277}
278
279void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) {
280    if (err != OK) {
281        mMetaDataSize = -1ll;
282        mContentType = "";
283        mSniffedMIME = "";
284        mDataSource.clear();
285        mCachedSource.clear();
286    }
287    notifyPrepared(err);
288}
289
290status_t NuPlayer::GenericSource::prefillCacheIfNecessary() {
291    CHECK(mDataSource != NULL);
292
293    if (mCachedSource == NULL) {
294        // no prefill if the data source is not cached
295        return OK;
296    }
297
298    // We're not doing this for streams that appear to be audio-only
299    // streams to ensure that even low bandwidth streams start
300    // playing back fairly instantly.
301    if (!strncasecmp(mContentType.string(), "audio/", 6)) {
302        return OK;
303    }
304
305    // We're going to prefill the cache before trying to instantiate
306    // the extractor below, as the latter is an operation that otherwise
307    // could block on the datasource for a significant amount of time.
308    // During that time we'd be unable to abort the preparation phase
309    // without this prefill.
310
311    // Initially make sure we have at least 192 KB for the sniff
312    // to complete without blocking.
313    static const size_t kMinBytesForSniffing = 192 * 1024;
314    static const size_t kDefaultMetaSize = 200000;
315
316    status_t finalStatus;
317
318    size_t cachedDataRemaining =
319            mCachedSource->approxDataRemaining(&finalStatus);
320
321    if (finalStatus != OK || (mMetaDataSize >= 0
322            && (off64_t)cachedDataRemaining >= mMetaDataSize)) {
323        ALOGV("stop caching, status %d, "
324                "metaDataSize %lld, cachedDataRemaining %zu",
325                finalStatus, mMetaDataSize, cachedDataRemaining);
326        return OK;
327    }
328
329    ALOGV("now cached %zu bytes of data", cachedDataRemaining);
330
331    if (mMetaDataSize < 0
332            && cachedDataRemaining >= kMinBytesForSniffing) {
333        String8 tmp;
334        float confidence;
335        sp<AMessage> meta;
336        if (!mCachedSource->sniff(&tmp, &confidence, &meta)) {
337            return UNKNOWN_ERROR;
338        }
339
340        // We successfully identified the file's extractor to
341        // be, remember this mime type so we don't have to
342        // sniff it again when we call MediaExtractor::Create()
343        mSniffedMIME = tmp.string();
344
345        if (meta == NULL
346                || !meta->findInt64("meta-data-size",
347                        reinterpret_cast<int64_t*>(&mMetaDataSize))) {
348            mMetaDataSize = kDefaultMetaSize;
349        }
350
351        if (mMetaDataSize < 0ll) {
352            ALOGE("invalid metaDataSize = %lld bytes", mMetaDataSize);
353            return UNKNOWN_ERROR;
354        }
355    }
356
357    return -EAGAIN;
358}
359
360void NuPlayer::GenericSource::start() {
361    ALOGI("start");
362
363    if (mAudioTrack.mSource != NULL) {
364        CHECK_EQ(mAudioTrack.mSource->start(), (status_t)OK);
365        mAudioTrack.mPackets =
366            new AnotherPacketSource(mAudioTrack.mSource->getFormat());
367
368        readBuffer(MEDIA_TRACK_TYPE_AUDIO);
369    }
370
371    if (mVideoTrack.mSource != NULL) {
372        CHECK_EQ(mVideoTrack.mSource->start(), (status_t)OK);
373        mVideoTrack.mPackets =
374            new AnotherPacketSource(mVideoTrack.mSource->getFormat());
375
376        readBuffer(MEDIA_TRACK_TYPE_VIDEO);
377    }
378}
379
380status_t NuPlayer::GenericSource::feedMoreTSData() {
381    return OK;
382}
383
384void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) {
385    switch (msg->what()) {
386      case kWhatPrepareAsync:
387      {
388          onPrepareAsync();
389          break;
390      }
391      case kWhatFetchSubtitleData:
392      {
393          fetchTextData(kWhatSendSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
394                  mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
395          break;
396      }
397
398      case kWhatFetchTimedTextData:
399      {
400          fetchTextData(kWhatSendTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
401                  mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
402          break;
403      }
404
405      case kWhatSendSubtitleData:
406      {
407          sendTextData(kWhatSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
408                  mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
409          break;
410      }
411
412      case kWhatSendTimedTextData:
413      {
414          sendTextData(kWhatTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
415                  mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
416          break;
417      }
418
419      case kWhatChangeAVSource:
420      {
421          int32_t trackIndex;
422          CHECK(msg->findInt32("trackIndex", &trackIndex));
423          const sp<MediaSource> source = mSources.itemAt(trackIndex);
424
425          Track* track;
426          const char *mime;
427          media_track_type trackType, counterpartType;
428          sp<MetaData> meta = source->getFormat();
429          meta->findCString(kKeyMIMEType, &mime);
430          if (!strncasecmp(mime, "audio/", 6)) {
431              track = &mAudioTrack;
432              trackType = MEDIA_TRACK_TYPE_AUDIO;
433              counterpartType = MEDIA_TRACK_TYPE_VIDEO;;
434          } else {
435              CHECK(!strncasecmp(mime, "video/", 6));
436              track = &mVideoTrack;
437              trackType = MEDIA_TRACK_TYPE_VIDEO;
438              counterpartType = MEDIA_TRACK_TYPE_AUDIO;;
439          }
440
441
442          if (track->mSource != NULL) {
443              track->mSource->stop();
444          }
445          track->mSource = source;
446          track->mSource->start();
447          track->mIndex = trackIndex;
448
449          status_t avail;
450          if (!track->mPackets->hasBufferAvailable(&avail)) {
451              // sync from other source
452              TRESPASS();
453              break;
454          }
455
456          int64_t timeUs, actualTimeUs;
457          const bool formatChange = true;
458          sp<AMessage> latestMeta = track->mPackets->getLatestEnqueuedMeta();
459          CHECK(latestMeta != NULL && latestMeta->findInt64("timeUs", &timeUs));
460          readBuffer(trackType, timeUs, &actualTimeUs, formatChange);
461          readBuffer(counterpartType, -1, NULL, formatChange);
462          ALOGV("timeUs %lld actualTimeUs %lld", timeUs, actualTimeUs);
463
464          break;
465      }
466
467      default:
468          Source::onMessageReceived(msg);
469          break;
470    }
471}
472
473void NuPlayer::GenericSource::fetchTextData(
474        uint32_t sendWhat,
475        media_track_type type,
476        int32_t curGen,
477        sp<AnotherPacketSource> packets,
478        sp<AMessage> msg) {
479    int32_t msgGeneration;
480    CHECK(msg->findInt32("generation", &msgGeneration));
481    if (msgGeneration != curGen) {
482        // stale
483        return;
484    }
485
486    int32_t avail;
487    if (packets->hasBufferAvailable(&avail)) {
488        return;
489    }
490
491    int64_t timeUs;
492    CHECK(msg->findInt64("timeUs", &timeUs));
493
494    int64_t subTimeUs;
495    readBuffer(type, timeUs, &subTimeUs);
496
497    int64_t delayUs = subTimeUs - timeUs;
498    if (msg->what() == kWhatFetchSubtitleData) {
499        const int64_t oneSecUs = 1000000ll;
500        delayUs -= oneSecUs;
501    }
502    sp<AMessage> msg2 = new AMessage(sendWhat, id());
503    msg2->setInt32("generation", msgGeneration);
504    msg2->post(delayUs < 0 ? 0 : delayUs);
505}
506
507void NuPlayer::GenericSource::sendTextData(
508        uint32_t what,
509        media_track_type type,
510        int32_t curGen,
511        sp<AnotherPacketSource> packets,
512        sp<AMessage> msg) {
513    int32_t msgGeneration;
514    CHECK(msg->findInt32("generation", &msgGeneration));
515    if (msgGeneration != curGen) {
516        // stale
517        return;
518    }
519
520    int64_t subTimeUs;
521    if (packets->nextBufferTime(&subTimeUs) != OK) {
522        return;
523    }
524
525    int64_t nextSubTimeUs;
526    readBuffer(type, -1, &nextSubTimeUs);
527
528    sp<ABuffer> buffer;
529    status_t dequeueStatus = packets->dequeueAccessUnit(&buffer);
530    if (dequeueStatus == OK) {
531        sp<AMessage> notify = dupNotify();
532        notify->setInt32("what", what);
533        notify->setBuffer("buffer", buffer);
534        notify->post();
535
536        const int64_t delayUs = nextSubTimeUs - subTimeUs;
537        msg->post(delayUs < 0 ? 0 : delayUs);
538    }
539}
540
541sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
542    sp<MediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
543
544    if (source == NULL) {
545        return NULL;
546    }
547
548    return source->getFormat();
549}
550
551status_t NuPlayer::GenericSource::dequeueAccessUnit(
552        bool audio, sp<ABuffer> *accessUnit) {
553    Track *track = audio ? &mAudioTrack : &mVideoTrack;
554
555    if (track->mSource == NULL) {
556        return -EWOULDBLOCK;
557    }
558
559    if (mIsWidevine && !audio) {
560        // try to read a buffer as we may not have been able to the last time
561        readBuffer(MEDIA_TRACK_TYPE_VIDEO, -1ll);
562    }
563
564    status_t finalResult;
565    if (!track->mPackets->hasBufferAvailable(&finalResult)) {
566        return (finalResult == OK ? -EWOULDBLOCK : finalResult);
567    }
568
569    status_t result = track->mPackets->dequeueAccessUnit(accessUnit);
570
571    if (!track->mPackets->hasBufferAvailable(&finalResult)) {
572        readBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO, -1ll);
573    }
574
575    if (mSubtitleTrack.mSource == NULL && mTimedTextTrack.mSource == NULL) {
576        return result;
577    }
578
579    if (mSubtitleTrack.mSource != NULL) {
580        CHECK(mSubtitleTrack.mPackets != NULL);
581    }
582    if (mTimedTextTrack.mSource != NULL) {
583        CHECK(mTimedTextTrack.mPackets != NULL);
584    }
585
586    if (result != OK) {
587        if (mSubtitleTrack.mSource != NULL) {
588            mSubtitleTrack.mPackets->clear();
589            mFetchSubtitleDataGeneration++;
590        }
591        if (mTimedTextTrack.mSource != NULL) {
592            mTimedTextTrack.mPackets->clear();
593            mFetchTimedTextDataGeneration++;
594        }
595        return result;
596    }
597
598    int64_t timeUs;
599    status_t eosResult; // ignored
600    CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs));
601
602    if (mSubtitleTrack.mSource != NULL
603            && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
604        sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, id());
605        msg->setInt64("timeUs", timeUs);
606        msg->setInt32("generation", mFetchSubtitleDataGeneration);
607        msg->post();
608    }
609
610    if (mTimedTextTrack.mSource != NULL
611            && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
612        sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, id());
613        msg->setInt64("timeUs", timeUs);
614        msg->setInt32("generation", mFetchTimedTextDataGeneration);
615        msg->post();
616    }
617
618    return result;
619}
620
621status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) {
622    *durationUs = mDurationUs;
623    return OK;
624}
625
626size_t NuPlayer::GenericSource::getTrackCount() const {
627    return mSources.size();
628}
629
630sp<AMessage> NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const {
631    size_t trackCount = mSources.size();
632    if (trackIndex >= trackCount) {
633        return NULL;
634    }
635
636    sp<AMessage> format = new AMessage();
637    sp<MetaData> meta = mSources.itemAt(trackIndex)->getFormat();
638
639    const char *mime;
640    CHECK(meta->findCString(kKeyMIMEType, &mime));
641
642    int32_t trackType;
643    if (!strncasecmp(mime, "video/", 6)) {
644        trackType = MEDIA_TRACK_TYPE_VIDEO;
645    } else if (!strncasecmp(mime, "audio/", 6)) {
646        trackType = MEDIA_TRACK_TYPE_AUDIO;
647    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
648        trackType = MEDIA_TRACK_TYPE_TIMEDTEXT;
649    } else {
650        trackType = MEDIA_TRACK_TYPE_UNKNOWN;
651    }
652    format->setInt32("type", trackType);
653
654    const char *lang;
655    if (!meta->findCString(kKeyMediaLanguage, &lang)) {
656        lang = "und";
657    }
658    format->setString("language", lang);
659
660    if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
661        format->setString("mime", mime);
662
663        int32_t isAutoselect = 1, isDefault = 0, isForced = 0;
664        meta->findInt32(kKeyTrackIsAutoselect, &isAutoselect);
665        meta->findInt32(kKeyTrackIsDefault, &isDefault);
666        meta->findInt32(kKeyTrackIsForced, &isForced);
667
668        format->setInt32("auto", !!isAutoselect);
669        format->setInt32("default", !!isDefault);
670        format->setInt32("forced", !!isForced);
671    }
672
673    return format;
674}
675
676ssize_t NuPlayer::GenericSource::getSelectedTrack(media_track_type type) const {
677    const Track *track = NULL;
678    switch (type) {
679    case MEDIA_TRACK_TYPE_VIDEO:
680        track = &mVideoTrack;
681        break;
682    case MEDIA_TRACK_TYPE_AUDIO:
683        track = &mAudioTrack;
684        break;
685    case MEDIA_TRACK_TYPE_TIMEDTEXT:
686        track = &mTimedTextTrack;
687        break;
688    case MEDIA_TRACK_TYPE_SUBTITLE:
689        track = &mSubtitleTrack;
690        break;
691    default:
692        break;
693    }
694
695    if (track != NULL && track->mSource != NULL) {
696        return track->mIndex;
697    }
698
699    return -1;
700}
701
702status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select) {
703    ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex);
704    if (trackIndex >= mSources.size()) {
705        return BAD_INDEX;
706    }
707
708    if (!select) {
709        Track* track = NULL;
710        if (mSubtitleTrack.mSource != NULL && trackIndex == mSubtitleTrack.mIndex) {
711            track = &mSubtitleTrack;
712            mFetchSubtitleDataGeneration++;
713        } else if (mTimedTextTrack.mSource != NULL && trackIndex == mTimedTextTrack.mIndex) {
714            track = &mTimedTextTrack;
715            mFetchTimedTextDataGeneration++;
716        }
717        if (track == NULL) {
718            return INVALID_OPERATION;
719        }
720        track->mSource->stop();
721        track->mSource = NULL;
722        track->mPackets->clear();
723        return OK;
724    }
725
726    const sp<MediaSource> source = mSources.itemAt(trackIndex);
727    sp<MetaData> meta = source->getFormat();
728    const char *mime;
729    CHECK(meta->findCString(kKeyMIMEType, &mime));
730    if (!strncasecmp(mime, "text/", 5)) {
731        bool isSubtitle = strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP);
732        Track *track = isSubtitle ? &mSubtitleTrack : &mTimedTextTrack;
733        if (track->mSource != NULL && track->mIndex == trackIndex) {
734            return OK;
735        }
736        track->mIndex = trackIndex;
737        if (track->mSource != NULL) {
738            track->mSource->stop();
739        }
740        track->mSource = mSources.itemAt(trackIndex);
741        track->mSource->start();
742        if (track->mPackets == NULL) {
743            track->mPackets = new AnotherPacketSource(track->mSource->getFormat());
744        } else {
745            track->mPackets->clear();
746            track->mPackets->setFormat(track->mSource->getFormat());
747
748        }
749
750        if (isSubtitle) {
751            mFetchSubtitleDataGeneration++;
752        } else {
753            mFetchTimedTextDataGeneration++;
754        }
755
756        return OK;
757    } else if (!strncasecmp(mime, "audio/", 6) || !strncasecmp(mime, "video/", 6)) {
758        bool audio = !strncasecmp(mime, "audio/", 6);
759        Track *track = audio ? &mAudioTrack : &mVideoTrack;
760        if (track->mSource != NULL && track->mIndex == trackIndex) {
761            return OK;
762        }
763
764        sp<AMessage> msg = new AMessage(kWhatChangeAVSource, id());
765        msg->setInt32("trackIndex", trackIndex);
766        msg->post();
767        return OK;
768    }
769
770    return INVALID_OPERATION;
771}
772
773status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) {
774    if (mVideoTrack.mSource != NULL) {
775        int64_t actualTimeUs;
776        readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, &actualTimeUs);
777
778        seekTimeUs = actualTimeUs;
779    }
780
781    if (mAudioTrack.mSource != NULL) {
782        readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs);
783    }
784
785    return OK;
786}
787
788sp<ABuffer> NuPlayer::GenericSource::mediaBufferToABuffer(
789        MediaBuffer* mb,
790        media_track_type trackType,
791        int64_t *actualTimeUs) {
792    bool audio = trackType == MEDIA_TRACK_TYPE_AUDIO;
793    size_t outLength = mb->range_length();
794
795    if (audio && mAudioIsVorbis) {
796        outLength += sizeof(int32_t);
797    }
798
799    sp<ABuffer> ab;
800    if (mIsWidevine && !audio) {
801        // data is already provided in the buffer
802        ab = new ABuffer(NULL, mb->range_length());
803        ab->meta()->setPointer("mediaBuffer", mb);
804        mb->add_ref();
805    } else {
806        ab = new ABuffer(outLength);
807        memcpy(ab->data(),
808               (const uint8_t *)mb->data() + mb->range_offset(),
809               mb->range_length());
810    }
811
812    if (audio && mAudioIsVorbis) {
813        int32_t numPageSamples;
814        if (!mb->meta_data()->findInt32(kKeyValidSamples, &numPageSamples)) {
815            numPageSamples = -1;
816        }
817
818        uint8_t* abEnd = ab->data() + mb->range_length();
819        memcpy(abEnd, &numPageSamples, sizeof(numPageSamples));
820    }
821
822    sp<AMessage> meta = ab->meta();
823
824    int64_t timeUs;
825    CHECK(mb->meta_data()->findInt64(kKeyTime, &timeUs));
826    meta->setInt64("timeUs", timeUs);
827
828    if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) {
829        const char *mime;
830        CHECK(mTimedTextTrack.mSource != NULL
831                && mTimedTextTrack.mSource->getFormat()->findCString(kKeyMIMEType, &mime));
832        meta->setString("mime", mime);
833    }
834
835    int64_t durationUs;
836    if (mb->meta_data()->findInt64(kKeyDuration, &durationUs)) {
837        meta->setInt64("durationUs", durationUs);
838    }
839
840    if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
841        meta->setInt32("trackIndex", mSubtitleTrack.mIndex);
842    }
843
844    if (actualTimeUs) {
845        *actualTimeUs = timeUs;
846    }
847
848    mb->release();
849    mb = NULL;
850
851    return ab;
852}
853
854void NuPlayer::GenericSource::readBuffer(
855        media_track_type trackType, int64_t seekTimeUs, int64_t *actualTimeUs, bool formatChange) {
856    Track *track;
857    switch (trackType) {
858        case MEDIA_TRACK_TYPE_VIDEO:
859            track = &mVideoTrack;
860            break;
861        case MEDIA_TRACK_TYPE_AUDIO:
862            track = &mAudioTrack;
863            break;
864        case MEDIA_TRACK_TYPE_SUBTITLE:
865            track = &mSubtitleTrack;
866            break;
867        case MEDIA_TRACK_TYPE_TIMEDTEXT:
868            track = &mTimedTextTrack;
869            break;
870        default:
871            TRESPASS();
872    }
873
874    if (track->mSource == NULL) {
875        return;
876    }
877
878    if (actualTimeUs) {
879        *actualTimeUs = seekTimeUs;
880    }
881
882    MediaSource::ReadOptions options;
883
884    bool seeking = false;
885
886    if (seekTimeUs >= 0) {
887        options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
888        seeking = true;
889    }
890
891    if (mIsWidevine && trackType != MEDIA_TRACK_TYPE_AUDIO) {
892        options.setNonBlocking();
893    }
894
895    for (;;) {
896        MediaBuffer *mbuf;
897        status_t err = track->mSource->read(&mbuf, &options);
898
899        options.clearSeekTo();
900
901        if (err == OK) {
902            // formatChange && seeking: track whose source is changed during selection
903            // formatChange && !seeking: track whose source is not changed during selection
904            // !formatChange: normal seek
905            if ((seeking || formatChange)
906                    && (trackType == MEDIA_TRACK_TYPE_AUDIO
907                    || trackType == MEDIA_TRACK_TYPE_VIDEO)) {
908                ATSParser::DiscontinuityType type = formatChange
909                        ? (seeking
910                                ? ATSParser::DISCONTINUITY_FORMATCHANGE
911                                : ATSParser::DISCONTINUITY_NONE)
912                        : ATSParser::DISCONTINUITY_SEEK;
913                track->mPackets->queueDiscontinuity( type, NULL, true /* discard */);
914            }
915
916            sp<ABuffer> buffer = mediaBufferToABuffer(mbuf, trackType, actualTimeUs);
917            track->mPackets->queueAccessUnit(buffer);
918            break;
919        } else if (err == WOULD_BLOCK) {
920            break;
921        } else if (err == INFO_FORMAT_CHANGED) {
922#if 0
923            track->mPackets->queueDiscontinuity(
924                    ATSParser::DISCONTINUITY_FORMATCHANGE,
925                    NULL,
926                    false /* discard */);
927#endif
928        } else {
929            track->mPackets->signalEOS(err);
930            break;
931        }
932    }
933}
934
935}  // namespace android
936