blob: 016a7647dafe0ee727f2ef04b527cd944918cbf5 [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 Shih3423bbd2014-07-16 15:47:09 -070048 mFetchSubtitleDataGeneration(0),
Lajos Molnare26940f2014-07-31 10:31:26 -070049 mFetchTimedTextDataGeneration(0),
Andreas Huberb5f25f02013-02-05 10:14:26 -080050 mDurationUs(0ll),
Lajos Molnarcc227032014-07-17 15:33:06 -070051 mAudioIsVorbis(false),
Chong Zhang3de157d2014-08-05 20:54:44 -070052 mIsWidevine(false),
Lajos Molnarcc227032014-07-17 15:33:06 -070053 mUIDValid(uidValid),
Chong Zhangd354d8d2014-08-20 13:09:58 -070054 mUID(uid),
Ronghua Wu80276872014-08-28 15:50:29 -070055 mDrmManagerClient(NULL),
Chong Zhang2a3cc9a2014-08-21 17:48:26 -070056 mMetaDataSize(-1ll),
57 mBitrate(-1ll),
Lajos Molnar84f52782014-09-11 10:01:55 -070058 mPollBufferingGeneration(0),
59 mPendingReadBufferTypes(0) {
Chong Zhanga19f33e2014-08-07 15:35:07 -070060 resetDataSource();
Andreas Huberafed0e12011-09-20 15:39:58 -070061 DataSource::RegisterDefaultSniffers();
Chong Zhang3de157d2014-08-05 20:54:44 -070062}
63
Chong Zhanga19f33e2014-08-07 15:35:07 -070064void NuPlayer::GenericSource::resetDataSource() {
Ronghua Wu80276872014-08-28 15:50:29 -070065 mAudioTimeUs = 0;
66 mVideoTimeUs = 0;
Chong Zhanga19f33e2014-08-07 15:35:07 -070067 mHTTPService.clear();
Robert Shih360d6d02014-09-29 14:42:35 -070068 mHttpSource.clear();
Chong Zhanga19f33e2014-08-07 15:35:07 -070069 mUri.clear();
70 mUriHeaders.clear();
71 mFd = -1;
72 mOffset = 0;
73 mLength = 0;
Ronghua Wu80276872014-08-28 15:50:29 -070074 setDrmPlaybackStatusIfNeeded(Playback::STOP, 0);
75 mDecryptHandle = NULL;
76 mDrmManagerClient = NULL;
77 mStarted = false;
Chong Zhanga19f33e2014-08-07 15:35:07 -070078}
79
80status_t NuPlayer::GenericSource::setDataSource(
Chong Zhang3de157d2014-08-05 20:54:44 -070081 const sp<IMediaHTTPService> &httpService,
82 const char *url,
83 const KeyedVector<String8, String8> *headers) {
Chong Zhanga19f33e2014-08-07 15:35:07 -070084 resetDataSource();
Chong Zhang3de157d2014-08-05 20:54:44 -070085
Chong Zhanga19f33e2014-08-07 15:35:07 -070086 mHTTPService = httpService;
87 mUri = url;
Andreas Huberafed0e12011-09-20 15:39:58 -070088
Chong Zhanga19f33e2014-08-07 15:35:07 -070089 if (headers) {
90 mUriHeaders = *headers;
Chong Zhang3de157d2014-08-05 20:54:44 -070091 }
92
Chong Zhanga19f33e2014-08-07 15:35:07 -070093 // delay data source creation to prepareAsync() to avoid blocking
94 // the calling thread in setDataSource for any significant time.
95 return OK;
Andreas Huberafed0e12011-09-20 15:39:58 -070096}
97
Chong Zhanga19f33e2014-08-07 15:35:07 -070098status_t NuPlayer::GenericSource::setDataSource(
Chong Zhang3de157d2014-08-05 20:54:44 -070099 int fd, int64_t offset, int64_t length) {
Chong Zhanga19f33e2014-08-07 15:35:07 -0700100 resetDataSource();
Andreas Huberafed0e12011-09-20 15:39:58 -0700101
Chong Zhanga19f33e2014-08-07 15:35:07 -0700102 mFd = dup(fd);
103 mOffset = offset;
104 mLength = length;
105
106 // delay data source creation to prepareAsync() to avoid blocking
107 // the calling thread in setDataSource for any significant time.
108 return OK;
Andreas Huberafed0e12011-09-20 15:39:58 -0700109}
110
Marco Nelissenf0b72b52014-09-16 15:43:44 -0700111sp<MetaData> NuPlayer::GenericSource::getFileFormatMeta() const {
112 return mFileMeta;
113}
114
Chong Zhangd354d8d2014-08-20 13:09:58 -0700115status_t NuPlayer::GenericSource::initFromDataSource() {
Lajos Molnarcc227032014-07-17 15:33:06 -0700116 sp<MediaExtractor> extractor;
117
Chong Zhangd354d8d2014-08-20 13:09:58 -0700118 CHECK(mDataSource != NULL);
119
Lajos Molnarcc227032014-07-17 15:33:06 -0700120 if (mIsWidevine) {
121 String8 mimeType;
122 float confidence;
123 sp<AMessage> dummy;
124 bool success;
125
Chong Zhangd354d8d2014-08-20 13:09:58 -0700126 success = SniffWVM(mDataSource, &mimeType, &confidence, &dummy);
Lajos Molnarcc227032014-07-17 15:33:06 -0700127 if (!success
128 || strcasecmp(
129 mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) {
130 ALOGE("unsupported widevine mime: %s", mimeType.string());
Chong Zhang3de157d2014-08-05 20:54:44 -0700131 return UNKNOWN_ERROR;
Lajos Molnarcc227032014-07-17 15:33:06 -0700132 }
133
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700134 mWVMExtractor = new WVMExtractor(mDataSource);
135 mWVMExtractor->setAdaptiveStreamingMode(true);
Lajos Molnarcc227032014-07-17 15:33:06 -0700136 if (mUIDValid) {
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700137 mWVMExtractor->setUID(mUID);
Lajos Molnarcc227032014-07-17 15:33:06 -0700138 }
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700139 extractor = mWVMExtractor;
Lajos Molnarcc227032014-07-17 15:33:06 -0700140 } else {
Chong Zhangd354d8d2014-08-20 13:09:58 -0700141 extractor = MediaExtractor::Create(mDataSource,
142 mSniffedMIME.empty() ? NULL: mSniffedMIME.c_str());
Lajos Molnarcc227032014-07-17 15:33:06 -0700143 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700144
Chong Zhang3de157d2014-08-05 20:54:44 -0700145 if (extractor == NULL) {
146 return UNKNOWN_ERROR;
147 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700148
Ronghua Wu80276872014-08-28 15:50:29 -0700149 if (extractor->getDrmFlag()) {
150 checkDrmStatus(mDataSource);
151 }
152
Marco Nelissenf0b72b52014-09-16 15:43:44 -0700153 mFileMeta = extractor->getMetaData();
154 if (mFileMeta != NULL) {
Marco Nelissenc1f4b2b2014-06-17 14:48:32 -0700155 int64_t duration;
Marco Nelissenf0b72b52014-09-16 15:43:44 -0700156 if (mFileMeta->findInt64(kKeyDuration, &duration)) {
Marco Nelissenc1f4b2b2014-06-17 14:48:32 -0700157 mDurationUs = duration;
158 }
159 }
160
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700161 int32_t totalBitrate = 0;
162
Marco Nelissen705d3292014-09-19 15:14:37 -0700163 size_t numtracks = extractor->countTracks();
164 if (numtracks == 0) {
165 return UNKNOWN_ERROR;
166 }
167
168 for (size_t i = 0; i < numtracks; ++i) {
Chong Zhangafc0a872014-08-26 09:56:52 -0700169 sp<MediaSource> track = extractor->getTrack(i);
170
Andreas Huberafed0e12011-09-20 15:39:58 -0700171 sp<MetaData> meta = extractor->getTrackMetaData(i);
172
173 const char *mime;
174 CHECK(meta->findCString(kKeyMIMEType, &mime));
175
Chong Zhangafc0a872014-08-26 09:56:52 -0700176 // Do the string compare immediately with "mime",
177 // we can't assume "mime" would stay valid after another
178 // extractor operation, some extractors might modify meta
179 // during getTrack() and make it invalid.
Andreas Huberafed0e12011-09-20 15:39:58 -0700180 if (!strncasecmp(mime, "audio/", 6)) {
181 if (mAudioTrack.mSource == NULL) {
Robert Shihdd235722014-06-12 14:49:23 -0700182 mAudioTrack.mIndex = i;
183 mAudioTrack.mSource = track;
Robert Shihaf52c1a2014-09-11 15:38:54 -0700184 mAudioTrack.mPackets =
185 new AnotherPacketSource(mAudioTrack.mSource->getFormat());
Andreas Huberafed0e12011-09-20 15:39:58 -0700186
187 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
188 mAudioIsVorbis = true;
189 } else {
190 mAudioIsVorbis = false;
191 }
192 }
193 } else if (!strncasecmp(mime, "video/", 6)) {
194 if (mVideoTrack.mSource == NULL) {
Robert Shihdd235722014-06-12 14:49:23 -0700195 mVideoTrack.mIndex = i;
196 mVideoTrack.mSource = track;
Robert Shihaf52c1a2014-09-11 15:38:54 -0700197 mVideoTrack.mPackets =
198 new AnotherPacketSource(mVideoTrack.mSource->getFormat());
Chong Zhang7e892182014-08-05 11:58:21 -0700199
200 // check if the source requires secure buffers
201 int32_t secure;
Chong Zhanga19f33e2014-08-07 15:35:07 -0700202 if (meta->findInt32(kKeyRequiresSecureBuffers, &secure)
203 && secure) {
Chong Zhang7e892182014-08-05 11:58:21 -0700204 mIsWidevine = true;
Chong Zhang3de157d2014-08-05 20:54:44 -0700205 if (mUIDValid) {
206 extractor->setUID(mUID);
207 }
Chong Zhang7e892182014-08-05 11:58:21 -0700208 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700209 }
210 }
211
212 if (track != NULL) {
Robert Shihdd235722014-06-12 14:49:23 -0700213 mSources.push(track);
Andreas Huberafed0e12011-09-20 15:39:58 -0700214 int64_t durationUs;
215 if (meta->findInt64(kKeyDuration, &durationUs)) {
216 if (durationUs > mDurationUs) {
217 mDurationUs = durationUs;
218 }
219 }
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700220
221 int32_t bitrate;
222 if (totalBitrate >= 0 && meta->findInt32(kKeyBitRate, &bitrate)) {
223 totalBitrate += bitrate;
224 } else {
225 totalBitrate = -1;
226 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700227 }
228 }
Chong Zhang3de157d2014-08-05 20:54:44 -0700229
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700230 mBitrate = totalBitrate;
231
Chong Zhang3de157d2014-08-05 20:54:44 -0700232 return OK;
Andreas Huberafed0e12011-09-20 15:39:58 -0700233}
234
Ronghua Wu80276872014-08-28 15:50:29 -0700235void NuPlayer::GenericSource::checkDrmStatus(const sp<DataSource>& dataSource) {
236 dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
237 if (mDecryptHandle != NULL) {
238 CHECK(mDrmManagerClient);
239 if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
240 sp<AMessage> msg = dupNotify();
241 msg->setInt32("what", kWhatDrmNoLicense);
242 msg->post();
243 }
244 }
245}
246
247int64_t NuPlayer::GenericSource::getLastReadPosition() {
248 if (mAudioTrack.mSource != NULL) {
249 return mAudioTimeUs;
250 } else if (mVideoTrack.mSource != NULL) {
251 return mVideoTimeUs;
252 } else {
253 return 0;
254 }
255}
256
Chong Zhanga19f33e2014-08-07 15:35:07 -0700257status_t NuPlayer::GenericSource::setBuffers(
258 bool audio, Vector<MediaBuffer *> &buffers) {
Lajos Molnarcc227032014-07-17 15:33:06 -0700259 if (mIsWidevine && !audio) {
260 return mVideoTrack.mSource->setBuffers(buffers);
261 }
262 return INVALID_OPERATION;
263}
264
Andreas Huberafed0e12011-09-20 15:39:58 -0700265NuPlayer::GenericSource::~GenericSource() {
Chong Zhang1228d6b2014-08-12 21:25:48 -0700266 if (mLooper != NULL) {
267 mLooper->unregisterHandler(id());
268 mLooper->stop();
269 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700270}
271
Andreas Huber9575c962013-02-05 13:59:56 -0800272void NuPlayer::GenericSource::prepareAsync() {
Chong Zhang1228d6b2014-08-12 21:25:48 -0700273 if (mLooper == NULL) {
274 mLooper = new ALooper;
275 mLooper->setName("generic");
276 mLooper->start();
277
278 mLooper->registerHandler(this);
279 }
280
281 sp<AMessage> msg = new AMessage(kWhatPrepareAsync, id());
282 msg->post();
283}
284
285void NuPlayer::GenericSource::onPrepareAsync() {
Chong Zhanga19f33e2014-08-07 15:35:07 -0700286 // delayed data source creation
Chong Zhangd354d8d2014-08-20 13:09:58 -0700287 if (mDataSource == NULL) {
288 if (!mUri.empty()) {
Robert Shih360d6d02014-09-29 14:42:35 -0700289 const char* uri = mUri.c_str();
290 mIsWidevine = !strncasecmp(uri, "widevine://", 11);
291
292 if (!strncasecmp("http://", uri, 7)
293 || !strncasecmp("https://", uri, 8)
294 || mIsWidevine) {
295 mHttpSource = DataSource::CreateMediaHTTP(mHTTPService);
296 if (mHttpSource == NULL) {
297 ALOGE("Failed to create http source!");
298 notifyPreparedAndCleanup(UNKNOWN_ERROR);
299 return;
300 }
301 }
Chong Zhanga19f33e2014-08-07 15:35:07 -0700302
Chong Zhangd354d8d2014-08-20 13:09:58 -0700303 mDataSource = DataSource::CreateFromURI(
Robert Shih360d6d02014-09-29 14:42:35 -0700304 mHTTPService, uri, &mUriHeaders, &mContentType,
305 static_cast<HTTPBase *>(mHttpSource.get()));
Chong Zhangd354d8d2014-08-20 13:09:58 -0700306 } else {
307 // set to false first, if the extractor
308 // comes back as secure, set it to true then.
309 mIsWidevine = false;
Chong Zhanga19f33e2014-08-07 15:35:07 -0700310
Chong Zhangd354d8d2014-08-20 13:09:58 -0700311 mDataSource = new FileSource(mFd, mOffset, mLength);
312 }
Chong Zhanga19f33e2014-08-07 15:35:07 -0700313
Chong Zhangd354d8d2014-08-20 13:09:58 -0700314 if (mDataSource == NULL) {
315 ALOGE("Failed to create data source!");
316 notifyPreparedAndCleanup(UNKNOWN_ERROR);
317 return;
318 }
319
320 if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
321 mCachedSource = static_cast<NuCachedSource2 *>(mDataSource.get());
322 }
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700323
324 if (mIsWidevine || mCachedSource != NULL) {
325 schedulePollBuffering();
326 }
Chong Zhanga19f33e2014-08-07 15:35:07 -0700327 }
328
Chong Zhangd354d8d2014-08-20 13:09:58 -0700329 // check initial caching status
330 status_t err = prefillCacheIfNecessary();
331 if (err != OK) {
332 if (err == -EAGAIN) {
333 (new AMessage(kWhatPrepareAsync, id()))->post(200000);
334 } else {
335 ALOGE("Failed to prefill data cache!");
336 notifyPreparedAndCleanup(UNKNOWN_ERROR);
337 }
Chong Zhanga19f33e2014-08-07 15:35:07 -0700338 return;
339 }
340
Chong Zhangd354d8d2014-08-20 13:09:58 -0700341 // init extrator from data source
342 err = initFromDataSource();
Chong Zhanga19f33e2014-08-07 15:35:07 -0700343
344 if (err != OK) {
345 ALOGE("Failed to init from data source!");
Chong Zhangd354d8d2014-08-20 13:09:58 -0700346 notifyPreparedAndCleanup(err);
Chong Zhanga19f33e2014-08-07 15:35:07 -0700347 return;
348 }
349
Andreas Huber9575c962013-02-05 13:59:56 -0800350 if (mVideoTrack.mSource != NULL) {
Robert Shih17f6dd62014-08-20 17:00:21 -0700351 sp<MetaData> meta = doGetFormatMeta(false /* audio */);
352 sp<AMessage> msg = new AMessage;
353 err = convertMetaDataToMessage(meta, &msg);
354 if(err != OK) {
355 notifyPreparedAndCleanup(err);
356 return;
357 }
358 notifyVideoSizeChanged(msg);
Andreas Huber9575c962013-02-05 13:59:56 -0800359 }
360
361 notifyFlagsChanged(
Lajos Molnarcc227032014-07-17 15:33:06 -0700362 (mIsWidevine ? FLAG_SECURE : 0)
363 | FLAG_CAN_PAUSE
Andreas Huber9575c962013-02-05 13:59:56 -0800364 | FLAG_CAN_SEEK_BACKWARD
365 | FLAG_CAN_SEEK_FORWARD
366 | FLAG_CAN_SEEK);
367
368 notifyPrepared();
369}
370
Chong Zhangd354d8d2014-08-20 13:09:58 -0700371void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) {
372 if (err != OK) {
373 mMetaDataSize = -1ll;
374 mContentType = "";
375 mSniffedMIME = "";
376 mDataSource.clear();
377 mCachedSource.clear();
Robert Shih360d6d02014-09-29 14:42:35 -0700378 mHttpSource.clear();
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700379
380 cancelPollBuffering();
Chong Zhangd354d8d2014-08-20 13:09:58 -0700381 }
382 notifyPrepared(err);
383}
384
385status_t NuPlayer::GenericSource::prefillCacheIfNecessary() {
386 CHECK(mDataSource != NULL);
387
388 if (mCachedSource == NULL) {
389 // no prefill if the data source is not cached
390 return OK;
391 }
392
393 // We're not doing this for streams that appear to be audio-only
394 // streams to ensure that even low bandwidth streams start
395 // playing back fairly instantly.
396 if (!strncasecmp(mContentType.string(), "audio/", 6)) {
397 return OK;
398 }
399
400 // We're going to prefill the cache before trying to instantiate
401 // the extractor below, as the latter is an operation that otherwise
402 // could block on the datasource for a significant amount of time.
403 // During that time we'd be unable to abort the preparation phase
404 // without this prefill.
405
406 // Initially make sure we have at least 192 KB for the sniff
407 // to complete without blocking.
408 static const size_t kMinBytesForSniffing = 192 * 1024;
409 static const size_t kDefaultMetaSize = 200000;
410
411 status_t finalStatus;
412
413 size_t cachedDataRemaining =
414 mCachedSource->approxDataRemaining(&finalStatus);
415
416 if (finalStatus != OK || (mMetaDataSize >= 0
417 && (off64_t)cachedDataRemaining >= mMetaDataSize)) {
418 ALOGV("stop caching, status %d, "
419 "metaDataSize %lld, cachedDataRemaining %zu",
420 finalStatus, mMetaDataSize, cachedDataRemaining);
421 return OK;
422 }
423
424 ALOGV("now cached %zu bytes of data", cachedDataRemaining);
425
426 if (mMetaDataSize < 0
427 && cachedDataRemaining >= kMinBytesForSniffing) {
428 String8 tmp;
429 float confidence;
430 sp<AMessage> meta;
431 if (!mCachedSource->sniff(&tmp, &confidence, &meta)) {
432 return UNKNOWN_ERROR;
433 }
434
435 // We successfully identified the file's extractor to
436 // be, remember this mime type so we don't have to
437 // sniff it again when we call MediaExtractor::Create()
438 mSniffedMIME = tmp.string();
439
440 if (meta == NULL
441 || !meta->findInt64("meta-data-size",
442 reinterpret_cast<int64_t*>(&mMetaDataSize))) {
443 mMetaDataSize = kDefaultMetaSize;
444 }
445
446 if (mMetaDataSize < 0ll) {
447 ALOGE("invalid metaDataSize = %lld bytes", mMetaDataSize);
448 return UNKNOWN_ERROR;
449 }
450 }
451
452 return -EAGAIN;
453}
454
Andreas Huberafed0e12011-09-20 15:39:58 -0700455void NuPlayer::GenericSource::start() {
456 ALOGI("start");
457
458 if (mAudioTrack.mSource != NULL) {
Robert Shihbace25b2014-07-25 14:14:34 -0700459 CHECK_EQ(mAudioTrack.mSource->start(), (status_t)OK);
Andreas Huberafed0e12011-09-20 15:39:58 -0700460
Robert Shih17f6dd62014-08-20 17:00:21 -0700461 postReadBuffer(MEDIA_TRACK_TYPE_AUDIO);
Andreas Huberafed0e12011-09-20 15:39:58 -0700462 }
463
464 if (mVideoTrack.mSource != NULL) {
Robert Shihbace25b2014-07-25 14:14:34 -0700465 CHECK_EQ(mVideoTrack.mSource->start(), (status_t)OK);
Andreas Huberafed0e12011-09-20 15:39:58 -0700466
Robert Shih17f6dd62014-08-20 17:00:21 -0700467 postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
Andreas Huberafed0e12011-09-20 15:39:58 -0700468 }
Ronghua Wu80276872014-08-28 15:50:29 -0700469
470 setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000);
471 mStarted = true;
472}
473
474void NuPlayer::GenericSource::stop() {
475 // nothing to do, just account for DRM playback status
476 setDrmPlaybackStatusIfNeeded(Playback::STOP, 0);
477 mStarted = false;
478}
479
480void NuPlayer::GenericSource::pause() {
481 // nothing to do, just account for DRM playback status
482 setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0);
483 mStarted = false;
484}
485
486void NuPlayer::GenericSource::resume() {
487 // nothing to do, just account for DRM playback status
488 setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000);
489 mStarted = true;
490}
491
Chong Zhang48296b72014-09-14 14:28:45 -0700492void NuPlayer::GenericSource::disconnect() {
493 if (mDataSource != NULL) {
494 // disconnect data source
495 if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
496 static_cast<NuCachedSource2 *>(mDataSource.get())->disconnect();
497 }
Robert Shih360d6d02014-09-29 14:42:35 -0700498 } else if (mHttpSource != NULL) {
499 static_cast<HTTPBase *>(mHttpSource.get())->disconnect();
Chong Zhang48296b72014-09-14 14:28:45 -0700500 }
501}
502
Ronghua Wu80276872014-08-28 15:50:29 -0700503void NuPlayer::GenericSource::setDrmPlaybackStatusIfNeeded(int playbackStatus, int64_t position) {
504 if (mDecryptHandle != NULL) {
505 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, playbackStatus, position);
506 }
Robert Shih17f6dd62014-08-20 17:00:21 -0700507 mSubtitleTrack.mPackets = new AnotherPacketSource(NULL);
508 mTimedTextTrack.mPackets = new AnotherPacketSource(NULL);
Andreas Huberafed0e12011-09-20 15:39:58 -0700509}
510
511status_t NuPlayer::GenericSource::feedMoreTSData() {
512 return OK;
513}
514
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700515void NuPlayer::GenericSource::schedulePollBuffering() {
516 sp<AMessage> msg = new AMessage(kWhatPollBuffering, id());
517 msg->setInt32("generation", mPollBufferingGeneration);
518 msg->post(1000000ll);
519}
520
521void NuPlayer::GenericSource::cancelPollBuffering() {
522 ++mPollBufferingGeneration;
523}
524
525void NuPlayer::GenericSource::notifyBufferingUpdate(int percentage) {
526 sp<AMessage> msg = dupNotify();
527 msg->setInt32("what", kWhatBufferingUpdate);
528 msg->setInt32("percentage", percentage);
529 msg->post();
530}
531
532void NuPlayer::GenericSource::onPollBuffering() {
533 status_t finalStatus = UNKNOWN_ERROR;
534 int64_t cachedDurationUs = 0ll;
535
536 if (mCachedSource != NULL) {
537 size_t cachedDataRemaining =
538 mCachedSource->approxDataRemaining(&finalStatus);
539
540 if (finalStatus == OK) {
541 off64_t size;
542 int64_t bitrate = 0ll;
543 if (mDurationUs > 0 && mCachedSource->getSize(&size) == OK) {
544 bitrate = size * 8000000ll / mDurationUs;
545 } else if (mBitrate > 0) {
546 bitrate = mBitrate;
547 }
548 if (bitrate > 0) {
549 cachedDurationUs = cachedDataRemaining * 8000000ll / bitrate;
550 }
551 }
552 } else if (mWVMExtractor != NULL) {
553 cachedDurationUs
554 = mWVMExtractor->getCachedDurationUs(&finalStatus);
555 }
556
557 if (finalStatus == ERROR_END_OF_STREAM) {
558 notifyBufferingUpdate(100);
559 cancelPollBuffering();
560 return;
561 } else if (cachedDurationUs > 0ll && mDurationUs > 0ll) {
562 int percentage = 100.0 * cachedDurationUs / mDurationUs;
563 if (percentage > 100) {
564 percentage = 100;
565 }
566
567 notifyBufferingUpdate(percentage);
568 }
569
570 schedulePollBuffering();
571}
572
573
Robert Shih3423bbd2014-07-16 15:47:09 -0700574void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) {
575 switch (msg->what()) {
Chong Zhang1228d6b2014-08-12 21:25:48 -0700576 case kWhatPrepareAsync:
577 {
578 onPrepareAsync();
579 break;
580 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700581 case kWhatFetchSubtitleData:
582 {
Lajos Molnare26940f2014-07-31 10:31:26 -0700583 fetchTextData(kWhatSendSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
584 mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
585 break;
586 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700587
Lajos Molnare26940f2014-07-31 10:31:26 -0700588 case kWhatFetchTimedTextData:
589 {
590 fetchTextData(kWhatSendTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
591 mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
Robert Shih3423bbd2014-07-16 15:47:09 -0700592 break;
593 }
594
595 case kWhatSendSubtitleData:
596 {
Lajos Molnare26940f2014-07-31 10:31:26 -0700597 sendTextData(kWhatSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
598 mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
599 break;
600 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700601
Lajos Molnare26940f2014-07-31 10:31:26 -0700602 case kWhatSendTimedTextData:
603 {
604 sendTextData(kWhatTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
605 mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
Robert Shih3423bbd2014-07-16 15:47:09 -0700606 break;
607 }
608
609 case kWhatChangeAVSource:
610 {
611 int32_t trackIndex;
612 CHECK(msg->findInt32("trackIndex", &trackIndex));
613 const sp<MediaSource> source = mSources.itemAt(trackIndex);
614
615 Track* track;
616 const char *mime;
617 media_track_type trackType, counterpartType;
618 sp<MetaData> meta = source->getFormat();
619 meta->findCString(kKeyMIMEType, &mime);
620 if (!strncasecmp(mime, "audio/", 6)) {
621 track = &mAudioTrack;
622 trackType = MEDIA_TRACK_TYPE_AUDIO;
623 counterpartType = MEDIA_TRACK_TYPE_VIDEO;;
624 } else {
625 CHECK(!strncasecmp(mime, "video/", 6));
626 track = &mVideoTrack;
627 trackType = MEDIA_TRACK_TYPE_VIDEO;
628 counterpartType = MEDIA_TRACK_TYPE_AUDIO;;
629 }
630
631
632 if (track->mSource != NULL) {
633 track->mSource->stop();
634 }
635 track->mSource = source;
636 track->mSource->start();
637 track->mIndex = trackIndex;
638
639 status_t avail;
640 if (!track->mPackets->hasBufferAvailable(&avail)) {
641 // sync from other source
642 TRESPASS();
643 break;
644 }
645
646 int64_t timeUs, actualTimeUs;
647 const bool formatChange = true;
Robert Shih309aa8b2014-07-29 18:34:36 -0700648 sp<AMessage> latestMeta = track->mPackets->getLatestEnqueuedMeta();
Robert Shih3423bbd2014-07-16 15:47:09 -0700649 CHECK(latestMeta != NULL && latestMeta->findInt64("timeUs", &timeUs));
650 readBuffer(trackType, timeUs, &actualTimeUs, formatChange);
651 readBuffer(counterpartType, -1, NULL, formatChange);
652 ALOGV("timeUs %lld actualTimeUs %lld", timeUs, actualTimeUs);
653
654 break;
655 }
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700656 case kWhatPollBuffering:
657 {
658 int32_t generation;
659 CHECK(msg->findInt32("generation", &generation));
660 if (generation == mPollBufferingGeneration) {
661 onPollBuffering();
662 }
663 break;
664 }
Robert Shih17f6dd62014-08-20 17:00:21 -0700665
666 case kWhatGetFormat:
667 {
668 onGetFormatMeta(msg);
669 break;
670 }
671
672 case kWhatGetSelectedTrack:
673 {
674 onGetSelectedTrack(msg);
675 break;
676 }
677
678 case kWhatSelectTrack:
679 {
680 onSelectTrack(msg);
681 break;
682 }
683
684 case kWhatSeek:
685 {
686 onSeek(msg);
687 break;
688 }
689
690 case kWhatReadBuffer:
691 {
692 onReadBuffer(msg);
693 break;
694 }
695
Robert Shih3423bbd2014-07-16 15:47:09 -0700696 default:
697 Source::onMessageReceived(msg);
698 break;
699 }
700}
701
Lajos Molnare26940f2014-07-31 10:31:26 -0700702void NuPlayer::GenericSource::fetchTextData(
703 uint32_t sendWhat,
704 media_track_type type,
705 int32_t curGen,
706 sp<AnotherPacketSource> packets,
707 sp<AMessage> msg) {
708 int32_t msgGeneration;
709 CHECK(msg->findInt32("generation", &msgGeneration));
710 if (msgGeneration != curGen) {
711 // stale
712 return;
713 }
714
715 int32_t avail;
716 if (packets->hasBufferAvailable(&avail)) {
717 return;
718 }
719
720 int64_t timeUs;
721 CHECK(msg->findInt64("timeUs", &timeUs));
722
723 int64_t subTimeUs;
724 readBuffer(type, timeUs, &subTimeUs);
725
726 int64_t delayUs = subTimeUs - timeUs;
727 if (msg->what() == kWhatFetchSubtitleData) {
728 const int64_t oneSecUs = 1000000ll;
729 delayUs -= oneSecUs;
730 }
731 sp<AMessage> msg2 = new AMessage(sendWhat, id());
732 msg2->setInt32("generation", msgGeneration);
733 msg2->post(delayUs < 0 ? 0 : delayUs);
734}
735
736void NuPlayer::GenericSource::sendTextData(
737 uint32_t what,
738 media_track_type type,
739 int32_t curGen,
740 sp<AnotherPacketSource> packets,
741 sp<AMessage> msg) {
742 int32_t msgGeneration;
743 CHECK(msg->findInt32("generation", &msgGeneration));
744 if (msgGeneration != curGen) {
745 // stale
746 return;
747 }
748
749 int64_t subTimeUs;
750 if (packets->nextBufferTime(&subTimeUs) != OK) {
751 return;
752 }
753
754 int64_t nextSubTimeUs;
755 readBuffer(type, -1, &nextSubTimeUs);
756
757 sp<ABuffer> buffer;
758 status_t dequeueStatus = packets->dequeueAccessUnit(&buffer);
759 if (dequeueStatus == OK) {
760 sp<AMessage> notify = dupNotify();
761 notify->setInt32("what", what);
762 notify->setBuffer("buffer", buffer);
763 notify->post();
764
765 const int64_t delayUs = nextSubTimeUs - subTimeUs;
766 msg->post(delayUs < 0 ? 0 : delayUs);
767 }
768}
769
Andreas Huber84066782011-08-16 09:34:26 -0700770sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
Robert Shih17f6dd62014-08-20 17:00:21 -0700771 sp<AMessage> msg = new AMessage(kWhatGetFormat, id());
772 msg->setInt32("audio", audio);
773
774 sp<AMessage> response;
775 void *format;
776 status_t err = msg->postAndAwaitResponse(&response);
777 if (err == OK && response != NULL) {
778 CHECK(response->findPointer("format", &format));
779 return (MetaData *)format;
780 } else {
781 return NULL;
782 }
783}
784
785void NuPlayer::GenericSource::onGetFormatMeta(sp<AMessage> msg) const {
786 int32_t audio;
787 CHECK(msg->findInt32("audio", &audio));
788
789 sp<AMessage> response = new AMessage;
790 sp<MetaData> format = doGetFormatMeta(audio);
791 response->setPointer("format", format.get());
792
793 uint32_t replyID;
794 CHECK(msg->senderAwaitsResponse(&replyID));
795 response->postReply(replyID);
796}
797
798sp<MetaData> NuPlayer::GenericSource::doGetFormatMeta(bool audio) const {
Andreas Huberafed0e12011-09-20 15:39:58 -0700799 sp<MediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
800
801 if (source == NULL) {
802 return NULL;
803 }
804
805 return source->getFormat();
806}
807
808status_t NuPlayer::GenericSource::dequeueAccessUnit(
809 bool audio, sp<ABuffer> *accessUnit) {
810 Track *track = audio ? &mAudioTrack : &mVideoTrack;
811
812 if (track->mSource == NULL) {
813 return -EWOULDBLOCK;
814 }
815
Lajos Molnarcc227032014-07-17 15:33:06 -0700816 if (mIsWidevine && !audio) {
817 // try to read a buffer as we may not have been able to the last time
Robert Shih17f6dd62014-08-20 17:00:21 -0700818 postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
Lajos Molnarcc227032014-07-17 15:33:06 -0700819 }
820
Andreas Huberafed0e12011-09-20 15:39:58 -0700821 status_t finalResult;
822 if (!track->mPackets->hasBufferAvailable(&finalResult)) {
Lajos Molnarcc227032014-07-17 15:33:06 -0700823 return (finalResult == OK ? -EWOULDBLOCK : finalResult);
Andreas Huberafed0e12011-09-20 15:39:58 -0700824 }
825
826 status_t result = track->mPackets->dequeueAccessUnit(accessUnit);
827
Robert Shih3423bbd2014-07-16 15:47:09 -0700828 if (!track->mPackets->hasBufferAvailable(&finalResult)) {
Robert Shih17f6dd62014-08-20 17:00:21 -0700829 postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
Lajos Molnare26940f2014-07-31 10:31:26 -0700830 }
831
Robert Shih3423bbd2014-07-16 15:47:09 -0700832 if (result != OK) {
Lajos Molnare26940f2014-07-31 10:31:26 -0700833 if (mSubtitleTrack.mSource != NULL) {
834 mSubtitleTrack.mPackets->clear();
835 mFetchSubtitleDataGeneration++;
836 }
837 if (mTimedTextTrack.mSource != NULL) {
838 mTimedTextTrack.mPackets->clear();
839 mFetchTimedTextDataGeneration++;
840 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700841 return result;
842 }
843
844 int64_t timeUs;
845 status_t eosResult; // ignored
846 CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs));
Lajos Molnare26940f2014-07-31 10:31:26 -0700847
848 if (mSubtitleTrack.mSource != NULL
849 && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
Robert Shih3423bbd2014-07-16 15:47:09 -0700850 sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, id());
851 msg->setInt64("timeUs", timeUs);
852 msg->setInt32("generation", mFetchSubtitleDataGeneration);
853 msg->post();
854 }
Robert Shiheb1735e2014-07-23 15:53:14 -0700855
Lajos Molnare26940f2014-07-31 10:31:26 -0700856 if (mTimedTextTrack.mSource != NULL
857 && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
858 sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, id());
859 msg->setInt64("timeUs", timeUs);
860 msg->setInt32("generation", mFetchTimedTextDataGeneration);
861 msg->post();
862 }
863
Andreas Huberafed0e12011-09-20 15:39:58 -0700864 return result;
865}
866
867status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) {
868 *durationUs = mDurationUs;
869 return OK;
870}
871
Robert Shihdd235722014-06-12 14:49:23 -0700872size_t NuPlayer::GenericSource::getTrackCount() const {
873 return mSources.size();
874}
875
876sp<AMessage> NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const {
877 size_t trackCount = mSources.size();
878 if (trackIndex >= trackCount) {
879 return NULL;
880 }
881
882 sp<AMessage> format = new AMessage();
883 sp<MetaData> meta = mSources.itemAt(trackIndex)->getFormat();
884
885 const char *mime;
886 CHECK(meta->findCString(kKeyMIMEType, &mime));
887
888 int32_t trackType;
889 if (!strncasecmp(mime, "video/", 6)) {
890 trackType = MEDIA_TRACK_TYPE_VIDEO;
891 } else if (!strncasecmp(mime, "audio/", 6)) {
892 trackType = MEDIA_TRACK_TYPE_AUDIO;
893 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
894 trackType = MEDIA_TRACK_TYPE_TIMEDTEXT;
895 } else {
896 trackType = MEDIA_TRACK_TYPE_UNKNOWN;
897 }
898 format->setInt32("type", trackType);
899
900 const char *lang;
901 if (!meta->findCString(kKeyMediaLanguage, &lang)) {
902 lang = "und";
903 }
904 format->setString("language", lang);
905
906 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
907 format->setString("mime", mime);
908
909 int32_t isAutoselect = 1, isDefault = 0, isForced = 0;
910 meta->findInt32(kKeyTrackIsAutoselect, &isAutoselect);
911 meta->findInt32(kKeyTrackIsDefault, &isDefault);
912 meta->findInt32(kKeyTrackIsForced, &isForced);
913
914 format->setInt32("auto", !!isAutoselect);
915 format->setInt32("default", !!isDefault);
916 format->setInt32("forced", !!isForced);
917 }
918
919 return format;
920}
921
Lajos Molnare26940f2014-07-31 10:31:26 -0700922ssize_t NuPlayer::GenericSource::getSelectedTrack(media_track_type type) const {
Robert Shih17f6dd62014-08-20 17:00:21 -0700923 sp<AMessage> msg = new AMessage(kWhatGetSelectedTrack, id());
924 msg->setInt32("type", type);
925
926 sp<AMessage> response;
927 int32_t index;
928 status_t err = msg->postAndAwaitResponse(&response);
929 if (err == OK && response != NULL) {
930 CHECK(response->findInt32("index", &index));
931 return index;
932 } else {
933 return -1;
934 }
935}
936
937void NuPlayer::GenericSource::onGetSelectedTrack(sp<AMessage> msg) const {
938 int32_t tmpType;
939 CHECK(msg->findInt32("type", &tmpType));
940 media_track_type type = (media_track_type)tmpType;
941
942 sp<AMessage> response = new AMessage;
943 ssize_t index = doGetSelectedTrack(type);
944 response->setInt32("index", index);
945
946 uint32_t replyID;
947 CHECK(msg->senderAwaitsResponse(&replyID));
948 response->postReply(replyID);
949}
950
951ssize_t NuPlayer::GenericSource::doGetSelectedTrack(media_track_type type) const {
Lajos Molnare26940f2014-07-31 10:31:26 -0700952 const Track *track = NULL;
953 switch (type) {
954 case MEDIA_TRACK_TYPE_VIDEO:
955 track = &mVideoTrack;
956 break;
957 case MEDIA_TRACK_TYPE_AUDIO:
958 track = &mAudioTrack;
959 break;
960 case MEDIA_TRACK_TYPE_TIMEDTEXT:
961 track = &mTimedTextTrack;
962 break;
963 case MEDIA_TRACK_TYPE_SUBTITLE:
964 track = &mSubtitleTrack;
965 break;
966 default:
967 break;
968 }
969
970 if (track != NULL && track->mSource != NULL) {
971 return track->mIndex;
972 }
973
974 return -1;
975}
976
Robert Shih3423bbd2014-07-16 15:47:09 -0700977status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select) {
Lajos Molnare26940f2014-07-31 10:31:26 -0700978 ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex);
Robert Shih17f6dd62014-08-20 17:00:21 -0700979 sp<AMessage> msg = new AMessage(kWhatSelectTrack, id());
980 msg->setInt32("trackIndex", trackIndex);
Robert Shihda23ab92014-09-16 11:34:08 -0700981 msg->setInt32("select", select);
Robert Shih17f6dd62014-08-20 17:00:21 -0700982
983 sp<AMessage> response;
984 status_t err = msg->postAndAwaitResponse(&response);
985 if (err == OK && response != NULL) {
986 CHECK(response->findInt32("err", &err));
987 }
988
989 return err;
990}
991
992void NuPlayer::GenericSource::onSelectTrack(sp<AMessage> msg) {
993 int32_t trackIndex, select;
994 CHECK(msg->findInt32("trackIndex", &trackIndex));
995 CHECK(msg->findInt32("select", &select));
996
997 sp<AMessage> response = new AMessage;
998 status_t err = doSelectTrack(trackIndex, select);
999 response->setInt32("err", err);
1000
1001 uint32_t replyID;
1002 CHECK(msg->senderAwaitsResponse(&replyID));
1003 response->postReply(replyID);
1004}
1005
1006status_t NuPlayer::GenericSource::doSelectTrack(size_t trackIndex, bool select) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001007 if (trackIndex >= mSources.size()) {
1008 return BAD_INDEX;
1009 }
1010
1011 if (!select) {
Lajos Molnare26940f2014-07-31 10:31:26 -07001012 Track* track = NULL;
1013 if (mSubtitleTrack.mSource != NULL && trackIndex == mSubtitleTrack.mIndex) {
1014 track = &mSubtitleTrack;
1015 mFetchSubtitleDataGeneration++;
1016 } else if (mTimedTextTrack.mSource != NULL && trackIndex == mTimedTextTrack.mIndex) {
1017 track = &mTimedTextTrack;
1018 mFetchTimedTextDataGeneration++;
1019 }
1020 if (track == NULL) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001021 return INVALID_OPERATION;
1022 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001023 track->mSource->stop();
1024 track->mSource = NULL;
1025 track->mPackets->clear();
Robert Shih3423bbd2014-07-16 15:47:09 -07001026 return OK;
1027 }
1028
1029 const sp<MediaSource> source = mSources.itemAt(trackIndex);
1030 sp<MetaData> meta = source->getFormat();
1031 const char *mime;
1032 CHECK(meta->findCString(kKeyMIMEType, &mime));
1033 if (!strncasecmp(mime, "text/", 5)) {
Lajos Molnare26940f2014-07-31 10:31:26 -07001034 bool isSubtitle = strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP);
1035 Track *track = isSubtitle ? &mSubtitleTrack : &mTimedTextTrack;
1036 if (track->mSource != NULL && track->mIndex == trackIndex) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001037 return OK;
1038 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001039 track->mIndex = trackIndex;
1040 if (track->mSource != NULL) {
1041 track->mSource->stop();
Robert Shih3423bbd2014-07-16 15:47:09 -07001042 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001043 track->mSource = mSources.itemAt(trackIndex);
1044 track->mSource->start();
1045 if (track->mPackets == NULL) {
1046 track->mPackets = new AnotherPacketSource(track->mSource->getFormat());
Robert Shih3423bbd2014-07-16 15:47:09 -07001047 } else {
Lajos Molnare26940f2014-07-31 10:31:26 -07001048 track->mPackets->clear();
1049 track->mPackets->setFormat(track->mSource->getFormat());
Robert Shih3423bbd2014-07-16 15:47:09 -07001050
1051 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001052
1053 if (isSubtitle) {
1054 mFetchSubtitleDataGeneration++;
1055 } else {
1056 mFetchTimedTextDataGeneration++;
1057 }
1058
Robert Shih3423bbd2014-07-16 15:47:09 -07001059 return OK;
1060 } else if (!strncasecmp(mime, "audio/", 6) || !strncasecmp(mime, "video/", 6)) {
1061 bool audio = !strncasecmp(mime, "audio/", 6);
1062 Track *track = audio ? &mAudioTrack : &mVideoTrack;
1063 if (track->mSource != NULL && track->mIndex == trackIndex) {
1064 return OK;
1065 }
1066
1067 sp<AMessage> msg = new AMessage(kWhatChangeAVSource, id());
1068 msg->setInt32("trackIndex", trackIndex);
1069 msg->post();
1070 return OK;
1071 }
1072
1073 return INVALID_OPERATION;
1074}
1075
Andreas Huberafed0e12011-09-20 15:39:58 -07001076status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) {
Robert Shih17f6dd62014-08-20 17:00:21 -07001077 sp<AMessage> msg = new AMessage(kWhatSeek, id());
1078 msg->setInt64("seekTimeUs", seekTimeUs);
1079
1080 sp<AMessage> response;
1081 status_t err = msg->postAndAwaitResponse(&response);
1082 if (err == OK && response != NULL) {
1083 CHECK(response->findInt32("err", &err));
1084 }
1085
1086 return err;
1087}
1088
1089void NuPlayer::GenericSource::onSeek(sp<AMessage> msg) {
1090 int64_t seekTimeUs;
1091 CHECK(msg->findInt64("seekTimeUs", &seekTimeUs));
1092
1093 sp<AMessage> response = new AMessage;
1094 status_t err = doSeek(seekTimeUs);
1095 response->setInt32("err", err);
1096
1097 uint32_t replyID;
1098 CHECK(msg->senderAwaitsResponse(&replyID));
1099 response->postReply(replyID);
1100}
1101
1102status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs) {
Andreas Huberafed0e12011-09-20 15:39:58 -07001103 if (mVideoTrack.mSource != NULL) {
1104 int64_t actualTimeUs;
Robert Shih3423bbd2014-07-16 15:47:09 -07001105 readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, &actualTimeUs);
Andreas Huberafed0e12011-09-20 15:39:58 -07001106
1107 seekTimeUs = actualTimeUs;
1108 }
1109
1110 if (mAudioTrack.mSource != NULL) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001111 readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs);
Andreas Huberafed0e12011-09-20 15:39:58 -07001112 }
1113
Ronghua Wu80276872014-08-28 15:50:29 -07001114 setDrmPlaybackStatusIfNeeded(Playback::START, seekTimeUs / 1000);
1115 if (!mStarted) {
1116 setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0);
1117 }
Andreas Huberafed0e12011-09-20 15:39:58 -07001118 return OK;
1119}
1120
Robert Shih3423bbd2014-07-16 15:47:09 -07001121sp<ABuffer> NuPlayer::GenericSource::mediaBufferToABuffer(
1122 MediaBuffer* mb,
1123 media_track_type trackType,
1124 int64_t *actualTimeUs) {
1125 bool audio = trackType == MEDIA_TRACK_TYPE_AUDIO;
1126 size_t outLength = mb->range_length();
1127
1128 if (audio && mAudioIsVorbis) {
1129 outLength += sizeof(int32_t);
1130 }
1131
1132 sp<ABuffer> ab;
1133 if (mIsWidevine && !audio) {
1134 // data is already provided in the buffer
1135 ab = new ABuffer(NULL, mb->range_length());
Robert Shih3423bbd2014-07-16 15:47:09 -07001136 mb->add_ref();
Wei Jia96e92b52014-09-18 17:36:20 -07001137 ab->setMediaBufferBase(mb);
Robert Shih3423bbd2014-07-16 15:47:09 -07001138 } else {
1139 ab = new ABuffer(outLength);
1140 memcpy(ab->data(),
1141 (const uint8_t *)mb->data() + mb->range_offset(),
1142 mb->range_length());
1143 }
1144
1145 if (audio && mAudioIsVorbis) {
1146 int32_t numPageSamples;
1147 if (!mb->meta_data()->findInt32(kKeyValidSamples, &numPageSamples)) {
1148 numPageSamples = -1;
1149 }
1150
1151 uint8_t* abEnd = ab->data() + mb->range_length();
1152 memcpy(abEnd, &numPageSamples, sizeof(numPageSamples));
1153 }
1154
Lajos Molnare26940f2014-07-31 10:31:26 -07001155 sp<AMessage> meta = ab->meta();
1156
Robert Shih3423bbd2014-07-16 15:47:09 -07001157 int64_t timeUs;
1158 CHECK(mb->meta_data()->findInt64(kKeyTime, &timeUs));
Robert Shih3423bbd2014-07-16 15:47:09 -07001159 meta->setInt64("timeUs", timeUs);
1160
Lajos Molnare26940f2014-07-31 10:31:26 -07001161 if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) {
1162 const char *mime;
1163 CHECK(mTimedTextTrack.mSource != NULL
1164 && mTimedTextTrack.mSource->getFormat()->findCString(kKeyMIMEType, &mime));
1165 meta->setString("mime", mime);
1166 }
1167
Robert Shih3423bbd2014-07-16 15:47:09 -07001168 int64_t durationUs;
1169 if (mb->meta_data()->findInt64(kKeyDuration, &durationUs)) {
1170 meta->setInt64("durationUs", durationUs);
1171 }
1172
1173 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
1174 meta->setInt32("trackIndex", mSubtitleTrack.mIndex);
1175 }
1176
1177 if (actualTimeUs) {
1178 *actualTimeUs = timeUs;
1179 }
1180
1181 mb->release();
1182 mb = NULL;
1183
1184 return ab;
1185}
1186
Robert Shih17f6dd62014-08-20 17:00:21 -07001187void NuPlayer::GenericSource::postReadBuffer(media_track_type trackType) {
Lajos Molnar84f52782014-09-11 10:01:55 -07001188 Mutex::Autolock _l(mReadBufferLock);
1189
1190 if ((mPendingReadBufferTypes & (1 << trackType)) == 0) {
1191 mPendingReadBufferTypes |= (1 << trackType);
1192 sp<AMessage> msg = new AMessage(kWhatReadBuffer, id());
1193 msg->setInt32("trackType", trackType);
1194 msg->post();
1195 }
Robert Shih17f6dd62014-08-20 17:00:21 -07001196}
1197
1198void NuPlayer::GenericSource::onReadBuffer(sp<AMessage> msg) {
1199 int32_t tmpType;
1200 CHECK(msg->findInt32("trackType", &tmpType));
1201 media_track_type trackType = (media_track_type)tmpType;
Lajos Molnar84f52782014-09-11 10:01:55 -07001202 {
1203 // only protect the variable change, as readBuffer may
1204 // take considerable time. This may result in one extra
1205 // read being processed, but that is benign.
1206 Mutex::Autolock _l(mReadBufferLock);
1207 mPendingReadBufferTypes &= ~(1 << trackType);
1208 }
Robert Shih17f6dd62014-08-20 17:00:21 -07001209 readBuffer(trackType);
1210}
1211
Andreas Huberafed0e12011-09-20 15:39:58 -07001212void NuPlayer::GenericSource::readBuffer(
Robert Shih3423bbd2014-07-16 15:47:09 -07001213 media_track_type trackType, int64_t seekTimeUs, int64_t *actualTimeUs, bool formatChange) {
1214 Track *track;
Phil Burkc5cc2e22014-09-09 20:08:39 -07001215 size_t maxBuffers = 1;
Robert Shih3423bbd2014-07-16 15:47:09 -07001216 switch (trackType) {
1217 case MEDIA_TRACK_TYPE_VIDEO:
1218 track = &mVideoTrack;
Jeff Tinkera28785a2014-09-23 22:24:26 -07001219 if (mIsWidevine) {
1220 maxBuffers = 2;
1221 }
Robert Shih3423bbd2014-07-16 15:47:09 -07001222 break;
1223 case MEDIA_TRACK_TYPE_AUDIO:
1224 track = &mAudioTrack;
Jeff Tinkera28785a2014-09-23 22:24:26 -07001225 if (mIsWidevine) {
1226 maxBuffers = 8;
1227 } else {
1228 maxBuffers = 64;
1229 }
Robert Shih3423bbd2014-07-16 15:47:09 -07001230 break;
1231 case MEDIA_TRACK_TYPE_SUBTITLE:
1232 track = &mSubtitleTrack;
1233 break;
Lajos Molnare26940f2014-07-31 10:31:26 -07001234 case MEDIA_TRACK_TYPE_TIMEDTEXT:
1235 track = &mTimedTextTrack;
1236 break;
Robert Shih3423bbd2014-07-16 15:47:09 -07001237 default:
1238 TRESPASS();
1239 }
1240
1241 if (track->mSource == NULL) {
1242 return;
1243 }
Andreas Huberafed0e12011-09-20 15:39:58 -07001244
1245 if (actualTimeUs) {
1246 *actualTimeUs = seekTimeUs;
1247 }
1248
1249 MediaSource::ReadOptions options;
1250
1251 bool seeking = false;
1252
1253 if (seekTimeUs >= 0) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001254 options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
Andreas Huberafed0e12011-09-20 15:39:58 -07001255 seeking = true;
1256 }
1257
Robert Shih3423bbd2014-07-16 15:47:09 -07001258 if (mIsWidevine && trackType != MEDIA_TRACK_TYPE_AUDIO) {
Lajos Molnarcc227032014-07-17 15:33:06 -07001259 options.setNonBlocking();
1260 }
1261
Phil Burkc5cc2e22014-09-09 20:08:39 -07001262 for (size_t numBuffers = 0; numBuffers < maxBuffers; ) {
Andreas Huberafed0e12011-09-20 15:39:58 -07001263 MediaBuffer *mbuf;
1264 status_t err = track->mSource->read(&mbuf, &options);
1265
1266 options.clearSeekTo();
1267
1268 if (err == OK) {
Ronghua Wu80276872014-08-28 15:50:29 -07001269 int64_t timeUs;
1270 CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs));
1271 if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
1272 mAudioTimeUs = timeUs;
1273 } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
1274 mVideoTimeUs = timeUs;
1275 }
1276
Robert Shih3423bbd2014-07-16 15:47:09 -07001277 // formatChange && seeking: track whose source is changed during selection
1278 // formatChange && !seeking: track whose source is not changed during selection
1279 // !formatChange: normal seek
Lajos Molnare26940f2014-07-31 10:31:26 -07001280 if ((seeking || formatChange)
1281 && (trackType == MEDIA_TRACK_TYPE_AUDIO
1282 || trackType == MEDIA_TRACK_TYPE_VIDEO)) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001283 ATSParser::DiscontinuityType type = formatChange
1284 ? (seeking
1285 ? ATSParser::DISCONTINUITY_FORMATCHANGE
1286 : ATSParser::DISCONTINUITY_NONE)
1287 : ATSParser::DISCONTINUITY_SEEK;
1288 track->mPackets->queueDiscontinuity( type, NULL, true /* discard */);
Andreas Huberafed0e12011-09-20 15:39:58 -07001289 }
1290
Robert Shih3423bbd2014-07-16 15:47:09 -07001291 sp<ABuffer> buffer = mediaBufferToABuffer(mbuf, trackType, actualTimeUs);
Andreas Huberafed0e12011-09-20 15:39:58 -07001292 track->mPackets->queueAccessUnit(buffer);
Marco Nelissen317a49a2014-09-16 21:32:33 -07001293 formatChange = false;
1294 seeking = false;
Phil Burkc5cc2e22014-09-09 20:08:39 -07001295 ++numBuffers;
Lajos Molnarcc227032014-07-17 15:33:06 -07001296 } else if (err == WOULD_BLOCK) {
1297 break;
Andreas Huberafed0e12011-09-20 15:39:58 -07001298 } else if (err == INFO_FORMAT_CHANGED) {
1299#if 0
1300 track->mPackets->queueDiscontinuity(
Chong Zhang632740c2014-06-26 13:03:47 -07001301 ATSParser::DISCONTINUITY_FORMATCHANGE,
1302 NULL,
1303 false /* discard */);
Andreas Huberafed0e12011-09-20 15:39:58 -07001304#endif
1305 } else {
1306 track->mPackets->signalEOS(err);
1307 break;
1308 }
1309 }
1310}
1311
Andreas Huberafed0e12011-09-20 15:39:58 -07001312} // namespace android