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