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