android_media_MediaExtractor.cpp revision c52b980277f08aee7981b1fdbca7a89464cf66d9
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 163} // namespace android 164 165//////////////////////////////////////////////////////////////////////////////// 166 167using namespace android; 168 169static sp<JMediaExtractor> setMediaExtractor( 170 JNIEnv *env, jobject thiz, const sp<JMediaExtractor> &extractor) { 171 sp<JMediaExtractor> old = 172 (JMediaExtractor *)env->GetIntField(thiz, gFields.context); 173 174 if (extractor != NULL) { 175 extractor->incStrong(thiz); 176 } 177 if (old != NULL) { 178 old->decStrong(thiz); 179 } 180 env->SetIntField(thiz, gFields.context, (int)extractor.get()); 181 182 return old; 183} 184 185static sp<JMediaExtractor> getMediaExtractor(JNIEnv *env, jobject thiz) { 186 return (JMediaExtractor *)env->GetIntField(thiz, gFields.context); 187} 188 189static void android_media_MediaExtractor_release(JNIEnv *env, jobject thiz) { 190 setMediaExtractor(env, thiz, NULL); 191} 192 193static jint android_media_MediaExtractor_countTracks( 194 JNIEnv *env, jobject thiz) { 195 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 196 197 if (extractor == NULL) { 198 jniThrowException(env, "java/lang/IllegalStateException", NULL); 199 return NULL; 200 } 201 202 return extractor->countTracks(); 203} 204 205static jobject android_media_MediaExtractor_getTrackFormat( 206 JNIEnv *env, jobject thiz, jint index) { 207 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 208 209 if (extractor == NULL) { 210 jniThrowException(env, "java/lang/IllegalStateException", NULL); 211 return NULL; 212 } 213 214 jobject format; 215 status_t err = extractor->getTrackFormat(index, &format); 216 217 if (err != OK) { 218 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 219 return NULL; 220 } 221 222 return format; 223} 224 225static void android_media_MediaExtractor_selectTrack( 226 JNIEnv *env, jobject thiz, jint index) { 227 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 228 229 if (extractor == NULL) { 230 jniThrowException(env, "java/lang/IllegalStateException", NULL); 231 return; 232 } 233 234 status_t err = extractor->selectTrack(index); 235 236 if (err != OK) { 237 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 238 return; 239 } 240} 241 242static void android_media_MediaExtractor_seekTo( 243 JNIEnv *env, jobject thiz, jlong timeUs) { 244 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 245 246 if (extractor == NULL) { 247 jniThrowException(env, "java/lang/IllegalStateException", NULL); 248 return; 249 } 250 251 status_t err = extractor->seekTo(timeUs); 252 253 if (err != OK) { 254 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 255 return; 256 } 257} 258 259static jboolean android_media_MediaExtractor_advance( 260 JNIEnv *env, jobject thiz) { 261 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 262 263 if (extractor == NULL) { 264 jniThrowException(env, "java/lang/IllegalStateException", NULL); 265 return false; 266 } 267 268 status_t err = extractor->advance(); 269 270 if (err == ERROR_END_OF_STREAM) { 271 return false; 272 } else if (err != OK) { 273 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 274 return false; 275 } 276 277 return true; 278} 279 280static jint android_media_MediaExtractor_readSampleData( 281 JNIEnv *env, jobject thiz, jobject byteBuf, jint offset) { 282 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 283 284 if (extractor == NULL) { 285 jniThrowException(env, "java/lang/IllegalStateException", NULL); 286 return -1; 287 } 288 289 size_t sampleSize; 290 status_t err = extractor->readSampleData(byteBuf, offset, &sampleSize); 291 292 if (err == ERROR_END_OF_STREAM) { 293 return -1; 294 } else if (err != OK) { 295 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 296 return false; 297 } 298 299 return sampleSize; 300} 301 302static jint android_media_MediaExtractor_getSampleTrackIndex( 303 JNIEnv *env, jobject thiz) { 304 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 305 306 if (extractor == NULL) { 307 jniThrowException(env, "java/lang/IllegalStateException", NULL); 308 return -1; 309 } 310 311 size_t trackIndex; 312 status_t err = extractor->getSampleTrackIndex(&trackIndex); 313 314 if (err == ERROR_END_OF_STREAM) { 315 return -1; 316 } else if (err != OK) { 317 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 318 return false; 319 } 320 321 return trackIndex; 322} 323 324static jlong android_media_MediaExtractor_getSampleTime( 325 JNIEnv *env, jobject thiz) { 326 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 327 328 if (extractor == NULL) { 329 jniThrowException(env, "java/lang/IllegalStateException", NULL); 330 return -1ll; 331 } 332 333 int64_t sampleTimeUs; 334 status_t err = extractor->getSampleTime(&sampleTimeUs); 335 336 if (err == ERROR_END_OF_STREAM) { 337 return -1ll; 338 } else if (err != OK) { 339 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 340 return false; 341 } 342 343 return sampleTimeUs; 344} 345 346static void android_media_MediaExtractor_native_init(JNIEnv *env) { 347 jclass clazz = env->FindClass("android/media/MediaExtractor"); 348 CHECK(clazz != NULL); 349 350 gFields.context = env->GetFieldID(clazz, "mNativeContext", "I"); 351 CHECK(gFields.context != NULL); 352 353 DataSource::RegisterDefaultSniffers(); 354} 355 356static void android_media_MediaExtractor_native_setup( 357 JNIEnv *env, jobject thiz, jstring path) { 358 sp<JMediaExtractor> extractor = new JMediaExtractor(env, thiz); 359 360 if (path == NULL) { 361 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 362 return; 363 } 364 365 const char *tmp = env->GetStringUTFChars(path, NULL); 366 367 if (tmp == NULL) { 368 return; 369 } 370 371 status_t err = extractor->setDataSource(tmp); 372 373 env->ReleaseStringUTFChars(path, tmp); 374 tmp = NULL; 375 376 if (err != OK) { 377 jniThrowException( 378 env, 379 "java/io/IOException", 380 "Failed to instantiate extractor."); 381 return; 382 } 383 384 setMediaExtractor(env,thiz, extractor); 385} 386 387static void android_media_MediaExtractor_native_finalize( 388 JNIEnv *env, jobject thiz) { 389 android_media_MediaExtractor_release(env, thiz); 390} 391 392static JNINativeMethod gMethods[] = { 393 { "release", "()V", (void *)android_media_MediaExtractor_release }, 394 395 { "countTracks", "()I", (void *)android_media_MediaExtractor_countTracks }, 396 397 { "getTrackFormat", "(I)Ljava/util/Map;", 398 (void *)android_media_MediaExtractor_getTrackFormat }, 399 400 { "selectTrack", "(I)V", (void *)android_media_MediaExtractor_selectTrack }, 401 402 { "seekTo", "(J)V", (void *)android_media_MediaExtractor_seekTo }, 403 404 { "advance", "()Z", (void *)android_media_MediaExtractor_advance }, 405 406 { "readSampleData", "(Ljava/nio/ByteBuffer;I)I", 407 (void *)android_media_MediaExtractor_readSampleData }, 408 409 { "getSampleTrackIndex", "()I", 410 (void *)android_media_MediaExtractor_getSampleTrackIndex }, 411 412 { "getSampleTime", "()J", 413 (void *)android_media_MediaExtractor_getSampleTime }, 414 415 { "native_init", "()V", (void *)android_media_MediaExtractor_native_init }, 416 417 { "native_setup", "(Ljava/lang/String;)V", 418 (void *)android_media_MediaExtractor_native_setup }, 419 420 { "native_finalize", "()V", 421 (void *)android_media_MediaExtractor_native_finalize }, 422}; 423 424int register_android_media_MediaExtractor(JNIEnv *env) { 425 return AndroidRuntime::registerNativeMethods(env, 426 "android/media/MediaExtractor", gMethods, NELEM(gMethods)); 427} 428