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