android_media_MediaExtractor.cpp revision 07ea426e3ae8915ca6bf67135f523f42cd920af0
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 "MediaExtractor-JNI" 19#include <utils/Log.h> 20 21#include "android_media_MediaExtractor.h" 22 23#include "android_media_Utils.h" 24#include "android_runtime/AndroidRuntime.h" 25#include "jni.h" 26#include "JNIHelp.h" 27 28#include <media/stagefright/foundation/ABuffer.h> 29#include <media/stagefright/foundation/ADebug.h> 30#include <media/stagefright/foundation/AMessage.h> 31#include <media/stagefright/DataSource.h> 32#include <media/stagefright/MediaErrors.h> 33#include <media/stagefright/NuMediaExtractor.h> 34 35namespace android { 36 37struct fields_t { 38 jfieldID context; 39}; 40 41static fields_t gFields; 42 43//////////////////////////////////////////////////////////////////////////////// 44 45JMediaExtractor::JMediaExtractor(JNIEnv *env, jobject thiz) 46 : mClass(NULL), 47 mObject(NULL) { 48 jclass clazz = env->GetObjectClass(thiz); 49 CHECK(clazz != NULL); 50 51 mClass = (jclass)env->NewGlobalRef(clazz); 52 mObject = env->NewWeakGlobalRef(thiz); 53 54 mImpl = new NuMediaExtractor; 55} 56 57JMediaExtractor::~JMediaExtractor() { 58 JNIEnv *env = AndroidRuntime::getJNIEnv(); 59 60 env->DeleteWeakGlobalRef(mObject); 61 mObject = NULL; 62 env->DeleteGlobalRef(mClass); 63 mClass = NULL; 64} 65 66status_t JMediaExtractor::setDataSource( 67 const char *path, const KeyedVector<String8, String8> *headers) { 68 return mImpl->setDataSource(path, headers); 69} 70 71status_t JMediaExtractor::setDataSource(int fd, off64_t offset, off64_t size) { 72 return mImpl->setDataSource(fd, offset, size); 73} 74 75size_t JMediaExtractor::countTracks() const { 76 return mImpl->countTracks(); 77} 78 79status_t JMediaExtractor::getTrackFormat(size_t index, jobject *format) const { 80 sp<AMessage> msg; 81 status_t err; 82 if ((err = mImpl->getTrackFormat(index, &msg)) != OK) { 83 return err; 84 } 85 86 JNIEnv *env = AndroidRuntime::getJNIEnv(); 87 88 return ConvertMessageToMap(env, msg, format); 89} 90 91status_t JMediaExtractor::selectTrack(size_t index) { 92 return mImpl->selectTrack(index); 93} 94 95status_t JMediaExtractor::seekTo(int64_t timeUs) { 96 return mImpl->seekTo(timeUs); 97} 98 99status_t JMediaExtractor::advance() { 100 return mImpl->advance(); 101} 102 103status_t JMediaExtractor::readSampleData( 104 jobject byteBuf, size_t offset, size_t *sampleSize) { 105 JNIEnv *env = AndroidRuntime::getJNIEnv(); 106 107 void *dst = env->GetDirectBufferAddress(byteBuf); 108 109 jlong dstSize; 110 jbyteArray byteArray = NULL; 111 112 if (dst == NULL) { 113 jclass byteBufClass = env->FindClass("java/nio/ByteBuffer"); 114 CHECK(byteBufClass != NULL); 115 116 jmethodID arrayID = 117 env->GetMethodID(byteBufClass, "array", "()[B"); 118 CHECK(arrayID != NULL); 119 120 byteArray = 121 (jbyteArray)env->CallObjectMethod(byteBuf, arrayID); 122 123 if (byteArray == NULL) { 124 return INVALID_OPERATION; 125 } 126 127 jboolean isCopy; 128 dst = env->GetByteArrayElements(byteArray, &isCopy); 129 130 dstSize = env->GetArrayLength(byteArray); 131 } else { 132 dstSize = env->GetDirectBufferCapacity(byteBuf); 133 } 134 135 if (dstSize < offset) { 136 if (byteArray != NULL) { 137 env->ReleaseByteArrayElements(byteArray, (jbyte *)dst, 0); 138 } 139 140 return -ERANGE; 141 } 142 143 sp<ABuffer> buffer = new ABuffer((char *)dst + offset, dstSize - offset); 144 145 status_t err = mImpl->readSampleData(buffer); 146 147 if (byteArray != NULL) { 148 env->ReleaseByteArrayElements(byteArray, (jbyte *)dst, 0); 149 } 150 151 if (err != OK) { 152 return err; 153 } 154 155 *sampleSize = buffer->size(); 156 157 return OK; 158} 159 160status_t JMediaExtractor::getSampleTrackIndex(size_t *trackIndex) { 161 return mImpl->getSampleTrackIndex(trackIndex); 162} 163 164status_t JMediaExtractor::getSampleTime(int64_t *sampleTimeUs) { 165 return mImpl->getSampleTime(sampleTimeUs); 166} 167 168status_t JMediaExtractor::getSampleFlags(uint32_t *sampleFlags) { 169 return mImpl->getSampleFlags(sampleFlags); 170} 171 172} // namespace android 173 174//////////////////////////////////////////////////////////////////////////////// 175 176using namespace android; 177 178static sp<JMediaExtractor> setMediaExtractor( 179 JNIEnv *env, jobject thiz, const sp<JMediaExtractor> &extractor) { 180 sp<JMediaExtractor> old = 181 (JMediaExtractor *)env->GetIntField(thiz, gFields.context); 182 183 if (extractor != NULL) { 184 extractor->incStrong(thiz); 185 } 186 if (old != NULL) { 187 old->decStrong(thiz); 188 } 189 env->SetIntField(thiz, gFields.context, (int)extractor.get()); 190 191 return old; 192} 193 194static sp<JMediaExtractor> getMediaExtractor(JNIEnv *env, jobject thiz) { 195 return (JMediaExtractor *)env->GetIntField(thiz, gFields.context); 196} 197 198static void android_media_MediaExtractor_release(JNIEnv *env, jobject thiz) { 199 setMediaExtractor(env, thiz, NULL); 200} 201 202static jint android_media_MediaExtractor_countTracks( 203 JNIEnv *env, jobject thiz) { 204 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 205 206 if (extractor == NULL) { 207 jniThrowException(env, "java/lang/IllegalStateException", NULL); 208 return -1; 209 } 210 211 return extractor->countTracks(); 212} 213 214static jobject android_media_MediaExtractor_getTrackFormat( 215 JNIEnv *env, jobject thiz, jint index) { 216 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 217 218 if (extractor == NULL) { 219 jniThrowException(env, "java/lang/IllegalStateException", NULL); 220 return NULL; 221 } 222 223 jobject format; 224 status_t err = extractor->getTrackFormat(index, &format); 225 226 if (err != OK) { 227 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 228 return NULL; 229 } 230 231 return format; 232} 233 234static void android_media_MediaExtractor_selectTrack( 235 JNIEnv *env, jobject thiz, jint index) { 236 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 237 238 if (extractor == NULL) { 239 jniThrowException(env, "java/lang/IllegalStateException", NULL); 240 return; 241 } 242 243 status_t err = extractor->selectTrack(index); 244 245 if (err != OK) { 246 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 247 return; 248 } 249} 250 251static void android_media_MediaExtractor_seekTo( 252 JNIEnv *env, jobject thiz, jlong timeUs) { 253 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 254 255 if (extractor == NULL) { 256 jniThrowException(env, "java/lang/IllegalStateException", NULL); 257 return; 258 } 259 260 status_t err = extractor->seekTo(timeUs); 261 262 if (err != OK) { 263 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 264 return; 265 } 266} 267 268static jboolean android_media_MediaExtractor_advance( 269 JNIEnv *env, jobject thiz) { 270 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 271 272 if (extractor == NULL) { 273 jniThrowException(env, "java/lang/IllegalStateException", NULL); 274 return false; 275 } 276 277 status_t err = extractor->advance(); 278 279 if (err == ERROR_END_OF_STREAM) { 280 return false; 281 } else if (err != OK) { 282 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 283 return false; 284 } 285 286 return true; 287} 288 289static jint android_media_MediaExtractor_readSampleData( 290 JNIEnv *env, jobject thiz, jobject byteBuf, jint offset) { 291 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 292 293 if (extractor == NULL) { 294 jniThrowException(env, "java/lang/IllegalStateException", NULL); 295 return -1; 296 } 297 298 size_t sampleSize; 299 status_t err = extractor->readSampleData(byteBuf, offset, &sampleSize); 300 301 if (err == ERROR_END_OF_STREAM) { 302 return -1; 303 } else if (err != OK) { 304 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 305 return false; 306 } 307 308 return sampleSize; 309} 310 311static jint android_media_MediaExtractor_getSampleTrackIndex( 312 JNIEnv *env, jobject thiz) { 313 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 314 315 if (extractor == NULL) { 316 jniThrowException(env, "java/lang/IllegalStateException", NULL); 317 return -1; 318 } 319 320 size_t trackIndex; 321 status_t err = extractor->getSampleTrackIndex(&trackIndex); 322 323 if (err == ERROR_END_OF_STREAM) { 324 return -1; 325 } else if (err != OK) { 326 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 327 return false; 328 } 329 330 return trackIndex; 331} 332 333static jlong android_media_MediaExtractor_getSampleTime( 334 JNIEnv *env, jobject thiz) { 335 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 336 337 if (extractor == NULL) { 338 jniThrowException(env, "java/lang/IllegalStateException", NULL); 339 return -1ll; 340 } 341 342 int64_t sampleTimeUs; 343 status_t err = extractor->getSampleTime(&sampleTimeUs); 344 345 if (err == ERROR_END_OF_STREAM) { 346 return -1ll; 347 } else if (err != OK) { 348 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 349 return false; 350 } 351 352 return sampleTimeUs; 353} 354 355static jint android_media_MediaExtractor_getSampleFlags( 356 JNIEnv *env, jobject thiz) { 357 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 358 359 if (extractor == NULL) { 360 jniThrowException(env, "java/lang/IllegalStateException", NULL); 361 return -1ll; 362 } 363 364 uint32_t sampleFlags; 365 status_t err = extractor->getSampleFlags(&sampleFlags); 366 367 if (err == ERROR_END_OF_STREAM) { 368 return -1ll; 369 } else if (err != OK) { 370 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 371 return false; 372 } 373 374 return sampleFlags; 375} 376 377static void android_media_MediaExtractor_native_init(JNIEnv *env) { 378 jclass clazz = env->FindClass("android/media/MediaExtractor"); 379 CHECK(clazz != NULL); 380 381 gFields.context = env->GetFieldID(clazz, "mNativeContext", "I"); 382 CHECK(gFields.context != NULL); 383 384 DataSource::RegisterDefaultSniffers(); 385} 386 387static void android_media_MediaExtractor_native_setup( 388 JNIEnv *env, jobject thiz) { 389 sp<JMediaExtractor> extractor = new JMediaExtractor(env, thiz); 390 setMediaExtractor(env,thiz, extractor); 391} 392 393static void android_media_MediaExtractor_setDataSource( 394 JNIEnv *env, jobject thiz, 395 jstring pathObj, jobjectArray keysArray, jobjectArray valuesArray) { 396 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 397 398 if (extractor == NULL) { 399 jniThrowException(env, "java/lang/IllegalStateException", NULL); 400 return; 401 } 402 403 if (pathObj == NULL) { 404 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 405 return; 406 } 407 408 KeyedVector<String8, String8> headers; 409 if (!ConvertKeyValueArraysToKeyedVector( 410 env, keysArray, valuesArray, &headers)) { 411 return; 412 } 413 414 const char *path = env->GetStringUTFChars(pathObj, NULL); 415 416 if (path == NULL) { 417 return; 418 } 419 420 status_t err = extractor->setDataSource(path, &headers); 421 422 env->ReleaseStringUTFChars(pathObj, path); 423 path = NULL; 424 425 if (err != OK) { 426 jniThrowException( 427 env, 428 "java/io/IOException", 429 "Failed to instantiate extractor."); 430 return; 431 } 432} 433 434static void android_media_MediaExtractor_setDataSourceFd( 435 JNIEnv *env, jobject thiz, 436 jobject fileDescObj, jlong offset, jlong length) { 437 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 438 439 if (extractor == NULL) { 440 jniThrowException(env, "java/lang/IllegalStateException", NULL); 441 return; 442 } 443 444 if (fileDescObj == NULL) { 445 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 446 return; 447 } 448 449 int fd = jniGetFDFromFileDescriptor(env, fileDescObj); 450 451 status_t err = extractor->setDataSource(fd, offset, length); 452 453 if (err != OK) { 454 jniThrowException( 455 env, 456 "java/io/IOException", 457 "Failed to instantiate extractor."); 458 return; 459 } 460} 461 462static void android_media_MediaExtractor_native_finalize( 463 JNIEnv *env, jobject thiz) { 464 android_media_MediaExtractor_release(env, thiz); 465} 466 467static JNINativeMethod gMethods[] = { 468 { "release", "()V", (void *)android_media_MediaExtractor_release }, 469 470 { "countTracks", "()I", (void *)android_media_MediaExtractor_countTracks }, 471 472 { "getTrackFormat", "(I)Ljava/util/Map;", 473 (void *)android_media_MediaExtractor_getTrackFormat }, 474 475 { "selectTrack", "(I)V", (void *)android_media_MediaExtractor_selectTrack }, 476 477 { "seekTo", "(J)V", (void *)android_media_MediaExtractor_seekTo }, 478 479 { "advance", "()Z", (void *)android_media_MediaExtractor_advance }, 480 481 { "readSampleData", "(Ljava/nio/ByteBuffer;I)I", 482 (void *)android_media_MediaExtractor_readSampleData }, 483 484 { "getSampleTrackIndex", "()I", 485 (void *)android_media_MediaExtractor_getSampleTrackIndex }, 486 487 { "getSampleTime", "()J", 488 (void *)android_media_MediaExtractor_getSampleTime }, 489 490 { "getSampleFlags", "()I", 491 (void *)android_media_MediaExtractor_getSampleFlags }, 492 493 { "native_init", "()V", (void *)android_media_MediaExtractor_native_init }, 494 495 { "native_setup", "()V", 496 (void *)android_media_MediaExtractor_native_setup }, 497 498 { "native_finalize", "()V", 499 (void *)android_media_MediaExtractor_native_finalize }, 500 501 { "setDataSource", "(Ljava/lang/String;[Ljava/lang/String;" 502 "[Ljava/lang/String;)V", 503 (void *)android_media_MediaExtractor_setDataSource }, 504 505 { "setDataSource", "(Ljava/io/FileDescriptor;JJ)V", 506 (void *)android_media_MediaExtractor_setDataSourceFd }, 507}; 508 509int register_android_media_MediaExtractor(JNIEnv *env) { 510 return AndroidRuntime::registerNativeMethods(env, 511 "android/media/MediaExtractor", gMethods, NELEM(gMethods)); 512} 513