android_media_MediaExtractor.cpp revision 9b8e496f4d143280deff137c5f30ca8907bc28db
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(const char *path) { 67 return mImpl->setDataSource(path); 68} 69 70size_t JMediaExtractor::countTracks() const { 71 return mImpl->countTracks(); 72} 73 74status_t JMediaExtractor::getTrackFormat(size_t index, jobject *format) const { 75 sp<AMessage> msg; 76 status_t err; 77 if ((err = mImpl->getTrackFormat(index, &msg)) != OK) { 78 return err; 79 } 80 81 JNIEnv *env = AndroidRuntime::getJNIEnv(); 82 83 return ConvertMessageToMap(env, msg, format); 84} 85 86status_t JMediaExtractor::selectTrack(size_t index) { 87 return mImpl->selectTrack(index); 88} 89 90status_t JMediaExtractor::seekTo(int64_t timeUs) { 91 return mImpl->seekTo(timeUs); 92} 93 94status_t JMediaExtractor::advance() { 95 return mImpl->advance(); 96} 97 98status_t JMediaExtractor::readSampleData( 99 jobject byteBuf, size_t offset, size_t *sampleSize) { 100 JNIEnv *env = AndroidRuntime::getJNIEnv(); 101 102 void *dst = env->GetDirectBufferAddress(byteBuf); 103 104 jlong dstSize; 105 jbyteArray byteArray = NULL; 106 107 if (dst == NULL) { 108 jclass byteBufClass = env->FindClass("java/nio/ByteBuffer"); 109 CHECK(byteBufClass != NULL); 110 111 jmethodID arrayID = 112 env->GetMethodID(byteBufClass, "array", "()[B"); 113 CHECK(arrayID != NULL); 114 115 byteArray = 116 (jbyteArray)env->CallObjectMethod(byteBuf, arrayID); 117 118 if (byteArray == NULL) { 119 return INVALID_OPERATION; 120 } 121 122 jboolean isCopy; 123 dst = env->GetByteArrayElements(byteArray, &isCopy); 124 125 dstSize = env->GetArrayLength(byteArray); 126 } else { 127 dstSize = env->GetDirectBufferCapacity(byteBuf); 128 } 129 130 if (dstSize < offset) { 131 if (byteArray != NULL) { 132 env->ReleaseByteArrayElements(byteArray, (jbyte *)dst, 0); 133 } 134 135 return -ERANGE; 136 } 137 138 sp<ABuffer> buffer = new ABuffer((char *)dst + offset, dstSize - offset); 139 140 status_t err = mImpl->readSampleData(buffer); 141 142 if (byteArray != NULL) { 143 env->ReleaseByteArrayElements(byteArray, (jbyte *)dst, 0); 144 } 145 146 if (err != OK) { 147 return err; 148 } 149 150 *sampleSize = buffer->size(); 151 152 return OK; 153} 154 155status_t JMediaExtractor::getSampleTrackIndex(size_t *trackIndex) { 156 return mImpl->getSampleTrackIndex(trackIndex); 157} 158 159status_t JMediaExtractor::getSampleTime(int64_t *sampleTimeUs) { 160 return mImpl->getSampleTime(sampleTimeUs); 161} 162 163status_t JMediaExtractor::getSampleFlags(uint32_t *sampleFlags) { 164 return mImpl->getSampleFlags(sampleFlags); 165} 166 167} // namespace android 168 169//////////////////////////////////////////////////////////////////////////////// 170 171using namespace android; 172 173static sp<JMediaExtractor> setMediaExtractor( 174 JNIEnv *env, jobject thiz, const sp<JMediaExtractor> &extractor) { 175 sp<JMediaExtractor> old = 176 (JMediaExtractor *)env->GetIntField(thiz, gFields.context); 177 178 if (extractor != NULL) { 179 extractor->incStrong(thiz); 180 } 181 if (old != NULL) { 182 old->decStrong(thiz); 183 } 184 env->SetIntField(thiz, gFields.context, (int)extractor.get()); 185 186 return old; 187} 188 189static sp<JMediaExtractor> getMediaExtractor(JNIEnv *env, jobject thiz) { 190 return (JMediaExtractor *)env->GetIntField(thiz, gFields.context); 191} 192 193static void android_media_MediaExtractor_release(JNIEnv *env, jobject thiz) { 194 setMediaExtractor(env, thiz, NULL); 195} 196 197static jint android_media_MediaExtractor_countTracks( 198 JNIEnv *env, jobject thiz) { 199 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 200 201 if (extractor == NULL) { 202 jniThrowException(env, "java/lang/IllegalStateException", NULL); 203 return NULL; 204 } 205 206 return extractor->countTracks(); 207} 208 209static jobject android_media_MediaExtractor_getTrackFormat( 210 JNIEnv *env, jobject thiz, jint index) { 211 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 212 213 if (extractor == NULL) { 214 jniThrowException(env, "java/lang/IllegalStateException", NULL); 215 return NULL; 216 } 217 218 jobject format; 219 status_t err = extractor->getTrackFormat(index, &format); 220 221 if (err != OK) { 222 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 223 return NULL; 224 } 225 226 return format; 227} 228 229static void android_media_MediaExtractor_selectTrack( 230 JNIEnv *env, jobject thiz, jint index) { 231 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 232 233 if (extractor == NULL) { 234 jniThrowException(env, "java/lang/IllegalStateException", NULL); 235 return; 236 } 237 238 status_t err = extractor->selectTrack(index); 239 240 if (err != OK) { 241 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 242 return; 243 } 244} 245 246static void android_media_MediaExtractor_seekTo( 247 JNIEnv *env, jobject thiz, jlong timeUs) { 248 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 249 250 if (extractor == NULL) { 251 jniThrowException(env, "java/lang/IllegalStateException", NULL); 252 return; 253 } 254 255 status_t err = extractor->seekTo(timeUs); 256 257 if (err != OK) { 258 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 259 return; 260 } 261} 262 263static jboolean android_media_MediaExtractor_advance( 264 JNIEnv *env, jobject thiz) { 265 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 266 267 if (extractor == NULL) { 268 jniThrowException(env, "java/lang/IllegalStateException", NULL); 269 return false; 270 } 271 272 status_t err = extractor->advance(); 273 274 if (err == ERROR_END_OF_STREAM) { 275 return false; 276 } else if (err != OK) { 277 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 278 return false; 279 } 280 281 return true; 282} 283 284static jint android_media_MediaExtractor_readSampleData( 285 JNIEnv *env, jobject thiz, jobject byteBuf, jint offset) { 286 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 287 288 if (extractor == NULL) { 289 jniThrowException(env, "java/lang/IllegalStateException", NULL); 290 return -1; 291 } 292 293 size_t sampleSize; 294 status_t err = extractor->readSampleData(byteBuf, offset, &sampleSize); 295 296 if (err == ERROR_END_OF_STREAM) { 297 return -1; 298 } else if (err != OK) { 299 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 300 return false; 301 } 302 303 return sampleSize; 304} 305 306static jint android_media_MediaExtractor_getSampleTrackIndex( 307 JNIEnv *env, jobject thiz) { 308 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 309 310 if (extractor == NULL) { 311 jniThrowException(env, "java/lang/IllegalStateException", NULL); 312 return -1; 313 } 314 315 size_t trackIndex; 316 status_t err = extractor->getSampleTrackIndex(&trackIndex); 317 318 if (err == ERROR_END_OF_STREAM) { 319 return -1; 320 } else if (err != OK) { 321 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 322 return false; 323 } 324 325 return trackIndex; 326} 327 328static jlong android_media_MediaExtractor_getSampleTime( 329 JNIEnv *env, jobject thiz) { 330 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 331 332 if (extractor == NULL) { 333 jniThrowException(env, "java/lang/IllegalStateException", NULL); 334 return -1ll; 335 } 336 337 int64_t sampleTimeUs; 338 status_t err = extractor->getSampleTime(&sampleTimeUs); 339 340 if (err == ERROR_END_OF_STREAM) { 341 return -1ll; 342 } else if (err != OK) { 343 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 344 return false; 345 } 346 347 return sampleTimeUs; 348} 349 350static jint android_media_MediaExtractor_getSampleFlags( 351 JNIEnv *env, jobject thiz) { 352 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 353 354 if (extractor == NULL) { 355 jniThrowException(env, "java/lang/IllegalStateException", NULL); 356 return -1ll; 357 } 358 359 uint32_t sampleFlags; 360 status_t err = extractor->getSampleFlags(&sampleFlags); 361 362 if (err == ERROR_END_OF_STREAM) { 363 return -1ll; 364 } else if (err != OK) { 365 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 366 return false; 367 } 368 369 return sampleFlags; 370} 371 372static void android_media_MediaExtractor_native_init(JNIEnv *env) { 373 jclass clazz = env->FindClass("android/media/MediaExtractor"); 374 CHECK(clazz != NULL); 375 376 gFields.context = env->GetFieldID(clazz, "mNativeContext", "I"); 377 CHECK(gFields.context != NULL); 378 379 DataSource::RegisterDefaultSniffers(); 380} 381 382static void android_media_MediaExtractor_native_setup( 383 JNIEnv *env, jobject thiz, jstring path) { 384 sp<JMediaExtractor> extractor = new JMediaExtractor(env, thiz); 385 386 if (path == NULL) { 387 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 388 return; 389 } 390 391 const char *tmp = env->GetStringUTFChars(path, NULL); 392 393 if (tmp == NULL) { 394 return; 395 } 396 397 status_t err = extractor->setDataSource(tmp); 398 399 env->ReleaseStringUTFChars(path, tmp); 400 tmp = NULL; 401 402 if (err != OK) { 403 jniThrowException( 404 env, 405 "java/io/IOException", 406 "Failed to instantiate extractor."); 407 return; 408 } 409 410 setMediaExtractor(env,thiz, extractor); 411} 412 413static void android_media_MediaExtractor_native_finalize( 414 JNIEnv *env, jobject thiz) { 415 android_media_MediaExtractor_release(env, thiz); 416} 417 418static JNINativeMethod gMethods[] = { 419 { "release", "()V", (void *)android_media_MediaExtractor_release }, 420 421 { "countTracks", "()I", (void *)android_media_MediaExtractor_countTracks }, 422 423 { "getTrackFormat", "(I)Ljava/util/Map;", 424 (void *)android_media_MediaExtractor_getTrackFormat }, 425 426 { "selectTrack", "(I)V", (void *)android_media_MediaExtractor_selectTrack }, 427 428 { "seekTo", "(J)V", (void *)android_media_MediaExtractor_seekTo }, 429 430 { "advance", "()Z", (void *)android_media_MediaExtractor_advance }, 431 432 { "readSampleData", "(Ljava/nio/ByteBuffer;I)I", 433 (void *)android_media_MediaExtractor_readSampleData }, 434 435 { "getSampleTrackIndex", "()I", 436 (void *)android_media_MediaExtractor_getSampleTrackIndex }, 437 438 { "getSampleTime", "()J", 439 (void *)android_media_MediaExtractor_getSampleTime }, 440 441 { "getSampleFlags", "()I", 442 (void *)android_media_MediaExtractor_getSampleFlags }, 443 444 { "native_init", "()V", (void *)android_media_MediaExtractor_native_init }, 445 446 { "native_setup", "(Ljava/lang/String;)V", 447 (void *)android_media_MediaExtractor_native_setup }, 448 449 { "native_finalize", "()V", 450 (void *)android_media_MediaExtractor_native_finalize }, 451}; 452 453int register_android_media_MediaExtractor(JNIEnv *env) { 454 return AndroidRuntime::registerNativeMethods(env, 455 "android/media/MediaExtractor", gMethods, NELEM(gMethods)); 456} 457