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