blob: baf211b1ce3c375f4e583f47351904bf2bb19072 [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;
Andy Hung2abde2c2014-09-30 14:40:32 -070076 mStopRead = true;
Chong Zhanga19f33e2014-08-07 15:35:07 -070077}
78
79status_t NuPlayer::GenericSource::setDataSource(
Chong Zhang3de157d2014-08-05 20:54:44 -070080 const sp<IMediaHTTPService> &httpService,
81 const char *url,
82 const KeyedVector<String8, String8> *headers) {
Chong Zhanga19f33e2014-08-07 15:35:07 -070083 resetDataSource();
Chong Zhang3de157d2014-08-05 20:54:44 -070084
Chong Zhanga19f33e2014-08-07 15:35:07 -070085 mHTTPService = httpService;
86 mUri = url;
Andreas Huberafed0e12011-09-20 15:39:58 -070087
Chong Zhanga19f33e2014-08-07 15:35:07 -070088 if (headers) {
89 mUriHeaders = *headers;
Chong Zhang3de157d2014-08-05 20:54:44 -070090 }
91
Chong Zhanga19f33e2014-08-07 15:35:07 -070092 // delay data source creation to prepareAsync() to avoid blocking
93 // the calling thread in setDataSource for any significant time.
94 return OK;
Andreas Huberafed0e12011-09-20 15:39:58 -070095}
96
Chong Zhanga19f33e2014-08-07 15:35:07 -070097status_t NuPlayer::GenericSource::setDataSource(
Chong Zhang3de157d2014-08-05 20:54:44 -070098 int fd, int64_t offset, int64_t length) {
Chong Zhanga19f33e2014-08-07 15:35:07 -070099 resetDataSource();
Andreas Huberafed0e12011-09-20 15:39:58 -0700100
Chong Zhanga19f33e2014-08-07 15:35:07 -0700101 mFd = dup(fd);
102 mOffset = offset;
103 mLength = length;
104
105 // delay data source creation to prepareAsync() to avoid blocking
106 // the calling thread in setDataSource for any significant time.
107 return OK;
Andreas Huberafed0e12011-09-20 15:39:58 -0700108}
109
Marco Nelissenf0b72b52014-09-16 15:43:44 -0700110sp<MetaData> NuPlayer::GenericSource::getFileFormatMeta() const {
111 return mFileMeta;
112}
113
Chong Zhangd354d8d2014-08-20 13:09:58 -0700114status_t NuPlayer::GenericSource::initFromDataSource() {
Lajos Molnarcc227032014-07-17 15:33:06 -0700115 sp<MediaExtractor> extractor;
116
Chong Zhangd354d8d2014-08-20 13:09:58 -0700117 CHECK(mDataSource != NULL);
118
Lajos Molnarcc227032014-07-17 15:33:06 -0700119 if (mIsWidevine) {
120 String8 mimeType;
121 float confidence;
122 sp<AMessage> dummy;
123 bool success;
124
Chong Zhangd354d8d2014-08-20 13:09:58 -0700125 success = SniffWVM(mDataSource, &mimeType, &confidence, &dummy);
Lajos Molnarcc227032014-07-17 15:33:06 -0700126 if (!success
127 || strcasecmp(
128 mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) {
129 ALOGE("unsupported widevine mime: %s", mimeType.string());
Chong Zhang3de157d2014-08-05 20:54:44 -0700130 return UNKNOWN_ERROR;
Lajos Molnarcc227032014-07-17 15:33:06 -0700131 }
132
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700133 mWVMExtractor = new WVMExtractor(mDataSource);
134 mWVMExtractor->setAdaptiveStreamingMode(true);
Lajos Molnarcc227032014-07-17 15:33:06 -0700135 if (mUIDValid) {
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700136 mWVMExtractor->setUID(mUID);
Lajos Molnarcc227032014-07-17 15:33:06 -0700137 }
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700138 extractor = mWVMExtractor;
Lajos Molnarcc227032014-07-17 15:33:06 -0700139 } else {
Chong Zhangd354d8d2014-08-20 13:09:58 -0700140 extractor = MediaExtractor::Create(mDataSource,
141 mSniffedMIME.empty() ? NULL: mSniffedMIME.c_str());
Lajos Molnarcc227032014-07-17 15:33:06 -0700142 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700143
Chong Zhang3de157d2014-08-05 20:54:44 -0700144 if (extractor == NULL) {
145 return UNKNOWN_ERROR;
146 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700147
Ronghua Wu80276872014-08-28 15:50:29 -0700148 if (extractor->getDrmFlag()) {
149 checkDrmStatus(mDataSource);
150 }
151
Marco Nelissenf0b72b52014-09-16 15:43:44 -0700152 mFileMeta = extractor->getMetaData();
153 if (mFileMeta != NULL) {
Marco Nelissenc1f4b2b2014-06-17 14:48:32 -0700154 int64_t duration;
Marco Nelissenf0b72b52014-09-16 15:43:44 -0700155 if (mFileMeta->findInt64(kKeyDuration, &duration)) {
Marco Nelissenc1f4b2b2014-06-17 14:48:32 -0700156 mDurationUs = duration;
157 }
158 }
159
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700160 int32_t totalBitrate = 0;
161
Marco Nelissen705d3292014-09-19 15:14:37 -0700162 size_t numtracks = extractor->countTracks();
163 if (numtracks == 0) {
164 return UNKNOWN_ERROR;
165 }
166
167 for (size_t i = 0; i < numtracks; ++i) {
Chong Zhangafc0a872014-08-26 09:56:52 -0700168 sp<MediaSource> track = extractor->getTrack(i);
169
Andreas Huberafed0e12011-09-20 15:39:58 -0700170 sp<MetaData> meta = extractor->getTrackMetaData(i);
171
172 const char *mime;
173 CHECK(meta->findCString(kKeyMIMEType, &mime));
174
Chong Zhangafc0a872014-08-26 09:56:52 -0700175 // Do the string compare immediately with "mime",
176 // we can't assume "mime" would stay valid after another
177 // extractor operation, some extractors might modify meta
178 // during getTrack() and make it invalid.
Andreas Huberafed0e12011-09-20 15:39:58 -0700179 if (!strncasecmp(mime, "audio/", 6)) {
180 if (mAudioTrack.mSource == NULL) {
Robert Shihdd235722014-06-12 14:49:23 -0700181 mAudioTrack.mIndex = i;
182 mAudioTrack.mSource = track;
Robert Shihaf52c1a2014-09-11 15:38:54 -0700183 mAudioTrack.mPackets =
184 new AnotherPacketSource(mAudioTrack.mSource->getFormat());
Andreas Huberafed0e12011-09-20 15:39:58 -0700185
186 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
187 mAudioIsVorbis = true;
188 } else {
189 mAudioIsVorbis = false;
190 }
191 }
192 } else if (!strncasecmp(mime, "video/", 6)) {
193 if (mVideoTrack.mSource == NULL) {
Robert Shihdd235722014-06-12 14:49:23 -0700194 mVideoTrack.mIndex = i;
195 mVideoTrack.mSource = track;
Robert Shihaf52c1a2014-09-11 15:38:54 -0700196 mVideoTrack.mPackets =
197 new AnotherPacketSource(mVideoTrack.mSource->getFormat());
Chong Zhang7e892182014-08-05 11:58:21 -0700198
199 // check if the source requires secure buffers
200 int32_t secure;
Chong Zhanga19f33e2014-08-07 15:35:07 -0700201 if (meta->findInt32(kKeyRequiresSecureBuffers, &secure)
202 && secure) {
Chong Zhang7e892182014-08-05 11:58:21 -0700203 mIsWidevine = true;
Chong Zhang3de157d2014-08-05 20:54:44 -0700204 if (mUIDValid) {
205 extractor->setUID(mUID);
206 }
Chong Zhang7e892182014-08-05 11:58:21 -0700207 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700208 }
209 }
210
211 if (track != NULL) {
Robert Shihdd235722014-06-12 14:49:23 -0700212 mSources.push(track);
Andreas Huberafed0e12011-09-20 15:39:58 -0700213 int64_t durationUs;
214 if (meta->findInt64(kKeyDuration, &durationUs)) {
215 if (durationUs > mDurationUs) {
216 mDurationUs = durationUs;
217 }
218 }
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700219
220 int32_t bitrate;
221 if (totalBitrate >= 0 && meta->findInt32(kKeyBitRate, &bitrate)) {
222 totalBitrate += bitrate;
223 } else {
224 totalBitrate = -1;
225 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700226 }
227 }
Chong Zhang3de157d2014-08-05 20:54:44 -0700228
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700229 mBitrate = totalBitrate;
230
Chong Zhang3de157d2014-08-05 20:54:44 -0700231 return OK;
Andreas Huberafed0e12011-09-20 15:39:58 -0700232}
233
Ronghua Wu80276872014-08-28 15:50:29 -0700234void NuPlayer::GenericSource::checkDrmStatus(const sp<DataSource>& dataSource) {
235 dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
236 if (mDecryptHandle != NULL) {
237 CHECK(mDrmManagerClient);
238 if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
239 sp<AMessage> msg = dupNotify();
240 msg->setInt32("what", kWhatDrmNoLicense);
241 msg->post();
242 }
243 }
244}
245
246int64_t NuPlayer::GenericSource::getLastReadPosition() {
247 if (mAudioTrack.mSource != NULL) {
248 return mAudioTimeUs;
249 } else if (mVideoTrack.mSource != NULL) {
250 return mVideoTimeUs;
251 } else {
252 return 0;
253 }
254}
255
Chong Zhanga19f33e2014-08-07 15:35:07 -0700256status_t NuPlayer::GenericSource::setBuffers(
257 bool audio, Vector<MediaBuffer *> &buffers) {
Lajos Molnarcc227032014-07-17 15:33:06 -0700258 if (mIsWidevine && !audio) {
259 return mVideoTrack.mSource->setBuffers(buffers);
260 }
261 return INVALID_OPERATION;
262}
263
Andreas Huberafed0e12011-09-20 15:39:58 -0700264NuPlayer::GenericSource::~GenericSource() {
Chong Zhang1228d6b2014-08-12 21:25:48 -0700265 if (mLooper != NULL) {
266 mLooper->unregisterHandler(id());
267 mLooper->stop();
268 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700269}
270
Andreas Huber9575c962013-02-05 13:59:56 -0800271void NuPlayer::GenericSource::prepareAsync() {
Chong Zhang1228d6b2014-08-12 21:25:48 -0700272 if (mLooper == NULL) {
273 mLooper = new ALooper;
274 mLooper->setName("generic");
275 mLooper->start();
276
277 mLooper->registerHandler(this);
278 }
279
280 sp<AMessage> msg = new AMessage(kWhatPrepareAsync, id());
281 msg->post();
282}
283
284void NuPlayer::GenericSource::onPrepareAsync() {
Chong Zhanga19f33e2014-08-07 15:35:07 -0700285 // delayed data source creation
Chong Zhangd354d8d2014-08-20 13:09:58 -0700286 if (mDataSource == NULL) {
287 if (!mUri.empty()) {
288 mIsWidevine = !strncasecmp(mUri.c_str(), "widevine://", 11);
Chong Zhanga19f33e2014-08-07 15:35:07 -0700289
Chong Zhangd354d8d2014-08-20 13:09:58 -0700290 mDataSource = DataSource::CreateFromURI(
291 mHTTPService, mUri.c_str(), &mUriHeaders, &mContentType);
292 } else {
293 // set to false first, if the extractor
294 // comes back as secure, set it to true then.
295 mIsWidevine = false;
Chong Zhanga19f33e2014-08-07 15:35:07 -0700296
Chong Zhangd354d8d2014-08-20 13:09:58 -0700297 mDataSource = new FileSource(mFd, mOffset, mLength);
298 }
Chong Zhanga19f33e2014-08-07 15:35:07 -0700299
Chong Zhangd354d8d2014-08-20 13:09:58 -0700300 if (mDataSource == NULL) {
301 ALOGE("Failed to create data source!");
302 notifyPreparedAndCleanup(UNKNOWN_ERROR);
303 return;
304 }
305
306 if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
307 mCachedSource = static_cast<NuCachedSource2 *>(mDataSource.get());
308 }
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700309
310 if (mIsWidevine || mCachedSource != NULL) {
311 schedulePollBuffering();
312 }
Chong Zhanga19f33e2014-08-07 15:35:07 -0700313 }
314
Chong Zhangd354d8d2014-08-20 13:09:58 -0700315 // check initial caching status
316 status_t err = prefillCacheIfNecessary();
317 if (err != OK) {
318 if (err == -EAGAIN) {
319 (new AMessage(kWhatPrepareAsync, id()))->post(200000);
320 } else {
321 ALOGE("Failed to prefill data cache!");
322 notifyPreparedAndCleanup(UNKNOWN_ERROR);
323 }
Chong Zhanga19f33e2014-08-07 15:35:07 -0700324 return;
325 }
326
Chong Zhangd354d8d2014-08-20 13:09:58 -0700327 // init extrator from data source
328 err = initFromDataSource();
Chong Zhanga19f33e2014-08-07 15:35:07 -0700329
330 if (err != OK) {
331 ALOGE("Failed to init from data source!");
Chong Zhangd354d8d2014-08-20 13:09:58 -0700332 notifyPreparedAndCleanup(err);
Chong Zhanga19f33e2014-08-07 15:35:07 -0700333 return;
334 }
335
Andreas Huber9575c962013-02-05 13:59:56 -0800336 if (mVideoTrack.mSource != NULL) {
Robert Shih17f6dd62014-08-20 17:00:21 -0700337 sp<MetaData> meta = doGetFormatMeta(false /* audio */);
338 sp<AMessage> msg = new AMessage;
339 err = convertMetaDataToMessage(meta, &msg);
340 if(err != OK) {
341 notifyPreparedAndCleanup(err);
342 return;
343 }
344 notifyVideoSizeChanged(msg);
Andreas Huber9575c962013-02-05 13:59:56 -0800345 }
346
347 notifyFlagsChanged(
Lajos Molnarcc227032014-07-17 15:33:06 -0700348 (mIsWidevine ? FLAG_SECURE : 0)
349 | FLAG_CAN_PAUSE
Andreas Huber9575c962013-02-05 13:59:56 -0800350 | FLAG_CAN_SEEK_BACKWARD
351 | FLAG_CAN_SEEK_FORWARD
352 | FLAG_CAN_SEEK);
353
354 notifyPrepared();
355}
356
Chong Zhangd354d8d2014-08-20 13:09:58 -0700357void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) {
358 if (err != OK) {
359 mMetaDataSize = -1ll;
360 mContentType = "";
361 mSniffedMIME = "";
362 mDataSource.clear();
363 mCachedSource.clear();
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700364
365 cancelPollBuffering();
Chong Zhangd354d8d2014-08-20 13:09:58 -0700366 }
367 notifyPrepared(err);
368}
369
370status_t NuPlayer::GenericSource::prefillCacheIfNecessary() {
371 CHECK(mDataSource != NULL);
372
373 if (mCachedSource == NULL) {
374 // no prefill if the data source is not cached
375 return OK;
376 }
377
378 // We're not doing this for streams that appear to be audio-only
379 // streams to ensure that even low bandwidth streams start
380 // playing back fairly instantly.
381 if (!strncasecmp(mContentType.string(), "audio/", 6)) {
382 return OK;
383 }
384
385 // We're going to prefill the cache before trying to instantiate
386 // the extractor below, as the latter is an operation that otherwise
387 // could block on the datasource for a significant amount of time.
388 // During that time we'd be unable to abort the preparation phase
389 // without this prefill.
390
391 // Initially make sure we have at least 192 KB for the sniff
392 // to complete without blocking.
393 static const size_t kMinBytesForSniffing = 192 * 1024;
394 static const size_t kDefaultMetaSize = 200000;
395
396 status_t finalStatus;
397
398 size_t cachedDataRemaining =
399 mCachedSource->approxDataRemaining(&finalStatus);
400
401 if (finalStatus != OK || (mMetaDataSize >= 0
402 && (off64_t)cachedDataRemaining >= mMetaDataSize)) {
403 ALOGV("stop caching, status %d, "
404 "metaDataSize %lld, cachedDataRemaining %zu",
405 finalStatus, mMetaDataSize, cachedDataRemaining);
406 return OK;
407 }
408
409 ALOGV("now cached %zu bytes of data", cachedDataRemaining);
410
411 if (mMetaDataSize < 0
412 && cachedDataRemaining >= kMinBytesForSniffing) {
413 String8 tmp;
414 float confidence;
415 sp<AMessage> meta;
416 if (!mCachedSource->sniff(&tmp, &confidence, &meta)) {
417 return UNKNOWN_ERROR;
418 }
419
420 // We successfully identified the file's extractor to
421 // be, remember this mime type so we don't have to
422 // sniff it again when we call MediaExtractor::Create()
423 mSniffedMIME = tmp.string();
424
425 if (meta == NULL
426 || !meta->findInt64("meta-data-size",
427 reinterpret_cast<int64_t*>(&mMetaDataSize))) {
428 mMetaDataSize = kDefaultMetaSize;
429 }
430
431 if (mMetaDataSize < 0ll) {
432 ALOGE("invalid metaDataSize = %lld bytes", mMetaDataSize);
433 return UNKNOWN_ERROR;
434 }
435 }
436
437 return -EAGAIN;
438}
439
Andreas Huberafed0e12011-09-20 15:39:58 -0700440void NuPlayer::GenericSource::start() {
441 ALOGI("start");
442
Andy Hung2abde2c2014-09-30 14:40:32 -0700443 mStopRead = false;
Andreas Huberafed0e12011-09-20 15:39:58 -0700444 if (mAudioTrack.mSource != NULL) {
Robert Shihbace25b2014-07-25 14:14:34 -0700445 CHECK_EQ(mAudioTrack.mSource->start(), (status_t)OK);
Andreas Huberafed0e12011-09-20 15:39:58 -0700446
Robert Shih17f6dd62014-08-20 17:00:21 -0700447 postReadBuffer(MEDIA_TRACK_TYPE_AUDIO);
Andreas Huberafed0e12011-09-20 15:39:58 -0700448 }
449
450 if (mVideoTrack.mSource != NULL) {
Robert Shihbace25b2014-07-25 14:14:34 -0700451 CHECK_EQ(mVideoTrack.mSource->start(), (status_t)OK);
Andreas Huberafed0e12011-09-20 15:39:58 -0700452
Robert Shih17f6dd62014-08-20 17:00:21 -0700453 postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
Andreas Huberafed0e12011-09-20 15:39:58 -0700454 }
Ronghua Wu80276872014-08-28 15:50:29 -0700455
456 setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000);
457 mStarted = true;
458}
459
460void NuPlayer::GenericSource::stop() {
461 // nothing to do, just account for DRM playback status
462 setDrmPlaybackStatusIfNeeded(Playback::STOP, 0);
463 mStarted = false;
Andy Hung2abde2c2014-09-30 14:40:32 -0700464 if (mIsWidevine) {
465 // For a widevine source we need to prevent any further reads.
466 sp<AMessage> msg = new AMessage(kWhatStopWidevine, id());
467 sp<AMessage> response;
468 (void) msg->postAndAwaitResponse(&response);
469 }
Ronghua Wu80276872014-08-28 15:50:29 -0700470}
471
472void NuPlayer::GenericSource::pause() {
473 // nothing to do, just account for DRM playback status
474 setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0);
475 mStarted = false;
476}
477
478void NuPlayer::GenericSource::resume() {
479 // nothing to do, just account for DRM playback status
480 setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000);
481 mStarted = true;
482}
483
Chong Zhang48296b72014-09-14 14:28:45 -0700484void NuPlayer::GenericSource::disconnect() {
485 if (mDataSource != NULL) {
486 // disconnect data source
487 if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
488 static_cast<NuCachedSource2 *>(mDataSource.get())->disconnect();
489 }
490 }
491}
492
Ronghua Wu80276872014-08-28 15:50:29 -0700493void NuPlayer::GenericSource::setDrmPlaybackStatusIfNeeded(int playbackStatus, int64_t position) {
494 if (mDecryptHandle != NULL) {
495 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, playbackStatus, position);
496 }
Robert Shih17f6dd62014-08-20 17:00:21 -0700497 mSubtitleTrack.mPackets = new AnotherPacketSource(NULL);
498 mTimedTextTrack.mPackets = new AnotherPacketSource(NULL);
Andreas Huberafed0e12011-09-20 15:39:58 -0700499}
500
501status_t NuPlayer::GenericSource::feedMoreTSData() {
502 return OK;
503}
504
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700505void NuPlayer::GenericSource::schedulePollBuffering() {
506 sp<AMessage> msg = new AMessage(kWhatPollBuffering, id());
507 msg->setInt32("generation", mPollBufferingGeneration);
508 msg->post(1000000ll);
509}
510
511void NuPlayer::GenericSource::cancelPollBuffering() {
512 ++mPollBufferingGeneration;
513}
514
515void NuPlayer::GenericSource::notifyBufferingUpdate(int percentage) {
516 sp<AMessage> msg = dupNotify();
517 msg->setInt32("what", kWhatBufferingUpdate);
518 msg->setInt32("percentage", percentage);
519 msg->post();
520}
521
522void NuPlayer::GenericSource::onPollBuffering() {
523 status_t finalStatus = UNKNOWN_ERROR;
524 int64_t cachedDurationUs = 0ll;
525
526 if (mCachedSource != NULL) {
527 size_t cachedDataRemaining =
528 mCachedSource->approxDataRemaining(&finalStatus);
529
530 if (finalStatus == OK) {
531 off64_t size;
532 int64_t bitrate = 0ll;
533 if (mDurationUs > 0 && mCachedSource->getSize(&size) == OK) {
534 bitrate = size * 8000000ll / mDurationUs;
535 } else if (mBitrate > 0) {
536 bitrate = mBitrate;
537 }
538 if (bitrate > 0) {
539 cachedDurationUs = cachedDataRemaining * 8000000ll / bitrate;
540 }
541 }
542 } else if (mWVMExtractor != NULL) {
543 cachedDurationUs
544 = mWVMExtractor->getCachedDurationUs(&finalStatus);
545 }
546
547 if (finalStatus == ERROR_END_OF_STREAM) {
548 notifyBufferingUpdate(100);
549 cancelPollBuffering();
550 return;
551 } else if (cachedDurationUs > 0ll && mDurationUs > 0ll) {
552 int percentage = 100.0 * cachedDurationUs / mDurationUs;
553 if (percentage > 100) {
554 percentage = 100;
555 }
556
557 notifyBufferingUpdate(percentage);
558 }
559
560 schedulePollBuffering();
561}
562
563
Robert Shih3423bbd2014-07-16 15:47:09 -0700564void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) {
565 switch (msg->what()) {
Chong Zhang1228d6b2014-08-12 21:25:48 -0700566 case kWhatPrepareAsync:
567 {
568 onPrepareAsync();
569 break;
570 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700571 case kWhatFetchSubtitleData:
572 {
Lajos Molnare26940f2014-07-31 10:31:26 -0700573 fetchTextData(kWhatSendSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
574 mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
575 break;
576 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700577
Lajos Molnare26940f2014-07-31 10:31:26 -0700578 case kWhatFetchTimedTextData:
579 {
580 fetchTextData(kWhatSendTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
581 mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
Robert Shih3423bbd2014-07-16 15:47:09 -0700582 break;
583 }
584
585 case kWhatSendSubtitleData:
586 {
Lajos Molnare26940f2014-07-31 10:31:26 -0700587 sendTextData(kWhatSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
588 mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
589 break;
590 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700591
Lajos Molnare26940f2014-07-31 10:31:26 -0700592 case kWhatSendTimedTextData:
593 {
594 sendTextData(kWhatTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
595 mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
Robert Shih3423bbd2014-07-16 15:47:09 -0700596 break;
597 }
598
599 case kWhatChangeAVSource:
600 {
601 int32_t trackIndex;
602 CHECK(msg->findInt32("trackIndex", &trackIndex));
603 const sp<MediaSource> source = mSources.itemAt(trackIndex);
604
605 Track* track;
606 const char *mime;
607 media_track_type trackType, counterpartType;
608 sp<MetaData> meta = source->getFormat();
609 meta->findCString(kKeyMIMEType, &mime);
610 if (!strncasecmp(mime, "audio/", 6)) {
611 track = &mAudioTrack;
612 trackType = MEDIA_TRACK_TYPE_AUDIO;
613 counterpartType = MEDIA_TRACK_TYPE_VIDEO;;
614 } else {
615 CHECK(!strncasecmp(mime, "video/", 6));
616 track = &mVideoTrack;
617 trackType = MEDIA_TRACK_TYPE_VIDEO;
618 counterpartType = MEDIA_TRACK_TYPE_AUDIO;;
619 }
620
621
622 if (track->mSource != NULL) {
623 track->mSource->stop();
624 }
625 track->mSource = source;
626 track->mSource->start();
627 track->mIndex = trackIndex;
628
629 status_t avail;
630 if (!track->mPackets->hasBufferAvailable(&avail)) {
631 // sync from other source
632 TRESPASS();
633 break;
634 }
635
636 int64_t timeUs, actualTimeUs;
637 const bool formatChange = true;
Robert Shih309aa8b2014-07-29 18:34:36 -0700638 sp<AMessage> latestMeta = track->mPackets->getLatestEnqueuedMeta();
Robert Shih3423bbd2014-07-16 15:47:09 -0700639 CHECK(latestMeta != NULL && latestMeta->findInt64("timeUs", &timeUs));
640 readBuffer(trackType, timeUs, &actualTimeUs, formatChange);
641 readBuffer(counterpartType, -1, NULL, formatChange);
642 ALOGV("timeUs %lld actualTimeUs %lld", timeUs, actualTimeUs);
643
644 break;
645 }
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700646 case kWhatPollBuffering:
647 {
648 int32_t generation;
649 CHECK(msg->findInt32("generation", &generation));
650 if (generation == mPollBufferingGeneration) {
651 onPollBuffering();
652 }
653 break;
654 }
Robert Shih17f6dd62014-08-20 17:00:21 -0700655
656 case kWhatGetFormat:
657 {
658 onGetFormatMeta(msg);
659 break;
660 }
661
662 case kWhatGetSelectedTrack:
663 {
664 onGetSelectedTrack(msg);
665 break;
666 }
667
668 case kWhatSelectTrack:
669 {
670 onSelectTrack(msg);
671 break;
672 }
673
674 case kWhatSeek:
675 {
676 onSeek(msg);
677 break;
678 }
679
680 case kWhatReadBuffer:
681 {
682 onReadBuffer(msg);
683 break;
684 }
685
Andy Hung2abde2c2014-09-30 14:40:32 -0700686 case kWhatStopWidevine:
687 {
688 // mStopRead is only used for Widevine to prevent the video source
689 // from being read while the associated video decoder is shutting down.
690 mStopRead = true;
691 if (mVideoTrack.mSource != NULL) {
692 mVideoTrack.mPackets->clear();
693 }
694 sp<AMessage> response = new AMessage;
695 uint32_t replyID;
696 CHECK(msg->senderAwaitsResponse(&replyID));
697 response->postReply(replyID);
698 break;
699 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700700 default:
701 Source::onMessageReceived(msg);
702 break;
703 }
704}
705
Lajos Molnare26940f2014-07-31 10:31:26 -0700706void NuPlayer::GenericSource::fetchTextData(
707 uint32_t sendWhat,
708 media_track_type type,
709 int32_t curGen,
710 sp<AnotherPacketSource> packets,
711 sp<AMessage> msg) {
712 int32_t msgGeneration;
713 CHECK(msg->findInt32("generation", &msgGeneration));
714 if (msgGeneration != curGen) {
715 // stale
716 return;
717 }
718
719 int32_t avail;
720 if (packets->hasBufferAvailable(&avail)) {
721 return;
722 }
723
724 int64_t timeUs;
725 CHECK(msg->findInt64("timeUs", &timeUs));
726
727 int64_t subTimeUs;
728 readBuffer(type, timeUs, &subTimeUs);
729
730 int64_t delayUs = subTimeUs - timeUs;
731 if (msg->what() == kWhatFetchSubtitleData) {
732 const int64_t oneSecUs = 1000000ll;
733 delayUs -= oneSecUs;
734 }
735 sp<AMessage> msg2 = new AMessage(sendWhat, id());
736 msg2->setInt32("generation", msgGeneration);
737 msg2->post(delayUs < 0 ? 0 : delayUs);
738}
739
740void NuPlayer::GenericSource::sendTextData(
741 uint32_t what,
742 media_track_type type,
743 int32_t curGen,
744 sp<AnotherPacketSource> packets,
745 sp<AMessage> msg) {
746 int32_t msgGeneration;
747 CHECK(msg->findInt32("generation", &msgGeneration));
748 if (msgGeneration != curGen) {
749 // stale
750 return;
751 }
752
753 int64_t subTimeUs;
754 if (packets->nextBufferTime(&subTimeUs) != OK) {
755 return;
756 }
757
758 int64_t nextSubTimeUs;
759 readBuffer(type, -1, &nextSubTimeUs);
760
761 sp<ABuffer> buffer;
762 status_t dequeueStatus = packets->dequeueAccessUnit(&buffer);
763 if (dequeueStatus == OK) {
764 sp<AMessage> notify = dupNotify();
765 notify->setInt32("what", what);
766 notify->setBuffer("buffer", buffer);
767 notify->post();
768
769 const int64_t delayUs = nextSubTimeUs - subTimeUs;
770 msg->post(delayUs < 0 ? 0 : delayUs);
771 }
772}
773
Andreas Huber84066782011-08-16 09:34:26 -0700774sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
Robert Shih17f6dd62014-08-20 17:00:21 -0700775 sp<AMessage> msg = new AMessage(kWhatGetFormat, id());
776 msg->setInt32("audio", audio);
777
778 sp<AMessage> response;
779 void *format;
780 status_t err = msg->postAndAwaitResponse(&response);
781 if (err == OK && response != NULL) {
782 CHECK(response->findPointer("format", &format));
783 return (MetaData *)format;
784 } else {
785 return NULL;
786 }
787}
788
789void NuPlayer::GenericSource::onGetFormatMeta(sp<AMessage> msg) const {
790 int32_t audio;
791 CHECK(msg->findInt32("audio", &audio));
792
793 sp<AMessage> response = new AMessage;
794 sp<MetaData> format = doGetFormatMeta(audio);
795 response->setPointer("format", format.get());
796
797 uint32_t replyID;
798 CHECK(msg->senderAwaitsResponse(&replyID));
799 response->postReply(replyID);
800}
801
802sp<MetaData> NuPlayer::GenericSource::doGetFormatMeta(bool audio) const {
Andreas Huberafed0e12011-09-20 15:39:58 -0700803 sp<MediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
804
805 if (source == NULL) {
806 return NULL;
807 }
808
809 return source->getFormat();
810}
811
812status_t NuPlayer::GenericSource::dequeueAccessUnit(
813 bool audio, sp<ABuffer> *accessUnit) {
814 Track *track = audio ? &mAudioTrack : &mVideoTrack;
815
816 if (track->mSource == NULL) {
817 return -EWOULDBLOCK;
818 }
819
Lajos Molnarcc227032014-07-17 15:33:06 -0700820 if (mIsWidevine && !audio) {
821 // try to read a buffer as we may not have been able to the last time
Robert Shih17f6dd62014-08-20 17:00:21 -0700822 postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
Lajos Molnarcc227032014-07-17 15:33:06 -0700823 }
824
Andreas Huberafed0e12011-09-20 15:39:58 -0700825 status_t finalResult;
826 if (!track->mPackets->hasBufferAvailable(&finalResult)) {
Lajos Molnarcc227032014-07-17 15:33:06 -0700827 return (finalResult == OK ? -EWOULDBLOCK : finalResult);
Andreas Huberafed0e12011-09-20 15:39:58 -0700828 }
829
830 status_t result = track->mPackets->dequeueAccessUnit(accessUnit);
831
Robert Shih3423bbd2014-07-16 15:47:09 -0700832 if (!track->mPackets->hasBufferAvailable(&finalResult)) {
Robert Shih17f6dd62014-08-20 17:00:21 -0700833 postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
Lajos Molnare26940f2014-07-31 10:31:26 -0700834 }
835
Robert Shih3423bbd2014-07-16 15:47:09 -0700836 if (result != OK) {
Lajos Molnare26940f2014-07-31 10:31:26 -0700837 if (mSubtitleTrack.mSource != NULL) {
838 mSubtitleTrack.mPackets->clear();
839 mFetchSubtitleDataGeneration++;
840 }
841 if (mTimedTextTrack.mSource != NULL) {
842 mTimedTextTrack.mPackets->clear();
843 mFetchTimedTextDataGeneration++;
844 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700845 return result;
846 }
847
848 int64_t timeUs;
849 status_t eosResult; // ignored
850 CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs));
Lajos Molnare26940f2014-07-31 10:31:26 -0700851
852 if (mSubtitleTrack.mSource != NULL
853 && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
Robert Shih3423bbd2014-07-16 15:47:09 -0700854 sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, id());
855 msg->setInt64("timeUs", timeUs);
856 msg->setInt32("generation", mFetchSubtitleDataGeneration);
857 msg->post();
858 }
Robert Shiheb1735e2014-07-23 15:53:14 -0700859
Lajos Molnare26940f2014-07-31 10:31:26 -0700860 if (mTimedTextTrack.mSource != NULL
861 && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
862 sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, id());
863 msg->setInt64("timeUs", timeUs);
864 msg->setInt32("generation", mFetchTimedTextDataGeneration);
865 msg->post();
866 }
867
Andreas Huberafed0e12011-09-20 15:39:58 -0700868 return result;
869}
870
871status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) {
872 *durationUs = mDurationUs;
873 return OK;
874}
875
Robert Shihdd235722014-06-12 14:49:23 -0700876size_t NuPlayer::GenericSource::getTrackCount() const {
877 return mSources.size();
878}
879
880sp<AMessage> NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const {
881 size_t trackCount = mSources.size();
882 if (trackIndex >= trackCount) {
883 return NULL;
884 }
885
886 sp<AMessage> format = new AMessage();
887 sp<MetaData> meta = mSources.itemAt(trackIndex)->getFormat();
888
889 const char *mime;
890 CHECK(meta->findCString(kKeyMIMEType, &mime));
891
892 int32_t trackType;
893 if (!strncasecmp(mime, "video/", 6)) {
894 trackType = MEDIA_TRACK_TYPE_VIDEO;
895 } else if (!strncasecmp(mime, "audio/", 6)) {
896 trackType = MEDIA_TRACK_TYPE_AUDIO;
897 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
898 trackType = MEDIA_TRACK_TYPE_TIMEDTEXT;
899 } else {
900 trackType = MEDIA_TRACK_TYPE_UNKNOWN;
901 }
902 format->setInt32("type", trackType);
903
904 const char *lang;
905 if (!meta->findCString(kKeyMediaLanguage, &lang)) {
906 lang = "und";
907 }
908 format->setString("language", lang);
909
910 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
911 format->setString("mime", mime);
912
913 int32_t isAutoselect = 1, isDefault = 0, isForced = 0;
914 meta->findInt32(kKeyTrackIsAutoselect, &isAutoselect);
915 meta->findInt32(kKeyTrackIsDefault, &isDefault);
916 meta->findInt32(kKeyTrackIsForced, &isForced);
917
918 format->setInt32("auto", !!isAutoselect);
919 format->setInt32("default", !!isDefault);
920 format->setInt32("forced", !!isForced);
921 }
922
923 return format;
924}
925
Lajos Molnare26940f2014-07-31 10:31:26 -0700926ssize_t NuPlayer::GenericSource::getSelectedTrack(media_track_type type) const {
Robert Shih17f6dd62014-08-20 17:00:21 -0700927 sp<AMessage> msg = new AMessage(kWhatGetSelectedTrack, id());
928 msg->setInt32("type", type);
929
930 sp<AMessage> response;
931 int32_t index;
932 status_t err = msg->postAndAwaitResponse(&response);
933 if (err == OK && response != NULL) {
934 CHECK(response->findInt32("index", &index));
935 return index;
936 } else {
937 return -1;
938 }
939}
940
941void NuPlayer::GenericSource::onGetSelectedTrack(sp<AMessage> msg) const {
942 int32_t tmpType;
943 CHECK(msg->findInt32("type", &tmpType));
944 media_track_type type = (media_track_type)tmpType;
945
946 sp<AMessage> response = new AMessage;
947 ssize_t index = doGetSelectedTrack(type);
948 response->setInt32("index", index);
949
950 uint32_t replyID;
951 CHECK(msg->senderAwaitsResponse(&replyID));
952 response->postReply(replyID);
953}
954
955ssize_t NuPlayer::GenericSource::doGetSelectedTrack(media_track_type type) const {
Lajos Molnare26940f2014-07-31 10:31:26 -0700956 const Track *track = NULL;
957 switch (type) {
958 case MEDIA_TRACK_TYPE_VIDEO:
959 track = &mVideoTrack;
960 break;
961 case MEDIA_TRACK_TYPE_AUDIO:
962 track = &mAudioTrack;
963 break;
964 case MEDIA_TRACK_TYPE_TIMEDTEXT:
965 track = &mTimedTextTrack;
966 break;
967 case MEDIA_TRACK_TYPE_SUBTITLE:
968 track = &mSubtitleTrack;
969 break;
970 default:
971 break;
972 }
973
974 if (track != NULL && track->mSource != NULL) {
975 return track->mIndex;
976 }
977
978 return -1;
979}
980
Robert Shih3423bbd2014-07-16 15:47:09 -0700981status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select) {
Lajos Molnare26940f2014-07-31 10:31:26 -0700982 ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex);
Robert Shih17f6dd62014-08-20 17:00:21 -0700983 sp<AMessage> msg = new AMessage(kWhatSelectTrack, id());
984 msg->setInt32("trackIndex", trackIndex);
Robert Shihda23ab92014-09-16 11:34:08 -0700985 msg->setInt32("select", select);
Robert Shih17f6dd62014-08-20 17:00:21 -0700986
987 sp<AMessage> response;
988 status_t err = msg->postAndAwaitResponse(&response);
989 if (err == OK && response != NULL) {
990 CHECK(response->findInt32("err", &err));
991 }
992
993 return err;
994}
995
996void NuPlayer::GenericSource::onSelectTrack(sp<AMessage> msg) {
997 int32_t trackIndex, select;
998 CHECK(msg->findInt32("trackIndex", &trackIndex));
999 CHECK(msg->findInt32("select", &select));
1000
1001 sp<AMessage> response = new AMessage;
1002 status_t err = doSelectTrack(trackIndex, select);
1003 response->setInt32("err", err);
1004
1005 uint32_t replyID;
1006 CHECK(msg->senderAwaitsResponse(&replyID));
1007 response->postReply(replyID);
1008}
1009
1010status_t NuPlayer::GenericSource::doSelectTrack(size_t trackIndex, bool select) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001011 if (trackIndex >= mSources.size()) {
1012 return BAD_INDEX;
1013 }
1014
1015 if (!select) {
Lajos Molnare26940f2014-07-31 10:31:26 -07001016 Track* track = NULL;
1017 if (mSubtitleTrack.mSource != NULL && trackIndex == mSubtitleTrack.mIndex) {
1018 track = &mSubtitleTrack;
1019 mFetchSubtitleDataGeneration++;
1020 } else if (mTimedTextTrack.mSource != NULL && trackIndex == mTimedTextTrack.mIndex) {
1021 track = &mTimedTextTrack;
1022 mFetchTimedTextDataGeneration++;
1023 }
1024 if (track == NULL) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001025 return INVALID_OPERATION;
1026 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001027 track->mSource->stop();
1028 track->mSource = NULL;
1029 track->mPackets->clear();
Robert Shih3423bbd2014-07-16 15:47:09 -07001030 return OK;
1031 }
1032
1033 const sp<MediaSource> source = mSources.itemAt(trackIndex);
1034 sp<MetaData> meta = source->getFormat();
1035 const char *mime;
1036 CHECK(meta->findCString(kKeyMIMEType, &mime));
1037 if (!strncasecmp(mime, "text/", 5)) {
Lajos Molnare26940f2014-07-31 10:31:26 -07001038 bool isSubtitle = strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP);
1039 Track *track = isSubtitle ? &mSubtitleTrack : &mTimedTextTrack;
1040 if (track->mSource != NULL && track->mIndex == trackIndex) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001041 return OK;
1042 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001043 track->mIndex = trackIndex;
1044 if (track->mSource != NULL) {
1045 track->mSource->stop();
Robert Shih3423bbd2014-07-16 15:47:09 -07001046 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001047 track->mSource = mSources.itemAt(trackIndex);
1048 track->mSource->start();
1049 if (track->mPackets == NULL) {
1050 track->mPackets = new AnotherPacketSource(track->mSource->getFormat());
Robert Shih3423bbd2014-07-16 15:47:09 -07001051 } else {
Lajos Molnare26940f2014-07-31 10:31:26 -07001052 track->mPackets->clear();
1053 track->mPackets->setFormat(track->mSource->getFormat());
Robert Shih3423bbd2014-07-16 15:47:09 -07001054
1055 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001056
1057 if (isSubtitle) {
1058 mFetchSubtitleDataGeneration++;
1059 } else {
1060 mFetchTimedTextDataGeneration++;
1061 }
1062
Robert Shih3423bbd2014-07-16 15:47:09 -07001063 return OK;
1064 } else if (!strncasecmp(mime, "audio/", 6) || !strncasecmp(mime, "video/", 6)) {
1065 bool audio = !strncasecmp(mime, "audio/", 6);
1066 Track *track = audio ? &mAudioTrack : &mVideoTrack;
1067 if (track->mSource != NULL && track->mIndex == trackIndex) {
1068 return OK;
1069 }
1070
1071 sp<AMessage> msg = new AMessage(kWhatChangeAVSource, id());
1072 msg->setInt32("trackIndex", trackIndex);
1073 msg->post();
1074 return OK;
1075 }
1076
1077 return INVALID_OPERATION;
1078}
1079
Andreas Huberafed0e12011-09-20 15:39:58 -07001080status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) {
Robert Shih17f6dd62014-08-20 17:00:21 -07001081 sp<AMessage> msg = new AMessage(kWhatSeek, id());
1082 msg->setInt64("seekTimeUs", seekTimeUs);
1083
1084 sp<AMessage> response;
1085 status_t err = msg->postAndAwaitResponse(&response);
1086 if (err == OK && response != NULL) {
1087 CHECK(response->findInt32("err", &err));
1088 }
1089
1090 return err;
1091}
1092
1093void NuPlayer::GenericSource::onSeek(sp<AMessage> msg) {
1094 int64_t seekTimeUs;
1095 CHECK(msg->findInt64("seekTimeUs", &seekTimeUs));
1096
1097 sp<AMessage> response = new AMessage;
1098 status_t err = doSeek(seekTimeUs);
1099 response->setInt32("err", err);
1100
1101 uint32_t replyID;
1102 CHECK(msg->senderAwaitsResponse(&replyID));
1103 response->postReply(replyID);
1104}
1105
1106status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs) {
Andy Hung2abde2c2014-09-30 14:40:32 -07001107 // If the Widevine source is stopped, do not attempt to read any
1108 // more buffers.
1109 if (mStopRead) {
1110 return INVALID_OPERATION;
1111 }
Andreas Huberafed0e12011-09-20 15:39:58 -07001112 if (mVideoTrack.mSource != NULL) {
1113 int64_t actualTimeUs;
Robert Shih3423bbd2014-07-16 15:47:09 -07001114 readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, &actualTimeUs);
Andreas Huberafed0e12011-09-20 15:39:58 -07001115
1116 seekTimeUs = actualTimeUs;
1117 }
1118
1119 if (mAudioTrack.mSource != NULL) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001120 readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs);
Andreas Huberafed0e12011-09-20 15:39:58 -07001121 }
1122
Ronghua Wu80276872014-08-28 15:50:29 -07001123 setDrmPlaybackStatusIfNeeded(Playback::START, seekTimeUs / 1000);
1124 if (!mStarted) {
1125 setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0);
1126 }
Andreas Huberafed0e12011-09-20 15:39:58 -07001127 return OK;
1128}
1129
Robert Shih3423bbd2014-07-16 15:47:09 -07001130sp<ABuffer> NuPlayer::GenericSource::mediaBufferToABuffer(
1131 MediaBuffer* mb,
1132 media_track_type trackType,
1133 int64_t *actualTimeUs) {
1134 bool audio = trackType == MEDIA_TRACK_TYPE_AUDIO;
1135 size_t outLength = mb->range_length();
1136
1137 if (audio && mAudioIsVorbis) {
1138 outLength += sizeof(int32_t);
1139 }
1140
1141 sp<ABuffer> ab;
1142 if (mIsWidevine && !audio) {
1143 // data is already provided in the buffer
1144 ab = new ABuffer(NULL, mb->range_length());
Robert Shih3423bbd2014-07-16 15:47:09 -07001145 mb->add_ref();
Wei Jia96e92b52014-09-18 17:36:20 -07001146 ab->setMediaBufferBase(mb);
Robert Shih3423bbd2014-07-16 15:47:09 -07001147 } else {
1148 ab = new ABuffer(outLength);
1149 memcpy(ab->data(),
1150 (const uint8_t *)mb->data() + mb->range_offset(),
1151 mb->range_length());
1152 }
1153
1154 if (audio && mAudioIsVorbis) {
1155 int32_t numPageSamples;
1156 if (!mb->meta_data()->findInt32(kKeyValidSamples, &numPageSamples)) {
1157 numPageSamples = -1;
1158 }
1159
1160 uint8_t* abEnd = ab->data() + mb->range_length();
1161 memcpy(abEnd, &numPageSamples, sizeof(numPageSamples));
1162 }
1163
Lajos Molnare26940f2014-07-31 10:31:26 -07001164 sp<AMessage> meta = ab->meta();
1165
Robert Shih3423bbd2014-07-16 15:47:09 -07001166 int64_t timeUs;
1167 CHECK(mb->meta_data()->findInt64(kKeyTime, &timeUs));
Robert Shih3423bbd2014-07-16 15:47:09 -07001168 meta->setInt64("timeUs", timeUs);
1169
Lajos Molnare26940f2014-07-31 10:31:26 -07001170 if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) {
1171 const char *mime;
1172 CHECK(mTimedTextTrack.mSource != NULL
1173 && mTimedTextTrack.mSource->getFormat()->findCString(kKeyMIMEType, &mime));
1174 meta->setString("mime", mime);
1175 }
1176
Robert Shih3423bbd2014-07-16 15:47:09 -07001177 int64_t durationUs;
1178 if (mb->meta_data()->findInt64(kKeyDuration, &durationUs)) {
1179 meta->setInt64("durationUs", durationUs);
1180 }
1181
1182 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
1183 meta->setInt32("trackIndex", mSubtitleTrack.mIndex);
1184 }
1185
1186 if (actualTimeUs) {
1187 *actualTimeUs = timeUs;
1188 }
1189
1190 mb->release();
1191 mb = NULL;
1192
1193 return ab;
1194}
1195
Robert Shih17f6dd62014-08-20 17:00:21 -07001196void NuPlayer::GenericSource::postReadBuffer(media_track_type trackType) {
Lajos Molnar84f52782014-09-11 10:01:55 -07001197 Mutex::Autolock _l(mReadBufferLock);
1198
1199 if ((mPendingReadBufferTypes & (1 << trackType)) == 0) {
1200 mPendingReadBufferTypes |= (1 << trackType);
1201 sp<AMessage> msg = new AMessage(kWhatReadBuffer, id());
1202 msg->setInt32("trackType", trackType);
1203 msg->post();
1204 }
Robert Shih17f6dd62014-08-20 17:00:21 -07001205}
1206
1207void NuPlayer::GenericSource::onReadBuffer(sp<AMessage> msg) {
1208 int32_t tmpType;
1209 CHECK(msg->findInt32("trackType", &tmpType));
1210 media_track_type trackType = (media_track_type)tmpType;
Lajos Molnar84f52782014-09-11 10:01:55 -07001211 {
1212 // only protect the variable change, as readBuffer may
1213 // take considerable time. This may result in one extra
1214 // read being processed, but that is benign.
1215 Mutex::Autolock _l(mReadBufferLock);
1216 mPendingReadBufferTypes &= ~(1 << trackType);
1217 }
Robert Shih17f6dd62014-08-20 17:00:21 -07001218 readBuffer(trackType);
1219}
1220
Andreas Huberafed0e12011-09-20 15:39:58 -07001221void NuPlayer::GenericSource::readBuffer(
Robert Shih3423bbd2014-07-16 15:47:09 -07001222 media_track_type trackType, int64_t seekTimeUs, int64_t *actualTimeUs, bool formatChange) {
Andy Hung2abde2c2014-09-30 14:40:32 -07001223 // Do not read data if Widevine source is stopped
1224 if (mStopRead) {
1225 return;
1226 }
Robert Shih3423bbd2014-07-16 15:47:09 -07001227 Track *track;
Phil Burkc5cc2e22014-09-09 20:08:39 -07001228 size_t maxBuffers = 1;
Robert Shih3423bbd2014-07-16 15:47:09 -07001229 switch (trackType) {
1230 case MEDIA_TRACK_TYPE_VIDEO:
1231 track = &mVideoTrack;
Jeff Tinkera28785a2014-09-23 22:24:26 -07001232 if (mIsWidevine) {
1233 maxBuffers = 2;
1234 }
Robert Shih3423bbd2014-07-16 15:47:09 -07001235 break;
1236 case MEDIA_TRACK_TYPE_AUDIO:
1237 track = &mAudioTrack;
Jeff Tinkera28785a2014-09-23 22:24:26 -07001238 if (mIsWidevine) {
1239 maxBuffers = 8;
1240 } else {
1241 maxBuffers = 64;
1242 }
Robert Shih3423bbd2014-07-16 15:47:09 -07001243 break;
1244 case MEDIA_TRACK_TYPE_SUBTITLE:
1245 track = &mSubtitleTrack;
1246 break;
Lajos Molnare26940f2014-07-31 10:31:26 -07001247 case MEDIA_TRACK_TYPE_TIMEDTEXT:
1248 track = &mTimedTextTrack;
1249 break;
Robert Shih3423bbd2014-07-16 15:47:09 -07001250 default:
1251 TRESPASS();
1252 }
1253
1254 if (track->mSource == NULL) {
1255 return;
1256 }
Andreas Huberafed0e12011-09-20 15:39:58 -07001257
1258 if (actualTimeUs) {
1259 *actualTimeUs = seekTimeUs;
1260 }
1261
1262 MediaSource::ReadOptions options;
1263
1264 bool seeking = false;
1265
1266 if (seekTimeUs >= 0) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001267 options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
Andreas Huberafed0e12011-09-20 15:39:58 -07001268 seeking = true;
1269 }
1270
Robert Shih3423bbd2014-07-16 15:47:09 -07001271 if (mIsWidevine && trackType != MEDIA_TRACK_TYPE_AUDIO) {
Lajos Molnarcc227032014-07-17 15:33:06 -07001272 options.setNonBlocking();
1273 }
1274
Phil Burkc5cc2e22014-09-09 20:08:39 -07001275 for (size_t numBuffers = 0; numBuffers < maxBuffers; ) {
Andreas Huberafed0e12011-09-20 15:39:58 -07001276 MediaBuffer *mbuf;
1277 status_t err = track->mSource->read(&mbuf, &options);
1278
1279 options.clearSeekTo();
1280
1281 if (err == OK) {
Ronghua Wu80276872014-08-28 15:50:29 -07001282 int64_t timeUs;
1283 CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs));
1284 if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
1285 mAudioTimeUs = timeUs;
1286 } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
1287 mVideoTimeUs = timeUs;
1288 }
1289
Robert Shih3423bbd2014-07-16 15:47:09 -07001290 // formatChange && seeking: track whose source is changed during selection
1291 // formatChange && !seeking: track whose source is not changed during selection
1292 // !formatChange: normal seek
Lajos Molnare26940f2014-07-31 10:31:26 -07001293 if ((seeking || formatChange)
1294 && (trackType == MEDIA_TRACK_TYPE_AUDIO
1295 || trackType == MEDIA_TRACK_TYPE_VIDEO)) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001296 ATSParser::DiscontinuityType type = formatChange
1297 ? (seeking
1298 ? ATSParser::DISCONTINUITY_FORMATCHANGE
1299 : ATSParser::DISCONTINUITY_NONE)
1300 : ATSParser::DISCONTINUITY_SEEK;
1301 track->mPackets->queueDiscontinuity( type, NULL, true /* discard */);
Andreas Huberafed0e12011-09-20 15:39:58 -07001302 }
1303
Robert Shih3423bbd2014-07-16 15:47:09 -07001304 sp<ABuffer> buffer = mediaBufferToABuffer(mbuf, trackType, actualTimeUs);
Andreas Huberafed0e12011-09-20 15:39:58 -07001305 track->mPackets->queueAccessUnit(buffer);
Marco Nelissen317a49a2014-09-16 21:32:33 -07001306 formatChange = false;
1307 seeking = false;
Phil Burkc5cc2e22014-09-09 20:08:39 -07001308 ++numBuffers;
Lajos Molnarcc227032014-07-17 15:33:06 -07001309 } else if (err == WOULD_BLOCK) {
1310 break;
Andreas Huberafed0e12011-09-20 15:39:58 -07001311 } else if (err == INFO_FORMAT_CHANGED) {
1312#if 0
1313 track->mPackets->queueDiscontinuity(
Chong Zhang632740c2014-06-26 13:03:47 -07001314 ATSParser::DISCONTINUITY_FORMATCHANGE,
1315 NULL,
1316 false /* discard */);
Andreas Huberafed0e12011-09-20 15:39:58 -07001317#endif
1318 } else {
1319 track->mPackets->signalEOS(err);
1320 break;
1321 }
1322 }
1323}
1324
Andreas Huberafed0e12011-09-20 15:39:58 -07001325} // namespace android