blob: 75a8f788c27dd1abbec9f55efb4e80a68607f98a [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),
Chong Zhang42e81532014-12-01 13:44:26 -080057 mIsSecure(false),
Lajos Molnarcc227032014-07-17 15:33:06 -070058 mUIDValid(uidValid),
Chong Zhangd354d8d2014-08-20 13:09:58 -070059 mUID(uid),
Chong Zhanga6bf21f2014-11-19 20:26:34 -080060 mFd(-1),
Ronghua Wu80276872014-08-28 15:50:29 -070061 mDrmManagerClient(NULL),
Chong Zhang2a3cc9a2014-08-21 17:48:26 -070062 mMetaDataSize(-1ll),
63 mBitrate(-1ll),
Lajos Molnar84f52782014-09-11 10:01:55 -070064 mPollBufferingGeneration(0),
65 mPendingReadBufferTypes(0) {
Chong Zhanga19f33e2014-08-07 15:35:07 -070066 resetDataSource();
Andreas Huberafed0e12011-09-20 15:39:58 -070067 DataSource::RegisterDefaultSniffers();
Chong Zhang3de157d2014-08-05 20:54:44 -070068}
69
Chong Zhanga19f33e2014-08-07 15:35:07 -070070void NuPlayer::GenericSource::resetDataSource() {
71 mHTTPService.clear();
Robert Shih360d6d02014-09-29 14:42:35 -070072 mHttpSource.clear();
Chong Zhanga19f33e2014-08-07 15:35:07 -070073 mUri.clear();
74 mUriHeaders.clear();
Chong Zhanga6bf21f2014-11-19 20:26:34 -080075 if (mFd >= 0) {
76 close(mFd);
77 mFd = -1;
78 }
Chong Zhanga19f33e2014-08-07 15:35:07 -070079 mOffset = 0;
80 mLength = 0;
Ronghua Wu80276872014-08-28 15:50:29 -070081 setDrmPlaybackStatusIfNeeded(Playback::STOP, 0);
82 mDecryptHandle = NULL;
83 mDrmManagerClient = NULL;
84 mStarted = false;
Andy Hung2abde2c2014-09-30 14:40:32 -070085 mStopRead = true;
Chong Zhanga19f33e2014-08-07 15:35:07 -070086}
87
88status_t NuPlayer::GenericSource::setDataSource(
Chong Zhang3de157d2014-08-05 20:54:44 -070089 const sp<IMediaHTTPService> &httpService,
90 const char *url,
91 const KeyedVector<String8, String8> *headers) {
Chong Zhanga19f33e2014-08-07 15:35:07 -070092 resetDataSource();
Chong Zhang3de157d2014-08-05 20:54:44 -070093
Chong Zhanga19f33e2014-08-07 15:35:07 -070094 mHTTPService = httpService;
95 mUri = url;
Andreas Huberafed0e12011-09-20 15:39:58 -070096
Chong Zhanga19f33e2014-08-07 15:35:07 -070097 if (headers) {
98 mUriHeaders = *headers;
Chong Zhang3de157d2014-08-05 20:54:44 -070099 }
100
Chong Zhanga19f33e2014-08-07 15:35:07 -0700101 // delay data source creation to prepareAsync() to avoid blocking
102 // the calling thread in setDataSource for any significant time.
103 return OK;
Andreas Huberafed0e12011-09-20 15:39:58 -0700104}
105
Chong Zhanga19f33e2014-08-07 15:35:07 -0700106status_t NuPlayer::GenericSource::setDataSource(
Chong Zhang3de157d2014-08-05 20:54:44 -0700107 int fd, int64_t offset, int64_t length) {
Chong Zhanga19f33e2014-08-07 15:35:07 -0700108 resetDataSource();
Andreas Huberafed0e12011-09-20 15:39:58 -0700109
Chong Zhanga19f33e2014-08-07 15:35:07 -0700110 mFd = dup(fd);
111 mOffset = offset;
112 mLength = length;
113
114 // delay data source creation to prepareAsync() to avoid blocking
115 // the calling thread in setDataSource for any significant time.
116 return OK;
Andreas Huberafed0e12011-09-20 15:39:58 -0700117}
118
Marco Nelissenf0b72b52014-09-16 15:43:44 -0700119sp<MetaData> NuPlayer::GenericSource::getFileFormatMeta() const {
120 return mFileMeta;
121}
122
Chong Zhangd354d8d2014-08-20 13:09:58 -0700123status_t NuPlayer::GenericSource::initFromDataSource() {
Lajos Molnarcc227032014-07-17 15:33:06 -0700124 sp<MediaExtractor> extractor;
125
Chong Zhangd354d8d2014-08-20 13:09:58 -0700126 CHECK(mDataSource != NULL);
127
Lajos Molnarcc227032014-07-17 15:33:06 -0700128 if (mIsWidevine) {
129 String8 mimeType;
130 float confidence;
131 sp<AMessage> dummy;
132 bool success;
133
Chong Zhangd354d8d2014-08-20 13:09:58 -0700134 success = SniffWVM(mDataSource, &mimeType, &confidence, &dummy);
Lajos Molnarcc227032014-07-17 15:33:06 -0700135 if (!success
136 || strcasecmp(
137 mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) {
138 ALOGE("unsupported widevine mime: %s", mimeType.string());
Chong Zhang3de157d2014-08-05 20:54:44 -0700139 return UNKNOWN_ERROR;
Lajos Molnarcc227032014-07-17 15:33:06 -0700140 }
141
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700142 mWVMExtractor = new WVMExtractor(mDataSource);
143 mWVMExtractor->setAdaptiveStreamingMode(true);
Lajos Molnarcc227032014-07-17 15:33:06 -0700144 if (mUIDValid) {
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700145 mWVMExtractor->setUID(mUID);
Lajos Molnarcc227032014-07-17 15:33:06 -0700146 }
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700147 extractor = mWVMExtractor;
Lajos Molnarcc227032014-07-17 15:33:06 -0700148 } else {
Chong Zhangd354d8d2014-08-20 13:09:58 -0700149 extractor = MediaExtractor::Create(mDataSource,
150 mSniffedMIME.empty() ? NULL: mSniffedMIME.c_str());
Lajos Molnarcc227032014-07-17 15:33:06 -0700151 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700152
Chong Zhang3de157d2014-08-05 20:54:44 -0700153 if (extractor == NULL) {
154 return UNKNOWN_ERROR;
155 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700156
Ronghua Wu80276872014-08-28 15:50:29 -0700157 if (extractor->getDrmFlag()) {
158 checkDrmStatus(mDataSource);
159 }
160
Marco Nelissenf0b72b52014-09-16 15:43:44 -0700161 mFileMeta = extractor->getMetaData();
162 if (mFileMeta != NULL) {
Marco Nelissenc1f4b2b2014-06-17 14:48:32 -0700163 int64_t duration;
Marco Nelissenf0b72b52014-09-16 15:43:44 -0700164 if (mFileMeta->findInt64(kKeyDuration, &duration)) {
Marco Nelissenc1f4b2b2014-06-17 14:48:32 -0700165 mDurationUs = duration;
166 }
Chong Zhang42e81532014-12-01 13:44:26 -0800167
168 if (!mIsWidevine) {
169 // Check mime to see if we actually have a widevine source.
170 // If the data source is not URL-type (eg. file source), we
171 // won't be able to tell until now.
172 const char *fileMime;
173 if (mFileMeta->findCString(kKeyMIMEType, &fileMime)
174 && !strncasecmp(fileMime, "video/wvm", 9)) {
175 mIsWidevine = true;
176 }
177 }
Marco Nelissenc1f4b2b2014-06-17 14:48:32 -0700178 }
179
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700180 int32_t totalBitrate = 0;
181
Marco Nelissen705d3292014-09-19 15:14:37 -0700182 size_t numtracks = extractor->countTracks();
183 if (numtracks == 0) {
184 return UNKNOWN_ERROR;
185 }
186
187 for (size_t i = 0; i < numtracks; ++i) {
Chong Zhangafc0a872014-08-26 09:56:52 -0700188 sp<MediaSource> track = extractor->getTrack(i);
189
Andreas Huberafed0e12011-09-20 15:39:58 -0700190 sp<MetaData> meta = extractor->getTrackMetaData(i);
191
192 const char *mime;
193 CHECK(meta->findCString(kKeyMIMEType, &mime));
194
Chong Zhangafc0a872014-08-26 09:56:52 -0700195 // Do the string compare immediately with "mime",
196 // we can't assume "mime" would stay valid after another
197 // extractor operation, some extractors might modify meta
198 // during getTrack() and make it invalid.
Andreas Huberafed0e12011-09-20 15:39:58 -0700199 if (!strncasecmp(mime, "audio/", 6)) {
200 if (mAudioTrack.mSource == NULL) {
Robert Shihdd235722014-06-12 14:49:23 -0700201 mAudioTrack.mIndex = i;
202 mAudioTrack.mSource = track;
Robert Shihaf52c1a2014-09-11 15:38:54 -0700203 mAudioTrack.mPackets =
204 new AnotherPacketSource(mAudioTrack.mSource->getFormat());
Andreas Huberafed0e12011-09-20 15:39:58 -0700205
206 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
207 mAudioIsVorbis = true;
208 } else {
209 mAudioIsVorbis = false;
210 }
211 }
212 } else if (!strncasecmp(mime, "video/", 6)) {
213 if (mVideoTrack.mSource == NULL) {
Robert Shihdd235722014-06-12 14:49:23 -0700214 mVideoTrack.mIndex = i;
215 mVideoTrack.mSource = track;
Robert Shihaf52c1a2014-09-11 15:38:54 -0700216 mVideoTrack.mPackets =
217 new AnotherPacketSource(mVideoTrack.mSource->getFormat());
Chong Zhang7e892182014-08-05 11:58:21 -0700218
219 // check if the source requires secure buffers
220 int32_t secure;
Chong Zhanga19f33e2014-08-07 15:35:07 -0700221 if (meta->findInt32(kKeyRequiresSecureBuffers, &secure)
222 && secure) {
Chong Zhang42e81532014-12-01 13:44:26 -0800223 mIsSecure = true;
Chong Zhang3de157d2014-08-05 20:54:44 -0700224 if (mUIDValid) {
225 extractor->setUID(mUID);
226 }
Chong Zhang7e892182014-08-05 11:58:21 -0700227 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700228 }
229 }
230
231 if (track != NULL) {
Robert Shihdd235722014-06-12 14:49:23 -0700232 mSources.push(track);
Andreas Huberafed0e12011-09-20 15:39:58 -0700233 int64_t durationUs;
234 if (meta->findInt64(kKeyDuration, &durationUs)) {
235 if (durationUs > mDurationUs) {
236 mDurationUs = durationUs;
237 }
238 }
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700239
240 int32_t bitrate;
241 if (totalBitrate >= 0 && meta->findInt32(kKeyBitRate, &bitrate)) {
242 totalBitrate += bitrate;
243 } else {
244 totalBitrate = -1;
245 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700246 }
247 }
Chong Zhang3de157d2014-08-05 20:54:44 -0700248
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700249 mBitrate = totalBitrate;
250
Chong Zhang3de157d2014-08-05 20:54:44 -0700251 return OK;
Andreas Huberafed0e12011-09-20 15:39:58 -0700252}
253
Ronghua Wu80276872014-08-28 15:50:29 -0700254void NuPlayer::GenericSource::checkDrmStatus(const sp<DataSource>& dataSource) {
255 dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
256 if (mDecryptHandle != NULL) {
257 CHECK(mDrmManagerClient);
258 if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
259 sp<AMessage> msg = dupNotify();
260 msg->setInt32("what", kWhatDrmNoLicense);
261 msg->post();
262 }
263 }
264}
265
266int64_t NuPlayer::GenericSource::getLastReadPosition() {
267 if (mAudioTrack.mSource != NULL) {
268 return mAudioTimeUs;
269 } else if (mVideoTrack.mSource != NULL) {
270 return mVideoTimeUs;
271 } else {
272 return 0;
273 }
274}
275
Chong Zhanga19f33e2014-08-07 15:35:07 -0700276status_t NuPlayer::GenericSource::setBuffers(
277 bool audio, Vector<MediaBuffer *> &buffers) {
Chong Zhang42e81532014-12-01 13:44:26 -0800278 if (mIsSecure && !audio) {
Lajos Molnarcc227032014-07-17 15:33:06 -0700279 return mVideoTrack.mSource->setBuffers(buffers);
280 }
281 return INVALID_OPERATION;
282}
283
Andreas Huberafed0e12011-09-20 15:39:58 -0700284NuPlayer::GenericSource::~GenericSource() {
Chong Zhang1228d6b2014-08-12 21:25:48 -0700285 if (mLooper != NULL) {
286 mLooper->unregisterHandler(id());
287 mLooper->stop();
288 }
Chong Zhanga6bf21f2014-11-19 20:26:34 -0800289 resetDataSource();
Andreas Huberafed0e12011-09-20 15:39:58 -0700290}
291
Andreas Huber9575c962013-02-05 13:59:56 -0800292void NuPlayer::GenericSource::prepareAsync() {
Chong Zhang1228d6b2014-08-12 21:25:48 -0700293 if (mLooper == NULL) {
294 mLooper = new ALooper;
295 mLooper->setName("generic");
296 mLooper->start();
297
298 mLooper->registerHandler(this);
299 }
300
301 sp<AMessage> msg = new AMessage(kWhatPrepareAsync, id());
302 msg->post();
303}
304
305void NuPlayer::GenericSource::onPrepareAsync() {
Chong Zhanga19f33e2014-08-07 15:35:07 -0700306 // delayed data source creation
Chong Zhangd354d8d2014-08-20 13:09:58 -0700307 if (mDataSource == NULL) {
Chong Zhang42e81532014-12-01 13:44:26 -0800308 // set to false first, if the extractor
309 // comes back as secure, set it to true then.
310 mIsSecure = false;
311
Chong Zhangd354d8d2014-08-20 13:09:58 -0700312 if (!mUri.empty()) {
Robert Shih360d6d02014-09-29 14:42:35 -0700313 const char* uri = mUri.c_str();
314 mIsWidevine = !strncasecmp(uri, "widevine://", 11);
315
316 if (!strncasecmp("http://", uri, 7)
317 || !strncasecmp("https://", uri, 8)
318 || mIsWidevine) {
319 mHttpSource = DataSource::CreateMediaHTTP(mHTTPService);
320 if (mHttpSource == NULL) {
321 ALOGE("Failed to create http source!");
322 notifyPreparedAndCleanup(UNKNOWN_ERROR);
323 return;
324 }
325 }
Chong Zhanga19f33e2014-08-07 15:35:07 -0700326
Chong Zhangd354d8d2014-08-20 13:09:58 -0700327 mDataSource = DataSource::CreateFromURI(
Robert Shih360d6d02014-09-29 14:42:35 -0700328 mHTTPService, uri, &mUriHeaders, &mContentType,
329 static_cast<HTTPBase *>(mHttpSource.get()));
Chong Zhangd354d8d2014-08-20 13:09:58 -0700330 } else {
Chong Zhangd354d8d2014-08-20 13:09:58 -0700331 mIsWidevine = false;
Chong Zhanga19f33e2014-08-07 15:35:07 -0700332
Chong Zhangd354d8d2014-08-20 13:09:58 -0700333 mDataSource = new FileSource(mFd, mOffset, mLength);
Chong Zhanga6bf21f2014-11-19 20:26:34 -0800334 mFd = -1;
Chong Zhangd354d8d2014-08-20 13:09:58 -0700335 }
Chong Zhanga19f33e2014-08-07 15:35:07 -0700336
Chong Zhangd354d8d2014-08-20 13:09:58 -0700337 if (mDataSource == NULL) {
338 ALOGE("Failed to create data source!");
339 notifyPreparedAndCleanup(UNKNOWN_ERROR);
340 return;
341 }
342
343 if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
344 mCachedSource = static_cast<NuCachedSource2 *>(mDataSource.get());
345 }
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700346
347 if (mIsWidevine || mCachedSource != NULL) {
348 schedulePollBuffering();
349 }
Chong Zhanga19f33e2014-08-07 15:35:07 -0700350 }
351
Chong Zhangd354d8d2014-08-20 13:09:58 -0700352 // check initial caching status
353 status_t err = prefillCacheIfNecessary();
354 if (err != OK) {
355 if (err == -EAGAIN) {
356 (new AMessage(kWhatPrepareAsync, id()))->post(200000);
357 } else {
358 ALOGE("Failed to prefill data cache!");
359 notifyPreparedAndCleanup(UNKNOWN_ERROR);
360 }
Chong Zhanga19f33e2014-08-07 15:35:07 -0700361 return;
362 }
363
Chong Zhangd354d8d2014-08-20 13:09:58 -0700364 // init extrator from data source
365 err = initFromDataSource();
Chong Zhanga19f33e2014-08-07 15:35:07 -0700366
367 if (err != OK) {
368 ALOGE("Failed to init from data source!");
Chong Zhangd354d8d2014-08-20 13:09:58 -0700369 notifyPreparedAndCleanup(err);
Chong Zhanga19f33e2014-08-07 15:35:07 -0700370 return;
371 }
372
Andreas Huber9575c962013-02-05 13:59:56 -0800373 if (mVideoTrack.mSource != NULL) {
Robert Shih17f6dd62014-08-20 17:00:21 -0700374 sp<MetaData> meta = doGetFormatMeta(false /* audio */);
375 sp<AMessage> msg = new AMessage;
376 err = convertMetaDataToMessage(meta, &msg);
377 if(err != OK) {
378 notifyPreparedAndCleanup(err);
379 return;
380 }
381 notifyVideoSizeChanged(msg);
Andreas Huber9575c962013-02-05 13:59:56 -0800382 }
383
384 notifyFlagsChanged(
Chong Zhang42e81532014-12-01 13:44:26 -0800385 (mIsSecure ? FLAG_SECURE : 0)
Lajos Molnarcc227032014-07-17 15:33:06 -0700386 | FLAG_CAN_PAUSE
Andreas Huber9575c962013-02-05 13:59:56 -0800387 | FLAG_CAN_SEEK_BACKWARD
388 | FLAG_CAN_SEEK_FORWARD
389 | FLAG_CAN_SEEK);
390
391 notifyPrepared();
392}
393
Chong Zhangd354d8d2014-08-20 13:09:58 -0700394void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) {
395 if (err != OK) {
396 mMetaDataSize = -1ll;
397 mContentType = "";
398 mSniffedMIME = "";
399 mDataSource.clear();
400 mCachedSource.clear();
Robert Shih360d6d02014-09-29 14:42:35 -0700401 mHttpSource.clear();
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700402
403 cancelPollBuffering();
Chong Zhangd354d8d2014-08-20 13:09:58 -0700404 }
405 notifyPrepared(err);
406}
407
408status_t NuPlayer::GenericSource::prefillCacheIfNecessary() {
409 CHECK(mDataSource != NULL);
410
411 if (mCachedSource == NULL) {
412 // no prefill if the data source is not cached
413 return OK;
414 }
415
416 // We're not doing this for streams that appear to be audio-only
417 // streams to ensure that even low bandwidth streams start
418 // playing back fairly instantly.
419 if (!strncasecmp(mContentType.string(), "audio/", 6)) {
420 return OK;
421 }
422
423 // We're going to prefill the cache before trying to instantiate
424 // the extractor below, as the latter is an operation that otherwise
425 // could block on the datasource for a significant amount of time.
426 // During that time we'd be unable to abort the preparation phase
427 // without this prefill.
428
429 // Initially make sure we have at least 192 KB for the sniff
430 // to complete without blocking.
431 static const size_t kMinBytesForSniffing = 192 * 1024;
432 static const size_t kDefaultMetaSize = 200000;
433
434 status_t finalStatus;
435
436 size_t cachedDataRemaining =
437 mCachedSource->approxDataRemaining(&finalStatus);
438
439 if (finalStatus != OK || (mMetaDataSize >= 0
440 && (off64_t)cachedDataRemaining >= mMetaDataSize)) {
441 ALOGV("stop caching, status %d, "
442 "metaDataSize %lld, cachedDataRemaining %zu",
443 finalStatus, mMetaDataSize, cachedDataRemaining);
444 return OK;
445 }
446
447 ALOGV("now cached %zu bytes of data", cachedDataRemaining);
448
449 if (mMetaDataSize < 0
450 && cachedDataRemaining >= kMinBytesForSniffing) {
451 String8 tmp;
452 float confidence;
453 sp<AMessage> meta;
454 if (!mCachedSource->sniff(&tmp, &confidence, &meta)) {
455 return UNKNOWN_ERROR;
456 }
457
458 // We successfully identified the file's extractor to
459 // be, remember this mime type so we don't have to
460 // sniff it again when we call MediaExtractor::Create()
461 mSniffedMIME = tmp.string();
462
463 if (meta == NULL
464 || !meta->findInt64("meta-data-size",
465 reinterpret_cast<int64_t*>(&mMetaDataSize))) {
466 mMetaDataSize = kDefaultMetaSize;
467 }
468
469 if (mMetaDataSize < 0ll) {
470 ALOGE("invalid metaDataSize = %lld bytes", mMetaDataSize);
471 return UNKNOWN_ERROR;
472 }
473 }
474
475 return -EAGAIN;
476}
477
Andreas Huberafed0e12011-09-20 15:39:58 -0700478void NuPlayer::GenericSource::start() {
479 ALOGI("start");
480
Andy Hung2abde2c2014-09-30 14:40:32 -0700481 mStopRead = false;
Andreas Huberafed0e12011-09-20 15:39:58 -0700482 if (mAudioTrack.mSource != NULL) {
Robert Shihbace25b2014-07-25 14:14:34 -0700483 CHECK_EQ(mAudioTrack.mSource->start(), (status_t)OK);
Andreas Huberafed0e12011-09-20 15:39:58 -0700484
Robert Shih17f6dd62014-08-20 17:00:21 -0700485 postReadBuffer(MEDIA_TRACK_TYPE_AUDIO);
Andreas Huberafed0e12011-09-20 15:39:58 -0700486 }
487
488 if (mVideoTrack.mSource != NULL) {
Robert Shihbace25b2014-07-25 14:14:34 -0700489 CHECK_EQ(mVideoTrack.mSource->start(), (status_t)OK);
Andreas Huberafed0e12011-09-20 15:39:58 -0700490
Robert Shih17f6dd62014-08-20 17:00:21 -0700491 postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
Andreas Huberafed0e12011-09-20 15:39:58 -0700492 }
Ronghua Wu80276872014-08-28 15:50:29 -0700493
494 setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000);
495 mStarted = true;
496}
497
498void NuPlayer::GenericSource::stop() {
499 // nothing to do, just account for DRM playback status
500 setDrmPlaybackStatusIfNeeded(Playback::STOP, 0);
501 mStarted = false;
Chong Zhang42e81532014-12-01 13:44:26 -0800502 if (mIsWidevine || mIsSecure) {
503 // For widevine or secure sources we need to prevent any further reads.
Andy Hung2abde2c2014-09-30 14:40:32 -0700504 sp<AMessage> msg = new AMessage(kWhatStopWidevine, id());
505 sp<AMessage> response;
506 (void) msg->postAndAwaitResponse(&response);
507 }
Ronghua Wu80276872014-08-28 15:50:29 -0700508}
509
510void NuPlayer::GenericSource::pause() {
511 // nothing to do, just account for DRM playback status
512 setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0);
513 mStarted = false;
514}
515
516void NuPlayer::GenericSource::resume() {
517 // nothing to do, just account for DRM playback status
518 setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000);
519 mStarted = true;
520}
521
Chong Zhang48296b72014-09-14 14:28:45 -0700522void NuPlayer::GenericSource::disconnect() {
523 if (mDataSource != NULL) {
524 // disconnect data source
525 if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
526 static_cast<NuCachedSource2 *>(mDataSource.get())->disconnect();
527 }
Robert Shih360d6d02014-09-29 14:42:35 -0700528 } else if (mHttpSource != NULL) {
529 static_cast<HTTPBase *>(mHttpSource.get())->disconnect();
Chong Zhang48296b72014-09-14 14:28:45 -0700530 }
531}
532
Ronghua Wu80276872014-08-28 15:50:29 -0700533void NuPlayer::GenericSource::setDrmPlaybackStatusIfNeeded(int playbackStatus, int64_t position) {
534 if (mDecryptHandle != NULL) {
535 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, playbackStatus, position);
536 }
Robert Shih17f6dd62014-08-20 17:00:21 -0700537 mSubtitleTrack.mPackets = new AnotherPacketSource(NULL);
538 mTimedTextTrack.mPackets = new AnotherPacketSource(NULL);
Andreas Huberafed0e12011-09-20 15:39:58 -0700539}
540
541status_t NuPlayer::GenericSource::feedMoreTSData() {
542 return OK;
543}
544
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700545void NuPlayer::GenericSource::schedulePollBuffering() {
546 sp<AMessage> msg = new AMessage(kWhatPollBuffering, id());
547 msg->setInt32("generation", mPollBufferingGeneration);
548 msg->post(1000000ll);
549}
550
551void NuPlayer::GenericSource::cancelPollBuffering() {
552 ++mPollBufferingGeneration;
553}
554
555void NuPlayer::GenericSource::notifyBufferingUpdate(int percentage) {
556 sp<AMessage> msg = dupNotify();
557 msg->setInt32("what", kWhatBufferingUpdate);
558 msg->setInt32("percentage", percentage);
559 msg->post();
560}
561
562void NuPlayer::GenericSource::onPollBuffering() {
563 status_t finalStatus = UNKNOWN_ERROR;
564 int64_t cachedDurationUs = 0ll;
565
566 if (mCachedSource != NULL) {
567 size_t cachedDataRemaining =
568 mCachedSource->approxDataRemaining(&finalStatus);
569
570 if (finalStatus == OK) {
571 off64_t size;
572 int64_t bitrate = 0ll;
573 if (mDurationUs > 0 && mCachedSource->getSize(&size) == OK) {
574 bitrate = size * 8000000ll / mDurationUs;
575 } else if (mBitrate > 0) {
576 bitrate = mBitrate;
577 }
578 if (bitrate > 0) {
579 cachedDurationUs = cachedDataRemaining * 8000000ll / bitrate;
580 }
581 }
582 } else if (mWVMExtractor != NULL) {
583 cachedDurationUs
584 = mWVMExtractor->getCachedDurationUs(&finalStatus);
585 }
586
587 if (finalStatus == ERROR_END_OF_STREAM) {
588 notifyBufferingUpdate(100);
589 cancelPollBuffering();
590 return;
591 } else if (cachedDurationUs > 0ll && mDurationUs > 0ll) {
592 int percentage = 100.0 * cachedDurationUs / mDurationUs;
593 if (percentage > 100) {
594 percentage = 100;
595 }
596
597 notifyBufferingUpdate(percentage);
598 }
599
600 schedulePollBuffering();
601}
602
603
Robert Shih3423bbd2014-07-16 15:47:09 -0700604void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) {
605 switch (msg->what()) {
Chong Zhang1228d6b2014-08-12 21:25:48 -0700606 case kWhatPrepareAsync:
607 {
608 onPrepareAsync();
609 break;
610 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700611 case kWhatFetchSubtitleData:
612 {
Lajos Molnare26940f2014-07-31 10:31:26 -0700613 fetchTextData(kWhatSendSubtitleData, 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 kWhatFetchTimedTextData:
619 {
620 fetchTextData(kWhatSendTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
621 mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
Robert Shih3423bbd2014-07-16 15:47:09 -0700622 break;
623 }
624
625 case kWhatSendSubtitleData:
626 {
Lajos Molnare26940f2014-07-31 10:31:26 -0700627 sendTextData(kWhatSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
628 mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
629 break;
630 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700631
Lajos Molnare26940f2014-07-31 10:31:26 -0700632 case kWhatSendTimedTextData:
633 {
634 sendTextData(kWhatTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
635 mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
Robert Shih3423bbd2014-07-16 15:47:09 -0700636 break;
637 }
638
639 case kWhatChangeAVSource:
640 {
641 int32_t trackIndex;
642 CHECK(msg->findInt32("trackIndex", &trackIndex));
643 const sp<MediaSource> source = mSources.itemAt(trackIndex);
644
645 Track* track;
646 const char *mime;
647 media_track_type trackType, counterpartType;
648 sp<MetaData> meta = source->getFormat();
649 meta->findCString(kKeyMIMEType, &mime);
650 if (!strncasecmp(mime, "audio/", 6)) {
651 track = &mAudioTrack;
652 trackType = MEDIA_TRACK_TYPE_AUDIO;
653 counterpartType = MEDIA_TRACK_TYPE_VIDEO;;
654 } else {
655 CHECK(!strncasecmp(mime, "video/", 6));
656 track = &mVideoTrack;
657 trackType = MEDIA_TRACK_TYPE_VIDEO;
658 counterpartType = MEDIA_TRACK_TYPE_AUDIO;;
659 }
660
661
662 if (track->mSource != NULL) {
663 track->mSource->stop();
664 }
665 track->mSource = source;
666 track->mSource->start();
667 track->mIndex = trackIndex;
668
Robert Shih3423bbd2014-07-16 15:47:09 -0700669 int64_t timeUs, actualTimeUs;
670 const bool formatChange = true;
Robert Shih5c67ddc2014-11-04 17:46:05 -0800671 if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
672 timeUs = mAudioLastDequeueTimeUs;
673 } else {
674 timeUs = mVideoLastDequeueTimeUs;
675 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700676 readBuffer(trackType, timeUs, &actualTimeUs, formatChange);
677 readBuffer(counterpartType, -1, NULL, formatChange);
678 ALOGV("timeUs %lld actualTimeUs %lld", timeUs, actualTimeUs);
679
680 break;
681 }
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700682 case kWhatPollBuffering:
683 {
684 int32_t generation;
685 CHECK(msg->findInt32("generation", &generation));
686 if (generation == mPollBufferingGeneration) {
687 onPollBuffering();
688 }
689 break;
690 }
Robert Shih17f6dd62014-08-20 17:00:21 -0700691
692 case kWhatGetFormat:
693 {
694 onGetFormatMeta(msg);
695 break;
696 }
697
698 case kWhatGetSelectedTrack:
699 {
700 onGetSelectedTrack(msg);
701 break;
702 }
703
704 case kWhatSelectTrack:
705 {
706 onSelectTrack(msg);
707 break;
708 }
709
710 case kWhatSeek:
711 {
712 onSeek(msg);
713 break;
714 }
715
716 case kWhatReadBuffer:
717 {
718 onReadBuffer(msg);
719 break;
720 }
721
Andy Hung2abde2c2014-09-30 14:40:32 -0700722 case kWhatStopWidevine:
723 {
724 // mStopRead is only used for Widevine to prevent the video source
725 // from being read while the associated video decoder is shutting down.
726 mStopRead = true;
727 if (mVideoTrack.mSource != NULL) {
728 mVideoTrack.mPackets->clear();
729 }
730 sp<AMessage> response = new AMessage;
731 uint32_t replyID;
732 CHECK(msg->senderAwaitsResponse(&replyID));
733 response->postReply(replyID);
734 break;
735 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700736 default:
737 Source::onMessageReceived(msg);
738 break;
739 }
740}
741
Lajos Molnare26940f2014-07-31 10:31:26 -0700742void NuPlayer::GenericSource::fetchTextData(
743 uint32_t sendWhat,
744 media_track_type type,
745 int32_t curGen,
746 sp<AnotherPacketSource> packets,
747 sp<AMessage> msg) {
748 int32_t msgGeneration;
749 CHECK(msg->findInt32("generation", &msgGeneration));
750 if (msgGeneration != curGen) {
751 // stale
752 return;
753 }
754
755 int32_t avail;
756 if (packets->hasBufferAvailable(&avail)) {
757 return;
758 }
759
760 int64_t timeUs;
761 CHECK(msg->findInt64("timeUs", &timeUs));
762
763 int64_t subTimeUs;
764 readBuffer(type, timeUs, &subTimeUs);
765
766 int64_t delayUs = subTimeUs - timeUs;
767 if (msg->what() == kWhatFetchSubtitleData) {
768 const int64_t oneSecUs = 1000000ll;
769 delayUs -= oneSecUs;
770 }
771 sp<AMessage> msg2 = new AMessage(sendWhat, id());
772 msg2->setInt32("generation", msgGeneration);
773 msg2->post(delayUs < 0 ? 0 : delayUs);
774}
775
776void NuPlayer::GenericSource::sendTextData(
777 uint32_t what,
778 media_track_type type,
779 int32_t curGen,
780 sp<AnotherPacketSource> packets,
781 sp<AMessage> msg) {
782 int32_t msgGeneration;
783 CHECK(msg->findInt32("generation", &msgGeneration));
784 if (msgGeneration != curGen) {
785 // stale
786 return;
787 }
788
789 int64_t subTimeUs;
790 if (packets->nextBufferTime(&subTimeUs) != OK) {
791 return;
792 }
793
794 int64_t nextSubTimeUs;
795 readBuffer(type, -1, &nextSubTimeUs);
796
797 sp<ABuffer> buffer;
798 status_t dequeueStatus = packets->dequeueAccessUnit(&buffer);
799 if (dequeueStatus == OK) {
800 sp<AMessage> notify = dupNotify();
801 notify->setInt32("what", what);
802 notify->setBuffer("buffer", buffer);
803 notify->post();
804
805 const int64_t delayUs = nextSubTimeUs - subTimeUs;
806 msg->post(delayUs < 0 ? 0 : delayUs);
807 }
808}
809
Andreas Huber84066782011-08-16 09:34:26 -0700810sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
Robert Shih17f6dd62014-08-20 17:00:21 -0700811 sp<AMessage> msg = new AMessage(kWhatGetFormat, id());
812 msg->setInt32("audio", audio);
813
814 sp<AMessage> response;
815 void *format;
816 status_t err = msg->postAndAwaitResponse(&response);
817 if (err == OK && response != NULL) {
818 CHECK(response->findPointer("format", &format));
819 return (MetaData *)format;
820 } else {
821 return NULL;
822 }
823}
824
825void NuPlayer::GenericSource::onGetFormatMeta(sp<AMessage> msg) const {
826 int32_t audio;
827 CHECK(msg->findInt32("audio", &audio));
828
829 sp<AMessage> response = new AMessage;
830 sp<MetaData> format = doGetFormatMeta(audio);
831 response->setPointer("format", format.get());
832
833 uint32_t replyID;
834 CHECK(msg->senderAwaitsResponse(&replyID));
835 response->postReply(replyID);
836}
837
838sp<MetaData> NuPlayer::GenericSource::doGetFormatMeta(bool audio) const {
Andreas Huberafed0e12011-09-20 15:39:58 -0700839 sp<MediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
840
841 if (source == NULL) {
842 return NULL;
843 }
844
845 return source->getFormat();
846}
847
848status_t NuPlayer::GenericSource::dequeueAccessUnit(
849 bool audio, sp<ABuffer> *accessUnit) {
850 Track *track = audio ? &mAudioTrack : &mVideoTrack;
851
852 if (track->mSource == NULL) {
853 return -EWOULDBLOCK;
854 }
855
Lajos Molnarcc227032014-07-17 15:33:06 -0700856 if (mIsWidevine && !audio) {
857 // try to read a buffer as we may not have been able to the last time
Robert Shih17f6dd62014-08-20 17:00:21 -0700858 postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
Lajos Molnarcc227032014-07-17 15:33:06 -0700859 }
860
Andreas Huberafed0e12011-09-20 15:39:58 -0700861 status_t finalResult;
862 if (!track->mPackets->hasBufferAvailable(&finalResult)) {
Chong Zhang42e81532014-12-01 13:44:26 -0800863 if (finalResult == OK) {
864 postReadBuffer(
865 audio ? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
866 return -EWOULDBLOCK;
867 }
868 return finalResult;
Andreas Huberafed0e12011-09-20 15:39:58 -0700869 }
870
871 status_t result = track->mPackets->dequeueAccessUnit(accessUnit);
872
Robert Shih3423bbd2014-07-16 15:47:09 -0700873 if (!track->mPackets->hasBufferAvailable(&finalResult)) {
Robert Shih17f6dd62014-08-20 17:00:21 -0700874 postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
Lajos Molnare26940f2014-07-31 10:31:26 -0700875 }
876
Robert Shih3423bbd2014-07-16 15:47:09 -0700877 if (result != OK) {
Lajos Molnare26940f2014-07-31 10:31:26 -0700878 if (mSubtitleTrack.mSource != NULL) {
879 mSubtitleTrack.mPackets->clear();
880 mFetchSubtitleDataGeneration++;
881 }
882 if (mTimedTextTrack.mSource != NULL) {
883 mTimedTextTrack.mPackets->clear();
884 mFetchTimedTextDataGeneration++;
885 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700886 return result;
887 }
888
889 int64_t timeUs;
890 status_t eosResult; // ignored
891 CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs));
Robert Shih5c67ddc2014-11-04 17:46:05 -0800892 if (audio) {
893 mAudioLastDequeueTimeUs = timeUs;
894 } else {
895 mVideoLastDequeueTimeUs = timeUs;
896 }
Lajos Molnare26940f2014-07-31 10:31:26 -0700897
898 if (mSubtitleTrack.mSource != NULL
899 && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
Robert Shih3423bbd2014-07-16 15:47:09 -0700900 sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, id());
901 msg->setInt64("timeUs", timeUs);
902 msg->setInt32("generation", mFetchSubtitleDataGeneration);
903 msg->post();
904 }
Robert Shiheb1735e2014-07-23 15:53:14 -0700905
Lajos Molnare26940f2014-07-31 10:31:26 -0700906 if (mTimedTextTrack.mSource != NULL
907 && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
908 sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, id());
909 msg->setInt64("timeUs", timeUs);
910 msg->setInt32("generation", mFetchTimedTextDataGeneration);
911 msg->post();
912 }
913
Andreas Huberafed0e12011-09-20 15:39:58 -0700914 return result;
915}
916
917status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) {
918 *durationUs = mDurationUs;
919 return OK;
920}
921
Robert Shihdd235722014-06-12 14:49:23 -0700922size_t NuPlayer::GenericSource::getTrackCount() const {
923 return mSources.size();
924}
925
926sp<AMessage> NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const {
927 size_t trackCount = mSources.size();
928 if (trackIndex >= trackCount) {
929 return NULL;
930 }
931
932 sp<AMessage> format = new AMessage();
933 sp<MetaData> meta = mSources.itemAt(trackIndex)->getFormat();
934
935 const char *mime;
936 CHECK(meta->findCString(kKeyMIMEType, &mime));
937
938 int32_t trackType;
939 if (!strncasecmp(mime, "video/", 6)) {
940 trackType = MEDIA_TRACK_TYPE_VIDEO;
941 } else if (!strncasecmp(mime, "audio/", 6)) {
942 trackType = MEDIA_TRACK_TYPE_AUDIO;
943 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
944 trackType = MEDIA_TRACK_TYPE_TIMEDTEXT;
945 } else {
946 trackType = MEDIA_TRACK_TYPE_UNKNOWN;
947 }
948 format->setInt32("type", trackType);
949
950 const char *lang;
951 if (!meta->findCString(kKeyMediaLanguage, &lang)) {
952 lang = "und";
953 }
954 format->setString("language", lang);
955
956 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
957 format->setString("mime", mime);
958
959 int32_t isAutoselect = 1, isDefault = 0, isForced = 0;
960 meta->findInt32(kKeyTrackIsAutoselect, &isAutoselect);
961 meta->findInt32(kKeyTrackIsDefault, &isDefault);
962 meta->findInt32(kKeyTrackIsForced, &isForced);
963
964 format->setInt32("auto", !!isAutoselect);
965 format->setInt32("default", !!isDefault);
966 format->setInt32("forced", !!isForced);
967 }
968
969 return format;
970}
971
Lajos Molnare26940f2014-07-31 10:31:26 -0700972ssize_t NuPlayer::GenericSource::getSelectedTrack(media_track_type type) const {
Robert Shih17f6dd62014-08-20 17:00:21 -0700973 sp<AMessage> msg = new AMessage(kWhatGetSelectedTrack, id());
974 msg->setInt32("type", type);
975
976 sp<AMessage> response;
977 int32_t index;
978 status_t err = msg->postAndAwaitResponse(&response);
979 if (err == OK && response != NULL) {
980 CHECK(response->findInt32("index", &index));
981 return index;
982 } else {
983 return -1;
984 }
985}
986
987void NuPlayer::GenericSource::onGetSelectedTrack(sp<AMessage> msg) const {
988 int32_t tmpType;
989 CHECK(msg->findInt32("type", &tmpType));
990 media_track_type type = (media_track_type)tmpType;
991
992 sp<AMessage> response = new AMessage;
993 ssize_t index = doGetSelectedTrack(type);
994 response->setInt32("index", index);
995
996 uint32_t replyID;
997 CHECK(msg->senderAwaitsResponse(&replyID));
998 response->postReply(replyID);
999}
1000
1001ssize_t NuPlayer::GenericSource::doGetSelectedTrack(media_track_type type) const {
Lajos Molnare26940f2014-07-31 10:31:26 -07001002 const Track *track = NULL;
1003 switch (type) {
1004 case MEDIA_TRACK_TYPE_VIDEO:
1005 track = &mVideoTrack;
1006 break;
1007 case MEDIA_TRACK_TYPE_AUDIO:
1008 track = &mAudioTrack;
1009 break;
1010 case MEDIA_TRACK_TYPE_TIMEDTEXT:
1011 track = &mTimedTextTrack;
1012 break;
1013 case MEDIA_TRACK_TYPE_SUBTITLE:
1014 track = &mSubtitleTrack;
1015 break;
1016 default:
1017 break;
1018 }
1019
1020 if (track != NULL && track->mSource != NULL) {
1021 return track->mIndex;
1022 }
1023
1024 return -1;
1025}
1026
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001027status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select, int64_t timeUs) {
Lajos Molnare26940f2014-07-31 10:31:26 -07001028 ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex);
Robert Shih17f6dd62014-08-20 17:00:21 -07001029 sp<AMessage> msg = new AMessage(kWhatSelectTrack, id());
1030 msg->setInt32("trackIndex", trackIndex);
Robert Shihda23ab92014-09-16 11:34:08 -07001031 msg->setInt32("select", select);
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001032 msg->setInt64("timeUs", timeUs);
Robert Shih17f6dd62014-08-20 17:00:21 -07001033
1034 sp<AMessage> response;
1035 status_t err = msg->postAndAwaitResponse(&response);
1036 if (err == OK && response != NULL) {
1037 CHECK(response->findInt32("err", &err));
1038 }
1039
1040 return err;
1041}
1042
1043void NuPlayer::GenericSource::onSelectTrack(sp<AMessage> msg) {
1044 int32_t trackIndex, select;
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001045 int64_t timeUs;
Robert Shih17f6dd62014-08-20 17:00:21 -07001046 CHECK(msg->findInt32("trackIndex", &trackIndex));
1047 CHECK(msg->findInt32("select", &select));
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001048 CHECK(msg->findInt64("timeUs", &timeUs));
Robert Shih17f6dd62014-08-20 17:00:21 -07001049
1050 sp<AMessage> response = new AMessage;
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001051 status_t err = doSelectTrack(trackIndex, select, timeUs);
Robert Shih17f6dd62014-08-20 17:00:21 -07001052 response->setInt32("err", err);
1053
1054 uint32_t replyID;
1055 CHECK(msg->senderAwaitsResponse(&replyID));
1056 response->postReply(replyID);
1057}
1058
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001059status_t NuPlayer::GenericSource::doSelectTrack(size_t trackIndex, bool select, int64_t timeUs) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001060 if (trackIndex >= mSources.size()) {
1061 return BAD_INDEX;
1062 }
1063
1064 if (!select) {
Lajos Molnare26940f2014-07-31 10:31:26 -07001065 Track* track = NULL;
1066 if (mSubtitleTrack.mSource != NULL && trackIndex == mSubtitleTrack.mIndex) {
1067 track = &mSubtitleTrack;
1068 mFetchSubtitleDataGeneration++;
1069 } else if (mTimedTextTrack.mSource != NULL && trackIndex == mTimedTextTrack.mIndex) {
1070 track = &mTimedTextTrack;
1071 mFetchTimedTextDataGeneration++;
1072 }
1073 if (track == NULL) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001074 return INVALID_OPERATION;
1075 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001076 track->mSource->stop();
1077 track->mSource = NULL;
1078 track->mPackets->clear();
Robert Shih3423bbd2014-07-16 15:47:09 -07001079 return OK;
1080 }
1081
1082 const sp<MediaSource> source = mSources.itemAt(trackIndex);
1083 sp<MetaData> meta = source->getFormat();
1084 const char *mime;
1085 CHECK(meta->findCString(kKeyMIMEType, &mime));
1086 if (!strncasecmp(mime, "text/", 5)) {
Lajos Molnare26940f2014-07-31 10:31:26 -07001087 bool isSubtitle = strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP);
1088 Track *track = isSubtitle ? &mSubtitleTrack : &mTimedTextTrack;
1089 if (track->mSource != NULL && track->mIndex == trackIndex) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001090 return OK;
1091 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001092 track->mIndex = trackIndex;
1093 if (track->mSource != NULL) {
1094 track->mSource->stop();
Robert Shih3423bbd2014-07-16 15:47:09 -07001095 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001096 track->mSource = mSources.itemAt(trackIndex);
1097 track->mSource->start();
1098 if (track->mPackets == NULL) {
1099 track->mPackets = new AnotherPacketSource(track->mSource->getFormat());
Robert Shih3423bbd2014-07-16 15:47:09 -07001100 } else {
Lajos Molnare26940f2014-07-31 10:31:26 -07001101 track->mPackets->clear();
1102 track->mPackets->setFormat(track->mSource->getFormat());
Robert Shih3423bbd2014-07-16 15:47:09 -07001103
1104 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001105
1106 if (isSubtitle) {
1107 mFetchSubtitleDataGeneration++;
1108 } else {
1109 mFetchTimedTextDataGeneration++;
1110 }
1111
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001112 status_t eosResult; // ignored
1113 if (mSubtitleTrack.mSource != NULL
1114 && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
1115 sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, id());
1116 msg->setInt64("timeUs", timeUs);
1117 msg->setInt32("generation", mFetchSubtitleDataGeneration);
1118 msg->post();
1119 }
1120
1121 if (mTimedTextTrack.mSource != NULL
1122 && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
1123 sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, id());
1124 msg->setInt64("timeUs", timeUs);
1125 msg->setInt32("generation", mFetchTimedTextDataGeneration);
1126 msg->post();
1127 }
1128
Robert Shih3423bbd2014-07-16 15:47:09 -07001129 return OK;
1130 } else if (!strncasecmp(mime, "audio/", 6) || !strncasecmp(mime, "video/", 6)) {
1131 bool audio = !strncasecmp(mime, "audio/", 6);
1132 Track *track = audio ? &mAudioTrack : &mVideoTrack;
1133 if (track->mSource != NULL && track->mIndex == trackIndex) {
1134 return OK;
1135 }
1136
1137 sp<AMessage> msg = new AMessage(kWhatChangeAVSource, id());
1138 msg->setInt32("trackIndex", trackIndex);
1139 msg->post();
1140 return OK;
1141 }
1142
1143 return INVALID_OPERATION;
1144}
1145
Andreas Huberafed0e12011-09-20 15:39:58 -07001146status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) {
Robert Shih17f6dd62014-08-20 17:00:21 -07001147 sp<AMessage> msg = new AMessage(kWhatSeek, id());
1148 msg->setInt64("seekTimeUs", seekTimeUs);
1149
1150 sp<AMessage> response;
1151 status_t err = msg->postAndAwaitResponse(&response);
1152 if (err == OK && response != NULL) {
1153 CHECK(response->findInt32("err", &err));
1154 }
1155
1156 return err;
1157}
1158
1159void NuPlayer::GenericSource::onSeek(sp<AMessage> msg) {
1160 int64_t seekTimeUs;
1161 CHECK(msg->findInt64("seekTimeUs", &seekTimeUs));
1162
1163 sp<AMessage> response = new AMessage;
1164 status_t err = doSeek(seekTimeUs);
1165 response->setInt32("err", err);
1166
1167 uint32_t replyID;
1168 CHECK(msg->senderAwaitsResponse(&replyID));
1169 response->postReply(replyID);
1170}
1171
1172status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs) {
Andy Hung2abde2c2014-09-30 14:40:32 -07001173 // If the Widevine source is stopped, do not attempt to read any
1174 // more buffers.
1175 if (mStopRead) {
1176 return INVALID_OPERATION;
1177 }
Andreas Huberafed0e12011-09-20 15:39:58 -07001178 if (mVideoTrack.mSource != NULL) {
1179 int64_t actualTimeUs;
Robert Shih3423bbd2014-07-16 15:47:09 -07001180 readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, &actualTimeUs);
Andreas Huberafed0e12011-09-20 15:39:58 -07001181
1182 seekTimeUs = actualTimeUs;
Robert Shih5c67ddc2014-11-04 17:46:05 -08001183 mVideoLastDequeueTimeUs = seekTimeUs;
Andreas Huberafed0e12011-09-20 15:39:58 -07001184 }
1185
1186 if (mAudioTrack.mSource != NULL) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001187 readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs);
Robert Shih5c67ddc2014-11-04 17:46:05 -08001188 mAudioLastDequeueTimeUs = seekTimeUs;
Andreas Huberafed0e12011-09-20 15:39:58 -07001189 }
1190
Ronghua Wu80276872014-08-28 15:50:29 -07001191 setDrmPlaybackStatusIfNeeded(Playback::START, seekTimeUs / 1000);
1192 if (!mStarted) {
1193 setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0);
1194 }
Andreas Huberafed0e12011-09-20 15:39:58 -07001195 return OK;
1196}
1197
Robert Shih3423bbd2014-07-16 15:47:09 -07001198sp<ABuffer> NuPlayer::GenericSource::mediaBufferToABuffer(
1199 MediaBuffer* mb,
1200 media_track_type trackType,
1201 int64_t *actualTimeUs) {
1202 bool audio = trackType == MEDIA_TRACK_TYPE_AUDIO;
1203 size_t outLength = mb->range_length();
1204
1205 if (audio && mAudioIsVorbis) {
1206 outLength += sizeof(int32_t);
1207 }
1208
1209 sp<ABuffer> ab;
Chong Zhang42e81532014-12-01 13:44:26 -08001210 if (mIsSecure && !audio) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001211 // data is already provided in the buffer
1212 ab = new ABuffer(NULL, mb->range_length());
Robert Shih3423bbd2014-07-16 15:47:09 -07001213 mb->add_ref();
Wei Jia96e92b52014-09-18 17:36:20 -07001214 ab->setMediaBufferBase(mb);
Robert Shih3423bbd2014-07-16 15:47:09 -07001215 } else {
1216 ab = new ABuffer(outLength);
1217 memcpy(ab->data(),
1218 (const uint8_t *)mb->data() + mb->range_offset(),
1219 mb->range_length());
1220 }
1221
1222 if (audio && mAudioIsVorbis) {
1223 int32_t numPageSamples;
1224 if (!mb->meta_data()->findInt32(kKeyValidSamples, &numPageSamples)) {
1225 numPageSamples = -1;
1226 }
1227
1228 uint8_t* abEnd = ab->data() + mb->range_length();
1229 memcpy(abEnd, &numPageSamples, sizeof(numPageSamples));
1230 }
1231
Lajos Molnare26940f2014-07-31 10:31:26 -07001232 sp<AMessage> meta = ab->meta();
1233
Robert Shih3423bbd2014-07-16 15:47:09 -07001234 int64_t timeUs;
1235 CHECK(mb->meta_data()->findInt64(kKeyTime, &timeUs));
Robert Shih3423bbd2014-07-16 15:47:09 -07001236 meta->setInt64("timeUs", timeUs);
1237
Lajos Molnare26940f2014-07-31 10:31:26 -07001238 if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) {
1239 const char *mime;
1240 CHECK(mTimedTextTrack.mSource != NULL
1241 && mTimedTextTrack.mSource->getFormat()->findCString(kKeyMIMEType, &mime));
1242 meta->setString("mime", mime);
1243 }
1244
Robert Shih3423bbd2014-07-16 15:47:09 -07001245 int64_t durationUs;
1246 if (mb->meta_data()->findInt64(kKeyDuration, &durationUs)) {
1247 meta->setInt64("durationUs", durationUs);
1248 }
1249
1250 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
1251 meta->setInt32("trackIndex", mSubtitleTrack.mIndex);
1252 }
1253
1254 if (actualTimeUs) {
1255 *actualTimeUs = timeUs;
1256 }
1257
1258 mb->release();
1259 mb = NULL;
1260
1261 return ab;
1262}
1263
Robert Shih17f6dd62014-08-20 17:00:21 -07001264void NuPlayer::GenericSource::postReadBuffer(media_track_type trackType) {
Lajos Molnar84f52782014-09-11 10:01:55 -07001265 Mutex::Autolock _l(mReadBufferLock);
1266
1267 if ((mPendingReadBufferTypes & (1 << trackType)) == 0) {
1268 mPendingReadBufferTypes |= (1 << trackType);
1269 sp<AMessage> msg = new AMessage(kWhatReadBuffer, id());
1270 msg->setInt32("trackType", trackType);
1271 msg->post();
1272 }
Robert Shih17f6dd62014-08-20 17:00:21 -07001273}
1274
1275void NuPlayer::GenericSource::onReadBuffer(sp<AMessage> msg) {
1276 int32_t tmpType;
1277 CHECK(msg->findInt32("trackType", &tmpType));
1278 media_track_type trackType = (media_track_type)tmpType;
Chong Zhang42e81532014-12-01 13:44:26 -08001279 readBuffer(trackType);
Lajos Molnar84f52782014-09-11 10:01:55 -07001280 {
1281 // only protect the variable change, as readBuffer may
Chong Zhang42e81532014-12-01 13:44:26 -08001282 // take considerable time.
Lajos Molnar84f52782014-09-11 10:01:55 -07001283 Mutex::Autolock _l(mReadBufferLock);
1284 mPendingReadBufferTypes &= ~(1 << trackType);
1285 }
Robert Shih17f6dd62014-08-20 17:00:21 -07001286}
1287
Andreas Huberafed0e12011-09-20 15:39:58 -07001288void NuPlayer::GenericSource::readBuffer(
Robert Shih3423bbd2014-07-16 15:47:09 -07001289 media_track_type trackType, int64_t seekTimeUs, int64_t *actualTimeUs, bool formatChange) {
Andy Hung2abde2c2014-09-30 14:40:32 -07001290 // Do not read data if Widevine source is stopped
1291 if (mStopRead) {
1292 return;
1293 }
Robert Shih3423bbd2014-07-16 15:47:09 -07001294 Track *track;
Phil Burkc5cc2e22014-09-09 20:08:39 -07001295 size_t maxBuffers = 1;
Robert Shih3423bbd2014-07-16 15:47:09 -07001296 switch (trackType) {
1297 case MEDIA_TRACK_TYPE_VIDEO:
1298 track = &mVideoTrack;
Jeff Tinkera28785a2014-09-23 22:24:26 -07001299 if (mIsWidevine) {
1300 maxBuffers = 2;
1301 }
Robert Shih3423bbd2014-07-16 15:47:09 -07001302 break;
1303 case MEDIA_TRACK_TYPE_AUDIO:
1304 track = &mAudioTrack;
Jeff Tinkera28785a2014-09-23 22:24:26 -07001305 if (mIsWidevine) {
1306 maxBuffers = 8;
1307 } else {
1308 maxBuffers = 64;
1309 }
Robert Shih3423bbd2014-07-16 15:47:09 -07001310 break;
1311 case MEDIA_TRACK_TYPE_SUBTITLE:
1312 track = &mSubtitleTrack;
1313 break;
Lajos Molnare26940f2014-07-31 10:31:26 -07001314 case MEDIA_TRACK_TYPE_TIMEDTEXT:
1315 track = &mTimedTextTrack;
1316 break;
Robert Shih3423bbd2014-07-16 15:47:09 -07001317 default:
1318 TRESPASS();
1319 }
1320
1321 if (track->mSource == NULL) {
1322 return;
1323 }
Andreas Huberafed0e12011-09-20 15:39:58 -07001324
1325 if (actualTimeUs) {
1326 *actualTimeUs = seekTimeUs;
1327 }
1328
1329 MediaSource::ReadOptions options;
1330
1331 bool seeking = false;
1332
1333 if (seekTimeUs >= 0) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001334 options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
Andreas Huberafed0e12011-09-20 15:39:58 -07001335 seeking = true;
1336 }
1337
Chong Zhang42e81532014-12-01 13:44:26 -08001338 if (mIsWidevine) {
Lajos Molnarcc227032014-07-17 15:33:06 -07001339 options.setNonBlocking();
1340 }
1341
Phil Burkc5cc2e22014-09-09 20:08:39 -07001342 for (size_t numBuffers = 0; numBuffers < maxBuffers; ) {
Andreas Huberafed0e12011-09-20 15:39:58 -07001343 MediaBuffer *mbuf;
1344 status_t err = track->mSource->read(&mbuf, &options);
1345
1346 options.clearSeekTo();
1347
1348 if (err == OK) {
Ronghua Wu80276872014-08-28 15:50:29 -07001349 int64_t timeUs;
1350 CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs));
1351 if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
1352 mAudioTimeUs = timeUs;
1353 } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
1354 mVideoTimeUs = timeUs;
1355 }
1356
Robert Shih3423bbd2014-07-16 15:47:09 -07001357 // formatChange && seeking: track whose source is changed during selection
1358 // formatChange && !seeking: track whose source is not changed during selection
1359 // !formatChange: normal seek
Lajos Molnare26940f2014-07-31 10:31:26 -07001360 if ((seeking || formatChange)
1361 && (trackType == MEDIA_TRACK_TYPE_AUDIO
1362 || trackType == MEDIA_TRACK_TYPE_VIDEO)) {
Wei Jiafef808d2014-10-31 17:57:05 -07001363 ATSParser::DiscontinuityType type = (formatChange && seeking)
1364 ? ATSParser::DISCONTINUITY_FORMATCHANGE
1365 : ATSParser::DISCONTINUITY_NONE;
Robert Shih3423bbd2014-07-16 15:47:09 -07001366 track->mPackets->queueDiscontinuity( type, NULL, true /* discard */);
Andreas Huberafed0e12011-09-20 15:39:58 -07001367 }
1368
Robert Shih3423bbd2014-07-16 15:47:09 -07001369 sp<ABuffer> buffer = mediaBufferToABuffer(mbuf, trackType, actualTimeUs);
Andreas Huberafed0e12011-09-20 15:39:58 -07001370 track->mPackets->queueAccessUnit(buffer);
Marco Nelissen317a49a2014-09-16 21:32:33 -07001371 formatChange = false;
1372 seeking = false;
Phil Burkc5cc2e22014-09-09 20:08:39 -07001373 ++numBuffers;
Lajos Molnarcc227032014-07-17 15:33:06 -07001374 } else if (err == WOULD_BLOCK) {
1375 break;
Andreas Huberafed0e12011-09-20 15:39:58 -07001376 } else if (err == INFO_FORMAT_CHANGED) {
1377#if 0
1378 track->mPackets->queueDiscontinuity(
Chong Zhang632740c2014-06-26 13:03:47 -07001379 ATSParser::DISCONTINUITY_FORMATCHANGE,
1380 NULL,
1381 false /* discard */);
Andreas Huberafed0e12011-09-20 15:39:58 -07001382#endif
1383 } else {
1384 track->mPackets->signalEOS(err);
1385 break;
1386 }
1387 }
1388}
1389
Andreas Huberafed0e12011-09-20 15:39:58 -07001390} // namespace android