blob: eb10dda8e068690e9510b7df397b608ad9fadec5 [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 Shih3423bbd2014-07-16 15:47:09 -07001008status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select) {
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 Shih17f6dd62014-08-20 17:00:21 -07001013
1014 sp<AMessage> response;
1015 status_t err = msg->postAndAwaitResponse(&response);
1016 if (err == OK && response != NULL) {
1017 CHECK(response->findInt32("err", &err));
1018 }
1019
1020 return err;
1021}
1022
1023void NuPlayer::GenericSource::onSelectTrack(sp<AMessage> msg) {
1024 int32_t trackIndex, select;
1025 CHECK(msg->findInt32("trackIndex", &trackIndex));
1026 CHECK(msg->findInt32("select", &select));
1027
1028 sp<AMessage> response = new AMessage;
1029 status_t err = doSelectTrack(trackIndex, select);
1030 response->setInt32("err", err);
1031
1032 uint32_t replyID;
1033 CHECK(msg->senderAwaitsResponse(&replyID));
1034 response->postReply(replyID);
1035}
1036
1037status_t NuPlayer::GenericSource::doSelectTrack(size_t trackIndex, bool select) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001038 if (trackIndex >= mSources.size()) {
1039 return BAD_INDEX;
1040 }
1041
1042 if (!select) {
Lajos Molnare26940f2014-07-31 10:31:26 -07001043 Track* track = NULL;
1044 if (mSubtitleTrack.mSource != NULL && trackIndex == mSubtitleTrack.mIndex) {
1045 track = &mSubtitleTrack;
1046 mFetchSubtitleDataGeneration++;
1047 } else if (mTimedTextTrack.mSource != NULL && trackIndex == mTimedTextTrack.mIndex) {
1048 track = &mTimedTextTrack;
1049 mFetchTimedTextDataGeneration++;
1050 }
1051 if (track == NULL) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001052 return INVALID_OPERATION;
1053 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001054 track->mSource->stop();
1055 track->mSource = NULL;
1056 track->mPackets->clear();
Robert Shih3423bbd2014-07-16 15:47:09 -07001057 return OK;
1058 }
1059
1060 const sp<MediaSource> source = mSources.itemAt(trackIndex);
1061 sp<MetaData> meta = source->getFormat();
1062 const char *mime;
1063 CHECK(meta->findCString(kKeyMIMEType, &mime));
1064 if (!strncasecmp(mime, "text/", 5)) {
Lajos Molnare26940f2014-07-31 10:31:26 -07001065 bool isSubtitle = strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP);
1066 Track *track = isSubtitle ? &mSubtitleTrack : &mTimedTextTrack;
1067 if (track->mSource != NULL && track->mIndex == trackIndex) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001068 return OK;
1069 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001070 track->mIndex = trackIndex;
1071 if (track->mSource != NULL) {
1072 track->mSource->stop();
Robert Shih3423bbd2014-07-16 15:47:09 -07001073 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001074 track->mSource = mSources.itemAt(trackIndex);
1075 track->mSource->start();
1076 if (track->mPackets == NULL) {
1077 track->mPackets = new AnotherPacketSource(track->mSource->getFormat());
Robert Shih3423bbd2014-07-16 15:47:09 -07001078 } else {
Lajos Molnare26940f2014-07-31 10:31:26 -07001079 track->mPackets->clear();
1080 track->mPackets->setFormat(track->mSource->getFormat());
Robert Shih3423bbd2014-07-16 15:47:09 -07001081
1082 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001083
1084 if (isSubtitle) {
1085 mFetchSubtitleDataGeneration++;
1086 } else {
1087 mFetchTimedTextDataGeneration++;
1088 }
1089
Robert Shih3423bbd2014-07-16 15:47:09 -07001090 return OK;
1091 } else if (!strncasecmp(mime, "audio/", 6) || !strncasecmp(mime, "video/", 6)) {
1092 bool audio = !strncasecmp(mime, "audio/", 6);
1093 Track *track = audio ? &mAudioTrack : &mVideoTrack;
1094 if (track->mSource != NULL && track->mIndex == trackIndex) {
1095 return OK;
1096 }
1097
1098 sp<AMessage> msg = new AMessage(kWhatChangeAVSource, id());
1099 msg->setInt32("trackIndex", trackIndex);
1100 msg->post();
1101 return OK;
1102 }
1103
1104 return INVALID_OPERATION;
1105}
1106
Andreas Huberafed0e12011-09-20 15:39:58 -07001107status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) {
Robert Shih17f6dd62014-08-20 17:00:21 -07001108 sp<AMessage> msg = new AMessage(kWhatSeek, id());
1109 msg->setInt64("seekTimeUs", seekTimeUs);
1110
1111 sp<AMessage> response;
1112 status_t err = msg->postAndAwaitResponse(&response);
1113 if (err == OK && response != NULL) {
1114 CHECK(response->findInt32("err", &err));
1115 }
1116
1117 return err;
1118}
1119
1120void NuPlayer::GenericSource::onSeek(sp<AMessage> msg) {
1121 int64_t seekTimeUs;
1122 CHECK(msg->findInt64("seekTimeUs", &seekTimeUs));
1123
1124 sp<AMessage> response = new AMessage;
1125 status_t err = doSeek(seekTimeUs);
1126 response->setInt32("err", err);
1127
1128 uint32_t replyID;
1129 CHECK(msg->senderAwaitsResponse(&replyID));
1130 response->postReply(replyID);
1131}
1132
1133status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs) {
Andy Hung2abde2c2014-09-30 14:40:32 -07001134 // If the Widevine source is stopped, do not attempt to read any
1135 // more buffers.
1136 if (mStopRead) {
1137 return INVALID_OPERATION;
1138 }
Andreas Huberafed0e12011-09-20 15:39:58 -07001139 if (mVideoTrack.mSource != NULL) {
1140 int64_t actualTimeUs;
Robert Shih3423bbd2014-07-16 15:47:09 -07001141 readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, &actualTimeUs);
Andreas Huberafed0e12011-09-20 15:39:58 -07001142
1143 seekTimeUs = actualTimeUs;
Robert Shih5c67ddc2014-11-04 17:46:05 -08001144 mVideoLastDequeueTimeUs = seekTimeUs;
Andreas Huberafed0e12011-09-20 15:39:58 -07001145 }
1146
1147 if (mAudioTrack.mSource != NULL) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001148 readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs);
Robert Shih5c67ddc2014-11-04 17:46:05 -08001149 mAudioLastDequeueTimeUs = seekTimeUs;
Andreas Huberafed0e12011-09-20 15:39:58 -07001150 }
1151
Ronghua Wu80276872014-08-28 15:50:29 -07001152 setDrmPlaybackStatusIfNeeded(Playback::START, seekTimeUs / 1000);
1153 if (!mStarted) {
1154 setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0);
1155 }
Andreas Huberafed0e12011-09-20 15:39:58 -07001156 return OK;
1157}
1158
Robert Shih3423bbd2014-07-16 15:47:09 -07001159sp<ABuffer> NuPlayer::GenericSource::mediaBufferToABuffer(
1160 MediaBuffer* mb,
1161 media_track_type trackType,
1162 int64_t *actualTimeUs) {
1163 bool audio = trackType == MEDIA_TRACK_TYPE_AUDIO;
1164 size_t outLength = mb->range_length();
1165
1166 if (audio && mAudioIsVorbis) {
1167 outLength += sizeof(int32_t);
1168 }
1169
1170 sp<ABuffer> ab;
1171 if (mIsWidevine && !audio) {
1172 // data is already provided in the buffer
1173 ab = new ABuffer(NULL, mb->range_length());
Robert Shih3423bbd2014-07-16 15:47:09 -07001174 mb->add_ref();
Wei Jia96e92b52014-09-18 17:36:20 -07001175 ab->setMediaBufferBase(mb);
Robert Shih3423bbd2014-07-16 15:47:09 -07001176 } else {
1177 ab = new ABuffer(outLength);
1178 memcpy(ab->data(),
1179 (const uint8_t *)mb->data() + mb->range_offset(),
1180 mb->range_length());
1181 }
1182
1183 if (audio && mAudioIsVorbis) {
1184 int32_t numPageSamples;
1185 if (!mb->meta_data()->findInt32(kKeyValidSamples, &numPageSamples)) {
1186 numPageSamples = -1;
1187 }
1188
1189 uint8_t* abEnd = ab->data() + mb->range_length();
1190 memcpy(abEnd, &numPageSamples, sizeof(numPageSamples));
1191 }
1192
Lajos Molnare26940f2014-07-31 10:31:26 -07001193 sp<AMessage> meta = ab->meta();
1194
Robert Shih3423bbd2014-07-16 15:47:09 -07001195 int64_t timeUs;
1196 CHECK(mb->meta_data()->findInt64(kKeyTime, &timeUs));
Robert Shih3423bbd2014-07-16 15:47:09 -07001197 meta->setInt64("timeUs", timeUs);
1198
Lajos Molnare26940f2014-07-31 10:31:26 -07001199 if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) {
1200 const char *mime;
1201 CHECK(mTimedTextTrack.mSource != NULL
1202 && mTimedTextTrack.mSource->getFormat()->findCString(kKeyMIMEType, &mime));
1203 meta->setString("mime", mime);
1204 }
1205
Robert Shih3423bbd2014-07-16 15:47:09 -07001206 int64_t durationUs;
1207 if (mb->meta_data()->findInt64(kKeyDuration, &durationUs)) {
1208 meta->setInt64("durationUs", durationUs);
1209 }
1210
1211 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
1212 meta->setInt32("trackIndex", mSubtitleTrack.mIndex);
1213 }
1214
1215 if (actualTimeUs) {
1216 *actualTimeUs = timeUs;
1217 }
1218
1219 mb->release();
1220 mb = NULL;
1221
1222 return ab;
1223}
1224
Robert Shih17f6dd62014-08-20 17:00:21 -07001225void NuPlayer::GenericSource::postReadBuffer(media_track_type trackType) {
Lajos Molnar84f52782014-09-11 10:01:55 -07001226 Mutex::Autolock _l(mReadBufferLock);
1227
1228 if ((mPendingReadBufferTypes & (1 << trackType)) == 0) {
1229 mPendingReadBufferTypes |= (1 << trackType);
1230 sp<AMessage> msg = new AMessage(kWhatReadBuffer, id());
1231 msg->setInt32("trackType", trackType);
1232 msg->post();
1233 }
Robert Shih17f6dd62014-08-20 17:00:21 -07001234}
1235
1236void NuPlayer::GenericSource::onReadBuffer(sp<AMessage> msg) {
1237 int32_t tmpType;
1238 CHECK(msg->findInt32("trackType", &tmpType));
1239 media_track_type trackType = (media_track_type)tmpType;
Lajos Molnar84f52782014-09-11 10:01:55 -07001240 {
1241 // only protect the variable change, as readBuffer may
1242 // take considerable time. This may result in one extra
1243 // read being processed, but that is benign.
1244 Mutex::Autolock _l(mReadBufferLock);
1245 mPendingReadBufferTypes &= ~(1 << trackType);
1246 }
Robert Shih17f6dd62014-08-20 17:00:21 -07001247 readBuffer(trackType);
1248}
1249
Andreas Huberafed0e12011-09-20 15:39:58 -07001250void NuPlayer::GenericSource::readBuffer(
Robert Shih3423bbd2014-07-16 15:47:09 -07001251 media_track_type trackType, int64_t seekTimeUs, int64_t *actualTimeUs, bool formatChange) {
Andy Hung2abde2c2014-09-30 14:40:32 -07001252 // Do not read data if Widevine source is stopped
1253 if (mStopRead) {
1254 return;
1255 }
Robert Shih3423bbd2014-07-16 15:47:09 -07001256 Track *track;
Phil Burkc5cc2e22014-09-09 20:08:39 -07001257 size_t maxBuffers = 1;
Robert Shih3423bbd2014-07-16 15:47:09 -07001258 switch (trackType) {
1259 case MEDIA_TRACK_TYPE_VIDEO:
1260 track = &mVideoTrack;
Jeff Tinkera28785a2014-09-23 22:24:26 -07001261 if (mIsWidevine) {
1262 maxBuffers = 2;
1263 }
Robert Shih3423bbd2014-07-16 15:47:09 -07001264 break;
1265 case MEDIA_TRACK_TYPE_AUDIO:
1266 track = &mAudioTrack;
Jeff Tinkera28785a2014-09-23 22:24:26 -07001267 if (mIsWidevine) {
1268 maxBuffers = 8;
1269 } else {
1270 maxBuffers = 64;
1271 }
Robert Shih3423bbd2014-07-16 15:47:09 -07001272 break;
1273 case MEDIA_TRACK_TYPE_SUBTITLE:
1274 track = &mSubtitleTrack;
1275 break;
Lajos Molnare26940f2014-07-31 10:31:26 -07001276 case MEDIA_TRACK_TYPE_TIMEDTEXT:
1277 track = &mTimedTextTrack;
1278 break;
Robert Shih3423bbd2014-07-16 15:47:09 -07001279 default:
1280 TRESPASS();
1281 }
1282
1283 if (track->mSource == NULL) {
1284 return;
1285 }
Andreas Huberafed0e12011-09-20 15:39:58 -07001286
1287 if (actualTimeUs) {
1288 *actualTimeUs = seekTimeUs;
1289 }
1290
1291 MediaSource::ReadOptions options;
1292
1293 bool seeking = false;
1294
1295 if (seekTimeUs >= 0) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001296 options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
Andreas Huberafed0e12011-09-20 15:39:58 -07001297 seeking = true;
1298 }
1299
Robert Shih3423bbd2014-07-16 15:47:09 -07001300 if (mIsWidevine && trackType != MEDIA_TRACK_TYPE_AUDIO) {
Lajos Molnarcc227032014-07-17 15:33:06 -07001301 options.setNonBlocking();
1302 }
1303
Phil Burkc5cc2e22014-09-09 20:08:39 -07001304 for (size_t numBuffers = 0; numBuffers < maxBuffers; ) {
Andreas Huberafed0e12011-09-20 15:39:58 -07001305 MediaBuffer *mbuf;
1306 status_t err = track->mSource->read(&mbuf, &options);
1307
1308 options.clearSeekTo();
1309
1310 if (err == OK) {
Ronghua Wu80276872014-08-28 15:50:29 -07001311 int64_t timeUs;
1312 CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs));
1313 if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
1314 mAudioTimeUs = timeUs;
1315 } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
1316 mVideoTimeUs = timeUs;
1317 }
1318
Robert Shih3423bbd2014-07-16 15:47:09 -07001319 // formatChange && seeking: track whose source is changed during selection
1320 // formatChange && !seeking: track whose source is not changed during selection
1321 // !formatChange: normal seek
Lajos Molnare26940f2014-07-31 10:31:26 -07001322 if ((seeking || formatChange)
1323 && (trackType == MEDIA_TRACK_TYPE_AUDIO
1324 || trackType == MEDIA_TRACK_TYPE_VIDEO)) {
Wei Jiafef808d2014-10-31 17:57:05 -07001325 ATSParser::DiscontinuityType type = (formatChange && seeking)
1326 ? ATSParser::DISCONTINUITY_FORMATCHANGE
1327 : ATSParser::DISCONTINUITY_NONE;
Robert Shih3423bbd2014-07-16 15:47:09 -07001328 track->mPackets->queueDiscontinuity( type, NULL, true /* discard */);
Andreas Huberafed0e12011-09-20 15:39:58 -07001329 }
1330
Robert Shih3423bbd2014-07-16 15:47:09 -07001331 sp<ABuffer> buffer = mediaBufferToABuffer(mbuf, trackType, actualTimeUs);
Andreas Huberafed0e12011-09-20 15:39:58 -07001332 track->mPackets->queueAccessUnit(buffer);
Marco Nelissen317a49a2014-09-16 21:32:33 -07001333 formatChange = false;
1334 seeking = false;
Phil Burkc5cc2e22014-09-09 20:08:39 -07001335 ++numBuffers;
Lajos Molnarcc227032014-07-17 15:33:06 -07001336 } else if (err == WOULD_BLOCK) {
1337 break;
Andreas Huberafed0e12011-09-20 15:39:58 -07001338 } else if (err == INFO_FORMAT_CHANGED) {
1339#if 0
1340 track->mPackets->queueDiscontinuity(
Chong Zhang632740c2014-06-26 13:03:47 -07001341 ATSParser::DISCONTINUITY_FORMATCHANGE,
1342 NULL,
1343 false /* discard */);
Andreas Huberafed0e12011-09-20 15:39:58 -07001344#endif
1345 } else {
1346 track->mPackets->signalEOS(err);
1347 break;
1348 }
1349 }
1350}
1351
Andreas Huberafed0e12011-09-20 15:39:58 -07001352} // namespace android