blob: 67e758450400923886ed437486e9f5eca72fffee [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"
Robert Shih360d6d02014-09-29 14:42:35 -070039#include "../../libstagefright/include/HTTPBase.h"
Andreas Huberafed0e12011-09-20 15:39:58 -070040
41namespace android {
42
43NuPlayer::GenericSource::GenericSource(
Andreas Huberb5f25f02013-02-05 10:14:26 -080044 const sp<AMessage> &notify,
Lajos Molnarcc227032014-07-17 15:33:06 -070045 bool uidValid,
46 uid_t uid)
Andreas Huberb5f25f02013-02-05 10:14:26 -080047 : Source(notify),
Robert Shih5c67ddc2014-11-04 17:46:05 -080048 mAudioTimeUs(0),
49 mAudioLastDequeueTimeUs(0),
50 mVideoTimeUs(0),
51 mVideoLastDequeueTimeUs(0),
Robert Shih3423bbd2014-07-16 15:47:09 -070052 mFetchSubtitleDataGeneration(0),
Lajos Molnare26940f2014-07-31 10:31:26 -070053 mFetchTimedTextDataGeneration(0),
Andreas Huberb5f25f02013-02-05 10:14:26 -080054 mDurationUs(0ll),
Lajos Molnarcc227032014-07-17 15:33:06 -070055 mAudioIsVorbis(false),
Chong Zhang3de157d2014-08-05 20:54:44 -070056 mIsWidevine(false),
Lajos Molnarcc227032014-07-17 15:33:06 -070057 mUIDValid(uidValid),
Chong Zhangd354d8d2014-08-20 13:09:58 -070058 mUID(uid),
Chong Zhanga6bf21f2014-11-19 20:26:34 -080059 mFd(-1),
Ronghua Wu80276872014-08-28 15:50:29 -070060 mDrmManagerClient(NULL),
Chong Zhang2a3cc9a2014-08-21 17:48:26 -070061 mMetaDataSize(-1ll),
62 mBitrate(-1ll),
Lajos Molnar84f52782014-09-11 10:01:55 -070063 mPollBufferingGeneration(0),
64 mPendingReadBufferTypes(0) {
Chong Zhanga19f33e2014-08-07 15:35:07 -070065 resetDataSource();
Andreas Huberafed0e12011-09-20 15:39:58 -070066 DataSource::RegisterDefaultSniffers();
Chong Zhang3de157d2014-08-05 20:54:44 -070067}
68
Chong Zhanga19f33e2014-08-07 15:35:07 -070069void NuPlayer::GenericSource::resetDataSource() {
70 mHTTPService.clear();
Robert Shih360d6d02014-09-29 14:42:35 -070071 mHttpSource.clear();
Chong Zhanga19f33e2014-08-07 15:35:07 -070072 mUri.clear();
73 mUriHeaders.clear();
Chong Zhanga6bf21f2014-11-19 20:26:34 -080074 if (mFd >= 0) {
75 close(mFd);
76 mFd = -1;
77 }
Chong Zhanga19f33e2014-08-07 15:35:07 -070078 mOffset = 0;
79 mLength = 0;
Ronghua Wu80276872014-08-28 15:50:29 -070080 setDrmPlaybackStatusIfNeeded(Playback::STOP, 0);
81 mDecryptHandle = NULL;
82 mDrmManagerClient = NULL;
83 mStarted = false;
Andy Hung2abde2c2014-09-30 14:40:32 -070084 mStopRead = true;
Chong Zhanga19f33e2014-08-07 15:35:07 -070085}
86
87status_t NuPlayer::GenericSource::setDataSource(
Chong Zhang3de157d2014-08-05 20:54:44 -070088 const sp<IMediaHTTPService> &httpService,
89 const char *url,
90 const KeyedVector<String8, String8> *headers) {
Chong Zhanga19f33e2014-08-07 15:35:07 -070091 resetDataSource();
Chong Zhang3de157d2014-08-05 20:54:44 -070092
Chong Zhanga19f33e2014-08-07 15:35:07 -070093 mHTTPService = httpService;
94 mUri = url;
Andreas Huberafed0e12011-09-20 15:39:58 -070095
Chong Zhanga19f33e2014-08-07 15:35:07 -070096 if (headers) {
97 mUriHeaders = *headers;
Chong Zhang3de157d2014-08-05 20:54:44 -070098 }
99
Chong Zhanga19f33e2014-08-07 15:35:07 -0700100 // delay data source creation to prepareAsync() to avoid blocking
101 // the calling thread in setDataSource for any significant time.
102 return OK;
Andreas Huberafed0e12011-09-20 15:39:58 -0700103}
104
Chong Zhanga19f33e2014-08-07 15:35:07 -0700105status_t NuPlayer::GenericSource::setDataSource(
Chong Zhang3de157d2014-08-05 20:54:44 -0700106 int fd, int64_t offset, int64_t length) {
Chong Zhanga19f33e2014-08-07 15:35:07 -0700107 resetDataSource();
Andreas Huberafed0e12011-09-20 15:39:58 -0700108
Chong Zhanga19f33e2014-08-07 15:35:07 -0700109 mFd = dup(fd);
110 mOffset = offset;
111 mLength = length;
112
113 // delay data source creation to prepareAsync() to avoid blocking
114 // the calling thread in setDataSource for any significant time.
115 return OK;
Andreas Huberafed0e12011-09-20 15:39:58 -0700116}
117
Marco Nelissenf0b72b52014-09-16 15:43:44 -0700118sp<MetaData> NuPlayer::GenericSource::getFileFormatMeta() const {
119 return mFileMeta;
120}
121
Chong Zhangd354d8d2014-08-20 13:09:58 -0700122status_t NuPlayer::GenericSource::initFromDataSource() {
Lajos Molnarcc227032014-07-17 15:33:06 -0700123 sp<MediaExtractor> extractor;
124
Chong Zhangd354d8d2014-08-20 13:09:58 -0700125 CHECK(mDataSource != NULL);
126
Lajos Molnarcc227032014-07-17 15:33:06 -0700127 if (mIsWidevine) {
128 String8 mimeType;
129 float confidence;
130 sp<AMessage> dummy;
131 bool success;
132
Chong Zhangd354d8d2014-08-20 13:09:58 -0700133 success = SniffWVM(mDataSource, &mimeType, &confidence, &dummy);
Lajos Molnarcc227032014-07-17 15:33:06 -0700134 if (!success
135 || strcasecmp(
136 mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) {
137 ALOGE("unsupported widevine mime: %s", mimeType.string());
Chong Zhang3de157d2014-08-05 20:54:44 -0700138 return UNKNOWN_ERROR;
Lajos Molnarcc227032014-07-17 15:33:06 -0700139 }
140
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700141 mWVMExtractor = new WVMExtractor(mDataSource);
142 mWVMExtractor->setAdaptiveStreamingMode(true);
Lajos Molnarcc227032014-07-17 15:33:06 -0700143 if (mUIDValid) {
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700144 mWVMExtractor->setUID(mUID);
Lajos Molnarcc227032014-07-17 15:33:06 -0700145 }
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700146 extractor = mWVMExtractor;
Lajos Molnarcc227032014-07-17 15:33:06 -0700147 } else {
Chong Zhangd354d8d2014-08-20 13:09:58 -0700148 extractor = MediaExtractor::Create(mDataSource,
149 mSniffedMIME.empty() ? NULL: mSniffedMIME.c_str());
Lajos Molnarcc227032014-07-17 15:33:06 -0700150 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700151
Chong Zhang3de157d2014-08-05 20:54:44 -0700152 if (extractor == NULL) {
153 return UNKNOWN_ERROR;
154 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700155
Ronghua Wu80276872014-08-28 15:50:29 -0700156 if (extractor->getDrmFlag()) {
157 checkDrmStatus(mDataSource);
158 }
159
Marco Nelissenf0b72b52014-09-16 15:43:44 -0700160 mFileMeta = extractor->getMetaData();
161 if (mFileMeta != NULL) {
Marco Nelissenc1f4b2b2014-06-17 14:48:32 -0700162 int64_t duration;
Marco Nelissenf0b72b52014-09-16 15:43:44 -0700163 if (mFileMeta->findInt64(kKeyDuration, &duration)) {
Marco Nelissenc1f4b2b2014-06-17 14:48:32 -0700164 mDurationUs = duration;
165 }
166 }
167
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700168 int32_t totalBitrate = 0;
169
Marco Nelissen705d3292014-09-19 15:14:37 -0700170 size_t numtracks = extractor->countTracks();
171 if (numtracks == 0) {
172 return UNKNOWN_ERROR;
173 }
174
175 for (size_t i = 0; i < numtracks; ++i) {
Chong Zhangafc0a872014-08-26 09:56:52 -0700176 sp<MediaSource> track = extractor->getTrack(i);
177
Andreas Huberafed0e12011-09-20 15:39:58 -0700178 sp<MetaData> meta = extractor->getTrackMetaData(i);
179
180 const char *mime;
181 CHECK(meta->findCString(kKeyMIMEType, &mime));
182
Chong Zhangafc0a872014-08-26 09:56:52 -0700183 // Do the string compare immediately with "mime",
184 // we can't assume "mime" would stay valid after another
185 // extractor operation, some extractors might modify meta
186 // during getTrack() and make it invalid.
Andreas Huberafed0e12011-09-20 15:39:58 -0700187 if (!strncasecmp(mime, "audio/", 6)) {
188 if (mAudioTrack.mSource == NULL) {
Robert Shihdd235722014-06-12 14:49:23 -0700189 mAudioTrack.mIndex = i;
190 mAudioTrack.mSource = track;
Robert Shihaf52c1a2014-09-11 15:38:54 -0700191 mAudioTrack.mPackets =
192 new AnotherPacketSource(mAudioTrack.mSource->getFormat());
Andreas Huberafed0e12011-09-20 15:39:58 -0700193
194 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
195 mAudioIsVorbis = true;
196 } else {
197 mAudioIsVorbis = false;
198 }
199 }
200 } else if (!strncasecmp(mime, "video/", 6)) {
201 if (mVideoTrack.mSource == NULL) {
Robert Shihdd235722014-06-12 14:49:23 -0700202 mVideoTrack.mIndex = i;
203 mVideoTrack.mSource = track;
Robert Shihaf52c1a2014-09-11 15:38:54 -0700204 mVideoTrack.mPackets =
205 new AnotherPacketSource(mVideoTrack.mSource->getFormat());
Chong Zhang7e892182014-08-05 11:58:21 -0700206
207 // check if the source requires secure buffers
208 int32_t secure;
Chong Zhanga19f33e2014-08-07 15:35:07 -0700209 if (meta->findInt32(kKeyRequiresSecureBuffers, &secure)
210 && secure) {
Chong Zhang7e892182014-08-05 11:58:21 -0700211 mIsWidevine = true;
Chong Zhang3de157d2014-08-05 20:54:44 -0700212 if (mUIDValid) {
213 extractor->setUID(mUID);
214 }
Chong Zhang7e892182014-08-05 11:58:21 -0700215 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700216 }
217 }
218
219 if (track != NULL) {
Robert Shihdd235722014-06-12 14:49:23 -0700220 mSources.push(track);
Andreas Huberafed0e12011-09-20 15:39:58 -0700221 int64_t durationUs;
222 if (meta->findInt64(kKeyDuration, &durationUs)) {
223 if (durationUs > mDurationUs) {
224 mDurationUs = durationUs;
225 }
226 }
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700227
228 int32_t bitrate;
229 if (totalBitrate >= 0 && meta->findInt32(kKeyBitRate, &bitrate)) {
230 totalBitrate += bitrate;
231 } else {
232 totalBitrate = -1;
233 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700234 }
235 }
Chong Zhang3de157d2014-08-05 20:54:44 -0700236
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700237 mBitrate = totalBitrate;
238
Chong Zhang3de157d2014-08-05 20:54:44 -0700239 return OK;
Andreas Huberafed0e12011-09-20 15:39:58 -0700240}
241
Ronghua Wu80276872014-08-28 15:50:29 -0700242void NuPlayer::GenericSource::checkDrmStatus(const sp<DataSource>& dataSource) {
243 dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
244 if (mDecryptHandle != NULL) {
245 CHECK(mDrmManagerClient);
246 if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
247 sp<AMessage> msg = dupNotify();
248 msg->setInt32("what", kWhatDrmNoLicense);
249 msg->post();
250 }
251 }
252}
253
254int64_t NuPlayer::GenericSource::getLastReadPosition() {
255 if (mAudioTrack.mSource != NULL) {
256 return mAudioTimeUs;
257 } else if (mVideoTrack.mSource != NULL) {
258 return mVideoTimeUs;
259 } else {
260 return 0;
261 }
262}
263
Chong Zhanga19f33e2014-08-07 15:35:07 -0700264status_t NuPlayer::GenericSource::setBuffers(
265 bool audio, Vector<MediaBuffer *> &buffers) {
Lajos Molnarcc227032014-07-17 15:33:06 -0700266 if (mIsWidevine && !audio) {
267 return mVideoTrack.mSource->setBuffers(buffers);
268 }
269 return INVALID_OPERATION;
270}
271
Andreas Huberafed0e12011-09-20 15:39:58 -0700272NuPlayer::GenericSource::~GenericSource() {
Chong Zhang1228d6b2014-08-12 21:25:48 -0700273 if (mLooper != NULL) {
274 mLooper->unregisterHandler(id());
275 mLooper->stop();
276 }
Chong Zhanga6bf21f2014-11-19 20:26:34 -0800277 resetDataSource();
Andreas Huberafed0e12011-09-20 15:39:58 -0700278}
279
Andreas Huber9575c962013-02-05 13:59:56 -0800280void NuPlayer::GenericSource::prepareAsync() {
Chong Zhang1228d6b2014-08-12 21:25:48 -0700281 if (mLooper == NULL) {
282 mLooper = new ALooper;
283 mLooper->setName("generic");
284 mLooper->start();
285
286 mLooper->registerHandler(this);
287 }
288
289 sp<AMessage> msg = new AMessage(kWhatPrepareAsync, id());
290 msg->post();
291}
292
293void NuPlayer::GenericSource::onPrepareAsync() {
Chong Zhanga19f33e2014-08-07 15:35:07 -0700294 // delayed data source creation
Chong Zhangd354d8d2014-08-20 13:09:58 -0700295 if (mDataSource == NULL) {
296 if (!mUri.empty()) {
Robert Shih360d6d02014-09-29 14:42:35 -0700297 const char* uri = mUri.c_str();
298 mIsWidevine = !strncasecmp(uri, "widevine://", 11);
299
300 if (!strncasecmp("http://", uri, 7)
301 || !strncasecmp("https://", uri, 8)
302 || mIsWidevine) {
303 mHttpSource = DataSource::CreateMediaHTTP(mHTTPService);
304 if (mHttpSource == NULL) {
305 ALOGE("Failed to create http source!");
306 notifyPreparedAndCleanup(UNKNOWN_ERROR);
307 return;
308 }
309 }
Chong Zhanga19f33e2014-08-07 15:35:07 -0700310
Chong Zhangd354d8d2014-08-20 13:09:58 -0700311 mDataSource = DataSource::CreateFromURI(
Robert Shih360d6d02014-09-29 14:42:35 -0700312 mHTTPService, uri, &mUriHeaders, &mContentType,
313 static_cast<HTTPBase *>(mHttpSource.get()));
Chong Zhangd354d8d2014-08-20 13:09:58 -0700314 } else {
315 // set to false first, if the extractor
316 // comes back as secure, set it to true then.
317 mIsWidevine = false;
Chong Zhanga19f33e2014-08-07 15:35:07 -0700318
Chong Zhangd354d8d2014-08-20 13:09:58 -0700319 mDataSource = new FileSource(mFd, mOffset, mLength);
Chong Zhanga6bf21f2014-11-19 20:26:34 -0800320 mFd = -1;
Chong Zhangd354d8d2014-08-20 13:09:58 -0700321 }
Chong Zhanga19f33e2014-08-07 15:35:07 -0700322
Chong Zhangd354d8d2014-08-20 13:09:58 -0700323 if (mDataSource == NULL) {
324 ALOGE("Failed to create data source!");
325 notifyPreparedAndCleanup(UNKNOWN_ERROR);
326 return;
327 }
328
329 if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
330 mCachedSource = static_cast<NuCachedSource2 *>(mDataSource.get());
331 }
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700332
333 if (mIsWidevine || mCachedSource != NULL) {
334 schedulePollBuffering();
335 }
Chong Zhanga19f33e2014-08-07 15:35:07 -0700336 }
337
Chong Zhangd354d8d2014-08-20 13:09:58 -0700338 // check initial caching status
339 status_t err = prefillCacheIfNecessary();
340 if (err != OK) {
341 if (err == -EAGAIN) {
342 (new AMessage(kWhatPrepareAsync, id()))->post(200000);
343 } else {
344 ALOGE("Failed to prefill data cache!");
345 notifyPreparedAndCleanup(UNKNOWN_ERROR);
346 }
Chong Zhanga19f33e2014-08-07 15:35:07 -0700347 return;
348 }
349
Chong Zhangd354d8d2014-08-20 13:09:58 -0700350 // init extrator from data source
351 err = initFromDataSource();
Chong Zhanga19f33e2014-08-07 15:35:07 -0700352
353 if (err != OK) {
354 ALOGE("Failed to init from data source!");
Chong Zhangd354d8d2014-08-20 13:09:58 -0700355 notifyPreparedAndCleanup(err);
Chong Zhanga19f33e2014-08-07 15:35:07 -0700356 return;
357 }
358
Andreas Huber9575c962013-02-05 13:59:56 -0800359 if (mVideoTrack.mSource != NULL) {
Robert Shih17f6dd62014-08-20 17:00:21 -0700360 sp<MetaData> meta = doGetFormatMeta(false /* audio */);
361 sp<AMessage> msg = new AMessage;
362 err = convertMetaDataToMessage(meta, &msg);
363 if(err != OK) {
364 notifyPreparedAndCleanup(err);
365 return;
366 }
367 notifyVideoSizeChanged(msg);
Andreas Huber9575c962013-02-05 13:59:56 -0800368 }
369
370 notifyFlagsChanged(
Lajos Molnarcc227032014-07-17 15:33:06 -0700371 (mIsWidevine ? FLAG_SECURE : 0)
372 | FLAG_CAN_PAUSE
Andreas Huber9575c962013-02-05 13:59:56 -0800373 | FLAG_CAN_SEEK_BACKWARD
374 | FLAG_CAN_SEEK_FORWARD
375 | FLAG_CAN_SEEK);
376
377 notifyPrepared();
378}
379
Chong Zhangd354d8d2014-08-20 13:09:58 -0700380void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) {
381 if (err != OK) {
382 mMetaDataSize = -1ll;
383 mContentType = "";
384 mSniffedMIME = "";
385 mDataSource.clear();
386 mCachedSource.clear();
Robert Shih360d6d02014-09-29 14:42:35 -0700387 mHttpSource.clear();
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700388
389 cancelPollBuffering();
Chong Zhangd354d8d2014-08-20 13:09:58 -0700390 }
391 notifyPrepared(err);
392}
393
394status_t NuPlayer::GenericSource::prefillCacheIfNecessary() {
395 CHECK(mDataSource != NULL);
396
397 if (mCachedSource == NULL) {
398 // no prefill if the data source is not cached
399 return OK;
400 }
401
402 // We're not doing this for streams that appear to be audio-only
403 // streams to ensure that even low bandwidth streams start
404 // playing back fairly instantly.
405 if (!strncasecmp(mContentType.string(), "audio/", 6)) {
406 return OK;
407 }
408
409 // We're going to prefill the cache before trying to instantiate
410 // the extractor below, as the latter is an operation that otherwise
411 // could block on the datasource for a significant amount of time.
412 // During that time we'd be unable to abort the preparation phase
413 // without this prefill.
414
415 // Initially make sure we have at least 192 KB for the sniff
416 // to complete without blocking.
417 static const size_t kMinBytesForSniffing = 192 * 1024;
418 static const size_t kDefaultMetaSize = 200000;
419
420 status_t finalStatus;
421
422 size_t cachedDataRemaining =
423 mCachedSource->approxDataRemaining(&finalStatus);
424
425 if (finalStatus != OK || (mMetaDataSize >= 0
426 && (off64_t)cachedDataRemaining >= mMetaDataSize)) {
427 ALOGV("stop caching, status %d, "
428 "metaDataSize %lld, cachedDataRemaining %zu",
429 finalStatus, mMetaDataSize, cachedDataRemaining);
430 return OK;
431 }
432
433 ALOGV("now cached %zu bytes of data", cachedDataRemaining);
434
435 if (mMetaDataSize < 0
436 && cachedDataRemaining >= kMinBytesForSniffing) {
437 String8 tmp;
438 float confidence;
439 sp<AMessage> meta;
440 if (!mCachedSource->sniff(&tmp, &confidence, &meta)) {
441 return UNKNOWN_ERROR;
442 }
443
444 // We successfully identified the file's extractor to
445 // be, remember this mime type so we don't have to
446 // sniff it again when we call MediaExtractor::Create()
447 mSniffedMIME = tmp.string();
448
449 if (meta == NULL
450 || !meta->findInt64("meta-data-size",
451 reinterpret_cast<int64_t*>(&mMetaDataSize))) {
452 mMetaDataSize = kDefaultMetaSize;
453 }
454
455 if (mMetaDataSize < 0ll) {
456 ALOGE("invalid metaDataSize = %lld bytes", mMetaDataSize);
457 return UNKNOWN_ERROR;
458 }
459 }
460
461 return -EAGAIN;
462}
463
Andreas Huberafed0e12011-09-20 15:39:58 -0700464void NuPlayer::GenericSource::start() {
465 ALOGI("start");
466
Andy Hung2abde2c2014-09-30 14:40:32 -0700467 mStopRead = false;
Andreas Huberafed0e12011-09-20 15:39:58 -0700468 if (mAudioTrack.mSource != NULL) {
Robert Shihbace25b2014-07-25 14:14:34 -0700469 CHECK_EQ(mAudioTrack.mSource->start(), (status_t)OK);
Andreas Huberafed0e12011-09-20 15:39:58 -0700470
Robert Shih17f6dd62014-08-20 17:00:21 -0700471 postReadBuffer(MEDIA_TRACK_TYPE_AUDIO);
Andreas Huberafed0e12011-09-20 15:39:58 -0700472 }
473
474 if (mVideoTrack.mSource != NULL) {
Robert Shihbace25b2014-07-25 14:14:34 -0700475 CHECK_EQ(mVideoTrack.mSource->start(), (status_t)OK);
Andreas Huberafed0e12011-09-20 15:39:58 -0700476
Robert Shih17f6dd62014-08-20 17:00:21 -0700477 postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
Andreas Huberafed0e12011-09-20 15:39:58 -0700478 }
Ronghua Wu80276872014-08-28 15:50:29 -0700479
480 setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000);
481 mStarted = true;
482}
483
484void NuPlayer::GenericSource::stop() {
485 // nothing to do, just account for DRM playback status
486 setDrmPlaybackStatusIfNeeded(Playback::STOP, 0);
487 mStarted = false;
Andy Hung2abde2c2014-09-30 14:40:32 -0700488 if (mIsWidevine) {
489 // For a widevine source we need to prevent any further reads.
490 sp<AMessage> msg = new AMessage(kWhatStopWidevine, id());
491 sp<AMessage> response;
492 (void) msg->postAndAwaitResponse(&response);
493 }
Ronghua Wu80276872014-08-28 15:50:29 -0700494}
495
496void NuPlayer::GenericSource::pause() {
497 // nothing to do, just account for DRM playback status
498 setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0);
499 mStarted = false;
500}
501
502void NuPlayer::GenericSource::resume() {
503 // nothing to do, just account for DRM playback status
504 setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000);
505 mStarted = true;
506}
507
Chong Zhang48296b72014-09-14 14:28:45 -0700508void NuPlayer::GenericSource::disconnect() {
509 if (mDataSource != NULL) {
510 // disconnect data source
511 if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
512 static_cast<NuCachedSource2 *>(mDataSource.get())->disconnect();
513 }
Robert Shih360d6d02014-09-29 14:42:35 -0700514 } else if (mHttpSource != NULL) {
515 static_cast<HTTPBase *>(mHttpSource.get())->disconnect();
Chong Zhang48296b72014-09-14 14:28:45 -0700516 }
517}
518
Ronghua Wu80276872014-08-28 15:50:29 -0700519void NuPlayer::GenericSource::setDrmPlaybackStatusIfNeeded(int playbackStatus, int64_t position) {
520 if (mDecryptHandle != NULL) {
521 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, playbackStatus, position);
522 }
Robert Shih17f6dd62014-08-20 17:00:21 -0700523 mSubtitleTrack.mPackets = new AnotherPacketSource(NULL);
524 mTimedTextTrack.mPackets = new AnotherPacketSource(NULL);
Andreas Huberafed0e12011-09-20 15:39:58 -0700525}
526
527status_t NuPlayer::GenericSource::feedMoreTSData() {
528 return OK;
529}
530
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700531void NuPlayer::GenericSource::schedulePollBuffering() {
532 sp<AMessage> msg = new AMessage(kWhatPollBuffering, id());
533 msg->setInt32("generation", mPollBufferingGeneration);
534 msg->post(1000000ll);
535}
536
537void NuPlayer::GenericSource::cancelPollBuffering() {
538 ++mPollBufferingGeneration;
539}
540
541void NuPlayer::GenericSource::notifyBufferingUpdate(int percentage) {
542 sp<AMessage> msg = dupNotify();
543 msg->setInt32("what", kWhatBufferingUpdate);
544 msg->setInt32("percentage", percentage);
545 msg->post();
546}
547
548void NuPlayer::GenericSource::onPollBuffering() {
549 status_t finalStatus = UNKNOWN_ERROR;
550 int64_t cachedDurationUs = 0ll;
551
552 if (mCachedSource != NULL) {
553 size_t cachedDataRemaining =
554 mCachedSource->approxDataRemaining(&finalStatus);
555
556 if (finalStatus == OK) {
557 off64_t size;
558 int64_t bitrate = 0ll;
559 if (mDurationUs > 0 && mCachedSource->getSize(&size) == OK) {
560 bitrate = size * 8000000ll / mDurationUs;
561 } else if (mBitrate > 0) {
562 bitrate = mBitrate;
563 }
564 if (bitrate > 0) {
565 cachedDurationUs = cachedDataRemaining * 8000000ll / bitrate;
566 }
567 }
568 } else if (mWVMExtractor != NULL) {
569 cachedDurationUs
570 = mWVMExtractor->getCachedDurationUs(&finalStatus);
571 }
572
573 if (finalStatus == ERROR_END_OF_STREAM) {
574 notifyBufferingUpdate(100);
575 cancelPollBuffering();
576 return;
577 } else if (cachedDurationUs > 0ll && mDurationUs > 0ll) {
578 int percentage = 100.0 * cachedDurationUs / mDurationUs;
579 if (percentage > 100) {
580 percentage = 100;
581 }
582
583 notifyBufferingUpdate(percentage);
584 }
585
586 schedulePollBuffering();
587}
588
589
Robert Shih3423bbd2014-07-16 15:47:09 -0700590void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) {
591 switch (msg->what()) {
Chong Zhang1228d6b2014-08-12 21:25:48 -0700592 case kWhatPrepareAsync:
593 {
594 onPrepareAsync();
595 break;
596 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700597 case kWhatFetchSubtitleData:
598 {
Lajos Molnare26940f2014-07-31 10:31:26 -0700599 fetchTextData(kWhatSendSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
600 mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
601 break;
602 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700603
Lajos Molnare26940f2014-07-31 10:31:26 -0700604 case kWhatFetchTimedTextData:
605 {
606 fetchTextData(kWhatSendTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
607 mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
Robert Shih3423bbd2014-07-16 15:47:09 -0700608 break;
609 }
610
611 case kWhatSendSubtitleData:
612 {
Lajos Molnare26940f2014-07-31 10:31:26 -0700613 sendTextData(kWhatSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
614 mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
615 break;
616 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700617
Lajos Molnare26940f2014-07-31 10:31:26 -0700618 case kWhatSendTimedTextData:
619 {
620 sendTextData(kWhatTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
621 mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
Robert Shih3423bbd2014-07-16 15:47:09 -0700622 break;
623 }
624
625 case kWhatChangeAVSource:
626 {
627 int32_t trackIndex;
628 CHECK(msg->findInt32("trackIndex", &trackIndex));
629 const sp<MediaSource> source = mSources.itemAt(trackIndex);
630
631 Track* track;
632 const char *mime;
633 media_track_type trackType, counterpartType;
634 sp<MetaData> meta = source->getFormat();
635 meta->findCString(kKeyMIMEType, &mime);
636 if (!strncasecmp(mime, "audio/", 6)) {
637 track = &mAudioTrack;
638 trackType = MEDIA_TRACK_TYPE_AUDIO;
639 counterpartType = MEDIA_TRACK_TYPE_VIDEO;;
640 } else {
641 CHECK(!strncasecmp(mime, "video/", 6));
642 track = &mVideoTrack;
643 trackType = MEDIA_TRACK_TYPE_VIDEO;
644 counterpartType = MEDIA_TRACK_TYPE_AUDIO;;
645 }
646
647
648 if (track->mSource != NULL) {
649 track->mSource->stop();
650 }
651 track->mSource = source;
652 track->mSource->start();
653 track->mIndex = trackIndex;
654
Robert Shih3423bbd2014-07-16 15:47:09 -0700655 int64_t timeUs, actualTimeUs;
656 const bool formatChange = true;
Robert Shih5c67ddc2014-11-04 17:46:05 -0800657 if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
658 timeUs = mAudioLastDequeueTimeUs;
659 } else {
660 timeUs = mVideoLastDequeueTimeUs;
661 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700662 readBuffer(trackType, timeUs, &actualTimeUs, formatChange);
663 readBuffer(counterpartType, -1, NULL, formatChange);
664 ALOGV("timeUs %lld actualTimeUs %lld", timeUs, actualTimeUs);
665
666 break;
667 }
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700668 case kWhatPollBuffering:
669 {
670 int32_t generation;
671 CHECK(msg->findInt32("generation", &generation));
672 if (generation == mPollBufferingGeneration) {
673 onPollBuffering();
674 }
675 break;
676 }
Robert Shih17f6dd62014-08-20 17:00:21 -0700677
678 case kWhatGetFormat:
679 {
680 onGetFormatMeta(msg);
681 break;
682 }
683
684 case kWhatGetSelectedTrack:
685 {
686 onGetSelectedTrack(msg);
687 break;
688 }
689
690 case kWhatSelectTrack:
691 {
692 onSelectTrack(msg);
693 break;
694 }
695
696 case kWhatSeek:
697 {
698 onSeek(msg);
699 break;
700 }
701
702 case kWhatReadBuffer:
703 {
704 onReadBuffer(msg);
705 break;
706 }
707
Andy Hung2abde2c2014-09-30 14:40:32 -0700708 case kWhatStopWidevine:
709 {
710 // mStopRead is only used for Widevine to prevent the video source
711 // from being read while the associated video decoder is shutting down.
712 mStopRead = true;
713 if (mVideoTrack.mSource != NULL) {
714 mVideoTrack.mPackets->clear();
715 }
716 sp<AMessage> response = new AMessage;
717 uint32_t replyID;
718 CHECK(msg->senderAwaitsResponse(&replyID));
719 response->postReply(replyID);
720 break;
721 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700722 default:
723 Source::onMessageReceived(msg);
724 break;
725 }
726}
727
Lajos Molnare26940f2014-07-31 10:31:26 -0700728void NuPlayer::GenericSource::fetchTextData(
729 uint32_t sendWhat,
730 media_track_type type,
731 int32_t curGen,
732 sp<AnotherPacketSource> packets,
733 sp<AMessage> msg) {
734 int32_t msgGeneration;
735 CHECK(msg->findInt32("generation", &msgGeneration));
736 if (msgGeneration != curGen) {
737 // stale
738 return;
739 }
740
741 int32_t avail;
742 if (packets->hasBufferAvailable(&avail)) {
743 return;
744 }
745
746 int64_t timeUs;
747 CHECK(msg->findInt64("timeUs", &timeUs));
748
749 int64_t subTimeUs;
750 readBuffer(type, timeUs, &subTimeUs);
751
752 int64_t delayUs = subTimeUs - timeUs;
753 if (msg->what() == kWhatFetchSubtitleData) {
754 const int64_t oneSecUs = 1000000ll;
755 delayUs -= oneSecUs;
756 }
757 sp<AMessage> msg2 = new AMessage(sendWhat, id());
758 msg2->setInt32("generation", msgGeneration);
759 msg2->post(delayUs < 0 ? 0 : delayUs);
760}
761
762void NuPlayer::GenericSource::sendTextData(
763 uint32_t what,
764 media_track_type type,
765 int32_t curGen,
766 sp<AnotherPacketSource> packets,
767 sp<AMessage> msg) {
768 int32_t msgGeneration;
769 CHECK(msg->findInt32("generation", &msgGeneration));
770 if (msgGeneration != curGen) {
771 // stale
772 return;
773 }
774
775 int64_t subTimeUs;
776 if (packets->nextBufferTime(&subTimeUs) != OK) {
777 return;
778 }
779
780 int64_t nextSubTimeUs;
781 readBuffer(type, -1, &nextSubTimeUs);
782
783 sp<ABuffer> buffer;
784 status_t dequeueStatus = packets->dequeueAccessUnit(&buffer);
785 if (dequeueStatus == OK) {
786 sp<AMessage> notify = dupNotify();
787 notify->setInt32("what", what);
788 notify->setBuffer("buffer", buffer);
789 notify->post();
790
791 const int64_t delayUs = nextSubTimeUs - subTimeUs;
792 msg->post(delayUs < 0 ? 0 : delayUs);
793 }
794}
795
Andreas Huber84066782011-08-16 09:34:26 -0700796sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
Robert Shih17f6dd62014-08-20 17:00:21 -0700797 sp<AMessage> msg = new AMessage(kWhatGetFormat, id());
798 msg->setInt32("audio", audio);
799
800 sp<AMessage> response;
801 void *format;
802 status_t err = msg->postAndAwaitResponse(&response);
803 if (err == OK && response != NULL) {
804 CHECK(response->findPointer("format", &format));
805 return (MetaData *)format;
806 } else {
807 return NULL;
808 }
809}
810
811void NuPlayer::GenericSource::onGetFormatMeta(sp<AMessage> msg) const {
812 int32_t audio;
813 CHECK(msg->findInt32("audio", &audio));
814
815 sp<AMessage> response = new AMessage;
816 sp<MetaData> format = doGetFormatMeta(audio);
817 response->setPointer("format", format.get());
818
819 uint32_t replyID;
820 CHECK(msg->senderAwaitsResponse(&replyID));
821 response->postReply(replyID);
822}
823
824sp<MetaData> NuPlayer::GenericSource::doGetFormatMeta(bool audio) const {
Andreas Huberafed0e12011-09-20 15:39:58 -0700825 sp<MediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
826
827 if (source == NULL) {
828 return NULL;
829 }
830
831 return source->getFormat();
832}
833
834status_t NuPlayer::GenericSource::dequeueAccessUnit(
835 bool audio, sp<ABuffer> *accessUnit) {
836 Track *track = audio ? &mAudioTrack : &mVideoTrack;
837
838 if (track->mSource == NULL) {
839 return -EWOULDBLOCK;
840 }
841
Lajos Molnarcc227032014-07-17 15:33:06 -0700842 if (mIsWidevine && !audio) {
843 // try to read a buffer as we may not have been able to the last time
Robert Shih17f6dd62014-08-20 17:00:21 -0700844 postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
Lajos Molnarcc227032014-07-17 15:33:06 -0700845 }
846
Andreas Huberafed0e12011-09-20 15:39:58 -0700847 status_t finalResult;
848 if (!track->mPackets->hasBufferAvailable(&finalResult)) {
Lajos Molnarcc227032014-07-17 15:33:06 -0700849 return (finalResult == OK ? -EWOULDBLOCK : finalResult);
Andreas Huberafed0e12011-09-20 15:39:58 -0700850 }
851
852 status_t result = track->mPackets->dequeueAccessUnit(accessUnit);
853
Robert Shih3423bbd2014-07-16 15:47:09 -0700854 if (!track->mPackets->hasBufferAvailable(&finalResult)) {
Robert Shih17f6dd62014-08-20 17:00:21 -0700855 postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
Lajos Molnare26940f2014-07-31 10:31:26 -0700856 }
857
Robert Shih3423bbd2014-07-16 15:47:09 -0700858 if (result != OK) {
Lajos Molnare26940f2014-07-31 10:31:26 -0700859 if (mSubtitleTrack.mSource != NULL) {
860 mSubtitleTrack.mPackets->clear();
861 mFetchSubtitleDataGeneration++;
862 }
863 if (mTimedTextTrack.mSource != NULL) {
864 mTimedTextTrack.mPackets->clear();
865 mFetchTimedTextDataGeneration++;
866 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700867 return result;
868 }
869
870 int64_t timeUs;
871 status_t eosResult; // ignored
872 CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs));
Robert Shih5c67ddc2014-11-04 17:46:05 -0800873 if (audio) {
874 mAudioLastDequeueTimeUs = timeUs;
875 } else {
876 mVideoLastDequeueTimeUs = timeUs;
877 }
Lajos Molnare26940f2014-07-31 10:31:26 -0700878
879 if (mSubtitleTrack.mSource != NULL
880 && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
Robert Shih3423bbd2014-07-16 15:47:09 -0700881 sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, id());
882 msg->setInt64("timeUs", timeUs);
883 msg->setInt32("generation", mFetchSubtitleDataGeneration);
884 msg->post();
885 }
Robert Shiheb1735e2014-07-23 15:53:14 -0700886
Lajos Molnare26940f2014-07-31 10:31:26 -0700887 if (mTimedTextTrack.mSource != NULL
888 && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
889 sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, id());
890 msg->setInt64("timeUs", timeUs);
891 msg->setInt32("generation", mFetchTimedTextDataGeneration);
892 msg->post();
893 }
894
Andreas Huberafed0e12011-09-20 15:39:58 -0700895 return result;
896}
897
898status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) {
899 *durationUs = mDurationUs;
900 return OK;
901}
902
Robert Shihdd235722014-06-12 14:49:23 -0700903size_t NuPlayer::GenericSource::getTrackCount() const {
904 return mSources.size();
905}
906
907sp<AMessage> NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const {
908 size_t trackCount = mSources.size();
909 if (trackIndex >= trackCount) {
910 return NULL;
911 }
912
913 sp<AMessage> format = new AMessage();
914 sp<MetaData> meta = mSources.itemAt(trackIndex)->getFormat();
915
916 const char *mime;
917 CHECK(meta->findCString(kKeyMIMEType, &mime));
918
919 int32_t trackType;
920 if (!strncasecmp(mime, "video/", 6)) {
921 trackType = MEDIA_TRACK_TYPE_VIDEO;
922 } else if (!strncasecmp(mime, "audio/", 6)) {
923 trackType = MEDIA_TRACK_TYPE_AUDIO;
924 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
925 trackType = MEDIA_TRACK_TYPE_TIMEDTEXT;
926 } else {
927 trackType = MEDIA_TRACK_TYPE_UNKNOWN;
928 }
929 format->setInt32("type", trackType);
930
931 const char *lang;
932 if (!meta->findCString(kKeyMediaLanguage, &lang)) {
933 lang = "und";
934 }
935 format->setString("language", lang);
936
937 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
938 format->setString("mime", mime);
939
940 int32_t isAutoselect = 1, isDefault = 0, isForced = 0;
941 meta->findInt32(kKeyTrackIsAutoselect, &isAutoselect);
942 meta->findInt32(kKeyTrackIsDefault, &isDefault);
943 meta->findInt32(kKeyTrackIsForced, &isForced);
944
945 format->setInt32("auto", !!isAutoselect);
946 format->setInt32("default", !!isDefault);
947 format->setInt32("forced", !!isForced);
948 }
949
950 return format;
951}
952
Lajos Molnare26940f2014-07-31 10:31:26 -0700953ssize_t NuPlayer::GenericSource::getSelectedTrack(media_track_type type) const {
Robert Shih17f6dd62014-08-20 17:00:21 -0700954 sp<AMessage> msg = new AMessage(kWhatGetSelectedTrack, id());
955 msg->setInt32("type", type);
956
957 sp<AMessage> response;
958 int32_t index;
959 status_t err = msg->postAndAwaitResponse(&response);
960 if (err == OK && response != NULL) {
961 CHECK(response->findInt32("index", &index));
962 return index;
963 } else {
964 return -1;
965 }
966}
967
968void NuPlayer::GenericSource::onGetSelectedTrack(sp<AMessage> msg) const {
969 int32_t tmpType;
970 CHECK(msg->findInt32("type", &tmpType));
971 media_track_type type = (media_track_type)tmpType;
972
973 sp<AMessage> response = new AMessage;
974 ssize_t index = doGetSelectedTrack(type);
975 response->setInt32("index", index);
976
977 uint32_t replyID;
978 CHECK(msg->senderAwaitsResponse(&replyID));
979 response->postReply(replyID);
980}
981
982ssize_t NuPlayer::GenericSource::doGetSelectedTrack(media_track_type type) const {
Lajos Molnare26940f2014-07-31 10:31:26 -0700983 const Track *track = NULL;
984 switch (type) {
985 case MEDIA_TRACK_TYPE_VIDEO:
986 track = &mVideoTrack;
987 break;
988 case MEDIA_TRACK_TYPE_AUDIO:
989 track = &mAudioTrack;
990 break;
991 case MEDIA_TRACK_TYPE_TIMEDTEXT:
992 track = &mTimedTextTrack;
993 break;
994 case MEDIA_TRACK_TYPE_SUBTITLE:
995 track = &mSubtitleTrack;
996 break;
997 default:
998 break;
999 }
1000
1001 if (track != NULL && track->mSource != NULL) {
1002 return track->mIndex;
1003 }
1004
1005 return -1;
1006}
1007
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001008status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select, int64_t timeUs) {
Lajos Molnare26940f2014-07-31 10:31:26 -07001009 ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex);
Robert Shih17f6dd62014-08-20 17:00:21 -07001010 sp<AMessage> msg = new AMessage(kWhatSelectTrack, id());
1011 msg->setInt32("trackIndex", trackIndex);
Robert Shihda23ab92014-09-16 11:34:08 -07001012 msg->setInt32("select", select);
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001013 msg->setInt64("timeUs", timeUs);
Robert Shih17f6dd62014-08-20 17:00:21 -07001014
1015 sp<AMessage> response;
1016 status_t err = msg->postAndAwaitResponse(&response);
1017 if (err == OK && response != NULL) {
1018 CHECK(response->findInt32("err", &err));
1019 }
1020
1021 return err;
1022}
1023
1024void NuPlayer::GenericSource::onSelectTrack(sp<AMessage> msg) {
1025 int32_t trackIndex, select;
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001026 int64_t timeUs;
Robert Shih17f6dd62014-08-20 17:00:21 -07001027 CHECK(msg->findInt32("trackIndex", &trackIndex));
1028 CHECK(msg->findInt32("select", &select));
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001029 CHECK(msg->findInt64("timeUs", &timeUs));
Robert Shih17f6dd62014-08-20 17:00:21 -07001030
1031 sp<AMessage> response = new AMessage;
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001032 status_t err = doSelectTrack(trackIndex, select, timeUs);
Robert Shih17f6dd62014-08-20 17:00:21 -07001033 response->setInt32("err", err);
1034
1035 uint32_t replyID;
1036 CHECK(msg->senderAwaitsResponse(&replyID));
1037 response->postReply(replyID);
1038}
1039
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001040status_t NuPlayer::GenericSource::doSelectTrack(size_t trackIndex, bool select, int64_t timeUs) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001041 if (trackIndex >= mSources.size()) {
1042 return BAD_INDEX;
1043 }
1044
1045 if (!select) {
Lajos Molnare26940f2014-07-31 10:31:26 -07001046 Track* track = NULL;
1047 if (mSubtitleTrack.mSource != NULL && trackIndex == mSubtitleTrack.mIndex) {
1048 track = &mSubtitleTrack;
1049 mFetchSubtitleDataGeneration++;
1050 } else if (mTimedTextTrack.mSource != NULL && trackIndex == mTimedTextTrack.mIndex) {
1051 track = &mTimedTextTrack;
1052 mFetchTimedTextDataGeneration++;
1053 }
1054 if (track == NULL) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001055 return INVALID_OPERATION;
1056 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001057 track->mSource->stop();
1058 track->mSource = NULL;
1059 track->mPackets->clear();
Robert Shih3423bbd2014-07-16 15:47:09 -07001060 return OK;
1061 }
1062
1063 const sp<MediaSource> source = mSources.itemAt(trackIndex);
1064 sp<MetaData> meta = source->getFormat();
1065 const char *mime;
1066 CHECK(meta->findCString(kKeyMIMEType, &mime));
1067 if (!strncasecmp(mime, "text/", 5)) {
Lajos Molnare26940f2014-07-31 10:31:26 -07001068 bool isSubtitle = strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP);
1069 Track *track = isSubtitle ? &mSubtitleTrack : &mTimedTextTrack;
1070 if (track->mSource != NULL && track->mIndex == trackIndex) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001071 return OK;
1072 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001073 track->mIndex = trackIndex;
1074 if (track->mSource != NULL) {
1075 track->mSource->stop();
Robert Shih3423bbd2014-07-16 15:47:09 -07001076 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001077 track->mSource = mSources.itemAt(trackIndex);
1078 track->mSource->start();
1079 if (track->mPackets == NULL) {
1080 track->mPackets = new AnotherPacketSource(track->mSource->getFormat());
Robert Shih3423bbd2014-07-16 15:47:09 -07001081 } else {
Lajos Molnare26940f2014-07-31 10:31:26 -07001082 track->mPackets->clear();
1083 track->mPackets->setFormat(track->mSource->getFormat());
Robert Shih3423bbd2014-07-16 15:47:09 -07001084
1085 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001086
1087 if (isSubtitle) {
1088 mFetchSubtitleDataGeneration++;
1089 } else {
1090 mFetchTimedTextDataGeneration++;
1091 }
1092
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001093 status_t eosResult; // ignored
1094 if (mSubtitleTrack.mSource != NULL
1095 && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
1096 sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, id());
1097 msg->setInt64("timeUs", timeUs);
1098 msg->setInt32("generation", mFetchSubtitleDataGeneration);
1099 msg->post();
1100 }
1101
1102 if (mTimedTextTrack.mSource != NULL
1103 && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
1104 sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, id());
1105 msg->setInt64("timeUs", timeUs);
1106 msg->setInt32("generation", mFetchTimedTextDataGeneration);
1107 msg->post();
1108 }
1109
Robert Shih3423bbd2014-07-16 15:47:09 -07001110 return OK;
1111 } else if (!strncasecmp(mime, "audio/", 6) || !strncasecmp(mime, "video/", 6)) {
1112 bool audio = !strncasecmp(mime, "audio/", 6);
1113 Track *track = audio ? &mAudioTrack : &mVideoTrack;
1114 if (track->mSource != NULL && track->mIndex == trackIndex) {
1115 return OK;
1116 }
1117
1118 sp<AMessage> msg = new AMessage(kWhatChangeAVSource, id());
1119 msg->setInt32("trackIndex", trackIndex);
1120 msg->post();
1121 return OK;
1122 }
1123
1124 return INVALID_OPERATION;
1125}
1126
Andreas Huberafed0e12011-09-20 15:39:58 -07001127status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) {
Robert Shih17f6dd62014-08-20 17:00:21 -07001128 sp<AMessage> msg = new AMessage(kWhatSeek, id());
1129 msg->setInt64("seekTimeUs", seekTimeUs);
1130
1131 sp<AMessage> response;
1132 status_t err = msg->postAndAwaitResponse(&response);
1133 if (err == OK && response != NULL) {
1134 CHECK(response->findInt32("err", &err));
1135 }
1136
1137 return err;
1138}
1139
1140void NuPlayer::GenericSource::onSeek(sp<AMessage> msg) {
1141 int64_t seekTimeUs;
1142 CHECK(msg->findInt64("seekTimeUs", &seekTimeUs));
1143
1144 sp<AMessage> response = new AMessage;
1145 status_t err = doSeek(seekTimeUs);
1146 response->setInt32("err", err);
1147
1148 uint32_t replyID;
1149 CHECK(msg->senderAwaitsResponse(&replyID));
1150 response->postReply(replyID);
1151}
1152
1153status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs) {
Andy Hung2abde2c2014-09-30 14:40:32 -07001154 // If the Widevine source is stopped, do not attempt to read any
1155 // more buffers.
1156 if (mStopRead) {
1157 return INVALID_OPERATION;
1158 }
Andreas Huberafed0e12011-09-20 15:39:58 -07001159 if (mVideoTrack.mSource != NULL) {
1160 int64_t actualTimeUs;
Robert Shih3423bbd2014-07-16 15:47:09 -07001161 readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, &actualTimeUs);
Andreas Huberafed0e12011-09-20 15:39:58 -07001162
1163 seekTimeUs = actualTimeUs;
Robert Shih5c67ddc2014-11-04 17:46:05 -08001164 mVideoLastDequeueTimeUs = seekTimeUs;
Andreas Huberafed0e12011-09-20 15:39:58 -07001165 }
1166
1167 if (mAudioTrack.mSource != NULL) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001168 readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs);
Robert Shih5c67ddc2014-11-04 17:46:05 -08001169 mAudioLastDequeueTimeUs = seekTimeUs;
Andreas Huberafed0e12011-09-20 15:39:58 -07001170 }
1171
Ronghua Wu80276872014-08-28 15:50:29 -07001172 setDrmPlaybackStatusIfNeeded(Playback::START, seekTimeUs / 1000);
1173 if (!mStarted) {
1174 setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0);
1175 }
Andreas Huberafed0e12011-09-20 15:39:58 -07001176 return OK;
1177}
1178
Robert Shih3423bbd2014-07-16 15:47:09 -07001179sp<ABuffer> NuPlayer::GenericSource::mediaBufferToABuffer(
1180 MediaBuffer* mb,
1181 media_track_type trackType,
Wei Jia474d7c72014-12-04 15:12:13 -08001182 int64_t /* seekTimeUs */,
Robert Shih3423bbd2014-07-16 15:47:09 -07001183 int64_t *actualTimeUs) {
1184 bool audio = trackType == MEDIA_TRACK_TYPE_AUDIO;
1185 size_t outLength = mb->range_length();
1186
1187 if (audio && mAudioIsVorbis) {
1188 outLength += sizeof(int32_t);
1189 }
1190
1191 sp<ABuffer> ab;
1192 if (mIsWidevine && !audio) {
1193 // data is already provided in the buffer
1194 ab = new ABuffer(NULL, mb->range_length());
Robert Shih3423bbd2014-07-16 15:47:09 -07001195 mb->add_ref();
Wei Jia96e92b52014-09-18 17:36:20 -07001196 ab->setMediaBufferBase(mb);
Robert Shih3423bbd2014-07-16 15:47:09 -07001197 } else {
1198 ab = new ABuffer(outLength);
1199 memcpy(ab->data(),
1200 (const uint8_t *)mb->data() + mb->range_offset(),
1201 mb->range_length());
1202 }
1203
1204 if (audio && mAudioIsVorbis) {
1205 int32_t numPageSamples;
1206 if (!mb->meta_data()->findInt32(kKeyValidSamples, &numPageSamples)) {
1207 numPageSamples = -1;
1208 }
1209
1210 uint8_t* abEnd = ab->data() + mb->range_length();
1211 memcpy(abEnd, &numPageSamples, sizeof(numPageSamples));
1212 }
1213
Lajos Molnare26940f2014-07-31 10:31:26 -07001214 sp<AMessage> meta = ab->meta();
1215
Robert Shih3423bbd2014-07-16 15:47:09 -07001216 int64_t timeUs;
1217 CHECK(mb->meta_data()->findInt64(kKeyTime, &timeUs));
Robert Shih3423bbd2014-07-16 15:47:09 -07001218 meta->setInt64("timeUs", timeUs);
1219
Wei Jia474d7c72014-12-04 15:12:13 -08001220#if 0
1221 // Temporarily disable pre-roll till we have a full solution to handle
1222 // both single seek and continous seek gracefully.
1223 if (seekTimeUs > timeUs) {
1224 sp<AMessage> extra = new AMessage;
1225 extra->setInt64("resume-at-mediaTimeUs", seekTimeUs);
1226 meta->setMessage("extra", extra);
1227 }
1228#endif
1229
Lajos Molnare26940f2014-07-31 10:31:26 -07001230 if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) {
1231 const char *mime;
1232 CHECK(mTimedTextTrack.mSource != NULL
1233 && mTimedTextTrack.mSource->getFormat()->findCString(kKeyMIMEType, &mime));
1234 meta->setString("mime", mime);
1235 }
1236
Robert Shih3423bbd2014-07-16 15:47:09 -07001237 int64_t durationUs;
1238 if (mb->meta_data()->findInt64(kKeyDuration, &durationUs)) {
1239 meta->setInt64("durationUs", durationUs);
1240 }
1241
1242 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
1243 meta->setInt32("trackIndex", mSubtitleTrack.mIndex);
1244 }
1245
1246 if (actualTimeUs) {
1247 *actualTimeUs = timeUs;
1248 }
1249
1250 mb->release();
1251 mb = NULL;
1252
1253 return ab;
1254}
1255
Robert Shih17f6dd62014-08-20 17:00:21 -07001256void NuPlayer::GenericSource::postReadBuffer(media_track_type trackType) {
Lajos Molnar84f52782014-09-11 10:01:55 -07001257 Mutex::Autolock _l(mReadBufferLock);
1258
1259 if ((mPendingReadBufferTypes & (1 << trackType)) == 0) {
1260 mPendingReadBufferTypes |= (1 << trackType);
1261 sp<AMessage> msg = new AMessage(kWhatReadBuffer, id());
1262 msg->setInt32("trackType", trackType);
1263 msg->post();
1264 }
Robert Shih17f6dd62014-08-20 17:00:21 -07001265}
1266
1267void NuPlayer::GenericSource::onReadBuffer(sp<AMessage> msg) {
1268 int32_t tmpType;
1269 CHECK(msg->findInt32("trackType", &tmpType));
1270 media_track_type trackType = (media_track_type)tmpType;
Lajos Molnar84f52782014-09-11 10:01:55 -07001271 {
1272 // only protect the variable change, as readBuffer may
1273 // take considerable time. This may result in one extra
1274 // read being processed, but that is benign.
1275 Mutex::Autolock _l(mReadBufferLock);
1276 mPendingReadBufferTypes &= ~(1 << trackType);
1277 }
Robert Shih17f6dd62014-08-20 17:00:21 -07001278 readBuffer(trackType);
1279}
1280
Andreas Huberafed0e12011-09-20 15:39:58 -07001281void NuPlayer::GenericSource::readBuffer(
Robert Shih3423bbd2014-07-16 15:47:09 -07001282 media_track_type trackType, int64_t seekTimeUs, int64_t *actualTimeUs, bool formatChange) {
Andy Hung2abde2c2014-09-30 14:40:32 -07001283 // Do not read data if Widevine source is stopped
1284 if (mStopRead) {
1285 return;
1286 }
Robert Shih3423bbd2014-07-16 15:47:09 -07001287 Track *track;
Phil Burkc5cc2e22014-09-09 20:08:39 -07001288 size_t maxBuffers = 1;
Robert Shih3423bbd2014-07-16 15:47:09 -07001289 switch (trackType) {
1290 case MEDIA_TRACK_TYPE_VIDEO:
1291 track = &mVideoTrack;
Jeff Tinkera28785a2014-09-23 22:24:26 -07001292 if (mIsWidevine) {
1293 maxBuffers = 2;
1294 }
Robert Shih3423bbd2014-07-16 15:47:09 -07001295 break;
1296 case MEDIA_TRACK_TYPE_AUDIO:
1297 track = &mAudioTrack;
Jeff Tinkera28785a2014-09-23 22:24:26 -07001298 if (mIsWidevine) {
1299 maxBuffers = 8;
1300 } else {
1301 maxBuffers = 64;
1302 }
Robert Shih3423bbd2014-07-16 15:47:09 -07001303 break;
1304 case MEDIA_TRACK_TYPE_SUBTITLE:
1305 track = &mSubtitleTrack;
1306 break;
Lajos Molnare26940f2014-07-31 10:31:26 -07001307 case MEDIA_TRACK_TYPE_TIMEDTEXT:
1308 track = &mTimedTextTrack;
1309 break;
Robert Shih3423bbd2014-07-16 15:47:09 -07001310 default:
1311 TRESPASS();
1312 }
1313
1314 if (track->mSource == NULL) {
1315 return;
1316 }
Andreas Huberafed0e12011-09-20 15:39:58 -07001317
1318 if (actualTimeUs) {
1319 *actualTimeUs = seekTimeUs;
1320 }
1321
1322 MediaSource::ReadOptions options;
1323
1324 bool seeking = false;
1325
1326 if (seekTimeUs >= 0) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001327 options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
Andreas Huberafed0e12011-09-20 15:39:58 -07001328 seeking = true;
1329 }
1330
Robert Shih3423bbd2014-07-16 15:47:09 -07001331 if (mIsWidevine && trackType != MEDIA_TRACK_TYPE_AUDIO) {
Lajos Molnarcc227032014-07-17 15:33:06 -07001332 options.setNonBlocking();
1333 }
1334
Phil Burkc5cc2e22014-09-09 20:08:39 -07001335 for (size_t numBuffers = 0; numBuffers < maxBuffers; ) {
Andreas Huberafed0e12011-09-20 15:39:58 -07001336 MediaBuffer *mbuf;
1337 status_t err = track->mSource->read(&mbuf, &options);
1338
1339 options.clearSeekTo();
1340
1341 if (err == OK) {
Ronghua Wu80276872014-08-28 15:50:29 -07001342 int64_t timeUs;
1343 CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs));
1344 if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
1345 mAudioTimeUs = timeUs;
1346 } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
1347 mVideoTimeUs = timeUs;
1348 }
1349
Robert Shih3423bbd2014-07-16 15:47:09 -07001350 // formatChange && seeking: track whose source is changed during selection
1351 // formatChange && !seeking: track whose source is not changed during selection
1352 // !formatChange: normal seek
Lajos Molnare26940f2014-07-31 10:31:26 -07001353 if ((seeking || formatChange)
1354 && (trackType == MEDIA_TRACK_TYPE_AUDIO
1355 || trackType == MEDIA_TRACK_TYPE_VIDEO)) {
Wei Jiafef808d2014-10-31 17:57:05 -07001356 ATSParser::DiscontinuityType type = (formatChange && seeking)
1357 ? ATSParser::DISCONTINUITY_FORMATCHANGE
1358 : ATSParser::DISCONTINUITY_NONE;
Robert Shih3423bbd2014-07-16 15:47:09 -07001359 track->mPackets->queueDiscontinuity( type, NULL, true /* discard */);
Andreas Huberafed0e12011-09-20 15:39:58 -07001360 }
1361
Wei Jia474d7c72014-12-04 15:12:13 -08001362 sp<ABuffer> buffer = mediaBufferToABuffer(
1363 mbuf, trackType, seekTimeUs, actualTimeUs);
Andreas Huberafed0e12011-09-20 15:39:58 -07001364 track->mPackets->queueAccessUnit(buffer);
Marco Nelissen317a49a2014-09-16 21:32:33 -07001365 formatChange = false;
1366 seeking = false;
Phil Burkc5cc2e22014-09-09 20:08:39 -07001367 ++numBuffers;
Lajos Molnarcc227032014-07-17 15:33:06 -07001368 } else if (err == WOULD_BLOCK) {
1369 break;
Andreas Huberafed0e12011-09-20 15:39:58 -07001370 } else if (err == INFO_FORMAT_CHANGED) {
1371#if 0
1372 track->mPackets->queueDiscontinuity(
Chong Zhang632740c2014-06-26 13:03:47 -07001373 ATSParser::DISCONTINUITY_FORMATCHANGE,
1374 NULL,
1375 false /* discard */);
Andreas Huberafed0e12011-09-20 15:39:58 -07001376#endif
1377 } else {
1378 track->mPackets->signalEOS(err);
1379 break;
1380 }
1381 }
1382}
1383
Andreas Huberafed0e12011-09-20 15:39:58 -07001384} // namespace android