GenericSource.cpp revision bf9b95d712a24b654761cb9fea0d94d383cfc661
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}
196
197void NuPlayer::GenericSource::prepareAsync() {
198    // delayed data source creation
199    AString sniffedMIME;
200    sp<DataSource> dataSource;
201
202    if (!mUri.empty()) {
203        mIsWidevine = !strncasecmp(mUri.c_str(), "widevine://", 11);
204
205        dataSource = DataSource::CreateFromURI(
206               mHTTPService, mUri.c_str(), &mUriHeaders, &sniffedMIME);
207    } else {
208        // set to false first, if the extractor
209        // comes back as secure, set it to true then.
210        mIsWidevine = false;
211
212        dataSource = new FileSource(mFd, mOffset, mLength);
213    }
214
215    if (dataSource == NULL) {
216        ALOGE("Failed to create data source!");
217        notifyPrepared(UNKNOWN_ERROR);
218        return;
219    }
220
221    status_t err = initFromDataSource(
222            dataSource, sniffedMIME.empty() ? NULL : sniffedMIME.c_str());
223
224    if (err != OK) {
225        ALOGE("Failed to init from data source!");
226        notifyPrepared(err);
227        return;
228    }
229
230    if (mVideoTrack.mSource != NULL) {
231        sp<MetaData> meta = mVideoTrack.mSource->getFormat();
232
233        int32_t width, height;
234        CHECK(meta->findInt32(kKeyWidth, &width));
235        CHECK(meta->findInt32(kKeyHeight, &height));
236
237        notifyVideoSizeChanged(width, height);
238    }
239
240    notifyFlagsChanged(
241            (mIsWidevine ? FLAG_SECURE : 0)
242            | FLAG_CAN_PAUSE
243            | FLAG_CAN_SEEK_BACKWARD
244            | FLAG_CAN_SEEK_FORWARD
245            | FLAG_CAN_SEEK);
246
247    notifyPrepared();
248}
249
250void NuPlayer::GenericSource::start() {
251    ALOGI("start");
252
253    if (mAudioTrack.mSource != NULL) {
254        CHECK_EQ(mAudioTrack.mSource->start(), (status_t)OK);
255        mAudioTrack.mPackets =
256            new AnotherPacketSource(mAudioTrack.mSource->getFormat());
257
258        readBuffer(MEDIA_TRACK_TYPE_AUDIO);
259    }
260
261    if (mVideoTrack.mSource != NULL) {
262        CHECK_EQ(mVideoTrack.mSource->start(), (status_t)OK);
263        mVideoTrack.mPackets =
264            new AnotherPacketSource(mVideoTrack.mSource->getFormat());
265
266        readBuffer(MEDIA_TRACK_TYPE_VIDEO);
267    }
268}
269
270status_t NuPlayer::GenericSource::feedMoreTSData() {
271    return OK;
272}
273
274void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) {
275    switch (msg->what()) {
276      case kWhatFetchSubtitleData:
277      {
278          fetchTextData(kWhatSendSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
279                  mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
280          break;
281      }
282
283      case kWhatFetchTimedTextData:
284      {
285          fetchTextData(kWhatSendTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
286                  mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
287          break;
288      }
289
290      case kWhatSendSubtitleData:
291      {
292          sendTextData(kWhatSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
293                  mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
294          break;
295      }
296
297      case kWhatSendTimedTextData:
298      {
299          sendTextData(kWhatTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
300                  mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
301          break;
302      }
303
304      case kWhatChangeAVSource:
305      {
306          int32_t trackIndex;
307          CHECK(msg->findInt32("trackIndex", &trackIndex));
308          const sp<MediaSource> source = mSources.itemAt(trackIndex);
309
310          Track* track;
311          const char *mime;
312          media_track_type trackType, counterpartType;
313          sp<MetaData> meta = source->getFormat();
314          meta->findCString(kKeyMIMEType, &mime);
315          if (!strncasecmp(mime, "audio/", 6)) {
316              track = &mAudioTrack;
317              trackType = MEDIA_TRACK_TYPE_AUDIO;
318              counterpartType = MEDIA_TRACK_TYPE_VIDEO;;
319          } else {
320              CHECK(!strncasecmp(mime, "video/", 6));
321              track = &mVideoTrack;
322              trackType = MEDIA_TRACK_TYPE_VIDEO;
323              counterpartType = MEDIA_TRACK_TYPE_AUDIO;;
324          }
325
326
327          if (track->mSource != NULL) {
328              track->mSource->stop();
329          }
330          track->mSource = source;
331          track->mSource->start();
332          track->mIndex = trackIndex;
333
334          status_t avail;
335          if (!track->mPackets->hasBufferAvailable(&avail)) {
336              // sync from other source
337              TRESPASS();
338              break;
339          }
340
341          int64_t timeUs, actualTimeUs;
342          const bool formatChange = true;
343          sp<AMessage> latestMeta = track->mPackets->getLatestMeta();
344          CHECK(latestMeta != NULL && latestMeta->findInt64("timeUs", &timeUs));
345          readBuffer(trackType, timeUs, &actualTimeUs, formatChange);
346          readBuffer(counterpartType, -1, NULL, formatChange);
347          ALOGV("timeUs %lld actualTimeUs %lld", timeUs, actualTimeUs);
348
349          break;
350      }
351
352      default:
353          Source::onMessageReceived(msg);
354          break;
355    }
356}
357
358void NuPlayer::GenericSource::fetchTextData(
359        uint32_t sendWhat,
360        media_track_type type,
361        int32_t curGen,
362        sp<AnotherPacketSource> packets,
363        sp<AMessage> msg) {
364    int32_t msgGeneration;
365    CHECK(msg->findInt32("generation", &msgGeneration));
366    if (msgGeneration != curGen) {
367        // stale
368        return;
369    }
370
371    int32_t avail;
372    if (packets->hasBufferAvailable(&avail)) {
373        return;
374    }
375
376    int64_t timeUs;
377    CHECK(msg->findInt64("timeUs", &timeUs));
378
379    int64_t subTimeUs;
380    readBuffer(type, timeUs, &subTimeUs);
381
382    int64_t delayUs = subTimeUs - timeUs;
383    if (msg->what() == kWhatFetchSubtitleData) {
384        const int64_t oneSecUs = 1000000ll;
385        delayUs -= oneSecUs;
386    }
387    sp<AMessage> msg2 = new AMessage(sendWhat, id());
388    msg2->setInt32("generation", msgGeneration);
389    msg2->post(delayUs < 0 ? 0 : delayUs);
390}
391
392void NuPlayer::GenericSource::sendTextData(
393        uint32_t what,
394        media_track_type type,
395        int32_t curGen,
396        sp<AnotherPacketSource> packets,
397        sp<AMessage> msg) {
398    int32_t msgGeneration;
399    CHECK(msg->findInt32("generation", &msgGeneration));
400    if (msgGeneration != curGen) {
401        // stale
402        return;
403    }
404
405    int64_t subTimeUs;
406    if (packets->nextBufferTime(&subTimeUs) != OK) {
407        return;
408    }
409
410    int64_t nextSubTimeUs;
411    readBuffer(type, -1, &nextSubTimeUs);
412
413    sp<ABuffer> buffer;
414    status_t dequeueStatus = packets->dequeueAccessUnit(&buffer);
415    if (dequeueStatus == OK) {
416        sp<AMessage> notify = dupNotify();
417        notify->setInt32("what", what);
418        notify->setBuffer("buffer", buffer);
419        notify->post();
420
421        const int64_t delayUs = nextSubTimeUs - subTimeUs;
422        msg->post(delayUs < 0 ? 0 : delayUs);
423    }
424}
425
426sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
427    sp<MediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
428
429    if (source == NULL) {
430        return NULL;
431    }
432
433    return source->getFormat();
434}
435
436status_t NuPlayer::GenericSource::dequeueAccessUnit(
437        bool audio, sp<ABuffer> *accessUnit) {
438    Track *track = audio ? &mAudioTrack : &mVideoTrack;
439
440    if (track->mSource == NULL) {
441        return -EWOULDBLOCK;
442    }
443
444    if (mIsWidevine && !audio) {
445        // try to read a buffer as we may not have been able to the last time
446        readBuffer(MEDIA_TRACK_TYPE_VIDEO, -1ll);
447    }
448
449    status_t finalResult;
450    if (!track->mPackets->hasBufferAvailable(&finalResult)) {
451        return (finalResult == OK ? -EWOULDBLOCK : finalResult);
452    }
453
454    status_t result = track->mPackets->dequeueAccessUnit(accessUnit);
455
456    if (!track->mPackets->hasBufferAvailable(&finalResult)) {
457        readBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO, -1ll);
458    }
459
460    if (mSubtitleTrack.mSource == NULL && mTimedTextTrack.mSource == NULL) {
461        return result;
462    }
463
464    if (mSubtitleTrack.mSource != NULL) {
465        CHECK(mSubtitleTrack.mPackets != NULL);
466    }
467    if (mTimedTextTrack.mSource != NULL) {
468        CHECK(mTimedTextTrack.mPackets != NULL);
469    }
470
471    if (result != OK) {
472        if (mSubtitleTrack.mSource != NULL) {
473            mSubtitleTrack.mPackets->clear();
474            mFetchSubtitleDataGeneration++;
475        }
476        if (mTimedTextTrack.mSource != NULL) {
477            mTimedTextTrack.mPackets->clear();
478            mFetchTimedTextDataGeneration++;
479        }
480        return result;
481    }
482
483    int64_t timeUs;
484    status_t eosResult; // ignored
485    CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs));
486
487    if (mSubtitleTrack.mSource != NULL
488            && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
489        sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, id());
490        msg->setInt64("timeUs", timeUs);
491        msg->setInt32("generation", mFetchSubtitleDataGeneration);
492        msg->post();
493    }
494
495    if (mTimedTextTrack.mSource != NULL
496            && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
497        sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, id());
498        msg->setInt64("timeUs", timeUs);
499        msg->setInt32("generation", mFetchTimedTextDataGeneration);
500        msg->post();
501    }
502
503    return result;
504}
505
506status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) {
507    *durationUs = mDurationUs;
508    return OK;
509}
510
511size_t NuPlayer::GenericSource::getTrackCount() const {
512    return mSources.size();
513}
514
515sp<AMessage> NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const {
516    size_t trackCount = mSources.size();
517    if (trackIndex >= trackCount) {
518        return NULL;
519    }
520
521    sp<AMessage> format = new AMessage();
522    sp<MetaData> meta = mSources.itemAt(trackIndex)->getFormat();
523
524    const char *mime;
525    CHECK(meta->findCString(kKeyMIMEType, &mime));
526
527    int32_t trackType;
528    if (!strncasecmp(mime, "video/", 6)) {
529        trackType = MEDIA_TRACK_TYPE_VIDEO;
530    } else if (!strncasecmp(mime, "audio/", 6)) {
531        trackType = MEDIA_TRACK_TYPE_AUDIO;
532    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
533        trackType = MEDIA_TRACK_TYPE_TIMEDTEXT;
534    } else {
535        trackType = MEDIA_TRACK_TYPE_UNKNOWN;
536    }
537    format->setInt32("type", trackType);
538
539    const char *lang;
540    if (!meta->findCString(kKeyMediaLanguage, &lang)) {
541        lang = "und";
542    }
543    format->setString("language", lang);
544
545    if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
546        format->setString("mime", mime);
547
548        int32_t isAutoselect = 1, isDefault = 0, isForced = 0;
549        meta->findInt32(kKeyTrackIsAutoselect, &isAutoselect);
550        meta->findInt32(kKeyTrackIsDefault, &isDefault);
551        meta->findInt32(kKeyTrackIsForced, &isForced);
552
553        format->setInt32("auto", !!isAutoselect);
554        format->setInt32("default", !!isDefault);
555        format->setInt32("forced", !!isForced);
556    }
557
558    return format;
559}
560
561ssize_t NuPlayer::GenericSource::getSelectedTrack(media_track_type type) const {
562    const Track *track = NULL;
563    switch (type) {
564    case MEDIA_TRACK_TYPE_VIDEO:
565        track = &mVideoTrack;
566        break;
567    case MEDIA_TRACK_TYPE_AUDIO:
568        track = &mAudioTrack;
569        break;
570    case MEDIA_TRACK_TYPE_TIMEDTEXT:
571        track = &mTimedTextTrack;
572        break;
573    case MEDIA_TRACK_TYPE_SUBTITLE:
574        track = &mSubtitleTrack;
575        break;
576    default:
577        break;
578    }
579
580    if (track != NULL && track->mSource != NULL) {
581        return track->mIndex;
582    }
583
584    return -1;
585}
586
587status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select) {
588    ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex);
589    if (trackIndex >= mSources.size()) {
590        return BAD_INDEX;
591    }
592
593    if (!select) {
594        Track* track = NULL;
595        if (mSubtitleTrack.mSource != NULL && trackIndex == mSubtitleTrack.mIndex) {
596            track = &mSubtitleTrack;
597            mFetchSubtitleDataGeneration++;
598        } else if (mTimedTextTrack.mSource != NULL && trackIndex == mTimedTextTrack.mIndex) {
599            track = &mTimedTextTrack;
600            mFetchTimedTextDataGeneration++;
601        }
602        if (track == NULL) {
603            return INVALID_OPERATION;
604        }
605        track->mSource->stop();
606        track->mSource = NULL;
607        track->mPackets->clear();
608        return OK;
609    }
610
611    const sp<MediaSource> source = mSources.itemAt(trackIndex);
612    sp<MetaData> meta = source->getFormat();
613    const char *mime;
614    CHECK(meta->findCString(kKeyMIMEType, &mime));
615    if (!strncasecmp(mime, "text/", 5)) {
616        bool isSubtitle = strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP);
617        Track *track = isSubtitle ? &mSubtitleTrack : &mTimedTextTrack;
618        if (track->mSource != NULL && track->mIndex == trackIndex) {
619            return OK;
620        }
621        track->mIndex = trackIndex;
622        if (track->mSource != NULL) {
623            track->mSource->stop();
624        }
625        track->mSource = mSources.itemAt(trackIndex);
626        track->mSource->start();
627        if (track->mPackets == NULL) {
628            track->mPackets = new AnotherPacketSource(track->mSource->getFormat());
629        } else {
630            track->mPackets->clear();
631            track->mPackets->setFormat(track->mSource->getFormat());
632
633        }
634
635        if (isSubtitle) {
636            mFetchSubtitleDataGeneration++;
637        } else {
638            mFetchTimedTextDataGeneration++;
639        }
640
641        return OK;
642    } else if (!strncasecmp(mime, "audio/", 6) || !strncasecmp(mime, "video/", 6)) {
643        bool audio = !strncasecmp(mime, "audio/", 6);
644        Track *track = audio ? &mAudioTrack : &mVideoTrack;
645        if (track->mSource != NULL && track->mIndex == trackIndex) {
646            return OK;
647        }
648
649        sp<AMessage> msg = new AMessage(kWhatChangeAVSource, id());
650        msg->setInt32("trackIndex", trackIndex);
651        msg->post();
652        return OK;
653    }
654
655    return INVALID_OPERATION;
656}
657
658status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) {
659    if (mVideoTrack.mSource != NULL) {
660        int64_t actualTimeUs;
661        readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, &actualTimeUs);
662
663        seekTimeUs = actualTimeUs;
664    }
665
666    if (mAudioTrack.mSource != NULL) {
667        readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs);
668    }
669
670    return OK;
671}
672
673sp<ABuffer> NuPlayer::GenericSource::mediaBufferToABuffer(
674        MediaBuffer* mb,
675        media_track_type trackType,
676        int64_t *actualTimeUs) {
677    bool audio = trackType == MEDIA_TRACK_TYPE_AUDIO;
678    size_t outLength = mb->range_length();
679
680    if (audio && mAudioIsVorbis) {
681        outLength += sizeof(int32_t);
682    }
683
684    sp<ABuffer> ab;
685    if (mIsWidevine && !audio) {
686        // data is already provided in the buffer
687        ab = new ABuffer(NULL, mb->range_length());
688        ab->meta()->setPointer("mediaBuffer", mb);
689        mb->add_ref();
690    } else {
691        ab = new ABuffer(outLength);
692        memcpy(ab->data(),
693               (const uint8_t *)mb->data() + mb->range_offset(),
694               mb->range_length());
695    }
696
697    if (audio && mAudioIsVorbis) {
698        int32_t numPageSamples;
699        if (!mb->meta_data()->findInt32(kKeyValidSamples, &numPageSamples)) {
700            numPageSamples = -1;
701        }
702
703        uint8_t* abEnd = ab->data() + mb->range_length();
704        memcpy(abEnd, &numPageSamples, sizeof(numPageSamples));
705    }
706
707    sp<AMessage> meta = ab->meta();
708
709    int64_t timeUs;
710    CHECK(mb->meta_data()->findInt64(kKeyTime, &timeUs));
711    meta->setInt64("timeUs", timeUs);
712
713    if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) {
714        const char *mime;
715        CHECK(mTimedTextTrack.mSource != NULL
716                && mTimedTextTrack.mSource->getFormat()->findCString(kKeyMIMEType, &mime));
717        meta->setString("mime", mime);
718    }
719
720    int64_t durationUs;
721    if (mb->meta_data()->findInt64(kKeyDuration, &durationUs)) {
722        meta->setInt64("durationUs", durationUs);
723    }
724
725    if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
726        meta->setInt32("trackIndex", mSubtitleTrack.mIndex);
727    }
728
729    if (actualTimeUs) {
730        *actualTimeUs = timeUs;
731    }
732
733    mb->release();
734    mb = NULL;
735
736    return ab;
737}
738
739void NuPlayer::GenericSource::readBuffer(
740        media_track_type trackType, int64_t seekTimeUs, int64_t *actualTimeUs, bool formatChange) {
741    Track *track;
742    switch (trackType) {
743        case MEDIA_TRACK_TYPE_VIDEO:
744            track = &mVideoTrack;
745            break;
746        case MEDIA_TRACK_TYPE_AUDIO:
747            track = &mAudioTrack;
748            break;
749        case MEDIA_TRACK_TYPE_SUBTITLE:
750            track = &mSubtitleTrack;
751            break;
752        case MEDIA_TRACK_TYPE_TIMEDTEXT:
753            track = &mTimedTextTrack;
754            break;
755        default:
756            TRESPASS();
757    }
758
759    if (track->mSource == NULL) {
760        return;
761    }
762
763    if (actualTimeUs) {
764        *actualTimeUs = seekTimeUs;
765    }
766
767    MediaSource::ReadOptions options;
768
769    bool seeking = false;
770
771    if (seekTimeUs >= 0) {
772        options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
773        seeking = true;
774    }
775
776    if (mIsWidevine && trackType != MEDIA_TRACK_TYPE_AUDIO) {
777        options.setNonBlocking();
778    }
779
780    for (;;) {
781        MediaBuffer *mbuf;
782        status_t err = track->mSource->read(&mbuf, &options);
783
784        options.clearSeekTo();
785
786        if (err == OK) {
787            // formatChange && seeking: track whose source is changed during selection
788            // formatChange && !seeking: track whose source is not changed during selection
789            // !formatChange: normal seek
790            if ((seeking || formatChange)
791                    && (trackType == MEDIA_TRACK_TYPE_AUDIO
792                    || trackType == MEDIA_TRACK_TYPE_VIDEO)) {
793                ATSParser::DiscontinuityType type = formatChange
794                        ? (seeking
795                                ? ATSParser::DISCONTINUITY_FORMATCHANGE
796                                : ATSParser::DISCONTINUITY_NONE)
797                        : ATSParser::DISCONTINUITY_SEEK;
798                track->mPackets->queueDiscontinuity( type, NULL, true /* discard */);
799            }
800
801            sp<ABuffer> buffer = mediaBufferToABuffer(mbuf, trackType, actualTimeUs);
802            track->mPackets->queueAccessUnit(buffer);
803            break;
804        } else if (err == WOULD_BLOCK) {
805            break;
806        } else if (err == INFO_FORMAT_CHANGED) {
807#if 0
808            track->mPackets->queueDiscontinuity(
809                    ATSParser::DISCONTINUITY_FORMATCHANGE,
810                    NULL,
811                    false /* discard */);
812#endif
813        } else {
814            track->mPackets->signalEOS(err);
815            break;
816        }
817    }
818}
819
820}  // namespace android
821