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