GenericSource.cpp revision fef808d42a9c94b0b5ef3c3d5fb0a090edbc42da
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Copyright (C) 2012 The Android Open Source Project 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Licensed under the Apache License, Version 2.0 (the "License"); 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * you may not use this file except in compliance with the License. 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * You may obtain a copy of the License at 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * http://www.apache.org/licenses/LICENSE-2.0 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Unless required by applicable law or agreed to in writing, software 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * distributed under the License is distributed on an "AS IS" BASIS, 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * See the License for the specific language governing permissions and 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * limitations under the License. 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//#define LOG_NDEBUG 0 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define LOG_TAG "GenericSource" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "GenericSource.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "AnotherPacketSource.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <media/IMediaHTTPService.h> 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <media/stagefright/foundation/ABuffer.h> 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <media/stagefright/foundation/ADebug.h> 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <media/stagefright/foundation/AMessage.h> 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <media/stagefright/DataSource.h> 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <media/stagefright/FileSource.h> 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <media/stagefright/MediaBuffer.h> 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <media/stagefright/MediaDefs.h> 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <media/stagefright/MediaExtractor.h> 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <media/stagefright/MediaSource.h> 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <media/stagefright/MetaData.h> 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <media/stagefright/Utils.h> 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "../../libstagefright/include/DRMExtractor.h" 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "../../libstagefright/include/NuCachedSource2.h" 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "../../libstagefright/include/WVMExtractor.h" 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "../../libstagefright/include/HTTPBase.h" 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace android { 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NuPlayer::GenericSource::GenericSource( 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sp<AMessage> ¬ify, 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool uidValid, 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uid_t uid) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : Source(notify), 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mFetchSubtitleDataGeneration(0), 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mFetchTimedTextDataGeneration(0), 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mDurationUs(0ll), 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mAudioIsVorbis(false), 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mIsWidevine(false), 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mUIDValid(uidValid), 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mUID(uid), 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mDrmManagerClient(NULL), 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mMetaDataSize(-1ll), 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mBitrate(-1ll), 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mPollBufferingGeneration(0), 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mPendingReadBufferTypes(0) { 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resetDataSource(); 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DataSource::RegisterDefaultSniffers(); 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NuPlayer::GenericSource::resetDataSource() { 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mAudioTimeUs = 0; 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mVideoTimeUs = 0; 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mHTTPService.clear(); 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mHttpSource.clear(); 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mUri.clear(); 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mUriHeaders.clear(); 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mFd = -1; 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mOffset = 0; 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mLength = 0; 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) setDrmPlaybackStatusIfNeeded(Playback::STOP, 0); 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mDecryptHandle = NULL; 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mDrmManagerClient = NULL; 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mStarted = false; 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mStopRead = true; 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)status_t NuPlayer::GenericSource::setDataSource( 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sp<IMediaHTTPService> &httpService, 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char *url, 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const KeyedVector<String8, String8> *headers) { 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resetDataSource(); 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mHTTPService = httpService; 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mUri = url; 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (headers) { 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mUriHeaders = *headers; 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // delay data source creation to prepareAsync() to avoid blocking 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the calling thread in setDataSource for any significant time. 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)status_t NuPlayer::GenericSource::setDataSource( 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int fd, int64_t offset, int64_t length) { 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resetDataSource(); 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mFd = dup(fd); 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mOffset = offset; 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mLength = length; 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // delay data source creation to prepareAsync() to avoid blocking 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the calling thread in setDataSource for any significant time. 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return OK; 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 112sp<MetaData> NuPlayer::GenericSource::getFileFormatMeta() const { 113 return mFileMeta; 114} 115 116status_t NuPlayer::GenericSource::initFromDataSource() { 117 sp<MediaExtractor> extractor; 118 119 CHECK(mDataSource != NULL); 120 121 if (mIsWidevine) { 122 String8 mimeType; 123 float confidence; 124 sp<AMessage> dummy; 125 bool success; 126 127 success = SniffWVM(mDataSource, &mimeType, &confidence, &dummy); 128 if (!success 129 || strcasecmp( 130 mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) { 131 ALOGE("unsupported widevine mime: %s", mimeType.string()); 132 return UNKNOWN_ERROR; 133 } 134 135 mWVMExtractor = new WVMExtractor(mDataSource); 136 mWVMExtractor->setAdaptiveStreamingMode(true); 137 if (mUIDValid) { 138 mWVMExtractor->setUID(mUID); 139 } 140 extractor = mWVMExtractor; 141 } else { 142 extractor = MediaExtractor::Create(mDataSource, 143 mSniffedMIME.empty() ? NULL: mSniffedMIME.c_str()); 144 } 145 146 if (extractor == NULL) { 147 return UNKNOWN_ERROR; 148 } 149 150 if (extractor->getDrmFlag()) { 151 checkDrmStatus(mDataSource); 152 } 153 154 mFileMeta = extractor->getMetaData(); 155 if (mFileMeta != NULL) { 156 int64_t duration; 157 if (mFileMeta->findInt64(kKeyDuration, &duration)) { 158 mDurationUs = duration; 159 } 160 } 161 162 int32_t totalBitrate = 0; 163 164 size_t numtracks = extractor->countTracks(); 165 if (numtracks == 0) { 166 return UNKNOWN_ERROR; 167 } 168 169 for (size_t i = 0; i < numtracks; ++i) { 170 sp<MediaSource> track = extractor->getTrack(i); 171 172 sp<MetaData> meta = extractor->getTrackMetaData(i); 173 174 const char *mime; 175 CHECK(meta->findCString(kKeyMIMEType, &mime)); 176 177 // Do the string compare immediately with "mime", 178 // we can't assume "mime" would stay valid after another 179 // extractor operation, some extractors might modify meta 180 // during getTrack() and make it invalid. 181 if (!strncasecmp(mime, "audio/", 6)) { 182 if (mAudioTrack.mSource == NULL) { 183 mAudioTrack.mIndex = i; 184 mAudioTrack.mSource = track; 185 mAudioTrack.mPackets = 186 new AnotherPacketSource(mAudioTrack.mSource->getFormat()); 187 188 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) { 189 mAudioIsVorbis = true; 190 } else { 191 mAudioIsVorbis = false; 192 } 193 } 194 } else if (!strncasecmp(mime, "video/", 6)) { 195 if (mVideoTrack.mSource == NULL) { 196 mVideoTrack.mIndex = i; 197 mVideoTrack.mSource = track; 198 mVideoTrack.mPackets = 199 new AnotherPacketSource(mVideoTrack.mSource->getFormat()); 200 201 // check if the source requires secure buffers 202 int32_t secure; 203 if (meta->findInt32(kKeyRequiresSecureBuffers, &secure) 204 && secure) { 205 mIsWidevine = true; 206 if (mUIDValid) { 207 extractor->setUID(mUID); 208 } 209 } 210 } 211 } 212 213 if (track != NULL) { 214 mSources.push(track); 215 int64_t durationUs; 216 if (meta->findInt64(kKeyDuration, &durationUs)) { 217 if (durationUs > mDurationUs) { 218 mDurationUs = durationUs; 219 } 220 } 221 222 int32_t bitrate; 223 if (totalBitrate >= 0 && meta->findInt32(kKeyBitRate, &bitrate)) { 224 totalBitrate += bitrate; 225 } else { 226 totalBitrate = -1; 227 } 228 } 229 } 230 231 mBitrate = totalBitrate; 232 233 return OK; 234} 235 236void NuPlayer::GenericSource::checkDrmStatus(const sp<DataSource>& dataSource) { 237 dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient); 238 if (mDecryptHandle != NULL) { 239 CHECK(mDrmManagerClient); 240 if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) { 241 sp<AMessage> msg = dupNotify(); 242 msg->setInt32("what", kWhatDrmNoLicense); 243 msg->post(); 244 } 245 } 246} 247 248int64_t NuPlayer::GenericSource::getLastReadPosition() { 249 if (mAudioTrack.mSource != NULL) { 250 return mAudioTimeUs; 251 } else if (mVideoTrack.mSource != NULL) { 252 return mVideoTimeUs; 253 } else { 254 return 0; 255 } 256} 257 258status_t NuPlayer::GenericSource::setBuffers( 259 bool audio, Vector<MediaBuffer *> &buffers) { 260 if (mIsWidevine && !audio) { 261 return mVideoTrack.mSource->setBuffers(buffers); 262 } 263 return INVALID_OPERATION; 264} 265 266NuPlayer::GenericSource::~GenericSource() { 267 if (mLooper != NULL) { 268 mLooper->unregisterHandler(id()); 269 mLooper->stop(); 270 } 271} 272 273void NuPlayer::GenericSource::prepareAsync() { 274 if (mLooper == NULL) { 275 mLooper = new ALooper; 276 mLooper->setName("generic"); 277 mLooper->start(); 278 279 mLooper->registerHandler(this); 280 } 281 282 sp<AMessage> msg = new AMessage(kWhatPrepareAsync, id()); 283 msg->post(); 284} 285 286void NuPlayer::GenericSource::onPrepareAsync() { 287 // delayed data source creation 288 if (mDataSource == NULL) { 289 if (!mUri.empty()) { 290 const char* uri = mUri.c_str(); 291 mIsWidevine = !strncasecmp(uri, "widevine://", 11); 292 293 if (!strncasecmp("http://", uri, 7) 294 || !strncasecmp("https://", uri, 8) 295 || mIsWidevine) { 296 mHttpSource = DataSource::CreateMediaHTTP(mHTTPService); 297 if (mHttpSource == NULL) { 298 ALOGE("Failed to create http source!"); 299 notifyPreparedAndCleanup(UNKNOWN_ERROR); 300 return; 301 } 302 } 303 304 mDataSource = DataSource::CreateFromURI( 305 mHTTPService, uri, &mUriHeaders, &mContentType, 306 static_cast<HTTPBase *>(mHttpSource.get())); 307 } else { 308 // set to false first, if the extractor 309 // comes back as secure, set it to true then. 310 mIsWidevine = false; 311 312 mDataSource = new FileSource(mFd, mOffset, mLength); 313 } 314 315 if (mDataSource == NULL) { 316 ALOGE("Failed to create data source!"); 317 notifyPreparedAndCleanup(UNKNOWN_ERROR); 318 return; 319 } 320 321 if (mDataSource->flags() & DataSource::kIsCachingDataSource) { 322 mCachedSource = static_cast<NuCachedSource2 *>(mDataSource.get()); 323 } 324 325 if (mIsWidevine || mCachedSource != NULL) { 326 schedulePollBuffering(); 327 } 328 } 329 330 // check initial caching status 331 status_t err = prefillCacheIfNecessary(); 332 if (err != OK) { 333 if (err == -EAGAIN) { 334 (new AMessage(kWhatPrepareAsync, id()))->post(200000); 335 } else { 336 ALOGE("Failed to prefill data cache!"); 337 notifyPreparedAndCleanup(UNKNOWN_ERROR); 338 } 339 return; 340 } 341 342 // init extrator from data source 343 err = initFromDataSource(); 344 345 if (err != OK) { 346 ALOGE("Failed to init from data source!"); 347 notifyPreparedAndCleanup(err); 348 return; 349 } 350 351 if (mVideoTrack.mSource != NULL) { 352 sp<MetaData> meta = doGetFormatMeta(false /* audio */); 353 sp<AMessage> msg = new AMessage; 354 err = convertMetaDataToMessage(meta, &msg); 355 if(err != OK) { 356 notifyPreparedAndCleanup(err); 357 return; 358 } 359 notifyVideoSizeChanged(msg); 360 } 361 362 notifyFlagsChanged( 363 (mIsWidevine ? FLAG_SECURE : 0) 364 | FLAG_CAN_PAUSE 365 | FLAG_CAN_SEEK_BACKWARD 366 | FLAG_CAN_SEEK_FORWARD 367 | FLAG_CAN_SEEK); 368 369 notifyPrepared(); 370} 371 372void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) { 373 if (err != OK) { 374 mMetaDataSize = -1ll; 375 mContentType = ""; 376 mSniffedMIME = ""; 377 mDataSource.clear(); 378 mCachedSource.clear(); 379 mHttpSource.clear(); 380 381 cancelPollBuffering(); 382 } 383 notifyPrepared(err); 384} 385 386status_t NuPlayer::GenericSource::prefillCacheIfNecessary() { 387 CHECK(mDataSource != NULL); 388 389 if (mCachedSource == NULL) { 390 // no prefill if the data source is not cached 391 return OK; 392 } 393 394 // We're not doing this for streams that appear to be audio-only 395 // streams to ensure that even low bandwidth streams start 396 // playing back fairly instantly. 397 if (!strncasecmp(mContentType.string(), "audio/", 6)) { 398 return OK; 399 } 400 401 // We're going to prefill the cache before trying to instantiate 402 // the extractor below, as the latter is an operation that otherwise 403 // could block on the datasource for a significant amount of time. 404 // During that time we'd be unable to abort the preparation phase 405 // without this prefill. 406 407 // Initially make sure we have at least 192 KB for the sniff 408 // to complete without blocking. 409 static const size_t kMinBytesForSniffing = 192 * 1024; 410 static const size_t kDefaultMetaSize = 200000; 411 412 status_t finalStatus; 413 414 size_t cachedDataRemaining = 415 mCachedSource->approxDataRemaining(&finalStatus); 416 417 if (finalStatus != OK || (mMetaDataSize >= 0 418 && (off64_t)cachedDataRemaining >= mMetaDataSize)) { 419 ALOGV("stop caching, status %d, " 420 "metaDataSize %lld, cachedDataRemaining %zu", 421 finalStatus, mMetaDataSize, cachedDataRemaining); 422 return OK; 423 } 424 425 ALOGV("now cached %zu bytes of data", cachedDataRemaining); 426 427 if (mMetaDataSize < 0 428 && cachedDataRemaining >= kMinBytesForSniffing) { 429 String8 tmp; 430 float confidence; 431 sp<AMessage> meta; 432 if (!mCachedSource->sniff(&tmp, &confidence, &meta)) { 433 return UNKNOWN_ERROR; 434 } 435 436 // We successfully identified the file's extractor to 437 // be, remember this mime type so we don't have to 438 // sniff it again when we call MediaExtractor::Create() 439 mSniffedMIME = tmp.string(); 440 441 if (meta == NULL 442 || !meta->findInt64("meta-data-size", 443 reinterpret_cast<int64_t*>(&mMetaDataSize))) { 444 mMetaDataSize = kDefaultMetaSize; 445 } 446 447 if (mMetaDataSize < 0ll) { 448 ALOGE("invalid metaDataSize = %lld bytes", mMetaDataSize); 449 return UNKNOWN_ERROR; 450 } 451 } 452 453 return -EAGAIN; 454} 455 456void NuPlayer::GenericSource::start() { 457 ALOGI("start"); 458 459 mStopRead = false; 460 if (mAudioTrack.mSource != NULL) { 461 CHECK_EQ(mAudioTrack.mSource->start(), (status_t)OK); 462 463 postReadBuffer(MEDIA_TRACK_TYPE_AUDIO); 464 } 465 466 if (mVideoTrack.mSource != NULL) { 467 CHECK_EQ(mVideoTrack.mSource->start(), (status_t)OK); 468 469 postReadBuffer(MEDIA_TRACK_TYPE_VIDEO); 470 } 471 472 setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000); 473 mStarted = true; 474} 475 476void NuPlayer::GenericSource::stop() { 477 // nothing to do, just account for DRM playback status 478 setDrmPlaybackStatusIfNeeded(Playback::STOP, 0); 479 mStarted = false; 480 if (mIsWidevine) { 481 // For a widevine source we need to prevent any further reads. 482 sp<AMessage> msg = new AMessage(kWhatStopWidevine, id()); 483 sp<AMessage> response; 484 (void) msg->postAndAwaitResponse(&response); 485 } 486} 487 488void NuPlayer::GenericSource::pause() { 489 // nothing to do, just account for DRM playback status 490 setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0); 491 mStarted = false; 492} 493 494void NuPlayer::GenericSource::resume() { 495 // nothing to do, just account for DRM playback status 496 setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000); 497 mStarted = true; 498} 499 500void NuPlayer::GenericSource::disconnect() { 501 if (mDataSource != NULL) { 502 // disconnect data source 503 if (mDataSource->flags() & DataSource::kIsCachingDataSource) { 504 static_cast<NuCachedSource2 *>(mDataSource.get())->disconnect(); 505 } 506 } else if (mHttpSource != NULL) { 507 static_cast<HTTPBase *>(mHttpSource.get())->disconnect(); 508 } 509} 510 511void NuPlayer::GenericSource::setDrmPlaybackStatusIfNeeded(int playbackStatus, int64_t position) { 512 if (mDecryptHandle != NULL) { 513 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, playbackStatus, position); 514 } 515 mSubtitleTrack.mPackets = new AnotherPacketSource(NULL); 516 mTimedTextTrack.mPackets = new AnotherPacketSource(NULL); 517} 518 519status_t NuPlayer::GenericSource::feedMoreTSData() { 520 return OK; 521} 522 523void NuPlayer::GenericSource::schedulePollBuffering() { 524 sp<AMessage> msg = new AMessage(kWhatPollBuffering, id()); 525 msg->setInt32("generation", mPollBufferingGeneration); 526 msg->post(1000000ll); 527} 528 529void NuPlayer::GenericSource::cancelPollBuffering() { 530 ++mPollBufferingGeneration; 531} 532 533void NuPlayer::GenericSource::notifyBufferingUpdate(int percentage) { 534 sp<AMessage> msg = dupNotify(); 535 msg->setInt32("what", kWhatBufferingUpdate); 536 msg->setInt32("percentage", percentage); 537 msg->post(); 538} 539 540void NuPlayer::GenericSource::onPollBuffering() { 541 status_t finalStatus = UNKNOWN_ERROR; 542 int64_t cachedDurationUs = 0ll; 543 544 if (mCachedSource != NULL) { 545 size_t cachedDataRemaining = 546 mCachedSource->approxDataRemaining(&finalStatus); 547 548 if (finalStatus == OK) { 549 off64_t size; 550 int64_t bitrate = 0ll; 551 if (mDurationUs > 0 && mCachedSource->getSize(&size) == OK) { 552 bitrate = size * 8000000ll / mDurationUs; 553 } else if (mBitrate > 0) { 554 bitrate = mBitrate; 555 } 556 if (bitrate > 0) { 557 cachedDurationUs = cachedDataRemaining * 8000000ll / bitrate; 558 } 559 } 560 } else if (mWVMExtractor != NULL) { 561 cachedDurationUs 562 = mWVMExtractor->getCachedDurationUs(&finalStatus); 563 } 564 565 if (finalStatus == ERROR_END_OF_STREAM) { 566 notifyBufferingUpdate(100); 567 cancelPollBuffering(); 568 return; 569 } else if (cachedDurationUs > 0ll && mDurationUs > 0ll) { 570 int percentage = 100.0 * cachedDurationUs / mDurationUs; 571 if (percentage > 100) { 572 percentage = 100; 573 } 574 575 notifyBufferingUpdate(percentage); 576 } 577 578 schedulePollBuffering(); 579} 580 581 582void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) { 583 switch (msg->what()) { 584 case kWhatPrepareAsync: 585 { 586 onPrepareAsync(); 587 break; 588 } 589 case kWhatFetchSubtitleData: 590 { 591 fetchTextData(kWhatSendSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE, 592 mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg); 593 break; 594 } 595 596 case kWhatFetchTimedTextData: 597 { 598 fetchTextData(kWhatSendTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT, 599 mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg); 600 break; 601 } 602 603 case kWhatSendSubtitleData: 604 { 605 sendTextData(kWhatSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE, 606 mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg); 607 break; 608 } 609 610 case kWhatSendTimedTextData: 611 { 612 sendTextData(kWhatTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT, 613 mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg); 614 break; 615 } 616 617 case kWhatChangeAVSource: 618 { 619 int32_t trackIndex; 620 CHECK(msg->findInt32("trackIndex", &trackIndex)); 621 const sp<MediaSource> source = mSources.itemAt(trackIndex); 622 623 Track* track; 624 const char *mime; 625 media_track_type trackType, counterpartType; 626 sp<MetaData> meta = source->getFormat(); 627 meta->findCString(kKeyMIMEType, &mime); 628 if (!strncasecmp(mime, "audio/", 6)) { 629 track = &mAudioTrack; 630 trackType = MEDIA_TRACK_TYPE_AUDIO; 631 counterpartType = MEDIA_TRACK_TYPE_VIDEO;; 632 } else { 633 CHECK(!strncasecmp(mime, "video/", 6)); 634 track = &mVideoTrack; 635 trackType = MEDIA_TRACK_TYPE_VIDEO; 636 counterpartType = MEDIA_TRACK_TYPE_AUDIO;; 637 } 638 639 640 if (track->mSource != NULL) { 641 track->mSource->stop(); 642 } 643 track->mSource = source; 644 track->mSource->start(); 645 track->mIndex = trackIndex; 646 647 status_t avail; 648 if (!track->mPackets->hasBufferAvailable(&avail)) { 649 // sync from other source 650 TRESPASS(); 651 break; 652 } 653 654 int64_t timeUs, actualTimeUs; 655 const bool formatChange = true; 656 sp<AMessage> latestMeta = track->mPackets->getLatestEnqueuedMeta(); 657 CHECK(latestMeta != NULL && latestMeta->findInt64("timeUs", &timeUs)); 658 readBuffer(trackType, timeUs, &actualTimeUs, formatChange); 659 readBuffer(counterpartType, -1, NULL, formatChange); 660 ALOGV("timeUs %lld actualTimeUs %lld", timeUs, actualTimeUs); 661 662 break; 663 } 664 case kWhatPollBuffering: 665 { 666 int32_t generation; 667 CHECK(msg->findInt32("generation", &generation)); 668 if (generation == mPollBufferingGeneration) { 669 onPollBuffering(); 670 } 671 break; 672 } 673 674 case kWhatGetFormat: 675 { 676 onGetFormatMeta(msg); 677 break; 678 } 679 680 case kWhatGetSelectedTrack: 681 { 682 onGetSelectedTrack(msg); 683 break; 684 } 685 686 case kWhatSelectTrack: 687 { 688 onSelectTrack(msg); 689 break; 690 } 691 692 case kWhatSeek: 693 { 694 onSeek(msg); 695 break; 696 } 697 698 case kWhatReadBuffer: 699 { 700 onReadBuffer(msg); 701 break; 702 } 703 704 case kWhatStopWidevine: 705 { 706 // mStopRead is only used for Widevine to prevent the video source 707 // from being read while the associated video decoder is shutting down. 708 mStopRead = true; 709 if (mVideoTrack.mSource != NULL) { 710 mVideoTrack.mPackets->clear(); 711 } 712 sp<AMessage> response = new AMessage; 713 uint32_t replyID; 714 CHECK(msg->senderAwaitsResponse(&replyID)); 715 response->postReply(replyID); 716 break; 717 } 718 default: 719 Source::onMessageReceived(msg); 720 break; 721 } 722} 723 724void NuPlayer::GenericSource::fetchTextData( 725 uint32_t sendWhat, 726 media_track_type type, 727 int32_t curGen, 728 sp<AnotherPacketSource> packets, 729 sp<AMessage> msg) { 730 int32_t msgGeneration; 731 CHECK(msg->findInt32("generation", &msgGeneration)); 732 if (msgGeneration != curGen) { 733 // stale 734 return; 735 } 736 737 int32_t avail; 738 if (packets->hasBufferAvailable(&avail)) { 739 return; 740 } 741 742 int64_t timeUs; 743 CHECK(msg->findInt64("timeUs", &timeUs)); 744 745 int64_t subTimeUs; 746 readBuffer(type, timeUs, &subTimeUs); 747 748 int64_t delayUs = subTimeUs - timeUs; 749 if (msg->what() == kWhatFetchSubtitleData) { 750 const int64_t oneSecUs = 1000000ll; 751 delayUs -= oneSecUs; 752 } 753 sp<AMessage> msg2 = new AMessage(sendWhat, id()); 754 msg2->setInt32("generation", msgGeneration); 755 msg2->post(delayUs < 0 ? 0 : delayUs); 756} 757 758void NuPlayer::GenericSource::sendTextData( 759 uint32_t what, 760 media_track_type type, 761 int32_t curGen, 762 sp<AnotherPacketSource> packets, 763 sp<AMessage> msg) { 764 int32_t msgGeneration; 765 CHECK(msg->findInt32("generation", &msgGeneration)); 766 if (msgGeneration != curGen) { 767 // stale 768 return; 769 } 770 771 int64_t subTimeUs; 772 if (packets->nextBufferTime(&subTimeUs) != OK) { 773 return; 774 } 775 776 int64_t nextSubTimeUs; 777 readBuffer(type, -1, &nextSubTimeUs); 778 779 sp<ABuffer> buffer; 780 status_t dequeueStatus = packets->dequeueAccessUnit(&buffer); 781 if (dequeueStatus == OK) { 782 sp<AMessage> notify = dupNotify(); 783 notify->setInt32("what", what); 784 notify->setBuffer("buffer", buffer); 785 notify->post(); 786 787 const int64_t delayUs = nextSubTimeUs - subTimeUs; 788 msg->post(delayUs < 0 ? 0 : delayUs); 789 } 790} 791 792sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) { 793 sp<AMessage> msg = new AMessage(kWhatGetFormat, id()); 794 msg->setInt32("audio", audio); 795 796 sp<AMessage> response; 797 void *format; 798 status_t err = msg->postAndAwaitResponse(&response); 799 if (err == OK && response != NULL) { 800 CHECK(response->findPointer("format", &format)); 801 return (MetaData *)format; 802 } else { 803 return NULL; 804 } 805} 806 807void NuPlayer::GenericSource::onGetFormatMeta(sp<AMessage> msg) const { 808 int32_t audio; 809 CHECK(msg->findInt32("audio", &audio)); 810 811 sp<AMessage> response = new AMessage; 812 sp<MetaData> format = doGetFormatMeta(audio); 813 response->setPointer("format", format.get()); 814 815 uint32_t replyID; 816 CHECK(msg->senderAwaitsResponse(&replyID)); 817 response->postReply(replyID); 818} 819 820sp<MetaData> NuPlayer::GenericSource::doGetFormatMeta(bool audio) const { 821 sp<MediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource; 822 823 if (source == NULL) { 824 return NULL; 825 } 826 827 return source->getFormat(); 828} 829 830status_t NuPlayer::GenericSource::dequeueAccessUnit( 831 bool audio, sp<ABuffer> *accessUnit) { 832 Track *track = audio ? &mAudioTrack : &mVideoTrack; 833 834 if (track->mSource == NULL) { 835 return -EWOULDBLOCK; 836 } 837 838 if (mIsWidevine && !audio) { 839 // try to read a buffer as we may not have been able to the last time 840 postReadBuffer(MEDIA_TRACK_TYPE_VIDEO); 841 } 842 843 status_t finalResult; 844 if (!track->mPackets->hasBufferAvailable(&finalResult)) { 845 return (finalResult == OK ? -EWOULDBLOCK : finalResult); 846 } 847 848 status_t result = track->mPackets->dequeueAccessUnit(accessUnit); 849 850 if (!track->mPackets->hasBufferAvailable(&finalResult)) { 851 postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO); 852 } 853 854 if (result != OK) { 855 if (mSubtitleTrack.mSource != NULL) { 856 mSubtitleTrack.mPackets->clear(); 857 mFetchSubtitleDataGeneration++; 858 } 859 if (mTimedTextTrack.mSource != NULL) { 860 mTimedTextTrack.mPackets->clear(); 861 mFetchTimedTextDataGeneration++; 862 } 863 return result; 864 } 865 866 int64_t timeUs; 867 status_t eosResult; // ignored 868 CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs)); 869 870 if (mSubtitleTrack.mSource != NULL 871 && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) { 872 sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, id()); 873 msg->setInt64("timeUs", timeUs); 874 msg->setInt32("generation", mFetchSubtitleDataGeneration); 875 msg->post(); 876 } 877 878 if (mTimedTextTrack.mSource != NULL 879 && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) { 880 sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, id()); 881 msg->setInt64("timeUs", timeUs); 882 msg->setInt32("generation", mFetchTimedTextDataGeneration); 883 msg->post(); 884 } 885 886 return result; 887} 888 889status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) { 890 *durationUs = mDurationUs; 891 return OK; 892} 893 894size_t NuPlayer::GenericSource::getTrackCount() const { 895 return mSources.size(); 896} 897 898sp<AMessage> NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const { 899 size_t trackCount = mSources.size(); 900 if (trackIndex >= trackCount) { 901 return NULL; 902 } 903 904 sp<AMessage> format = new AMessage(); 905 sp<MetaData> meta = mSources.itemAt(trackIndex)->getFormat(); 906 907 const char *mime; 908 CHECK(meta->findCString(kKeyMIMEType, &mime)); 909 910 int32_t trackType; 911 if (!strncasecmp(mime, "video/", 6)) { 912 trackType = MEDIA_TRACK_TYPE_VIDEO; 913 } else if (!strncasecmp(mime, "audio/", 6)) { 914 trackType = MEDIA_TRACK_TYPE_AUDIO; 915 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) { 916 trackType = MEDIA_TRACK_TYPE_TIMEDTEXT; 917 } else { 918 trackType = MEDIA_TRACK_TYPE_UNKNOWN; 919 } 920 format->setInt32("type", trackType); 921 922 const char *lang; 923 if (!meta->findCString(kKeyMediaLanguage, &lang)) { 924 lang = "und"; 925 } 926 format->setString("language", lang); 927 928 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) { 929 format->setString("mime", mime); 930 931 int32_t isAutoselect = 1, isDefault = 0, isForced = 0; 932 meta->findInt32(kKeyTrackIsAutoselect, &isAutoselect); 933 meta->findInt32(kKeyTrackIsDefault, &isDefault); 934 meta->findInt32(kKeyTrackIsForced, &isForced); 935 936 format->setInt32("auto", !!isAutoselect); 937 format->setInt32("default", !!isDefault); 938 format->setInt32("forced", !!isForced); 939 } 940 941 return format; 942} 943 944ssize_t NuPlayer::GenericSource::getSelectedTrack(media_track_type type) const { 945 sp<AMessage> msg = new AMessage(kWhatGetSelectedTrack, id()); 946 msg->setInt32("type", type); 947 948 sp<AMessage> response; 949 int32_t index; 950 status_t err = msg->postAndAwaitResponse(&response); 951 if (err == OK && response != NULL) { 952 CHECK(response->findInt32("index", &index)); 953 return index; 954 } else { 955 return -1; 956 } 957} 958 959void NuPlayer::GenericSource::onGetSelectedTrack(sp<AMessage> msg) const { 960 int32_t tmpType; 961 CHECK(msg->findInt32("type", &tmpType)); 962 media_track_type type = (media_track_type)tmpType; 963 964 sp<AMessage> response = new AMessage; 965 ssize_t index = doGetSelectedTrack(type); 966 response->setInt32("index", index); 967 968 uint32_t replyID; 969 CHECK(msg->senderAwaitsResponse(&replyID)); 970 response->postReply(replyID); 971} 972 973ssize_t NuPlayer::GenericSource::doGetSelectedTrack(media_track_type type) const { 974 const Track *track = NULL; 975 switch (type) { 976 case MEDIA_TRACK_TYPE_VIDEO: 977 track = &mVideoTrack; 978 break; 979 case MEDIA_TRACK_TYPE_AUDIO: 980 track = &mAudioTrack; 981 break; 982 case MEDIA_TRACK_TYPE_TIMEDTEXT: 983 track = &mTimedTextTrack; 984 break; 985 case MEDIA_TRACK_TYPE_SUBTITLE: 986 track = &mSubtitleTrack; 987 break; 988 default: 989 break; 990 } 991 992 if (track != NULL && track->mSource != NULL) { 993 return track->mIndex; 994 } 995 996 return -1; 997} 998 999status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select) { 1000 ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex); 1001 sp<AMessage> msg = new AMessage(kWhatSelectTrack, id()); 1002 msg->setInt32("trackIndex", trackIndex); 1003 msg->setInt32("select", select); 1004 1005 sp<AMessage> response; 1006 status_t err = msg->postAndAwaitResponse(&response); 1007 if (err == OK && response != NULL) { 1008 CHECK(response->findInt32("err", &err)); 1009 } 1010 1011 return err; 1012} 1013 1014void NuPlayer::GenericSource::onSelectTrack(sp<AMessage> msg) { 1015 int32_t trackIndex, select; 1016 CHECK(msg->findInt32("trackIndex", &trackIndex)); 1017 CHECK(msg->findInt32("select", &select)); 1018 1019 sp<AMessage> response = new AMessage; 1020 status_t err = doSelectTrack(trackIndex, select); 1021 response->setInt32("err", err); 1022 1023 uint32_t replyID; 1024 CHECK(msg->senderAwaitsResponse(&replyID)); 1025 response->postReply(replyID); 1026} 1027 1028status_t NuPlayer::GenericSource::doSelectTrack(size_t trackIndex, bool select) { 1029 if (trackIndex >= mSources.size()) { 1030 return BAD_INDEX; 1031 } 1032 1033 if (!select) { 1034 Track* track = NULL; 1035 if (mSubtitleTrack.mSource != NULL && trackIndex == mSubtitleTrack.mIndex) { 1036 track = &mSubtitleTrack; 1037 mFetchSubtitleDataGeneration++; 1038 } else if (mTimedTextTrack.mSource != NULL && trackIndex == mTimedTextTrack.mIndex) { 1039 track = &mTimedTextTrack; 1040 mFetchTimedTextDataGeneration++; 1041 } 1042 if (track == NULL) { 1043 return INVALID_OPERATION; 1044 } 1045 track->mSource->stop(); 1046 track->mSource = NULL; 1047 track->mPackets->clear(); 1048 return OK; 1049 } 1050 1051 const sp<MediaSource> source = mSources.itemAt(trackIndex); 1052 sp<MetaData> meta = source->getFormat(); 1053 const char *mime; 1054 CHECK(meta->findCString(kKeyMIMEType, &mime)); 1055 if (!strncasecmp(mime, "text/", 5)) { 1056 bool isSubtitle = strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP); 1057 Track *track = isSubtitle ? &mSubtitleTrack : &mTimedTextTrack; 1058 if (track->mSource != NULL && track->mIndex == trackIndex) { 1059 return OK; 1060 } 1061 track->mIndex = trackIndex; 1062 if (track->mSource != NULL) { 1063 track->mSource->stop(); 1064 } 1065 track->mSource = mSources.itemAt(trackIndex); 1066 track->mSource->start(); 1067 if (track->mPackets == NULL) { 1068 track->mPackets = new AnotherPacketSource(track->mSource->getFormat()); 1069 } else { 1070 track->mPackets->clear(); 1071 track->mPackets->setFormat(track->mSource->getFormat()); 1072 1073 } 1074 1075 if (isSubtitle) { 1076 mFetchSubtitleDataGeneration++; 1077 } else { 1078 mFetchTimedTextDataGeneration++; 1079 } 1080 1081 return OK; 1082 } else if (!strncasecmp(mime, "audio/", 6) || !strncasecmp(mime, "video/", 6)) { 1083 bool audio = !strncasecmp(mime, "audio/", 6); 1084 Track *track = audio ? &mAudioTrack : &mVideoTrack; 1085 if (track->mSource != NULL && track->mIndex == trackIndex) { 1086 return OK; 1087 } 1088 1089 sp<AMessage> msg = new AMessage(kWhatChangeAVSource, id()); 1090 msg->setInt32("trackIndex", trackIndex); 1091 msg->post(); 1092 return OK; 1093 } 1094 1095 return INVALID_OPERATION; 1096} 1097 1098status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) { 1099 sp<AMessage> msg = new AMessage(kWhatSeek, id()); 1100 msg->setInt64("seekTimeUs", seekTimeUs); 1101 1102 sp<AMessage> response; 1103 status_t err = msg->postAndAwaitResponse(&response); 1104 if (err == OK && response != NULL) { 1105 CHECK(response->findInt32("err", &err)); 1106 } 1107 1108 return err; 1109} 1110 1111void NuPlayer::GenericSource::onSeek(sp<AMessage> msg) { 1112 int64_t seekTimeUs; 1113 CHECK(msg->findInt64("seekTimeUs", &seekTimeUs)); 1114 1115 sp<AMessage> response = new AMessage; 1116 status_t err = doSeek(seekTimeUs); 1117 response->setInt32("err", err); 1118 1119 uint32_t replyID; 1120 CHECK(msg->senderAwaitsResponse(&replyID)); 1121 response->postReply(replyID); 1122} 1123 1124status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs) { 1125 // If the Widevine source is stopped, do not attempt to read any 1126 // more buffers. 1127 if (mStopRead) { 1128 return INVALID_OPERATION; 1129 } 1130 if (mVideoTrack.mSource != NULL) { 1131 int64_t actualTimeUs; 1132 readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, &actualTimeUs); 1133 1134 seekTimeUs = actualTimeUs; 1135 } 1136 1137 if (mAudioTrack.mSource != NULL) { 1138 readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs); 1139 } 1140 1141 setDrmPlaybackStatusIfNeeded(Playback::START, seekTimeUs / 1000); 1142 if (!mStarted) { 1143 setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0); 1144 } 1145 return OK; 1146} 1147 1148sp<ABuffer> NuPlayer::GenericSource::mediaBufferToABuffer( 1149 MediaBuffer* mb, 1150 media_track_type trackType, 1151 int64_t *actualTimeUs) { 1152 bool audio = trackType == MEDIA_TRACK_TYPE_AUDIO; 1153 size_t outLength = mb->range_length(); 1154 1155 if (audio && mAudioIsVorbis) { 1156 outLength += sizeof(int32_t); 1157 } 1158 1159 sp<ABuffer> ab; 1160 if (mIsWidevine && !audio) { 1161 // data is already provided in the buffer 1162 ab = new ABuffer(NULL, mb->range_length()); 1163 mb->add_ref(); 1164 ab->setMediaBufferBase(mb); 1165 } else { 1166 ab = new ABuffer(outLength); 1167 memcpy(ab->data(), 1168 (const uint8_t *)mb->data() + mb->range_offset(), 1169 mb->range_length()); 1170 } 1171 1172 if (audio && mAudioIsVorbis) { 1173 int32_t numPageSamples; 1174 if (!mb->meta_data()->findInt32(kKeyValidSamples, &numPageSamples)) { 1175 numPageSamples = -1; 1176 } 1177 1178 uint8_t* abEnd = ab->data() + mb->range_length(); 1179 memcpy(abEnd, &numPageSamples, sizeof(numPageSamples)); 1180 } 1181 1182 sp<AMessage> meta = ab->meta(); 1183 1184 int64_t timeUs; 1185 CHECK(mb->meta_data()->findInt64(kKeyTime, &timeUs)); 1186 meta->setInt64("timeUs", timeUs); 1187 1188 if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) { 1189 const char *mime; 1190 CHECK(mTimedTextTrack.mSource != NULL 1191 && mTimedTextTrack.mSource->getFormat()->findCString(kKeyMIMEType, &mime)); 1192 meta->setString("mime", mime); 1193 } 1194 1195 int64_t durationUs; 1196 if (mb->meta_data()->findInt64(kKeyDuration, &durationUs)) { 1197 meta->setInt64("durationUs", durationUs); 1198 } 1199 1200 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) { 1201 meta->setInt32("trackIndex", mSubtitleTrack.mIndex); 1202 } 1203 1204 if (actualTimeUs) { 1205 *actualTimeUs = timeUs; 1206 } 1207 1208 mb->release(); 1209 mb = NULL; 1210 1211 return ab; 1212} 1213 1214void NuPlayer::GenericSource::postReadBuffer(media_track_type trackType) { 1215 Mutex::Autolock _l(mReadBufferLock); 1216 1217 if ((mPendingReadBufferTypes & (1 << trackType)) == 0) { 1218 mPendingReadBufferTypes |= (1 << trackType); 1219 sp<AMessage> msg = new AMessage(kWhatReadBuffer, id()); 1220 msg->setInt32("trackType", trackType); 1221 msg->post(); 1222 } 1223} 1224 1225void NuPlayer::GenericSource::onReadBuffer(sp<AMessage> msg) { 1226 int32_t tmpType; 1227 CHECK(msg->findInt32("trackType", &tmpType)); 1228 media_track_type trackType = (media_track_type)tmpType; 1229 { 1230 // only protect the variable change, as readBuffer may 1231 // take considerable time. This may result in one extra 1232 // read being processed, but that is benign. 1233 Mutex::Autolock _l(mReadBufferLock); 1234 mPendingReadBufferTypes &= ~(1 << trackType); 1235 } 1236 readBuffer(trackType); 1237} 1238 1239void NuPlayer::GenericSource::readBuffer( 1240 media_track_type trackType, int64_t seekTimeUs, int64_t *actualTimeUs, bool formatChange) { 1241 // Do not read data if Widevine source is stopped 1242 if (mStopRead) { 1243 return; 1244 } 1245 Track *track; 1246 size_t maxBuffers = 1; 1247 switch (trackType) { 1248 case MEDIA_TRACK_TYPE_VIDEO: 1249 track = &mVideoTrack; 1250 if (mIsWidevine) { 1251 maxBuffers = 2; 1252 } 1253 break; 1254 case MEDIA_TRACK_TYPE_AUDIO: 1255 track = &mAudioTrack; 1256 if (mIsWidevine) { 1257 maxBuffers = 8; 1258 } else { 1259 maxBuffers = 64; 1260 } 1261 break; 1262 case MEDIA_TRACK_TYPE_SUBTITLE: 1263 track = &mSubtitleTrack; 1264 break; 1265 case MEDIA_TRACK_TYPE_TIMEDTEXT: 1266 track = &mTimedTextTrack; 1267 break; 1268 default: 1269 TRESPASS(); 1270 } 1271 1272 if (track->mSource == NULL) { 1273 return; 1274 } 1275 1276 if (actualTimeUs) { 1277 *actualTimeUs = seekTimeUs; 1278 } 1279 1280 MediaSource::ReadOptions options; 1281 1282 bool seeking = false; 1283 1284 if (seekTimeUs >= 0) { 1285 options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC); 1286 seeking = true; 1287 } 1288 1289 if (mIsWidevine && trackType != MEDIA_TRACK_TYPE_AUDIO) { 1290 options.setNonBlocking(); 1291 } 1292 1293 for (size_t numBuffers = 0; numBuffers < maxBuffers; ) { 1294 MediaBuffer *mbuf; 1295 status_t err = track->mSource->read(&mbuf, &options); 1296 1297 options.clearSeekTo(); 1298 1299 if (err == OK) { 1300 int64_t timeUs; 1301 CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs)); 1302 if (trackType == MEDIA_TRACK_TYPE_AUDIO) { 1303 mAudioTimeUs = timeUs; 1304 } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) { 1305 mVideoTimeUs = timeUs; 1306 } 1307 1308 // formatChange && seeking: track whose source is changed during selection 1309 // formatChange && !seeking: track whose source is not changed during selection 1310 // !formatChange: normal seek 1311 if ((seeking || formatChange) 1312 && (trackType == MEDIA_TRACK_TYPE_AUDIO 1313 || trackType == MEDIA_TRACK_TYPE_VIDEO)) { 1314 ATSParser::DiscontinuityType type = (formatChange && seeking) 1315 ? ATSParser::DISCONTINUITY_FORMATCHANGE 1316 : ATSParser::DISCONTINUITY_NONE; 1317 track->mPackets->queueDiscontinuity( type, NULL, true /* discard */); 1318 } 1319 1320 sp<ABuffer> buffer = mediaBufferToABuffer(mbuf, trackType, actualTimeUs); 1321 track->mPackets->queueAccessUnit(buffer); 1322 formatChange = false; 1323 seeking = false; 1324 ++numBuffers; 1325 } else if (err == WOULD_BLOCK) { 1326 break; 1327 } else if (err == INFO_FORMAT_CHANGED) { 1328#if 0 1329 track->mPackets->queueDiscontinuity( 1330 ATSParser::DISCONTINUITY_FORMATCHANGE, 1331 NULL, 1332 false /* discard */); 1333#endif 1334 } else { 1335 track->mPackets->signalEOS(err); 1336 break; 1337 } 1338 } 1339} 1340 1341} // namespace android 1342