GenericSource.cpp revision 1713460104b86f6be3a5d9993d9ace864d889b2d
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 <media/stagefright/Utils.h>
36#include "../../libstagefright/include/DRMExtractor.h"
37#include "../../libstagefright/include/NuCachedSource2.h"
38#include "../../libstagefright/include/WVMExtractor.h"
39#include "../../libstagefright/include/HTTPBase.h"
40
41namespace android {
42
43NuPlayer::GenericSource::GenericSource(
44        const sp<AMessage> &notify,
45        bool uidValid,
46        uid_t uid)
47    : Source(notify),
48      mAudioTimeUs(0),
49      mAudioLastDequeueTimeUs(0),
50      mVideoTimeUs(0),
51      mVideoLastDequeueTimeUs(0),
52      mFetchSubtitleDataGeneration(0),
53      mFetchTimedTextDataGeneration(0),
54      mDurationUs(0ll),
55      mAudioIsVorbis(false),
56      mIsWidevine(false),
57      mIsSecure(false),
58      mUIDValid(uidValid),
59      mUID(uid),
60      mFd(-1),
61      mDrmManagerClient(NULL),
62      mMetaDataSize(-1ll),
63      mBitrate(-1ll),
64      mPollBufferingGeneration(0),
65      mPendingReadBufferTypes(0) {
66    resetDataSource();
67    DataSource::RegisterDefaultSniffers();
68}
69
70void NuPlayer::GenericSource::resetDataSource() {
71    mHTTPService.clear();
72    mHttpSource.clear();
73    mUri.clear();
74    mUriHeaders.clear();
75    if (mFd >= 0) {
76        close(mFd);
77        mFd = -1;
78    }
79    mOffset = 0;
80    mLength = 0;
81    setDrmPlaybackStatusIfNeeded(Playback::STOP, 0);
82    mDecryptHandle = NULL;
83    mDrmManagerClient = NULL;
84    mStarted = false;
85    mStopRead = true;
86}
87
88status_t NuPlayer::GenericSource::setDataSource(
89        const sp<IMediaHTTPService> &httpService,
90        const char *url,
91        const KeyedVector<String8, String8> *headers) {
92    resetDataSource();
93
94    mHTTPService = httpService;
95    mUri = url;
96
97    if (headers) {
98        mUriHeaders = *headers;
99    }
100
101    // delay data source creation to prepareAsync() to avoid blocking
102    // the calling thread in setDataSource for any significant time.
103    return OK;
104}
105
106status_t NuPlayer::GenericSource::setDataSource(
107        int fd, int64_t offset, int64_t length) {
108    resetDataSource();
109
110    mFd = dup(fd);
111    mOffset = offset;
112    mLength = length;
113
114    // delay data source creation to prepareAsync() to avoid blocking
115    // the calling thread in setDataSource for any significant time.
116    return OK;
117}
118
119sp<MetaData> NuPlayer::GenericSource::getFileFormatMeta() const {
120    return mFileMeta;
121}
122
123status_t NuPlayer::GenericSource::initFromDataSource() {
124    sp<MediaExtractor> extractor;
125
126    CHECK(mDataSource != NULL);
127
128    if (mIsWidevine) {
129        String8 mimeType;
130        float confidence;
131        sp<AMessage> dummy;
132        bool success;
133
134        success = SniffWVM(mDataSource, &mimeType, &confidence, &dummy);
135        if (!success
136                || strcasecmp(
137                    mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) {
138            ALOGE("unsupported widevine mime: %s", mimeType.string());
139            return UNKNOWN_ERROR;
140        }
141
142        mWVMExtractor = new WVMExtractor(mDataSource);
143        mWVMExtractor->setAdaptiveStreamingMode(true);
144        if (mUIDValid) {
145            mWVMExtractor->setUID(mUID);
146        }
147        extractor = mWVMExtractor;
148    } else {
149        extractor = MediaExtractor::Create(mDataSource,
150                mSniffedMIME.empty() ? NULL: mSniffedMIME.c_str());
151    }
152
153    if (extractor == NULL) {
154        return UNKNOWN_ERROR;
155    }
156
157    if (extractor->getDrmFlag()) {
158        checkDrmStatus(mDataSource);
159    }
160
161    mFileMeta = extractor->getMetaData();
162    if (mFileMeta != NULL) {
163        int64_t duration;
164        if (mFileMeta->findInt64(kKeyDuration, &duration)) {
165            mDurationUs = duration;
166        }
167
168        if (!mIsWidevine) {
169            // Check mime to see if we actually have a widevine source.
170            // If the data source is not URL-type (eg. file source), we
171            // won't be able to tell until now.
172            const char *fileMime;
173            if (mFileMeta->findCString(kKeyMIMEType, &fileMime)
174                    && !strncasecmp(fileMime, "video/wvm", 9)) {
175                mIsWidevine = true;
176                if (!mUri.empty()) {
177                  // streaming, but the app forgot to specify widevine:// url
178                  mWVMExtractor = static_cast<WVMExtractor *>(extractor.get());
179                  mWVMExtractor->setAdaptiveStreamingMode(true);
180                  if (mUIDValid) {
181                    mWVMExtractor->setUID(mUID);
182                  }
183                }
184            }
185        }
186    }
187
188    int32_t totalBitrate = 0;
189
190    size_t numtracks = extractor->countTracks();
191    if (numtracks == 0) {
192        return UNKNOWN_ERROR;
193    }
194
195    for (size_t i = 0; i < numtracks; ++i) {
196        sp<MediaSource> track = extractor->getTrack(i);
197
198        sp<MetaData> meta = extractor->getTrackMetaData(i);
199
200        const char *mime;
201        CHECK(meta->findCString(kKeyMIMEType, &mime));
202
203        // Do the string compare immediately with "mime",
204        // we can't assume "mime" would stay valid after another
205        // extractor operation, some extractors might modify meta
206        // during getTrack() and make it invalid.
207        if (!strncasecmp(mime, "audio/", 6)) {
208            if (mAudioTrack.mSource == NULL) {
209                mAudioTrack.mIndex = i;
210                mAudioTrack.mSource = track;
211                mAudioTrack.mPackets =
212                    new AnotherPacketSource(mAudioTrack.mSource->getFormat());
213
214                if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
215                    mAudioIsVorbis = true;
216                } else {
217                    mAudioIsVorbis = false;
218                }
219            }
220        } else if (!strncasecmp(mime, "video/", 6)) {
221            if (mVideoTrack.mSource == NULL) {
222                mVideoTrack.mIndex = i;
223                mVideoTrack.mSource = track;
224                mVideoTrack.mPackets =
225                    new AnotherPacketSource(mVideoTrack.mSource->getFormat());
226
227                // check if the source requires secure buffers
228                int32_t secure;
229                if (meta->findInt32(kKeyRequiresSecureBuffers, &secure)
230                        && secure) {
231                    mIsSecure = true;
232                    if (mUIDValid) {
233                        extractor->setUID(mUID);
234                    }
235                }
236            }
237        }
238
239        if (track != NULL) {
240            mSources.push(track);
241            int64_t durationUs;
242            if (meta->findInt64(kKeyDuration, &durationUs)) {
243                if (durationUs > mDurationUs) {
244                    mDurationUs = durationUs;
245                }
246            }
247
248            int32_t bitrate;
249            if (totalBitrate >= 0 && meta->findInt32(kKeyBitRate, &bitrate)) {
250                totalBitrate += bitrate;
251            } else {
252                totalBitrate = -1;
253            }
254        }
255    }
256
257    mBitrate = totalBitrate;
258
259    return OK;
260}
261
262void NuPlayer::GenericSource::checkDrmStatus(const sp<DataSource>& dataSource) {
263    dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
264    if (mDecryptHandle != NULL) {
265        CHECK(mDrmManagerClient);
266        if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
267            sp<AMessage> msg = dupNotify();
268            msg->setInt32("what", kWhatDrmNoLicense);
269            msg->post();
270        }
271    }
272}
273
274int64_t NuPlayer::GenericSource::getLastReadPosition() {
275    if (mAudioTrack.mSource != NULL) {
276        return mAudioTimeUs;
277    } else if (mVideoTrack.mSource != NULL) {
278        return mVideoTimeUs;
279    } else {
280        return 0;
281    }
282}
283
284status_t NuPlayer::GenericSource::setBuffers(
285        bool audio, Vector<MediaBuffer *> &buffers) {
286    if (mIsSecure && !audio) {
287        return mVideoTrack.mSource->setBuffers(buffers);
288    }
289    return INVALID_OPERATION;
290}
291
292NuPlayer::GenericSource::~GenericSource() {
293    if (mLooper != NULL) {
294        mLooper->unregisterHandler(id());
295        mLooper->stop();
296    }
297    resetDataSource();
298}
299
300void NuPlayer::GenericSource::prepareAsync() {
301    if (mLooper == NULL) {
302        mLooper = new ALooper;
303        mLooper->setName("generic");
304        mLooper->start();
305
306        mLooper->registerHandler(this);
307    }
308
309    sp<AMessage> msg = new AMessage(kWhatPrepareAsync, id());
310    msg->post();
311}
312
313void NuPlayer::GenericSource::onPrepareAsync() {
314    // delayed data source creation
315    if (mDataSource == NULL) {
316        // set to false first, if the extractor
317        // comes back as secure, set it to true then.
318        mIsSecure = false;
319
320        if (!mUri.empty()) {
321            const char* uri = mUri.c_str();
322            mIsWidevine = !strncasecmp(uri, "widevine://", 11);
323
324            if (!strncasecmp("http://", uri, 7)
325                    || !strncasecmp("https://", uri, 8)
326                    || mIsWidevine) {
327                mHttpSource = DataSource::CreateMediaHTTP(mHTTPService);
328                if (mHttpSource == NULL) {
329                    ALOGE("Failed to create http source!");
330                    notifyPreparedAndCleanup(UNKNOWN_ERROR);
331                    return;
332                }
333            }
334
335            mDataSource = DataSource::CreateFromURI(
336                   mHTTPService, uri, &mUriHeaders, &mContentType,
337                   static_cast<HTTPBase *>(mHttpSource.get()));
338        } else {
339            mIsWidevine = false;
340
341            mDataSource = new FileSource(mFd, mOffset, mLength);
342            mFd = -1;
343        }
344
345        if (mDataSource == NULL) {
346            ALOGE("Failed to create data source!");
347            notifyPreparedAndCleanup(UNKNOWN_ERROR);
348            return;
349        }
350
351        if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
352            mCachedSource = static_cast<NuCachedSource2 *>(mDataSource.get());
353        }
354
355        if (mIsWidevine || mCachedSource != NULL) {
356            schedulePollBuffering();
357        }
358    }
359
360    // check initial caching status
361    status_t err = prefillCacheIfNecessary();
362    if (err != OK) {
363        if (err == -EAGAIN) {
364            (new AMessage(kWhatPrepareAsync, id()))->post(200000);
365        } else {
366            ALOGE("Failed to prefill data cache!");
367            notifyPreparedAndCleanup(UNKNOWN_ERROR);
368        }
369        return;
370    }
371
372    // init extrator from data source
373    err = initFromDataSource();
374
375    if (err != OK) {
376        ALOGE("Failed to init from data source!");
377        notifyPreparedAndCleanup(err);
378        return;
379    }
380
381    if (mVideoTrack.mSource != NULL) {
382        sp<MetaData> meta = doGetFormatMeta(false /* audio */);
383        sp<AMessage> msg = new AMessage;
384        err = convertMetaDataToMessage(meta, &msg);
385        if(err != OK) {
386            notifyPreparedAndCleanup(err);
387            return;
388        }
389        notifyVideoSizeChanged(msg);
390    }
391
392    notifyFlagsChanged(
393            (mIsSecure ? FLAG_SECURE : 0)
394            | (mDecryptHandle != NULL ? FLAG_PROTECTED : 0)
395            | FLAG_CAN_PAUSE
396            | FLAG_CAN_SEEK_BACKWARD
397            | FLAG_CAN_SEEK_FORWARD
398            | FLAG_CAN_SEEK);
399
400    notifyPrepared();
401}
402
403void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) {
404    if (err != OK) {
405        mMetaDataSize = -1ll;
406        mContentType = "";
407        mSniffedMIME = "";
408        mDataSource.clear();
409        mCachedSource.clear();
410        mHttpSource.clear();
411
412        cancelPollBuffering();
413    }
414    notifyPrepared(err);
415}
416
417status_t NuPlayer::GenericSource::prefillCacheIfNecessary() {
418    CHECK(mDataSource != NULL);
419
420    if (mCachedSource == NULL) {
421        // no prefill if the data source is not cached
422        return OK;
423    }
424
425    // We're not doing this for streams that appear to be audio-only
426    // streams to ensure that even low bandwidth streams start
427    // playing back fairly instantly.
428    if (!strncasecmp(mContentType.string(), "audio/", 6)) {
429        return OK;
430    }
431
432    // We're going to prefill the cache before trying to instantiate
433    // the extractor below, as the latter is an operation that otherwise
434    // could block on the datasource for a significant amount of time.
435    // During that time we'd be unable to abort the preparation phase
436    // without this prefill.
437
438    // Initially make sure we have at least 192 KB for the sniff
439    // to complete without blocking.
440    static const size_t kMinBytesForSniffing = 192 * 1024;
441    static const size_t kDefaultMetaSize = 200000;
442
443    status_t finalStatus;
444
445    size_t cachedDataRemaining =
446            mCachedSource->approxDataRemaining(&finalStatus);
447
448    if (finalStatus != OK || (mMetaDataSize >= 0
449            && (off64_t)cachedDataRemaining >= mMetaDataSize)) {
450        ALOGV("stop caching, status %d, "
451                "metaDataSize %lld, cachedDataRemaining %zu",
452                finalStatus, mMetaDataSize, cachedDataRemaining);
453        return OK;
454    }
455
456    ALOGV("now cached %zu bytes of data", cachedDataRemaining);
457
458    if (mMetaDataSize < 0
459            && cachedDataRemaining >= kMinBytesForSniffing) {
460        String8 tmp;
461        float confidence;
462        sp<AMessage> meta;
463        if (!mCachedSource->sniff(&tmp, &confidence, &meta)) {
464            return UNKNOWN_ERROR;
465        }
466
467        // We successfully identified the file's extractor to
468        // be, remember this mime type so we don't have to
469        // sniff it again when we call MediaExtractor::Create()
470        mSniffedMIME = tmp.string();
471
472        if (meta == NULL
473                || !meta->findInt64("meta-data-size",
474                        reinterpret_cast<int64_t*>(&mMetaDataSize))) {
475            mMetaDataSize = kDefaultMetaSize;
476        }
477
478        if (mMetaDataSize < 0ll) {
479            ALOGE("invalid metaDataSize = %lld bytes", mMetaDataSize);
480            return UNKNOWN_ERROR;
481        }
482    }
483
484    return -EAGAIN;
485}
486
487void NuPlayer::GenericSource::start() {
488    ALOGI("start");
489
490    mStopRead = false;
491    if (mAudioTrack.mSource != NULL) {
492        CHECK_EQ(mAudioTrack.mSource->start(), (status_t)OK);
493
494        postReadBuffer(MEDIA_TRACK_TYPE_AUDIO);
495    }
496
497    if (mVideoTrack.mSource != NULL) {
498        CHECK_EQ(mVideoTrack.mSource->start(), (status_t)OK);
499
500        postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
501    }
502
503    setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000);
504    mStarted = true;
505}
506
507void NuPlayer::GenericSource::stop() {
508    // nothing to do, just account for DRM playback status
509    setDrmPlaybackStatusIfNeeded(Playback::STOP, 0);
510    mStarted = false;
511    if (mIsWidevine || mIsSecure) {
512        // For widevine or secure sources we need to prevent any further reads.
513        sp<AMessage> msg = new AMessage(kWhatStopWidevine, id());
514        sp<AMessage> response;
515        (void) msg->postAndAwaitResponse(&response);
516    }
517}
518
519void NuPlayer::GenericSource::pause() {
520    // nothing to do, just account for DRM playback status
521    setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0);
522    mStarted = false;
523}
524
525void NuPlayer::GenericSource::resume() {
526    // nothing to do, just account for DRM playback status
527    setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000);
528    mStarted = true;
529}
530
531void NuPlayer::GenericSource::disconnect() {
532    if (mDataSource != NULL) {
533        // disconnect data source
534        if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
535            static_cast<NuCachedSource2 *>(mDataSource.get())->disconnect();
536        }
537    } else if (mHttpSource != NULL) {
538        static_cast<HTTPBase *>(mHttpSource.get())->disconnect();
539    }
540}
541
542void NuPlayer::GenericSource::setDrmPlaybackStatusIfNeeded(int playbackStatus, int64_t position) {
543    if (mDecryptHandle != NULL) {
544        mDrmManagerClient->setPlaybackStatus(mDecryptHandle, playbackStatus, position);
545    }
546    mSubtitleTrack.mPackets = new AnotherPacketSource(NULL);
547    mTimedTextTrack.mPackets = new AnotherPacketSource(NULL);
548}
549
550status_t NuPlayer::GenericSource::feedMoreTSData() {
551    return OK;
552}
553
554void NuPlayer::GenericSource::schedulePollBuffering() {
555    sp<AMessage> msg = new AMessage(kWhatPollBuffering, id());
556    msg->setInt32("generation", mPollBufferingGeneration);
557    msg->post(1000000ll);
558}
559
560void NuPlayer::GenericSource::cancelPollBuffering() {
561    ++mPollBufferingGeneration;
562}
563
564void NuPlayer::GenericSource::notifyBufferingUpdate(int percentage) {
565    sp<AMessage> msg = dupNotify();
566    msg->setInt32("what", kWhatBufferingUpdate);
567    msg->setInt32("percentage", percentage);
568    msg->post();
569}
570
571void NuPlayer::GenericSource::onPollBuffering() {
572    status_t finalStatus = UNKNOWN_ERROR;
573    int64_t cachedDurationUs = 0ll;
574
575    if (mCachedSource != NULL) {
576        size_t cachedDataRemaining =
577                mCachedSource->approxDataRemaining(&finalStatus);
578
579        if (finalStatus == OK) {
580            off64_t size;
581            int64_t bitrate = 0ll;
582            if (mDurationUs > 0 && mCachedSource->getSize(&size) == OK) {
583                bitrate = size * 8000000ll / mDurationUs;
584            } else if (mBitrate > 0) {
585                bitrate = mBitrate;
586            }
587            if (bitrate > 0) {
588                cachedDurationUs = cachedDataRemaining * 8000000ll / bitrate;
589            }
590        }
591    } else if (mWVMExtractor != NULL) {
592        cachedDurationUs
593            = mWVMExtractor->getCachedDurationUs(&finalStatus);
594    }
595
596    if (finalStatus == ERROR_END_OF_STREAM) {
597        notifyBufferingUpdate(100);
598        cancelPollBuffering();
599        return;
600    } else if (cachedDurationUs > 0ll && mDurationUs > 0ll) {
601        int percentage = 100.0 * cachedDurationUs / mDurationUs;
602        if (percentage > 100) {
603            percentage = 100;
604        }
605
606        notifyBufferingUpdate(percentage);
607    }
608
609    schedulePollBuffering();
610}
611
612
613void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) {
614    switch (msg->what()) {
615      case kWhatPrepareAsync:
616      {
617          onPrepareAsync();
618          break;
619      }
620      case kWhatFetchSubtitleData:
621      {
622          fetchTextData(kWhatSendSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
623                  mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
624          break;
625      }
626
627      case kWhatFetchTimedTextData:
628      {
629          fetchTextData(kWhatSendTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
630                  mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
631          break;
632      }
633
634      case kWhatSendSubtitleData:
635      {
636          sendTextData(kWhatSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
637                  mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
638          break;
639      }
640
641      case kWhatSendTimedTextData:
642      {
643          sendTextData(kWhatTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
644                  mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
645          break;
646      }
647
648      case kWhatChangeAVSource:
649      {
650          int32_t trackIndex;
651          CHECK(msg->findInt32("trackIndex", &trackIndex));
652          const sp<MediaSource> source = mSources.itemAt(trackIndex);
653
654          Track* track;
655          const char *mime;
656          media_track_type trackType, counterpartType;
657          sp<MetaData> meta = source->getFormat();
658          meta->findCString(kKeyMIMEType, &mime);
659          if (!strncasecmp(mime, "audio/", 6)) {
660              track = &mAudioTrack;
661              trackType = MEDIA_TRACK_TYPE_AUDIO;
662              counterpartType = MEDIA_TRACK_TYPE_VIDEO;;
663          } else {
664              CHECK(!strncasecmp(mime, "video/", 6));
665              track = &mVideoTrack;
666              trackType = MEDIA_TRACK_TYPE_VIDEO;
667              counterpartType = MEDIA_TRACK_TYPE_AUDIO;;
668          }
669
670
671          if (track->mSource != NULL) {
672              track->mSource->stop();
673          }
674          track->mSource = source;
675          track->mSource->start();
676          track->mIndex = trackIndex;
677
678          int64_t timeUs, actualTimeUs;
679          const bool formatChange = true;
680          if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
681              timeUs = mAudioLastDequeueTimeUs;
682          } else {
683              timeUs = mVideoLastDequeueTimeUs;
684          }
685          readBuffer(trackType, timeUs, &actualTimeUs, formatChange);
686          readBuffer(counterpartType, -1, NULL, formatChange);
687          ALOGV("timeUs %lld actualTimeUs %lld", timeUs, actualTimeUs);
688
689          break;
690      }
691      case kWhatPollBuffering:
692      {
693          int32_t generation;
694          CHECK(msg->findInt32("generation", &generation));
695          if (generation == mPollBufferingGeneration) {
696              onPollBuffering();
697          }
698          break;
699      }
700
701      case kWhatGetFormat:
702      {
703          onGetFormatMeta(msg);
704          break;
705      }
706
707      case kWhatGetSelectedTrack:
708      {
709          onGetSelectedTrack(msg);
710          break;
711      }
712
713      case kWhatSelectTrack:
714      {
715          onSelectTrack(msg);
716          break;
717      }
718
719      case kWhatSeek:
720      {
721          onSeek(msg);
722          break;
723      }
724
725      case kWhatReadBuffer:
726      {
727          onReadBuffer(msg);
728          break;
729      }
730
731      case kWhatStopWidevine:
732      {
733          // mStopRead is only used for Widevine to prevent the video source
734          // from being read while the associated video decoder is shutting down.
735          mStopRead = true;
736          if (mVideoTrack.mSource != NULL) {
737              mVideoTrack.mPackets->clear();
738          }
739          sp<AMessage> response = new AMessage;
740          uint32_t replyID;
741          CHECK(msg->senderAwaitsResponse(&replyID));
742          response->postReply(replyID);
743          break;
744      }
745      default:
746          Source::onMessageReceived(msg);
747          break;
748    }
749}
750
751void NuPlayer::GenericSource::fetchTextData(
752        uint32_t sendWhat,
753        media_track_type type,
754        int32_t curGen,
755        sp<AnotherPacketSource> packets,
756        sp<AMessage> msg) {
757    int32_t msgGeneration;
758    CHECK(msg->findInt32("generation", &msgGeneration));
759    if (msgGeneration != curGen) {
760        // stale
761        return;
762    }
763
764    int32_t avail;
765    if (packets->hasBufferAvailable(&avail)) {
766        return;
767    }
768
769    int64_t timeUs;
770    CHECK(msg->findInt64("timeUs", &timeUs));
771
772    int64_t subTimeUs;
773    readBuffer(type, timeUs, &subTimeUs);
774
775    int64_t delayUs = subTimeUs - timeUs;
776    if (msg->what() == kWhatFetchSubtitleData) {
777        const int64_t oneSecUs = 1000000ll;
778        delayUs -= oneSecUs;
779    }
780    sp<AMessage> msg2 = new AMessage(sendWhat, id());
781    msg2->setInt32("generation", msgGeneration);
782    msg2->post(delayUs < 0 ? 0 : delayUs);
783}
784
785void NuPlayer::GenericSource::sendTextData(
786        uint32_t what,
787        media_track_type type,
788        int32_t curGen,
789        sp<AnotherPacketSource> packets,
790        sp<AMessage> msg) {
791    int32_t msgGeneration;
792    CHECK(msg->findInt32("generation", &msgGeneration));
793    if (msgGeneration != curGen) {
794        // stale
795        return;
796    }
797
798    int64_t subTimeUs;
799    if (packets->nextBufferTime(&subTimeUs) != OK) {
800        return;
801    }
802
803    int64_t nextSubTimeUs;
804    readBuffer(type, -1, &nextSubTimeUs);
805
806    sp<ABuffer> buffer;
807    status_t dequeueStatus = packets->dequeueAccessUnit(&buffer);
808    if (dequeueStatus == OK) {
809        sp<AMessage> notify = dupNotify();
810        notify->setInt32("what", what);
811        notify->setBuffer("buffer", buffer);
812        notify->post();
813
814        const int64_t delayUs = nextSubTimeUs - subTimeUs;
815        msg->post(delayUs < 0 ? 0 : delayUs);
816    }
817}
818
819sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
820    sp<AMessage> msg = new AMessage(kWhatGetFormat, id());
821    msg->setInt32("audio", audio);
822
823    sp<AMessage> response;
824    void *format;
825    status_t err = msg->postAndAwaitResponse(&response);
826    if (err == OK && response != NULL) {
827        CHECK(response->findPointer("format", &format));
828        return (MetaData *)format;
829    } else {
830        return NULL;
831    }
832}
833
834void NuPlayer::GenericSource::onGetFormatMeta(sp<AMessage> msg) const {
835    int32_t audio;
836    CHECK(msg->findInt32("audio", &audio));
837
838    sp<AMessage> response = new AMessage;
839    sp<MetaData> format = doGetFormatMeta(audio);
840    response->setPointer("format", format.get());
841
842    uint32_t replyID;
843    CHECK(msg->senderAwaitsResponse(&replyID));
844    response->postReply(replyID);
845}
846
847sp<MetaData> NuPlayer::GenericSource::doGetFormatMeta(bool audio) const {
848    sp<MediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
849
850    if (source == NULL) {
851        return NULL;
852    }
853
854    return source->getFormat();
855}
856
857status_t NuPlayer::GenericSource::dequeueAccessUnit(
858        bool audio, sp<ABuffer> *accessUnit) {
859    Track *track = audio ? &mAudioTrack : &mVideoTrack;
860
861    if (track->mSource == NULL) {
862        return -EWOULDBLOCK;
863    }
864
865    if (mIsWidevine && !audio) {
866        // try to read a buffer as we may not have been able to the last time
867        postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
868    }
869
870    status_t finalResult;
871    if (!track->mPackets->hasBufferAvailable(&finalResult)) {
872        if (finalResult == OK) {
873            postReadBuffer(
874                    audio ? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
875            return -EWOULDBLOCK;
876        }
877        return finalResult;
878    }
879
880    status_t result = track->mPackets->dequeueAccessUnit(accessUnit);
881
882    if (!track->mPackets->hasBufferAvailable(&finalResult)) {
883        postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
884    }
885
886    if (result != OK) {
887        if (mSubtitleTrack.mSource != NULL) {
888            mSubtitleTrack.mPackets->clear();
889            mFetchSubtitleDataGeneration++;
890        }
891        if (mTimedTextTrack.mSource != NULL) {
892            mTimedTextTrack.mPackets->clear();
893            mFetchTimedTextDataGeneration++;
894        }
895        return result;
896    }
897
898    int64_t timeUs;
899    status_t eosResult; // ignored
900    CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs));
901    if (audio) {
902        mAudioLastDequeueTimeUs = timeUs;
903    } else {
904        mVideoLastDequeueTimeUs = timeUs;
905    }
906
907    if (mSubtitleTrack.mSource != NULL
908            && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
909        sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, id());
910        msg->setInt64("timeUs", timeUs);
911        msg->setInt32("generation", mFetchSubtitleDataGeneration);
912        msg->post();
913    }
914
915    if (mTimedTextTrack.mSource != NULL
916            && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
917        sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, id());
918        msg->setInt64("timeUs", timeUs);
919        msg->setInt32("generation", mFetchTimedTextDataGeneration);
920        msg->post();
921    }
922
923    return result;
924}
925
926status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) {
927    *durationUs = mDurationUs;
928    return OK;
929}
930
931size_t NuPlayer::GenericSource::getTrackCount() const {
932    return mSources.size();
933}
934
935sp<AMessage> NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const {
936    size_t trackCount = mSources.size();
937    if (trackIndex >= trackCount) {
938        return NULL;
939    }
940
941    sp<AMessage> format = new AMessage();
942    sp<MetaData> meta = mSources.itemAt(trackIndex)->getFormat();
943
944    const char *mime;
945    CHECK(meta->findCString(kKeyMIMEType, &mime));
946
947    int32_t trackType;
948    if (!strncasecmp(mime, "video/", 6)) {
949        trackType = MEDIA_TRACK_TYPE_VIDEO;
950    } else if (!strncasecmp(mime, "audio/", 6)) {
951        trackType = MEDIA_TRACK_TYPE_AUDIO;
952    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
953        trackType = MEDIA_TRACK_TYPE_TIMEDTEXT;
954    } else {
955        trackType = MEDIA_TRACK_TYPE_UNKNOWN;
956    }
957    format->setInt32("type", trackType);
958
959    const char *lang;
960    if (!meta->findCString(kKeyMediaLanguage, &lang)) {
961        lang = "und";
962    }
963    format->setString("language", lang);
964
965    if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
966        format->setString("mime", mime);
967
968        int32_t isAutoselect = 1, isDefault = 0, isForced = 0;
969        meta->findInt32(kKeyTrackIsAutoselect, &isAutoselect);
970        meta->findInt32(kKeyTrackIsDefault, &isDefault);
971        meta->findInt32(kKeyTrackIsForced, &isForced);
972
973        format->setInt32("auto", !!isAutoselect);
974        format->setInt32("default", !!isDefault);
975        format->setInt32("forced", !!isForced);
976    }
977
978    return format;
979}
980
981ssize_t NuPlayer::GenericSource::getSelectedTrack(media_track_type type) const {
982    sp<AMessage> msg = new AMessage(kWhatGetSelectedTrack, id());
983    msg->setInt32("type", type);
984
985    sp<AMessage> response;
986    int32_t index;
987    status_t err = msg->postAndAwaitResponse(&response);
988    if (err == OK && response != NULL) {
989        CHECK(response->findInt32("index", &index));
990        return index;
991    } else {
992        return -1;
993    }
994}
995
996void NuPlayer::GenericSource::onGetSelectedTrack(sp<AMessage> msg) const {
997    int32_t tmpType;
998    CHECK(msg->findInt32("type", &tmpType));
999    media_track_type type = (media_track_type)tmpType;
1000
1001    sp<AMessage> response = new AMessage;
1002    ssize_t index = doGetSelectedTrack(type);
1003    response->setInt32("index", index);
1004
1005    uint32_t replyID;
1006    CHECK(msg->senderAwaitsResponse(&replyID));
1007    response->postReply(replyID);
1008}
1009
1010ssize_t NuPlayer::GenericSource::doGetSelectedTrack(media_track_type type) const {
1011    const Track *track = NULL;
1012    switch (type) {
1013    case MEDIA_TRACK_TYPE_VIDEO:
1014        track = &mVideoTrack;
1015        break;
1016    case MEDIA_TRACK_TYPE_AUDIO:
1017        track = &mAudioTrack;
1018        break;
1019    case MEDIA_TRACK_TYPE_TIMEDTEXT:
1020        track = &mTimedTextTrack;
1021        break;
1022    case MEDIA_TRACK_TYPE_SUBTITLE:
1023        track = &mSubtitleTrack;
1024        break;
1025    default:
1026        break;
1027    }
1028
1029    if (track != NULL && track->mSource != NULL) {
1030        return track->mIndex;
1031    }
1032
1033    return -1;
1034}
1035
1036status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select, int64_t timeUs) {
1037    ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex);
1038    sp<AMessage> msg = new AMessage(kWhatSelectTrack, id());
1039    msg->setInt32("trackIndex", trackIndex);
1040    msg->setInt32("select", select);
1041    msg->setInt64("timeUs", timeUs);
1042
1043    sp<AMessage> response;
1044    status_t err = msg->postAndAwaitResponse(&response);
1045    if (err == OK && response != NULL) {
1046        CHECK(response->findInt32("err", &err));
1047    }
1048
1049    return err;
1050}
1051
1052void NuPlayer::GenericSource::onSelectTrack(sp<AMessage> msg) {
1053    int32_t trackIndex, select;
1054    int64_t timeUs;
1055    CHECK(msg->findInt32("trackIndex", &trackIndex));
1056    CHECK(msg->findInt32("select", &select));
1057    CHECK(msg->findInt64("timeUs", &timeUs));
1058
1059    sp<AMessage> response = new AMessage;
1060    status_t err = doSelectTrack(trackIndex, select, timeUs);
1061    response->setInt32("err", err);
1062
1063    uint32_t replyID;
1064    CHECK(msg->senderAwaitsResponse(&replyID));
1065    response->postReply(replyID);
1066}
1067
1068status_t NuPlayer::GenericSource::doSelectTrack(size_t trackIndex, bool select, int64_t timeUs) {
1069    if (trackIndex >= mSources.size()) {
1070        return BAD_INDEX;
1071    }
1072
1073    if (!select) {
1074        Track* track = NULL;
1075        if (mSubtitleTrack.mSource != NULL && trackIndex == mSubtitleTrack.mIndex) {
1076            track = &mSubtitleTrack;
1077            mFetchSubtitleDataGeneration++;
1078        } else if (mTimedTextTrack.mSource != NULL && trackIndex == mTimedTextTrack.mIndex) {
1079            track = &mTimedTextTrack;
1080            mFetchTimedTextDataGeneration++;
1081        }
1082        if (track == NULL) {
1083            return INVALID_OPERATION;
1084        }
1085        track->mSource->stop();
1086        track->mSource = NULL;
1087        track->mPackets->clear();
1088        return OK;
1089    }
1090
1091    const sp<MediaSource> source = mSources.itemAt(trackIndex);
1092    sp<MetaData> meta = source->getFormat();
1093    const char *mime;
1094    CHECK(meta->findCString(kKeyMIMEType, &mime));
1095    if (!strncasecmp(mime, "text/", 5)) {
1096        bool isSubtitle = strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP);
1097        Track *track = isSubtitle ? &mSubtitleTrack : &mTimedTextTrack;
1098        if (track->mSource != NULL && track->mIndex == trackIndex) {
1099            return OK;
1100        }
1101        track->mIndex = trackIndex;
1102        if (track->mSource != NULL) {
1103            track->mSource->stop();
1104        }
1105        track->mSource = mSources.itemAt(trackIndex);
1106        track->mSource->start();
1107        if (track->mPackets == NULL) {
1108            track->mPackets = new AnotherPacketSource(track->mSource->getFormat());
1109        } else {
1110            track->mPackets->clear();
1111            track->mPackets->setFormat(track->mSource->getFormat());
1112
1113        }
1114
1115        if (isSubtitle) {
1116            mFetchSubtitleDataGeneration++;
1117        } else {
1118            mFetchTimedTextDataGeneration++;
1119        }
1120
1121        status_t eosResult; // ignored
1122        if (mSubtitleTrack.mSource != NULL
1123                && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
1124            sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, id());
1125            msg->setInt64("timeUs", timeUs);
1126            msg->setInt32("generation", mFetchSubtitleDataGeneration);
1127            msg->post();
1128        }
1129
1130        if (mTimedTextTrack.mSource != NULL
1131                && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
1132            sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, id());
1133            msg->setInt64("timeUs", timeUs);
1134            msg->setInt32("generation", mFetchTimedTextDataGeneration);
1135            msg->post();
1136        }
1137
1138        return OK;
1139    } else if (!strncasecmp(mime, "audio/", 6) || !strncasecmp(mime, "video/", 6)) {
1140        bool audio = !strncasecmp(mime, "audio/", 6);
1141        Track *track = audio ? &mAudioTrack : &mVideoTrack;
1142        if (track->mSource != NULL && track->mIndex == trackIndex) {
1143            return OK;
1144        }
1145
1146        sp<AMessage> msg = new AMessage(kWhatChangeAVSource, id());
1147        msg->setInt32("trackIndex", trackIndex);
1148        msg->post();
1149        return OK;
1150    }
1151
1152    return INVALID_OPERATION;
1153}
1154
1155status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) {
1156    sp<AMessage> msg = new AMessage(kWhatSeek, id());
1157    msg->setInt64("seekTimeUs", seekTimeUs);
1158
1159    sp<AMessage> response;
1160    status_t err = msg->postAndAwaitResponse(&response);
1161    if (err == OK && response != NULL) {
1162        CHECK(response->findInt32("err", &err));
1163    }
1164
1165    return err;
1166}
1167
1168void NuPlayer::GenericSource::onSeek(sp<AMessage> msg) {
1169    int64_t seekTimeUs;
1170    CHECK(msg->findInt64("seekTimeUs", &seekTimeUs));
1171
1172    sp<AMessage> response = new AMessage;
1173    status_t err = doSeek(seekTimeUs);
1174    response->setInt32("err", err);
1175
1176    uint32_t replyID;
1177    CHECK(msg->senderAwaitsResponse(&replyID));
1178    response->postReply(replyID);
1179}
1180
1181status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs) {
1182    // If the Widevine source is stopped, do not attempt to read any
1183    // more buffers.
1184    if (mStopRead) {
1185        return INVALID_OPERATION;
1186    }
1187    if (mVideoTrack.mSource != NULL) {
1188        int64_t actualTimeUs;
1189        readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, &actualTimeUs);
1190
1191        seekTimeUs = actualTimeUs;
1192        mVideoLastDequeueTimeUs = seekTimeUs;
1193    }
1194
1195    if (mAudioTrack.mSource != NULL) {
1196        readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs);
1197        mAudioLastDequeueTimeUs = seekTimeUs;
1198    }
1199
1200    setDrmPlaybackStatusIfNeeded(Playback::START, seekTimeUs / 1000);
1201    if (!mStarted) {
1202        setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0);
1203    }
1204    return OK;
1205}
1206
1207sp<ABuffer> NuPlayer::GenericSource::mediaBufferToABuffer(
1208        MediaBuffer* mb,
1209        media_track_type trackType,
1210        int64_t /* seekTimeUs */,
1211        int64_t *actualTimeUs) {
1212    bool audio = trackType == MEDIA_TRACK_TYPE_AUDIO;
1213    size_t outLength = mb->range_length();
1214
1215    if (audio && mAudioIsVorbis) {
1216        outLength += sizeof(int32_t);
1217    }
1218
1219    sp<ABuffer> ab;
1220    if (mIsSecure && !audio) {
1221        // data is already provided in the buffer
1222        ab = new ABuffer(NULL, mb->range_length());
1223        mb->add_ref();
1224        ab->setMediaBufferBase(mb);
1225    } else {
1226        ab = new ABuffer(outLength);
1227        memcpy(ab->data(),
1228               (const uint8_t *)mb->data() + mb->range_offset(),
1229               mb->range_length());
1230    }
1231
1232    if (audio && mAudioIsVorbis) {
1233        int32_t numPageSamples;
1234        if (!mb->meta_data()->findInt32(kKeyValidSamples, &numPageSamples)) {
1235            numPageSamples = -1;
1236        }
1237
1238        uint8_t* abEnd = ab->data() + mb->range_length();
1239        memcpy(abEnd, &numPageSamples, sizeof(numPageSamples));
1240    }
1241
1242    sp<AMessage> meta = ab->meta();
1243
1244    int64_t timeUs;
1245    CHECK(mb->meta_data()->findInt64(kKeyTime, &timeUs));
1246    meta->setInt64("timeUs", timeUs);
1247
1248#if 0
1249    // Temporarily disable pre-roll till we have a full solution to handle
1250    // both single seek and continous seek gracefully.
1251    if (seekTimeUs > timeUs) {
1252        sp<AMessage> extra = new AMessage;
1253        extra->setInt64("resume-at-mediaTimeUs", seekTimeUs);
1254        meta->setMessage("extra", extra);
1255    }
1256#endif
1257
1258    if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) {
1259        const char *mime;
1260        CHECK(mTimedTextTrack.mSource != NULL
1261                && mTimedTextTrack.mSource->getFormat()->findCString(kKeyMIMEType, &mime));
1262        meta->setString("mime", mime);
1263    }
1264
1265    int64_t durationUs;
1266    if (mb->meta_data()->findInt64(kKeyDuration, &durationUs)) {
1267        meta->setInt64("durationUs", durationUs);
1268    }
1269
1270    if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
1271        meta->setInt32("trackIndex", mSubtitleTrack.mIndex);
1272    }
1273
1274    if (actualTimeUs) {
1275        *actualTimeUs = timeUs;
1276    }
1277
1278    mb->release();
1279    mb = NULL;
1280
1281    return ab;
1282}
1283
1284void NuPlayer::GenericSource::postReadBuffer(media_track_type trackType) {
1285    Mutex::Autolock _l(mReadBufferLock);
1286
1287    if ((mPendingReadBufferTypes & (1 << trackType)) == 0) {
1288        mPendingReadBufferTypes |= (1 << trackType);
1289        sp<AMessage> msg = new AMessage(kWhatReadBuffer, id());
1290        msg->setInt32("trackType", trackType);
1291        msg->post();
1292    }
1293}
1294
1295void NuPlayer::GenericSource::onReadBuffer(sp<AMessage> msg) {
1296    int32_t tmpType;
1297    CHECK(msg->findInt32("trackType", &tmpType));
1298    media_track_type trackType = (media_track_type)tmpType;
1299    readBuffer(trackType);
1300    {
1301        // only protect the variable change, as readBuffer may
1302        // take considerable time.
1303        Mutex::Autolock _l(mReadBufferLock);
1304        mPendingReadBufferTypes &= ~(1 << trackType);
1305    }
1306}
1307
1308void NuPlayer::GenericSource::readBuffer(
1309        media_track_type trackType, int64_t seekTimeUs, int64_t *actualTimeUs, bool formatChange) {
1310    // Do not read data if Widevine source is stopped
1311    if (mStopRead) {
1312        return;
1313    }
1314    Track *track;
1315    size_t maxBuffers = 1;
1316    switch (trackType) {
1317        case MEDIA_TRACK_TYPE_VIDEO:
1318            track = &mVideoTrack;
1319            if (mIsWidevine) {
1320                maxBuffers = 2;
1321            }
1322            break;
1323        case MEDIA_TRACK_TYPE_AUDIO:
1324            track = &mAudioTrack;
1325            if (mIsWidevine) {
1326                maxBuffers = 8;
1327            } else {
1328                maxBuffers = 64;
1329            }
1330            break;
1331        case MEDIA_TRACK_TYPE_SUBTITLE:
1332            track = &mSubtitleTrack;
1333            break;
1334        case MEDIA_TRACK_TYPE_TIMEDTEXT:
1335            track = &mTimedTextTrack;
1336            break;
1337        default:
1338            TRESPASS();
1339    }
1340
1341    if (track->mSource == NULL) {
1342        return;
1343    }
1344
1345    if (actualTimeUs) {
1346        *actualTimeUs = seekTimeUs;
1347    }
1348
1349    MediaSource::ReadOptions options;
1350
1351    bool seeking = false;
1352
1353    if (seekTimeUs >= 0) {
1354        options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
1355        seeking = true;
1356    }
1357
1358    if (mIsWidevine) {
1359        options.setNonBlocking();
1360    }
1361
1362    for (size_t numBuffers = 0; numBuffers < maxBuffers; ) {
1363        MediaBuffer *mbuf;
1364        status_t err = track->mSource->read(&mbuf, &options);
1365
1366        options.clearSeekTo();
1367
1368        if (err == OK) {
1369            int64_t timeUs;
1370            CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs));
1371            if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
1372                mAudioTimeUs = timeUs;
1373            } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
1374                mVideoTimeUs = timeUs;
1375            }
1376
1377            // formatChange && seeking: track whose source is changed during selection
1378            // formatChange && !seeking: track whose source is not changed during selection
1379            // !formatChange: normal seek
1380            if ((seeking || formatChange)
1381                    && (trackType == MEDIA_TRACK_TYPE_AUDIO
1382                    || trackType == MEDIA_TRACK_TYPE_VIDEO)) {
1383                ATSParser::DiscontinuityType type = (formatChange && seeking)
1384                        ? ATSParser::DISCONTINUITY_FORMATCHANGE
1385                        : ATSParser::DISCONTINUITY_NONE;
1386                track->mPackets->queueDiscontinuity( type, NULL, true /* discard */);
1387            }
1388
1389            sp<ABuffer> buffer = mediaBufferToABuffer(
1390                    mbuf, trackType, seekTimeUs, actualTimeUs);
1391            track->mPackets->queueAccessUnit(buffer);
1392            formatChange = false;
1393            seeking = false;
1394            ++numBuffers;
1395        } else if (err == WOULD_BLOCK) {
1396            break;
1397        } else if (err == INFO_FORMAT_CHANGED) {
1398#if 0
1399            track->mPackets->queueDiscontinuity(
1400                    ATSParser::DISCONTINUITY_FORMATCHANGE,
1401                    NULL,
1402                    false /* discard */);
1403#endif
1404        } else {
1405            track->mPackets->signalEOS(err);
1406            break;
1407        }
1408    }
1409}
1410
1411}  // namespace android
1412