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