blob: cbc5e0d2e8840b994d7a4feacc069ab3c439f766 [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
Chong Zhangefbb6192015-01-30 17:13:27 -080043static int64_t kLowWaterMarkUs = 2000000ll; // 2secs
44static int64_t kHighWaterMarkUs = 5000000ll; // 5secs
45static const ssize_t kLowWaterMarkBytes = 40000;
46static const ssize_t kHighWaterMarkBytes = 200000;
47
Andreas Huberafed0e12011-09-20 15:39:58 -070048NuPlayer::GenericSource::GenericSource(
Andreas Huberb5f25f02013-02-05 10:14:26 -080049 const sp<AMessage> &notify,
Lajos Molnarcc227032014-07-17 15:33:06 -070050 bool uidValid,
51 uid_t uid)
Andreas Huberb5f25f02013-02-05 10:14:26 -080052 : Source(notify),
Robert Shih5c67ddc2014-11-04 17:46:05 -080053 mAudioTimeUs(0),
54 mAudioLastDequeueTimeUs(0),
55 mVideoTimeUs(0),
56 mVideoLastDequeueTimeUs(0),
Robert Shih3423bbd2014-07-16 15:47:09 -070057 mFetchSubtitleDataGeneration(0),
Lajos Molnare26940f2014-07-31 10:31:26 -070058 mFetchTimedTextDataGeneration(0),
Andreas Huberb5f25f02013-02-05 10:14:26 -080059 mDurationUs(0ll),
Lajos Molnarcc227032014-07-17 15:33:06 -070060 mAudioIsVorbis(false),
Chong Zhang3de157d2014-08-05 20:54:44 -070061 mIsWidevine(false),
Chong Zhang42e81532014-12-01 13:44:26 -080062 mIsSecure(false),
Chong Zhangefbb6192015-01-30 17:13:27 -080063 mIsStreaming(false),
Lajos Molnarcc227032014-07-17 15:33:06 -070064 mUIDValid(uidValid),
Chong Zhangd354d8d2014-08-20 13:09:58 -070065 mUID(uid),
Chong Zhanga6bf21f2014-11-19 20:26:34 -080066 mFd(-1),
Ronghua Wu80276872014-08-28 15:50:29 -070067 mDrmManagerClient(NULL),
Chong Zhang2a3cc9a2014-08-21 17:48:26 -070068 mMetaDataSize(-1ll),
69 mBitrate(-1ll),
Lajos Molnar84f52782014-09-11 10:01:55 -070070 mPollBufferingGeneration(0),
Chong Zhangefbb6192015-01-30 17:13:27 -080071 mPendingReadBufferTypes(0),
72 mBuffering(false),
73 mPrepareBuffering(false) {
Chong Zhanga19f33e2014-08-07 15:35:07 -070074 resetDataSource();
Andreas Huberafed0e12011-09-20 15:39:58 -070075 DataSource::RegisterDefaultSniffers();
Chong Zhang3de157d2014-08-05 20:54:44 -070076}
77
Chong Zhanga19f33e2014-08-07 15:35:07 -070078void NuPlayer::GenericSource::resetDataSource() {
79 mHTTPService.clear();
Robert Shih360d6d02014-09-29 14:42:35 -070080 mHttpSource.clear();
Chong Zhanga19f33e2014-08-07 15:35:07 -070081 mUri.clear();
82 mUriHeaders.clear();
Chong Zhanga6bf21f2014-11-19 20:26:34 -080083 if (mFd >= 0) {
84 close(mFd);
85 mFd = -1;
86 }
Chong Zhanga19f33e2014-08-07 15:35:07 -070087 mOffset = 0;
88 mLength = 0;
Ronghua Wu80276872014-08-28 15:50:29 -070089 setDrmPlaybackStatusIfNeeded(Playback::STOP, 0);
90 mDecryptHandle = NULL;
91 mDrmManagerClient = NULL;
92 mStarted = false;
Andy Hung2abde2c2014-09-30 14:40:32 -070093 mStopRead = true;
Chong Zhanga19f33e2014-08-07 15:35:07 -070094}
95
96status_t NuPlayer::GenericSource::setDataSource(
Chong Zhang3de157d2014-08-05 20:54:44 -070097 const sp<IMediaHTTPService> &httpService,
98 const char *url,
99 const KeyedVector<String8, String8> *headers) {
Chong Zhanga19f33e2014-08-07 15:35:07 -0700100 resetDataSource();
Chong Zhang3de157d2014-08-05 20:54:44 -0700101
Chong Zhanga19f33e2014-08-07 15:35:07 -0700102 mHTTPService = httpService;
103 mUri = url;
Andreas Huberafed0e12011-09-20 15:39:58 -0700104
Chong Zhanga19f33e2014-08-07 15:35:07 -0700105 if (headers) {
106 mUriHeaders = *headers;
Chong Zhang3de157d2014-08-05 20:54:44 -0700107 }
108
Chong Zhanga19f33e2014-08-07 15:35:07 -0700109 // delay data source creation to prepareAsync() to avoid blocking
110 // the calling thread in setDataSource for any significant time.
111 return OK;
Andreas Huberafed0e12011-09-20 15:39:58 -0700112}
113
Chong Zhanga19f33e2014-08-07 15:35:07 -0700114status_t NuPlayer::GenericSource::setDataSource(
Chong Zhang3de157d2014-08-05 20:54:44 -0700115 int fd, int64_t offset, int64_t length) {
Chong Zhanga19f33e2014-08-07 15:35:07 -0700116 resetDataSource();
Andreas Huberafed0e12011-09-20 15:39:58 -0700117
Chong Zhanga19f33e2014-08-07 15:35:07 -0700118 mFd = dup(fd);
119 mOffset = offset;
120 mLength = length;
121
122 // delay data source creation to prepareAsync() to avoid blocking
123 // the calling thread in setDataSource for any significant time.
124 return OK;
Andreas Huberafed0e12011-09-20 15:39:58 -0700125}
126
Marco Nelissenf0b72b52014-09-16 15:43:44 -0700127sp<MetaData> NuPlayer::GenericSource::getFileFormatMeta() const {
128 return mFileMeta;
129}
130
Chong Zhangd354d8d2014-08-20 13:09:58 -0700131status_t NuPlayer::GenericSource::initFromDataSource() {
Lajos Molnarcc227032014-07-17 15:33:06 -0700132 sp<MediaExtractor> extractor;
Chong Zhangfc6cfd82015-02-19 16:39:59 -0800133 String8 mimeType;
134 float confidence;
135 sp<AMessage> dummy;
136 bool isWidevineStreaming = false;
Lajos Molnarcc227032014-07-17 15:33:06 -0700137
Chong Zhangd354d8d2014-08-20 13:09:58 -0700138 CHECK(mDataSource != NULL);
139
Lajos Molnarcc227032014-07-17 15:33:06 -0700140 if (mIsWidevine) {
Chong Zhangfc6cfd82015-02-19 16:39:59 -0800141 isWidevineStreaming = SniffWVM(
142 mDataSource, &mimeType, &confidence, &dummy);
143 if (!isWidevineStreaming ||
144 strcasecmp(
Lajos Molnarcc227032014-07-17 15:33:06 -0700145 mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) {
146 ALOGE("unsupported widevine mime: %s", mimeType.string());
Chong Zhang3de157d2014-08-05 20:54:44 -0700147 return UNKNOWN_ERROR;
Lajos Molnarcc227032014-07-17 15:33:06 -0700148 }
Chong Zhangfc6cfd82015-02-19 16:39:59 -0800149 } else if (mIsStreaming) {
150 if (mSniffedMIME.empty()) {
151 if (!mDataSource->sniff(&mimeType, &confidence, &dummy)) {
152 return UNKNOWN_ERROR;
153 }
154 mSniffedMIME = mimeType.string();
155 }
156 isWidevineStreaming = !strcasecmp(
157 mSniffedMIME.c_str(), MEDIA_MIMETYPE_CONTAINER_WVM);
158 }
Lajos Molnarcc227032014-07-17 15:33:06 -0700159
Chong Zhangfc6cfd82015-02-19 16:39:59 -0800160 if (isWidevineStreaming) {
161 // we don't want cached source for widevine streaming.
162 mCachedSource.clear();
163 mDataSource = mHttpSource;
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700164 mWVMExtractor = new WVMExtractor(mDataSource);
165 mWVMExtractor->setAdaptiveStreamingMode(true);
Lajos Molnarcc227032014-07-17 15:33:06 -0700166 if (mUIDValid) {
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700167 mWVMExtractor->setUID(mUID);
Lajos Molnarcc227032014-07-17 15:33:06 -0700168 }
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700169 extractor = mWVMExtractor;
Lajos Molnarcc227032014-07-17 15:33:06 -0700170 } else {
Chong Zhangd354d8d2014-08-20 13:09:58 -0700171 extractor = MediaExtractor::Create(mDataSource,
172 mSniffedMIME.empty() ? NULL: mSniffedMIME.c_str());
Lajos Molnarcc227032014-07-17 15:33:06 -0700173 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700174
Chong Zhang3de157d2014-08-05 20:54:44 -0700175 if (extractor == NULL) {
176 return UNKNOWN_ERROR;
177 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700178
Ronghua Wu80276872014-08-28 15:50:29 -0700179 if (extractor->getDrmFlag()) {
180 checkDrmStatus(mDataSource);
181 }
182
Marco Nelissenf0b72b52014-09-16 15:43:44 -0700183 mFileMeta = extractor->getMetaData();
184 if (mFileMeta != NULL) {
Marco Nelissenc1f4b2b2014-06-17 14:48:32 -0700185 int64_t duration;
Marco Nelissenf0b72b52014-09-16 15:43:44 -0700186 if (mFileMeta->findInt64(kKeyDuration, &duration)) {
Marco Nelissenc1f4b2b2014-06-17 14:48:32 -0700187 mDurationUs = duration;
188 }
Chong Zhang42e81532014-12-01 13:44:26 -0800189
190 if (!mIsWidevine) {
191 // Check mime to see if we actually have a widevine source.
192 // If the data source is not URL-type (eg. file source), we
193 // won't be able to tell until now.
194 const char *fileMime;
195 if (mFileMeta->findCString(kKeyMIMEType, &fileMime)
196 && !strncasecmp(fileMime, "video/wvm", 9)) {
197 mIsWidevine = true;
198 }
199 }
Marco Nelissenc1f4b2b2014-06-17 14:48:32 -0700200 }
201
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700202 int32_t totalBitrate = 0;
203
Marco Nelissen705d3292014-09-19 15:14:37 -0700204 size_t numtracks = extractor->countTracks();
205 if (numtracks == 0) {
206 return UNKNOWN_ERROR;
207 }
208
209 for (size_t i = 0; i < numtracks; ++i) {
Chong Zhangafc0a872014-08-26 09:56:52 -0700210 sp<MediaSource> track = extractor->getTrack(i);
211
Andreas Huberafed0e12011-09-20 15:39:58 -0700212 sp<MetaData> meta = extractor->getTrackMetaData(i);
213
214 const char *mime;
215 CHECK(meta->findCString(kKeyMIMEType, &mime));
216
Chong Zhangafc0a872014-08-26 09:56:52 -0700217 // Do the string compare immediately with "mime",
218 // we can't assume "mime" would stay valid after another
219 // extractor operation, some extractors might modify meta
220 // during getTrack() and make it invalid.
Andreas Huberafed0e12011-09-20 15:39:58 -0700221 if (!strncasecmp(mime, "audio/", 6)) {
222 if (mAudioTrack.mSource == NULL) {
Robert Shihdd235722014-06-12 14:49:23 -0700223 mAudioTrack.mIndex = i;
224 mAudioTrack.mSource = track;
Robert Shihaf52c1a2014-09-11 15:38:54 -0700225 mAudioTrack.mPackets =
226 new AnotherPacketSource(mAudioTrack.mSource->getFormat());
Andreas Huberafed0e12011-09-20 15:39:58 -0700227
228 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
229 mAudioIsVorbis = true;
230 } else {
231 mAudioIsVorbis = false;
232 }
233 }
234 } else if (!strncasecmp(mime, "video/", 6)) {
235 if (mVideoTrack.mSource == NULL) {
Robert Shihdd235722014-06-12 14:49:23 -0700236 mVideoTrack.mIndex = i;
237 mVideoTrack.mSource = track;
Robert Shihaf52c1a2014-09-11 15:38:54 -0700238 mVideoTrack.mPackets =
239 new AnotherPacketSource(mVideoTrack.mSource->getFormat());
Chong Zhang7e892182014-08-05 11:58:21 -0700240
241 // check if the source requires secure buffers
242 int32_t secure;
Chong Zhanga19f33e2014-08-07 15:35:07 -0700243 if (meta->findInt32(kKeyRequiresSecureBuffers, &secure)
244 && secure) {
Chong Zhang42e81532014-12-01 13:44:26 -0800245 mIsSecure = true;
Chong Zhang3de157d2014-08-05 20:54:44 -0700246 if (mUIDValid) {
247 extractor->setUID(mUID);
248 }
Chong Zhang7e892182014-08-05 11:58:21 -0700249 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700250 }
251 }
252
253 if (track != NULL) {
Robert Shihdd235722014-06-12 14:49:23 -0700254 mSources.push(track);
Andreas Huberafed0e12011-09-20 15:39:58 -0700255 int64_t durationUs;
256 if (meta->findInt64(kKeyDuration, &durationUs)) {
257 if (durationUs > mDurationUs) {
258 mDurationUs = durationUs;
259 }
260 }
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700261
262 int32_t bitrate;
263 if (totalBitrate >= 0 && meta->findInt32(kKeyBitRate, &bitrate)) {
264 totalBitrate += bitrate;
265 } else {
266 totalBitrate = -1;
267 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700268 }
269 }
Chong Zhang3de157d2014-08-05 20:54:44 -0700270
Chong Zhangefbb6192015-01-30 17:13:27 -0800271 // Start the selected A/V tracks now before we start buffering.
272 // Widevine sources might re-initialize crypto when starting, if we delay
273 // this to start(), all data buffered during prepare would be wasted.
274 // (We don't actually start reading until start().)
275 if (mAudioTrack.mSource != NULL && mAudioTrack.mSource->start() != OK) {
276 ALOGE("failed to start audio track!");
277 return UNKNOWN_ERROR;
278 }
279
280 if (mVideoTrack.mSource != NULL && mVideoTrack.mSource->start() != OK) {
281 ALOGE("failed to start video track!");
282 return UNKNOWN_ERROR;
283 }
284
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700285 mBitrate = totalBitrate;
286
Chong Zhang3de157d2014-08-05 20:54:44 -0700287 return OK;
Andreas Huberafed0e12011-09-20 15:39:58 -0700288}
289
Ronghua Wu80276872014-08-28 15:50:29 -0700290void NuPlayer::GenericSource::checkDrmStatus(const sp<DataSource>& dataSource) {
291 dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
292 if (mDecryptHandle != NULL) {
293 CHECK(mDrmManagerClient);
294 if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
295 sp<AMessage> msg = dupNotify();
296 msg->setInt32("what", kWhatDrmNoLicense);
297 msg->post();
298 }
299 }
300}
301
302int64_t NuPlayer::GenericSource::getLastReadPosition() {
303 if (mAudioTrack.mSource != NULL) {
304 return mAudioTimeUs;
305 } else if (mVideoTrack.mSource != NULL) {
306 return mVideoTimeUs;
307 } else {
308 return 0;
309 }
310}
311
Chong Zhanga19f33e2014-08-07 15:35:07 -0700312status_t NuPlayer::GenericSource::setBuffers(
313 bool audio, Vector<MediaBuffer *> &buffers) {
Chong Zhang42e81532014-12-01 13:44:26 -0800314 if (mIsSecure && !audio) {
Lajos Molnarcc227032014-07-17 15:33:06 -0700315 return mVideoTrack.mSource->setBuffers(buffers);
316 }
317 return INVALID_OPERATION;
318}
319
Andreas Huberafed0e12011-09-20 15:39:58 -0700320NuPlayer::GenericSource::~GenericSource() {
Chong Zhang1228d6b2014-08-12 21:25:48 -0700321 if (mLooper != NULL) {
322 mLooper->unregisterHandler(id());
323 mLooper->stop();
324 }
Chong Zhanga6bf21f2014-11-19 20:26:34 -0800325 resetDataSource();
Andreas Huberafed0e12011-09-20 15:39:58 -0700326}
327
Andreas Huber9575c962013-02-05 13:59:56 -0800328void NuPlayer::GenericSource::prepareAsync() {
Chong Zhang1228d6b2014-08-12 21:25:48 -0700329 if (mLooper == NULL) {
330 mLooper = new ALooper;
331 mLooper->setName("generic");
332 mLooper->start();
333
334 mLooper->registerHandler(this);
335 }
336
337 sp<AMessage> msg = new AMessage(kWhatPrepareAsync, id());
338 msg->post();
339}
340
341void NuPlayer::GenericSource::onPrepareAsync() {
Chong Zhanga19f33e2014-08-07 15:35:07 -0700342 // delayed data source creation
Chong Zhangd354d8d2014-08-20 13:09:58 -0700343 if (mDataSource == NULL) {
Chong Zhang42e81532014-12-01 13:44:26 -0800344 // set to false first, if the extractor
345 // comes back as secure, set it to true then.
346 mIsSecure = false;
347
Chong Zhangd354d8d2014-08-20 13:09:58 -0700348 if (!mUri.empty()) {
Robert Shih360d6d02014-09-29 14:42:35 -0700349 const char* uri = mUri.c_str();
350 mIsWidevine = !strncasecmp(uri, "widevine://", 11);
351
352 if (!strncasecmp("http://", uri, 7)
353 || !strncasecmp("https://", uri, 8)
354 || mIsWidevine) {
355 mHttpSource = DataSource::CreateMediaHTTP(mHTTPService);
356 if (mHttpSource == NULL) {
357 ALOGE("Failed to create http source!");
358 notifyPreparedAndCleanup(UNKNOWN_ERROR);
359 return;
360 }
361 }
Chong Zhanga19f33e2014-08-07 15:35:07 -0700362
Chong Zhangd354d8d2014-08-20 13:09:58 -0700363 mDataSource = DataSource::CreateFromURI(
Robert Shih360d6d02014-09-29 14:42:35 -0700364 mHTTPService, uri, &mUriHeaders, &mContentType,
365 static_cast<HTTPBase *>(mHttpSource.get()));
Chong Zhangd354d8d2014-08-20 13:09:58 -0700366 } else {
Chong Zhangd354d8d2014-08-20 13:09:58 -0700367 mIsWidevine = false;
Chong Zhanga19f33e2014-08-07 15:35:07 -0700368
Chong Zhangd354d8d2014-08-20 13:09:58 -0700369 mDataSource = new FileSource(mFd, mOffset, mLength);
Chong Zhanga6bf21f2014-11-19 20:26:34 -0800370 mFd = -1;
Chong Zhangd354d8d2014-08-20 13:09:58 -0700371 }
Chong Zhanga19f33e2014-08-07 15:35:07 -0700372
Chong Zhangd354d8d2014-08-20 13:09:58 -0700373 if (mDataSource == NULL) {
374 ALOGE("Failed to create data source!");
375 notifyPreparedAndCleanup(UNKNOWN_ERROR);
376 return;
377 }
378
379 if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
380 mCachedSource = static_cast<NuCachedSource2 *>(mDataSource.get());
381 }
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700382
Chong Zhangefbb6192015-01-30 17:13:27 -0800383 // For widevine or other cached streaming cases, we need to wait for
384 // enough buffering before reporting prepared.
385 // Note that even when URL doesn't start with widevine://, mIsWidevine
386 // could still be set to true later, if the streaming or file source
387 // is sniffed to be widevine. We don't want to buffer for file source
388 // in that case, so must check the flag now.
389 mIsStreaming = (mIsWidevine || mCachedSource != NULL);
Chong Zhanga19f33e2014-08-07 15:35:07 -0700390 }
391
Chong Zhangd354d8d2014-08-20 13:09:58 -0700392 // check initial caching status
393 status_t err = prefillCacheIfNecessary();
394 if (err != OK) {
395 if (err == -EAGAIN) {
396 (new AMessage(kWhatPrepareAsync, id()))->post(200000);
397 } else {
398 ALOGE("Failed to prefill data cache!");
399 notifyPreparedAndCleanup(UNKNOWN_ERROR);
400 }
Chong Zhanga19f33e2014-08-07 15:35:07 -0700401 return;
402 }
403
Chong Zhangd354d8d2014-08-20 13:09:58 -0700404 // init extrator from data source
405 err = initFromDataSource();
Chong Zhanga19f33e2014-08-07 15:35:07 -0700406
407 if (err != OK) {
408 ALOGE("Failed to init from data source!");
Chong Zhangd354d8d2014-08-20 13:09:58 -0700409 notifyPreparedAndCleanup(err);
Chong Zhanga19f33e2014-08-07 15:35:07 -0700410 return;
411 }
412
Andreas Huber9575c962013-02-05 13:59:56 -0800413 if (mVideoTrack.mSource != NULL) {
Robert Shih17f6dd62014-08-20 17:00:21 -0700414 sp<MetaData> meta = doGetFormatMeta(false /* audio */);
415 sp<AMessage> msg = new AMessage;
416 err = convertMetaDataToMessage(meta, &msg);
417 if(err != OK) {
418 notifyPreparedAndCleanup(err);
419 return;
420 }
421 notifyVideoSizeChanged(msg);
Andreas Huber9575c962013-02-05 13:59:56 -0800422 }
423
424 notifyFlagsChanged(
Chong Zhang42e81532014-12-01 13:44:26 -0800425 (mIsSecure ? FLAG_SECURE : 0)
Chong Zhang17134602015-01-07 16:14:34 -0800426 | (mDecryptHandle != NULL ? FLAG_PROTECTED : 0)
Lajos Molnarcc227032014-07-17 15:33:06 -0700427 | FLAG_CAN_PAUSE
Andreas Huber9575c962013-02-05 13:59:56 -0800428 | FLAG_CAN_SEEK_BACKWARD
429 | FLAG_CAN_SEEK_FORWARD
430 | FLAG_CAN_SEEK);
431
Chong Zhangefbb6192015-01-30 17:13:27 -0800432 if (mIsStreaming) {
433 mPrepareBuffering = true;
434
435 ensureCacheIsFetching();
436 restartPollBuffering();
437 } else {
438 notifyPrepared();
439 }
Andreas Huber9575c962013-02-05 13:59:56 -0800440}
441
Chong Zhangd354d8d2014-08-20 13:09:58 -0700442void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) {
443 if (err != OK) {
444 mMetaDataSize = -1ll;
445 mContentType = "";
446 mSniffedMIME = "";
447 mDataSource.clear();
448 mCachedSource.clear();
Robert Shih360d6d02014-09-29 14:42:35 -0700449 mHttpSource.clear();
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700450
451 cancelPollBuffering();
Chong Zhangd354d8d2014-08-20 13:09:58 -0700452 }
453 notifyPrepared(err);
454}
455
456status_t NuPlayer::GenericSource::prefillCacheIfNecessary() {
457 CHECK(mDataSource != NULL);
458
459 if (mCachedSource == NULL) {
460 // no prefill if the data source is not cached
461 return OK;
462 }
463
464 // We're not doing this for streams that appear to be audio-only
465 // streams to ensure that even low bandwidth streams start
466 // playing back fairly instantly.
467 if (!strncasecmp(mContentType.string(), "audio/", 6)) {
468 return OK;
469 }
470
471 // We're going to prefill the cache before trying to instantiate
472 // the extractor below, as the latter is an operation that otherwise
473 // could block on the datasource for a significant amount of time.
474 // During that time we'd be unable to abort the preparation phase
475 // without this prefill.
476
477 // Initially make sure we have at least 192 KB for the sniff
478 // to complete without blocking.
479 static const size_t kMinBytesForSniffing = 192 * 1024;
480 static const size_t kDefaultMetaSize = 200000;
481
482 status_t finalStatus;
483
484 size_t cachedDataRemaining =
485 mCachedSource->approxDataRemaining(&finalStatus);
486
487 if (finalStatus != OK || (mMetaDataSize >= 0
488 && (off64_t)cachedDataRemaining >= mMetaDataSize)) {
489 ALOGV("stop caching, status %d, "
490 "metaDataSize %lld, cachedDataRemaining %zu",
491 finalStatus, mMetaDataSize, cachedDataRemaining);
492 return OK;
493 }
494
495 ALOGV("now cached %zu bytes of data", cachedDataRemaining);
496
497 if (mMetaDataSize < 0
498 && cachedDataRemaining >= kMinBytesForSniffing) {
499 String8 tmp;
500 float confidence;
501 sp<AMessage> meta;
502 if (!mCachedSource->sniff(&tmp, &confidence, &meta)) {
503 return UNKNOWN_ERROR;
504 }
505
506 // We successfully identified the file's extractor to
507 // be, remember this mime type so we don't have to
508 // sniff it again when we call MediaExtractor::Create()
509 mSniffedMIME = tmp.string();
510
511 if (meta == NULL
512 || !meta->findInt64("meta-data-size",
513 reinterpret_cast<int64_t*>(&mMetaDataSize))) {
514 mMetaDataSize = kDefaultMetaSize;
515 }
516
517 if (mMetaDataSize < 0ll) {
518 ALOGE("invalid metaDataSize = %lld bytes", mMetaDataSize);
519 return UNKNOWN_ERROR;
520 }
521 }
522
523 return -EAGAIN;
524}
525
Andreas Huberafed0e12011-09-20 15:39:58 -0700526void NuPlayer::GenericSource::start() {
527 ALOGI("start");
528
Andy Hung2abde2c2014-09-30 14:40:32 -0700529 mStopRead = false;
Andreas Huberafed0e12011-09-20 15:39:58 -0700530 if (mAudioTrack.mSource != NULL) {
Robert Shih17f6dd62014-08-20 17:00:21 -0700531 postReadBuffer(MEDIA_TRACK_TYPE_AUDIO);
Andreas Huberafed0e12011-09-20 15:39:58 -0700532 }
533
534 if (mVideoTrack.mSource != NULL) {
Robert Shih17f6dd62014-08-20 17:00:21 -0700535 postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
Andreas Huberafed0e12011-09-20 15:39:58 -0700536 }
Ronghua Wu80276872014-08-28 15:50:29 -0700537
538 setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000);
539 mStarted = true;
Chong Zhangefbb6192015-01-30 17:13:27 -0800540
541 (new AMessage(kWhatStart, id()))->post();
Ronghua Wu80276872014-08-28 15:50:29 -0700542}
543
544void NuPlayer::GenericSource::stop() {
545 // nothing to do, just account for DRM playback status
546 setDrmPlaybackStatusIfNeeded(Playback::STOP, 0);
547 mStarted = false;
Chong Zhang42e81532014-12-01 13:44:26 -0800548 if (mIsWidevine || mIsSecure) {
549 // For widevine or secure sources we need to prevent any further reads.
Andy Hung2abde2c2014-09-30 14:40:32 -0700550 sp<AMessage> msg = new AMessage(kWhatStopWidevine, id());
551 sp<AMessage> response;
552 (void) msg->postAndAwaitResponse(&response);
553 }
Ronghua Wu80276872014-08-28 15:50:29 -0700554}
555
556void NuPlayer::GenericSource::pause() {
557 // nothing to do, just account for DRM playback status
558 setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0);
559 mStarted = false;
560}
561
562void NuPlayer::GenericSource::resume() {
563 // nothing to do, just account for DRM playback status
564 setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000);
565 mStarted = true;
Chong Zhangefbb6192015-01-30 17:13:27 -0800566
567 (new AMessage(kWhatResume, id()))->post();
Ronghua Wu80276872014-08-28 15:50:29 -0700568}
569
Chong Zhang48296b72014-09-14 14:28:45 -0700570void NuPlayer::GenericSource::disconnect() {
571 if (mDataSource != NULL) {
572 // disconnect data source
573 if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
574 static_cast<NuCachedSource2 *>(mDataSource.get())->disconnect();
575 }
Robert Shih360d6d02014-09-29 14:42:35 -0700576 } else if (mHttpSource != NULL) {
577 static_cast<HTTPBase *>(mHttpSource.get())->disconnect();
Chong Zhang48296b72014-09-14 14:28:45 -0700578 }
579}
580
Ronghua Wu80276872014-08-28 15:50:29 -0700581void NuPlayer::GenericSource::setDrmPlaybackStatusIfNeeded(int playbackStatus, int64_t position) {
582 if (mDecryptHandle != NULL) {
583 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, playbackStatus, position);
584 }
Robert Shih17f6dd62014-08-20 17:00:21 -0700585 mSubtitleTrack.mPackets = new AnotherPacketSource(NULL);
586 mTimedTextTrack.mPackets = new AnotherPacketSource(NULL);
Andreas Huberafed0e12011-09-20 15:39:58 -0700587}
588
589status_t NuPlayer::GenericSource::feedMoreTSData() {
590 return OK;
591}
592
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700593void NuPlayer::GenericSource::schedulePollBuffering() {
594 sp<AMessage> msg = new AMessage(kWhatPollBuffering, id());
595 msg->setInt32("generation", mPollBufferingGeneration);
596 msg->post(1000000ll);
597}
598
599void NuPlayer::GenericSource::cancelPollBuffering() {
Chong Zhangefbb6192015-01-30 17:13:27 -0800600 mBuffering = false;
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700601 ++mPollBufferingGeneration;
602}
603
Chong Zhangefbb6192015-01-30 17:13:27 -0800604void NuPlayer::GenericSource::restartPollBuffering() {
605 if (mIsStreaming) {
606 cancelPollBuffering();
607 onPollBuffering();
608 }
609}
610
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700611void NuPlayer::GenericSource::notifyBufferingUpdate(int percentage) {
Chong Zhangefbb6192015-01-30 17:13:27 -0800612 ALOGV("notifyBufferingUpdate: buffering %d%%", percentage);
613
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700614 sp<AMessage> msg = dupNotify();
615 msg->setInt32("what", kWhatBufferingUpdate);
616 msg->setInt32("percentage", percentage);
617 msg->post();
618}
619
Chong Zhangefbb6192015-01-30 17:13:27 -0800620void NuPlayer::GenericSource::startBufferingIfNecessary() {
621 ALOGV("startBufferingIfNecessary: mPrepareBuffering=%d, mBuffering=%d",
622 mPrepareBuffering, mBuffering);
623
624 if (mPrepareBuffering) {
625 return;
626 }
627
628 if (!mBuffering) {
629 mBuffering = true;
630
631 ensureCacheIsFetching();
632 sendCacheStats();
633
634 sp<AMessage> notify = dupNotify();
635 notify->setInt32("what", kWhatPauseOnBufferingStart);
636 notify->post();
637 }
638}
639
640void NuPlayer::GenericSource::stopBufferingIfNecessary() {
641 ALOGV("stopBufferingIfNecessary: mPrepareBuffering=%d, mBuffering=%d",
642 mPrepareBuffering, mBuffering);
643
644 if (mPrepareBuffering) {
645 mPrepareBuffering = false;
646 notifyPrepared();
647 return;
648 }
649
650 if (mBuffering) {
651 mBuffering = false;
652
653 sendCacheStats();
654
655 sp<AMessage> notify = dupNotify();
656 notify->setInt32("what", kWhatResumeOnBufferingEnd);
657 notify->post();
658 }
659}
660
661void NuPlayer::GenericSource::sendCacheStats() {
662 int32_t kbps = 0;
663 status_t err = UNKNOWN_ERROR;
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700664
Chong Zhangfc6cfd82015-02-19 16:39:59 -0800665 if (mWVMExtractor != NULL) {
Chong Zhangefbb6192015-01-30 17:13:27 -0800666 err = mWVMExtractor->getEstimatedBandwidthKbps(&kbps);
Chong Zhangfc6cfd82015-02-19 16:39:59 -0800667 } else if (mCachedSource != NULL) {
668 err = mCachedSource->getEstimatedBandwidthKbps(&kbps);
Chong Zhangefbb6192015-01-30 17:13:27 -0800669 }
670
671 if (err == OK) {
672 sp<AMessage> notify = dupNotify();
673 notify->setInt32("what", kWhatCacheStats);
674 notify->setInt32("bandwidth", kbps);
675 notify->post();
676 }
677}
678
679void NuPlayer::GenericSource::ensureCacheIsFetching() {
680 if (mCachedSource != NULL) {
681 mCachedSource->resumeFetchingIfNecessary();
682 }
683}
684
685void NuPlayer::GenericSource::onPollBuffering() {
686 status_t finalStatus = UNKNOWN_ERROR;
687 int64_t cachedDurationUs = -1ll;
688 ssize_t cachedDataRemaining = -1;
689
Chong Zhangfc6cfd82015-02-19 16:39:59 -0800690 ALOGW_IF(mWVMExtractor != NULL && mCachedSource != NULL,
691 "WVMExtractor and NuCachedSource both present");
692
693 if (mWVMExtractor != NULL) {
694 cachedDurationUs =
695 mWVMExtractor->getCachedDurationUs(&finalStatus);
696 } else if (mCachedSource != NULL) {
Chong Zhangefbb6192015-01-30 17:13:27 -0800697 cachedDataRemaining =
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700698 mCachedSource->approxDataRemaining(&finalStatus);
699
700 if (finalStatus == OK) {
701 off64_t size;
702 int64_t bitrate = 0ll;
703 if (mDurationUs > 0 && mCachedSource->getSize(&size) == OK) {
704 bitrate = size * 8000000ll / mDurationUs;
705 } else if (mBitrate > 0) {
706 bitrate = mBitrate;
707 }
708 if (bitrate > 0) {
709 cachedDurationUs = cachedDataRemaining * 8000000ll / bitrate;
710 }
711 }
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700712 }
713
Chong Zhangefbb6192015-01-30 17:13:27 -0800714 if (finalStatus != OK) {
715 ALOGV("onPollBuffering: EOS (finalStatus = %d)", finalStatus);
716
717 if (finalStatus == ERROR_END_OF_STREAM) {
718 notifyBufferingUpdate(100);
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700719 }
720
Chong Zhangefbb6192015-01-30 17:13:27 -0800721 stopBufferingIfNecessary();
722 return;
723 } else if (cachedDurationUs >= 0ll) {
724 if (mDurationUs > 0ll) {
725 int64_t cachedPosUs = getLastReadPosition() + cachedDurationUs;
726 int percentage = 100.0 * cachedPosUs / mDurationUs;
727 if (percentage > 100) {
728 percentage = 100;
729 }
730
731 notifyBufferingUpdate(percentage);
732 }
733
734 ALOGV("onPollBuffering: cachedDurationUs %.1f sec",
735 cachedDurationUs / 1000000.0f);
736
737 if (cachedDurationUs < kLowWaterMarkUs) {
738 startBufferingIfNecessary();
739 } else if (cachedDurationUs > kHighWaterMarkUs) {
740 stopBufferingIfNecessary();
741 }
742 } else if (cachedDataRemaining >= 0) {
743 ALOGV("onPollBuffering: cachedDataRemaining %d bytes",
744 cachedDataRemaining);
745
746 if (cachedDataRemaining < kLowWaterMarkBytes) {
747 startBufferingIfNecessary();
748 } else if (cachedDataRemaining > kHighWaterMarkBytes) {
749 stopBufferingIfNecessary();
750 }
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700751 }
752
753 schedulePollBuffering();
754}
755
Robert Shih3423bbd2014-07-16 15:47:09 -0700756void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) {
757 switch (msg->what()) {
Chong Zhang1228d6b2014-08-12 21:25:48 -0700758 case kWhatPrepareAsync:
759 {
760 onPrepareAsync();
761 break;
762 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700763 case kWhatFetchSubtitleData:
764 {
Lajos Molnare26940f2014-07-31 10:31:26 -0700765 fetchTextData(kWhatSendSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
766 mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
767 break;
768 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700769
Lajos Molnare26940f2014-07-31 10:31:26 -0700770 case kWhatFetchTimedTextData:
771 {
772 fetchTextData(kWhatSendTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
773 mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
Robert Shih3423bbd2014-07-16 15:47:09 -0700774 break;
775 }
776
777 case kWhatSendSubtitleData:
778 {
Lajos Molnare26940f2014-07-31 10:31:26 -0700779 sendTextData(kWhatSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
780 mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
781 break;
782 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700783
Lajos Molnare26940f2014-07-31 10:31:26 -0700784 case kWhatSendTimedTextData:
785 {
786 sendTextData(kWhatTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
787 mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
Robert Shih3423bbd2014-07-16 15:47:09 -0700788 break;
789 }
790
791 case kWhatChangeAVSource:
792 {
793 int32_t trackIndex;
794 CHECK(msg->findInt32("trackIndex", &trackIndex));
795 const sp<MediaSource> source = mSources.itemAt(trackIndex);
796
797 Track* track;
798 const char *mime;
799 media_track_type trackType, counterpartType;
800 sp<MetaData> meta = source->getFormat();
801 meta->findCString(kKeyMIMEType, &mime);
802 if (!strncasecmp(mime, "audio/", 6)) {
803 track = &mAudioTrack;
804 trackType = MEDIA_TRACK_TYPE_AUDIO;
805 counterpartType = MEDIA_TRACK_TYPE_VIDEO;;
806 } else {
807 CHECK(!strncasecmp(mime, "video/", 6));
808 track = &mVideoTrack;
809 trackType = MEDIA_TRACK_TYPE_VIDEO;
810 counterpartType = MEDIA_TRACK_TYPE_AUDIO;;
811 }
812
813
814 if (track->mSource != NULL) {
815 track->mSource->stop();
816 }
817 track->mSource = source;
818 track->mSource->start();
819 track->mIndex = trackIndex;
820
Robert Shih3423bbd2014-07-16 15:47:09 -0700821 int64_t timeUs, actualTimeUs;
822 const bool formatChange = true;
Robert Shih5c67ddc2014-11-04 17:46:05 -0800823 if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
824 timeUs = mAudioLastDequeueTimeUs;
825 } else {
826 timeUs = mVideoLastDequeueTimeUs;
827 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700828 readBuffer(trackType, timeUs, &actualTimeUs, formatChange);
829 readBuffer(counterpartType, -1, NULL, formatChange);
830 ALOGV("timeUs %lld actualTimeUs %lld", timeUs, actualTimeUs);
831
832 break;
833 }
Chong Zhangefbb6192015-01-30 17:13:27 -0800834
835 case kWhatStart:
836 case kWhatResume:
837 {
838 restartPollBuffering();
839 break;
840 }
841
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700842 case kWhatPollBuffering:
843 {
844 int32_t generation;
845 CHECK(msg->findInt32("generation", &generation));
846 if (generation == mPollBufferingGeneration) {
847 onPollBuffering();
848 }
849 break;
850 }
Robert Shih17f6dd62014-08-20 17:00:21 -0700851
852 case kWhatGetFormat:
853 {
854 onGetFormatMeta(msg);
855 break;
856 }
857
858 case kWhatGetSelectedTrack:
859 {
860 onGetSelectedTrack(msg);
861 break;
862 }
863
864 case kWhatSelectTrack:
865 {
866 onSelectTrack(msg);
867 break;
868 }
869
870 case kWhatSeek:
871 {
872 onSeek(msg);
873 break;
874 }
875
876 case kWhatReadBuffer:
877 {
878 onReadBuffer(msg);
879 break;
880 }
881
Andy Hung2abde2c2014-09-30 14:40:32 -0700882 case kWhatStopWidevine:
883 {
884 // mStopRead is only used for Widevine to prevent the video source
885 // from being read while the associated video decoder is shutting down.
886 mStopRead = true;
887 if (mVideoTrack.mSource != NULL) {
888 mVideoTrack.mPackets->clear();
889 }
890 sp<AMessage> response = new AMessage;
891 uint32_t replyID;
892 CHECK(msg->senderAwaitsResponse(&replyID));
893 response->postReply(replyID);
894 break;
895 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700896 default:
897 Source::onMessageReceived(msg);
898 break;
899 }
900}
901
Lajos Molnare26940f2014-07-31 10:31:26 -0700902void NuPlayer::GenericSource::fetchTextData(
903 uint32_t sendWhat,
904 media_track_type type,
905 int32_t curGen,
906 sp<AnotherPacketSource> packets,
907 sp<AMessage> msg) {
908 int32_t msgGeneration;
909 CHECK(msg->findInt32("generation", &msgGeneration));
910 if (msgGeneration != curGen) {
911 // stale
912 return;
913 }
914
915 int32_t avail;
916 if (packets->hasBufferAvailable(&avail)) {
917 return;
918 }
919
920 int64_t timeUs;
921 CHECK(msg->findInt64("timeUs", &timeUs));
922
923 int64_t subTimeUs;
924 readBuffer(type, timeUs, &subTimeUs);
925
926 int64_t delayUs = subTimeUs - timeUs;
927 if (msg->what() == kWhatFetchSubtitleData) {
928 const int64_t oneSecUs = 1000000ll;
929 delayUs -= oneSecUs;
930 }
931 sp<AMessage> msg2 = new AMessage(sendWhat, id());
932 msg2->setInt32("generation", msgGeneration);
933 msg2->post(delayUs < 0 ? 0 : delayUs);
934}
935
936void NuPlayer::GenericSource::sendTextData(
937 uint32_t what,
938 media_track_type type,
939 int32_t curGen,
940 sp<AnotherPacketSource> packets,
941 sp<AMessage> msg) {
942 int32_t msgGeneration;
943 CHECK(msg->findInt32("generation", &msgGeneration));
944 if (msgGeneration != curGen) {
945 // stale
946 return;
947 }
948
949 int64_t subTimeUs;
950 if (packets->nextBufferTime(&subTimeUs) != OK) {
951 return;
952 }
953
954 int64_t nextSubTimeUs;
955 readBuffer(type, -1, &nextSubTimeUs);
956
957 sp<ABuffer> buffer;
958 status_t dequeueStatus = packets->dequeueAccessUnit(&buffer);
959 if (dequeueStatus == OK) {
960 sp<AMessage> notify = dupNotify();
961 notify->setInt32("what", what);
962 notify->setBuffer("buffer", buffer);
963 notify->post();
964
965 const int64_t delayUs = nextSubTimeUs - subTimeUs;
966 msg->post(delayUs < 0 ? 0 : delayUs);
967 }
968}
969
Andreas Huber84066782011-08-16 09:34:26 -0700970sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
Robert Shih17f6dd62014-08-20 17:00:21 -0700971 sp<AMessage> msg = new AMessage(kWhatGetFormat, id());
972 msg->setInt32("audio", audio);
973
974 sp<AMessage> response;
975 void *format;
976 status_t err = msg->postAndAwaitResponse(&response);
977 if (err == OK && response != NULL) {
978 CHECK(response->findPointer("format", &format));
979 return (MetaData *)format;
980 } else {
981 return NULL;
982 }
983}
984
985void NuPlayer::GenericSource::onGetFormatMeta(sp<AMessage> msg) const {
986 int32_t audio;
987 CHECK(msg->findInt32("audio", &audio));
988
989 sp<AMessage> response = new AMessage;
990 sp<MetaData> format = doGetFormatMeta(audio);
991 response->setPointer("format", format.get());
992
993 uint32_t replyID;
994 CHECK(msg->senderAwaitsResponse(&replyID));
995 response->postReply(replyID);
996}
997
998sp<MetaData> NuPlayer::GenericSource::doGetFormatMeta(bool audio) const {
Andreas Huberafed0e12011-09-20 15:39:58 -0700999 sp<MediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
1000
1001 if (source == NULL) {
1002 return NULL;
1003 }
1004
1005 return source->getFormat();
1006}
1007
1008status_t NuPlayer::GenericSource::dequeueAccessUnit(
1009 bool audio, sp<ABuffer> *accessUnit) {
1010 Track *track = audio ? &mAudioTrack : &mVideoTrack;
1011
1012 if (track->mSource == NULL) {
1013 return -EWOULDBLOCK;
1014 }
1015
Lajos Molnarcc227032014-07-17 15:33:06 -07001016 if (mIsWidevine && !audio) {
1017 // try to read a buffer as we may not have been able to the last time
Robert Shih17f6dd62014-08-20 17:00:21 -07001018 postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
Lajos Molnarcc227032014-07-17 15:33:06 -07001019 }
1020
Andreas Huberafed0e12011-09-20 15:39:58 -07001021 status_t finalResult;
1022 if (!track->mPackets->hasBufferAvailable(&finalResult)) {
Chong Zhang42e81532014-12-01 13:44:26 -08001023 if (finalResult == OK) {
1024 postReadBuffer(
1025 audio ? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
1026 return -EWOULDBLOCK;
1027 }
1028 return finalResult;
Andreas Huberafed0e12011-09-20 15:39:58 -07001029 }
1030
1031 status_t result = track->mPackets->dequeueAccessUnit(accessUnit);
1032
Robert Shih3423bbd2014-07-16 15:47:09 -07001033 if (!track->mPackets->hasBufferAvailable(&finalResult)) {
Robert Shih17f6dd62014-08-20 17:00:21 -07001034 postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
Lajos Molnare26940f2014-07-31 10:31:26 -07001035 }
1036
Robert Shih3423bbd2014-07-16 15:47:09 -07001037 if (result != OK) {
Lajos Molnare26940f2014-07-31 10:31:26 -07001038 if (mSubtitleTrack.mSource != NULL) {
1039 mSubtitleTrack.mPackets->clear();
1040 mFetchSubtitleDataGeneration++;
1041 }
1042 if (mTimedTextTrack.mSource != NULL) {
1043 mTimedTextTrack.mPackets->clear();
1044 mFetchTimedTextDataGeneration++;
1045 }
Robert Shih3423bbd2014-07-16 15:47:09 -07001046 return result;
1047 }
1048
1049 int64_t timeUs;
1050 status_t eosResult; // ignored
1051 CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs));
Robert Shih5c67ddc2014-11-04 17:46:05 -08001052 if (audio) {
1053 mAudioLastDequeueTimeUs = timeUs;
1054 } else {
1055 mVideoLastDequeueTimeUs = timeUs;
1056 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001057
1058 if (mSubtitleTrack.mSource != NULL
1059 && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001060 sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, id());
1061 msg->setInt64("timeUs", timeUs);
1062 msg->setInt32("generation", mFetchSubtitleDataGeneration);
1063 msg->post();
1064 }
Robert Shiheb1735e2014-07-23 15:53:14 -07001065
Lajos Molnare26940f2014-07-31 10:31:26 -07001066 if (mTimedTextTrack.mSource != NULL
1067 && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
1068 sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, id());
1069 msg->setInt64("timeUs", timeUs);
1070 msg->setInt32("generation", mFetchTimedTextDataGeneration);
1071 msg->post();
1072 }
1073
Andreas Huberafed0e12011-09-20 15:39:58 -07001074 return result;
1075}
1076
1077status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) {
1078 *durationUs = mDurationUs;
1079 return OK;
1080}
1081
Robert Shihdd235722014-06-12 14:49:23 -07001082size_t NuPlayer::GenericSource::getTrackCount() const {
1083 return mSources.size();
1084}
1085
1086sp<AMessage> NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const {
1087 size_t trackCount = mSources.size();
1088 if (trackIndex >= trackCount) {
1089 return NULL;
1090 }
1091
1092 sp<AMessage> format = new AMessage();
1093 sp<MetaData> meta = mSources.itemAt(trackIndex)->getFormat();
1094
1095 const char *mime;
1096 CHECK(meta->findCString(kKeyMIMEType, &mime));
1097
1098 int32_t trackType;
1099 if (!strncasecmp(mime, "video/", 6)) {
1100 trackType = MEDIA_TRACK_TYPE_VIDEO;
1101 } else if (!strncasecmp(mime, "audio/", 6)) {
1102 trackType = MEDIA_TRACK_TYPE_AUDIO;
1103 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
1104 trackType = MEDIA_TRACK_TYPE_TIMEDTEXT;
1105 } else {
1106 trackType = MEDIA_TRACK_TYPE_UNKNOWN;
1107 }
1108 format->setInt32("type", trackType);
1109
1110 const char *lang;
1111 if (!meta->findCString(kKeyMediaLanguage, &lang)) {
1112 lang = "und";
1113 }
1114 format->setString("language", lang);
1115
1116 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
1117 format->setString("mime", mime);
1118
1119 int32_t isAutoselect = 1, isDefault = 0, isForced = 0;
1120 meta->findInt32(kKeyTrackIsAutoselect, &isAutoselect);
1121 meta->findInt32(kKeyTrackIsDefault, &isDefault);
1122 meta->findInt32(kKeyTrackIsForced, &isForced);
1123
1124 format->setInt32("auto", !!isAutoselect);
1125 format->setInt32("default", !!isDefault);
1126 format->setInt32("forced", !!isForced);
1127 }
1128
1129 return format;
1130}
1131
Lajos Molnare26940f2014-07-31 10:31:26 -07001132ssize_t NuPlayer::GenericSource::getSelectedTrack(media_track_type type) const {
Robert Shih17f6dd62014-08-20 17:00:21 -07001133 sp<AMessage> msg = new AMessage(kWhatGetSelectedTrack, id());
1134 msg->setInt32("type", type);
1135
1136 sp<AMessage> response;
1137 int32_t index;
1138 status_t err = msg->postAndAwaitResponse(&response);
1139 if (err == OK && response != NULL) {
1140 CHECK(response->findInt32("index", &index));
1141 return index;
1142 } else {
1143 return -1;
1144 }
1145}
1146
1147void NuPlayer::GenericSource::onGetSelectedTrack(sp<AMessage> msg) const {
1148 int32_t tmpType;
1149 CHECK(msg->findInt32("type", &tmpType));
1150 media_track_type type = (media_track_type)tmpType;
1151
1152 sp<AMessage> response = new AMessage;
1153 ssize_t index = doGetSelectedTrack(type);
1154 response->setInt32("index", index);
1155
1156 uint32_t replyID;
1157 CHECK(msg->senderAwaitsResponse(&replyID));
1158 response->postReply(replyID);
1159}
1160
1161ssize_t NuPlayer::GenericSource::doGetSelectedTrack(media_track_type type) const {
Lajos Molnare26940f2014-07-31 10:31:26 -07001162 const Track *track = NULL;
1163 switch (type) {
1164 case MEDIA_TRACK_TYPE_VIDEO:
1165 track = &mVideoTrack;
1166 break;
1167 case MEDIA_TRACK_TYPE_AUDIO:
1168 track = &mAudioTrack;
1169 break;
1170 case MEDIA_TRACK_TYPE_TIMEDTEXT:
1171 track = &mTimedTextTrack;
1172 break;
1173 case MEDIA_TRACK_TYPE_SUBTITLE:
1174 track = &mSubtitleTrack;
1175 break;
1176 default:
1177 break;
1178 }
1179
1180 if (track != NULL && track->mSource != NULL) {
1181 return track->mIndex;
1182 }
1183
1184 return -1;
1185}
1186
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001187status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select, int64_t timeUs) {
Lajos Molnare26940f2014-07-31 10:31:26 -07001188 ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex);
Robert Shih17f6dd62014-08-20 17:00:21 -07001189 sp<AMessage> msg = new AMessage(kWhatSelectTrack, id());
1190 msg->setInt32("trackIndex", trackIndex);
Robert Shihda23ab92014-09-16 11:34:08 -07001191 msg->setInt32("select", select);
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001192 msg->setInt64("timeUs", timeUs);
Robert Shih17f6dd62014-08-20 17:00:21 -07001193
1194 sp<AMessage> response;
1195 status_t err = msg->postAndAwaitResponse(&response);
1196 if (err == OK && response != NULL) {
1197 CHECK(response->findInt32("err", &err));
1198 }
1199
1200 return err;
1201}
1202
1203void NuPlayer::GenericSource::onSelectTrack(sp<AMessage> msg) {
1204 int32_t trackIndex, select;
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001205 int64_t timeUs;
Robert Shih17f6dd62014-08-20 17:00:21 -07001206 CHECK(msg->findInt32("trackIndex", &trackIndex));
1207 CHECK(msg->findInt32("select", &select));
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001208 CHECK(msg->findInt64("timeUs", &timeUs));
Robert Shih17f6dd62014-08-20 17:00:21 -07001209
1210 sp<AMessage> response = new AMessage;
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001211 status_t err = doSelectTrack(trackIndex, select, timeUs);
Robert Shih17f6dd62014-08-20 17:00:21 -07001212 response->setInt32("err", err);
1213
1214 uint32_t replyID;
1215 CHECK(msg->senderAwaitsResponse(&replyID));
1216 response->postReply(replyID);
1217}
1218
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001219status_t NuPlayer::GenericSource::doSelectTrack(size_t trackIndex, bool select, int64_t timeUs) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001220 if (trackIndex >= mSources.size()) {
1221 return BAD_INDEX;
1222 }
1223
1224 if (!select) {
Lajos Molnare26940f2014-07-31 10:31:26 -07001225 Track* track = NULL;
1226 if (mSubtitleTrack.mSource != NULL && trackIndex == mSubtitleTrack.mIndex) {
1227 track = &mSubtitleTrack;
1228 mFetchSubtitleDataGeneration++;
1229 } else if (mTimedTextTrack.mSource != NULL && trackIndex == mTimedTextTrack.mIndex) {
1230 track = &mTimedTextTrack;
1231 mFetchTimedTextDataGeneration++;
1232 }
1233 if (track == NULL) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001234 return INVALID_OPERATION;
1235 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001236 track->mSource->stop();
1237 track->mSource = NULL;
1238 track->mPackets->clear();
Robert Shih3423bbd2014-07-16 15:47:09 -07001239 return OK;
1240 }
1241
1242 const sp<MediaSource> source = mSources.itemAt(trackIndex);
1243 sp<MetaData> meta = source->getFormat();
1244 const char *mime;
1245 CHECK(meta->findCString(kKeyMIMEType, &mime));
1246 if (!strncasecmp(mime, "text/", 5)) {
Lajos Molnare26940f2014-07-31 10:31:26 -07001247 bool isSubtitle = strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP);
1248 Track *track = isSubtitle ? &mSubtitleTrack : &mTimedTextTrack;
1249 if (track->mSource != NULL && track->mIndex == trackIndex) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001250 return OK;
1251 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001252 track->mIndex = trackIndex;
1253 if (track->mSource != NULL) {
1254 track->mSource->stop();
Robert Shih3423bbd2014-07-16 15:47:09 -07001255 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001256 track->mSource = mSources.itemAt(trackIndex);
1257 track->mSource->start();
1258 if (track->mPackets == NULL) {
1259 track->mPackets = new AnotherPacketSource(track->mSource->getFormat());
Robert Shih3423bbd2014-07-16 15:47:09 -07001260 } else {
Lajos Molnare26940f2014-07-31 10:31:26 -07001261 track->mPackets->clear();
1262 track->mPackets->setFormat(track->mSource->getFormat());
Robert Shih3423bbd2014-07-16 15:47:09 -07001263
1264 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001265
1266 if (isSubtitle) {
1267 mFetchSubtitleDataGeneration++;
1268 } else {
1269 mFetchTimedTextDataGeneration++;
1270 }
1271
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001272 status_t eosResult; // ignored
1273 if (mSubtitleTrack.mSource != NULL
1274 && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
1275 sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, id());
1276 msg->setInt64("timeUs", timeUs);
1277 msg->setInt32("generation", mFetchSubtitleDataGeneration);
1278 msg->post();
1279 }
1280
1281 if (mTimedTextTrack.mSource != NULL
1282 && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
1283 sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, id());
1284 msg->setInt64("timeUs", timeUs);
1285 msg->setInt32("generation", mFetchTimedTextDataGeneration);
1286 msg->post();
1287 }
1288
Robert Shih3423bbd2014-07-16 15:47:09 -07001289 return OK;
1290 } else if (!strncasecmp(mime, "audio/", 6) || !strncasecmp(mime, "video/", 6)) {
1291 bool audio = !strncasecmp(mime, "audio/", 6);
1292 Track *track = audio ? &mAudioTrack : &mVideoTrack;
1293 if (track->mSource != NULL && track->mIndex == trackIndex) {
1294 return OK;
1295 }
1296
1297 sp<AMessage> msg = new AMessage(kWhatChangeAVSource, id());
1298 msg->setInt32("trackIndex", trackIndex);
1299 msg->post();
1300 return OK;
1301 }
1302
1303 return INVALID_OPERATION;
1304}
1305
Andreas Huberafed0e12011-09-20 15:39:58 -07001306status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) {
Robert Shih17f6dd62014-08-20 17:00:21 -07001307 sp<AMessage> msg = new AMessage(kWhatSeek, id());
1308 msg->setInt64("seekTimeUs", seekTimeUs);
1309
1310 sp<AMessage> response;
1311 status_t err = msg->postAndAwaitResponse(&response);
1312 if (err == OK && response != NULL) {
1313 CHECK(response->findInt32("err", &err));
1314 }
1315
1316 return err;
1317}
1318
1319void NuPlayer::GenericSource::onSeek(sp<AMessage> msg) {
1320 int64_t seekTimeUs;
1321 CHECK(msg->findInt64("seekTimeUs", &seekTimeUs));
1322
1323 sp<AMessage> response = new AMessage;
1324 status_t err = doSeek(seekTimeUs);
1325 response->setInt32("err", err);
1326
1327 uint32_t replyID;
1328 CHECK(msg->senderAwaitsResponse(&replyID));
1329 response->postReply(replyID);
1330}
1331
1332status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs) {
Andy Hung2abde2c2014-09-30 14:40:32 -07001333 // If the Widevine source is stopped, do not attempt to read any
1334 // more buffers.
1335 if (mStopRead) {
1336 return INVALID_OPERATION;
1337 }
Andreas Huberafed0e12011-09-20 15:39:58 -07001338 if (mVideoTrack.mSource != NULL) {
1339 int64_t actualTimeUs;
Robert Shih3423bbd2014-07-16 15:47:09 -07001340 readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, &actualTimeUs);
Andreas Huberafed0e12011-09-20 15:39:58 -07001341
1342 seekTimeUs = actualTimeUs;
Robert Shih5c67ddc2014-11-04 17:46:05 -08001343 mVideoLastDequeueTimeUs = seekTimeUs;
Andreas Huberafed0e12011-09-20 15:39:58 -07001344 }
1345
1346 if (mAudioTrack.mSource != NULL) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001347 readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs);
Robert Shih5c67ddc2014-11-04 17:46:05 -08001348 mAudioLastDequeueTimeUs = seekTimeUs;
Andreas Huberafed0e12011-09-20 15:39:58 -07001349 }
1350
Ronghua Wu80276872014-08-28 15:50:29 -07001351 setDrmPlaybackStatusIfNeeded(Playback::START, seekTimeUs / 1000);
1352 if (!mStarted) {
1353 setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0);
1354 }
Chong Zhangefbb6192015-01-30 17:13:27 -08001355
1356 // If currently buffering, post kWhatBufferingEnd first, so that
1357 // NuPlayer resumes. Otherwise, if cache hits high watermark
1358 // before new polling happens, no one will resume the playback.
1359 stopBufferingIfNecessary();
1360 restartPollBuffering();
1361
Andreas Huberafed0e12011-09-20 15:39:58 -07001362 return OK;
1363}
1364
Robert Shih3423bbd2014-07-16 15:47:09 -07001365sp<ABuffer> NuPlayer::GenericSource::mediaBufferToABuffer(
1366 MediaBuffer* mb,
1367 media_track_type trackType,
Wei Jia474d7c72014-12-04 15:12:13 -08001368 int64_t /* seekTimeUs */,
Robert Shih3423bbd2014-07-16 15:47:09 -07001369 int64_t *actualTimeUs) {
1370 bool audio = trackType == MEDIA_TRACK_TYPE_AUDIO;
1371 size_t outLength = mb->range_length();
1372
1373 if (audio && mAudioIsVorbis) {
1374 outLength += sizeof(int32_t);
1375 }
1376
1377 sp<ABuffer> ab;
Chong Zhang42e81532014-12-01 13:44:26 -08001378 if (mIsSecure && !audio) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001379 // data is already provided in the buffer
1380 ab = new ABuffer(NULL, mb->range_length());
Robert Shih3423bbd2014-07-16 15:47:09 -07001381 mb->add_ref();
Wei Jia96e92b52014-09-18 17:36:20 -07001382 ab->setMediaBufferBase(mb);
Robert Shih3423bbd2014-07-16 15:47:09 -07001383 } else {
1384 ab = new ABuffer(outLength);
1385 memcpy(ab->data(),
1386 (const uint8_t *)mb->data() + mb->range_offset(),
1387 mb->range_length());
1388 }
1389
1390 if (audio && mAudioIsVorbis) {
1391 int32_t numPageSamples;
1392 if (!mb->meta_data()->findInt32(kKeyValidSamples, &numPageSamples)) {
1393 numPageSamples = -1;
1394 }
1395
1396 uint8_t* abEnd = ab->data() + mb->range_length();
1397 memcpy(abEnd, &numPageSamples, sizeof(numPageSamples));
1398 }
1399
Lajos Molnare26940f2014-07-31 10:31:26 -07001400 sp<AMessage> meta = ab->meta();
1401
Robert Shih3423bbd2014-07-16 15:47:09 -07001402 int64_t timeUs;
1403 CHECK(mb->meta_data()->findInt64(kKeyTime, &timeUs));
Robert Shih3423bbd2014-07-16 15:47:09 -07001404 meta->setInt64("timeUs", timeUs);
1405
Wei Jia474d7c72014-12-04 15:12:13 -08001406#if 0
1407 // Temporarily disable pre-roll till we have a full solution to handle
1408 // both single seek and continous seek gracefully.
1409 if (seekTimeUs > timeUs) {
1410 sp<AMessage> extra = new AMessage;
1411 extra->setInt64("resume-at-mediaTimeUs", seekTimeUs);
1412 meta->setMessage("extra", extra);
1413 }
1414#endif
1415
Lajos Molnare26940f2014-07-31 10:31:26 -07001416 if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) {
1417 const char *mime;
1418 CHECK(mTimedTextTrack.mSource != NULL
1419 && mTimedTextTrack.mSource->getFormat()->findCString(kKeyMIMEType, &mime));
1420 meta->setString("mime", mime);
1421 }
1422
Robert Shih3423bbd2014-07-16 15:47:09 -07001423 int64_t durationUs;
1424 if (mb->meta_data()->findInt64(kKeyDuration, &durationUs)) {
1425 meta->setInt64("durationUs", durationUs);
1426 }
1427
1428 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
1429 meta->setInt32("trackIndex", mSubtitleTrack.mIndex);
1430 }
1431
1432 if (actualTimeUs) {
1433 *actualTimeUs = timeUs;
1434 }
1435
1436 mb->release();
1437 mb = NULL;
1438
1439 return ab;
1440}
1441
Robert Shih17f6dd62014-08-20 17:00:21 -07001442void NuPlayer::GenericSource::postReadBuffer(media_track_type trackType) {
Lajos Molnar84f52782014-09-11 10:01:55 -07001443 Mutex::Autolock _l(mReadBufferLock);
1444
1445 if ((mPendingReadBufferTypes & (1 << trackType)) == 0) {
1446 mPendingReadBufferTypes |= (1 << trackType);
1447 sp<AMessage> msg = new AMessage(kWhatReadBuffer, id());
1448 msg->setInt32("trackType", trackType);
1449 msg->post();
1450 }
Robert Shih17f6dd62014-08-20 17:00:21 -07001451}
1452
1453void NuPlayer::GenericSource::onReadBuffer(sp<AMessage> msg) {
1454 int32_t tmpType;
1455 CHECK(msg->findInt32("trackType", &tmpType));
1456 media_track_type trackType = (media_track_type)tmpType;
Chong Zhang42e81532014-12-01 13:44:26 -08001457 readBuffer(trackType);
Lajos Molnar84f52782014-09-11 10:01:55 -07001458 {
1459 // only protect the variable change, as readBuffer may
Chong Zhang42e81532014-12-01 13:44:26 -08001460 // take considerable time.
Lajos Molnar84f52782014-09-11 10:01:55 -07001461 Mutex::Autolock _l(mReadBufferLock);
1462 mPendingReadBufferTypes &= ~(1 << trackType);
1463 }
Robert Shih17f6dd62014-08-20 17:00:21 -07001464}
1465
Andreas Huberafed0e12011-09-20 15:39:58 -07001466void NuPlayer::GenericSource::readBuffer(
Robert Shih3423bbd2014-07-16 15:47:09 -07001467 media_track_type trackType, int64_t seekTimeUs, int64_t *actualTimeUs, bool formatChange) {
Andy Hung2abde2c2014-09-30 14:40:32 -07001468 // Do not read data if Widevine source is stopped
1469 if (mStopRead) {
1470 return;
1471 }
Robert Shih3423bbd2014-07-16 15:47:09 -07001472 Track *track;
Phil Burkc5cc2e22014-09-09 20:08:39 -07001473 size_t maxBuffers = 1;
Robert Shih3423bbd2014-07-16 15:47:09 -07001474 switch (trackType) {
1475 case MEDIA_TRACK_TYPE_VIDEO:
1476 track = &mVideoTrack;
Jeff Tinkera28785a2014-09-23 22:24:26 -07001477 if (mIsWidevine) {
1478 maxBuffers = 2;
1479 }
Robert Shih3423bbd2014-07-16 15:47:09 -07001480 break;
1481 case MEDIA_TRACK_TYPE_AUDIO:
1482 track = &mAudioTrack;
Jeff Tinkera28785a2014-09-23 22:24:26 -07001483 if (mIsWidevine) {
1484 maxBuffers = 8;
1485 } else {
1486 maxBuffers = 64;
1487 }
Robert Shih3423bbd2014-07-16 15:47:09 -07001488 break;
1489 case MEDIA_TRACK_TYPE_SUBTITLE:
1490 track = &mSubtitleTrack;
1491 break;
Lajos Molnare26940f2014-07-31 10:31:26 -07001492 case MEDIA_TRACK_TYPE_TIMEDTEXT:
1493 track = &mTimedTextTrack;
1494 break;
Robert Shih3423bbd2014-07-16 15:47:09 -07001495 default:
1496 TRESPASS();
1497 }
1498
1499 if (track->mSource == NULL) {
1500 return;
1501 }
Andreas Huberafed0e12011-09-20 15:39:58 -07001502
1503 if (actualTimeUs) {
1504 *actualTimeUs = seekTimeUs;
1505 }
1506
1507 MediaSource::ReadOptions options;
1508
1509 bool seeking = false;
1510
1511 if (seekTimeUs >= 0) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001512 options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
Andreas Huberafed0e12011-09-20 15:39:58 -07001513 seeking = true;
1514 }
1515
Chong Zhang42e81532014-12-01 13:44:26 -08001516 if (mIsWidevine) {
Lajos Molnarcc227032014-07-17 15:33:06 -07001517 options.setNonBlocking();
1518 }
1519
Phil Burkc5cc2e22014-09-09 20:08:39 -07001520 for (size_t numBuffers = 0; numBuffers < maxBuffers; ) {
Andreas Huberafed0e12011-09-20 15:39:58 -07001521 MediaBuffer *mbuf;
1522 status_t err = track->mSource->read(&mbuf, &options);
1523
1524 options.clearSeekTo();
1525
1526 if (err == OK) {
Ronghua Wu80276872014-08-28 15:50:29 -07001527 int64_t timeUs;
1528 CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs));
1529 if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
1530 mAudioTimeUs = timeUs;
1531 } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
1532 mVideoTimeUs = timeUs;
1533 }
1534
Robert Shih3423bbd2014-07-16 15:47:09 -07001535 // formatChange && seeking: track whose source is changed during selection
1536 // formatChange && !seeking: track whose source is not changed during selection
1537 // !formatChange: normal seek
Lajos Molnare26940f2014-07-31 10:31:26 -07001538 if ((seeking || formatChange)
1539 && (trackType == MEDIA_TRACK_TYPE_AUDIO
1540 || trackType == MEDIA_TRACK_TYPE_VIDEO)) {
Wei Jiafef808d2014-10-31 17:57:05 -07001541 ATSParser::DiscontinuityType type = (formatChange && seeking)
1542 ? ATSParser::DISCONTINUITY_FORMATCHANGE
1543 : ATSParser::DISCONTINUITY_NONE;
Robert Shih3423bbd2014-07-16 15:47:09 -07001544 track->mPackets->queueDiscontinuity( type, NULL, true /* discard */);
Andreas Huberafed0e12011-09-20 15:39:58 -07001545 }
1546
Wei Jia474d7c72014-12-04 15:12:13 -08001547 sp<ABuffer> buffer = mediaBufferToABuffer(
1548 mbuf, trackType, seekTimeUs, actualTimeUs);
Andreas Huberafed0e12011-09-20 15:39:58 -07001549 track->mPackets->queueAccessUnit(buffer);
Marco Nelissen317a49a2014-09-16 21:32:33 -07001550 formatChange = false;
1551 seeking = false;
Phil Burkc5cc2e22014-09-09 20:08:39 -07001552 ++numBuffers;
Lajos Molnarcc227032014-07-17 15:33:06 -07001553 } else if (err == WOULD_BLOCK) {
1554 break;
Andreas Huberafed0e12011-09-20 15:39:58 -07001555 } else if (err == INFO_FORMAT_CHANGED) {
1556#if 0
1557 track->mPackets->queueDiscontinuity(
Chong Zhang632740c2014-06-26 13:03:47 -07001558 ATSParser::DISCONTINUITY_FORMATCHANGE,
1559 NULL,
1560 false /* discard */);
Andreas Huberafed0e12011-09-20 15:39:58 -07001561#endif
1562 } else {
1563 track->mPackets->signalEOS(err);
1564 break;
1565 }
1566 }
1567}
1568
Andreas Huberafed0e12011-09-20 15:39:58 -07001569} // namespace android