blob: 4d3ccd22e058974dfd33eb284423784568f1e7db [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() {
Marco Nelissenb2487f02015-09-01 13:23:23 -0700138 sp<IMediaExtractor> 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) {
Marco Nelissenb2487f02015-09-01 13:23:23 -0700213 sp<IMediaSource> track = extractor->getTrack(i);
Wei Jia0386c912015-08-28 10:35:35 -0700214 if (track == NULL) {
215 continue;
216 }
Chong Zhangafc0a872014-08-26 09:56:52 -0700217
Andreas Huberafed0e12011-09-20 15:39:58 -0700218 sp<MetaData> meta = extractor->getTrackMetaData(i);
Marco Nelissenc367ca12015-09-15 09:51:59 -0700219 if (meta == NULL) {
220 ALOGE("no metadata for track %zu", i);
221 return UNKNOWN_ERROR;
222 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700223
224 const char *mime;
225 CHECK(meta->findCString(kKeyMIMEType, &mime));
226
Chong Zhangafc0a872014-08-26 09:56:52 -0700227 // Do the string compare immediately with "mime",
228 // we can't assume "mime" would stay valid after another
229 // extractor operation, some extractors might modify meta
230 // during getTrack() and make it invalid.
Andreas Huberafed0e12011-09-20 15:39:58 -0700231 if (!strncasecmp(mime, "audio/", 6)) {
232 if (mAudioTrack.mSource == NULL) {
Robert Shihdd235722014-06-12 14:49:23 -0700233 mAudioTrack.mIndex = i;
234 mAudioTrack.mSource = track;
Robert Shihaf52c1a2014-09-11 15:38:54 -0700235 mAudioTrack.mPackets =
236 new AnotherPacketSource(mAudioTrack.mSource->getFormat());
Andreas Huberafed0e12011-09-20 15:39:58 -0700237
238 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
239 mAudioIsVorbis = true;
240 } else {
241 mAudioIsVorbis = false;
242 }
243 }
244 } else if (!strncasecmp(mime, "video/", 6)) {
245 if (mVideoTrack.mSource == NULL) {
Robert Shihdd235722014-06-12 14:49:23 -0700246 mVideoTrack.mIndex = i;
247 mVideoTrack.mSource = track;
Robert Shihaf52c1a2014-09-11 15:38:54 -0700248 mVideoTrack.mPackets =
249 new AnotherPacketSource(mVideoTrack.mSource->getFormat());
Chong Zhang7e892182014-08-05 11:58:21 -0700250
251 // check if the source requires secure buffers
252 int32_t secure;
Chong Zhanga19f33e2014-08-07 15:35:07 -0700253 if (meta->findInt32(kKeyRequiresSecureBuffers, &secure)
254 && secure) {
Chong Zhang42e81532014-12-01 13:44:26 -0800255 mIsSecure = true;
Chong Zhang3de157d2014-08-05 20:54:44 -0700256 if (mUIDValid) {
257 extractor->setUID(mUID);
258 }
Chong Zhang7e892182014-08-05 11:58:21 -0700259 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700260 }
261 }
262
Wei Jia0386c912015-08-28 10:35:35 -0700263 mSources.push(track);
264 int64_t durationUs;
265 if (meta->findInt64(kKeyDuration, &durationUs)) {
266 if (durationUs > mDurationUs) {
267 mDurationUs = durationUs;
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700268 }
Andreas Huberafed0e12011-09-20 15:39:58 -0700269 }
Wei Jia0386c912015-08-28 10:35:35 -0700270
271 int32_t bitrate;
272 if (totalBitrate >= 0 && meta->findInt32(kKeyBitRate, &bitrate)) {
273 totalBitrate += bitrate;
274 } else {
275 totalBitrate = -1;
276 }
277 }
278
279 if (mSources.size() == 0) {
280 ALOGE("b/23705695");
281 return UNKNOWN_ERROR;
Andreas Huberafed0e12011-09-20 15:39:58 -0700282 }
Chong Zhang3de157d2014-08-05 20:54:44 -0700283
Lajos Molnarfcd3e942015-03-31 10:06:48 -0700284 mBitrate = totalBitrate;
285
286 return OK;
287}
288
289status_t NuPlayer::GenericSource::startSources() {
Chong Zhangefbb6192015-01-30 17:13:27 -0800290 // Start the selected A/V tracks now before we start buffering.
291 // Widevine sources might re-initialize crypto when starting, if we delay
292 // this to start(), all data buffered during prepare would be wasted.
293 // (We don't actually start reading until start().)
294 if (mAudioTrack.mSource != NULL && mAudioTrack.mSource->start() != OK) {
295 ALOGE("failed to start audio track!");
296 return UNKNOWN_ERROR;
297 }
298
299 if (mVideoTrack.mSource != NULL && mVideoTrack.mSource->start() != OK) {
300 ALOGE("failed to start video track!");
301 return UNKNOWN_ERROR;
302 }
303
Chong Zhang3de157d2014-08-05 20:54:44 -0700304 return OK;
Andreas Huberafed0e12011-09-20 15:39:58 -0700305}
306
Ronghua Wu80276872014-08-28 15:50:29 -0700307void NuPlayer::GenericSource::checkDrmStatus(const sp<DataSource>& dataSource) {
308 dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
309 if (mDecryptHandle != NULL) {
310 CHECK(mDrmManagerClient);
311 if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
312 sp<AMessage> msg = dupNotify();
313 msg->setInt32("what", kWhatDrmNoLicense);
314 msg->post();
315 }
316 }
317}
318
319int64_t NuPlayer::GenericSource::getLastReadPosition() {
320 if (mAudioTrack.mSource != NULL) {
321 return mAudioTimeUs;
322 } else if (mVideoTrack.mSource != NULL) {
323 return mVideoTimeUs;
324 } else {
325 return 0;
326 }
327}
328
Chong Zhanga19f33e2014-08-07 15:35:07 -0700329status_t NuPlayer::GenericSource::setBuffers(
330 bool audio, Vector<MediaBuffer *> &buffers) {
Wei Jia0386c912015-08-28 10:35:35 -0700331 if (mIsSecure && !audio && mVideoTrack.mSource != NULL) {
Lajos Molnarcc227032014-07-17 15:33:06 -0700332 return mVideoTrack.mSource->setBuffers(buffers);
333 }
334 return INVALID_OPERATION;
335}
336
Ronghua Wu02cb98d2015-05-27 11:02:54 -0700337bool NuPlayer::GenericSource::isStreaming() const {
338 return mIsStreaming;
339}
340
Andreas Huberafed0e12011-09-20 15:39:58 -0700341NuPlayer::GenericSource::~GenericSource() {
Chong Zhang1228d6b2014-08-12 21:25:48 -0700342 if (mLooper != NULL) {
343 mLooper->unregisterHandler(id());
344 mLooper->stop();
345 }
Chong Zhanga6bf21f2014-11-19 20:26:34 -0800346 resetDataSource();
Andreas Huberafed0e12011-09-20 15:39:58 -0700347}
348
Andreas Huber9575c962013-02-05 13:59:56 -0800349void NuPlayer::GenericSource::prepareAsync() {
Chong Zhang1228d6b2014-08-12 21:25:48 -0700350 if (mLooper == NULL) {
351 mLooper = new ALooper;
352 mLooper->setName("generic");
353 mLooper->start();
354
355 mLooper->registerHandler(this);
356 }
357
Lajos Molnar1d15ab52015-03-04 16:46:34 -0800358 sp<AMessage> msg = new AMessage(kWhatPrepareAsync, this);
Chong Zhang1228d6b2014-08-12 21:25:48 -0700359 msg->post();
360}
361
362void NuPlayer::GenericSource::onPrepareAsync() {
Chong Zhanga19f33e2014-08-07 15:35:07 -0700363 // delayed data source creation
Chong Zhangd354d8d2014-08-20 13:09:58 -0700364 if (mDataSource == NULL) {
Chong Zhang42e81532014-12-01 13:44:26 -0800365 // set to false first, if the extractor
366 // comes back as secure, set it to true then.
367 mIsSecure = false;
368
Chong Zhangd354d8d2014-08-20 13:09:58 -0700369 if (!mUri.empty()) {
Robert Shih360d6d02014-09-29 14:42:35 -0700370 const char* uri = mUri.c_str();
Chong Zhangc287cad2015-02-19 18:30:30 -0800371 String8 contentType;
Robert Shih360d6d02014-09-29 14:42:35 -0700372 mIsWidevine = !strncasecmp(uri, "widevine://", 11);
373
374 if (!strncasecmp("http://", uri, 7)
375 || !strncasecmp("https://", uri, 8)
376 || mIsWidevine) {
377 mHttpSource = DataSource::CreateMediaHTTP(mHTTPService);
378 if (mHttpSource == NULL) {
379 ALOGE("Failed to create http source!");
380 notifyPreparedAndCleanup(UNKNOWN_ERROR);
381 return;
382 }
383 }
Chong Zhanga19f33e2014-08-07 15:35:07 -0700384
Chong Zhangd354d8d2014-08-20 13:09:58 -0700385 mDataSource = DataSource::CreateFromURI(
Chong Zhangc287cad2015-02-19 18:30:30 -0800386 mHTTPService, uri, &mUriHeaders, &contentType,
Robert Shih360d6d02014-09-29 14:42:35 -0700387 static_cast<HTTPBase *>(mHttpSource.get()));
Chong Zhangd354d8d2014-08-20 13:09:58 -0700388 } else {
Chong Zhangd354d8d2014-08-20 13:09:58 -0700389 mIsWidevine = false;
Chong Zhanga19f33e2014-08-07 15:35:07 -0700390
Chong Zhangd354d8d2014-08-20 13:09:58 -0700391 mDataSource = new FileSource(mFd, mOffset, mLength);
Chong Zhanga6bf21f2014-11-19 20:26:34 -0800392 mFd = -1;
Chong Zhangd354d8d2014-08-20 13:09:58 -0700393 }
Chong Zhanga19f33e2014-08-07 15:35:07 -0700394
Chong Zhangd354d8d2014-08-20 13:09:58 -0700395 if (mDataSource == NULL) {
396 ALOGE("Failed to create data source!");
397 notifyPreparedAndCleanup(UNKNOWN_ERROR);
398 return;
399 }
Chong Zhanga19f33e2014-08-07 15:35:07 -0700400 }
401
Chris Watkins99f31602015-03-20 13:06:33 -0700402 if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
403 mCachedSource = static_cast<NuCachedSource2 *>(mDataSource.get());
404 }
405
406 // For widevine or other cached streaming cases, we need to wait for
407 // enough buffering before reporting prepared.
408 // Note that even when URL doesn't start with widevine://, mIsWidevine
409 // could still be set to true later, if the streaming or file source
410 // is sniffed to be widevine. We don't want to buffer for file source
411 // in that case, so must check the flag now.
412 mIsStreaming = (mIsWidevine || mCachedSource != NULL);
413
Chong Zhangc287cad2015-02-19 18:30:30 -0800414 // init extractor from data source
415 status_t err = initFromDataSource();
Chong Zhanga19f33e2014-08-07 15:35:07 -0700416
417 if (err != OK) {
418 ALOGE("Failed to init from data source!");
Chong Zhangd354d8d2014-08-20 13:09:58 -0700419 notifyPreparedAndCleanup(err);
Chong Zhanga19f33e2014-08-07 15:35:07 -0700420 return;
421 }
422
Andreas Huber9575c962013-02-05 13:59:56 -0800423 if (mVideoTrack.mSource != NULL) {
Robert Shih17f6dd62014-08-20 17:00:21 -0700424 sp<MetaData> meta = doGetFormatMeta(false /* audio */);
425 sp<AMessage> msg = new AMessage;
426 err = convertMetaDataToMessage(meta, &msg);
427 if(err != OK) {
428 notifyPreparedAndCleanup(err);
429 return;
430 }
431 notifyVideoSizeChanged(msg);
Andreas Huber9575c962013-02-05 13:59:56 -0800432 }
433
434 notifyFlagsChanged(
Chong Zhang42e81532014-12-01 13:44:26 -0800435 (mIsSecure ? FLAG_SECURE : 0)
Chong Zhang17134602015-01-07 16:14:34 -0800436 | (mDecryptHandle != NULL ? FLAG_PROTECTED : 0)
Lajos Molnarcc227032014-07-17 15:33:06 -0700437 | FLAG_CAN_PAUSE
Andreas Huber9575c962013-02-05 13:59:56 -0800438 | FLAG_CAN_SEEK_BACKWARD
439 | FLAG_CAN_SEEK_FORWARD
440 | FLAG_CAN_SEEK);
441
Lajos Molnarfcd3e942015-03-31 10:06:48 -0700442 if (mIsSecure) {
443 // secure decoders must be instantiated before starting widevine source
444 sp<AMessage> reply = new AMessage(kWhatSecureDecodersInstantiated, this);
445 notifyInstantiateSecureDecoders(reply);
446 } else {
447 finishPrepareAsync();
448 }
449}
450
451void NuPlayer::GenericSource::onSecureDecodersInstantiated(status_t err) {
452 if (err != OK) {
453 ALOGE("Failed to instantiate secure decoders!");
454 notifyPreparedAndCleanup(err);
455 return;
456 }
457 finishPrepareAsync();
458}
459
460void NuPlayer::GenericSource::finishPrepareAsync() {
461 status_t err = startSources();
462 if (err != OK) {
463 ALOGE("Failed to init start data source!");
464 notifyPreparedAndCleanup(err);
465 return;
466 }
467
Chong Zhangefbb6192015-01-30 17:13:27 -0800468 if (mIsStreaming) {
469 mPrepareBuffering = true;
470
471 ensureCacheIsFetching();
472 restartPollBuffering();
473 } else {
474 notifyPrepared();
475 }
Andreas Huber9575c962013-02-05 13:59:56 -0800476}
477
Chong Zhangd354d8d2014-08-20 13:09:58 -0700478void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) {
479 if (err != OK) {
Robert Shihebc27122015-09-02 14:02:47 -0700480 {
481 sp<DataSource> dataSource = mDataSource;
482 sp<NuCachedSource2> cachedSource = mCachedSource;
483 sp<DataSource> httpSource = mHttpSource;
484 {
485 Mutex::Autolock _l(mDisconnectLock);
486 mDataSource.clear();
Wei Jiacdc9cf62015-10-22 11:35:04 -0700487 mDecryptHandle = NULL;
Wei Jiab41fd0d2015-10-19 16:14:14 -0700488 mDrmManagerClient = NULL;
Robert Shihebc27122015-09-02 14:02:47 -0700489 mCachedSource.clear();
490 mHttpSource.clear();
491 }
492 }
Lajos Molnarfcd3e942015-03-31 10:06:48 -0700493 mBitrate = -1;
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700494
495 cancelPollBuffering();
Chong Zhangd354d8d2014-08-20 13:09:58 -0700496 }
497 notifyPrepared(err);
498}
499
Andreas Huberafed0e12011-09-20 15:39:58 -0700500void NuPlayer::GenericSource::start() {
501 ALOGI("start");
502
Andy Hung2abde2c2014-09-30 14:40:32 -0700503 mStopRead = false;
Andreas Huberafed0e12011-09-20 15:39:58 -0700504 if (mAudioTrack.mSource != NULL) {
Robert Shih17f6dd62014-08-20 17:00:21 -0700505 postReadBuffer(MEDIA_TRACK_TYPE_AUDIO);
Andreas Huberafed0e12011-09-20 15:39:58 -0700506 }
507
508 if (mVideoTrack.mSource != NULL) {
Robert Shih17f6dd62014-08-20 17:00:21 -0700509 postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
Andreas Huberafed0e12011-09-20 15:39:58 -0700510 }
Ronghua Wu80276872014-08-28 15:50:29 -0700511
512 setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000);
513 mStarted = true;
Chong Zhangefbb6192015-01-30 17:13:27 -0800514
Lajos Molnar1d15ab52015-03-04 16:46:34 -0800515 (new AMessage(kWhatStart, this))->post();
Ronghua Wu80276872014-08-28 15:50:29 -0700516}
517
518void NuPlayer::GenericSource::stop() {
519 // nothing to do, just account for DRM playback status
520 setDrmPlaybackStatusIfNeeded(Playback::STOP, 0);
521 mStarted = false;
Chong Zhang42e81532014-12-01 13:44:26 -0800522 if (mIsWidevine || mIsSecure) {
523 // For widevine or secure sources we need to prevent any further reads.
Lajos Molnar1d15ab52015-03-04 16:46:34 -0800524 sp<AMessage> msg = new AMessage(kWhatStopWidevine, this);
Andy Hung2abde2c2014-09-30 14:40:32 -0700525 sp<AMessage> response;
526 (void) msg->postAndAwaitResponse(&response);
527 }
Ronghua Wu80276872014-08-28 15:50:29 -0700528}
529
530void NuPlayer::GenericSource::pause() {
531 // nothing to do, just account for DRM playback status
532 setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0);
533 mStarted = false;
534}
535
536void NuPlayer::GenericSource::resume() {
537 // nothing to do, just account for DRM playback status
538 setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000);
539 mStarted = true;
Chong Zhangefbb6192015-01-30 17:13:27 -0800540
Lajos Molnar1d15ab52015-03-04 16:46:34 -0800541 (new AMessage(kWhatResume, this))->post();
Ronghua Wu80276872014-08-28 15:50:29 -0700542}
543
Chong Zhang48296b72014-09-14 14:28:45 -0700544void NuPlayer::GenericSource::disconnect() {
Robert Shihebc27122015-09-02 14:02:47 -0700545 sp<DataSource> dataSource, httpSource;
546 {
547 Mutex::Autolock _l(mDisconnectLock);
548 dataSource = mDataSource;
549 httpSource = mHttpSource;
550 }
551
552 if (dataSource != NULL) {
Chong Zhang48296b72014-09-14 14:28:45 -0700553 // disconnect data source
Robert Shihebc27122015-09-02 14:02:47 -0700554 if (dataSource->flags() & DataSource::kIsCachingDataSource) {
555 static_cast<NuCachedSource2 *>(dataSource.get())->disconnect();
Chong Zhang48296b72014-09-14 14:28:45 -0700556 }
Robert Shihebc27122015-09-02 14:02:47 -0700557 } else if (httpSource != NULL) {
558 static_cast<HTTPBase *>(httpSource.get())->disconnect();
Chong Zhang48296b72014-09-14 14:28:45 -0700559 }
560}
561
Ronghua Wu80276872014-08-28 15:50:29 -0700562void NuPlayer::GenericSource::setDrmPlaybackStatusIfNeeded(int playbackStatus, int64_t position) {
563 if (mDecryptHandle != NULL) {
564 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, playbackStatus, position);
565 }
Robert Shih17f6dd62014-08-20 17:00:21 -0700566 mSubtitleTrack.mPackets = new AnotherPacketSource(NULL);
567 mTimedTextTrack.mPackets = new AnotherPacketSource(NULL);
Andreas Huberafed0e12011-09-20 15:39:58 -0700568}
569
570status_t NuPlayer::GenericSource::feedMoreTSData() {
571 return OK;
572}
573
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700574void NuPlayer::GenericSource::schedulePollBuffering() {
Lajos Molnar1d15ab52015-03-04 16:46:34 -0800575 sp<AMessage> msg = new AMessage(kWhatPollBuffering, this);
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700576 msg->setInt32("generation", mPollBufferingGeneration);
577 msg->post(1000000ll);
578}
579
580void NuPlayer::GenericSource::cancelPollBuffering() {
Chong Zhangefbb6192015-01-30 17:13:27 -0800581 mBuffering = false;
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700582 ++mPollBufferingGeneration;
Chong Zhangc287cad2015-02-19 18:30:30 -0800583 mPrevBufferPercentage = -1;
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700584}
585
Chong Zhangefbb6192015-01-30 17:13:27 -0800586void NuPlayer::GenericSource::restartPollBuffering() {
587 if (mIsStreaming) {
588 cancelPollBuffering();
589 onPollBuffering();
590 }
591}
592
Chong Zhangc287cad2015-02-19 18:30:30 -0800593void NuPlayer::GenericSource::notifyBufferingUpdate(int32_t percentage) {
594 // Buffering percent could go backward as it's estimated from remaining
595 // data and last access time. This could cause the buffering position
596 // drawn on media control to jitter slightly. Remember previously reported
597 // percentage and don't allow it to go backward.
598 if (percentage < mPrevBufferPercentage) {
599 percentage = mPrevBufferPercentage;
600 } else if (percentage > 100) {
601 percentage = 100;
602 }
603
604 mPrevBufferPercentage = percentage;
605
Chong Zhangefbb6192015-01-30 17:13:27 -0800606 ALOGV("notifyBufferingUpdate: buffering %d%%", percentage);
607
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700608 sp<AMessage> msg = dupNotify();
609 msg->setInt32("what", kWhatBufferingUpdate);
610 msg->setInt32("percentage", percentage);
611 msg->post();
612}
613
Chong Zhangefbb6192015-01-30 17:13:27 -0800614void NuPlayer::GenericSource::startBufferingIfNecessary() {
615 ALOGV("startBufferingIfNecessary: mPrepareBuffering=%d, mBuffering=%d",
616 mPrepareBuffering, mBuffering);
617
618 if (mPrepareBuffering) {
619 return;
620 }
621
622 if (!mBuffering) {
623 mBuffering = true;
624
625 ensureCacheIsFetching();
626 sendCacheStats();
627
628 sp<AMessage> notify = dupNotify();
629 notify->setInt32("what", kWhatPauseOnBufferingStart);
630 notify->post();
631 }
632}
633
634void NuPlayer::GenericSource::stopBufferingIfNecessary() {
635 ALOGV("stopBufferingIfNecessary: mPrepareBuffering=%d, mBuffering=%d",
636 mPrepareBuffering, mBuffering);
637
638 if (mPrepareBuffering) {
639 mPrepareBuffering = false;
640 notifyPrepared();
641 return;
642 }
643
644 if (mBuffering) {
645 mBuffering = false;
646
647 sendCacheStats();
648
649 sp<AMessage> notify = dupNotify();
650 notify->setInt32("what", kWhatResumeOnBufferingEnd);
651 notify->post();
652 }
653}
654
655void NuPlayer::GenericSource::sendCacheStats() {
656 int32_t kbps = 0;
657 status_t err = UNKNOWN_ERROR;
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700658
Chong Zhangfc6cfd82015-02-19 16:39:59 -0800659 if (mWVMExtractor != NULL) {
Chong Zhangefbb6192015-01-30 17:13:27 -0800660 err = mWVMExtractor->getEstimatedBandwidthKbps(&kbps);
Chong Zhangfc6cfd82015-02-19 16:39:59 -0800661 } else if (mCachedSource != NULL) {
662 err = mCachedSource->getEstimatedBandwidthKbps(&kbps);
Chong Zhangefbb6192015-01-30 17:13:27 -0800663 }
664
665 if (err == OK) {
666 sp<AMessage> notify = dupNotify();
667 notify->setInt32("what", kWhatCacheStats);
668 notify->setInt32("bandwidth", kbps);
669 notify->post();
670 }
671}
672
673void NuPlayer::GenericSource::ensureCacheIsFetching() {
674 if (mCachedSource != NULL) {
675 mCachedSource->resumeFetchingIfNecessary();
676 }
677}
678
679void NuPlayer::GenericSource::onPollBuffering() {
680 status_t finalStatus = UNKNOWN_ERROR;
681 int64_t cachedDurationUs = -1ll;
682 ssize_t cachedDataRemaining = -1;
683
Chong Zhangfc6cfd82015-02-19 16:39:59 -0800684 ALOGW_IF(mWVMExtractor != NULL && mCachedSource != NULL,
685 "WVMExtractor and NuCachedSource both present");
686
687 if (mWVMExtractor != NULL) {
688 cachedDurationUs =
689 mWVMExtractor->getCachedDurationUs(&finalStatus);
690 } else if (mCachedSource != NULL) {
Chong Zhangefbb6192015-01-30 17:13:27 -0800691 cachedDataRemaining =
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700692 mCachedSource->approxDataRemaining(&finalStatus);
693
694 if (finalStatus == OK) {
695 off64_t size;
696 int64_t bitrate = 0ll;
697 if (mDurationUs > 0 && mCachedSource->getSize(&size) == OK) {
698 bitrate = size * 8000000ll / mDurationUs;
699 } else if (mBitrate > 0) {
700 bitrate = mBitrate;
701 }
702 if (bitrate > 0) {
703 cachedDurationUs = cachedDataRemaining * 8000000ll / bitrate;
704 }
705 }
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700706 }
707
Chong Zhangefbb6192015-01-30 17:13:27 -0800708 if (finalStatus != OK) {
709 ALOGV("onPollBuffering: EOS (finalStatus = %d)", finalStatus);
710
711 if (finalStatus == ERROR_END_OF_STREAM) {
712 notifyBufferingUpdate(100);
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700713 }
714
Chong Zhangefbb6192015-01-30 17:13:27 -0800715 stopBufferingIfNecessary();
716 return;
717 } else if (cachedDurationUs >= 0ll) {
718 if (mDurationUs > 0ll) {
719 int64_t cachedPosUs = getLastReadPosition() + cachedDurationUs;
720 int percentage = 100.0 * cachedPosUs / mDurationUs;
721 if (percentage > 100) {
722 percentage = 100;
723 }
724
725 notifyBufferingUpdate(percentage);
726 }
727
728 ALOGV("onPollBuffering: cachedDurationUs %.1f sec",
729 cachedDurationUs / 1000000.0f);
730
731 if (cachedDurationUs < kLowWaterMarkUs) {
732 startBufferingIfNecessary();
733 } else if (cachedDurationUs > kHighWaterMarkUs) {
734 stopBufferingIfNecessary();
735 }
736 } else if (cachedDataRemaining >= 0) {
Lajos Molnar6d339f12015-04-17 16:15:53 -0700737 ALOGV("onPollBuffering: cachedDataRemaining %zd bytes",
Chong Zhangefbb6192015-01-30 17:13:27 -0800738 cachedDataRemaining);
739
740 if (cachedDataRemaining < kLowWaterMarkBytes) {
741 startBufferingIfNecessary();
742 } else if (cachedDataRemaining > kHighWaterMarkBytes) {
743 stopBufferingIfNecessary();
744 }
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700745 }
746
747 schedulePollBuffering();
748}
749
Robert Shih3423bbd2014-07-16 15:47:09 -0700750void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) {
751 switch (msg->what()) {
Chong Zhang1228d6b2014-08-12 21:25:48 -0700752 case kWhatPrepareAsync:
753 {
754 onPrepareAsync();
755 break;
756 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700757 case kWhatFetchSubtitleData:
758 {
Lajos Molnare26940f2014-07-31 10:31:26 -0700759 fetchTextData(kWhatSendSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
760 mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
761 break;
762 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700763
Lajos Molnare26940f2014-07-31 10:31:26 -0700764 case kWhatFetchTimedTextData:
765 {
766 fetchTextData(kWhatSendTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
767 mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
Robert Shih3423bbd2014-07-16 15:47:09 -0700768 break;
769 }
770
771 case kWhatSendSubtitleData:
772 {
Lajos Molnare26940f2014-07-31 10:31:26 -0700773 sendTextData(kWhatSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
774 mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg);
775 break;
776 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700777
Marco Nelissen55e2f4c2015-09-04 15:57:15 -0700778 case kWhatSendGlobalTimedTextData:
779 {
780 sendGlobalTextData(kWhatTimedTextData, mFetchTimedTextDataGeneration, msg);
781 break;
782 }
Lajos Molnare26940f2014-07-31 10:31:26 -0700783 case kWhatSendTimedTextData:
784 {
785 sendTextData(kWhatTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
786 mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg);
Robert Shih3423bbd2014-07-16 15:47:09 -0700787 break;
788 }
789
790 case kWhatChangeAVSource:
791 {
792 int32_t trackIndex;
793 CHECK(msg->findInt32("trackIndex", &trackIndex));
Marco Nelissenb2487f02015-09-01 13:23:23 -0700794 const sp<IMediaSource> source = mSources.itemAt(trackIndex);
Robert Shih3423bbd2014-07-16 15:47:09 -0700795
796 Track* track;
797 const char *mime;
798 media_track_type trackType, counterpartType;
799 sp<MetaData> meta = source->getFormat();
800 meta->findCString(kKeyMIMEType, &mime);
801 if (!strncasecmp(mime, "audio/", 6)) {
802 track = &mAudioTrack;
803 trackType = MEDIA_TRACK_TYPE_AUDIO;
804 counterpartType = MEDIA_TRACK_TYPE_VIDEO;;
805 } else {
806 CHECK(!strncasecmp(mime, "video/", 6));
807 track = &mVideoTrack;
808 trackType = MEDIA_TRACK_TYPE_VIDEO;
809 counterpartType = MEDIA_TRACK_TYPE_AUDIO;;
810 }
811
812
813 if (track->mSource != NULL) {
814 track->mSource->stop();
815 }
816 track->mSource = source;
817 track->mSource->start();
818 track->mIndex = trackIndex;
819
Robert Shih3423bbd2014-07-16 15:47:09 -0700820 int64_t timeUs, actualTimeUs;
821 const bool formatChange = true;
Robert Shih5c67ddc2014-11-04 17:46:05 -0800822 if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
823 timeUs = mAudioLastDequeueTimeUs;
824 } else {
825 timeUs = mVideoLastDequeueTimeUs;
826 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700827 readBuffer(trackType, timeUs, &actualTimeUs, formatChange);
828 readBuffer(counterpartType, -1, NULL, formatChange);
Lajos Molnar6d339f12015-04-17 16:15:53 -0700829 ALOGV("timeUs %lld actualTimeUs %lld", (long long)timeUs, (long long)actualTimeUs);
Robert Shih3423bbd2014-07-16 15:47:09 -0700830
831 break;
832 }
Chong Zhangefbb6192015-01-30 17:13:27 -0800833
834 case kWhatStart:
835 case kWhatResume:
836 {
837 restartPollBuffering();
838 break;
839 }
840
Chong Zhang2a3cc9a2014-08-21 17:48:26 -0700841 case kWhatPollBuffering:
842 {
843 int32_t generation;
844 CHECK(msg->findInt32("generation", &generation));
845 if (generation == mPollBufferingGeneration) {
846 onPollBuffering();
847 }
848 break;
849 }
Robert Shih17f6dd62014-08-20 17:00:21 -0700850
851 case kWhatGetFormat:
852 {
853 onGetFormatMeta(msg);
854 break;
855 }
856
857 case kWhatGetSelectedTrack:
858 {
859 onGetSelectedTrack(msg);
860 break;
861 }
862
863 case kWhatSelectTrack:
864 {
865 onSelectTrack(msg);
866 break;
867 }
868
869 case kWhatSeek:
870 {
871 onSeek(msg);
872 break;
873 }
874
875 case kWhatReadBuffer:
876 {
877 onReadBuffer(msg);
878 break;
879 }
880
Lajos Molnarfcd3e942015-03-31 10:06:48 -0700881 case kWhatSecureDecodersInstantiated:
882 {
883 int32_t err;
884 CHECK(msg->findInt32("err", &err));
885 onSecureDecodersInstantiated(err);
886 break;
887 }
888
Andy Hung2abde2c2014-09-30 14:40:32 -0700889 case kWhatStopWidevine:
890 {
891 // mStopRead is only used for Widevine to prevent the video source
892 // from being read while the associated video decoder is shutting down.
893 mStopRead = true;
894 if (mVideoTrack.mSource != NULL) {
895 mVideoTrack.mPackets->clear();
896 }
897 sp<AMessage> response = new AMessage;
Lajos Molnar3f274362015-03-05 14:35:41 -0800898 sp<AReplyToken> replyID;
Andy Hung2abde2c2014-09-30 14:40:32 -0700899 CHECK(msg->senderAwaitsResponse(&replyID));
900 response->postReply(replyID);
901 break;
902 }
Robert Shih3423bbd2014-07-16 15:47:09 -0700903 default:
904 Source::onMessageReceived(msg);
905 break;
906 }
907}
908
Lajos Molnare26940f2014-07-31 10:31:26 -0700909void NuPlayer::GenericSource::fetchTextData(
910 uint32_t sendWhat,
911 media_track_type type,
912 int32_t curGen,
913 sp<AnotherPacketSource> packets,
914 sp<AMessage> msg) {
915 int32_t msgGeneration;
916 CHECK(msg->findInt32("generation", &msgGeneration));
917 if (msgGeneration != curGen) {
918 // stale
919 return;
920 }
921
922 int32_t avail;
923 if (packets->hasBufferAvailable(&avail)) {
924 return;
925 }
926
927 int64_t timeUs;
928 CHECK(msg->findInt64("timeUs", &timeUs));
929
930 int64_t subTimeUs;
931 readBuffer(type, timeUs, &subTimeUs);
932
933 int64_t delayUs = subTimeUs - timeUs;
934 if (msg->what() == kWhatFetchSubtitleData) {
935 const int64_t oneSecUs = 1000000ll;
936 delayUs -= oneSecUs;
937 }
Lajos Molnar1d15ab52015-03-04 16:46:34 -0800938 sp<AMessage> msg2 = new AMessage(sendWhat, this);
Lajos Molnare26940f2014-07-31 10:31:26 -0700939 msg2->setInt32("generation", msgGeneration);
940 msg2->post(delayUs < 0 ? 0 : delayUs);
941}
942
943void NuPlayer::GenericSource::sendTextData(
944 uint32_t what,
945 media_track_type type,
946 int32_t curGen,
947 sp<AnotherPacketSource> packets,
948 sp<AMessage> msg) {
949 int32_t msgGeneration;
950 CHECK(msg->findInt32("generation", &msgGeneration));
951 if (msgGeneration != curGen) {
952 // stale
953 return;
954 }
955
956 int64_t subTimeUs;
957 if (packets->nextBufferTime(&subTimeUs) != OK) {
958 return;
959 }
960
961 int64_t nextSubTimeUs;
962 readBuffer(type, -1, &nextSubTimeUs);
963
964 sp<ABuffer> buffer;
965 status_t dequeueStatus = packets->dequeueAccessUnit(&buffer);
966 if (dequeueStatus == OK) {
967 sp<AMessage> notify = dupNotify();
968 notify->setInt32("what", what);
969 notify->setBuffer("buffer", buffer);
970 notify->post();
971
972 const int64_t delayUs = nextSubTimeUs - subTimeUs;
973 msg->post(delayUs < 0 ? 0 : delayUs);
974 }
975}
976
Marco Nelissen55e2f4c2015-09-04 15:57:15 -0700977void NuPlayer::GenericSource::sendGlobalTextData(
978 uint32_t what,
979 int32_t curGen,
980 sp<AMessage> msg) {
981 int32_t msgGeneration;
982 CHECK(msg->findInt32("generation", &msgGeneration));
983 if (msgGeneration != curGen) {
984 // stale
985 return;
986 }
987
988 uint32_t textType;
989 const void *data;
990 size_t size = 0;
991 if (mTimedTextTrack.mSource->getFormat()->findData(
992 kKeyTextFormatData, &textType, &data, &size)) {
993 mGlobalTimedText = new ABuffer(size);
994 if (mGlobalTimedText->data()) {
995 memcpy(mGlobalTimedText->data(), data, size);
996 sp<AMessage> globalMeta = mGlobalTimedText->meta();
997 globalMeta->setInt64("timeUs", 0);
998 globalMeta->setString("mime", MEDIA_MIMETYPE_TEXT_3GPP);
999 globalMeta->setInt32("global", 1);
1000 sp<AMessage> notify = dupNotify();
1001 notify->setInt32("what", what);
1002 notify->setBuffer("buffer", mGlobalTimedText);
1003 notify->post();
1004 }
1005 }
1006}
1007
Andreas Huber84066782011-08-16 09:34:26 -07001008sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
Lajos Molnar1d15ab52015-03-04 16:46:34 -08001009 sp<AMessage> msg = new AMessage(kWhatGetFormat, this);
Robert Shih17f6dd62014-08-20 17:00:21 -07001010 msg->setInt32("audio", audio);
1011
1012 sp<AMessage> response;
1013 void *format;
1014 status_t err = msg->postAndAwaitResponse(&response);
1015 if (err == OK && response != NULL) {
1016 CHECK(response->findPointer("format", &format));
1017 return (MetaData *)format;
1018 } else {
1019 return NULL;
1020 }
1021}
1022
1023void NuPlayer::GenericSource::onGetFormatMeta(sp<AMessage> msg) const {
1024 int32_t audio;
1025 CHECK(msg->findInt32("audio", &audio));
1026
1027 sp<AMessage> response = new AMessage;
1028 sp<MetaData> format = doGetFormatMeta(audio);
1029 response->setPointer("format", format.get());
1030
Lajos Molnar3f274362015-03-05 14:35:41 -08001031 sp<AReplyToken> replyID;
Robert Shih17f6dd62014-08-20 17:00:21 -07001032 CHECK(msg->senderAwaitsResponse(&replyID));
1033 response->postReply(replyID);
1034}
1035
1036sp<MetaData> NuPlayer::GenericSource::doGetFormatMeta(bool audio) const {
Marco Nelissenb2487f02015-09-01 13:23:23 -07001037 sp<IMediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
Andreas Huberafed0e12011-09-20 15:39:58 -07001038
1039 if (source == NULL) {
1040 return NULL;
1041 }
1042
1043 return source->getFormat();
1044}
1045
1046status_t NuPlayer::GenericSource::dequeueAccessUnit(
1047 bool audio, sp<ABuffer> *accessUnit) {
1048 Track *track = audio ? &mAudioTrack : &mVideoTrack;
1049
1050 if (track->mSource == NULL) {
1051 return -EWOULDBLOCK;
1052 }
1053
Lajos Molnarcc227032014-07-17 15:33:06 -07001054 if (mIsWidevine && !audio) {
1055 // try to read a buffer as we may not have been able to the last time
Robert Shih17f6dd62014-08-20 17:00:21 -07001056 postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
Lajos Molnarcc227032014-07-17 15:33:06 -07001057 }
1058
Andreas Huberafed0e12011-09-20 15:39:58 -07001059 status_t finalResult;
1060 if (!track->mPackets->hasBufferAvailable(&finalResult)) {
Chong Zhang42e81532014-12-01 13:44:26 -08001061 if (finalResult == OK) {
1062 postReadBuffer(
1063 audio ? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
1064 return -EWOULDBLOCK;
1065 }
1066 return finalResult;
Andreas Huberafed0e12011-09-20 15:39:58 -07001067 }
1068
1069 status_t result = track->mPackets->dequeueAccessUnit(accessUnit);
1070
Chong Zhangfcf044a2015-07-14 15:58:51 -07001071 // start pulling in more buffers if we only have one (or no) buffer left
1072 // so that decoder has less chance of being starved
1073 if (track->mPackets->getAvailableBufferCount(&finalResult) < 2) {
Robert Shih17f6dd62014-08-20 17:00:21 -07001074 postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
Lajos Molnare26940f2014-07-31 10:31:26 -07001075 }
1076
Robert Shih3423bbd2014-07-16 15:47:09 -07001077 if (result != OK) {
Lajos Molnare26940f2014-07-31 10:31:26 -07001078 if (mSubtitleTrack.mSource != NULL) {
1079 mSubtitleTrack.mPackets->clear();
1080 mFetchSubtitleDataGeneration++;
1081 }
1082 if (mTimedTextTrack.mSource != NULL) {
1083 mTimedTextTrack.mPackets->clear();
1084 mFetchTimedTextDataGeneration++;
1085 }
Robert Shih3423bbd2014-07-16 15:47:09 -07001086 return result;
1087 }
1088
1089 int64_t timeUs;
1090 status_t eosResult; // ignored
1091 CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs));
Robert Shih5c67ddc2014-11-04 17:46:05 -08001092 if (audio) {
1093 mAudioLastDequeueTimeUs = timeUs;
1094 } else {
1095 mVideoLastDequeueTimeUs = timeUs;
1096 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001097
1098 if (mSubtitleTrack.mSource != NULL
1099 && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
Lajos Molnar1d15ab52015-03-04 16:46:34 -08001100 sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, this);
Robert Shih3423bbd2014-07-16 15:47:09 -07001101 msg->setInt64("timeUs", timeUs);
1102 msg->setInt32("generation", mFetchSubtitleDataGeneration);
1103 msg->post();
1104 }
Robert Shiheb1735e2014-07-23 15:53:14 -07001105
Lajos Molnare26940f2014-07-31 10:31:26 -07001106 if (mTimedTextTrack.mSource != NULL
1107 && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
Lajos Molnar1d15ab52015-03-04 16:46:34 -08001108 sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, this);
Lajos Molnare26940f2014-07-31 10:31:26 -07001109 msg->setInt64("timeUs", timeUs);
1110 msg->setInt32("generation", mFetchTimedTextDataGeneration);
1111 msg->post();
1112 }
1113
Andreas Huberafed0e12011-09-20 15:39:58 -07001114 return result;
1115}
1116
1117status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) {
1118 *durationUs = mDurationUs;
1119 return OK;
1120}
1121
Robert Shihdd235722014-06-12 14:49:23 -07001122size_t NuPlayer::GenericSource::getTrackCount() const {
1123 return mSources.size();
1124}
1125
1126sp<AMessage> NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const {
1127 size_t trackCount = mSources.size();
1128 if (trackIndex >= trackCount) {
1129 return NULL;
1130 }
1131
1132 sp<AMessage> format = new AMessage();
1133 sp<MetaData> meta = mSources.itemAt(trackIndex)->getFormat();
Marco Nelissenc367ca12015-09-15 09:51:59 -07001134 if (meta == NULL) {
1135 ALOGE("no metadata for track %zu", trackIndex);
1136 return NULL;
1137 }
Robert Shihdd235722014-06-12 14:49:23 -07001138
1139 const char *mime;
1140 CHECK(meta->findCString(kKeyMIMEType, &mime));
Robert Shih755106e2015-04-30 14:36:45 -07001141 format->setString("mime", mime);
Robert Shihdd235722014-06-12 14:49:23 -07001142
1143 int32_t trackType;
1144 if (!strncasecmp(mime, "video/", 6)) {
1145 trackType = MEDIA_TRACK_TYPE_VIDEO;
1146 } else if (!strncasecmp(mime, "audio/", 6)) {
1147 trackType = MEDIA_TRACK_TYPE_AUDIO;
1148 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
1149 trackType = MEDIA_TRACK_TYPE_TIMEDTEXT;
1150 } else {
1151 trackType = MEDIA_TRACK_TYPE_UNKNOWN;
1152 }
1153 format->setInt32("type", trackType);
1154
1155 const char *lang;
1156 if (!meta->findCString(kKeyMediaLanguage, &lang)) {
1157 lang = "und";
1158 }
1159 format->setString("language", lang);
1160
1161 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
Robert Shihdd235722014-06-12 14:49:23 -07001162 int32_t isAutoselect = 1, isDefault = 0, isForced = 0;
1163 meta->findInt32(kKeyTrackIsAutoselect, &isAutoselect);
1164 meta->findInt32(kKeyTrackIsDefault, &isDefault);
1165 meta->findInt32(kKeyTrackIsForced, &isForced);
1166
1167 format->setInt32("auto", !!isAutoselect);
1168 format->setInt32("default", !!isDefault);
1169 format->setInt32("forced", !!isForced);
1170 }
1171
1172 return format;
1173}
1174
Lajos Molnare26940f2014-07-31 10:31:26 -07001175ssize_t NuPlayer::GenericSource::getSelectedTrack(media_track_type type) const {
Lajos Molnar1d15ab52015-03-04 16:46:34 -08001176 sp<AMessage> msg = new AMessage(kWhatGetSelectedTrack, this);
Robert Shih17f6dd62014-08-20 17:00:21 -07001177 msg->setInt32("type", type);
1178
1179 sp<AMessage> response;
1180 int32_t index;
1181 status_t err = msg->postAndAwaitResponse(&response);
1182 if (err == OK && response != NULL) {
1183 CHECK(response->findInt32("index", &index));
1184 return index;
1185 } else {
1186 return -1;
1187 }
1188}
1189
1190void NuPlayer::GenericSource::onGetSelectedTrack(sp<AMessage> msg) const {
1191 int32_t tmpType;
1192 CHECK(msg->findInt32("type", &tmpType));
1193 media_track_type type = (media_track_type)tmpType;
1194
1195 sp<AMessage> response = new AMessage;
1196 ssize_t index = doGetSelectedTrack(type);
1197 response->setInt32("index", index);
1198
Lajos Molnar3f274362015-03-05 14:35:41 -08001199 sp<AReplyToken> replyID;
Robert Shih17f6dd62014-08-20 17:00:21 -07001200 CHECK(msg->senderAwaitsResponse(&replyID));
1201 response->postReply(replyID);
1202}
1203
1204ssize_t NuPlayer::GenericSource::doGetSelectedTrack(media_track_type type) const {
Lajos Molnare26940f2014-07-31 10:31:26 -07001205 const Track *track = NULL;
1206 switch (type) {
1207 case MEDIA_TRACK_TYPE_VIDEO:
1208 track = &mVideoTrack;
1209 break;
1210 case MEDIA_TRACK_TYPE_AUDIO:
1211 track = &mAudioTrack;
1212 break;
1213 case MEDIA_TRACK_TYPE_TIMEDTEXT:
1214 track = &mTimedTextTrack;
1215 break;
1216 case MEDIA_TRACK_TYPE_SUBTITLE:
1217 track = &mSubtitleTrack;
1218 break;
1219 default:
1220 break;
1221 }
1222
1223 if (track != NULL && track->mSource != NULL) {
1224 return track->mIndex;
1225 }
1226
1227 return -1;
1228}
1229
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001230status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select, int64_t timeUs) {
Lajos Molnare26940f2014-07-31 10:31:26 -07001231 ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex);
Lajos Molnar1d15ab52015-03-04 16:46:34 -08001232 sp<AMessage> msg = new AMessage(kWhatSelectTrack, this);
Robert Shih17f6dd62014-08-20 17:00:21 -07001233 msg->setInt32("trackIndex", trackIndex);
Robert Shihda23ab92014-09-16 11:34:08 -07001234 msg->setInt32("select", select);
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001235 msg->setInt64("timeUs", timeUs);
Robert Shih17f6dd62014-08-20 17:00:21 -07001236
1237 sp<AMessage> response;
1238 status_t err = msg->postAndAwaitResponse(&response);
1239 if (err == OK && response != NULL) {
1240 CHECK(response->findInt32("err", &err));
1241 }
1242
1243 return err;
1244}
1245
1246void NuPlayer::GenericSource::onSelectTrack(sp<AMessage> msg) {
1247 int32_t trackIndex, select;
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001248 int64_t timeUs;
Robert Shih17f6dd62014-08-20 17:00:21 -07001249 CHECK(msg->findInt32("trackIndex", &trackIndex));
1250 CHECK(msg->findInt32("select", &select));
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001251 CHECK(msg->findInt64("timeUs", &timeUs));
Robert Shih17f6dd62014-08-20 17:00:21 -07001252
1253 sp<AMessage> response = new AMessage;
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001254 status_t err = doSelectTrack(trackIndex, select, timeUs);
Robert Shih17f6dd62014-08-20 17:00:21 -07001255 response->setInt32("err", err);
1256
Lajos Molnar3f274362015-03-05 14:35:41 -08001257 sp<AReplyToken> replyID;
Robert Shih17f6dd62014-08-20 17:00:21 -07001258 CHECK(msg->senderAwaitsResponse(&replyID));
1259 response->postReply(replyID);
1260}
1261
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001262status_t NuPlayer::GenericSource::doSelectTrack(size_t trackIndex, bool select, int64_t timeUs) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001263 if (trackIndex >= mSources.size()) {
1264 return BAD_INDEX;
1265 }
1266
1267 if (!select) {
Lajos Molnare26940f2014-07-31 10:31:26 -07001268 Track* track = NULL;
1269 if (mSubtitleTrack.mSource != NULL && trackIndex == mSubtitleTrack.mIndex) {
1270 track = &mSubtitleTrack;
1271 mFetchSubtitleDataGeneration++;
1272 } else if (mTimedTextTrack.mSource != NULL && trackIndex == mTimedTextTrack.mIndex) {
1273 track = &mTimedTextTrack;
1274 mFetchTimedTextDataGeneration++;
1275 }
1276 if (track == NULL) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001277 return INVALID_OPERATION;
1278 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001279 track->mSource->stop();
1280 track->mSource = NULL;
1281 track->mPackets->clear();
Robert Shih3423bbd2014-07-16 15:47:09 -07001282 return OK;
1283 }
1284
Marco Nelissenb2487f02015-09-01 13:23:23 -07001285 const sp<IMediaSource> source = mSources.itemAt(trackIndex);
Robert Shih3423bbd2014-07-16 15:47:09 -07001286 sp<MetaData> meta = source->getFormat();
1287 const char *mime;
1288 CHECK(meta->findCString(kKeyMIMEType, &mime));
1289 if (!strncasecmp(mime, "text/", 5)) {
Lajos Molnare26940f2014-07-31 10:31:26 -07001290 bool isSubtitle = strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP);
1291 Track *track = isSubtitle ? &mSubtitleTrack : &mTimedTextTrack;
1292 if (track->mSource != NULL && track->mIndex == trackIndex) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001293 return OK;
1294 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001295 track->mIndex = trackIndex;
1296 if (track->mSource != NULL) {
1297 track->mSource->stop();
Robert Shih3423bbd2014-07-16 15:47:09 -07001298 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001299 track->mSource = mSources.itemAt(trackIndex);
1300 track->mSource->start();
1301 if (track->mPackets == NULL) {
1302 track->mPackets = new AnotherPacketSource(track->mSource->getFormat());
Robert Shih3423bbd2014-07-16 15:47:09 -07001303 } else {
Lajos Molnare26940f2014-07-31 10:31:26 -07001304 track->mPackets->clear();
1305 track->mPackets->setFormat(track->mSource->getFormat());
Robert Shih3423bbd2014-07-16 15:47:09 -07001306
1307 }
Lajos Molnare26940f2014-07-31 10:31:26 -07001308
1309 if (isSubtitle) {
1310 mFetchSubtitleDataGeneration++;
1311 } else {
1312 mFetchTimedTextDataGeneration++;
1313 }
1314
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001315 status_t eosResult; // ignored
1316 if (mSubtitleTrack.mSource != NULL
1317 && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
Lajos Molnar1d15ab52015-03-04 16:46:34 -08001318 sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, this);
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001319 msg->setInt64("timeUs", timeUs);
1320 msg->setInt32("generation", mFetchSubtitleDataGeneration);
1321 msg->post();
1322 }
1323
Marco Nelissen55e2f4c2015-09-04 15:57:15 -07001324 sp<AMessage> msg2 = new AMessage(kWhatSendGlobalTimedTextData, this);
1325 msg2->setInt32("generation", mFetchTimedTextDataGeneration);
1326 msg2->post();
1327
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001328 if (mTimedTextTrack.mSource != NULL
1329 && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
Lajos Molnar1d15ab52015-03-04 16:46:34 -08001330 sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, this);
Robert Shih6ffb1fd2014-10-29 16:24:32 -07001331 msg->setInt64("timeUs", timeUs);
1332 msg->setInt32("generation", mFetchTimedTextDataGeneration);
1333 msg->post();
1334 }
1335
Robert Shih3423bbd2014-07-16 15:47:09 -07001336 return OK;
1337 } else if (!strncasecmp(mime, "audio/", 6) || !strncasecmp(mime, "video/", 6)) {
1338 bool audio = !strncasecmp(mime, "audio/", 6);
1339 Track *track = audio ? &mAudioTrack : &mVideoTrack;
1340 if (track->mSource != NULL && track->mIndex == trackIndex) {
1341 return OK;
1342 }
1343
Lajos Molnar1d15ab52015-03-04 16:46:34 -08001344 sp<AMessage> msg = new AMessage(kWhatChangeAVSource, this);
Robert Shih3423bbd2014-07-16 15:47:09 -07001345 msg->setInt32("trackIndex", trackIndex);
1346 msg->post();
1347 return OK;
1348 }
1349
1350 return INVALID_OPERATION;
1351}
1352
Andreas Huberafed0e12011-09-20 15:39:58 -07001353status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) {
Lajos Molnar1d15ab52015-03-04 16:46:34 -08001354 sp<AMessage> msg = new AMessage(kWhatSeek, this);
Robert Shih17f6dd62014-08-20 17:00:21 -07001355 msg->setInt64("seekTimeUs", seekTimeUs);
1356
1357 sp<AMessage> response;
1358 status_t err = msg->postAndAwaitResponse(&response);
1359 if (err == OK && response != NULL) {
1360 CHECK(response->findInt32("err", &err));
1361 }
1362
1363 return err;
1364}
1365
1366void NuPlayer::GenericSource::onSeek(sp<AMessage> msg) {
1367 int64_t seekTimeUs;
1368 CHECK(msg->findInt64("seekTimeUs", &seekTimeUs));
1369
1370 sp<AMessage> response = new AMessage;
1371 status_t err = doSeek(seekTimeUs);
1372 response->setInt32("err", err);
1373
Lajos Molnar3f274362015-03-05 14:35:41 -08001374 sp<AReplyToken> replyID;
Robert Shih17f6dd62014-08-20 17:00:21 -07001375 CHECK(msg->senderAwaitsResponse(&replyID));
1376 response->postReply(replyID);
1377}
1378
1379status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs) {
Andy Hung2abde2c2014-09-30 14:40:32 -07001380 // If the Widevine source is stopped, do not attempt to read any
1381 // more buffers.
1382 if (mStopRead) {
1383 return INVALID_OPERATION;
1384 }
Andreas Huberafed0e12011-09-20 15:39:58 -07001385 if (mVideoTrack.mSource != NULL) {
1386 int64_t actualTimeUs;
Robert Shih3423bbd2014-07-16 15:47:09 -07001387 readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, &actualTimeUs);
Andreas Huberafed0e12011-09-20 15:39:58 -07001388
1389 seekTimeUs = actualTimeUs;
Robert Shih5c67ddc2014-11-04 17:46:05 -08001390 mVideoLastDequeueTimeUs = seekTimeUs;
Andreas Huberafed0e12011-09-20 15:39:58 -07001391 }
1392
1393 if (mAudioTrack.mSource != NULL) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001394 readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs);
Robert Shih5c67ddc2014-11-04 17:46:05 -08001395 mAudioLastDequeueTimeUs = seekTimeUs;
Andreas Huberafed0e12011-09-20 15:39:58 -07001396 }
1397
Ronghua Wu80276872014-08-28 15:50:29 -07001398 setDrmPlaybackStatusIfNeeded(Playback::START, seekTimeUs / 1000);
1399 if (!mStarted) {
1400 setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0);
1401 }
Chong Zhangefbb6192015-01-30 17:13:27 -08001402
1403 // If currently buffering, post kWhatBufferingEnd first, so that
1404 // NuPlayer resumes. Otherwise, if cache hits high watermark
1405 // before new polling happens, no one will resume the playback.
1406 stopBufferingIfNecessary();
1407 restartPollBuffering();
1408
Andreas Huberafed0e12011-09-20 15:39:58 -07001409 return OK;
1410}
1411
Robert Shih3423bbd2014-07-16 15:47:09 -07001412sp<ABuffer> NuPlayer::GenericSource::mediaBufferToABuffer(
1413 MediaBuffer* mb,
1414 media_track_type trackType,
Wei Jia474d7c72014-12-04 15:12:13 -08001415 int64_t /* seekTimeUs */,
Robert Shih3423bbd2014-07-16 15:47:09 -07001416 int64_t *actualTimeUs) {
1417 bool audio = trackType == MEDIA_TRACK_TYPE_AUDIO;
1418 size_t outLength = mb->range_length();
1419
1420 if (audio && mAudioIsVorbis) {
1421 outLength += sizeof(int32_t);
1422 }
1423
1424 sp<ABuffer> ab;
Chong Zhang42e81532014-12-01 13:44:26 -08001425 if (mIsSecure && !audio) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001426 // data is already provided in the buffer
1427 ab = new ABuffer(NULL, mb->range_length());
Robert Shih3423bbd2014-07-16 15:47:09 -07001428 mb->add_ref();
Wei Jia96e92b52014-09-18 17:36:20 -07001429 ab->setMediaBufferBase(mb);
Robert Shih3423bbd2014-07-16 15:47:09 -07001430 } else {
1431 ab = new ABuffer(outLength);
1432 memcpy(ab->data(),
1433 (const uint8_t *)mb->data() + mb->range_offset(),
1434 mb->range_length());
1435 }
1436
1437 if (audio && mAudioIsVorbis) {
1438 int32_t numPageSamples;
1439 if (!mb->meta_data()->findInt32(kKeyValidSamples, &numPageSamples)) {
1440 numPageSamples = -1;
1441 }
1442
1443 uint8_t* abEnd = ab->data() + mb->range_length();
1444 memcpy(abEnd, &numPageSamples, sizeof(numPageSamples));
1445 }
1446
Lajos Molnare26940f2014-07-31 10:31:26 -07001447 sp<AMessage> meta = ab->meta();
1448
Robert Shih3423bbd2014-07-16 15:47:09 -07001449 int64_t timeUs;
1450 CHECK(mb->meta_data()->findInt64(kKeyTime, &timeUs));
Robert Shih3423bbd2014-07-16 15:47:09 -07001451 meta->setInt64("timeUs", timeUs);
1452
Wei Jia474d7c72014-12-04 15:12:13 -08001453#if 0
1454 // Temporarily disable pre-roll till we have a full solution to handle
1455 // both single seek and continous seek gracefully.
1456 if (seekTimeUs > timeUs) {
1457 sp<AMessage> extra = new AMessage;
1458 extra->setInt64("resume-at-mediaTimeUs", seekTimeUs);
1459 meta->setMessage("extra", extra);
1460 }
1461#endif
1462
Lajos Molnare26940f2014-07-31 10:31:26 -07001463 if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) {
1464 const char *mime;
1465 CHECK(mTimedTextTrack.mSource != NULL
1466 && mTimedTextTrack.mSource->getFormat()->findCString(kKeyMIMEType, &mime));
1467 meta->setString("mime", mime);
1468 }
1469
Robert Shih3423bbd2014-07-16 15:47:09 -07001470 int64_t durationUs;
1471 if (mb->meta_data()->findInt64(kKeyDuration, &durationUs)) {
1472 meta->setInt64("durationUs", durationUs);
1473 }
1474
1475 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
1476 meta->setInt32("trackIndex", mSubtitleTrack.mIndex);
1477 }
1478
Robert Shihf8bd8512015-04-23 16:39:18 -07001479 uint32_t dataType; // unused
1480 const void *seiData;
1481 size_t seiLength;
1482 if (mb->meta_data()->findData(kKeySEI, &dataType, &seiData, &seiLength)) {
1483 sp<ABuffer> sei = ABuffer::CreateAsCopy(seiData, seiLength);;
1484 meta->setBuffer("sei", sei);
1485 }
1486
Robert Shih3423bbd2014-07-16 15:47:09 -07001487 if (actualTimeUs) {
1488 *actualTimeUs = timeUs;
1489 }
1490
1491 mb->release();
1492 mb = NULL;
1493
1494 return ab;
1495}
1496
Robert Shih17f6dd62014-08-20 17:00:21 -07001497void NuPlayer::GenericSource::postReadBuffer(media_track_type trackType) {
Lajos Molnar84f52782014-09-11 10:01:55 -07001498 Mutex::Autolock _l(mReadBufferLock);
1499
1500 if ((mPendingReadBufferTypes & (1 << trackType)) == 0) {
1501 mPendingReadBufferTypes |= (1 << trackType);
Lajos Molnar1d15ab52015-03-04 16:46:34 -08001502 sp<AMessage> msg = new AMessage(kWhatReadBuffer, this);
Lajos Molnar84f52782014-09-11 10:01:55 -07001503 msg->setInt32("trackType", trackType);
1504 msg->post();
1505 }
Robert Shih17f6dd62014-08-20 17:00:21 -07001506}
1507
1508void NuPlayer::GenericSource::onReadBuffer(sp<AMessage> msg) {
1509 int32_t tmpType;
1510 CHECK(msg->findInt32("trackType", &tmpType));
1511 media_track_type trackType = (media_track_type)tmpType;
Chong Zhang42e81532014-12-01 13:44:26 -08001512 readBuffer(trackType);
Lajos Molnar84f52782014-09-11 10:01:55 -07001513 {
1514 // only protect the variable change, as readBuffer may
Chong Zhang42e81532014-12-01 13:44:26 -08001515 // take considerable time.
Lajos Molnar84f52782014-09-11 10:01:55 -07001516 Mutex::Autolock _l(mReadBufferLock);
1517 mPendingReadBufferTypes &= ~(1 << trackType);
1518 }
Robert Shih17f6dd62014-08-20 17:00:21 -07001519}
1520
Andreas Huberafed0e12011-09-20 15:39:58 -07001521void NuPlayer::GenericSource::readBuffer(
Robert Shih3423bbd2014-07-16 15:47:09 -07001522 media_track_type trackType, int64_t seekTimeUs, int64_t *actualTimeUs, bool formatChange) {
Andy Hung2abde2c2014-09-30 14:40:32 -07001523 // Do not read data if Widevine source is stopped
1524 if (mStopRead) {
1525 return;
1526 }
Robert Shih3423bbd2014-07-16 15:47:09 -07001527 Track *track;
Phil Burkc5cc2e22014-09-09 20:08:39 -07001528 size_t maxBuffers = 1;
Robert Shih3423bbd2014-07-16 15:47:09 -07001529 switch (trackType) {
1530 case MEDIA_TRACK_TYPE_VIDEO:
1531 track = &mVideoTrack;
Jeff Tinkera28785a2014-09-23 22:24:26 -07001532 if (mIsWidevine) {
1533 maxBuffers = 2;
Chong Zhangfcf044a2015-07-14 15:58:51 -07001534 } else {
1535 maxBuffers = 4;
Jeff Tinkera28785a2014-09-23 22:24:26 -07001536 }
Robert Shih3423bbd2014-07-16 15:47:09 -07001537 break;
1538 case MEDIA_TRACK_TYPE_AUDIO:
1539 track = &mAudioTrack;
Jeff Tinkera28785a2014-09-23 22:24:26 -07001540 if (mIsWidevine) {
1541 maxBuffers = 8;
1542 } else {
1543 maxBuffers = 64;
1544 }
Robert Shih3423bbd2014-07-16 15:47:09 -07001545 break;
1546 case MEDIA_TRACK_TYPE_SUBTITLE:
1547 track = &mSubtitleTrack;
1548 break;
Lajos Molnare26940f2014-07-31 10:31:26 -07001549 case MEDIA_TRACK_TYPE_TIMEDTEXT:
1550 track = &mTimedTextTrack;
1551 break;
Robert Shih3423bbd2014-07-16 15:47:09 -07001552 default:
1553 TRESPASS();
1554 }
1555
1556 if (track->mSource == NULL) {
1557 return;
1558 }
Andreas Huberafed0e12011-09-20 15:39:58 -07001559
1560 if (actualTimeUs) {
1561 *actualTimeUs = seekTimeUs;
1562 }
1563
1564 MediaSource::ReadOptions options;
1565
1566 bool seeking = false;
1567
1568 if (seekTimeUs >= 0) {
Robert Shih3423bbd2014-07-16 15:47:09 -07001569 options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
Andreas Huberafed0e12011-09-20 15:39:58 -07001570 seeking = true;
1571 }
1572
Chong Zhang42e81532014-12-01 13:44:26 -08001573 if (mIsWidevine) {
Lajos Molnarcc227032014-07-17 15:33:06 -07001574 options.setNonBlocking();
1575 }
1576
Phil Burkc5cc2e22014-09-09 20:08:39 -07001577 for (size_t numBuffers = 0; numBuffers < maxBuffers; ) {
Andreas Huberafed0e12011-09-20 15:39:58 -07001578 MediaBuffer *mbuf;
1579 status_t err = track->mSource->read(&mbuf, &options);
1580
1581 options.clearSeekTo();
1582
1583 if (err == OK) {
Ronghua Wu80276872014-08-28 15:50:29 -07001584 int64_t timeUs;
1585 CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs));
1586 if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
1587 mAudioTimeUs = timeUs;
1588 } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
1589 mVideoTimeUs = timeUs;
1590 }
1591
Ronghua Wu8f291bc2015-05-19 10:11:53 -07001592 queueDiscontinuityIfNeeded(seeking, formatChange, trackType, track);
Andreas Huberafed0e12011-09-20 15:39:58 -07001593
Wei Jia474d7c72014-12-04 15:12:13 -08001594 sp<ABuffer> buffer = mediaBufferToABuffer(
Shivaprasad Hongal98e7ece2015-07-23 19:57:14 -07001595 mbuf, trackType, seekTimeUs,
1596 numBuffers == 0 ? actualTimeUs : NULL);
Andreas Huberafed0e12011-09-20 15:39:58 -07001597 track->mPackets->queueAccessUnit(buffer);
Marco Nelissen317a49a2014-09-16 21:32:33 -07001598 formatChange = false;
1599 seeking = false;
Phil Burkc5cc2e22014-09-09 20:08:39 -07001600 ++numBuffers;
Lajos Molnarcc227032014-07-17 15:33:06 -07001601 } else if (err == WOULD_BLOCK) {
1602 break;
Andreas Huberafed0e12011-09-20 15:39:58 -07001603 } else if (err == INFO_FORMAT_CHANGED) {
1604#if 0
1605 track->mPackets->queueDiscontinuity(
Chong Zhang632740c2014-06-26 13:03:47 -07001606 ATSParser::DISCONTINUITY_FORMATCHANGE,
1607 NULL,
1608 false /* discard */);
Andreas Huberafed0e12011-09-20 15:39:58 -07001609#endif
1610 } else {
Ronghua Wu8f291bc2015-05-19 10:11:53 -07001611 queueDiscontinuityIfNeeded(seeking, formatChange, trackType, track);
Andreas Huberafed0e12011-09-20 15:39:58 -07001612 track->mPackets->signalEOS(err);
1613 break;
1614 }
1615 }
1616}
1617
Ronghua Wu8f291bc2015-05-19 10:11:53 -07001618void NuPlayer::GenericSource::queueDiscontinuityIfNeeded(
1619 bool seeking, bool formatChange, media_track_type trackType, Track *track) {
1620 // formatChange && seeking: track whose source is changed during selection
1621 // formatChange && !seeking: track whose source is not changed during selection
1622 // !formatChange: normal seek
1623 if ((seeking || formatChange)
1624 && (trackType == MEDIA_TRACK_TYPE_AUDIO
1625 || trackType == MEDIA_TRACK_TYPE_VIDEO)) {
1626 ATSParser::DiscontinuityType type = (formatChange && seeking)
1627 ? ATSParser::DISCONTINUITY_FORMATCHANGE
1628 : ATSParser::DISCONTINUITY_NONE;
1629 track->mPackets->queueDiscontinuity(type, NULL /* extra */, true /* discard */);
1630 }
1631}
1632
Andreas Huberafed0e12011-09-20 15:39:58 -07001633} // namespace android