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