1 /* 2 * Copyright (C) 2014 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 "NdkMediaExtractor" 19 20 21 #include <media/NdkMediaError.h> 22 #include <media/NdkMediaExtractor.h> 23 #include "NdkMediaDataSourcePriv.h" 24 #include "NdkMediaFormatPriv.h" 25 26 27 #include <inttypes.h> 28 #include <utils/Log.h> 29 #include <utils/StrongPointer.h> 30 #include <media/hardware/CryptoAPI.h> 31 #include <media/stagefright/foundation/ABuffer.h> 32 #include <media/stagefright/foundation/AMessage.h> 33 #include <media/stagefright/MetaData.h> 34 #include <media/stagefright/NuMediaExtractor.h> 35 #include <media/IMediaHTTPService.h> 36 #include <android_runtime/AndroidRuntime.h> 37 #include <android_util_Binder.h> 38 39 #include <jni.h> 40 41 using namespace android; 42 43 static media_status_t translate_error(status_t err) { 44 if (err == OK) { 45 return AMEDIA_OK; 46 } else if (err == ERROR_END_OF_STREAM) { 47 return AMEDIA_ERROR_END_OF_STREAM; 48 } else if (err == ERROR_IO) { 49 return AMEDIA_ERROR_IO; 50 } 51 52 ALOGE("sf error code: %d", err); 53 return AMEDIA_ERROR_UNKNOWN; 54 } 55 56 struct AMediaExtractor { 57 sp<NuMediaExtractor> mImpl; 58 sp<ABuffer> mPsshBuf; 59 }; 60 61 extern "C" { 62 63 EXPORT 64 AMediaExtractor* AMediaExtractor_new() { 65 ALOGV("ctor"); 66 AMediaExtractor *mData = new AMediaExtractor(); 67 mData->mImpl = new NuMediaExtractor(); 68 return mData; 69 } 70 71 EXPORT 72 media_status_t AMediaExtractor_delete(AMediaExtractor *mData) { 73 ALOGV("dtor"); 74 delete mData; 75 return AMEDIA_OK; 76 } 77 78 EXPORT 79 media_status_t AMediaExtractor_setDataSourceFd(AMediaExtractor *mData, int fd, off64_t offset, 80 off64_t length) { 81 ALOGV("setDataSource(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length); 82 return translate_error(mData->mImpl->setDataSource(fd, offset, length)); 83 } 84 85 EXPORT 86 media_status_t AMediaExtractor_setDataSource(AMediaExtractor *mData, const char *location) { 87 ALOGV("setDataSource(%s)", location); 88 // TODO: add header support 89 90 JNIEnv *env = AndroidRuntime::getJNIEnv(); 91 jobject service = NULL; 92 if (env == NULL) { 93 ALOGE("setDataSource(path) must be called from Java thread"); 94 return AMEDIA_ERROR_UNSUPPORTED; 95 } 96 97 jclass mediahttpclass = env->FindClass("android/media/MediaHTTPService"); 98 if (mediahttpclass == NULL) { 99 ALOGE("can't find MediaHttpService"); 100 env->ExceptionClear(); 101 return AMEDIA_ERROR_UNSUPPORTED; 102 } 103 104 jmethodID mediaHttpCreateMethod = env->GetStaticMethodID(mediahttpclass, 105 "createHttpServiceBinderIfNecessary", "(Ljava/lang/String;)Landroid/os/IBinder;"); 106 if (mediaHttpCreateMethod == NULL) { 107 ALOGE("can't find method"); 108 env->ExceptionClear(); 109 return AMEDIA_ERROR_UNSUPPORTED; 110 } 111 112 jstring jloc = env->NewStringUTF(location); 113 114 service = env->CallStaticObjectMethod(mediahttpclass, mediaHttpCreateMethod, jloc); 115 env->DeleteLocalRef(jloc); 116 117 sp<IMediaHTTPService> httpService; 118 if (service != NULL) { 119 sp<IBinder> binder = ibinderForJavaObject(env, service); 120 httpService = interface_cast<IMediaHTTPService>(binder); 121 } 122 123 status_t err = mData->mImpl->setDataSource(httpService, location, NULL); 124 env->ExceptionClear(); 125 return translate_error(err); 126 } 127 128 EXPORT 129 media_status_t AMediaExtractor_setDataSourceCustom(AMediaExtractor* mData, AMediaDataSource *src) { 130 return translate_error(mData->mImpl->setDataSource(new NdkDataSource(src))); 131 } 132 133 EXPORT 134 AMediaFormat* AMediaExtractor_getFileFormat(AMediaExtractor *mData) { 135 sp<AMessage> format; 136 mData->mImpl->getFileFormat(&format); 137 return AMediaFormat_fromMsg(&format); 138 } 139 140 EXPORT 141 size_t AMediaExtractor_getTrackCount(AMediaExtractor *mData) { 142 return mData->mImpl->countTracks(); 143 } 144 145 EXPORT 146 AMediaFormat* AMediaExtractor_getTrackFormat(AMediaExtractor *mData, size_t idx) { 147 sp<AMessage> format; 148 mData->mImpl->getTrackFormat(idx, &format); 149 return AMediaFormat_fromMsg(&format); 150 } 151 152 EXPORT 153 media_status_t AMediaExtractor_selectTrack(AMediaExtractor *mData, size_t idx) { 154 ALOGV("selectTrack(%zu)", idx); 155 return translate_error(mData->mImpl->selectTrack(idx)); 156 } 157 158 EXPORT 159 media_status_t AMediaExtractor_unselectTrack(AMediaExtractor *mData, size_t idx) { 160 ALOGV("unselectTrack(%zu)", idx); 161 return translate_error(mData->mImpl->unselectTrack(idx)); 162 } 163 164 EXPORT 165 bool AMediaExtractor_advance(AMediaExtractor *mData) { 166 //ALOGV("advance"); 167 status_t err = mData->mImpl->advance(); 168 if (err == ERROR_END_OF_STREAM) { 169 return false; 170 } else if (err != OK) { 171 ALOGE("sf error code: %d", err); 172 return false; 173 } 174 return true; 175 } 176 177 EXPORT 178 media_status_t AMediaExtractor_seekTo(AMediaExtractor *ex, int64_t seekPosUs, SeekMode mode) { 179 android::MediaSource::ReadOptions::SeekMode sfmode; 180 if (mode == AMEDIAEXTRACTOR_SEEK_PREVIOUS_SYNC) { 181 sfmode = android::MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC; 182 } else if (mode == AMEDIAEXTRACTOR_SEEK_CLOSEST_SYNC) { 183 sfmode = android::MediaSource::ReadOptions::SEEK_CLOSEST_SYNC; 184 } else { 185 sfmode = android::MediaSource::ReadOptions::SEEK_NEXT_SYNC; 186 } 187 188 return translate_error(ex->mImpl->seekTo(seekPosUs, sfmode)); 189 } 190 191 EXPORT 192 ssize_t AMediaExtractor_readSampleData(AMediaExtractor *mData, uint8_t *buffer, size_t capacity) { 193 //ALOGV("readSampleData"); 194 sp<ABuffer> tmp = new ABuffer(buffer, capacity); 195 if (mData->mImpl->readSampleData(tmp) == OK) { 196 return tmp->size(); 197 } 198 return -1; 199 } 200 201 EXPORT 202 ssize_t AMediaExtractor_getSampleSize(AMediaExtractor *mData) { 203 size_t sampleSize; 204 status_t err = mData->mImpl->getSampleSize(&sampleSize); 205 if (err != OK) { 206 return -1; 207 } 208 return sampleSize; 209 } 210 211 EXPORT 212 uint32_t AMediaExtractor_getSampleFlags(AMediaExtractor *mData) { 213 int sampleFlags = 0; 214 sp<MetaData> meta; 215 status_t err = mData->mImpl->getSampleMeta(&meta); 216 if (err != OK) { 217 return -1; 218 } 219 int32_t val; 220 if (meta->findInt32(kKeyIsSyncFrame, &val) && val != 0) { 221 sampleFlags |= AMEDIAEXTRACTOR_SAMPLE_FLAG_SYNC; 222 } 223 224 uint32_t type; 225 const void *data; 226 size_t size; 227 if (meta->findData(kKeyEncryptedSizes, &type, &data, &size)) { 228 sampleFlags |= AMEDIAEXTRACTOR_SAMPLE_FLAG_ENCRYPTED; 229 } 230 return sampleFlags; 231 } 232 233 EXPORT 234 int AMediaExtractor_getSampleTrackIndex(AMediaExtractor *mData) { 235 size_t idx; 236 if (mData->mImpl->getSampleTrackIndex(&idx) != OK) { 237 return -1; 238 } 239 return idx; 240 } 241 242 EXPORT 243 int64_t AMediaExtractor_getSampleTime(AMediaExtractor *mData) { 244 int64_t time; 245 if (mData->mImpl->getSampleTime(&time) != OK) { 246 return -1; 247 } 248 return time; 249 } 250 251 EXPORT 252 PsshInfo* AMediaExtractor_getPsshInfo(AMediaExtractor *ex) { 253 254 if (ex->mPsshBuf != NULL) { 255 return (PsshInfo*) ex->mPsshBuf->data(); 256 } 257 258 sp<AMessage> format; 259 ex->mImpl->getFileFormat(&format); 260 sp<ABuffer> buffer; 261 if(!format->findBuffer("pssh", &buffer)) { 262 return NULL; 263 } 264 265 // the format of the buffer is 1 or more of: 266 // { 267 // 16 byte uuid 268 // 4 byte data length N 269 // N bytes of data 270 // } 271 272 // Determine the number of entries in the source data. 273 // Since we got the data from stagefright, we trust it is valid and properly formatted. 274 const uint8_t* data = buffer->data(); 275 size_t len = buffer->size(); 276 size_t numentries = 0; 277 while (len > 0) { 278 numentries++; 279 280 if (len < 16) { 281 ALOGE("invalid PSSH data"); 282 return NULL; 283 } 284 // skip uuid 285 data += 16; 286 len -= 16; 287 288 // get data length 289 if (len < 4) { 290 ALOGE("invalid PSSH data"); 291 return NULL; 292 } 293 uint32_t datalen = *((uint32_t*)data); 294 data += 4; 295 len -= 4; 296 297 if (len < datalen) { 298 ALOGE("invalid PSSH data"); 299 return NULL; 300 } 301 // skip the data 302 data += datalen; 303 len -= datalen; 304 } 305 306 // there are <numentries> in the source buffer, we need 307 // (source buffer size) - (sizeof(uint32_t) * numentries) + sizeof(size_t) 308 // + ((sizeof(void*) + sizeof(size_t)) * numentries) bytes for the PsshInfo structure 309 // Or in other words, the data lengths in the source structure are replaced by size_t 310 // (which may be the same size or larger, for 64 bit), and in addition there is an 311 // extra pointer for each entry, and an extra size_t for the entire PsshInfo. 312 size_t newsize = buffer->size() - (sizeof(uint32_t) * numentries) + sizeof(size_t) 313 + ((sizeof(void*) + sizeof(size_t)) * numentries); 314 if (newsize <= buffer->size()) { 315 ALOGE("invalid PSSH data"); 316 return NULL; 317 } 318 ex->mPsshBuf = new ABuffer(newsize); 319 ex->mPsshBuf->setRange(0, newsize); 320 321 // copy data 322 const uint8_t* src = buffer->data(); 323 uint8_t* dst = ex->mPsshBuf->data(); 324 uint8_t* dstdata = dst + sizeof(size_t) + numentries * sizeof(PsshEntry); 325 *((size_t*)dst) = numentries; 326 dst += sizeof(size_t); 327 for (size_t i = 0; i < numentries; i++) { 328 // copy uuid 329 memcpy(dst, src, 16); 330 src += 16; 331 dst += 16; 332 333 // get/copy data length 334 uint32_t datalen = *((uint32_t*)src); 335 *((size_t*)dst) = datalen; 336 src += sizeof(uint32_t); 337 dst += sizeof(size_t); 338 339 // the next entry in the destination is a pointer to the actual data, which we store 340 // after the array of PsshEntry 341 *((void**)dst) = dstdata; 342 dst += sizeof(void*); 343 344 // copy the actual data 345 memcpy(dstdata, src, datalen); 346 dstdata += datalen; 347 src += datalen; 348 } 349 350 return (PsshInfo*) ex->mPsshBuf->data(); 351 } 352 353 EXPORT 354 AMediaCodecCryptoInfo *AMediaExtractor_getSampleCryptoInfo(AMediaExtractor *ex) { 355 sp<MetaData> meta; 356 if(ex->mImpl->getSampleMeta(&meta) != 0) { 357 return NULL; 358 } 359 360 uint32_t type; 361 const void *crypteddata; 362 size_t cryptedsize; 363 if (!meta->findData(kKeyEncryptedSizes, &type, &crypteddata, &cryptedsize)) { 364 return NULL; 365 } 366 size_t numSubSamples = cryptedsize / sizeof(size_t); 367 368 const void *cleardata; 369 size_t clearsize; 370 if (meta->findData(kKeyPlainSizes, &type, &cleardata, &clearsize)) { 371 if (clearsize != cryptedsize) { 372 // The two must be of the same length. 373 return NULL; 374 } 375 } 376 377 const void *key; 378 size_t keysize; 379 if (meta->findData(kKeyCryptoKey, &type, &key, &keysize)) { 380 if (keysize != 16) { 381 // Keys must be 16 bytes in length. 382 return NULL; 383 } 384 } 385 386 const void *iv; 387 size_t ivsize; 388 if (meta->findData(kKeyCryptoIV, &type, &iv, &ivsize)) { 389 if (ivsize != 16) { 390 // IVs must be 16 bytes in length. 391 return NULL; 392 } 393 } 394 395 int32_t mode; 396 if (!meta->findInt32(kKeyCryptoMode, &mode)) { 397 mode = CryptoPlugin::kMode_AES_CTR; 398 } 399 400 return AMediaCodecCryptoInfo_new( 401 numSubSamples, 402 (uint8_t*) key, 403 (uint8_t*) iv, 404 (cryptoinfo_mode_t) mode, 405 (size_t*) cleardata, 406 (size_t*) crypteddata); 407 } 408 409 EXPORT 410 int64_t AMediaExtractor_getCachedDuration(AMediaExtractor *ex) { 411 bool eos; 412 int64_t durationUs; 413 if (ex->mImpl->getCachedDuration(&durationUs, &eos)) { 414 return durationUs; 415 } 416 return -1; 417 } 418 419 EXPORT 420 media_status_t AMediaExtractor_getSampleFormat(AMediaExtractor *ex, AMediaFormat *fmt) { 421 if (fmt == NULL) { 422 return AMEDIA_ERROR_INVALID_PARAMETER; 423 } 424 425 sp<MetaData> sampleMeta; 426 status_t err = ex->mImpl->getSampleMeta(&sampleMeta); 427 if (err != OK) { 428 return translate_error(err); 429 } 430 431 sp<AMessage> meta; 432 AMediaFormat_getFormat(fmt, &meta); 433 meta->clear(); 434 435 int32_t layerId; 436 if (sampleMeta->findInt32(kKeyTemporalLayerId, &layerId)) { 437 meta->setInt32(AMEDIAFORMAT_KEY_TEMPORAL_LAYER_ID, layerId); 438 } 439 440 size_t trackIndex; 441 err = ex->mImpl->getSampleTrackIndex(&trackIndex); 442 if (err == OK) { 443 meta->setInt32(AMEDIAFORMAT_KEY_TRACK_INDEX, trackIndex); 444 sp<AMessage> trackFormat; 445 AString mime; 446 err = ex->mImpl->getTrackFormat(trackIndex, &trackFormat); 447 if (err == OK 448 && trackFormat != NULL 449 && trackFormat->findString(AMEDIAFORMAT_KEY_MIME, &mime)) { 450 meta->setString(AMEDIAFORMAT_KEY_MIME, mime); 451 } 452 } 453 454 int64_t durationUs; 455 if (sampleMeta->findInt64(kKeyDuration, &durationUs)) { 456 meta->setInt64(AMEDIAFORMAT_KEY_DURATION, durationUs); 457 } 458 459 uint32_t dataType; // unused 460 const void *seiData; 461 size_t seiLength; 462 if (sampleMeta->findData(kKeySEI, &dataType, &seiData, &seiLength)) { 463 sp<ABuffer> sei = ABuffer::CreateAsCopy(seiData, seiLength);; 464 meta->setBuffer(AMEDIAFORMAT_KEY_SEI, sei); 465 } 466 467 const void *mpegUserDataPointer; 468 size_t mpegUserDataLength; 469 if (sampleMeta->findData( 470 kKeyMpegUserData, &dataType, &mpegUserDataPointer, &mpegUserDataLength)) { 471 sp<ABuffer> mpegUserData = ABuffer::CreateAsCopy(mpegUserDataPointer, mpegUserDataLength); 472 meta->setBuffer(AMEDIAFORMAT_KEY_MPEG_USER_DATA, mpegUserData); 473 } 474 475 return AMEDIA_OK; 476 } 477 478 EXPORT 479 media_status_t AMediaExtractor_disconnect(AMediaExtractor * ex) { 480 ex->mImpl->disconnect(); 481 return AMEDIA_OK; 482 } 483 484 } // extern "C" 485 486