blob: f84decdaa3a8f2045a47550bd16150216cfee07a [file] [log] [blame]
Andreas Huberafed0e12011-09-20 15:39:58 -07001/*
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
Chong Zhang7e892182014-08-05 11:58:21 -070017//#define LOG_NDEBUG 0
18#define LOG_TAG "GenericSource"
19
Andreas Huberafed0e12011-09-20 15:39:58 -070020#include "GenericSource.h"
21
22#include "AnotherPacketSource.h"
23
Chong Zhanga19f33e2014-08-07 15:35:07 -070024#include <media/IMediaHTTPService.h>
Andreas Huberafed0e12011-09-20 15:39:58 -070025#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>
Robert Shih17f6dd62014-08-20 17:00:21 -070035#include <media/stagefright/Utils.h>
Ronghua Wu80276872014-08-28 15:50:29 -070036#include "../../libstagefright/include/DRMExtractor.h"
Chong Zhangd354d8d2014-08-20 13:09:58 -070037#include "../../libstagefright/include/NuCachedSource2.h"
Lajos Molnarcc227032014-07-17 15:33:06 -070038#include "../../libstagefright/include/WVMExtractor.h"
Andreas Huberafed0e12011-09-20 15:39:58 -070039
40namespace android {
41
42NuPlayer::GenericSource::GenericSource(
Andreas Huberb5f25f02013-02-05 10:14:26 -080043 const sp<AMessage> &notify,
Lajos Molnarcc227032014-07-17 15:33:06 -070044 bool uidValid,
45 uid_t uid)
Andreas Huberb5f25f02013-02-05 10:14:26 -080046 : Source(notify),
Robert Shih3423bbd2014-07-16 15:47:09 -070047 mFetchSubtitleDataGeneration(0),
Lajos Molnare26940f2014-07-31 10:31:26 -070048 mFetchTimedTextDataGeneration(0),
Andreas Huberb5f25f02013-02-05 10:14:26 -080049 mDurationUs(0ll),
Lajos Molnarcc227032014-07-17 15:33:06 -070050 mAudioIsVorbis(false),
Chong Zhang3de157d2014-08-05 20:54:44 -070051 mIsWidevine(false),
Lajos Molnarcc227032014-07-17 15:33:06 -070052 mUIDValid(uidValid),
Chong Zhangd354d8d2014-08-20 13:09:58 -070053 mUID(uid),
Ronghua Wu80276872014-08-28 15:50:29 -070054 mDrmManagerClient(NULL),
Chong Zhang2a3cc9a2014-08-21 17:48:26 -070055 mMetaDataSize(-1ll),
56 mBitrate(-1ll),
Lajos Molnar84f52782014-09-11 10:01:55 -070057 mPollBufferingGeneration(0),
58 mPendingReadBufferTypes(0) {
Chong Zhanga19f33e2014-08-07 15:35:07 -070059 resetDataSource();
Andreas Huberafed0e12011-09-20 15:39:58 -070060 DataSource::RegisterDefaultSniffers();
Chong Zhang3de157d2014-08-05 20:54:44 -070061}
62
Chong Zhanga19f33e2014-08-07 15:35:07 -070063void NuPlayer::GenericSource::resetDataSource() {
Ronghua Wu80276872014-08-28 15:50:29 -070064 mAudioTimeUs = 0;
65 mVideoTimeUs = 0;
Chong Zhanga19f33e2014-08-07 15:35:07 -070066 mHTTPService.clear();
67 mUri.clear();
68 mUriHeaders.clear();
69 mFd = -1;
70 mOffset = 0;
71 mLength = 0;
Ronghua Wu80276872014-08-28 15:50:29 -070072 setDrmPlaybackStatusIfNeeded(Playback::STOP, 0);
73 mDecryptHandle = NULL;
74 mDrmManagerClient = NULL;
75 mStarted = false;
Chong Zhanga19f33e2014-08-07 15:35:07 -070076}
77
78status_t NuPlayer::GenericSource::setDataSource(
Chong Zhang3de157d2014-08-05 20:54:44 -070079 const sp<IMediaHTTPService> &httpService,
80 const char *url,
81 const KeyedVector<String8, String8> *headers) {
Chong Zhanga19f33e2014-08-07 15:35:07 -070082 resetDataSource();
Chong Zhang3de157d2014-08-05 20:54:44 -070083
Chong Zhanga19f33e2014-08-07 15:35:07 -070084 mHTTPService = httpService;
85 mUri = url;
Andreas Huberafed0e12011-09-20 15:39:58 -070086
Chong Zhanga19f33e2014-08-07 15:35:07 -070087 if (headers) {
88 mUriHeaders = *headers;
Chong Zhang3de157d2014-08-05 20:54:44 -070089 }
90
Chong Zhanga19f33e2014-08-07 15:35:07 -070091 // delay data source creation to prepareAsync() to avoid blocking
92 // the calling thread in setDataSource for any significant time.
93 return OK;
Andreas Huberafed0e12011-09-20 15:39:58 -070094}
95
Chong Zhanga19f33e2014-08-07 15:35:07 -070096status_t NuPlayer::GenericSource::setDataSource(
Chong Zhang3de157d2014-08-05 20:54:44 -070097 int fd, int64_t offset, int64_t length) {
Chong Zhanga19f33e2014-08-07 15:35:07 -070098 resetDataSource();
Andreas Huberafed0e12011-09-20 15:39:58 -070099
Chong Zhanga19f33e2014-08-07 15:35:07 -0700100 mFd = dup(fd);
101 mOffset = offset;
102 mLength = length;
103
104 // delay data source creation to prepareAsync() to avoid blocking
105 // the calling thread in setDataSource for any significant time.
106 return OK;
Andreas Huberafed0e12011-09-20 15:39:58 -0700107}
108
Marco Nelissenf0b72b52014-09-16 15:43:44 -0700109sp<MetaData> NuPlayer::GenericSource::getFileFormatMeta() const {
110 return mFileMeta;
111}
112
Chong Zhangd354d8d2014-08-20 13:09:58 -0700113status_t NuPlayer::GenericSource::initFromDataSource() {
Lajos Molnarcc227032014-07-17 15:33:06 -0700114 sp<MediaExtractor> extractor;
115
Chong Zhangd354d8d2014-08-20 13:09:58 -0700116 CHECK(mDataSource != NULL);
117
Lajos Molnarcc227032014-07-17 15:33:06 -0700118 if (mIsWidevine) {
119 String8 mimeType;
120 float confidence;
121 sp<AMessage> dummy;
122 bool success;
123
Chong Zhangd354d8d2014-08-20 13:09:58 -0700124 success = SniffWVM(mDataSource, &mimeType, &confidence, &dummy);
Lajos Molnarcc227032014-07-17 15:33:06 -0700125 if (!success
126 || strcasecmp(
127 mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) {
128 ALOGE("unsupported widevine mime: %s", mimeType.string());
Chong Zhang3de157d2014-08-05 20:54:44 -0700129 return UNKNOWN_ERROR;
Lajos Molnarcc227032014-07-17 15:33:06 -0700130 }
131
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700132 mWVMExtractor = new WVMExtractor(mDataSource);
133 mWVMExtractor->setAdaptiveStreamingMode(true);
Lajos Molnarcc227032014-07-17 15:33:06 -0700134 if (mUIDValid) {
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700135 mWVMExtractor->setUID(mUID);
Lajos Molnarcc227032014-07-17 15:33:06 -0700136 }
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700137 extractor = mWVMExtractor;
Lajos Molnarcc227032014-07-17 15:33:06 -0700138 } else {
Chong Zhangd354d8d2014-08-20 13:09:58 -0700139 extractor = MediaExtractor::Create(mDataSource,
140 mSniffedMIME.empty() ? NULL: mSniffedMIME.c_str());
Lajos Molnarcc227032014-07-17 15:33:06 -0700141 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700142
Chong Zhang3de157d2014-08-05 20:54:44 -0700143 if (extractor == NULL) {
144 return UNKNOWN_ERROR;
145 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700146
Ronghua Wu80276872014-08-28 15:50:29 -0700147 if (extractor->getDrmFlag()) {
148 checkDrmStatus(mDataSource);
149 }
150
Marco Nelissenf0b72b52014-09-16 15:43:44 -0700151 mFileMeta = extractor->getMetaData();
152 if (mFileMeta != NULL) {
Marco Nelissenc1f4b2b2014-06-17 14:48:32 -0700153 int64_t duration;
Marco Nelissenf0b72b52014-09-16 15:43:44 -0700154 if (mFileMeta->findInt64(kKeyDuration, &duration)) {
Marco Nelissenc1f4b2b2014-06-17 14:48:32 -0700155 mDurationUs = duration;
156 }
157 }
158
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700159 int32_t totalBitrate = 0;
160
Marco Nelissen705d3292014-09-19 15:14:37 -0700161 size_t numtracks = extractor->countTracks();
162 if (numtracks == 0) {
163 return UNKNOWN_ERROR;
164 }
165
166 for (size_t i = 0; i < numtracks; ++i) {
Chong Zhangafc0a872014-08-26 09:56:52 -0700167 sp<MediaSource> track = extractor->getTrack(i);
168
Andreas Huberafed0e12011-09-20 15:39:58 -0700169 sp<MetaData> meta = extractor->getTrackMetaData(i);
170
171 const char *mime;
172 CHECK(meta->findCString(kKeyMIMEType, &mime));
173
Chong Zhangafc0a872014-08-26 09:56:52 -0700174 // Do the string compare immediately with "mime",
175 // we can't assume "mime" would stay valid after another
176 // extractor operation, some extractors might modify meta
177 // during getTrack() and make it invalid.
Andreas Huberafed0e12011-09-20 15:39:58 -0700178 if (!strncasecmp(mime, "audio/", 6)) {
179 if (mAudioTrack.mSource == NULL) {
Robert Shihdd235722014-06-12 14:49:23 -0700180 mAudioTrack.mIndex = i;
181 mAudioTrack.mSource = track;
Robert Shihaf52c1a2014-09-11 15:38:54 -0700182 mAudioTrack.mPackets =
183 new AnotherPacketSource(mAudioTrack.mSource->getFormat());
Andreas Huberafed0e12011-09-20 15:39:58 -0700184
185 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
186 mAudioIsVorbis = true;
187 } else {
188 mAudioIsVorbis = false;
189 }
190 }
191 } else if (!strncasecmp(mime, "video/", 6)) {
192 if (mVideoTrack.mSource == NULL) {
Robert Shihdd235722014-06-12 14:49:23 -0700193 mVideoTrack.mIndex = i;
194 mVideoTrack.mSource = track;
Robert Shihaf52c1a2014-09-11 15:38:54 -0700195 mVideoTrack.mPackets =
196 new AnotherPacketSource(mVideoTrack.mSource->getFormat());
Chong Zhang7e892182014-08-05 11:58:21 -0700197
198 // check if the source requires secure buffers
199 int32_t secure;
Chong Zhanga19f33e2014-08-07 15:35:07 -0700200 if (meta->findInt32(kKeyRequiresSecureBuffers, &secure)
201 && secure) {
Chong Zhang7e892182014-08-05 11:58:21 -0700202 mIsWidevine = true;
Chong Zhang3de157d2014-08-05 20:54:44 -0700203 if (mUIDValid) {
204 extractor->setUID(mUID);
205 }
Chong Zhang7e892182014-08-05 11:58:21 -0700206 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700207 }
208 }
209
210 if (track != NULL) {
Robert Shihdd235722014-06-12 14:49:23 -0700211 mSources.push(track);
Andreas Huberafed0e12011-09-20 15:39:58 -0700212 int64_t durationUs;
213 if (meta->findInt64(kKeyDuration, &durationUs)) {
214 if (durationUs > mDurationUs) {
215 mDurationUs = durationUs;
216 }
217 }
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700218
219 int32_t bitrate;
220 if (totalBitrate >= 0 && meta->findInt32(kKeyBitRate, &bitrate)) {
221 totalBitrate += bitrate;
222 } else {
223 totalBitrate = -1;
224 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700225 }
226 }
Chong Zhang3de157d2014-08-05 20:54:44 -0700227
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700228 mBitrate = totalBitrate;
229
Chong Zhang3de157d2014-08-05 20:54:44 -0700230 return OK;
Andreas Huberafed0e12011-09-20 15:39:58 -0700231}
232
Ronghua Wu80276872014-08-28 15:50:29 -0700233void NuPlayer::GenericSource::checkDrmStatus(const sp<DataSource>& dataSource) {
234 dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
235 if (mDecryptHandle != NULL) {
236 CHECK(mDrmManagerClient);
237 if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
238 sp<AMessage> msg = dupNotify();
239 msg->setInt32("what", kWhatDrmNoLicense);
240 msg->post();
241 }
242 }
243}
244
245int64_t NuPlayer::GenericSource::getLastReadPosition() {
246 if (mAudioTrack.mSource != NULL) {
247 return mAudioTimeUs;
248 } else if (mVideoTrack.mSource != NULL) {
249 return mVideoTimeUs;
250 } else {
251 return 0;
252 }
253}
254
Chong Zhanga19f33e2014-08-07 15:35:07 -0700255status_t NuPlayer::GenericSource::setBuffers(
256 bool audio, Vector<MediaBuffer *> &buffers) {
Lajos Molnarcc227032014-07-17 15:33:06 -0700257 if (mIsWidevine && !audio) {
258 return mVideoTrack.mSource->setBuffers(buffers);
259 }
260 return INVALID_OPERATION;
261}
262
Andreas Huberafed0e12011-09-20 15:39:58 -0700263NuPlayer::GenericSource::~GenericSource() {
Chong Zhang1228d6b2014-08-12 21:25:48 -0700264 if (mLooper != NULL) {
265 mLooper->unregisterHandler(id());
266 mLooper->stop();
267 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700268}
269
Andreas Huber9575c962013-02-05 13:59:56 -0800270void NuPlayer::GenericSource::prepareAsync() {
Chong Zhang1228d6b2014-08-12 21:25:48 -0700271 if (mLooper == NULL) {
272 mLooper = new ALooper;
273 mLooper->setName("generic");
274 mLooper->start();
275
276 mLooper->registerHandler(this);
277 }
278
279 sp<AMessage> msg = new AMessage(kWhatPrepareAsync, id());
280 msg->post();
281}
282
283void NuPlayer::GenericSource::onPrepareAsync() {
Chong Zhanga19f33e2014-08-07 15:35:07 -0700284 // delayed data source creation
Chong Zhangd354d8d2014-08-20 13:09:58 -0700285 if (mDataSource == NULL) {
286 if (!mUri.empty()) {
287 mIsWidevine = !strncasecmp(mUri.c_str(), "widevine://", 11);
Chong Zhanga19f33e2014-08-07 15:35:07 -0700288
Chong Zhangd354d8d2014-08-20 13:09:58 -0700289 mDataSource = DataSource::CreateFromURI(
290 mHTTPService, mUri.c_str(), &mUriHeaders, &mContentType);
291 } else {
292 // set to false first, if the extractor
293 // comes back as secure, set it to true then.
294 mIsWidevine = false;
Chong Zhanga19f33e2014-08-07 15:35:07 -0700295
Chong Zhangd354d8d2014-08-20 13:09:58 -0700296 mDataSource = new FileSource(mFd, mOffset, mLength);
297 }
Chong Zhanga19f33e2014-08-07 15:35:07 -0700298
Chong Zhangd354d8d2014-08-20 13:09:58 -0700299 if (mDataSource == NULL) {
300 ALOGE("Failed to create data source!");
301 notifyPreparedAndCleanup(UNKNOWN_ERROR);
302 return;
303 }
304
305 if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
306 mCachedSource = static_cast<NuCachedSource2 *>(mDataSource.get());
307 }
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700308
309 if (mIsWidevine || mCachedSource != NULL) {
310 schedulePollBuffering();
311 }
Chong Zhanga19f33e2014-08-07 15:35:07 -0700312 }
313
Chong Zhangd354d8d2014-08-20 13:09:58 -0700314 // check initial caching status
315 status_t err = prefillCacheIfNecessary();
316 if (err != OK) {
317 if (err == -EAGAIN) {
318 (new AMessage(kWhatPrepareAsync, id()))->post(200000);
319 } else {
320 ALOGE("Failed to prefill data cache!");
321 notifyPreparedAndCleanup(UNKNOWN_ERROR);
322 }
Chong Zhanga19f33e2014-08-07 15:35:07 -0700323 return;
324 }
325
Chong Zhangd354d8d2014-08-20 13:09:58 -0700326 // init extrator from data source
327 err = initFromDataSource();
Chong Zhanga19f33e2014-08-07 15:35:07 -0700328
329 if (err != OK) {
330 ALOGE("Failed to init from data source!");
Chong Zhangd354d8d2014-08-20 13:09:58 -0700331 notifyPreparedAndCleanup(err);
Chong Zhanga19f33e2014-08-07 15:35:07 -0700332 return;
333 }
334
Andreas Huber9575c962013-02-05 13:59:56 -0800335 if (mVideoTrack.mSource != NULL) {
Robert Shih17f6dd62014-08-20 17:00:21 -0700336 sp<MetaData> meta = doGetFormatMeta(false /* audio */);
337 sp<AMessage> msg = new AMessage;
338 err = convertMetaDataToMessage(meta, &msg);
339 if(err != OK) {
340 notifyPreparedAndCleanup(err);
341 return;
342 }
343 notifyVideoSizeChanged(msg);
Andreas Huber9575c962013-02-05 13:59:56 -0800344 }
345
346 notifyFlagsChanged(
Lajos Molnarcc227032014-07-17 15:33:06 -0700347 (mIsWidevine ? FLAG_SECURE : 0)
348 | FLAG_CAN_PAUSE
Andreas Huber9575c962013-02-05 13:59:56 -0800349 | FLAG_CAN_SEEK_BACKWARD
350 | FLAG_CAN_SEEK_FORWARD
351 | FLAG_CAN_SEEK);
352
353 notifyPrepared();
354}
355
Chong Zhangd354d8d2014-08-20 13:09:58 -0700356void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) {
357 if (err != OK) {
358 mMetaDataSize = -1ll;
359 mContentType = "";
360 mSniffedMIME = "";
361 mDataSource.clear();
362 mCachedSource.clear();
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700363
364 cancelPollBuffering();
Chong Zhangd354d8d2014-08-20 13:09:58 -0700365 }
366 notifyPrepared(err);
367}
368
369status_t NuPlayer::GenericSource::prefillCacheIfNecessary() {
370 CHECK(mDataSource != NULL);
371
372 if (mCachedSource == NULL) {
373 // no prefill if the data source is not cached
374 return OK;
375 }
376
377 // We're not doing this for streams that appear to be audio-only
378 // streams to ensure that even low bandwidth streams start
379 // playing back fairly instantly.
380 if (!strncasecmp(mContentType.string(), "audio/", 6)) {
381 return OK;
382 }
383
384 // We're going to prefill the cache before trying to instantiate
385 // the extractor below, as the latter is an operation that otherwise
386 // could block on the datasource for a significant amount of time.
387 // During that time we'd be unable to abort the preparation phase
388 // without this prefill.
389
390 // Initially make sure we have at least 192 KB for the sniff
391 // to complete without blocking.
392 static const size_t kMinBytesForSniffing = 192 * 1024;
393 static const size_t kDefaultMetaSize = 200000;
394
395 status_t finalStatus;
396
397 size_t cachedDataRemaining =
398 mCachedSource->approxDataRemaining(&finalStatus);
399
400 if (finalStatus != OK || (mMetaDataSize >= 0
401 && (off64_t)cachedDataRemaining >= mMetaDataSize)) {
402 ALOGV("stop caching, status %d, "
403 "metaDataSize %lld, cachedDataRemaining %zu",
404 finalStatus, mMetaDataSize, cachedDataRemaining);
405 return OK;
406 }
407
408 ALOGV("now cached %zu bytes of data", cachedDataRemaining);
409
410 if (mMetaDataSize < 0
411 && cachedDataRemaining >= kMinBytesForSniffing) {
412 String8 tmp;
413 float confidence;
414 sp<AMessage> meta;
415 if (!mCachedSource->sniff(&tmp, &confidence, &meta)) {
416 return UNKNOWN_ERROR;
417 }
418
419 // We successfully identified the file's extractor to
420 // be, remember this mime type so we don't have to
421 // sniff it again when we call MediaExtractor::Create()
422 mSniffedMIME = tmp.string();
423
424 if (meta == NULL
425 || !meta->findInt64("meta-data-size",
426 reinterpret_cast<int64_t*>(&mMetaDataSize))) {
427 mMetaDataSize = kDefaultMetaSize;
428 }
429
430 if (mMetaDataSize < 0ll) {
431 ALOGE("invalid metaDataSize = %lld bytes", mMetaDataSize);
432 return UNKNOWN_ERROR;
433 }
434 }
435
436 return -EAGAIN;
437}
438
Andreas Huberafed0e12011-09-20 15:39:58 -0700439void NuPlayer::GenericSource::start() {
440 ALOGI("start");
441
442 if (mAudioTrack.mSource != NULL) {
Robert Shihbace25b2014-07-25 14:14:34 -0700443 CHECK_EQ(mAudioTrack.mSource->start(), (status_t)OK);
Andreas Huberafed0e12011-09-20 15:39:58 -0700444
Robert Shih17f6dd62014-08-20 17:00:21 -0700445 postReadBuffer(MEDIA_TRACK_TYPE_AUDIO);
Andreas Huberafed0e12011-09-20 15:39:58 -0700446 }
447
448 if (mVideoTrack.mSource != NULL) {
Robert Shihbace25b2014-07-25 14:14:34 -0700449 CHECK_EQ(mVideoTrack.mSource->start(), (status_t)OK);
Andreas Huberafed0e12011-09-20 15:39:58 -0700450
Robert Shih17f6dd62014-08-20 17:00:21 -0700451 postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
Andreas Huberafed0e12011-09-20 15:39:58 -0700452 }
Ronghua Wu80276872014-08-28 15:50:29 -0700453
454 setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000);
455 mStarted = true;
456}
457
458void NuPlayer::GenericSource::stop() {
459 // nothing to do, just account for DRM playback status
460 setDrmPlaybackStatusIfNeeded(Playback::STOP, 0);
461 mStarted = false;
462}
463
464void NuPlayer::GenericSource::pause() {
465 // nothing to do, just account for DRM playback status
466 setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0);
467 mStarted = false;
468}
469
470void NuPlayer::GenericSource::resume() {
471 // nothing to do, just account for DRM playback status
472 setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000);
473 mStarted = true;
474}
475
Chong Zhang48296b72014-09-14 14:28:45 -0700476void NuPlayer::GenericSource::disconnect() {
477 if (mDataSource != NULL) {
478 // disconnect data source
479 if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
480 static_cast<NuCachedSource2 *>(mDataSource.get())->disconnect();
481 }
482 }
483}
484
Ronghua Wu80276872014-08-28 15:50:29 -0700485void NuPlayer::GenericSource::setDrmPlaybackStatusIfNeeded(int playbackStatus, int64_t position) {
486 if (mDecryptHandle != NULL) {
487 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, playbackStatus, position);
488 }
Robert Shih17f6dd62014-08-20 17:00:21 -0700489 mSubtitleTrack.mPackets = new AnotherPacketSource(NULL);
490 mTimedTextTrack.mPackets = new AnotherPacketSource(NULL);
Andreas Huberafed0e12011-09-20 15:39:58 -0700491}
492
493status_t NuPlayer::GenericSource::feedMoreTSData() {
494 return OK;
495}
496
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700497void NuPlayer::GenericSource::schedulePollBuffering() {
498 sp<AMessage> msg = new AMessage(kWhatPollBuffering, id());
499 msg->setInt32("generation", mPollBufferingGeneration);
500 msg->post(1000000ll);
501}
502
503void NuPlayer::GenericSource::cancelPollBuffering() {
504 ++mPollBufferingGeneration;
505}
506
507void NuPlayer::GenericSource::notifyBufferingUpdate(int percentage) {
508 sp<AMessage> msg = dupNotify();
509 msg->setInt32("what", kWhatBufferingUpdate);
510 msg->setInt32("percentage", percentage);
511 msg->post();
512}
513
514void NuPlayer::GenericSource::onPollBuffering() {
515 status_t finalStatus = UNKNOWN_ERROR;
516 int64_t cachedDurationUs = 0ll;
517
518 if (mCachedSource != NULL) {
519 size_t cachedDataRemaining =
520 mCachedSource->approxDataRemaining(&finalStatus);
521
522 if (finalStatus == OK) {
523 off64_t size;
524 int64_t bitrate = 0ll;
525 if (mDurationUs > 0 && mCachedSource->getSize(&size) == OK) {
526 bitrate = size * 8000000ll / mDurationUs;
527 } else if (mBitrate > 0) {
528 bitrate = mBitrate;
529 }
530 if (bitrate > 0) {
531 cachedDurationUs = cachedDataRemaining * 8000000ll / bitrate;
532 }
533 }
534 } else if (mWVMExtractor != NULL) {
535 cachedDurationUs
536 = mWVMExtractor->getCachedDurationUs(&finalStatus);
537 }
538
539 if (finalStatus == ERROR_END_OF_STREAM) {
540 notifyBufferingUpdate(100);
541 cancelPollBuffering();
542 return;
543 } else if (cachedDurationUs > 0ll && mDurationUs > 0ll) {
544 int percentage = 100.0 * cachedDurationUs / mDurationUs;
545 if (percentage > 100) {
546 percentage = 100;
547 }
548
549 notifyBufferingUpdate(percentage);
550 }
551
552 schedulePollBuffering();
553}
554
555
Robert Shih3423bbd2014-07-16 15:47:09 -0700556void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) {
557 switch (msg->what()) {
Chong Zhang1228d6b2014-08-12 21:25:48 -0700558 case kWhatPrepareAsync:
559 {
560 onPrepareAsync();
561 break;
562 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700563 case kWhatFetchSubtitleData:
564 {
Lajos Molnare26940f2014-07-31 10:31:26 -0700565 fetchTextData(kWhatSendSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
566 mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
567 break;
568 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700569
Lajos Molnare26940f2014-07-31 10:31:26 -0700570 case kWhatFetchTimedTextData:
571 {
572 fetchTextData(kWhatSendTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
573 mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
Robert Shih3423bbd2014-07-16 15:47:09 -0700574 break;
575 }
576
577 case kWhatSendSubtitleData:
578 {
Lajos Molnare26940f2014-07-31 10:31:26 -0700579 sendTextData(kWhatSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
580 mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
581 break;
582 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700583
Lajos Molnare26940f2014-07-31 10:31:26 -0700584 case kWhatSendTimedTextData:
585 {
586 sendTextData(kWhatTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
587 mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
Robert Shih3423bbd2014-07-16 15:47:09 -0700588 break;
589 }
590
591 case kWhatChangeAVSource:
592 {
593 int32_t trackIndex;
594 CHECK(msg->findInt32("trackIndex", &trackIndex));
595 const sp<MediaSource> source = mSources.itemAt(trackIndex);
596
597 Track* track;
598 const char *mime;
599 media_track_type trackType, counterpartType;
600 sp<MetaData> meta = source->getFormat();
601 meta->findCString(kKeyMIMEType, &mime);
602 if (!strncasecmp(mime, "audio/", 6)) {
603 track = &mAudioTrack;
604 trackType = MEDIA_TRACK_TYPE_AUDIO;
605 counterpartType = MEDIA_TRACK_TYPE_VIDEO;;
606 } else {
607 CHECK(!strncasecmp(mime, "video/", 6));
608 track = &mVideoTrack;
609 trackType = MEDIA_TRACK_TYPE_VIDEO;
610 counterpartType = MEDIA_TRACK_TYPE_AUDIO;;
611 }
612
613
614 if (track->mSource != NULL) {
615 track->mSource->stop();
616 }
617 track->mSource = source;
618 track->mSource->start();
619 track->mIndex = trackIndex;
620
621 status_t avail;
622 if (!track->mPackets->hasBufferAvailable(&avail)) {
623 // sync from other source
624 TRESPASS();
625 break;
626 }
627
628 int64_t timeUs, actualTimeUs;
629 const bool formatChange = true;
Robert Shih309aa8b2014-07-29 18:34:36 -0700630 sp<AMessage> latestMeta = track->mPackets->getLatestEnqueuedMeta();
Robert Shih3423bbd2014-07-16 15:47:09 -0700631 CHECK(latestMeta != NULL && latestMeta->findInt64("timeUs", &timeUs));
632 readBuffer(trackType, timeUs, &actualTimeUs, formatChange);
633 readBuffer(counterpartType, -1, NULL, formatChange);
634 ALOGV("timeUs %lld actualTimeUs %lld", timeUs, actualTimeUs);
635
636 break;
637 }
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700638 case kWhatPollBuffering:
639 {
640 int32_t generation;
641 CHECK(msg->findInt32("generation", &generation));
642 if (generation == mPollBufferingGeneration) {
643 onPollBuffering();
644 }
645 break;
646 }
Robert Shih17f6dd62014-08-20 17:00:21 -0700647
648 case kWhatGetFormat:
649 {
650 onGetFormatMeta(msg);
651 break;
652 }
653
654 case kWhatGetSelectedTrack:
655 {
656 onGetSelectedTrack(msg);
657 break;
658 }
659
660 case kWhatSelectTrack:
661 {
662 onSelectTrack(msg);
663 break;
664 }
665
666 case kWhatSeek:
667 {
668 onSeek(msg);
669 break;
670 }
671
672 case kWhatReadBuffer:
673 {
674 onReadBuffer(msg);
675 break;
676 }
677
Robert Shih3423bbd2014-07-16 15:47:09 -0700678 default:
679 Source::onMessageReceived(msg);
680 break;
681 }
682}
683
Lajos Molnare26940f2014-07-31 10:31:26 -0700684void NuPlayer::GenericSource::fetchTextData(
685 uint32_t sendWhat,
686 media_track_type type,
687 int32_t curGen,
688 sp<AnotherPacketSource> packets,
689 sp<AMessage> msg) {
690 int32_t msgGeneration;
691 CHECK(msg->findInt32("generation", &msgGeneration));
692 if (msgGeneration != curGen) {
693 // stale
694 return;
695 }
696
697 int32_t avail;
698 if (packets->hasBufferAvailable(&avail)) {
699 return;
700 }
701
702 int64_t timeUs;
703 CHECK(msg->findInt64("timeUs", &timeUs));
704
705 int64_t subTimeUs;
706 readBuffer(type, timeUs, &subTimeUs);
707
708 int64_t delayUs = subTimeUs - timeUs;
709 if (msg->what() == kWhatFetchSubtitleData) {
710 const int64_t oneSecUs = 1000000ll;
711 delayUs -= oneSecUs;
712 }
713 sp<AMessage> msg2 = new AMessage(sendWhat, id());
714 msg2->setInt32("generation", msgGeneration);
715 msg2->post(delayUs < 0 ? 0 : delayUs);
716}
717
718void NuPlayer::GenericSource::sendTextData(
719 uint32_t what,
720 media_track_type type,
721 int32_t curGen,
722 sp<AnotherPacketSource> packets,
723 sp<AMessage> msg) {
724 int32_t msgGeneration;
725 CHECK(msg->findInt32("generation", &msgGeneration));
726 if (msgGeneration != curGen) {
727 // stale
728 return;
729 }
730
731 int64_t subTimeUs;
732 if (packets->nextBufferTime(&subTimeUs) != OK) {
733 return;
734 }
735
736 int64_t nextSubTimeUs;
737 readBuffer(type, -1, &nextSubTimeUs);
738
739 sp<ABuffer> buffer;
740 status_t dequeueStatus = packets->dequeueAccessUnit(&buffer);
741 if (dequeueStatus == OK) {
742 sp<AMessage> notify = dupNotify();
743 notify->setInt32("what", what);
744 notify->setBuffer("buffer", buffer);
745 notify->post();
746
747 const int64_t delayUs = nextSubTimeUs - subTimeUs;
748 msg->post(delayUs < 0 ? 0 : delayUs);
749 }
750}
751
Andreas Huber84066782011-08-16 09:34:26 -0700752sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
Robert Shih17f6dd62014-08-20 17:00:21 -0700753 sp<AMessage> msg = new AMessage(kWhatGetFormat, id());
754 msg->setInt32("audio", audio);
755
756 sp<AMessage> response;
757 void *format;
758 status_t err = msg->postAndAwaitResponse(&response);
759 if (err == OK && response != NULL) {
760 CHECK(response->findPointer("format", &format));
761 return (MetaData *)format;
762 } else {
763 return NULL;
764 }
765}
766
767void NuPlayer::GenericSource::onGetFormatMeta(sp<AMessage> msg) const {
768 int32_t audio;
769 CHECK(msg->findInt32("audio", &audio));
770
771 sp<AMessage> response = new AMessage;
772 sp<MetaData> format = doGetFormatMeta(audio);
773 response->setPointer("format", format.get());
774
775 uint32_t replyID;
776 CHECK(msg->senderAwaitsResponse(&replyID));
777 response->postReply(replyID);
778}
779
780sp<MetaData> NuPlayer::GenericSource::doGetFormatMeta(bool audio) const {
Andreas Huberafed0e12011-09-20 15:39:58 -0700781 sp<MediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
782
783 if (source == NULL) {
784 return NULL;
785 }
786
787 return source->getFormat();
788}
789
790status_t NuPlayer::GenericSource::dequeueAccessUnit(
791 bool audio, sp<ABuffer> *accessUnit) {
792 Track *track = audio ? &mAudioTrack : &mVideoTrack;
793
794 if (track->mSource == NULL) {
795 return -EWOULDBLOCK;
796 }
797
Lajos Molnarcc227032014-07-17 15:33:06 -0700798 if (mIsWidevine && !audio) {
799 // try to read a buffer as we may not have been able to the last time
Robert Shih17f6dd62014-08-20 17:00:21 -0700800 postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
Lajos Molnarcc227032014-07-17 15:33:06 -0700801 }
802
Andreas Huberafed0e12011-09-20 15:39:58 -0700803 status_t finalResult;
804 if (!track->mPackets->hasBufferAvailable(&finalResult)) {
Lajos Molnarcc227032014-07-17 15:33:06 -0700805 return (finalResult == OK ? -EWOULDBLOCK : finalResult);
Andreas Huberafed0e12011-09-20 15:39:58 -0700806 }
807
808 status_t result = track->mPackets->dequeueAccessUnit(accessUnit);
809
Robert Shih3423bbd2014-07-16 15:47:09 -0700810 if (!track->mPackets->hasBufferAvailable(&finalResult)) {
Robert Shih17f6dd62014-08-20 17:00:21 -0700811 postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
Lajos Molnare26940f2014-07-31 10:31:26 -0700812 }
813
Robert Shih3423bbd2014-07-16 15:47:09 -0700814 if (result != OK) {
Lajos Molnare26940f2014-07-31 10:31:26 -0700815 if (mSubtitleTrack.mSource != NULL) {
816 mSubtitleTrack.mPackets->clear();
817 mFetchSubtitleDataGeneration++;
818 }
819 if (mTimedTextTrack.mSource != NULL) {
820 mTimedTextTrack.mPackets->clear();
821 mFetchTimedTextDataGeneration++;
822 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700823 return result;
824 }
825
826 int64_t timeUs;
827 status_t eosResult; // ignored
828 CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs));
Lajos Molnare26940f2014-07-31 10:31:26 -0700829
830 if (mSubtitleTrack.mSource != NULL
831 && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
Robert Shih3423bbd2014-07-16 15:47:09 -0700832 sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, id());
833 msg->setInt64("timeUs", timeUs);
834 msg->setInt32("generation", mFetchSubtitleDataGeneration);
835 msg->post();
836 }
Robert Shiheb1735e2014-07-23 15:53:14 -0700837
Lajos Molnare26940f2014-07-31 10:31:26 -0700838 if (mTimedTextTrack.mSource != NULL
839 && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
840 sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, id());
841 msg->setInt64("timeUs", timeUs);
842 msg->setInt32("generation", mFetchTimedTextDataGeneration);
843 msg->post();
844 }
845
Andreas Huberafed0e12011-09-20 15:39:58 -0700846 return result;
847}
848
849status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) {
850 *durationUs = mDurationUs;
851 return OK;
852}
853
Robert Shihdd235722014-06-12 14:49:23 -0700854size_t NuPlayer::GenericSource::getTrackCount() const {
855 return mSources.size();
856}
857
858sp<AMessage> NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const {
859 size_t trackCount = mSources.size();
860 if (trackIndex >= trackCount) {
861 return NULL;
862 }
863
864 sp<AMessage> format = new AMessage();
865 sp<MetaData> meta = mSources.itemAt(trackIndex)->getFormat();
866
867 const char *mime;
868 CHECK(meta->findCString(kKeyMIMEType, &mime));
869
870 int32_t trackType;
871 if (!strncasecmp(mime, "video/", 6)) {
872 trackType = MEDIA_TRACK_TYPE_VIDEO;
873 } else if (!strncasecmp(mime, "audio/", 6)) {
874 trackType = MEDIA_TRACK_TYPE_AUDIO;
875 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
876 trackType = MEDIA_TRACK_TYPE_TIMEDTEXT;
877 } else {
878 trackType = MEDIA_TRACK_TYPE_UNKNOWN;
879 }
880 format->setInt32("type", trackType);
881
882 const char *lang;
883 if (!meta->findCString(kKeyMediaLanguage, &lang)) {
884 lang = "und";
885 }
886 format->setString("language", lang);
887
888 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
889 format->setString("mime", mime);
890
891 int32_t isAutoselect = 1, isDefault = 0, isForced = 0;
892 meta->findInt32(kKeyTrackIsAutoselect, &isAutoselect);
893 meta->findInt32(kKeyTrackIsDefault, &isDefault);
894 meta->findInt32(kKeyTrackIsForced, &isForced);
895
896 format->setInt32("auto", !!isAutoselect);
897 format->setInt32("default", !!isDefault);
898 format->setInt32("forced", !!isForced);
899 }
900
901 return format;
902}
903
Lajos Molnare26940f2014-07-31 10:31:26 -0700904ssize_t NuPlayer::GenericSource::getSelectedTrack(media_track_type type) const {
Robert Shih17f6dd62014-08-20 17:00:21 -0700905 sp<AMessage> msg = new AMessage(kWhatGetSelectedTrack, id());
906 msg->setInt32("type", type);
907
908 sp<AMessage> response;
909 int32_t index;
910 status_t err = msg->postAndAwaitResponse(&response);
911 if (err == OK && response != NULL) {
912 CHECK(response->findInt32("index", &index));
913 return index;
914 } else {
915 return -1;
916 }
917}
918
919void NuPlayer::GenericSource::onGetSelectedTrack(sp<AMessage> msg) const {
920 int32_t tmpType;
921 CHECK(msg->findInt32("type", &tmpType));
922 media_track_type type = (media_track_type)tmpType;
923
924 sp<AMessage> response = new AMessage;
925 ssize_t index = doGetSelectedTrack(type);
926 response->setInt32("index", index);
927
928 uint32_t replyID;
929 CHECK(msg->senderAwaitsResponse(&replyID));
930 response->postReply(replyID);
931}
932
933ssize_t NuPlayer::GenericSource::doGetSelectedTrack(media_track_type type) const {
Lajos Molnare26940f2014-07-31 10:31:26 -0700934 const Track *track = NULL;
935 switch (type) {
936 case MEDIA_TRACK_TYPE_VIDEO:
937 track = &mVideoTrack;
938 break;
939 case MEDIA_TRACK_TYPE_AUDIO:
940 track = &mAudioTrack;
941 break;
942 case MEDIA_TRACK_TYPE_TIMEDTEXT:
943 track = &mTimedTextTrack;
944 break;
945 case MEDIA_TRACK_TYPE_SUBTITLE:
946 track = &mSubtitleTrack;
947 break;
948 default:
949 break;
950 }
951
952 if (track != NULL && track->mSource != NULL) {
953 return track->mIndex;
954 }
955
956 return -1;
957}
958
Robert Shih3423bbd2014-07-16 15:47:09 -0700959status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select) {
Lajos Molnare26940f2014-07-31 10:31:26 -0700960 ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex);
Robert Shih17f6dd62014-08-20 17:00:21 -0700961 sp<AMessage> msg = new AMessage(kWhatSelectTrack, id());
962 msg->setInt32("trackIndex", trackIndex);
Robert Shihda23ab92014-09-16 11:34:08 -0700963 msg->setInt32("select", select);
Robert Shih17f6dd62014-08-20 17:00:21 -0700964
965 sp<AMessage> response;
966 status_t err = msg->postAndAwaitResponse(&response);
967 if (err == OK && response != NULL) {
968 CHECK(response->findInt32("err", &err));
969 }
970
971 return err;
972}
973
974void NuPlayer::GenericSource::onSelectTrack(sp<AMessage> msg) {
975 int32_t trackIndex, select;
976 CHECK(msg->findInt32("trackIndex", &trackIndex));
977 CHECK(msg->findInt32("select", &select));
978
979 sp<AMessage> response = new AMessage;
980 status_t err = doSelectTrack(trackIndex, select);
981 response->setInt32("err", err);
982
983 uint32_t replyID;
984 CHECK(msg->senderAwaitsResponse(&replyID));
985 response->postReply(replyID);
986}
987
988status_t NuPlayer::GenericSource::doSelectTrack(size_t trackIndex, bool select) {
Robert Shih3423bbd2014-07-16 15:47:09 -0700989 if (trackIndex >= mSources.size()) {
990 return BAD_INDEX;
991 }
992
993 if (!select) {
Lajos Molnare26940f2014-07-31 10:31:26 -0700994 Track* track = NULL;
995 if (mSubtitleTrack.mSource != NULL && trackIndex == mSubtitleTrack.mIndex) {
996 track = &mSubtitleTrack;
997 mFetchSubtitleDataGeneration++;
998 } else if (mTimedTextTrack.mSource != NULL && trackIndex == mTimedTextTrack.mIndex) {
999 track = &mTimedTextTrack;
1000 mFetchTimedTextDataGeneration++;
1001 }
1002 if (track == NULL) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001003 return INVALID_OPERATION;
1004 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001005 track->mSource->stop();
1006 track->mSource = NULL;
1007 track->mPackets->clear();
Robert Shih3423bbd2014-07-16 15:47:09 -07001008 return OK;
1009 }
1010
1011 const sp<MediaSource> source = mSources.itemAt(trackIndex);
1012 sp<MetaData> meta = source->getFormat();
1013 const char *mime;
1014 CHECK(meta->findCString(kKeyMIMEType, &mime));
1015 if (!strncasecmp(mime, "text/", 5)) {
Lajos Molnare26940f2014-07-31 10:31:26 -07001016 bool isSubtitle = strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP);
1017 Track *track = isSubtitle ? &mSubtitleTrack : &mTimedTextTrack;
1018 if (track->mSource != NULL && track->mIndex == trackIndex) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001019 return OK;
1020 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001021 track->mIndex = trackIndex;
1022 if (track->mSource != NULL) {
1023 track->mSource->stop();
Robert Shih3423bbd2014-07-16 15:47:09 -07001024 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001025 track->mSource = mSources.itemAt(trackIndex);
1026 track->mSource->start();
1027 if (track->mPackets == NULL) {
1028 track->mPackets = new AnotherPacketSource(track->mSource->getFormat());
Robert Shih3423bbd2014-07-16 15:47:09 -07001029 } else {
Lajos Molnare26940f2014-07-31 10:31:26 -07001030 track->mPackets->clear();
1031 track->mPackets->setFormat(track->mSource->getFormat());
Robert Shih3423bbd2014-07-16 15:47:09 -07001032
1033 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001034
1035 if (isSubtitle) {
1036 mFetchSubtitleDataGeneration++;
1037 } else {
1038 mFetchTimedTextDataGeneration++;
1039 }
1040
Robert Shih3423bbd2014-07-16 15:47:09 -07001041 return OK;
1042 } else if (!strncasecmp(mime, "audio/", 6) || !strncasecmp(mime, "video/", 6)) {
1043 bool audio = !strncasecmp(mime, "audio/", 6);
1044 Track *track = audio ? &mAudioTrack : &mVideoTrack;
1045 if (track->mSource != NULL && track->mIndex == trackIndex) {
1046 return OK;
1047 }
1048
1049 sp<AMessage> msg = new AMessage(kWhatChangeAVSource, id());
1050 msg->setInt32("trackIndex", trackIndex);
1051 msg->post();
1052 return OK;
1053 }
1054
1055 return INVALID_OPERATION;
1056}
1057
Andreas Huberafed0e12011-09-20 15:39:58 -07001058status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) {
Robert Shih17f6dd62014-08-20 17:00:21 -07001059 sp<AMessage> msg = new AMessage(kWhatSeek, id());
1060 msg->setInt64("seekTimeUs", seekTimeUs);
1061
1062 sp<AMessage> response;
1063 status_t err = msg->postAndAwaitResponse(&response);
1064 if (err == OK && response != NULL) {
1065 CHECK(response->findInt32("err", &err));
1066 }
1067
1068 return err;
1069}
1070
1071void NuPlayer::GenericSource::onSeek(sp<AMessage> msg) {
1072 int64_t seekTimeUs;
1073 CHECK(msg->findInt64("seekTimeUs", &seekTimeUs));
1074
1075 sp<AMessage> response = new AMessage;
1076 status_t err = doSeek(seekTimeUs);
1077 response->setInt32("err", err);
1078
1079 uint32_t replyID;
1080 CHECK(msg->senderAwaitsResponse(&replyID));
1081 response->postReply(replyID);
1082}
1083
1084status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs) {
Andreas Huberafed0e12011-09-20 15:39:58 -07001085 if (mVideoTrack.mSource != NULL) {
1086 int64_t actualTimeUs;
Robert Shih3423bbd2014-07-16 15:47:09 -07001087 readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, &actualTimeUs);
Andreas Huberafed0e12011-09-20 15:39:58 -07001088
1089 seekTimeUs = actualTimeUs;
1090 }
1091
1092 if (mAudioTrack.mSource != NULL) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001093 readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs);
Andreas Huberafed0e12011-09-20 15:39:58 -07001094 }
1095
Ronghua Wu80276872014-08-28 15:50:29 -07001096 setDrmPlaybackStatusIfNeeded(Playback::START, seekTimeUs / 1000);
1097 if (!mStarted) {
1098 setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0);
1099 }
Andreas Huberafed0e12011-09-20 15:39:58 -07001100 return OK;
1101}
1102
Robert Shih3423bbd2014-07-16 15:47:09 -07001103sp<ABuffer> NuPlayer::GenericSource::mediaBufferToABuffer(
1104 MediaBuffer* mb,
1105 media_track_type trackType,
1106 int64_t *actualTimeUs) {
1107 bool audio = trackType == MEDIA_TRACK_TYPE_AUDIO;
1108 size_t outLength = mb->range_length();
1109
1110 if (audio && mAudioIsVorbis) {
1111 outLength += sizeof(int32_t);
1112 }
1113
1114 sp<ABuffer> ab;
1115 if (mIsWidevine && !audio) {
1116 // data is already provided in the buffer
1117 ab = new ABuffer(NULL, mb->range_length());
Robert Shih3423bbd2014-07-16 15:47:09 -07001118 mb->add_ref();
Wei Jia96e92b52014-09-18 17:36:20 -07001119 ab->setMediaBufferBase(mb);
Robert Shih3423bbd2014-07-16 15:47:09 -07001120 } else {
1121 ab = new ABuffer(outLength);
1122 memcpy(ab->data(),
1123 (const uint8_t *)mb->data() + mb->range_offset(),
1124 mb->range_length());
1125 }
1126
1127 if (audio && mAudioIsVorbis) {
1128 int32_t numPageSamples;
1129 if (!mb->meta_data()->findInt32(kKeyValidSamples, &numPageSamples)) {
1130 numPageSamples = -1;
1131 }
1132
1133 uint8_t* abEnd = ab->data() + mb->range_length();
1134 memcpy(abEnd, &numPageSamples, sizeof(numPageSamples));
1135 }
1136
Lajos Molnare26940f2014-07-31 10:31:26 -07001137 sp<AMessage> meta = ab->meta();
1138
Robert Shih3423bbd2014-07-16 15:47:09 -07001139 int64_t timeUs;
1140 CHECK(mb->meta_data()->findInt64(kKeyTime, &timeUs));
Robert Shih3423bbd2014-07-16 15:47:09 -07001141 meta->setInt64("timeUs", timeUs);
1142
Lajos Molnare26940f2014-07-31 10:31:26 -07001143 if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) {
1144 const char *mime;
1145 CHECK(mTimedTextTrack.mSource != NULL
1146 && mTimedTextTrack.mSource->getFormat()->findCString(kKeyMIMEType, &mime));
1147 meta->setString("mime", mime);
1148 }
1149
Robert Shih3423bbd2014-07-16 15:47:09 -07001150 int64_t durationUs;
1151 if (mb->meta_data()->findInt64(kKeyDuration, &durationUs)) {
1152 meta->setInt64("durationUs", durationUs);
1153 }
1154
1155 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
1156 meta->setInt32("trackIndex", mSubtitleTrack.mIndex);
1157 }
1158
1159 if (actualTimeUs) {
1160 *actualTimeUs = timeUs;
1161 }
1162
1163 mb->release();
1164 mb = NULL;
1165
1166 return ab;
1167}
1168
Robert Shih17f6dd62014-08-20 17:00:21 -07001169void NuPlayer::GenericSource::postReadBuffer(media_track_type trackType) {
Lajos Molnar84f52782014-09-11 10:01:55 -07001170 Mutex::Autolock _l(mReadBufferLock);
1171
1172 if ((mPendingReadBufferTypes & (1 << trackType)) == 0) {
1173 mPendingReadBufferTypes |= (1 << trackType);
1174 sp<AMessage> msg = new AMessage(kWhatReadBuffer, id());
1175 msg->setInt32("trackType", trackType);
1176 msg->post();
1177 }
Robert Shih17f6dd62014-08-20 17:00:21 -07001178}
1179
1180void NuPlayer::GenericSource::onReadBuffer(sp<AMessage> msg) {
1181 int32_t tmpType;
1182 CHECK(msg->findInt32("trackType", &tmpType));
1183 media_track_type trackType = (media_track_type)tmpType;
Lajos Molnar84f52782014-09-11 10:01:55 -07001184 {
1185 // only protect the variable change, as readBuffer may
1186 // take considerable time. This may result in one extra
1187 // read being processed, but that is benign.
1188 Mutex::Autolock _l(mReadBufferLock);
1189 mPendingReadBufferTypes &= ~(1 << trackType);
1190 }
Robert Shih17f6dd62014-08-20 17:00:21 -07001191 readBuffer(trackType);
1192}
1193
Andreas Huberafed0e12011-09-20 15:39:58 -07001194void NuPlayer::GenericSource::readBuffer(
Robert Shih3423bbd2014-07-16 15:47:09 -07001195 media_track_type trackType, int64_t seekTimeUs, int64_t *actualTimeUs, bool formatChange) {
1196 Track *track;
Phil Burkc5cc2e22014-09-09 20:08:39 -07001197 size_t maxBuffers = 1;
Robert Shih3423bbd2014-07-16 15:47:09 -07001198 switch (trackType) {
1199 case MEDIA_TRACK_TYPE_VIDEO:
1200 track = &mVideoTrack;
Jeff Tinkera28785a2014-09-23 22:24:26 -07001201 if (mIsWidevine) {
1202 maxBuffers = 2;
1203 }
Robert Shih3423bbd2014-07-16 15:47:09 -07001204 break;
1205 case MEDIA_TRACK_TYPE_AUDIO:
1206 track = &mAudioTrack;
Jeff Tinkera28785a2014-09-23 22:24:26 -07001207 if (mIsWidevine) {
1208 maxBuffers = 8;
1209 } else {
1210 maxBuffers = 64;
1211 }
Robert Shih3423bbd2014-07-16 15:47:09 -07001212 break;
1213 case MEDIA_TRACK_TYPE_SUBTITLE:
1214 track = &mSubtitleTrack;
1215 break;
Lajos Molnare26940f2014-07-31 10:31:26 -07001216 case MEDIA_TRACK_TYPE_TIMEDTEXT:
1217 track = &mTimedTextTrack;
1218 break;
Robert Shih3423bbd2014-07-16 15:47:09 -07001219 default:
1220 TRESPASS();
1221 }
1222
1223 if (track->mSource == NULL) {
1224 return;
1225 }
Andreas Huberafed0e12011-09-20 15:39:58 -07001226
1227 if (actualTimeUs) {
1228 *actualTimeUs = seekTimeUs;
1229 }
1230
1231 MediaSource::ReadOptions options;
1232
1233 bool seeking = false;
1234
1235 if (seekTimeUs >= 0) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001236 options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
Andreas Huberafed0e12011-09-20 15:39:58 -07001237 seeking = true;
1238 }
1239
Robert Shih3423bbd2014-07-16 15:47:09 -07001240 if (mIsWidevine && trackType != MEDIA_TRACK_TYPE_AUDIO) {
Lajos Molnarcc227032014-07-17 15:33:06 -07001241 options.setNonBlocking();
1242 }
1243
Phil Burkc5cc2e22014-09-09 20:08:39 -07001244 for (size_t numBuffers = 0; numBuffers < maxBuffers; ) {
Andreas Huberafed0e12011-09-20 15:39:58 -07001245 MediaBuffer *mbuf;
1246 status_t err = track->mSource->read(&mbuf, &options);
1247
1248 options.clearSeekTo();
1249
1250 if (err == OK) {
Ronghua Wu80276872014-08-28 15:50:29 -07001251 int64_t timeUs;
1252 CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs));
1253 if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
1254 mAudioTimeUs = timeUs;
1255 } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
1256 mVideoTimeUs = timeUs;
1257 }
1258
Robert Shih3423bbd2014-07-16 15:47:09 -07001259 // formatChange && seeking: track whose source is changed during selection
1260 // formatChange && !seeking: track whose source is not changed during selection
1261 // !formatChange: normal seek
Lajos Molnare26940f2014-07-31 10:31:26 -07001262 if ((seeking || formatChange)
1263 && (trackType == MEDIA_TRACK_TYPE_AUDIO
1264 || trackType == MEDIA_TRACK_TYPE_VIDEO)) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001265 ATSParser::DiscontinuityType type = formatChange
1266 ? (seeking
1267 ? ATSParser::DISCONTINUITY_FORMATCHANGE
1268 : ATSParser::DISCONTINUITY_NONE)
1269 : ATSParser::DISCONTINUITY_SEEK;
1270 track->mPackets->queueDiscontinuity( type, NULL, true /* discard */);
Andreas Huberafed0e12011-09-20 15:39:58 -07001271 }
1272
Robert Shih3423bbd2014-07-16 15:47:09 -07001273 sp<ABuffer> buffer = mediaBufferToABuffer(mbuf, trackType, actualTimeUs);
Andreas Huberafed0e12011-09-20 15:39:58 -07001274 track->mPackets->queueAccessUnit(buffer);
Marco Nelissen317a49a2014-09-16 21:32:33 -07001275 formatChange = false;
1276 seeking = false;
Phil Burkc5cc2e22014-09-09 20:08:39 -07001277 ++numBuffers;
Lajos Molnarcc227032014-07-17 15:33:06 -07001278 } else if (err == WOULD_BLOCK) {
1279 break;
Andreas Huberafed0e12011-09-20 15:39:58 -07001280 } else if (err == INFO_FORMAT_CHANGED) {
1281#if 0
1282 track->mPackets->queueDiscontinuity(
Chong Zhang632740c2014-06-26 13:03:47 -07001283 ATSParser::DISCONTINUITY_FORMATCHANGE,
1284 NULL,
1285 false /* discard */);
Andreas Huberafed0e12011-09-20 15:39:58 -07001286#endif
1287 } else {
1288 track->mPackets->signalEOS(err);
1289 break;
1290 }
1291 }
1292}
1293
Andreas Huberafed0e12011-09-20 15:39:58 -07001294} // namespace android