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