NuMediaExtractor.cpp revision 1608735ef488ecd8c3c012a3b0d4b1d4ef3d93c7
1/* 2 * Copyright 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//#define LOG_NDEBUG 0 18#define LOG_TAG "NuMediaExtractor" 19#include <utils/Log.h> 20 21#include <media/stagefright/NuMediaExtractor.h> 22 23#include "include/ESDS.h" 24#include "include/WVMExtractor.h" 25 26#include <media/stagefright/foundation/ABuffer.h> 27#include <media/stagefright/foundation/ADebug.h> 28#include <media/stagefright/foundation/AMessage.h> 29#include <media/stagefright/DataSource.h> 30#include <media/stagefright/FileSource.h> 31#include <media/stagefright/MediaBuffer.h> 32#include <media/stagefright/MediaDefs.h> 33#include <media/stagefright/MediaErrors.h> 34#include <media/stagefright/MediaExtractor.h> 35#include <media/stagefright/MediaSource.h> 36#include <media/stagefright/MetaData.h> 37#include <media/stagefright/Utils.h> 38 39namespace android { 40 41NuMediaExtractor::NuMediaExtractor() { 42} 43 44NuMediaExtractor::~NuMediaExtractor() { 45 releaseTrackSamples(); 46 47 for (size_t i = 0; i < mSelectedTracks.size(); ++i) { 48 TrackInfo *info = &mSelectedTracks.editItemAt(i); 49 50 CHECK_EQ((status_t)OK, info->mSource->stop()); 51 } 52 53 mSelectedTracks.clear(); 54} 55 56status_t NuMediaExtractor::setDataSource( 57 const char *path, const KeyedVector<String8, String8> *headers) { 58 if (mImpl != NULL) { 59 return -EINVAL; 60 } 61 62 sp<DataSource> dataSource = 63 DataSource::CreateFromURI(path, headers); 64 65 if (dataSource == NULL) { 66 return -ENOENT; 67 } 68 69 if (!strncasecmp("widevine://", path, 11)) { 70 String8 mimeType; 71 float confidence; 72 sp<AMessage> dummy; 73 bool success = SniffWVM(dataSource, &mimeType, &confidence, &dummy); 74 75 if (!success 76 || strcasecmp( 77 mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) { 78 return ERROR_UNSUPPORTED; 79 } 80 81 sp<WVMExtractor> extractor = new WVMExtractor(dataSource); 82 extractor->setAdaptiveStreamingMode(true); 83 84 mImpl = extractor; 85 } else { 86 mImpl = MediaExtractor::Create(dataSource); 87 } 88 89 if (mImpl == NULL) { 90 return ERROR_UNSUPPORTED; 91 } 92 93 return OK; 94} 95 96status_t NuMediaExtractor::setDataSource(int fd, off64_t offset, off64_t size) { 97 if (mImpl != NULL) { 98 return -EINVAL; 99 } 100 101 sp<FileSource> fileSource = new FileSource(dup(fd), offset, size); 102 103 status_t err = fileSource->initCheck(); 104 if (err != OK) { 105 return err; 106 } 107 108 mImpl = MediaExtractor::Create(fileSource); 109 110 if (mImpl == NULL) { 111 return ERROR_UNSUPPORTED; 112 } 113 114 return OK; 115} 116 117size_t NuMediaExtractor::countTracks() const { 118 return mImpl == NULL ? 0 : mImpl->countTracks(); 119} 120 121status_t NuMediaExtractor::getTrackFormat( 122 size_t index, sp<AMessage> *format) const { 123 *format = NULL; 124 125 if (mImpl == NULL) { 126 return -EINVAL; 127 } 128 129 if (index >= mImpl->countTracks()) { 130 return -ERANGE; 131 } 132 133 sp<MetaData> meta = mImpl->getTrackMetaData(index); 134 135 const char *mime; 136 CHECK(meta->findCString(kKeyMIMEType, &mime)); 137 138 sp<AMessage> msg = new AMessage; 139 msg->setString("mime", mime); 140 141 int64_t durationUs; 142 if (meta->findInt64(kKeyDuration, &durationUs)) { 143 msg->setInt64("durationUs", durationUs); 144 } 145 146 if (!strncasecmp("video/", mime, 6)) { 147 int32_t width, height; 148 CHECK(meta->findInt32(kKeyWidth, &width)); 149 CHECK(meta->findInt32(kKeyHeight, &height)); 150 151 msg->setInt32("width", width); 152 msg->setInt32("height", height); 153 } else { 154 CHECK(!strncasecmp("audio/", mime, 6)); 155 156 int32_t numChannels, sampleRate; 157 CHECK(meta->findInt32(kKeyChannelCount, &numChannels)); 158 CHECK(meta->findInt32(kKeySampleRate, &sampleRate)); 159 160 msg->setInt32("channel-count", numChannels); 161 msg->setInt32("sample-rate", sampleRate); 162 163 int32_t isADTS; 164 if (meta->findInt32(kKeyIsADTS, &isADTS)) { 165 msg->setInt32("is-adts", true); 166 } 167 } 168 169 int32_t maxInputSize; 170 if (meta->findInt32(kKeyMaxInputSize, &maxInputSize)) { 171 msg->setInt32("max-input-size", maxInputSize); 172 } 173 174 uint32_t type; 175 const void *data; 176 size_t size; 177 if (meta->findData(kKeyAVCC, &type, &data, &size)) { 178 // Parse the AVCDecoderConfigurationRecord 179 180 const uint8_t *ptr = (const uint8_t *)data; 181 182 CHECK(size >= 7); 183 CHECK_EQ((unsigned)ptr[0], 1u); // configurationVersion == 1 184 uint8_t profile = ptr[1]; 185 uint8_t level = ptr[3]; 186 187 // There is decodable content out there that fails the following 188 // assertion, let's be lenient for now... 189 // CHECK((ptr[4] >> 2) == 0x3f); // reserved 190 191 size_t lengthSize = 1 + (ptr[4] & 3); 192 193 // commented out check below as H264_QVGA_500_NO_AUDIO.3gp 194 // violates it... 195 // CHECK((ptr[5] >> 5) == 7); // reserved 196 197 size_t numSeqParameterSets = ptr[5] & 31; 198 199 ptr += 6; 200 size -= 6; 201 202 sp<ABuffer> buffer = new ABuffer(1024); 203 buffer->setRange(0, 0); 204 205 for (size_t i = 0; i < numSeqParameterSets; ++i) { 206 CHECK(size >= 2); 207 size_t length = U16_AT(ptr); 208 209 ptr += 2; 210 size -= 2; 211 212 CHECK(size >= length); 213 214 memcpy(buffer->data() + buffer->size(), "\x00\x00\x00\x01", 4); 215 memcpy(buffer->data() + buffer->size() + 4, ptr, length); 216 buffer->setRange(0, buffer->size() + 4 + length); 217 218 ptr += length; 219 size -= length; 220 } 221 222 buffer->meta()->setInt32("csd", true); 223 buffer->meta()->setInt64("timeUs", 0); 224 225 msg->setBuffer("csd-0", buffer); 226 227 buffer = new ABuffer(1024); 228 buffer->setRange(0, 0); 229 230 CHECK(size >= 1); 231 size_t numPictureParameterSets = *ptr; 232 ++ptr; 233 --size; 234 235 for (size_t i = 0; i < numPictureParameterSets; ++i) { 236 CHECK(size >= 2); 237 size_t length = U16_AT(ptr); 238 239 ptr += 2; 240 size -= 2; 241 242 CHECK(size >= length); 243 244 memcpy(buffer->data() + buffer->size(), "\x00\x00\x00\x01", 4); 245 memcpy(buffer->data() + buffer->size() + 4, ptr, length); 246 buffer->setRange(0, buffer->size() + 4 + length); 247 248 ptr += length; 249 size -= length; 250 } 251 252 buffer->meta()->setInt32("csd", true); 253 buffer->meta()->setInt64("timeUs", 0); 254 msg->setBuffer("csd-1", buffer); 255 } else if (meta->findData(kKeyESDS, &type, &data, &size)) { 256 ESDS esds((const char *)data, size); 257 CHECK_EQ(esds.InitCheck(), (status_t)OK); 258 259 const void *codec_specific_data; 260 size_t codec_specific_data_size; 261 esds.getCodecSpecificInfo( 262 &codec_specific_data, &codec_specific_data_size); 263 264 sp<ABuffer> buffer = new ABuffer(codec_specific_data_size); 265 266 memcpy(buffer->data(), codec_specific_data, 267 codec_specific_data_size); 268 269 buffer->meta()->setInt32("csd", true); 270 buffer->meta()->setInt64("timeUs", 0); 271 msg->setBuffer("csd-0", buffer); 272 } else if (meta->findData(kKeyVorbisInfo, &type, &data, &size)) { 273 sp<ABuffer> buffer = new ABuffer(size); 274 memcpy(buffer->data(), data, size); 275 276 buffer->meta()->setInt32("csd", true); 277 buffer->meta()->setInt64("timeUs", 0); 278 msg->setBuffer("csd-0", buffer); 279 280 if (!meta->findData(kKeyVorbisBooks, &type, &data, &size)) { 281 return -EINVAL; 282 } 283 284 buffer = new ABuffer(size); 285 memcpy(buffer->data(), data, size); 286 287 buffer->meta()->setInt32("csd", true); 288 buffer->meta()->setInt64("timeUs", 0); 289 msg->setBuffer("csd-1", buffer); 290 } 291 292 if (meta->findData(kKeyEMM, &type, &data, &size)) { 293 sp<ABuffer> emm = new ABuffer(size); 294 memcpy(emm->data(), data, size); 295 296 msg->setBuffer("emm", emm); 297 } 298 299 if (meta->findData(kKeyECM, &type, &data, &size)) { 300 sp<ABuffer> ecm = new ABuffer(size); 301 memcpy(ecm->data(), data, size); 302 303 msg->setBuffer("ecm", ecm); 304 } 305 306 *format = msg; 307 308 return OK; 309} 310 311status_t NuMediaExtractor::selectTrack(size_t index) { 312 if (mImpl == NULL) { 313 return -EINVAL; 314 } 315 316 if (index >= mImpl->countTracks()) { 317 return -ERANGE; 318 } 319 320 for (size_t i = 0; i < mSelectedTracks.size(); ++i) { 321 TrackInfo *info = &mSelectedTracks.editItemAt(i); 322 323 if (info->mTrackIndex == index) { 324 // This track has already been selected. 325 return OK; 326 } 327 } 328 329 sp<MediaSource> source = mImpl->getTrack(index); 330 331 CHECK_EQ((status_t)OK, source->start()); 332 333 mSelectedTracks.push(); 334 TrackInfo *info = &mSelectedTracks.editItemAt(mSelectedTracks.size() - 1); 335 336 info->mSource = source; 337 info->mTrackIndex = index; 338 info->mFinalResult = OK; 339 info->mSample = NULL; 340 info->mSampleTimeUs = -1ll; 341 info->mSampleFlags = 0; 342 info->mTrackFlags = 0; 343 344 const char *mime; 345 CHECK(source->getFormat()->findCString(kKeyMIMEType, &mime)); 346 347 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) { 348 info->mTrackFlags |= kIsVorbis; 349 } 350 351 return OK; 352} 353 354void NuMediaExtractor::releaseTrackSamples() { 355 for (size_t i = 0; i < mSelectedTracks.size(); ++i) { 356 TrackInfo *info = &mSelectedTracks.editItemAt(i); 357 358 if (info->mSample != NULL) { 359 info->mSample->release(); 360 info->mSample = NULL; 361 362 info->mSampleTimeUs = -1ll; 363 info->mSampleFlags = 0; 364 } 365 } 366} 367 368ssize_t NuMediaExtractor::fetchTrackSamples(int64_t seekTimeUs) { 369 TrackInfo *minInfo = NULL; 370 ssize_t minIndex = -1; 371 372 for (size_t i = 0; i < mSelectedTracks.size(); ++i) { 373 TrackInfo *info = &mSelectedTracks.editItemAt(i); 374 375 if (seekTimeUs >= 0ll) { 376 info->mFinalResult = OK; 377 378 if (info->mSample != NULL) { 379 info->mSample->release(); 380 info->mSample = NULL; 381 info->mSampleTimeUs = -1ll; 382 info->mSampleFlags = 0; 383 } 384 } else if (info->mFinalResult != OK) { 385 continue; 386 } 387 388 if (info->mSample == NULL) { 389 MediaSource::ReadOptions options; 390 if (seekTimeUs >= 0ll) { 391 options.setSeekTo(seekTimeUs); 392 } 393 status_t err = info->mSource->read(&info->mSample, &options); 394 395 if (err != OK) { 396 CHECK(info->mSample == NULL); 397 398 info->mFinalResult = err; 399 info->mSampleTimeUs = -1ll; 400 info->mSampleFlags = 0; 401 continue; 402 } else { 403 CHECK(info->mSample != NULL); 404 CHECK(info->mSample->meta_data()->findInt64( 405 kKeyTime, &info->mSampleTimeUs)); 406 407 info->mSampleFlags = 0; 408 409 int32_t val; 410 if (info->mSample->meta_data()->findInt32( 411 kKeyIsSyncFrame, &val) && val != 0) { 412 info->mSampleFlags |= SAMPLE_FLAG_SYNC; 413 } 414 415 if (info->mSample->meta_data()->findInt32( 416 kKeyScrambling, &val) && val != 0) { 417 info->mSampleFlags |= SAMPLE_FLAG_ENCRYPTED; 418 } 419 } 420 } 421 422 if (minInfo == NULL || info->mSampleTimeUs < minInfo->mSampleTimeUs) { 423 minInfo = info; 424 minIndex = i; 425 } 426 } 427 428 return minIndex; 429} 430 431status_t NuMediaExtractor::seekTo(int64_t timeUs) { 432 return fetchTrackSamples(timeUs); 433} 434 435status_t NuMediaExtractor::advance() { 436 ssize_t minIndex = fetchTrackSamples(); 437 438 if (minIndex < 0) { 439 return ERROR_END_OF_STREAM; 440 } 441 442 TrackInfo *info = &mSelectedTracks.editItemAt(minIndex); 443 444 info->mSample->release(); 445 info->mSample = NULL; 446 info->mSampleTimeUs = -1ll; 447 448 return OK; 449} 450 451status_t NuMediaExtractor::readSampleData(const sp<ABuffer> &buffer) { 452 ssize_t minIndex = fetchTrackSamples(); 453 454 if (minIndex < 0) { 455 return ERROR_END_OF_STREAM; 456 } 457 458 TrackInfo *info = &mSelectedTracks.editItemAt(minIndex); 459 460 size_t sampleSize = info->mSample->range_length(); 461 462 if (info->mTrackFlags & kIsVorbis) { 463 // Each sample's data is suffixed by the number of page samples 464 // or -1 if not available. 465 sampleSize += sizeof(int32_t); 466 } 467 468 if (buffer->capacity() < sampleSize) { 469 return -ENOMEM; 470 } 471 472 const uint8_t *src = 473 (const uint8_t *)info->mSample->data() 474 + info->mSample->range_offset(); 475 476 memcpy((uint8_t *)buffer->data(), src, info->mSample->range_length()); 477 478 if (info->mTrackFlags & kIsVorbis) { 479 int32_t numPageSamples; 480 if (!info->mSample->meta_data()->findInt32( 481 kKeyValidSamples, &numPageSamples)) { 482 numPageSamples = -1; 483 } 484 485 memcpy((uint8_t *)buffer->data() + info->mSample->range_length(), 486 &numPageSamples, 487 sizeof(numPageSamples)); 488 } 489 490 buffer->setRange(0, sampleSize); 491 492 return OK; 493} 494 495status_t NuMediaExtractor::getSampleTrackIndex(size_t *trackIndex) { 496 ssize_t minIndex = fetchTrackSamples(); 497 498 if (minIndex < 0) { 499 return ERROR_END_OF_STREAM; 500 } 501 502 TrackInfo *info = &mSelectedTracks.editItemAt(minIndex); 503 *trackIndex = info->mTrackIndex; 504 505 return OK; 506} 507 508status_t NuMediaExtractor::getSampleTime(int64_t *sampleTimeUs) { 509 ssize_t minIndex = fetchTrackSamples(); 510 511 if (minIndex < 0) { 512 return ERROR_END_OF_STREAM; 513 } 514 515 TrackInfo *info = &mSelectedTracks.editItemAt(minIndex); 516 *sampleTimeUs = info->mSampleTimeUs; 517 518 return OK; 519} 520 521status_t NuMediaExtractor::getSampleFlags(uint32_t *sampleFlags) { 522 ssize_t minIndex = fetchTrackSamples(); 523 524 if (minIndex < 0) { 525 return ERROR_END_OF_STREAM; 526 } 527 528 TrackInfo *info = &mSelectedTracks.editItemAt(minIndex); 529 *sampleFlags = info->mSampleFlags; 530 531 return OK; 532} 533 534} // namespace android 535