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