GenericSource.cpp revision cb48eacb6f8857c7857bb28d6a13d4a0d417f2bd
1/* 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 17#include "GenericSource.h" 18 19#include "AnotherPacketSource.h" 20 21#include <media/stagefright/foundation/ABuffer.h> 22#include <media/stagefright/foundation/ADebug.h> 23#include <media/stagefright/foundation/AMessage.h> 24#include <media/stagefright/DataSource.h> 25#include <media/stagefright/FileSource.h> 26#include <media/stagefright/MediaBuffer.h> 27#include <media/stagefright/MediaDefs.h> 28#include <media/stagefright/MediaExtractor.h> 29#include <media/stagefright/MediaSource.h> 30#include <media/stagefright/MetaData.h> 31#include "../../libstagefright/include/WVMExtractor.h" 32 33namespace android { 34 35NuPlayer::GenericSource::GenericSource( 36 const sp<AMessage> ¬ify, 37 const sp<IMediaHTTPService> &httpService, 38 const char *url, 39 const KeyedVector<String8, String8> *headers, 40 bool isWidevine, 41 bool uidValid, 42 uid_t uid) 43 : Source(notify), 44 mDurationUs(0ll), 45 mAudioIsVorbis(false), 46 mIsWidevine(isWidevine), 47 mUIDValid(uidValid), 48 mUID(uid) { 49 DataSource::RegisterDefaultSniffers(); 50 51 sp<DataSource> dataSource = 52 DataSource::CreateFromURI(httpService, url, headers); 53 CHECK(dataSource != NULL); 54 55 initFromDataSource(dataSource); 56} 57 58NuPlayer::GenericSource::GenericSource( 59 const sp<AMessage> ¬ify, 60 int fd, int64_t offset, int64_t length) 61 : Source(notify), 62 mDurationUs(0ll), 63 mAudioIsVorbis(false) { 64 DataSource::RegisterDefaultSniffers(); 65 66 sp<DataSource> dataSource = new FileSource(dup(fd), offset, length); 67 68 initFromDataSource(dataSource); 69} 70 71void NuPlayer::GenericSource::initFromDataSource( 72 const sp<DataSource> &dataSource) { 73 sp<MediaExtractor> extractor; 74 75 if (mIsWidevine) { 76 String8 mimeType; 77 float confidence; 78 sp<AMessage> dummy; 79 bool success; 80 81 success = SniffWVM(dataSource, &mimeType, &confidence, &dummy); 82 if (!success 83 || strcasecmp( 84 mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) { 85 ALOGE("unsupported widevine mime: %s", mimeType.string()); 86 return; 87 } 88 89 sp<WVMExtractor> wvmExtractor = new WVMExtractor(dataSource); 90 wvmExtractor->setAdaptiveStreamingMode(true); 91 if (mUIDValid) { 92 wvmExtractor->setUID(mUID); 93 } 94 extractor = wvmExtractor; 95 } else { 96 extractor = MediaExtractor::Create(dataSource); 97 } 98 99 CHECK(extractor != NULL); 100 101 sp<MetaData> fileMeta = extractor->getMetaData(); 102 if (fileMeta != NULL) { 103 int64_t duration; 104 if (fileMeta->findInt64(kKeyDuration, &duration)) { 105 mDurationUs = duration; 106 } 107 } 108 109 for (size_t i = 0; i < extractor->countTracks(); ++i) { 110 sp<MetaData> meta = extractor->getTrackMetaData(i); 111 112 const char *mime; 113 CHECK(meta->findCString(kKeyMIMEType, &mime)); 114 115 sp<MediaSource> track = extractor->getTrack(i); 116 117 if (!strncasecmp(mime, "audio/", 6)) { 118 if (mAudioTrack.mSource == NULL) { 119 mAudioTrack.mIndex = i; 120 mAudioTrack.mSource = track; 121 122 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) { 123 mAudioIsVorbis = true; 124 } else { 125 mAudioIsVorbis = false; 126 } 127 } 128 } else if (!strncasecmp(mime, "video/", 6)) { 129 if (mVideoTrack.mSource == NULL) { 130 mVideoTrack.mIndex = i; 131 mVideoTrack.mSource = track; 132 } 133 } 134 135 if (track != NULL) { 136 mSources.push(track); 137 int64_t durationUs; 138 if (meta->findInt64(kKeyDuration, &durationUs)) { 139 if (durationUs > mDurationUs) { 140 mDurationUs = durationUs; 141 } 142 } 143 } 144 } 145} 146 147status_t NuPlayer::GenericSource::setBuffers(bool audio, Vector<MediaBuffer *> &buffers) { 148 if (mIsWidevine && !audio) { 149 return mVideoTrack.mSource->setBuffers(buffers); 150 } 151 return INVALID_OPERATION; 152} 153 154NuPlayer::GenericSource::~GenericSource() { 155} 156 157void NuPlayer::GenericSource::prepareAsync() { 158 if (mVideoTrack.mSource != NULL) { 159 sp<MetaData> meta = mVideoTrack.mSource->getFormat(); 160 161 int32_t width, height; 162 CHECK(meta->findInt32(kKeyWidth, &width)); 163 CHECK(meta->findInt32(kKeyHeight, &height)); 164 165 notifyVideoSizeChanged(width, height); 166 } 167 168 notifyFlagsChanged( 169 (mIsWidevine ? FLAG_SECURE : 0) 170 | FLAG_CAN_PAUSE 171 | FLAG_CAN_SEEK_BACKWARD 172 | FLAG_CAN_SEEK_FORWARD 173 | FLAG_CAN_SEEK); 174 175 notifyPrepared(); 176} 177 178void NuPlayer::GenericSource::start() { 179 ALOGI("start"); 180 181 if (mAudioTrack.mSource != NULL) { 182 CHECK_EQ(mAudioTrack.mSource->start(), (status_t)OK); 183 184 mAudioTrack.mPackets = 185 new AnotherPacketSource(mAudioTrack.mSource->getFormat()); 186 187 readBuffer(true /* audio */); 188 } 189 190 if (mVideoTrack.mSource != NULL) { 191 CHECK_EQ(mVideoTrack.mSource->start(), (status_t)OK); 192 193 mVideoTrack.mPackets = 194 new AnotherPacketSource(mVideoTrack.mSource->getFormat()); 195 196 readBuffer(false /* audio */); 197 } 198} 199 200status_t NuPlayer::GenericSource::feedMoreTSData() { 201 return OK; 202} 203 204sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) { 205 sp<MediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource; 206 207 if (source == NULL) { 208 return NULL; 209 } 210 211 return source->getFormat(); 212} 213 214status_t NuPlayer::GenericSource::dequeueAccessUnit( 215 bool audio, sp<ABuffer> *accessUnit) { 216 Track *track = audio ? &mAudioTrack : &mVideoTrack; 217 218 if (track->mSource == NULL) { 219 return -EWOULDBLOCK; 220 } 221 222 if (mIsWidevine && !audio) { 223 // try to read a buffer as we may not have been able to the last time 224 readBuffer(audio, -1ll); 225 } 226 227 status_t finalResult; 228 if (!track->mPackets->hasBufferAvailable(&finalResult)) { 229 return (finalResult == OK ? -EWOULDBLOCK : finalResult); 230 } 231 232 status_t result = track->mPackets->dequeueAccessUnit(accessUnit); 233 234 readBuffer(audio, -1ll); 235 236 return result; 237} 238 239status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) { 240 *durationUs = mDurationUs; 241 return OK; 242} 243 244size_t NuPlayer::GenericSource::getTrackCount() const { 245 return mSources.size(); 246} 247 248sp<AMessage> NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const { 249 size_t trackCount = mSources.size(); 250 if (trackIndex >= trackCount) { 251 return NULL; 252 } 253 254 sp<AMessage> format = new AMessage(); 255 sp<MetaData> meta = mSources.itemAt(trackIndex)->getFormat(); 256 257 const char *mime; 258 CHECK(meta->findCString(kKeyMIMEType, &mime)); 259 260 int32_t trackType; 261 if (!strncasecmp(mime, "video/", 6)) { 262 trackType = MEDIA_TRACK_TYPE_VIDEO; 263 } else if (!strncasecmp(mime, "audio/", 6)) { 264 trackType = MEDIA_TRACK_TYPE_AUDIO; 265 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) { 266 trackType = MEDIA_TRACK_TYPE_TIMEDTEXT; 267 } else { 268 trackType = MEDIA_TRACK_TYPE_UNKNOWN; 269 } 270 format->setInt32("type", trackType); 271 272 const char *lang; 273 if (!meta->findCString(kKeyMediaLanguage, &lang)) { 274 lang = "und"; 275 } 276 format->setString("language", lang); 277 278 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) { 279 format->setString("mime", mime); 280 281 int32_t isAutoselect = 1, isDefault = 0, isForced = 0; 282 meta->findInt32(kKeyTrackIsAutoselect, &isAutoselect); 283 meta->findInt32(kKeyTrackIsDefault, &isDefault); 284 meta->findInt32(kKeyTrackIsForced, &isForced); 285 286 format->setInt32("auto", !!isAutoselect); 287 format->setInt32("default", !!isDefault); 288 format->setInt32("forced", !!isForced); 289 } 290 291 return format; 292} 293 294status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) { 295 if (mVideoTrack.mSource != NULL) { 296 int64_t actualTimeUs; 297 readBuffer(false /* audio */, seekTimeUs, &actualTimeUs); 298 299 seekTimeUs = actualTimeUs; 300 } 301 302 if (mAudioTrack.mSource != NULL) { 303 readBuffer(true /* audio */, seekTimeUs); 304 } 305 306 return OK; 307} 308 309void NuPlayer::GenericSource::readBuffer( 310 bool audio, int64_t seekTimeUs, int64_t *actualTimeUs) { 311 Track *track = audio ? &mAudioTrack : &mVideoTrack; 312 CHECK(track->mSource != NULL); 313 314 if (actualTimeUs) { 315 *actualTimeUs = seekTimeUs; 316 } 317 318 MediaSource::ReadOptions options; 319 320 bool seeking = false; 321 322 if (seekTimeUs >= 0) { 323 options.setSeekTo(seekTimeUs); 324 seeking = true; 325 } 326 327 if (mIsWidevine && !audio) { 328 options.setNonBlocking(); 329 } 330 331 for (;;) { 332 MediaBuffer *mbuf; 333 status_t err = track->mSource->read(&mbuf, &options); 334 335 options.clearSeekTo(); 336 337 if (err == OK) { 338 size_t outLength = mbuf->range_length(); 339 340 if (audio && mAudioIsVorbis) { 341 outLength += sizeof(int32_t); 342 } 343 344 sp<ABuffer> buffer; 345 if (mIsWidevine && !audio) { 346 // data is already provided in the buffer 347 buffer = new ABuffer(NULL, mbuf->range_length()); 348 buffer->meta()->setPointer("mediaBuffer", mbuf); 349 mbuf->add_ref(); 350 } else { 351 buffer = new ABuffer(outLength); 352 memcpy(buffer->data(), 353 (const uint8_t *)mbuf->data() + mbuf->range_offset(), 354 mbuf->range_length()); 355 } 356 357 if (audio && mAudioIsVorbis) { 358 int32_t numPageSamples; 359 if (!mbuf->meta_data()->findInt32( 360 kKeyValidSamples, &numPageSamples)) { 361 numPageSamples = -1; 362 } 363 364 memcpy(buffer->data() + mbuf->range_length(), 365 &numPageSamples, 366 sizeof(numPageSamples)); 367 } 368 369 int64_t timeUs; 370 CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs)); 371 372 buffer->meta()->setInt64("timeUs", timeUs); 373 374 if (actualTimeUs) { 375 *actualTimeUs = timeUs; 376 } 377 378 mbuf->release(); 379 mbuf = NULL; 380 381 if (seeking) { 382 track->mPackets->queueDiscontinuity( 383 ATSParser::DISCONTINUITY_SEEK, 384 NULL, 385 true /* discard */); 386 } 387 388 track->mPackets->queueAccessUnit(buffer); 389 break; 390 } else if (err == WOULD_BLOCK) { 391 break; 392 } else if (err == INFO_FORMAT_CHANGED) { 393#if 0 394 track->mPackets->queueDiscontinuity( 395 ATSParser::DISCONTINUITY_FORMATCHANGE, 396 NULL, 397 false /* discard */); 398#endif 399 } else { 400 track->mPackets->signalEOS(err); 401 break; 402 } 403 } 404} 405 406} // namespace android 407