blob: 95f07091885f19dbfeae0bd90bd7046c4b0f919a [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),
Marco Nelissen02fc5e32015-05-27 11:20:41 -070059 mDurationUs(-1ll),
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
Chris Watkins99f31602015-03-20 13:06:33 -0700127status_t NuPlayer::GenericSource::setDataSource(const sp<DataSource>& source) {
128 resetDataSource();
129 mDataSource = source;
130 return OK;
131}
132
Marco Nelissenf0b72b52014-09-16 15:43:44 -0700133sp<MetaData> NuPlayer::GenericSource::getFileFormatMeta() const {
134 return mFileMeta;
135}
136
Chong Zhangd354d8d2014-08-20 13:09:58 -0700137status_t NuPlayer::GenericSource::initFromDataSource() {
Lajos Molnarcc227032014-07-17 15:33:06 -0700138 sp<MediaExtractor> extractor;
Chong Zhangfc6cfd82015-02-19 16:39:59 -0800139 String8 mimeType;
140 float confidence;
141 sp<AMessage> dummy;
142 bool isWidevineStreaming = false;
Lajos Molnarcc227032014-07-17 15:33:06 -0700143
Chong Zhangd354d8d2014-08-20 13:09:58 -0700144 CHECK(mDataSource != NULL);
145
Lajos Molnarcc227032014-07-17 15:33:06 -0700146 if (mIsWidevine) {
Chong Zhangfc6cfd82015-02-19 16:39:59 -0800147 isWidevineStreaming = SniffWVM(
148 mDataSource, &mimeType, &confidence, &dummy);
149 if (!isWidevineStreaming ||
150 strcasecmp(
Lajos Molnarcc227032014-07-17 15:33:06 -0700151 mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) {
152 ALOGE("unsupported widevine mime: %s", mimeType.string());
Chong Zhang3de157d2014-08-05 20:54:44 -0700153 return UNKNOWN_ERROR;
Lajos Molnarcc227032014-07-17 15:33:06 -0700154 }
Chong Zhangfc6cfd82015-02-19 16:39:59 -0800155 } else if (mIsStreaming) {
Chong Zhangc287cad2015-02-19 18:30:30 -0800156 if (!mDataSource->sniff(&mimeType, &confidence, &dummy)) {
157 return UNKNOWN_ERROR;
Chong Zhangfc6cfd82015-02-19 16:39:59 -0800158 }
159 isWidevineStreaming = !strcasecmp(
Chong Zhangc287cad2015-02-19 18:30:30 -0800160 mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM);
Chong Zhangfc6cfd82015-02-19 16:39:59 -0800161 }
Lajos Molnarcc227032014-07-17 15:33:06 -0700162
Chong Zhangfc6cfd82015-02-19 16:39:59 -0800163 if (isWidevineStreaming) {
164 // we don't want cached source for widevine streaming.
165 mCachedSource.clear();
166 mDataSource = mHttpSource;
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700167 mWVMExtractor = new WVMExtractor(mDataSource);
168 mWVMExtractor->setAdaptiveStreamingMode(true);
Lajos Molnarcc227032014-07-17 15:33:06 -0700169 if (mUIDValid) {
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700170 mWVMExtractor->setUID(mUID);
Lajos Molnarcc227032014-07-17 15:33:06 -0700171 }
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700172 extractor = mWVMExtractor;
Lajos Molnarcc227032014-07-17 15:33:06 -0700173 } else {
Chong Zhangd354d8d2014-08-20 13:09:58 -0700174 extractor = MediaExtractor::Create(mDataSource,
Chong Zhangc287cad2015-02-19 18:30:30 -0800175 mimeType.isEmpty() ? NULL : mimeType.string());
Lajos Molnarcc227032014-07-17 15:33:06 -0700176 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700177
Chong Zhang3de157d2014-08-05 20:54:44 -0700178 if (extractor == NULL) {
179 return UNKNOWN_ERROR;
180 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700181
Ronghua Wu80276872014-08-28 15:50:29 -0700182 if (extractor->getDrmFlag()) {
183 checkDrmStatus(mDataSource);
184 }
185
Marco Nelissenf0b72b52014-09-16 15:43:44 -0700186 mFileMeta = extractor->getMetaData();
187 if (mFileMeta != NULL) {
Marco Nelissenc1f4b2b2014-06-17 14:48:32 -0700188 int64_t duration;
Marco Nelissenf0b72b52014-09-16 15:43:44 -0700189 if (mFileMeta->findInt64(kKeyDuration, &duration)) {
Marco Nelissenc1f4b2b2014-06-17 14:48:32 -0700190 mDurationUs = duration;
191 }
Chong Zhang42e81532014-12-01 13:44:26 -0800192
193 if (!mIsWidevine) {
194 // Check mime to see if we actually have a widevine source.
195 // If the data source is not URL-type (eg. file source), we
196 // won't be able to tell until now.
197 const char *fileMime;
198 if (mFileMeta->findCString(kKeyMIMEType, &fileMime)
199 && !strncasecmp(fileMime, "video/wvm", 9)) {
200 mIsWidevine = true;
201 }
202 }
Marco Nelissenc1f4b2b2014-06-17 14:48:32 -0700203 }
204
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700205 int32_t totalBitrate = 0;
206
Marco Nelissen705d3292014-09-19 15:14:37 -0700207 size_t numtracks = extractor->countTracks();
208 if (numtracks == 0) {
209 return UNKNOWN_ERROR;
210 }
211
212 for (size_t i = 0; i < numtracks; ++i) {
Chong Zhangafc0a872014-08-26 09:56:52 -0700213 sp<MediaSource> track = extractor->getTrack(i);
214
Andreas Huberafed0e12011-09-20 15:39:58 -0700215 sp<MetaData> meta = extractor->getTrackMetaData(i);
216
217 const char *mime;
218 CHECK(meta->findCString(kKeyMIMEType, &mime));
219
Chong Zhangafc0a872014-08-26 09:56:52 -0700220 // Do the string compare immediately with "mime",
221 // we can't assume "mime" would stay valid after another
222 // extractor operation, some extractors might modify meta
223 // during getTrack() and make it invalid.
Andreas Huberafed0e12011-09-20 15:39:58 -0700224 if (!strncasecmp(mime, "audio/", 6)) {
225 if (mAudioTrack.mSource == NULL) {
Robert Shihdd235722014-06-12 14:49:23 -0700226 mAudioTrack.mIndex = i;
227 mAudioTrack.mSource = track;
Robert Shihaf52c1a2014-09-11 15:38:54 -0700228 mAudioTrack.mPackets =
229 new AnotherPacketSource(mAudioTrack.mSource->getFormat());
Andreas Huberafed0e12011-09-20 15:39:58 -0700230
231 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
232 mAudioIsVorbis = true;
233 } else {
234 mAudioIsVorbis = false;
235 }
236 }
237 } else if (!strncasecmp(mime, "video/", 6)) {
238 if (mVideoTrack.mSource == NULL) {
Robert Shihdd235722014-06-12 14:49:23 -0700239 mVideoTrack.mIndex = i;
240 mVideoTrack.mSource = track;
Robert Shihaf52c1a2014-09-11 15:38:54 -0700241 mVideoTrack.mPackets =
242 new AnotherPacketSource(mVideoTrack.mSource->getFormat());
Chong Zhang7e892182014-08-05 11:58:21 -0700243
244 // check if the source requires secure buffers
245 int32_t secure;
Chong Zhanga19f33e2014-08-07 15:35:07 -0700246 if (meta->findInt32(kKeyRequiresSecureBuffers, &secure)
247 && secure) {
Chong Zhang42e81532014-12-01 13:44:26 -0800248 mIsSecure = true;
Chong Zhang3de157d2014-08-05 20:54:44 -0700249 if (mUIDValid) {
250 extractor->setUID(mUID);
251 }
Chong Zhang7e892182014-08-05 11:58:21 -0700252 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700253 }
254 }
255
256 if (track != NULL) {
Robert Shihdd235722014-06-12 14:49:23 -0700257 mSources.push(track);
Andreas Huberafed0e12011-09-20 15:39:58 -0700258 int64_t durationUs;
259 if (meta->findInt64(kKeyDuration, &durationUs)) {
260 if (durationUs > mDurationUs) {
261 mDurationUs = durationUs;
262 }
263 }
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700264
265 int32_t bitrate;
266 if (totalBitrate >= 0 && meta->findInt32(kKeyBitRate, &bitrate)) {
267 totalBitrate += bitrate;
268 } else {
269 totalBitrate = -1;
270 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700271 }
272 }
Chong Zhang3de157d2014-08-05 20:54:44 -0700273
Lajos Molnarfcd3e942015-03-31 10:06:48 -0700274 mBitrate = totalBitrate;
275
276 return OK;
277}
278
279status_t NuPlayer::GenericSource::startSources() {
Chong Zhangefbb6192015-01-30 17:13:27 -0800280 // Start the selected A/V tracks now before we start buffering.
281 // Widevine sources might re-initialize crypto when starting, if we delay
282 // this to start(), all data buffered during prepare would be wasted.
283 // (We don't actually start reading until start().)
284 if (mAudioTrack.mSource != NULL && mAudioTrack.mSource->start() != OK) {
285 ALOGE("failed to start audio track!");
286 return UNKNOWN_ERROR;
287 }
288
289 if (mVideoTrack.mSource != NULL && mVideoTrack.mSource->start() != OK) {
290 ALOGE("failed to start video track!");
291 return UNKNOWN_ERROR;
292 }
293
Chong Zhang3de157d2014-08-05 20:54:44 -0700294 return OK;
Andreas Huberafed0e12011-09-20 15:39:58 -0700295}
296
Ronghua Wu80276872014-08-28 15:50:29 -0700297void NuPlayer::GenericSource::checkDrmStatus(const sp<DataSource>& dataSource) {
298 dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
299 if (mDecryptHandle != NULL) {
300 CHECK(mDrmManagerClient);
301 if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
302 sp<AMessage> msg = dupNotify();
303 msg->setInt32("what", kWhatDrmNoLicense);
304 msg->post();
305 }
306 }
307}
308
309int64_t NuPlayer::GenericSource::getLastReadPosition() {
310 if (mAudioTrack.mSource != NULL) {
311 return mAudioTimeUs;
312 } else if (mVideoTrack.mSource != NULL) {
313 return mVideoTimeUs;
314 } else {
315 return 0;
316 }
317}
318
Chong Zhanga19f33e2014-08-07 15:35:07 -0700319status_t NuPlayer::GenericSource::setBuffers(
320 bool audio, Vector<MediaBuffer *> &buffers) {
Chong Zhang42e81532014-12-01 13:44:26 -0800321 if (mIsSecure && !audio) {
Lajos Molnarcc227032014-07-17 15:33:06 -0700322 return mVideoTrack.mSource->setBuffers(buffers);
323 }
324 return INVALID_OPERATION;
325}
326
Andreas Huberafed0e12011-09-20 15:39:58 -0700327NuPlayer::GenericSource::~GenericSource() {
Chong Zhang1228d6b2014-08-12 21:25:48 -0700328 if (mLooper != NULL) {
329 mLooper->unregisterHandler(id());
330 mLooper->stop();
331 }
Chong Zhanga6bf21f2014-11-19 20:26:34 -0800332 resetDataSource();
Andreas Huberafed0e12011-09-20 15:39:58 -0700333}
334
Andreas Huber9575c962013-02-05 13:59:56 -0800335void NuPlayer::GenericSource::prepareAsync() {
Chong Zhang1228d6b2014-08-12 21:25:48 -0700336 if (mLooper == NULL) {
337 mLooper = new ALooper;
338 mLooper->setName("generic");
339 mLooper->start();
340
341 mLooper->registerHandler(this);
342 }
343
Lajos Molnar1d15ab52015-03-04 16:46:34 -0800344 sp<AMessage> msg = new AMessage(kWhatPrepareAsync, this);
Chong Zhang1228d6b2014-08-12 21:25:48 -0700345 msg->post();
346}
347
348void NuPlayer::GenericSource::onPrepareAsync() {
Chong Zhanga19f33e2014-08-07 15:35:07 -0700349 // delayed data source creation
Chong Zhangd354d8d2014-08-20 13:09:58 -0700350 if (mDataSource == NULL) {
Chong Zhang42e81532014-12-01 13:44:26 -0800351 // set to false first, if the extractor
352 // comes back as secure, set it to true then.
353 mIsSecure = false;
354
Chong Zhangd354d8d2014-08-20 13:09:58 -0700355 if (!mUri.empty()) {
Robert Shih360d6d02014-09-29 14:42:35 -0700356 const char* uri = mUri.c_str();
Chong Zhangc287cad2015-02-19 18:30:30 -0800357 String8 contentType;
Robert Shih360d6d02014-09-29 14:42:35 -0700358 mIsWidevine = !strncasecmp(uri, "widevine://", 11);
359
360 if (!strncasecmp("http://", uri, 7)
361 || !strncasecmp("https://", uri, 8)
362 || mIsWidevine) {
363 mHttpSource = DataSource::CreateMediaHTTP(mHTTPService);
364 if (mHttpSource == NULL) {
365 ALOGE("Failed to create http source!");
366 notifyPreparedAndCleanup(UNKNOWN_ERROR);
367 return;
368 }
369 }
Chong Zhanga19f33e2014-08-07 15:35:07 -0700370
Chong Zhangd354d8d2014-08-20 13:09:58 -0700371 mDataSource = DataSource::CreateFromURI(
Chong Zhangc287cad2015-02-19 18:30:30 -0800372 mHTTPService, uri, &mUriHeaders, &contentType,
Robert Shih360d6d02014-09-29 14:42:35 -0700373 static_cast<HTTPBase *>(mHttpSource.get()));
Chong Zhangd354d8d2014-08-20 13:09:58 -0700374 } else {
Chong Zhangd354d8d2014-08-20 13:09:58 -0700375 mIsWidevine = false;
Chong Zhanga19f33e2014-08-07 15:35:07 -0700376
Chong Zhangd354d8d2014-08-20 13:09:58 -0700377 mDataSource = new FileSource(mFd, mOffset, mLength);
Chong Zhanga6bf21f2014-11-19 20:26:34 -0800378 mFd = -1;
Chong Zhangd354d8d2014-08-20 13:09:58 -0700379 }
Chong Zhanga19f33e2014-08-07 15:35:07 -0700380
Chong Zhangd354d8d2014-08-20 13:09:58 -0700381 if (mDataSource == NULL) {
382 ALOGE("Failed to create data source!");
383 notifyPreparedAndCleanup(UNKNOWN_ERROR);
384 return;
385 }
Chong Zhanga19f33e2014-08-07 15:35:07 -0700386 }
387
Chris Watkins99f31602015-03-20 13:06:33 -0700388 if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
389 mCachedSource = static_cast<NuCachedSource2 *>(mDataSource.get());
390 }
391
392 // For widevine or other cached streaming cases, we need to wait for
393 // enough buffering before reporting prepared.
394 // Note that even when URL doesn't start with widevine://, mIsWidevine
395 // could still be set to true later, if the streaming or file source
396 // is sniffed to be widevine. We don't want to buffer for file source
397 // in that case, so must check the flag now.
398 mIsStreaming = (mIsWidevine || mCachedSource != NULL);
399
Chong Zhangc287cad2015-02-19 18:30:30 -0800400 // init extractor from data source
401 status_t err = initFromDataSource();
Chong Zhanga19f33e2014-08-07 15:35:07 -0700402
403 if (err != OK) {
404 ALOGE("Failed to init from data source!");
Chong Zhangd354d8d2014-08-20 13:09:58 -0700405 notifyPreparedAndCleanup(err);
Chong Zhanga19f33e2014-08-07 15:35:07 -0700406 return;
407 }
408
Andreas Huber9575c962013-02-05 13:59:56 -0800409 if (mVideoTrack.mSource != NULL) {
Robert Shih17f6dd62014-08-20 17:00:21 -0700410 sp<MetaData> meta = doGetFormatMeta(false /* audio */);
411 sp<AMessage> msg = new AMessage;
412 err = convertMetaDataToMessage(meta, &msg);
413 if(err != OK) {
414 notifyPreparedAndCleanup(err);
415 return;
416 }
417 notifyVideoSizeChanged(msg);
Andreas Huber9575c962013-02-05 13:59:56 -0800418 }
419
420 notifyFlagsChanged(
Chong Zhang42e81532014-12-01 13:44:26 -0800421 (mIsSecure ? FLAG_SECURE : 0)
Chong Zhang17134602015-01-07 16:14:34 -0800422 | (mDecryptHandle != NULL ? FLAG_PROTECTED : 0)
Lajos Molnarcc227032014-07-17 15:33:06 -0700423 | FLAG_CAN_PAUSE
Andreas Huber9575c962013-02-05 13:59:56 -0800424 | FLAG_CAN_SEEK_BACKWARD
425 | FLAG_CAN_SEEK_FORWARD
426 | FLAG_CAN_SEEK);
427
Lajos Molnarfcd3e942015-03-31 10:06:48 -0700428 if (mIsSecure) {
429 // secure decoders must be instantiated before starting widevine source
430 sp<AMessage> reply = new AMessage(kWhatSecureDecodersInstantiated, this);
431 notifyInstantiateSecureDecoders(reply);
432 } else {
433 finishPrepareAsync();
434 }
435}
436
437void NuPlayer::GenericSource::onSecureDecodersInstantiated(status_t err) {
438 if (err != OK) {
439 ALOGE("Failed to instantiate secure decoders!");
440 notifyPreparedAndCleanup(err);
441 return;
442 }
443 finishPrepareAsync();
444}
445
446void NuPlayer::GenericSource::finishPrepareAsync() {
447 status_t err = startSources();
448 if (err != OK) {
449 ALOGE("Failed to init start data source!");
450 notifyPreparedAndCleanup(err);
451 return;
452 }
453
Chong Zhangefbb6192015-01-30 17:13:27 -0800454 if (mIsStreaming) {
455 mPrepareBuffering = true;
456
457 ensureCacheIsFetching();
458 restartPollBuffering();
459 } else {
460 notifyPrepared();
461 }
Andreas Huber9575c962013-02-05 13:59:56 -0800462}
463
Chong Zhangd354d8d2014-08-20 13:09:58 -0700464void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) {
465 if (err != OK) {
Chong Zhangd354d8d2014-08-20 13:09:58 -0700466 mDataSource.clear();
467 mCachedSource.clear();
Robert Shih360d6d02014-09-29 14:42:35 -0700468 mHttpSource.clear();
Lajos Molnarfcd3e942015-03-31 10:06:48 -0700469 mBitrate = -1;
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700470
471 cancelPollBuffering();
Chong Zhangd354d8d2014-08-20 13:09:58 -0700472 }
473 notifyPrepared(err);
474}
475
Andreas Huberafed0e12011-09-20 15:39:58 -0700476void NuPlayer::GenericSource::start() {
477 ALOGI("start");
478
Andy Hung2abde2c2014-09-30 14:40:32 -0700479 mStopRead = false;
Andreas Huberafed0e12011-09-20 15:39:58 -0700480 if (mAudioTrack.mSource != NULL) {
Robert Shih17f6dd62014-08-20 17:00:21 -0700481 postReadBuffer(MEDIA_TRACK_TYPE_AUDIO);
Andreas Huberafed0e12011-09-20 15:39:58 -0700482 }
483
484 if (mVideoTrack.mSource != NULL) {
Robert Shih17f6dd62014-08-20 17:00:21 -0700485 postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
Andreas Huberafed0e12011-09-20 15:39:58 -0700486 }
Ronghua Wu80276872014-08-28 15:50:29 -0700487
488 setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000);
489 mStarted = true;
Chong Zhangefbb6192015-01-30 17:13:27 -0800490
Lajos Molnar1d15ab52015-03-04 16:46:34 -0800491 (new AMessage(kWhatStart, this))->post();
Ronghua Wu80276872014-08-28 15:50:29 -0700492}
493
494void NuPlayer::GenericSource::stop() {
495 // nothing to do, just account for DRM playback status
496 setDrmPlaybackStatusIfNeeded(Playback::STOP, 0);
497 mStarted = false;
Chong Zhang42e81532014-12-01 13:44:26 -0800498 if (mIsWidevine || mIsSecure) {
499 // For widevine or secure sources we need to prevent any further reads.
Lajos Molnar1d15ab52015-03-04 16:46:34 -0800500 sp<AMessage> msg = new AMessage(kWhatStopWidevine, this);
Andy Hung2abde2c2014-09-30 14:40:32 -0700501 sp<AMessage> response;
502 (void) msg->postAndAwaitResponse(&response);
503 }
Ronghua Wu80276872014-08-28 15:50:29 -0700504}
505
506void NuPlayer::GenericSource::pause() {
507 // nothing to do, just account for DRM playback status
508 setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0);
509 mStarted = false;
510}
511
512void NuPlayer::GenericSource::resume() {
513 // nothing to do, just account for DRM playback status
514 setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000);
515 mStarted = true;
Chong Zhangefbb6192015-01-30 17:13:27 -0800516
Lajos Molnar1d15ab52015-03-04 16:46:34 -0800517 (new AMessage(kWhatResume, this))->post();
Ronghua Wu80276872014-08-28 15:50:29 -0700518}
519
Chong Zhang48296b72014-09-14 14:28:45 -0700520void NuPlayer::GenericSource::disconnect() {
521 if (mDataSource != NULL) {
522 // disconnect data source
523 if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
524 static_cast<NuCachedSource2 *>(mDataSource.get())->disconnect();
525 }
Robert Shih360d6d02014-09-29 14:42:35 -0700526 } else if (mHttpSource != NULL) {
527 static_cast<HTTPBase *>(mHttpSource.get())->disconnect();
Chong Zhang48296b72014-09-14 14:28:45 -0700528 }
529}
530
Ronghua Wu80276872014-08-28 15:50:29 -0700531void NuPlayer::GenericSource::setDrmPlaybackStatusIfNeeded(int playbackStatus, int64_t position) {
532 if (mDecryptHandle != NULL) {
533 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, playbackStatus, position);
534 }
Robert Shih17f6dd62014-08-20 17:00:21 -0700535 mSubtitleTrack.mPackets = new AnotherPacketSource(NULL);
536 mTimedTextTrack.mPackets = new AnotherPacketSource(NULL);
Andreas Huberafed0e12011-09-20 15:39:58 -0700537}
538
539status_t NuPlayer::GenericSource::feedMoreTSData() {
540 return OK;
541}
542
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700543void NuPlayer::GenericSource::schedulePollBuffering() {
Lajos Molnar1d15ab52015-03-04 16:46:34 -0800544 sp<AMessage> msg = new AMessage(kWhatPollBuffering, this);
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700545 msg->setInt32("generation", mPollBufferingGeneration);
546 msg->post(1000000ll);
547}
548
549void NuPlayer::GenericSource::cancelPollBuffering() {
Chong Zhangefbb6192015-01-30 17:13:27 -0800550 mBuffering = false;
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700551 ++mPollBufferingGeneration;
Chong Zhangc287cad2015-02-19 18:30:30 -0800552 mPrevBufferPercentage = -1;
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700553}
554
Chong Zhangefbb6192015-01-30 17:13:27 -0800555void NuPlayer::GenericSource::restartPollBuffering() {
556 if (mIsStreaming) {
557 cancelPollBuffering();
558 onPollBuffering();
559 }
560}
561
Chong Zhangc287cad2015-02-19 18:30:30 -0800562void NuPlayer::GenericSource::notifyBufferingUpdate(int32_t percentage) {
563 // Buffering percent could go backward as it's estimated from remaining
564 // data and last access time. This could cause the buffering position
565 // drawn on media control to jitter slightly. Remember previously reported
566 // percentage and don't allow it to go backward.
567 if (percentage < mPrevBufferPercentage) {
568 percentage = mPrevBufferPercentage;
569 } else if (percentage > 100) {
570 percentage = 100;
571 }
572
573 mPrevBufferPercentage = percentage;
574
Chong Zhangefbb6192015-01-30 17:13:27 -0800575 ALOGV("notifyBufferingUpdate: buffering %d%%", percentage);
576
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700577 sp<AMessage> msg = dupNotify();
578 msg->setInt32("what", kWhatBufferingUpdate);
579 msg->setInt32("percentage", percentage);
580 msg->post();
581}
582
Chong Zhangefbb6192015-01-30 17:13:27 -0800583void NuPlayer::GenericSource::startBufferingIfNecessary() {
584 ALOGV("startBufferingIfNecessary: mPrepareBuffering=%d, mBuffering=%d",
585 mPrepareBuffering, mBuffering);
586
587 if (mPrepareBuffering) {
588 return;
589 }
590
591 if (!mBuffering) {
592 mBuffering = true;
593
594 ensureCacheIsFetching();
595 sendCacheStats();
596
597 sp<AMessage> notify = dupNotify();
598 notify->setInt32("what", kWhatPauseOnBufferingStart);
599 notify->post();
600 }
601}
602
603void NuPlayer::GenericSource::stopBufferingIfNecessary() {
604 ALOGV("stopBufferingIfNecessary: mPrepareBuffering=%d, mBuffering=%d",
605 mPrepareBuffering, mBuffering);
606
607 if (mPrepareBuffering) {
608 mPrepareBuffering = false;
609 notifyPrepared();
610 return;
611 }
612
613 if (mBuffering) {
614 mBuffering = false;
615
616 sendCacheStats();
617
618 sp<AMessage> notify = dupNotify();
619 notify->setInt32("what", kWhatResumeOnBufferingEnd);
620 notify->post();
621 }
622}
623
624void NuPlayer::GenericSource::sendCacheStats() {
625 int32_t kbps = 0;
626 status_t err = UNKNOWN_ERROR;
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700627
Chong Zhangfc6cfd82015-02-19 16:39:59 -0800628 if (mWVMExtractor != NULL) {
Chong Zhangefbb6192015-01-30 17:13:27 -0800629 err = mWVMExtractor->getEstimatedBandwidthKbps(&kbps);
Chong Zhangfc6cfd82015-02-19 16:39:59 -0800630 } else if (mCachedSource != NULL) {
631 err = mCachedSource->getEstimatedBandwidthKbps(&kbps);
Chong Zhangefbb6192015-01-30 17:13:27 -0800632 }
633
634 if (err == OK) {
635 sp<AMessage> notify = dupNotify();
636 notify->setInt32("what", kWhatCacheStats);
637 notify->setInt32("bandwidth", kbps);
638 notify->post();
639 }
640}
641
642void NuPlayer::GenericSource::ensureCacheIsFetching() {
643 if (mCachedSource != NULL) {
644 mCachedSource->resumeFetchingIfNecessary();
645 }
646}
647
648void NuPlayer::GenericSource::onPollBuffering() {
649 status_t finalStatus = UNKNOWN_ERROR;
650 int64_t cachedDurationUs = -1ll;
651 ssize_t cachedDataRemaining = -1;
652
Chong Zhangfc6cfd82015-02-19 16:39:59 -0800653 ALOGW_IF(mWVMExtractor != NULL && mCachedSource != NULL,
654 "WVMExtractor and NuCachedSource both present");
655
656 if (mWVMExtractor != NULL) {
657 cachedDurationUs =
658 mWVMExtractor->getCachedDurationUs(&finalStatus);
659 } else if (mCachedSource != NULL) {
Chong Zhangefbb6192015-01-30 17:13:27 -0800660 cachedDataRemaining =
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700661 mCachedSource->approxDataRemaining(&finalStatus);
662
663 if (finalStatus == OK) {
664 off64_t size;
665 int64_t bitrate = 0ll;
666 if (mDurationUs > 0 && mCachedSource->getSize(&size) == OK) {
667 bitrate = size * 8000000ll / mDurationUs;
668 } else if (mBitrate > 0) {
669 bitrate = mBitrate;
670 }
671 if (bitrate > 0) {
672 cachedDurationUs = cachedDataRemaining * 8000000ll / bitrate;
673 }
674 }
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700675 }
676
Chong Zhangefbb6192015-01-30 17:13:27 -0800677 if (finalStatus != OK) {
678 ALOGV("onPollBuffering: EOS (finalStatus = %d)", finalStatus);
679
680 if (finalStatus == ERROR_END_OF_STREAM) {
681 notifyBufferingUpdate(100);
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700682 }
683
Chong Zhangefbb6192015-01-30 17:13:27 -0800684 stopBufferingIfNecessary();
685 return;
686 } else if (cachedDurationUs >= 0ll) {
687 if (mDurationUs > 0ll) {
688 int64_t cachedPosUs = getLastReadPosition() + cachedDurationUs;
689 int percentage = 100.0 * cachedPosUs / mDurationUs;
690 if (percentage > 100) {
691 percentage = 100;
692 }
693
694 notifyBufferingUpdate(percentage);
695 }
696
697 ALOGV("onPollBuffering: cachedDurationUs %.1f sec",
698 cachedDurationUs / 1000000.0f);
699
700 if (cachedDurationUs < kLowWaterMarkUs) {
701 startBufferingIfNecessary();
702 } else if (cachedDurationUs > kHighWaterMarkUs) {
703 stopBufferingIfNecessary();
704 }
705 } else if (cachedDataRemaining >= 0) {
Lajos Molnar6d339f12015-04-17 16:15:53 -0700706 ALOGV("onPollBuffering: cachedDataRemaining %zd bytes",
Chong Zhangefbb6192015-01-30 17:13:27 -0800707 cachedDataRemaining);
708
709 if (cachedDataRemaining < kLowWaterMarkBytes) {
710 startBufferingIfNecessary();
711 } else if (cachedDataRemaining > kHighWaterMarkBytes) {
712 stopBufferingIfNecessary();
713 }
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700714 }
715
716 schedulePollBuffering();
717}
718
Robert Shih3423bbd2014-07-16 15:47:09 -0700719void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) {
720 switch (msg->what()) {
Chong Zhang1228d6b2014-08-12 21:25:48 -0700721 case kWhatPrepareAsync:
722 {
723 onPrepareAsync();
724 break;
725 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700726 case kWhatFetchSubtitleData:
727 {
Lajos Molnare26940f2014-07-31 10:31:26 -0700728 fetchTextData(kWhatSendSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
729 mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
730 break;
731 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700732
Lajos Molnare26940f2014-07-31 10:31:26 -0700733 case kWhatFetchTimedTextData:
734 {
735 fetchTextData(kWhatSendTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
736 mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
Robert Shih3423bbd2014-07-16 15:47:09 -0700737 break;
738 }
739
740 case kWhatSendSubtitleData:
741 {
Lajos Molnare26940f2014-07-31 10:31:26 -0700742 sendTextData(kWhatSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
743 mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
744 break;
745 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700746
Lajos Molnare26940f2014-07-31 10:31:26 -0700747 case kWhatSendTimedTextData:
748 {
749 sendTextData(kWhatTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
750 mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
Robert Shih3423bbd2014-07-16 15:47:09 -0700751 break;
752 }
753
754 case kWhatChangeAVSource:
755 {
756 int32_t trackIndex;
757 CHECK(msg->findInt32("trackIndex", &trackIndex));
758 const sp<MediaSource> source = mSources.itemAt(trackIndex);
759
760 Track* track;
761 const char *mime;
762 media_track_type trackType, counterpartType;
763 sp<MetaData> meta = source->getFormat();
764 meta->findCString(kKeyMIMEType, &mime);
765 if (!strncasecmp(mime, "audio/", 6)) {
766 track = &mAudioTrack;
767 trackType = MEDIA_TRACK_TYPE_AUDIO;
768 counterpartType = MEDIA_TRACK_TYPE_VIDEO;;
769 } else {
770 CHECK(!strncasecmp(mime, "video/", 6));
771 track = &mVideoTrack;
772 trackType = MEDIA_TRACK_TYPE_VIDEO;
773 counterpartType = MEDIA_TRACK_TYPE_AUDIO;;
774 }
775
776
777 if (track->mSource != NULL) {
778 track->mSource->stop();
779 }
780 track->mSource = source;
781 track->mSource->start();
782 track->mIndex = trackIndex;
783
Robert Shih3423bbd2014-07-16 15:47:09 -0700784 int64_t timeUs, actualTimeUs;
785 const bool formatChange = true;
Robert Shih5c67ddc2014-11-04 17:46:05 -0800786 if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
787 timeUs = mAudioLastDequeueTimeUs;
788 } else {
789 timeUs = mVideoLastDequeueTimeUs;
790 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700791 readBuffer(trackType, timeUs, &actualTimeUs, formatChange);
792 readBuffer(counterpartType, -1, NULL, formatChange);
Lajos Molnar6d339f12015-04-17 16:15:53 -0700793 ALOGV("timeUs %lld actualTimeUs %lld", (long long)timeUs, (long long)actualTimeUs);
Robert Shih3423bbd2014-07-16 15:47:09 -0700794
795 break;
796 }
Chong Zhangefbb6192015-01-30 17:13:27 -0800797
798 case kWhatStart:
799 case kWhatResume:
800 {
801 restartPollBuffering();
802 break;
803 }
804
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700805 case kWhatPollBuffering:
806 {
807 int32_t generation;
808 CHECK(msg->findInt32("generation", &generation));
809 if (generation == mPollBufferingGeneration) {
810 onPollBuffering();
811 }
812 break;
813 }
Robert Shih17f6dd62014-08-20 17:00:21 -0700814
815 case kWhatGetFormat:
816 {
817 onGetFormatMeta(msg);
818 break;
819 }
820
821 case kWhatGetSelectedTrack:
822 {
823 onGetSelectedTrack(msg);
824 break;
825 }
826
827 case kWhatSelectTrack:
828 {
829 onSelectTrack(msg);
830 break;
831 }
832
833 case kWhatSeek:
834 {
835 onSeek(msg);
836 break;
837 }
838
839 case kWhatReadBuffer:
840 {
841 onReadBuffer(msg);
842 break;
843 }
844
Lajos Molnarfcd3e942015-03-31 10:06:48 -0700845 case kWhatSecureDecodersInstantiated:
846 {
847 int32_t err;
848 CHECK(msg->findInt32("err", &err));
849 onSecureDecodersInstantiated(err);
850 break;
851 }
852
Andy Hung2abde2c2014-09-30 14:40:32 -0700853 case kWhatStopWidevine:
854 {
855 // mStopRead is only used for Widevine to prevent the video source
856 // from being read while the associated video decoder is shutting down.
857 mStopRead = true;
858 if (mVideoTrack.mSource != NULL) {
859 mVideoTrack.mPackets->clear();
860 }
861 sp<AMessage> response = new AMessage;
Lajos Molnar3f274362015-03-05 14:35:41 -0800862 sp<AReplyToken> replyID;
Andy Hung2abde2c2014-09-30 14:40:32 -0700863 CHECK(msg->senderAwaitsResponse(&replyID));
864 response->postReply(replyID);
865 break;
866 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700867 default:
868 Source::onMessageReceived(msg);
869 break;
870 }
871}
872
Lajos Molnare26940f2014-07-31 10:31:26 -0700873void NuPlayer::GenericSource::fetchTextData(
874 uint32_t sendWhat,
875 media_track_type type,
876 int32_t curGen,
877 sp<AnotherPacketSource> packets,
878 sp<AMessage> msg) {
879 int32_t msgGeneration;
880 CHECK(msg->findInt32("generation", &msgGeneration));
881 if (msgGeneration != curGen) {
882 // stale
883 return;
884 }
885
886 int32_t avail;
887 if (packets->hasBufferAvailable(&avail)) {
888 return;
889 }
890
891 int64_t timeUs;
892 CHECK(msg->findInt64("timeUs", &timeUs));
893
894 int64_t subTimeUs;
895 readBuffer(type, timeUs, &subTimeUs);
896
897 int64_t delayUs = subTimeUs - timeUs;
898 if (msg->what() == kWhatFetchSubtitleData) {
899 const int64_t oneSecUs = 1000000ll;
900 delayUs -= oneSecUs;
901 }
Lajos Molnar1d15ab52015-03-04 16:46:34 -0800902 sp<AMessage> msg2 = new AMessage(sendWhat, this);
Lajos Molnare26940f2014-07-31 10:31:26 -0700903 msg2->setInt32("generation", msgGeneration);
904 msg2->post(delayUs < 0 ? 0 : delayUs);
905}
906
907void NuPlayer::GenericSource::sendTextData(
908 uint32_t what,
909 media_track_type type,
910 int32_t curGen,
911 sp<AnotherPacketSource> packets,
912 sp<AMessage> msg) {
913 int32_t msgGeneration;
914 CHECK(msg->findInt32("generation", &msgGeneration));
915 if (msgGeneration != curGen) {
916 // stale
917 return;
918 }
919
920 int64_t subTimeUs;
921 if (packets->nextBufferTime(&subTimeUs) != OK) {
922 return;
923 }
924
925 int64_t nextSubTimeUs;
926 readBuffer(type, -1, &nextSubTimeUs);
927
928 sp<ABuffer> buffer;
929 status_t dequeueStatus = packets->dequeueAccessUnit(&buffer);
930 if (dequeueStatus == OK) {
931 sp<AMessage> notify = dupNotify();
932 notify->setInt32("what", what);
933 notify->setBuffer("buffer", buffer);
934 notify->post();
935
936 const int64_t delayUs = nextSubTimeUs - subTimeUs;
937 msg->post(delayUs < 0 ? 0 : delayUs);
938 }
939}
940
Andreas Huber84066782011-08-16 09:34:26 -0700941sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
Lajos Molnar1d15ab52015-03-04 16:46:34 -0800942 sp<AMessage> msg = new AMessage(kWhatGetFormat, this);
Robert Shih17f6dd62014-08-20 17:00:21 -0700943 msg->setInt32("audio", audio);
944
945 sp<AMessage> response;
946 void *format;
947 status_t err = msg->postAndAwaitResponse(&response);
948 if (err == OK && response != NULL) {
949 CHECK(response->findPointer("format", &format));
950 return (MetaData *)format;
951 } else {
952 return NULL;
953 }
954}
955
956void NuPlayer::GenericSource::onGetFormatMeta(sp<AMessage> msg) const {
957 int32_t audio;
958 CHECK(msg->findInt32("audio", &audio));
959
960 sp<AMessage> response = new AMessage;
961 sp<MetaData> format = doGetFormatMeta(audio);
962 response->setPointer("format", format.get());
963
Lajos Molnar3f274362015-03-05 14:35:41 -0800964 sp<AReplyToken> replyID;
Robert Shih17f6dd62014-08-20 17:00:21 -0700965 CHECK(msg->senderAwaitsResponse(&replyID));
966 response->postReply(replyID);
967}
968
969sp<MetaData> NuPlayer::GenericSource::doGetFormatMeta(bool audio) const {
Andreas Huberafed0e12011-09-20 15:39:58 -0700970 sp<MediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
971
972 if (source == NULL) {
973 return NULL;
974 }
975
976 return source->getFormat();
977}
978
979status_t NuPlayer::GenericSource::dequeueAccessUnit(
980 bool audio, sp<ABuffer> *accessUnit) {
981 Track *track = audio ? &mAudioTrack : &mVideoTrack;
982
983 if (track->mSource == NULL) {
984 return -EWOULDBLOCK;
985 }
986
Lajos Molnarcc227032014-07-17 15:33:06 -0700987 if (mIsWidevine && !audio) {
988 // try to read a buffer as we may not have been able to the last time
Robert Shih17f6dd62014-08-20 17:00:21 -0700989 postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
Lajos Molnarcc227032014-07-17 15:33:06 -0700990 }
991
Andreas Huberafed0e12011-09-20 15:39:58 -0700992 status_t finalResult;
993 if (!track->mPackets->hasBufferAvailable(&finalResult)) {
Chong Zhang42e81532014-12-01 13:44:26 -0800994 if (finalResult == OK) {
995 postReadBuffer(
996 audio ? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
997 return -EWOULDBLOCK;
998 }
999 return finalResult;
Andreas Huberafed0e12011-09-20 15:39:58 -07001000 }
1001
1002 status_t result = track->mPackets->dequeueAccessUnit(accessUnit);
1003
Robert Shih3423bbd2014-07-16 15:47:09 -07001004 if (!track->mPackets->hasBufferAvailable(&finalResult)) {
Robert Shih17f6dd62014-08-20 17:00:21 -07001005 postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
Lajos Molnare26940f2014-07-31 10:31:26 -07001006 }
1007
Robert Shih3423bbd2014-07-16 15:47:09 -07001008 if (result != OK) {
Lajos Molnare26940f2014-07-31 10:31:26 -07001009 if (mSubtitleTrack.mSource != NULL) {
1010 mSubtitleTrack.mPackets->clear();
1011 mFetchSubtitleDataGeneration++;
1012 }
1013 if (mTimedTextTrack.mSource != NULL) {
1014 mTimedTextTrack.mPackets->clear();
1015 mFetchTimedTextDataGeneration++;
1016 }
Robert Shih3423bbd2014-07-16 15:47:09 -07001017 return result;
1018 }
1019
1020 int64_t timeUs;
1021 status_t eosResult; // ignored
1022 CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs));
Robert Shih5c67ddc2014-11-04 17:46:05 -08001023 if (audio) {
1024 mAudioLastDequeueTimeUs = timeUs;
1025 } else {
1026 mVideoLastDequeueTimeUs = timeUs;
1027 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001028
1029 if (mSubtitleTrack.mSource != NULL
1030 && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
Lajos Molnar1d15ab52015-03-04 16:46:34 -08001031 sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, this);
Robert Shih3423bbd2014-07-16 15:47:09 -07001032 msg->setInt64("timeUs", timeUs);
1033 msg->setInt32("generation", mFetchSubtitleDataGeneration);
1034 msg->post();
1035 }
Robert Shiheb1735e2014-07-23 15:53:14 -07001036
Lajos Molnare26940f2014-07-31 10:31:26 -07001037 if (mTimedTextTrack.mSource != NULL
1038 && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
Lajos Molnar1d15ab52015-03-04 16:46:34 -08001039 sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, this);
Lajos Molnare26940f2014-07-31 10:31:26 -07001040 msg->setInt64("timeUs", timeUs);
1041 msg->setInt32("generation", mFetchTimedTextDataGeneration);
1042 msg->post();
1043 }
1044
Andreas Huberafed0e12011-09-20 15:39:58 -07001045 return result;
1046}
1047
1048status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) {
1049 *durationUs = mDurationUs;
1050 return OK;
1051}
1052
Robert Shihdd235722014-06-12 14:49:23 -07001053size_t NuPlayer::GenericSource::getTrackCount() const {
1054 return mSources.size();
1055}
1056
1057sp<AMessage> NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const {
1058 size_t trackCount = mSources.size();
1059 if (trackIndex >= trackCount) {
1060 return NULL;
1061 }
1062
1063 sp<AMessage> format = new AMessage();
1064 sp<MetaData> meta = mSources.itemAt(trackIndex)->getFormat();
1065
1066 const char *mime;
1067 CHECK(meta->findCString(kKeyMIMEType, &mime));
Robert Shih755106e2015-04-30 14:36:45 -07001068 format->setString("mime", mime);
Robert Shihdd235722014-06-12 14:49:23 -07001069
1070 int32_t trackType;
1071 if (!strncasecmp(mime, "video/", 6)) {
1072 trackType = MEDIA_TRACK_TYPE_VIDEO;
1073 } else if (!strncasecmp(mime, "audio/", 6)) {
1074 trackType = MEDIA_TRACK_TYPE_AUDIO;
1075 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
1076 trackType = MEDIA_TRACK_TYPE_TIMEDTEXT;
1077 } else {
1078 trackType = MEDIA_TRACK_TYPE_UNKNOWN;
1079 }
1080 format->setInt32("type", trackType);
1081
1082 const char *lang;
1083 if (!meta->findCString(kKeyMediaLanguage, &lang)) {
1084 lang = "und";
1085 }
1086 format->setString("language", lang);
1087
1088 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
Robert Shihdd235722014-06-12 14:49:23 -07001089 int32_t isAutoselect = 1, isDefault = 0, isForced = 0;
1090 meta->findInt32(kKeyTrackIsAutoselect, &isAutoselect);
1091 meta->findInt32(kKeyTrackIsDefault, &isDefault);
1092 meta->findInt32(kKeyTrackIsForced, &isForced);
1093
1094 format->setInt32("auto", !!isAutoselect);
1095 format->setInt32("default", !!isDefault);
1096 format->setInt32("forced", !!isForced);
1097 }
1098
1099 return format;
1100}
1101
Lajos Molnare26940f2014-07-31 10:31:26 -07001102ssize_t NuPlayer::GenericSource::getSelectedTrack(media_track_type type) const {
Lajos Molnar1d15ab52015-03-04 16:46:34 -08001103 sp<AMessage> msg = new AMessage(kWhatGetSelectedTrack, this);
Robert Shih17f6dd62014-08-20 17:00:21 -07001104 msg->setInt32("type", type);
1105
1106 sp<AMessage> response;
1107 int32_t index;
1108 status_t err = msg->postAndAwaitResponse(&response);
1109 if (err == OK && response != NULL) {
1110 CHECK(response->findInt32("index", &index));
1111 return index;
1112 } else {
1113 return -1;
1114 }
1115}
1116
1117void NuPlayer::GenericSource::onGetSelectedTrack(sp<AMessage> msg) const {
1118 int32_t tmpType;
1119 CHECK(msg->findInt32("type", &tmpType));
1120 media_track_type type = (media_track_type)tmpType;
1121
1122 sp<AMessage> response = new AMessage;
1123 ssize_t index = doGetSelectedTrack(type);
1124 response->setInt32("index", index);
1125
Lajos Molnar3f274362015-03-05 14:35:41 -08001126 sp<AReplyToken> replyID;
Robert Shih17f6dd62014-08-20 17:00:21 -07001127 CHECK(msg->senderAwaitsResponse(&replyID));
1128 response->postReply(replyID);
1129}
1130
1131ssize_t NuPlayer::GenericSource::doGetSelectedTrack(media_track_type type) const {
Lajos Molnare26940f2014-07-31 10:31:26 -07001132 const Track *track = NULL;
1133 switch (type) {
1134 case MEDIA_TRACK_TYPE_VIDEO:
1135 track = &mVideoTrack;
1136 break;
1137 case MEDIA_TRACK_TYPE_AUDIO:
1138 track = &mAudioTrack;
1139 break;
1140 case MEDIA_TRACK_TYPE_TIMEDTEXT:
1141 track = &mTimedTextTrack;
1142 break;
1143 case MEDIA_TRACK_TYPE_SUBTITLE:
1144 track = &mSubtitleTrack;
1145 break;
1146 default:
1147 break;
1148 }
1149
1150 if (track != NULL && track->mSource != NULL) {
1151 return track->mIndex;
1152 }
1153
1154 return -1;
1155}
1156
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001157status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select, int64_t timeUs) {
Lajos Molnare26940f2014-07-31 10:31:26 -07001158 ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex);
Lajos Molnar1d15ab52015-03-04 16:46:34 -08001159 sp<AMessage> msg = new AMessage(kWhatSelectTrack, this);
Robert Shih17f6dd62014-08-20 17:00:21 -07001160 msg->setInt32("trackIndex", trackIndex);
Robert Shihda23ab92014-09-16 11:34:08 -07001161 msg->setInt32("select", select);
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001162 msg->setInt64("timeUs", timeUs);
Robert Shih17f6dd62014-08-20 17:00:21 -07001163
1164 sp<AMessage> response;
1165 status_t err = msg->postAndAwaitResponse(&response);
1166 if (err == OK && response != NULL) {
1167 CHECK(response->findInt32("err", &err));
1168 }
1169
1170 return err;
1171}
1172
1173void NuPlayer::GenericSource::onSelectTrack(sp<AMessage> msg) {
1174 int32_t trackIndex, select;
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001175 int64_t timeUs;
Robert Shih17f6dd62014-08-20 17:00:21 -07001176 CHECK(msg->findInt32("trackIndex", &trackIndex));
1177 CHECK(msg->findInt32("select", &select));
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001178 CHECK(msg->findInt64("timeUs", &timeUs));
Robert Shih17f6dd62014-08-20 17:00:21 -07001179
1180 sp<AMessage> response = new AMessage;
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001181 status_t err = doSelectTrack(trackIndex, select, timeUs);
Robert Shih17f6dd62014-08-20 17:00:21 -07001182 response->setInt32("err", err);
1183
Lajos Molnar3f274362015-03-05 14:35:41 -08001184 sp<AReplyToken> replyID;
Robert Shih17f6dd62014-08-20 17:00:21 -07001185 CHECK(msg->senderAwaitsResponse(&replyID));
1186 response->postReply(replyID);
1187}
1188
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001189status_t NuPlayer::GenericSource::doSelectTrack(size_t trackIndex, bool select, int64_t timeUs) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001190 if (trackIndex >= mSources.size()) {
1191 return BAD_INDEX;
1192 }
1193
1194 if (!select) {
Lajos Molnare26940f2014-07-31 10:31:26 -07001195 Track* track = NULL;
1196 if (mSubtitleTrack.mSource != NULL && trackIndex == mSubtitleTrack.mIndex) {
1197 track = &mSubtitleTrack;
1198 mFetchSubtitleDataGeneration++;
1199 } else if (mTimedTextTrack.mSource != NULL && trackIndex == mTimedTextTrack.mIndex) {
1200 track = &mTimedTextTrack;
1201 mFetchTimedTextDataGeneration++;
1202 }
1203 if (track == NULL) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001204 return INVALID_OPERATION;
1205 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001206 track->mSource->stop();
1207 track->mSource = NULL;
1208 track->mPackets->clear();
Robert Shih3423bbd2014-07-16 15:47:09 -07001209 return OK;
1210 }
1211
1212 const sp<MediaSource> source = mSources.itemAt(trackIndex);
1213 sp<MetaData> meta = source->getFormat();
1214 const char *mime;
1215 CHECK(meta->findCString(kKeyMIMEType, &mime));
1216 if (!strncasecmp(mime, "text/", 5)) {
Lajos Molnare26940f2014-07-31 10:31:26 -07001217 bool isSubtitle = strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP);
1218 Track *track = isSubtitle ? &mSubtitleTrack : &mTimedTextTrack;
1219 if (track->mSource != NULL && track->mIndex == trackIndex) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001220 return OK;
1221 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001222 track->mIndex = trackIndex;
1223 if (track->mSource != NULL) {
1224 track->mSource->stop();
Robert Shih3423bbd2014-07-16 15:47:09 -07001225 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001226 track->mSource = mSources.itemAt(trackIndex);
1227 track->mSource->start();
1228 if (track->mPackets == NULL) {
1229 track->mPackets = new AnotherPacketSource(track->mSource->getFormat());
Robert Shih3423bbd2014-07-16 15:47:09 -07001230 } else {
Lajos Molnare26940f2014-07-31 10:31:26 -07001231 track->mPackets->clear();
1232 track->mPackets->setFormat(track->mSource->getFormat());
Robert Shih3423bbd2014-07-16 15:47:09 -07001233
1234 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001235
1236 if (isSubtitle) {
1237 mFetchSubtitleDataGeneration++;
1238 } else {
1239 mFetchTimedTextDataGeneration++;
1240 }
1241
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001242 status_t eosResult; // ignored
1243 if (mSubtitleTrack.mSource != NULL
1244 && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
Lajos Molnar1d15ab52015-03-04 16:46:34 -08001245 sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, this);
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001246 msg->setInt64("timeUs", timeUs);
1247 msg->setInt32("generation", mFetchSubtitleDataGeneration);
1248 msg->post();
1249 }
1250
1251 if (mTimedTextTrack.mSource != NULL
1252 && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
Lajos Molnar1d15ab52015-03-04 16:46:34 -08001253 sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, this);
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001254 msg->setInt64("timeUs", timeUs);
1255 msg->setInt32("generation", mFetchTimedTextDataGeneration);
1256 msg->post();
1257 }
1258
Robert Shih3423bbd2014-07-16 15:47:09 -07001259 return OK;
1260 } else if (!strncasecmp(mime, "audio/", 6) || !strncasecmp(mime, "video/", 6)) {
1261 bool audio = !strncasecmp(mime, "audio/", 6);
1262 Track *track = audio ? &mAudioTrack : &mVideoTrack;
1263 if (track->mSource != NULL && track->mIndex == trackIndex) {
1264 return OK;
1265 }
1266
Lajos Molnar1d15ab52015-03-04 16:46:34 -08001267 sp<AMessage> msg = new AMessage(kWhatChangeAVSource, this);
Robert Shih3423bbd2014-07-16 15:47:09 -07001268 msg->setInt32("trackIndex", trackIndex);
1269 msg->post();
1270 return OK;
1271 }
1272
1273 return INVALID_OPERATION;
1274}
1275
Andreas Huberafed0e12011-09-20 15:39:58 -07001276status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) {
Lajos Molnar1d15ab52015-03-04 16:46:34 -08001277 sp<AMessage> msg = new AMessage(kWhatSeek, this);
Robert Shih17f6dd62014-08-20 17:00:21 -07001278 msg->setInt64("seekTimeUs", seekTimeUs);
1279
1280 sp<AMessage> response;
1281 status_t err = msg->postAndAwaitResponse(&response);
1282 if (err == OK && response != NULL) {
1283 CHECK(response->findInt32("err", &err));
1284 }
1285
1286 return err;
1287}
1288
1289void NuPlayer::GenericSource::onSeek(sp<AMessage> msg) {
1290 int64_t seekTimeUs;
1291 CHECK(msg->findInt64("seekTimeUs", &seekTimeUs));
1292
1293 sp<AMessage> response = new AMessage;
1294 status_t err = doSeek(seekTimeUs);
1295 response->setInt32("err", err);
1296
Lajos Molnar3f274362015-03-05 14:35:41 -08001297 sp<AReplyToken> replyID;
Robert Shih17f6dd62014-08-20 17:00:21 -07001298 CHECK(msg->senderAwaitsResponse(&replyID));
1299 response->postReply(replyID);
1300}
1301
1302status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs) {
Andy Hung2abde2c2014-09-30 14:40:32 -07001303 // If the Widevine source is stopped, do not attempt to read any
1304 // more buffers.
1305 if (mStopRead) {
1306 return INVALID_OPERATION;
1307 }
Andreas Huberafed0e12011-09-20 15:39:58 -07001308 if (mVideoTrack.mSource != NULL) {
1309 int64_t actualTimeUs;
Robert Shih3423bbd2014-07-16 15:47:09 -07001310 readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, &actualTimeUs);
Andreas Huberafed0e12011-09-20 15:39:58 -07001311
1312 seekTimeUs = actualTimeUs;
Robert Shih5c67ddc2014-11-04 17:46:05 -08001313 mVideoLastDequeueTimeUs = seekTimeUs;
Andreas Huberafed0e12011-09-20 15:39:58 -07001314 }
1315
1316 if (mAudioTrack.mSource != NULL) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001317 readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs);
Robert Shih5c67ddc2014-11-04 17:46:05 -08001318 mAudioLastDequeueTimeUs = seekTimeUs;
Andreas Huberafed0e12011-09-20 15:39:58 -07001319 }
1320
Ronghua Wu80276872014-08-28 15:50:29 -07001321 setDrmPlaybackStatusIfNeeded(Playback::START, seekTimeUs / 1000);
1322 if (!mStarted) {
1323 setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0);
1324 }
Chong Zhangefbb6192015-01-30 17:13:27 -08001325
1326 // If currently buffering, post kWhatBufferingEnd first, so that
1327 // NuPlayer resumes. Otherwise, if cache hits high watermark
1328 // before new polling happens, no one will resume the playback.
1329 stopBufferingIfNecessary();
1330 restartPollBuffering();
1331
Andreas Huberafed0e12011-09-20 15:39:58 -07001332 return OK;
1333}
1334
Robert Shih3423bbd2014-07-16 15:47:09 -07001335sp<ABuffer> NuPlayer::GenericSource::mediaBufferToABuffer(
1336 MediaBuffer* mb,
1337 media_track_type trackType,
Wei Jia474d7c72014-12-04 15:12:13 -08001338 int64_t /* seekTimeUs */,
Robert Shih3423bbd2014-07-16 15:47:09 -07001339 int64_t *actualTimeUs) {
1340 bool audio = trackType == MEDIA_TRACK_TYPE_AUDIO;
1341 size_t outLength = mb->range_length();
1342
1343 if (audio && mAudioIsVorbis) {
1344 outLength += sizeof(int32_t);
1345 }
1346
1347 sp<ABuffer> ab;
Chong Zhang42e81532014-12-01 13:44:26 -08001348 if (mIsSecure && !audio) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001349 // data is already provided in the buffer
1350 ab = new ABuffer(NULL, mb->range_length());
Robert Shih3423bbd2014-07-16 15:47:09 -07001351 mb->add_ref();
Wei Jia96e92b52014-09-18 17:36:20 -07001352 ab->setMediaBufferBase(mb);
Robert Shih3423bbd2014-07-16 15:47:09 -07001353 } else {
1354 ab = new ABuffer(outLength);
1355 memcpy(ab->data(),
1356 (const uint8_t *)mb->data() + mb->range_offset(),
1357 mb->range_length());
1358 }
1359
1360 if (audio && mAudioIsVorbis) {
1361 int32_t numPageSamples;
1362 if (!mb->meta_data()->findInt32(kKeyValidSamples, &numPageSamples)) {
1363 numPageSamples = -1;
1364 }
1365
1366 uint8_t* abEnd = ab->data() + mb->range_length();
1367 memcpy(abEnd, &numPageSamples, sizeof(numPageSamples));
1368 }
1369
Lajos Molnare26940f2014-07-31 10:31:26 -07001370 sp<AMessage> meta = ab->meta();
1371
Robert Shih3423bbd2014-07-16 15:47:09 -07001372 int64_t timeUs;
1373 CHECK(mb->meta_data()->findInt64(kKeyTime, &timeUs));
Robert Shih3423bbd2014-07-16 15:47:09 -07001374 meta->setInt64("timeUs", timeUs);
1375
Wei Jia474d7c72014-12-04 15:12:13 -08001376#if 0
1377 // Temporarily disable pre-roll till we have a full solution to handle
1378 // both single seek and continous seek gracefully.
1379 if (seekTimeUs > timeUs) {
1380 sp<AMessage> extra = new AMessage;
1381 extra->setInt64("resume-at-mediaTimeUs", seekTimeUs);
1382 meta->setMessage("extra", extra);
1383 }
1384#endif
1385
Lajos Molnare26940f2014-07-31 10:31:26 -07001386 if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) {
1387 const char *mime;
1388 CHECK(mTimedTextTrack.mSource != NULL
1389 && mTimedTextTrack.mSource->getFormat()->findCString(kKeyMIMEType, &mime));
1390 meta->setString("mime", mime);
1391 }
1392
Robert Shih3423bbd2014-07-16 15:47:09 -07001393 int64_t durationUs;
1394 if (mb->meta_data()->findInt64(kKeyDuration, &durationUs)) {
1395 meta->setInt64("durationUs", durationUs);
1396 }
1397
1398 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
1399 meta->setInt32("trackIndex", mSubtitleTrack.mIndex);
1400 }
1401
Robert Shihf8bd8512015-04-23 16:39:18 -07001402 uint32_t dataType; // unused
1403 const void *seiData;
1404 size_t seiLength;
1405 if (mb->meta_data()->findData(kKeySEI, &dataType, &seiData, &seiLength)) {
1406 sp<ABuffer> sei = ABuffer::CreateAsCopy(seiData, seiLength);;
1407 meta->setBuffer("sei", sei);
1408 }
1409
Robert Shih3423bbd2014-07-16 15:47:09 -07001410 if (actualTimeUs) {
1411 *actualTimeUs = timeUs;
1412 }
1413
1414 mb->release();
1415 mb = NULL;
1416
1417 return ab;
1418}
1419
Robert Shih17f6dd62014-08-20 17:00:21 -07001420void NuPlayer::GenericSource::postReadBuffer(media_track_type trackType) {
Lajos Molnar84f52782014-09-11 10:01:55 -07001421 Mutex::Autolock _l(mReadBufferLock);
1422
1423 if ((mPendingReadBufferTypes & (1 << trackType)) == 0) {
1424 mPendingReadBufferTypes |= (1 << trackType);
Lajos Molnar1d15ab52015-03-04 16:46:34 -08001425 sp<AMessage> msg = new AMessage(kWhatReadBuffer, this);
Lajos Molnar84f52782014-09-11 10:01:55 -07001426 msg->setInt32("trackType", trackType);
1427 msg->post();
1428 }
Robert Shih17f6dd62014-08-20 17:00:21 -07001429}
1430
1431void NuPlayer::GenericSource::onReadBuffer(sp<AMessage> msg) {
1432 int32_t tmpType;
1433 CHECK(msg->findInt32("trackType", &tmpType));
1434 media_track_type trackType = (media_track_type)tmpType;
Chong Zhang42e81532014-12-01 13:44:26 -08001435 readBuffer(trackType);
Lajos Molnar84f52782014-09-11 10:01:55 -07001436 {
1437 // only protect the variable change, as readBuffer may
Chong Zhang42e81532014-12-01 13:44:26 -08001438 // take considerable time.
Lajos Molnar84f52782014-09-11 10:01:55 -07001439 Mutex::Autolock _l(mReadBufferLock);
1440 mPendingReadBufferTypes &= ~(1 << trackType);
1441 }
Robert Shih17f6dd62014-08-20 17:00:21 -07001442}
1443
Andreas Huberafed0e12011-09-20 15:39:58 -07001444void NuPlayer::GenericSource::readBuffer(
Robert Shih3423bbd2014-07-16 15:47:09 -07001445 media_track_type trackType, int64_t seekTimeUs, int64_t *actualTimeUs, bool formatChange) {
Andy Hung2abde2c2014-09-30 14:40:32 -07001446 // Do not read data if Widevine source is stopped
1447 if (mStopRead) {
1448 return;
1449 }
Robert Shih3423bbd2014-07-16 15:47:09 -07001450 Track *track;
Phil Burkc5cc2e22014-09-09 20:08:39 -07001451 size_t maxBuffers = 1;
Robert Shih3423bbd2014-07-16 15:47:09 -07001452 switch (trackType) {
1453 case MEDIA_TRACK_TYPE_VIDEO:
1454 track = &mVideoTrack;
Jeff Tinkera28785a2014-09-23 22:24:26 -07001455 if (mIsWidevine) {
1456 maxBuffers = 2;
1457 }
Robert Shih3423bbd2014-07-16 15:47:09 -07001458 break;
1459 case MEDIA_TRACK_TYPE_AUDIO:
1460 track = &mAudioTrack;
Jeff Tinkera28785a2014-09-23 22:24:26 -07001461 if (mIsWidevine) {
1462 maxBuffers = 8;
1463 } else {
1464 maxBuffers = 64;
1465 }
Robert Shih3423bbd2014-07-16 15:47:09 -07001466 break;
1467 case MEDIA_TRACK_TYPE_SUBTITLE:
1468 track = &mSubtitleTrack;
1469 break;
Lajos Molnare26940f2014-07-31 10:31:26 -07001470 case MEDIA_TRACK_TYPE_TIMEDTEXT:
1471 track = &mTimedTextTrack;
1472 break;
Robert Shih3423bbd2014-07-16 15:47:09 -07001473 default:
1474 TRESPASS();
1475 }
1476
1477 if (track->mSource == NULL) {
1478 return;
1479 }
Andreas Huberafed0e12011-09-20 15:39:58 -07001480
1481 if (actualTimeUs) {
1482 *actualTimeUs = seekTimeUs;
1483 }
1484
1485 MediaSource::ReadOptions options;
1486
1487 bool seeking = false;
1488
1489 if (seekTimeUs >= 0) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001490 options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
Andreas Huberafed0e12011-09-20 15:39:58 -07001491 seeking = true;
1492 }
1493
Chong Zhang42e81532014-12-01 13:44:26 -08001494 if (mIsWidevine) {
Lajos Molnarcc227032014-07-17 15:33:06 -07001495 options.setNonBlocking();
1496 }
1497
Phil Burkc5cc2e22014-09-09 20:08:39 -07001498 for (size_t numBuffers = 0; numBuffers < maxBuffers; ) {
Andreas Huberafed0e12011-09-20 15:39:58 -07001499 MediaBuffer *mbuf;
1500 status_t err = track->mSource->read(&mbuf, &options);
1501
1502 options.clearSeekTo();
1503
1504 if (err == OK) {
Ronghua Wu80276872014-08-28 15:50:29 -07001505 int64_t timeUs;
1506 CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs));
1507 if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
1508 mAudioTimeUs = timeUs;
1509 } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
1510 mVideoTimeUs = timeUs;
1511 }
1512
Ronghua Wu8f291bc2015-05-19 10:11:53 -07001513 queueDiscontinuityIfNeeded(seeking, formatChange, trackType, track);
Andreas Huberafed0e12011-09-20 15:39:58 -07001514
Wei Jia474d7c72014-12-04 15:12:13 -08001515 sp<ABuffer> buffer = mediaBufferToABuffer(
1516 mbuf, trackType, seekTimeUs, actualTimeUs);
Andreas Huberafed0e12011-09-20 15:39:58 -07001517 track->mPackets->queueAccessUnit(buffer);
Marco Nelissen317a49a2014-09-16 21:32:33 -07001518 formatChange = false;
1519 seeking = false;
Phil Burkc5cc2e22014-09-09 20:08:39 -07001520 ++numBuffers;
Lajos Molnarcc227032014-07-17 15:33:06 -07001521 } else if (err == WOULD_BLOCK) {
1522 break;
Andreas Huberafed0e12011-09-20 15:39:58 -07001523 } else if (err == INFO_FORMAT_CHANGED) {
1524#if 0
1525 track->mPackets->queueDiscontinuity(
Chong Zhang632740c2014-06-26 13:03:47 -07001526 ATSParser::DISCONTINUITY_FORMATCHANGE,
1527 NULL,
1528 false /* discard */);
Andreas Huberafed0e12011-09-20 15:39:58 -07001529#endif
1530 } else {
Ronghua Wu8f291bc2015-05-19 10:11:53 -07001531 queueDiscontinuityIfNeeded(seeking, formatChange, trackType, track);
Andreas Huberafed0e12011-09-20 15:39:58 -07001532 track->mPackets->signalEOS(err);
1533 break;
1534 }
1535 }
1536}
1537
Ronghua Wu8f291bc2015-05-19 10:11:53 -07001538void NuPlayer::GenericSource::queueDiscontinuityIfNeeded(
1539 bool seeking, bool formatChange, media_track_type trackType, Track *track) {
1540 // formatChange && seeking: track whose source is changed during selection
1541 // formatChange && !seeking: track whose source is not changed during selection
1542 // !formatChange: normal seek
1543 if ((seeking || formatChange)
1544 && (trackType == MEDIA_TRACK_TYPE_AUDIO
1545 || trackType == MEDIA_TRACK_TYPE_VIDEO)) {
1546 ATSParser::DiscontinuityType type = (formatChange && seeking)
1547 ? ATSParser::DISCONTINUITY_FORMATCHANGE
1548 : ATSParser::DISCONTINUITY_NONE;
1549 track->mPackets->queueDiscontinuity(type, NULL /* extra */, true /* discard */);
1550 }
1551}
1552
Andreas Huberafed0e12011-09-20 15:39:58 -07001553} // namespace android