GenericSource.cpp revision 3de157dd8f9cd45bf9b0406268f5830887105ae1
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/stagefright/foundation/ABuffer.h>
25#include <media/stagefright/foundation/ADebug.h>
26#include <media/stagefright/foundation/AMessage.h>
27#include <media/stagefright/DataSource.h>
28#include <media/stagefright/FileSource.h>
29#include <media/stagefright/MediaBuffer.h>
30#include <media/stagefright/MediaDefs.h>
31#include <media/stagefright/MediaExtractor.h>
32#include <media/stagefright/MediaSource.h>
33#include <media/stagefright/MetaData.h>
34#include "../../libstagefright/include/WVMExtractor.h"
35
36namespace android {
37
38NuPlayer::GenericSource::GenericSource(
39        const sp<AMessage> &notify,
40        bool uidValid,
41        uid_t uid)
42    : Source(notify),
43      mFetchSubtitleDataGeneration(0),
44      mFetchTimedTextDataGeneration(0),
45      mDurationUs(0ll),
46      mAudioIsVorbis(false),
47      mIsWidevine(false),
48      mUIDValid(uidValid),
49      mUID(uid) {
50    DataSource::RegisterDefaultSniffers();
51}
52
53status_t NuPlayer::GenericSource::init(
54        const sp<IMediaHTTPService> &httpService,
55        const char *url,
56        const KeyedVector<String8, String8> *headers) {
57    mIsWidevine = !strncasecmp(url, "widevine://", 11);
58
59    AString sniffedMIME;
60
61    sp<DataSource> dataSource =
62        DataSource::CreateFromURI(httpService, url, headers, &sniffedMIME);
63
64    if (dataSource == NULL) {
65        return UNKNOWN_ERROR;
66    }
67
68    return initFromDataSource(
69            dataSource, sniffedMIME.empty() ? NULL : sniffedMIME.c_str());
70}
71
72status_t NuPlayer::GenericSource::init(
73        int fd, int64_t offset, int64_t length) {
74    sp<DataSource> dataSource = new FileSource(dup(fd), offset, length);
75
76    return initFromDataSource(dataSource, NULL);
77}
78
79status_t NuPlayer::GenericSource::initFromDataSource(
80        const sp<DataSource> &dataSource,
81        const char* mime) {
82    sp<MediaExtractor> extractor;
83
84    if (mIsWidevine) {
85        String8 mimeType;
86        float confidence;
87        sp<AMessage> dummy;
88        bool success;
89
90        success = SniffWVM(dataSource, &mimeType, &confidence, &dummy);
91        if (!success
92                || strcasecmp(
93                    mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) {
94            ALOGE("unsupported widevine mime: %s", mimeType.string());
95            return UNKNOWN_ERROR;
96        }
97
98        sp<WVMExtractor> wvmExtractor = new WVMExtractor(dataSource);
99        wvmExtractor->setAdaptiveStreamingMode(true);
100        if (mUIDValid) {
101            wvmExtractor->setUID(mUID);
102        }
103        extractor = wvmExtractor;
104    } else {
105        extractor = MediaExtractor::Create(dataSource, mime);
106    }
107
108    if (extractor == NULL) {
109        return UNKNOWN_ERROR;
110    }
111
112    sp<MetaData> fileMeta = extractor->getMetaData();
113    if (fileMeta != NULL) {
114        int64_t duration;
115        if (fileMeta->findInt64(kKeyDuration, &duration)) {
116            mDurationUs = duration;
117        }
118    }
119
120    for (size_t i = 0; i < extractor->countTracks(); ++i) {
121        sp<MetaData> meta = extractor->getTrackMetaData(i);
122
123        const char *mime;
124        CHECK(meta->findCString(kKeyMIMEType, &mime));
125
126        sp<MediaSource> track = extractor->getTrack(i);
127
128        if (!strncasecmp(mime, "audio/", 6)) {
129            if (mAudioTrack.mSource == NULL) {
130                mAudioTrack.mIndex = i;
131                mAudioTrack.mSource = track;
132
133                if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
134                    mAudioIsVorbis = true;
135                } else {
136                    mAudioIsVorbis = false;
137                }
138            }
139        } else if (!strncasecmp(mime, "video/", 6)) {
140            if (mVideoTrack.mSource == NULL) {
141                mVideoTrack.mIndex = i;
142                mVideoTrack.mSource = track;
143
144                // check if the source requires secure buffers
145                int32_t secure;
146                if (meta->findInt32(kKeyRequiresSecureBuffers, &secure) && secure) {
147                    mIsWidevine = true;
148                    if (mUIDValid) {
149                        extractor->setUID(mUID);
150                    }
151                }
152            }
153        }
154
155        if (track != NULL) {
156            mSources.push(track);
157            int64_t durationUs;
158            if (meta->findInt64(kKeyDuration, &durationUs)) {
159                if (durationUs > mDurationUs) {
160                    mDurationUs = durationUs;
161                }
162            }
163        }
164    }
165
166    return OK;
167}
168
169status_t NuPlayer::GenericSource::setBuffers(bool audio, Vector<MediaBuffer *> &buffers) {
170    if (mIsWidevine && !audio) {
171        return mVideoTrack.mSource->setBuffers(buffers);
172    }
173    return INVALID_OPERATION;
174}
175
176NuPlayer::GenericSource::~GenericSource() {
177}
178
179void NuPlayer::GenericSource::prepareAsync() {
180    if (mVideoTrack.mSource != NULL) {
181        sp<MetaData> meta = mVideoTrack.mSource->getFormat();
182
183        int32_t width, height;
184        CHECK(meta->findInt32(kKeyWidth, &width));
185        CHECK(meta->findInt32(kKeyHeight, &height));
186
187        notifyVideoSizeChanged(width, height);
188    }
189
190    notifyFlagsChanged(
191            (mIsWidevine ? FLAG_SECURE : 0)
192            | FLAG_CAN_PAUSE
193            | FLAG_CAN_SEEK_BACKWARD
194            | FLAG_CAN_SEEK_FORWARD
195            | FLAG_CAN_SEEK);
196
197    notifyPrepared();
198}
199
200void NuPlayer::GenericSource::start() {
201    ALOGI("start");
202
203    if (mAudioTrack.mSource != NULL) {
204        CHECK_EQ(mAudioTrack.mSource->start(), (status_t)OK);
205        mAudioTrack.mPackets =
206            new AnotherPacketSource(mAudioTrack.mSource->getFormat());
207
208        readBuffer(MEDIA_TRACK_TYPE_AUDIO);
209    }
210
211    if (mVideoTrack.mSource != NULL) {
212        CHECK_EQ(mVideoTrack.mSource->start(), (status_t)OK);
213        mVideoTrack.mPackets =
214            new AnotherPacketSource(mVideoTrack.mSource->getFormat());
215
216        readBuffer(MEDIA_TRACK_TYPE_VIDEO);
217    }
218}
219
220status_t NuPlayer::GenericSource::feedMoreTSData() {
221    return OK;
222}
223
224void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) {
225    switch (msg->what()) {
226      case kWhatFetchSubtitleData:
227      {
228          fetchTextData(kWhatSendSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
229                  mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
230          break;
231      }
232
233      case kWhatFetchTimedTextData:
234      {
235          fetchTextData(kWhatSendTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
236                  mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
237          break;
238      }
239
240      case kWhatSendSubtitleData:
241      {
242          sendTextData(kWhatSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
243                  mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
244          break;
245      }
246
247      case kWhatSendTimedTextData:
248      {
249          sendTextData(kWhatTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
250                  mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
251          break;
252      }
253
254      case kWhatChangeAVSource:
255      {
256          int32_t trackIndex;
257          CHECK(msg->findInt32("trackIndex", &trackIndex));
258          const sp<MediaSource> source = mSources.itemAt(trackIndex);
259
260          Track* track;
261          const char *mime;
262          media_track_type trackType, counterpartType;
263          sp<MetaData> meta = source->getFormat();
264          meta->findCString(kKeyMIMEType, &mime);
265          if (!strncasecmp(mime, "audio/", 6)) {
266              track = &mAudioTrack;
267              trackType = MEDIA_TRACK_TYPE_AUDIO;
268              counterpartType = MEDIA_TRACK_TYPE_VIDEO;;
269          } else {
270              CHECK(!strncasecmp(mime, "video/", 6));
271              track = &mVideoTrack;
272              trackType = MEDIA_TRACK_TYPE_VIDEO;
273              counterpartType = MEDIA_TRACK_TYPE_AUDIO;;
274          }
275
276
277          if (track->mSource != NULL) {
278              track->mSource->stop();
279          }
280          track->mSource = source;
281          track->mSource->start();
282          track->mIndex = trackIndex;
283
284          status_t avail;
285          if (!track->mPackets->hasBufferAvailable(&avail)) {
286              // sync from other source
287              TRESPASS();
288              break;
289          }
290
291          int64_t timeUs, actualTimeUs;
292          const bool formatChange = true;
293          sp<AMessage> latestMeta = track->mPackets->getLatestMeta();
294          CHECK(latestMeta != NULL && latestMeta->findInt64("timeUs", &timeUs));
295          readBuffer(trackType, timeUs, &actualTimeUs, formatChange);
296          readBuffer(counterpartType, -1, NULL, formatChange);
297          ALOGV("timeUs %lld actualTimeUs %lld", timeUs, actualTimeUs);
298
299          break;
300      }
301
302      default:
303          Source::onMessageReceived(msg);
304          break;
305    }
306}
307
308void NuPlayer::GenericSource::fetchTextData(
309        uint32_t sendWhat,
310        media_track_type type,
311        int32_t curGen,
312        sp<AnotherPacketSource> packets,
313        sp<AMessage> msg) {
314    int32_t msgGeneration;
315    CHECK(msg->findInt32("generation", &msgGeneration));
316    if (msgGeneration != curGen) {
317        // stale
318        return;
319    }
320
321    int32_t avail;
322    if (packets->hasBufferAvailable(&avail)) {
323        return;
324    }
325
326    int64_t timeUs;
327    CHECK(msg->findInt64("timeUs", &timeUs));
328
329    int64_t subTimeUs;
330    readBuffer(type, timeUs, &subTimeUs);
331
332    int64_t delayUs = subTimeUs - timeUs;
333    if (msg->what() == kWhatFetchSubtitleData) {
334        const int64_t oneSecUs = 1000000ll;
335        delayUs -= oneSecUs;
336    }
337    sp<AMessage> msg2 = new AMessage(sendWhat, id());
338    msg2->setInt32("generation", msgGeneration);
339    msg2->post(delayUs < 0 ? 0 : delayUs);
340}
341
342void NuPlayer::GenericSource::sendTextData(
343        uint32_t what,
344        media_track_type type,
345        int32_t curGen,
346        sp<AnotherPacketSource> packets,
347        sp<AMessage> msg) {
348    int32_t msgGeneration;
349    CHECK(msg->findInt32("generation", &msgGeneration));
350    if (msgGeneration != curGen) {
351        // stale
352        return;
353    }
354
355    int64_t subTimeUs;
356    if (packets->nextBufferTime(&subTimeUs) != OK) {
357        return;
358    }
359
360    int64_t nextSubTimeUs;
361    readBuffer(type, -1, &nextSubTimeUs);
362
363    sp<ABuffer> buffer;
364    status_t dequeueStatus = packets->dequeueAccessUnit(&buffer);
365    if (dequeueStatus == OK) {
366        sp<AMessage> notify = dupNotify();
367        notify->setInt32("what", what);
368        notify->setBuffer("buffer", buffer);
369        notify->post();
370
371        const int64_t delayUs = nextSubTimeUs - subTimeUs;
372        msg->post(delayUs < 0 ? 0 : delayUs);
373    }
374}
375
376sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
377    sp<MediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
378
379    if (source == NULL) {
380        return NULL;
381    }
382
383    return source->getFormat();
384}
385
386status_t NuPlayer::GenericSource::dequeueAccessUnit(
387        bool audio, sp<ABuffer> *accessUnit) {
388    Track *track = audio ? &mAudioTrack : &mVideoTrack;
389
390    if (track->mSource == NULL) {
391        return -EWOULDBLOCK;
392    }
393
394    if (mIsWidevine && !audio) {
395        // try to read a buffer as we may not have been able to the last time
396        readBuffer(MEDIA_TRACK_TYPE_VIDEO, -1ll);
397    }
398
399    status_t finalResult;
400    if (!track->mPackets->hasBufferAvailable(&finalResult)) {
401        return (finalResult == OK ? -EWOULDBLOCK : finalResult);
402    }
403
404    status_t result = track->mPackets->dequeueAccessUnit(accessUnit);
405
406    if (!track->mPackets->hasBufferAvailable(&finalResult)) {
407        readBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO, -1ll);
408    }
409
410    if (mSubtitleTrack.mSource == NULL && mTimedTextTrack.mSource == NULL) {
411        return result;
412    }
413
414    if (mSubtitleTrack.mSource != NULL) {
415        CHECK(mSubtitleTrack.mPackets != NULL);
416    }
417    if (mTimedTextTrack.mSource != NULL) {
418        CHECK(mTimedTextTrack.mPackets != NULL);
419    }
420
421    if (result != OK) {
422        if (mSubtitleTrack.mSource != NULL) {
423            mSubtitleTrack.mPackets->clear();
424            mFetchSubtitleDataGeneration++;
425        }
426        if (mTimedTextTrack.mSource != NULL) {
427            mTimedTextTrack.mPackets->clear();
428            mFetchTimedTextDataGeneration++;
429        }
430        return result;
431    }
432
433    int64_t timeUs;
434    status_t eosResult; // ignored
435    CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs));
436
437    if (mSubtitleTrack.mSource != NULL
438            && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
439        sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, id());
440        msg->setInt64("timeUs", timeUs);
441        msg->setInt32("generation", mFetchSubtitleDataGeneration);
442        msg->post();
443    }
444
445    if (mTimedTextTrack.mSource != NULL
446            && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
447        sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, id());
448        msg->setInt64("timeUs", timeUs);
449        msg->setInt32("generation", mFetchTimedTextDataGeneration);
450        msg->post();
451    }
452
453    return result;
454}
455
456status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) {
457    *durationUs = mDurationUs;
458    return OK;
459}
460
461size_t NuPlayer::GenericSource::getTrackCount() const {
462    return mSources.size();
463}
464
465sp<AMessage> NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const {
466    size_t trackCount = mSources.size();
467    if (trackIndex >= trackCount) {
468        return NULL;
469    }
470
471    sp<AMessage> format = new AMessage();
472    sp<MetaData> meta = mSources.itemAt(trackIndex)->getFormat();
473
474    const char *mime;
475    CHECK(meta->findCString(kKeyMIMEType, &mime));
476
477    int32_t trackType;
478    if (!strncasecmp(mime, "video/", 6)) {
479        trackType = MEDIA_TRACK_TYPE_VIDEO;
480    } else if (!strncasecmp(mime, "audio/", 6)) {
481        trackType = MEDIA_TRACK_TYPE_AUDIO;
482    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
483        trackType = MEDIA_TRACK_TYPE_TIMEDTEXT;
484    } else {
485        trackType = MEDIA_TRACK_TYPE_UNKNOWN;
486    }
487    format->setInt32("type", trackType);
488
489    const char *lang;
490    if (!meta->findCString(kKeyMediaLanguage, &lang)) {
491        lang = "und";
492    }
493    format->setString("language", lang);
494
495    if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
496        format->setString("mime", mime);
497
498        int32_t isAutoselect = 1, isDefault = 0, isForced = 0;
499        meta->findInt32(kKeyTrackIsAutoselect, &isAutoselect);
500        meta->findInt32(kKeyTrackIsDefault, &isDefault);
501        meta->findInt32(kKeyTrackIsForced, &isForced);
502
503        format->setInt32("auto", !!isAutoselect);
504        format->setInt32("default", !!isDefault);
505        format->setInt32("forced", !!isForced);
506    }
507
508    return format;
509}
510
511ssize_t NuPlayer::GenericSource::getSelectedTrack(media_track_type type) const {
512    const Track *track = NULL;
513    switch (type) {
514    case MEDIA_TRACK_TYPE_VIDEO:
515        track = &mVideoTrack;
516        break;
517    case MEDIA_TRACK_TYPE_AUDIO:
518        track = &mAudioTrack;
519        break;
520    case MEDIA_TRACK_TYPE_TIMEDTEXT:
521        track = &mTimedTextTrack;
522        break;
523    case MEDIA_TRACK_TYPE_SUBTITLE:
524        track = &mSubtitleTrack;
525        break;
526    default:
527        break;
528    }
529
530    if (track != NULL && track->mSource != NULL) {
531        return track->mIndex;
532    }
533
534    return -1;
535}
536
537status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select) {
538    ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex);
539    if (trackIndex >= mSources.size()) {
540        return BAD_INDEX;
541    }
542
543    if (!select) {
544        Track* track = NULL;
545        if (mSubtitleTrack.mSource != NULL && trackIndex == mSubtitleTrack.mIndex) {
546            track = &mSubtitleTrack;
547            mFetchSubtitleDataGeneration++;
548        } else if (mTimedTextTrack.mSource != NULL && trackIndex == mTimedTextTrack.mIndex) {
549            track = &mTimedTextTrack;
550            mFetchTimedTextDataGeneration++;
551        }
552        if (track == NULL) {
553            return INVALID_OPERATION;
554        }
555        track->mSource->stop();
556        track->mSource = NULL;
557        track->mPackets->clear();
558        return OK;
559    }
560
561    const sp<MediaSource> source = mSources.itemAt(trackIndex);
562    sp<MetaData> meta = source->getFormat();
563    const char *mime;
564    CHECK(meta->findCString(kKeyMIMEType, &mime));
565    if (!strncasecmp(mime, "text/", 5)) {
566        bool isSubtitle = strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP);
567        Track *track = isSubtitle ? &mSubtitleTrack : &mTimedTextTrack;
568        if (track->mSource != NULL && track->mIndex == trackIndex) {
569            return OK;
570        }
571        track->mIndex = trackIndex;
572        if (track->mSource != NULL) {
573            track->mSource->stop();
574        }
575        track->mSource = mSources.itemAt(trackIndex);
576        track->mSource->start();
577        if (track->mPackets == NULL) {
578            track->mPackets = new AnotherPacketSource(track->mSource->getFormat());
579        } else {
580            track->mPackets->clear();
581            track->mPackets->setFormat(track->mSource->getFormat());
582
583        }
584
585        if (isSubtitle) {
586            mFetchSubtitleDataGeneration++;
587        } else {
588            mFetchTimedTextDataGeneration++;
589        }
590
591        return OK;
592    } else if (!strncasecmp(mime, "audio/", 6) || !strncasecmp(mime, "video/", 6)) {
593        bool audio = !strncasecmp(mime, "audio/", 6);
594        Track *track = audio ? &mAudioTrack : &mVideoTrack;
595        if (track->mSource != NULL && track->mIndex == trackIndex) {
596            return OK;
597        }
598
599        sp<AMessage> msg = new AMessage(kWhatChangeAVSource, id());
600        msg->setInt32("trackIndex", trackIndex);
601        msg->post();
602        return OK;
603    }
604
605    return INVALID_OPERATION;
606}
607
608status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) {
609    if (mVideoTrack.mSource != NULL) {
610        int64_t actualTimeUs;
611        readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, &actualTimeUs);
612
613        seekTimeUs = actualTimeUs;
614    }
615
616    if (mAudioTrack.mSource != NULL) {
617        readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs);
618    }
619
620    return OK;
621}
622
623sp<ABuffer> NuPlayer::GenericSource::mediaBufferToABuffer(
624        MediaBuffer* mb,
625        media_track_type trackType,
626        int64_t *actualTimeUs) {
627    bool audio = trackType == MEDIA_TRACK_TYPE_AUDIO;
628    size_t outLength = mb->range_length();
629
630    if (audio && mAudioIsVorbis) {
631        outLength += sizeof(int32_t);
632    }
633
634    sp<ABuffer> ab;
635    if (mIsWidevine && !audio) {
636        // data is already provided in the buffer
637        ab = new ABuffer(NULL, mb->range_length());
638        ab->meta()->setPointer("mediaBuffer", mb);
639        mb->add_ref();
640    } else {
641        ab = new ABuffer(outLength);
642        memcpy(ab->data(),
643               (const uint8_t *)mb->data() + mb->range_offset(),
644               mb->range_length());
645    }
646
647    if (audio && mAudioIsVorbis) {
648        int32_t numPageSamples;
649        if (!mb->meta_data()->findInt32(kKeyValidSamples, &numPageSamples)) {
650            numPageSamples = -1;
651        }
652
653        uint8_t* abEnd = ab->data() + mb->range_length();
654        memcpy(abEnd, &numPageSamples, sizeof(numPageSamples));
655    }
656
657    sp<AMessage> meta = ab->meta();
658
659    int64_t timeUs;
660    CHECK(mb->meta_data()->findInt64(kKeyTime, &timeUs));
661    meta->setInt64("timeUs", timeUs);
662
663    if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) {
664        const char *mime;
665        CHECK(mTimedTextTrack.mSource != NULL
666                && mTimedTextTrack.mSource->getFormat()->findCString(kKeyMIMEType, &mime));
667        meta->setString("mime", mime);
668    }
669
670    int64_t durationUs;
671    if (mb->meta_data()->findInt64(kKeyDuration, &durationUs)) {
672        meta->setInt64("durationUs", durationUs);
673    }
674
675    if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
676        meta->setInt32("trackIndex", mSubtitleTrack.mIndex);
677    }
678
679    if (actualTimeUs) {
680        *actualTimeUs = timeUs;
681    }
682
683    mb->release();
684    mb = NULL;
685
686    return ab;
687}
688
689void NuPlayer::GenericSource::readBuffer(
690        media_track_type trackType, int64_t seekTimeUs, int64_t *actualTimeUs, bool formatChange) {
691    Track *track;
692    switch (trackType) {
693        case MEDIA_TRACK_TYPE_VIDEO:
694            track = &mVideoTrack;
695            break;
696        case MEDIA_TRACK_TYPE_AUDIO:
697            track = &mAudioTrack;
698            break;
699        case MEDIA_TRACK_TYPE_SUBTITLE:
700            track = &mSubtitleTrack;
701            break;
702        case MEDIA_TRACK_TYPE_TIMEDTEXT:
703            track = &mTimedTextTrack;
704            break;
705        default:
706            TRESPASS();
707    }
708
709    if (track->mSource == NULL) {
710        return;
711    }
712
713    if (actualTimeUs) {
714        *actualTimeUs = seekTimeUs;
715    }
716
717    MediaSource::ReadOptions options;
718
719    bool seeking = false;
720
721    if (seekTimeUs >= 0) {
722        options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
723        seeking = true;
724    }
725
726    if (mIsWidevine && trackType != MEDIA_TRACK_TYPE_AUDIO) {
727        options.setNonBlocking();
728    }
729
730    for (;;) {
731        MediaBuffer *mbuf;
732        status_t err = track->mSource->read(&mbuf, &options);
733
734        options.clearSeekTo();
735
736        if (err == OK) {
737            // formatChange && seeking: track whose source is changed during selection
738            // formatChange && !seeking: track whose source is not changed during selection
739            // !formatChange: normal seek
740            if ((seeking || formatChange)
741                    && (trackType == MEDIA_TRACK_TYPE_AUDIO
742                    || trackType == MEDIA_TRACK_TYPE_VIDEO)) {
743                ATSParser::DiscontinuityType type = formatChange
744                        ? (seeking
745                                ? ATSParser::DISCONTINUITY_FORMATCHANGE
746                                : ATSParser::DISCONTINUITY_NONE)
747                        : ATSParser::DISCONTINUITY_SEEK;
748                track->mPackets->queueDiscontinuity( type, NULL, true /* discard */);
749            }
750
751            sp<ABuffer> buffer = mediaBufferToABuffer(mbuf, trackType, actualTimeUs);
752            track->mPackets->queueAccessUnit(buffer);
753            break;
754        } else if (err == WOULD_BLOCK) {
755            break;
756        } else if (err == INFO_FORMAT_CHANGED) {
757#if 0
758            track->mPackets->queueDiscontinuity(
759                    ATSParser::DISCONTINUITY_FORMATCHANGE,
760                    NULL,
761                    false /* discard */);
762#endif
763        } else {
764            track->mPackets->signalEOS(err);
765            break;
766        }
767    }
768}
769
770}  // namespace android
771