blob: 5a31b74c708f176886348aca6ce110224550aaf0 [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 mBitrate(-1ll),
Lajos Molnar84f52782014-09-11 10:01:55 -070069 mPollBufferingGeneration(0),
Chong Zhangefbb6192015-01-30 17:13:27 -080070 mPendingReadBufferTypes(0),
71 mBuffering(false),
Chong Zhangc287cad2015-02-19 18:30:30 -080072 mPrepareBuffering(false),
73 mPrevBufferPercentage(-1) {
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) {
Chong Zhangc287cad2015-02-19 18:30:30 -0800150 if (!mDataSource->sniff(&mimeType, &confidence, &dummy)) {
151 return UNKNOWN_ERROR;
Chong Zhangfc6cfd82015-02-19 16:39:59 -0800152 }
153 isWidevineStreaming = !strcasecmp(
Chong Zhangc287cad2015-02-19 18:30:30 -0800154 mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM);
Chong Zhangfc6cfd82015-02-19 16:39:59 -0800155 }
Lajos Molnarcc227032014-07-17 15:33:06 -0700156
Chong Zhangfc6cfd82015-02-19 16:39:59 -0800157 if (isWidevineStreaming) {
158 // we don't want cached source for widevine streaming.
159 mCachedSource.clear();
160 mDataSource = mHttpSource;
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700161 mWVMExtractor = new WVMExtractor(mDataSource);
162 mWVMExtractor->setAdaptiveStreamingMode(true);
Lajos Molnarcc227032014-07-17 15:33:06 -0700163 if (mUIDValid) {
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700164 mWVMExtractor->setUID(mUID);
Lajos Molnarcc227032014-07-17 15:33:06 -0700165 }
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700166 extractor = mWVMExtractor;
Lajos Molnarcc227032014-07-17 15:33:06 -0700167 } else {
Chong Zhangd354d8d2014-08-20 13:09:58 -0700168 extractor = MediaExtractor::Create(mDataSource,
Chong Zhangc287cad2015-02-19 18:30:30 -0800169 mimeType.isEmpty() ? NULL : mimeType.string());
Lajos Molnarcc227032014-07-17 15:33:06 -0700170 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700171
Chong Zhang3de157d2014-08-05 20:54:44 -0700172 if (extractor == NULL) {
173 return UNKNOWN_ERROR;
174 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700175
Ronghua Wu80276872014-08-28 15:50:29 -0700176 if (extractor->getDrmFlag()) {
177 checkDrmStatus(mDataSource);
178 }
179
Marco Nelissenf0b72b52014-09-16 15:43:44 -0700180 mFileMeta = extractor->getMetaData();
181 if (mFileMeta != NULL) {
Marco Nelissenc1f4b2b2014-06-17 14:48:32 -0700182 int64_t duration;
Marco Nelissenf0b72b52014-09-16 15:43:44 -0700183 if (mFileMeta->findInt64(kKeyDuration, &duration)) {
Marco Nelissenc1f4b2b2014-06-17 14:48:32 -0700184 mDurationUs = duration;
185 }
Chong Zhang42e81532014-12-01 13:44:26 -0800186
187 if (!mIsWidevine) {
188 // Check mime to see if we actually have a widevine source.
189 // If the data source is not URL-type (eg. file source), we
190 // won't be able to tell until now.
191 const char *fileMime;
192 if (mFileMeta->findCString(kKeyMIMEType, &fileMime)
193 && !strncasecmp(fileMime, "video/wvm", 9)) {
194 mIsWidevine = true;
195 }
196 }
Marco Nelissenc1f4b2b2014-06-17 14:48:32 -0700197 }
198
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700199 int32_t totalBitrate = 0;
200
Marco Nelissen705d3292014-09-19 15:14:37 -0700201 size_t numtracks = extractor->countTracks();
202 if (numtracks == 0) {
203 return UNKNOWN_ERROR;
204 }
205
206 for (size_t i = 0; i < numtracks; ++i) {
Chong Zhangafc0a872014-08-26 09:56:52 -0700207 sp<MediaSource> track = extractor->getTrack(i);
208
Andreas Huberafed0e12011-09-20 15:39:58 -0700209 sp<MetaData> meta = extractor->getTrackMetaData(i);
210
211 const char *mime;
212 CHECK(meta->findCString(kKeyMIMEType, &mime));
213
Chong Zhangafc0a872014-08-26 09:56:52 -0700214 // Do the string compare immediately with "mime",
215 // we can't assume "mime" would stay valid after another
216 // extractor operation, some extractors might modify meta
217 // during getTrack() and make it invalid.
Andreas Huberafed0e12011-09-20 15:39:58 -0700218 if (!strncasecmp(mime, "audio/", 6)) {
219 if (mAudioTrack.mSource == NULL) {
Robert Shihdd235722014-06-12 14:49:23 -0700220 mAudioTrack.mIndex = i;
221 mAudioTrack.mSource = track;
Robert Shihaf52c1a2014-09-11 15:38:54 -0700222 mAudioTrack.mPackets =
223 new AnotherPacketSource(mAudioTrack.mSource->getFormat());
Andreas Huberafed0e12011-09-20 15:39:58 -0700224
225 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
226 mAudioIsVorbis = true;
227 } else {
228 mAudioIsVorbis = false;
229 }
230 }
231 } else if (!strncasecmp(mime, "video/", 6)) {
232 if (mVideoTrack.mSource == NULL) {
Robert Shihdd235722014-06-12 14:49:23 -0700233 mVideoTrack.mIndex = i;
234 mVideoTrack.mSource = track;
Robert Shihaf52c1a2014-09-11 15:38:54 -0700235 mVideoTrack.mPackets =
236 new AnotherPacketSource(mVideoTrack.mSource->getFormat());
Chong Zhang7e892182014-08-05 11:58:21 -0700237
238 // check if the source requires secure buffers
239 int32_t secure;
Chong Zhanga19f33e2014-08-07 15:35:07 -0700240 if (meta->findInt32(kKeyRequiresSecureBuffers, &secure)
241 && secure) {
Chong Zhang42e81532014-12-01 13:44:26 -0800242 mIsSecure = true;
Chong Zhang3de157d2014-08-05 20:54:44 -0700243 if (mUIDValid) {
244 extractor->setUID(mUID);
245 }
Chong Zhang7e892182014-08-05 11:58:21 -0700246 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700247 }
248 }
249
250 if (track != NULL) {
Robert Shihdd235722014-06-12 14:49:23 -0700251 mSources.push(track);
Andreas Huberafed0e12011-09-20 15:39:58 -0700252 int64_t durationUs;
253 if (meta->findInt64(kKeyDuration, &durationUs)) {
254 if (durationUs > mDurationUs) {
255 mDurationUs = durationUs;
256 }
257 }
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700258
259 int32_t bitrate;
260 if (totalBitrate >= 0 && meta->findInt32(kKeyBitRate, &bitrate)) {
261 totalBitrate += bitrate;
262 } else {
263 totalBitrate = -1;
264 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700265 }
266 }
Chong Zhang3de157d2014-08-05 20:54:44 -0700267
Lajos Molnarfcd3e942015-03-31 10:06:48 -0700268 mBitrate = totalBitrate;
269
270 return OK;
271}
272
273status_t NuPlayer::GenericSource::startSources() {
Chong Zhangefbb6192015-01-30 17:13:27 -0800274 // Start the selected A/V tracks now before we start buffering.
275 // Widevine sources might re-initialize crypto when starting, if we delay
276 // this to start(), all data buffered during prepare would be wasted.
277 // (We don't actually start reading until start().)
278 if (mAudioTrack.mSource != NULL && mAudioTrack.mSource->start() != OK) {
279 ALOGE("failed to start audio track!");
280 return UNKNOWN_ERROR;
281 }
282
283 if (mVideoTrack.mSource != NULL && mVideoTrack.mSource->start() != OK) {
284 ALOGE("failed to start video track!");
285 return UNKNOWN_ERROR;
286 }
287
Chong Zhang3de157d2014-08-05 20:54:44 -0700288 return OK;
Andreas Huberafed0e12011-09-20 15:39:58 -0700289}
290
Ronghua Wu80276872014-08-28 15:50:29 -0700291void NuPlayer::GenericSource::checkDrmStatus(const sp<DataSource>& dataSource) {
292 dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
293 if (mDecryptHandle != NULL) {
294 CHECK(mDrmManagerClient);
295 if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
296 sp<AMessage> msg = dupNotify();
297 msg->setInt32("what", kWhatDrmNoLicense);
298 msg->post();
299 }
300 }
301}
302
303int64_t NuPlayer::GenericSource::getLastReadPosition() {
304 if (mAudioTrack.mSource != NULL) {
305 return mAudioTimeUs;
306 } else if (mVideoTrack.mSource != NULL) {
307 return mVideoTimeUs;
308 } else {
309 return 0;
310 }
311}
312
Chong Zhanga19f33e2014-08-07 15:35:07 -0700313status_t NuPlayer::GenericSource::setBuffers(
314 bool audio, Vector<MediaBuffer *> &buffers) {
Chong Zhang42e81532014-12-01 13:44:26 -0800315 if (mIsSecure && !audio) {
Lajos Molnarcc227032014-07-17 15:33:06 -0700316 return mVideoTrack.mSource->setBuffers(buffers);
317 }
318 return INVALID_OPERATION;
319}
320
Andreas Huberafed0e12011-09-20 15:39:58 -0700321NuPlayer::GenericSource::~GenericSource() {
Chong Zhang1228d6b2014-08-12 21:25:48 -0700322 if (mLooper != NULL) {
323 mLooper->unregisterHandler(id());
324 mLooper->stop();
325 }
Chong Zhanga6bf21f2014-11-19 20:26:34 -0800326 resetDataSource();
Andreas Huberafed0e12011-09-20 15:39:58 -0700327}
328
Andreas Huber9575c962013-02-05 13:59:56 -0800329void NuPlayer::GenericSource::prepareAsync() {
Chong Zhang1228d6b2014-08-12 21:25:48 -0700330 if (mLooper == NULL) {
331 mLooper = new ALooper;
332 mLooper->setName("generic");
333 mLooper->start();
334
335 mLooper->registerHandler(this);
336 }
337
Lajos Molnar1d15ab52015-03-04 16:46:34 -0800338 sp<AMessage> msg = new AMessage(kWhatPrepareAsync, this);
Chong Zhang1228d6b2014-08-12 21:25:48 -0700339 msg->post();
340}
341
342void NuPlayer::GenericSource::onPrepareAsync() {
Chong Zhanga19f33e2014-08-07 15:35:07 -0700343 // delayed data source creation
Chong Zhangd354d8d2014-08-20 13:09:58 -0700344 if (mDataSource == NULL) {
Chong Zhang42e81532014-12-01 13:44:26 -0800345 // set to false first, if the extractor
346 // comes back as secure, set it to true then.
347 mIsSecure = false;
348
Chong Zhangd354d8d2014-08-20 13:09:58 -0700349 if (!mUri.empty()) {
Robert Shih360d6d02014-09-29 14:42:35 -0700350 const char* uri = mUri.c_str();
Chong Zhangc287cad2015-02-19 18:30:30 -0800351 String8 contentType;
Robert Shih360d6d02014-09-29 14:42:35 -0700352 mIsWidevine = !strncasecmp(uri, "widevine://", 11);
353
354 if (!strncasecmp("http://", uri, 7)
355 || !strncasecmp("https://", uri, 8)
356 || mIsWidevine) {
357 mHttpSource = DataSource::CreateMediaHTTP(mHTTPService);
358 if (mHttpSource == NULL) {
359 ALOGE("Failed to create http source!");
360 notifyPreparedAndCleanup(UNKNOWN_ERROR);
361 return;
362 }
363 }
Chong Zhanga19f33e2014-08-07 15:35:07 -0700364
Chong Zhangd354d8d2014-08-20 13:09:58 -0700365 mDataSource = DataSource::CreateFromURI(
Chong Zhangc287cad2015-02-19 18:30:30 -0800366 mHTTPService, uri, &mUriHeaders, &contentType,
Robert Shih360d6d02014-09-29 14:42:35 -0700367 static_cast<HTTPBase *>(mHttpSource.get()));
Chong Zhangd354d8d2014-08-20 13:09:58 -0700368 } else {
Chong Zhangd354d8d2014-08-20 13:09:58 -0700369 mIsWidevine = false;
Chong Zhanga19f33e2014-08-07 15:35:07 -0700370
Chong Zhangd354d8d2014-08-20 13:09:58 -0700371 mDataSource = new FileSource(mFd, mOffset, mLength);
Chong Zhanga6bf21f2014-11-19 20:26:34 -0800372 mFd = -1;
Chong Zhangd354d8d2014-08-20 13:09:58 -0700373 }
Chong Zhanga19f33e2014-08-07 15:35:07 -0700374
Chong Zhangd354d8d2014-08-20 13:09:58 -0700375 if (mDataSource == NULL) {
376 ALOGE("Failed to create data source!");
377 notifyPreparedAndCleanup(UNKNOWN_ERROR);
378 return;
379 }
380
381 if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
382 mCachedSource = static_cast<NuCachedSource2 *>(mDataSource.get());
383 }
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700384
Chong Zhangefbb6192015-01-30 17:13:27 -0800385 // For widevine or other cached streaming cases, we need to wait for
386 // enough buffering before reporting prepared.
387 // Note that even when URL doesn't start with widevine://, mIsWidevine
388 // could still be set to true later, if the streaming or file source
389 // is sniffed to be widevine. We don't want to buffer for file source
390 // in that case, so must check the flag now.
391 mIsStreaming = (mIsWidevine || mCachedSource != NULL);
Chong Zhanga19f33e2014-08-07 15:35:07 -0700392 }
393
Chong Zhangc287cad2015-02-19 18:30:30 -0800394 // init extractor from data source
395 status_t err = initFromDataSource();
Chong Zhanga19f33e2014-08-07 15:35:07 -0700396
397 if (err != OK) {
398 ALOGE("Failed to init from data source!");
Chong Zhangd354d8d2014-08-20 13:09:58 -0700399 notifyPreparedAndCleanup(err);
Chong Zhanga19f33e2014-08-07 15:35:07 -0700400 return;
401 }
402
Andreas Huber9575c962013-02-05 13:59:56 -0800403 if (mVideoTrack.mSource != NULL) {
Robert Shih17f6dd62014-08-20 17:00:21 -0700404 sp<MetaData> meta = doGetFormatMeta(false /* audio */);
405 sp<AMessage> msg = new AMessage;
406 err = convertMetaDataToMessage(meta, &msg);
407 if(err != OK) {
408 notifyPreparedAndCleanup(err);
409 return;
410 }
411 notifyVideoSizeChanged(msg);
Andreas Huber9575c962013-02-05 13:59:56 -0800412 }
413
414 notifyFlagsChanged(
Chong Zhang42e81532014-12-01 13:44:26 -0800415 (mIsSecure ? FLAG_SECURE : 0)
Chong Zhang17134602015-01-07 16:14:34 -0800416 | (mDecryptHandle != NULL ? FLAG_PROTECTED : 0)
Lajos Molnarcc227032014-07-17 15:33:06 -0700417 | FLAG_CAN_PAUSE
Andreas Huber9575c962013-02-05 13:59:56 -0800418 | FLAG_CAN_SEEK_BACKWARD
419 | FLAG_CAN_SEEK_FORWARD
420 | FLAG_CAN_SEEK);
421
Lajos Molnarfcd3e942015-03-31 10:06:48 -0700422 if (mIsSecure) {
423 // secure decoders must be instantiated before starting widevine source
424 sp<AMessage> reply = new AMessage(kWhatSecureDecodersInstantiated, this);
425 notifyInstantiateSecureDecoders(reply);
426 } else {
427 finishPrepareAsync();
428 }
429}
430
431void NuPlayer::GenericSource::onSecureDecodersInstantiated(status_t err) {
432 if (err != OK) {
433 ALOGE("Failed to instantiate secure decoders!");
434 notifyPreparedAndCleanup(err);
435 return;
436 }
437 finishPrepareAsync();
438}
439
440void NuPlayer::GenericSource::finishPrepareAsync() {
441 status_t err = startSources();
442 if (err != OK) {
443 ALOGE("Failed to init start data source!");
444 notifyPreparedAndCleanup(err);
445 return;
446 }
447
Chong Zhangefbb6192015-01-30 17:13:27 -0800448 if (mIsStreaming) {
449 mPrepareBuffering = true;
450
451 ensureCacheIsFetching();
452 restartPollBuffering();
453 } else {
454 notifyPrepared();
455 }
Andreas Huber9575c962013-02-05 13:59:56 -0800456}
457
Chong Zhangd354d8d2014-08-20 13:09:58 -0700458void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) {
459 if (err != OK) {
Chong Zhangd354d8d2014-08-20 13:09:58 -0700460 mDataSource.clear();
461 mCachedSource.clear();
Robert Shih360d6d02014-09-29 14:42:35 -0700462 mHttpSource.clear();
Lajos Molnarfcd3e942015-03-31 10:06:48 -0700463 mBitrate = -1;
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700464
465 cancelPollBuffering();
Chong Zhangd354d8d2014-08-20 13:09:58 -0700466 }
467 notifyPrepared(err);
468}
469
Andreas Huberafed0e12011-09-20 15:39:58 -0700470void NuPlayer::GenericSource::start() {
471 ALOGI("start");
472
Andy Hung2abde2c2014-09-30 14:40:32 -0700473 mStopRead = false;
Andreas Huberafed0e12011-09-20 15:39:58 -0700474 if (mAudioTrack.mSource != NULL) {
Robert Shih17f6dd62014-08-20 17:00:21 -0700475 postReadBuffer(MEDIA_TRACK_TYPE_AUDIO);
Andreas Huberafed0e12011-09-20 15:39:58 -0700476 }
477
478 if (mVideoTrack.mSource != NULL) {
Robert Shih17f6dd62014-08-20 17:00:21 -0700479 postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
Andreas Huberafed0e12011-09-20 15:39:58 -0700480 }
Ronghua Wu80276872014-08-28 15:50:29 -0700481
482 setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000);
483 mStarted = true;
Chong Zhangefbb6192015-01-30 17:13:27 -0800484
Lajos Molnar1d15ab52015-03-04 16:46:34 -0800485 (new AMessage(kWhatStart, this))->post();
Ronghua Wu80276872014-08-28 15:50:29 -0700486}
487
488void NuPlayer::GenericSource::stop() {
489 // nothing to do, just account for DRM playback status
490 setDrmPlaybackStatusIfNeeded(Playback::STOP, 0);
491 mStarted = false;
Chong Zhang42e81532014-12-01 13:44:26 -0800492 if (mIsWidevine || mIsSecure) {
493 // For widevine or secure sources we need to prevent any further reads.
Lajos Molnar1d15ab52015-03-04 16:46:34 -0800494 sp<AMessage> msg = new AMessage(kWhatStopWidevine, this);
Andy Hung2abde2c2014-09-30 14:40:32 -0700495 sp<AMessage> response;
496 (void) msg->postAndAwaitResponse(&response);
497 }
Ronghua Wu80276872014-08-28 15:50:29 -0700498}
499
500void NuPlayer::GenericSource::pause() {
501 // nothing to do, just account for DRM playback status
502 setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0);
503 mStarted = false;
504}
505
506void NuPlayer::GenericSource::resume() {
507 // nothing to do, just account for DRM playback status
508 setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000);
509 mStarted = true;
Chong Zhangefbb6192015-01-30 17:13:27 -0800510
Lajos Molnar1d15ab52015-03-04 16:46:34 -0800511 (new AMessage(kWhatResume, this))->post();
Ronghua Wu80276872014-08-28 15:50:29 -0700512}
513
Chong Zhang48296b72014-09-14 14:28:45 -0700514void NuPlayer::GenericSource::disconnect() {
515 if (mDataSource != NULL) {
516 // disconnect data source
517 if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
518 static_cast<NuCachedSource2 *>(mDataSource.get())->disconnect();
519 }
Robert Shih360d6d02014-09-29 14:42:35 -0700520 } else if (mHttpSource != NULL) {
521 static_cast<HTTPBase *>(mHttpSource.get())->disconnect();
Chong Zhang48296b72014-09-14 14:28:45 -0700522 }
523}
524
Ronghua Wu80276872014-08-28 15:50:29 -0700525void NuPlayer::GenericSource::setDrmPlaybackStatusIfNeeded(int playbackStatus, int64_t position) {
526 if (mDecryptHandle != NULL) {
527 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, playbackStatus, position);
528 }
Robert Shih17f6dd62014-08-20 17:00:21 -0700529 mSubtitleTrack.mPackets = new AnotherPacketSource(NULL);
530 mTimedTextTrack.mPackets = new AnotherPacketSource(NULL);
Andreas Huberafed0e12011-09-20 15:39:58 -0700531}
532
533status_t NuPlayer::GenericSource::feedMoreTSData() {
534 return OK;
535}
536
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700537void NuPlayer::GenericSource::schedulePollBuffering() {
Lajos Molnar1d15ab52015-03-04 16:46:34 -0800538 sp<AMessage> msg = new AMessage(kWhatPollBuffering, this);
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700539 msg->setInt32("generation", mPollBufferingGeneration);
540 msg->post(1000000ll);
541}
542
543void NuPlayer::GenericSource::cancelPollBuffering() {
Chong Zhangefbb6192015-01-30 17:13:27 -0800544 mBuffering = false;
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700545 ++mPollBufferingGeneration;
Chong Zhangc287cad2015-02-19 18:30:30 -0800546 mPrevBufferPercentage = -1;
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700547}
548
Chong Zhangefbb6192015-01-30 17:13:27 -0800549void NuPlayer::GenericSource::restartPollBuffering() {
550 if (mIsStreaming) {
551 cancelPollBuffering();
552 onPollBuffering();
553 }
554}
555
Chong Zhangc287cad2015-02-19 18:30:30 -0800556void NuPlayer::GenericSource::notifyBufferingUpdate(int32_t percentage) {
557 // Buffering percent could go backward as it's estimated from remaining
558 // data and last access time. This could cause the buffering position
559 // drawn on media control to jitter slightly. Remember previously reported
560 // percentage and don't allow it to go backward.
561 if (percentage < mPrevBufferPercentage) {
562 percentage = mPrevBufferPercentage;
563 } else if (percentage > 100) {
564 percentage = 100;
565 }
566
567 mPrevBufferPercentage = percentage;
568
Chong Zhangefbb6192015-01-30 17:13:27 -0800569 ALOGV("notifyBufferingUpdate: buffering %d%%", percentage);
570
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700571 sp<AMessage> msg = dupNotify();
572 msg->setInt32("what", kWhatBufferingUpdate);
573 msg->setInt32("percentage", percentage);
574 msg->post();
575}
576
Chong Zhangefbb6192015-01-30 17:13:27 -0800577void NuPlayer::GenericSource::startBufferingIfNecessary() {
578 ALOGV("startBufferingIfNecessary: mPrepareBuffering=%d, mBuffering=%d",
579 mPrepareBuffering, mBuffering);
580
581 if (mPrepareBuffering) {
582 return;
583 }
584
585 if (!mBuffering) {
586 mBuffering = true;
587
588 ensureCacheIsFetching();
589 sendCacheStats();
590
591 sp<AMessage> notify = dupNotify();
592 notify->setInt32("what", kWhatPauseOnBufferingStart);
593 notify->post();
594 }
595}
596
597void NuPlayer::GenericSource::stopBufferingIfNecessary() {
598 ALOGV("stopBufferingIfNecessary: mPrepareBuffering=%d, mBuffering=%d",
599 mPrepareBuffering, mBuffering);
600
601 if (mPrepareBuffering) {
602 mPrepareBuffering = false;
603 notifyPrepared();
604 return;
605 }
606
607 if (mBuffering) {
608 mBuffering = false;
609
610 sendCacheStats();
611
612 sp<AMessage> notify = dupNotify();
613 notify->setInt32("what", kWhatResumeOnBufferingEnd);
614 notify->post();
615 }
616}
617
618void NuPlayer::GenericSource::sendCacheStats() {
619 int32_t kbps = 0;
620 status_t err = UNKNOWN_ERROR;
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700621
Chong Zhangfc6cfd82015-02-19 16:39:59 -0800622 if (mWVMExtractor != NULL) {
Chong Zhangefbb6192015-01-30 17:13:27 -0800623 err = mWVMExtractor->getEstimatedBandwidthKbps(&kbps);
Chong Zhangfc6cfd82015-02-19 16:39:59 -0800624 } else if (mCachedSource != NULL) {
625 err = mCachedSource->getEstimatedBandwidthKbps(&kbps);
Chong Zhangefbb6192015-01-30 17:13:27 -0800626 }
627
628 if (err == OK) {
629 sp<AMessage> notify = dupNotify();
630 notify->setInt32("what", kWhatCacheStats);
631 notify->setInt32("bandwidth", kbps);
632 notify->post();
633 }
634}
635
636void NuPlayer::GenericSource::ensureCacheIsFetching() {
637 if (mCachedSource != NULL) {
638 mCachedSource->resumeFetchingIfNecessary();
639 }
640}
641
642void NuPlayer::GenericSource::onPollBuffering() {
643 status_t finalStatus = UNKNOWN_ERROR;
644 int64_t cachedDurationUs = -1ll;
645 ssize_t cachedDataRemaining = -1;
646
Chong Zhangfc6cfd82015-02-19 16:39:59 -0800647 ALOGW_IF(mWVMExtractor != NULL && mCachedSource != NULL,
648 "WVMExtractor and NuCachedSource both present");
649
650 if (mWVMExtractor != NULL) {
651 cachedDurationUs =
652 mWVMExtractor->getCachedDurationUs(&finalStatus);
653 } else if (mCachedSource != NULL) {
Chong Zhangefbb6192015-01-30 17:13:27 -0800654 cachedDataRemaining =
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700655 mCachedSource->approxDataRemaining(&finalStatus);
656
657 if (finalStatus == OK) {
658 off64_t size;
659 int64_t bitrate = 0ll;
660 if (mDurationUs > 0 && mCachedSource->getSize(&size) == OK) {
661 bitrate = size * 8000000ll / mDurationUs;
662 } else if (mBitrate > 0) {
663 bitrate = mBitrate;
664 }
665 if (bitrate > 0) {
666 cachedDurationUs = cachedDataRemaining * 8000000ll / bitrate;
667 }
668 }
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700669 }
670
Chong Zhangefbb6192015-01-30 17:13:27 -0800671 if (finalStatus != OK) {
672 ALOGV("onPollBuffering: EOS (finalStatus = %d)", finalStatus);
673
674 if (finalStatus == ERROR_END_OF_STREAM) {
675 notifyBufferingUpdate(100);
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700676 }
677
Chong Zhangefbb6192015-01-30 17:13:27 -0800678 stopBufferingIfNecessary();
679 return;
680 } else if (cachedDurationUs >= 0ll) {
681 if (mDurationUs > 0ll) {
682 int64_t cachedPosUs = getLastReadPosition() + cachedDurationUs;
683 int percentage = 100.0 * cachedPosUs / mDurationUs;
684 if (percentage > 100) {
685 percentage = 100;
686 }
687
688 notifyBufferingUpdate(percentage);
689 }
690
691 ALOGV("onPollBuffering: cachedDurationUs %.1f sec",
692 cachedDurationUs / 1000000.0f);
693
694 if (cachedDurationUs < kLowWaterMarkUs) {
695 startBufferingIfNecessary();
696 } else if (cachedDurationUs > kHighWaterMarkUs) {
697 stopBufferingIfNecessary();
698 }
699 } else if (cachedDataRemaining >= 0) {
700 ALOGV("onPollBuffering: cachedDataRemaining %d bytes",
701 cachedDataRemaining);
702
703 if (cachedDataRemaining < kLowWaterMarkBytes) {
704 startBufferingIfNecessary();
705 } else if (cachedDataRemaining > kHighWaterMarkBytes) {
706 stopBufferingIfNecessary();
707 }
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700708 }
709
710 schedulePollBuffering();
711}
712
Robert Shih3423bbd2014-07-16 15:47:09 -0700713void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) {
714 switch (msg->what()) {
Chong Zhang1228d6b2014-08-12 21:25:48 -0700715 case kWhatPrepareAsync:
716 {
717 onPrepareAsync();
718 break;
719 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700720 case kWhatFetchSubtitleData:
721 {
Lajos Molnare26940f2014-07-31 10:31:26 -0700722 fetchTextData(kWhatSendSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
723 mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
724 break;
725 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700726
Lajos Molnare26940f2014-07-31 10:31:26 -0700727 case kWhatFetchTimedTextData:
728 {
729 fetchTextData(kWhatSendTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
730 mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
Robert Shih3423bbd2014-07-16 15:47:09 -0700731 break;
732 }
733
734 case kWhatSendSubtitleData:
735 {
Lajos Molnare26940f2014-07-31 10:31:26 -0700736 sendTextData(kWhatSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
737 mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
738 break;
739 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700740
Lajos Molnare26940f2014-07-31 10:31:26 -0700741 case kWhatSendTimedTextData:
742 {
743 sendTextData(kWhatTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
744 mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
Robert Shih3423bbd2014-07-16 15:47:09 -0700745 break;
746 }
747
748 case kWhatChangeAVSource:
749 {
750 int32_t trackIndex;
751 CHECK(msg->findInt32("trackIndex", &trackIndex));
752 const sp<MediaSource> source = mSources.itemAt(trackIndex);
753
754 Track* track;
755 const char *mime;
756 media_track_type trackType, counterpartType;
757 sp<MetaData> meta = source->getFormat();
758 meta->findCString(kKeyMIMEType, &mime);
759 if (!strncasecmp(mime, "audio/", 6)) {
760 track = &mAudioTrack;
761 trackType = MEDIA_TRACK_TYPE_AUDIO;
762 counterpartType = MEDIA_TRACK_TYPE_VIDEO;;
763 } else {
764 CHECK(!strncasecmp(mime, "video/", 6));
765 track = &mVideoTrack;
766 trackType = MEDIA_TRACK_TYPE_VIDEO;
767 counterpartType = MEDIA_TRACK_TYPE_AUDIO;;
768 }
769
770
771 if (track->mSource != NULL) {
772 track->mSource->stop();
773 }
774 track->mSource = source;
775 track->mSource->start();
776 track->mIndex = trackIndex;
777
Robert Shih3423bbd2014-07-16 15:47:09 -0700778 int64_t timeUs, actualTimeUs;
779 const bool formatChange = true;
Robert Shih5c67ddc2014-11-04 17:46:05 -0800780 if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
781 timeUs = mAudioLastDequeueTimeUs;
782 } else {
783 timeUs = mVideoLastDequeueTimeUs;
784 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700785 readBuffer(trackType, timeUs, &actualTimeUs, formatChange);
786 readBuffer(counterpartType, -1, NULL, formatChange);
787 ALOGV("timeUs %lld actualTimeUs %lld", timeUs, actualTimeUs);
788
789 break;
790 }
Chong Zhangefbb6192015-01-30 17:13:27 -0800791
792 case kWhatStart:
793 case kWhatResume:
794 {
795 restartPollBuffering();
796 break;
797 }
798
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700799 case kWhatPollBuffering:
800 {
801 int32_t generation;
802 CHECK(msg->findInt32("generation", &generation));
803 if (generation == mPollBufferingGeneration) {
804 onPollBuffering();
805 }
806 break;
807 }
Robert Shih17f6dd62014-08-20 17:00:21 -0700808
809 case kWhatGetFormat:
810 {
811 onGetFormatMeta(msg);
812 break;
813 }
814
815 case kWhatGetSelectedTrack:
816 {
817 onGetSelectedTrack(msg);
818 break;
819 }
820
821 case kWhatSelectTrack:
822 {
823 onSelectTrack(msg);
824 break;
825 }
826
827 case kWhatSeek:
828 {
829 onSeek(msg);
830 break;
831 }
832
833 case kWhatReadBuffer:
834 {
835 onReadBuffer(msg);
836 break;
837 }
838
Lajos Molnarfcd3e942015-03-31 10:06:48 -0700839 case kWhatSecureDecodersInstantiated:
840 {
841 int32_t err;
842 CHECK(msg->findInt32("err", &err));
843 onSecureDecodersInstantiated(err);
844 break;
845 }
846
Andy Hung2abde2c2014-09-30 14:40:32 -0700847 case kWhatStopWidevine:
848 {
849 // mStopRead is only used for Widevine to prevent the video source
850 // from being read while the associated video decoder is shutting down.
851 mStopRead = true;
852 if (mVideoTrack.mSource != NULL) {
853 mVideoTrack.mPackets->clear();
854 }
855 sp<AMessage> response = new AMessage;
Lajos Molnar3f274362015-03-05 14:35:41 -0800856 sp<AReplyToken> replyID;
Andy Hung2abde2c2014-09-30 14:40:32 -0700857 CHECK(msg->senderAwaitsResponse(&replyID));
858 response->postReply(replyID);
859 break;
860 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700861 default:
862 Source::onMessageReceived(msg);
863 break;
864 }
865}
866
Lajos Molnare26940f2014-07-31 10:31:26 -0700867void NuPlayer::GenericSource::fetchTextData(
868 uint32_t sendWhat,
869 media_track_type type,
870 int32_t curGen,
871 sp<AnotherPacketSource> packets,
872 sp<AMessage> msg) {
873 int32_t msgGeneration;
874 CHECK(msg->findInt32("generation", &msgGeneration));
875 if (msgGeneration != curGen) {
876 // stale
877 return;
878 }
879
880 int32_t avail;
881 if (packets->hasBufferAvailable(&avail)) {
882 return;
883 }
884
885 int64_t timeUs;
886 CHECK(msg->findInt64("timeUs", &timeUs));
887
888 int64_t subTimeUs;
889 readBuffer(type, timeUs, &subTimeUs);
890
891 int64_t delayUs = subTimeUs - timeUs;
892 if (msg->what() == kWhatFetchSubtitleData) {
893 const int64_t oneSecUs = 1000000ll;
894 delayUs -= oneSecUs;
895 }
Lajos Molnar1d15ab52015-03-04 16:46:34 -0800896 sp<AMessage> msg2 = new AMessage(sendWhat, this);
Lajos Molnare26940f2014-07-31 10:31:26 -0700897 msg2->setInt32("generation", msgGeneration);
898 msg2->post(delayUs < 0 ? 0 : delayUs);
899}
900
901void NuPlayer::GenericSource::sendTextData(
902 uint32_t what,
903 media_track_type type,
904 int32_t curGen,
905 sp<AnotherPacketSource> packets,
906 sp<AMessage> msg) {
907 int32_t msgGeneration;
908 CHECK(msg->findInt32("generation", &msgGeneration));
909 if (msgGeneration != curGen) {
910 // stale
911 return;
912 }
913
914 int64_t subTimeUs;
915 if (packets->nextBufferTime(&subTimeUs) != OK) {
916 return;
917 }
918
919 int64_t nextSubTimeUs;
920 readBuffer(type, -1, &nextSubTimeUs);
921
922 sp<ABuffer> buffer;
923 status_t dequeueStatus = packets->dequeueAccessUnit(&buffer);
924 if (dequeueStatus == OK) {
925 sp<AMessage> notify = dupNotify();
926 notify->setInt32("what", what);
927 notify->setBuffer("buffer", buffer);
928 notify->post();
929
930 const int64_t delayUs = nextSubTimeUs - subTimeUs;
931 msg->post(delayUs < 0 ? 0 : delayUs);
932 }
933}
934
Andreas Huber84066782011-08-16 09:34:26 -0700935sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
Lajos Molnar1d15ab52015-03-04 16:46:34 -0800936 sp<AMessage> msg = new AMessage(kWhatGetFormat, this);
Robert Shih17f6dd62014-08-20 17:00:21 -0700937 msg->setInt32("audio", audio);
938
939 sp<AMessage> response;
940 void *format;
941 status_t err = msg->postAndAwaitResponse(&response);
942 if (err == OK && response != NULL) {
943 CHECK(response->findPointer("format", &format));
944 return (MetaData *)format;
945 } else {
946 return NULL;
947 }
948}
949
950void NuPlayer::GenericSource::onGetFormatMeta(sp<AMessage> msg) const {
951 int32_t audio;
952 CHECK(msg->findInt32("audio", &audio));
953
954 sp<AMessage> response = new AMessage;
955 sp<MetaData> format = doGetFormatMeta(audio);
956 response->setPointer("format", format.get());
957
Lajos Molnar3f274362015-03-05 14:35:41 -0800958 sp<AReplyToken> replyID;
Robert Shih17f6dd62014-08-20 17:00:21 -0700959 CHECK(msg->senderAwaitsResponse(&replyID));
960 response->postReply(replyID);
961}
962
963sp<MetaData> NuPlayer::GenericSource::doGetFormatMeta(bool audio) const {
Andreas Huberafed0e12011-09-20 15:39:58 -0700964 sp<MediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
965
966 if (source == NULL) {
967 return NULL;
968 }
969
970 return source->getFormat();
971}
972
973status_t NuPlayer::GenericSource::dequeueAccessUnit(
974 bool audio, sp<ABuffer> *accessUnit) {
975 Track *track = audio ? &mAudioTrack : &mVideoTrack;
976
977 if (track->mSource == NULL) {
978 return -EWOULDBLOCK;
979 }
980
Lajos Molnarcc227032014-07-17 15:33:06 -0700981 if (mIsWidevine && !audio) {
982 // try to read a buffer as we may not have been able to the last time
Robert Shih17f6dd62014-08-20 17:00:21 -0700983 postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
Lajos Molnarcc227032014-07-17 15:33:06 -0700984 }
985
Andreas Huberafed0e12011-09-20 15:39:58 -0700986 status_t finalResult;
987 if (!track->mPackets->hasBufferAvailable(&finalResult)) {
Chong Zhang42e81532014-12-01 13:44:26 -0800988 if (finalResult == OK) {
989 postReadBuffer(
990 audio ? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
991 return -EWOULDBLOCK;
992 }
993 return finalResult;
Andreas Huberafed0e12011-09-20 15:39:58 -0700994 }
995
996 status_t result = track->mPackets->dequeueAccessUnit(accessUnit);
997
Robert Shih3423bbd2014-07-16 15:47:09 -0700998 if (!track->mPackets->hasBufferAvailable(&finalResult)) {
Robert Shih17f6dd62014-08-20 17:00:21 -0700999 postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
Lajos Molnare26940f2014-07-31 10:31:26 -07001000 }
1001
Robert Shih3423bbd2014-07-16 15:47:09 -07001002 if (result != OK) {
Lajos Molnare26940f2014-07-31 10:31:26 -07001003 if (mSubtitleTrack.mSource != NULL) {
1004 mSubtitleTrack.mPackets->clear();
1005 mFetchSubtitleDataGeneration++;
1006 }
1007 if (mTimedTextTrack.mSource != NULL) {
1008 mTimedTextTrack.mPackets->clear();
1009 mFetchTimedTextDataGeneration++;
1010 }
Robert Shih3423bbd2014-07-16 15:47:09 -07001011 return result;
1012 }
1013
1014 int64_t timeUs;
1015 status_t eosResult; // ignored
1016 CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs));
Robert Shih5c67ddc2014-11-04 17:46:05 -08001017 if (audio) {
1018 mAudioLastDequeueTimeUs = timeUs;
1019 } else {
1020 mVideoLastDequeueTimeUs = timeUs;
1021 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001022
1023 if (mSubtitleTrack.mSource != NULL
1024 && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
Lajos Molnar1d15ab52015-03-04 16:46:34 -08001025 sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, this);
Robert Shih3423bbd2014-07-16 15:47:09 -07001026 msg->setInt64("timeUs", timeUs);
1027 msg->setInt32("generation", mFetchSubtitleDataGeneration);
1028 msg->post();
1029 }
Robert Shiheb1735e2014-07-23 15:53:14 -07001030
Lajos Molnare26940f2014-07-31 10:31:26 -07001031 if (mTimedTextTrack.mSource != NULL
1032 && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
Lajos Molnar1d15ab52015-03-04 16:46:34 -08001033 sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, this);
Lajos Molnare26940f2014-07-31 10:31:26 -07001034 msg->setInt64("timeUs", timeUs);
1035 msg->setInt32("generation", mFetchTimedTextDataGeneration);
1036 msg->post();
1037 }
1038
Andreas Huberafed0e12011-09-20 15:39:58 -07001039 return result;
1040}
1041
1042status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) {
1043 *durationUs = mDurationUs;
1044 return OK;
1045}
1046
Robert Shihdd235722014-06-12 14:49:23 -07001047size_t NuPlayer::GenericSource::getTrackCount() const {
1048 return mSources.size();
1049}
1050
1051sp<AMessage> NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const {
1052 size_t trackCount = mSources.size();
1053 if (trackIndex >= trackCount) {
1054 return NULL;
1055 }
1056
1057 sp<AMessage> format = new AMessage();
1058 sp<MetaData> meta = mSources.itemAt(trackIndex)->getFormat();
1059
1060 const char *mime;
1061 CHECK(meta->findCString(kKeyMIMEType, &mime));
1062
1063 int32_t trackType;
1064 if (!strncasecmp(mime, "video/", 6)) {
1065 trackType = MEDIA_TRACK_TYPE_VIDEO;
1066 } else if (!strncasecmp(mime, "audio/", 6)) {
1067 trackType = MEDIA_TRACK_TYPE_AUDIO;
1068 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
1069 trackType = MEDIA_TRACK_TYPE_TIMEDTEXT;
1070 } else {
1071 trackType = MEDIA_TRACK_TYPE_UNKNOWN;
1072 }
1073 format->setInt32("type", trackType);
1074
1075 const char *lang;
1076 if (!meta->findCString(kKeyMediaLanguage, &lang)) {
1077 lang = "und";
1078 }
1079 format->setString("language", lang);
1080
1081 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
1082 format->setString("mime", mime);
1083
1084 int32_t isAutoselect = 1, isDefault = 0, isForced = 0;
1085 meta->findInt32(kKeyTrackIsAutoselect, &isAutoselect);
1086 meta->findInt32(kKeyTrackIsDefault, &isDefault);
1087 meta->findInt32(kKeyTrackIsForced, &isForced);
1088
1089 format->setInt32("auto", !!isAutoselect);
1090 format->setInt32("default", !!isDefault);
1091 format->setInt32("forced", !!isForced);
1092 }
1093
1094 return format;
1095}
1096
Lajos Molnare26940f2014-07-31 10:31:26 -07001097ssize_t NuPlayer::GenericSource::getSelectedTrack(media_track_type type) const {
Lajos Molnar1d15ab52015-03-04 16:46:34 -08001098 sp<AMessage> msg = new AMessage(kWhatGetSelectedTrack, this);
Robert Shih17f6dd62014-08-20 17:00:21 -07001099 msg->setInt32("type", type);
1100
1101 sp<AMessage> response;
1102 int32_t index;
1103 status_t err = msg->postAndAwaitResponse(&response);
1104 if (err == OK && response != NULL) {
1105 CHECK(response->findInt32("index", &index));
1106 return index;
1107 } else {
1108 return -1;
1109 }
1110}
1111
1112void NuPlayer::GenericSource::onGetSelectedTrack(sp<AMessage> msg) const {
1113 int32_t tmpType;
1114 CHECK(msg->findInt32("type", &tmpType));
1115 media_track_type type = (media_track_type)tmpType;
1116
1117 sp<AMessage> response = new AMessage;
1118 ssize_t index = doGetSelectedTrack(type);
1119 response->setInt32("index", index);
1120
Lajos Molnar3f274362015-03-05 14:35:41 -08001121 sp<AReplyToken> replyID;
Robert Shih17f6dd62014-08-20 17:00:21 -07001122 CHECK(msg->senderAwaitsResponse(&replyID));
1123 response->postReply(replyID);
1124}
1125
1126ssize_t NuPlayer::GenericSource::doGetSelectedTrack(media_track_type type) const {
Lajos Molnare26940f2014-07-31 10:31:26 -07001127 const Track *track = NULL;
1128 switch (type) {
1129 case MEDIA_TRACK_TYPE_VIDEO:
1130 track = &mVideoTrack;
1131 break;
1132 case MEDIA_TRACK_TYPE_AUDIO:
1133 track = &mAudioTrack;
1134 break;
1135 case MEDIA_TRACK_TYPE_TIMEDTEXT:
1136 track = &mTimedTextTrack;
1137 break;
1138 case MEDIA_TRACK_TYPE_SUBTITLE:
1139 track = &mSubtitleTrack;
1140 break;
1141 default:
1142 break;
1143 }
1144
1145 if (track != NULL && track->mSource != NULL) {
1146 return track->mIndex;
1147 }
1148
1149 return -1;
1150}
1151
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001152status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select, int64_t timeUs) {
Lajos Molnare26940f2014-07-31 10:31:26 -07001153 ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex);
Lajos Molnar1d15ab52015-03-04 16:46:34 -08001154 sp<AMessage> msg = new AMessage(kWhatSelectTrack, this);
Robert Shih17f6dd62014-08-20 17:00:21 -07001155 msg->setInt32("trackIndex", trackIndex);
Robert Shihda23ab92014-09-16 11:34:08 -07001156 msg->setInt32("select", select);
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001157 msg->setInt64("timeUs", timeUs);
Robert Shih17f6dd62014-08-20 17:00:21 -07001158
1159 sp<AMessage> response;
1160 status_t err = msg->postAndAwaitResponse(&response);
1161 if (err == OK && response != NULL) {
1162 CHECK(response->findInt32("err", &err));
1163 }
1164
1165 return err;
1166}
1167
1168void NuPlayer::GenericSource::onSelectTrack(sp<AMessage> msg) {
1169 int32_t trackIndex, select;
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001170 int64_t timeUs;
Robert Shih17f6dd62014-08-20 17:00:21 -07001171 CHECK(msg->findInt32("trackIndex", &trackIndex));
1172 CHECK(msg->findInt32("select", &select));
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001173 CHECK(msg->findInt64("timeUs", &timeUs));
Robert Shih17f6dd62014-08-20 17:00:21 -07001174
1175 sp<AMessage> response = new AMessage;
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001176 status_t err = doSelectTrack(trackIndex, select, timeUs);
Robert Shih17f6dd62014-08-20 17:00:21 -07001177 response->setInt32("err", err);
1178
Lajos Molnar3f274362015-03-05 14:35:41 -08001179 sp<AReplyToken> replyID;
Robert Shih17f6dd62014-08-20 17:00:21 -07001180 CHECK(msg->senderAwaitsResponse(&replyID));
1181 response->postReply(replyID);
1182}
1183
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001184status_t NuPlayer::GenericSource::doSelectTrack(size_t trackIndex, bool select, int64_t timeUs) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001185 if (trackIndex >= mSources.size()) {
1186 return BAD_INDEX;
1187 }
1188
1189 if (!select) {
Lajos Molnare26940f2014-07-31 10:31:26 -07001190 Track* track = NULL;
1191 if (mSubtitleTrack.mSource != NULL && trackIndex == mSubtitleTrack.mIndex) {
1192 track = &mSubtitleTrack;
1193 mFetchSubtitleDataGeneration++;
1194 } else if (mTimedTextTrack.mSource != NULL && trackIndex == mTimedTextTrack.mIndex) {
1195 track = &mTimedTextTrack;
1196 mFetchTimedTextDataGeneration++;
1197 }
1198 if (track == NULL) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001199 return INVALID_OPERATION;
1200 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001201 track->mSource->stop();
1202 track->mSource = NULL;
1203 track->mPackets->clear();
Robert Shih3423bbd2014-07-16 15:47:09 -07001204 return OK;
1205 }
1206
1207 const sp<MediaSource> source = mSources.itemAt(trackIndex);
1208 sp<MetaData> meta = source->getFormat();
1209 const char *mime;
1210 CHECK(meta->findCString(kKeyMIMEType, &mime));
1211 if (!strncasecmp(mime, "text/", 5)) {
Lajos Molnare26940f2014-07-31 10:31:26 -07001212 bool isSubtitle = strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP);
1213 Track *track = isSubtitle ? &mSubtitleTrack : &mTimedTextTrack;
1214 if (track->mSource != NULL && track->mIndex == trackIndex) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001215 return OK;
1216 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001217 track->mIndex = trackIndex;
1218 if (track->mSource != NULL) {
1219 track->mSource->stop();
Robert Shih3423bbd2014-07-16 15:47:09 -07001220 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001221 track->mSource = mSources.itemAt(trackIndex);
1222 track->mSource->start();
1223 if (track->mPackets == NULL) {
1224 track->mPackets = new AnotherPacketSource(track->mSource->getFormat());
Robert Shih3423bbd2014-07-16 15:47:09 -07001225 } else {
Lajos Molnare26940f2014-07-31 10:31:26 -07001226 track->mPackets->clear();
1227 track->mPackets->setFormat(track->mSource->getFormat());
Robert Shih3423bbd2014-07-16 15:47:09 -07001228
1229 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001230
1231 if (isSubtitle) {
1232 mFetchSubtitleDataGeneration++;
1233 } else {
1234 mFetchTimedTextDataGeneration++;
1235 }
1236
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001237 status_t eosResult; // ignored
1238 if (mSubtitleTrack.mSource != NULL
1239 && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
Lajos Molnar1d15ab52015-03-04 16:46:34 -08001240 sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, this);
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001241 msg->setInt64("timeUs", timeUs);
1242 msg->setInt32("generation", mFetchSubtitleDataGeneration);
1243 msg->post();
1244 }
1245
1246 if (mTimedTextTrack.mSource != NULL
1247 && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
Lajos Molnar1d15ab52015-03-04 16:46:34 -08001248 sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, this);
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001249 msg->setInt64("timeUs", timeUs);
1250 msg->setInt32("generation", mFetchTimedTextDataGeneration);
1251 msg->post();
1252 }
1253
Robert Shih3423bbd2014-07-16 15:47:09 -07001254 return OK;
1255 } else if (!strncasecmp(mime, "audio/", 6) || !strncasecmp(mime, "video/", 6)) {
1256 bool audio = !strncasecmp(mime, "audio/", 6);
1257 Track *track = audio ? &mAudioTrack : &mVideoTrack;
1258 if (track->mSource != NULL && track->mIndex == trackIndex) {
1259 return OK;
1260 }
1261
Lajos Molnar1d15ab52015-03-04 16:46:34 -08001262 sp<AMessage> msg = new AMessage(kWhatChangeAVSource, this);
Robert Shih3423bbd2014-07-16 15:47:09 -07001263 msg->setInt32("trackIndex", trackIndex);
1264 msg->post();
1265 return OK;
1266 }
1267
1268 return INVALID_OPERATION;
1269}
1270
Andreas Huberafed0e12011-09-20 15:39:58 -07001271status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) {
Lajos Molnar1d15ab52015-03-04 16:46:34 -08001272 sp<AMessage> msg = new AMessage(kWhatSeek, this);
Robert Shih17f6dd62014-08-20 17:00:21 -07001273 msg->setInt64("seekTimeUs", seekTimeUs);
1274
1275 sp<AMessage> response;
1276 status_t err = msg->postAndAwaitResponse(&response);
1277 if (err == OK && response != NULL) {
1278 CHECK(response->findInt32("err", &err));
1279 }
1280
1281 return err;
1282}
1283
1284void NuPlayer::GenericSource::onSeek(sp<AMessage> msg) {
1285 int64_t seekTimeUs;
1286 CHECK(msg->findInt64("seekTimeUs", &seekTimeUs));
1287
1288 sp<AMessage> response = new AMessage;
1289 status_t err = doSeek(seekTimeUs);
1290 response->setInt32("err", err);
1291
Lajos Molnar3f274362015-03-05 14:35:41 -08001292 sp<AReplyToken> replyID;
Robert Shih17f6dd62014-08-20 17:00:21 -07001293 CHECK(msg->senderAwaitsResponse(&replyID));
1294 response->postReply(replyID);
1295}
1296
1297status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs) {
Andy Hung2abde2c2014-09-30 14:40:32 -07001298 // If the Widevine source is stopped, do not attempt to read any
1299 // more buffers.
1300 if (mStopRead) {
1301 return INVALID_OPERATION;
1302 }
Andreas Huberafed0e12011-09-20 15:39:58 -07001303 if (mVideoTrack.mSource != NULL) {
1304 int64_t actualTimeUs;
Robert Shih3423bbd2014-07-16 15:47:09 -07001305 readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, &actualTimeUs);
Andreas Huberafed0e12011-09-20 15:39:58 -07001306
1307 seekTimeUs = actualTimeUs;
Robert Shih5c67ddc2014-11-04 17:46:05 -08001308 mVideoLastDequeueTimeUs = seekTimeUs;
Andreas Huberafed0e12011-09-20 15:39:58 -07001309 }
1310
1311 if (mAudioTrack.mSource != NULL) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001312 readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs);
Robert Shih5c67ddc2014-11-04 17:46:05 -08001313 mAudioLastDequeueTimeUs = seekTimeUs;
Andreas Huberafed0e12011-09-20 15:39:58 -07001314 }
1315
Ronghua Wu80276872014-08-28 15:50:29 -07001316 setDrmPlaybackStatusIfNeeded(Playback::START, seekTimeUs / 1000);
1317 if (!mStarted) {
1318 setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0);
1319 }
Chong Zhangefbb6192015-01-30 17:13:27 -08001320
1321 // If currently buffering, post kWhatBufferingEnd first, so that
1322 // NuPlayer resumes. Otherwise, if cache hits high watermark
1323 // before new polling happens, no one will resume the playback.
1324 stopBufferingIfNecessary();
1325 restartPollBuffering();
1326
Andreas Huberafed0e12011-09-20 15:39:58 -07001327 return OK;
1328}
1329
Robert Shih3423bbd2014-07-16 15:47:09 -07001330sp<ABuffer> NuPlayer::GenericSource::mediaBufferToABuffer(
1331 MediaBuffer* mb,
1332 media_track_type trackType,
Wei Jia474d7c72014-12-04 15:12:13 -08001333 int64_t /* seekTimeUs */,
Robert Shih3423bbd2014-07-16 15:47:09 -07001334 int64_t *actualTimeUs) {
1335 bool audio = trackType == MEDIA_TRACK_TYPE_AUDIO;
1336 size_t outLength = mb->range_length();
1337
1338 if (audio && mAudioIsVorbis) {
1339 outLength += sizeof(int32_t);
1340 }
1341
1342 sp<ABuffer> ab;
Chong Zhang42e81532014-12-01 13:44:26 -08001343 if (mIsSecure && !audio) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001344 // data is already provided in the buffer
1345 ab = new ABuffer(NULL, mb->range_length());
Robert Shih3423bbd2014-07-16 15:47:09 -07001346 mb->add_ref();
Wei Jia96e92b52014-09-18 17:36:20 -07001347 ab->setMediaBufferBase(mb);
Robert Shih3423bbd2014-07-16 15:47:09 -07001348 } else {
1349 ab = new ABuffer(outLength);
1350 memcpy(ab->data(),
1351 (const uint8_t *)mb->data() + mb->range_offset(),
1352 mb->range_length());
1353 }
1354
1355 if (audio && mAudioIsVorbis) {
1356 int32_t numPageSamples;
1357 if (!mb->meta_data()->findInt32(kKeyValidSamples, &numPageSamples)) {
1358 numPageSamples = -1;
1359 }
1360
1361 uint8_t* abEnd = ab->data() + mb->range_length();
1362 memcpy(abEnd, &numPageSamples, sizeof(numPageSamples));
1363 }
1364
Lajos Molnare26940f2014-07-31 10:31:26 -07001365 sp<AMessage> meta = ab->meta();
1366
Robert Shih3423bbd2014-07-16 15:47:09 -07001367 int64_t timeUs;
1368 CHECK(mb->meta_data()->findInt64(kKeyTime, &timeUs));
Robert Shih3423bbd2014-07-16 15:47:09 -07001369 meta->setInt64("timeUs", timeUs);
1370
Wei Jia474d7c72014-12-04 15:12:13 -08001371#if 0
1372 // Temporarily disable pre-roll till we have a full solution to handle
1373 // both single seek and continous seek gracefully.
1374 if (seekTimeUs > timeUs) {
1375 sp<AMessage> extra = new AMessage;
1376 extra->setInt64("resume-at-mediaTimeUs", seekTimeUs);
1377 meta->setMessage("extra", extra);
1378 }
1379#endif
1380
Lajos Molnare26940f2014-07-31 10:31:26 -07001381 if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) {
1382 const char *mime;
1383 CHECK(mTimedTextTrack.mSource != NULL
1384 && mTimedTextTrack.mSource->getFormat()->findCString(kKeyMIMEType, &mime));
1385 meta->setString("mime", mime);
1386 }
1387
Robert Shih3423bbd2014-07-16 15:47:09 -07001388 int64_t durationUs;
1389 if (mb->meta_data()->findInt64(kKeyDuration, &durationUs)) {
1390 meta->setInt64("durationUs", durationUs);
1391 }
1392
1393 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
1394 meta->setInt32("trackIndex", mSubtitleTrack.mIndex);
1395 }
1396
1397 if (actualTimeUs) {
1398 *actualTimeUs = timeUs;
1399 }
1400
1401 mb->release();
1402 mb = NULL;
1403
1404 return ab;
1405}
1406
Robert Shih17f6dd62014-08-20 17:00:21 -07001407void NuPlayer::GenericSource::postReadBuffer(media_track_type trackType) {
Lajos Molnar84f52782014-09-11 10:01:55 -07001408 Mutex::Autolock _l(mReadBufferLock);
1409
1410 if ((mPendingReadBufferTypes & (1 << trackType)) == 0) {
1411 mPendingReadBufferTypes |= (1 << trackType);
Lajos Molnar1d15ab52015-03-04 16:46:34 -08001412 sp<AMessage> msg = new AMessage(kWhatReadBuffer, this);
Lajos Molnar84f52782014-09-11 10:01:55 -07001413 msg->setInt32("trackType", trackType);
1414 msg->post();
1415 }
Robert Shih17f6dd62014-08-20 17:00:21 -07001416}
1417
1418void NuPlayer::GenericSource::onReadBuffer(sp<AMessage> msg) {
1419 int32_t tmpType;
1420 CHECK(msg->findInt32("trackType", &tmpType));
1421 media_track_type trackType = (media_track_type)tmpType;
Chong Zhang42e81532014-12-01 13:44:26 -08001422 readBuffer(trackType);
Lajos Molnar84f52782014-09-11 10:01:55 -07001423 {
1424 // only protect the variable change, as readBuffer may
Chong Zhang42e81532014-12-01 13:44:26 -08001425 // take considerable time.
Lajos Molnar84f52782014-09-11 10:01:55 -07001426 Mutex::Autolock _l(mReadBufferLock);
1427 mPendingReadBufferTypes &= ~(1 << trackType);
1428 }
Robert Shih17f6dd62014-08-20 17:00:21 -07001429}
1430
Andreas Huberafed0e12011-09-20 15:39:58 -07001431void NuPlayer::GenericSource::readBuffer(
Robert Shih3423bbd2014-07-16 15:47:09 -07001432 media_track_type trackType, int64_t seekTimeUs, int64_t *actualTimeUs, bool formatChange) {
Andy Hung2abde2c2014-09-30 14:40:32 -07001433 // Do not read data if Widevine source is stopped
1434 if (mStopRead) {
1435 return;
1436 }
Robert Shih3423bbd2014-07-16 15:47:09 -07001437 Track *track;
Phil Burkc5cc2e22014-09-09 20:08:39 -07001438 size_t maxBuffers = 1;
Robert Shih3423bbd2014-07-16 15:47:09 -07001439 switch (trackType) {
1440 case MEDIA_TRACK_TYPE_VIDEO:
1441 track = &mVideoTrack;
Jeff Tinkera28785a2014-09-23 22:24:26 -07001442 if (mIsWidevine) {
1443 maxBuffers = 2;
1444 }
Robert Shih3423bbd2014-07-16 15:47:09 -07001445 break;
1446 case MEDIA_TRACK_TYPE_AUDIO:
1447 track = &mAudioTrack;
Jeff Tinkera28785a2014-09-23 22:24:26 -07001448 if (mIsWidevine) {
1449 maxBuffers = 8;
1450 } else {
1451 maxBuffers = 64;
1452 }
Robert Shih3423bbd2014-07-16 15:47:09 -07001453 break;
1454 case MEDIA_TRACK_TYPE_SUBTITLE:
1455 track = &mSubtitleTrack;
1456 break;
Lajos Molnare26940f2014-07-31 10:31:26 -07001457 case MEDIA_TRACK_TYPE_TIMEDTEXT:
1458 track = &mTimedTextTrack;
1459 break;
Robert Shih3423bbd2014-07-16 15:47:09 -07001460 default:
1461 TRESPASS();
1462 }
1463
1464 if (track->mSource == NULL) {
1465 return;
1466 }
Andreas Huberafed0e12011-09-20 15:39:58 -07001467
1468 if (actualTimeUs) {
1469 *actualTimeUs = seekTimeUs;
1470 }
1471
1472 MediaSource::ReadOptions options;
1473
1474 bool seeking = false;
1475
1476 if (seekTimeUs >= 0) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001477 options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
Andreas Huberafed0e12011-09-20 15:39:58 -07001478 seeking = true;
1479 }
1480
Chong Zhang42e81532014-12-01 13:44:26 -08001481 if (mIsWidevine) {
Lajos Molnarcc227032014-07-17 15:33:06 -07001482 options.setNonBlocking();
1483 }
1484
Phil Burkc5cc2e22014-09-09 20:08:39 -07001485 for (size_t numBuffers = 0; numBuffers < maxBuffers; ) {
Andreas Huberafed0e12011-09-20 15:39:58 -07001486 MediaBuffer *mbuf;
1487 status_t err = track->mSource->read(&mbuf, &options);
1488
1489 options.clearSeekTo();
1490
1491 if (err == OK) {
Ronghua Wu80276872014-08-28 15:50:29 -07001492 int64_t timeUs;
1493 CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs));
1494 if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
1495 mAudioTimeUs = timeUs;
1496 } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
1497 mVideoTimeUs = timeUs;
1498 }
1499
Robert Shih3423bbd2014-07-16 15:47:09 -07001500 // formatChange && seeking: track whose source is changed during selection
1501 // formatChange && !seeking: track whose source is not changed during selection
1502 // !formatChange: normal seek
Lajos Molnare26940f2014-07-31 10:31:26 -07001503 if ((seeking || formatChange)
1504 && (trackType == MEDIA_TRACK_TYPE_AUDIO
1505 || trackType == MEDIA_TRACK_TYPE_VIDEO)) {
Wei Jiafef808d2014-10-31 17:57:05 -07001506 ATSParser::DiscontinuityType type = (formatChange && seeking)
1507 ? ATSParser::DISCONTINUITY_FORMATCHANGE
1508 : ATSParser::DISCONTINUITY_NONE;
Robert Shih3423bbd2014-07-16 15:47:09 -07001509 track->mPackets->queueDiscontinuity( type, NULL, true /* discard */);
Andreas Huberafed0e12011-09-20 15:39:58 -07001510 }
1511
Wei Jia474d7c72014-12-04 15:12:13 -08001512 sp<ABuffer> buffer = mediaBufferToABuffer(
1513 mbuf, trackType, seekTimeUs, actualTimeUs);
Andreas Huberafed0e12011-09-20 15:39:58 -07001514 track->mPackets->queueAccessUnit(buffer);
Marco Nelissen317a49a2014-09-16 21:32:33 -07001515 formatChange = false;
1516 seeking = false;
Phil Burkc5cc2e22014-09-09 20:08:39 -07001517 ++numBuffers;
Lajos Molnarcc227032014-07-17 15:33:06 -07001518 } else if (err == WOULD_BLOCK) {
1519 break;
Andreas Huberafed0e12011-09-20 15:39:58 -07001520 } else if (err == INFO_FORMAT_CHANGED) {
1521#if 0
1522 track->mPackets->queueDiscontinuity(
Chong Zhang632740c2014-06-26 13:03:47 -07001523 ATSParser::DISCONTINUITY_FORMATCHANGE,
1524 NULL,
1525 false /* discard */);
Andreas Huberafed0e12011-09-20 15:39:58 -07001526#endif
1527 } else {
1528 track->mPackets->signalEOS(err);
1529 break;
1530 }
1531 }
1532}
1533
Andreas Huberafed0e12011-09-20 15:39:58 -07001534} // namespace android