android_media_MediaExtractor.cpp revision 88572f7a3e9d7ef85c26865a0150f3c2041561c2
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 if (dst == NULL) { 105 // XXX if dst is NULL also fall back to "array()" 106 return INVALID_OPERATION; 107 } 108 109 jlong dstSize = env->GetDirectBufferCapacity(byteBuf); 110 111 if (dstSize < offset) { 112 return -ERANGE; 113 } 114 115 sp<ABuffer> buffer = new ABuffer((char *)dst + offset, dstSize - offset); 116 117 status_t err = mImpl->readSampleData(buffer); 118 119 if (err != OK) { 120 return err; 121 } 122 123 *sampleSize = buffer->size(); 124 125 return OK; 126} 127 128status_t JMediaExtractor::getSampleTrackIndex(size_t *trackIndex) { 129 return mImpl->getSampleTrackIndex(trackIndex); 130} 131 132status_t JMediaExtractor::getSampleTime(int64_t *sampleTimeUs) { 133 return mImpl->getSampleTime(sampleTimeUs); 134} 135 136} // namespace android 137 138//////////////////////////////////////////////////////////////////////////////// 139 140using namespace android; 141 142static sp<JMediaExtractor> setMediaExtractor( 143 JNIEnv *env, jobject thiz, const sp<JMediaExtractor> &extractor) { 144 sp<JMediaExtractor> old = 145 (JMediaExtractor *)env->GetIntField(thiz, gFields.context); 146 147 if (extractor != NULL) { 148 extractor->incStrong(thiz); 149 } 150 if (old != NULL) { 151 old->decStrong(thiz); 152 } 153 env->SetIntField(thiz, gFields.context, (int)extractor.get()); 154 155 return old; 156} 157 158static sp<JMediaExtractor> getMediaExtractor(JNIEnv *env, jobject thiz) { 159 return (JMediaExtractor *)env->GetIntField(thiz, gFields.context); 160} 161 162static void android_media_MediaExtractor_release(JNIEnv *env, jobject thiz) { 163 setMediaExtractor(env, thiz, NULL); 164} 165 166static jint android_media_MediaExtractor_countTracks( 167 JNIEnv *env, jobject thiz) { 168 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 169 170 if (extractor == NULL) { 171 jniThrowException(env, "java/lang/IllegalStateException", NULL); 172 return NULL; 173 } 174 175 return extractor->countTracks(); 176} 177 178static jobject android_media_MediaExtractor_getTrackFormat( 179 JNIEnv *env, jobject thiz, jint index) { 180 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 181 182 if (extractor == NULL) { 183 jniThrowException(env, "java/lang/IllegalStateException", NULL); 184 return NULL; 185 } 186 187 jobject format; 188 status_t err = extractor->getTrackFormat(index, &format); 189 190 if (err != OK) { 191 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 192 return NULL; 193 } 194 195 return format; 196} 197 198static void android_media_MediaExtractor_selectTrack( 199 JNIEnv *env, jobject thiz, jint index) { 200 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 201 202 if (extractor == NULL) { 203 jniThrowException(env, "java/lang/IllegalStateException", NULL); 204 return; 205 } 206 207 status_t err = extractor->selectTrack(index); 208 209 if (err != OK) { 210 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 211 return; 212 } 213} 214 215static void android_media_MediaExtractor_seekTo( 216 JNIEnv *env, jobject thiz, jlong timeUs) { 217 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 218 219 if (extractor == NULL) { 220 jniThrowException(env, "java/lang/IllegalStateException", NULL); 221 return; 222 } 223 224 status_t err = extractor->seekTo(timeUs); 225 226 if (err != OK) { 227 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 228 return; 229 } 230} 231 232static jboolean android_media_MediaExtractor_advance( 233 JNIEnv *env, jobject thiz) { 234 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 235 236 if (extractor == NULL) { 237 jniThrowException(env, "java/lang/IllegalStateException", NULL); 238 return false; 239 } 240 241 status_t err = extractor->advance(); 242 243 if (err == ERROR_END_OF_STREAM) { 244 return false; 245 } else if (err != OK) { 246 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 247 return false; 248 } 249 250 return true; 251} 252 253static jint android_media_MediaExtractor_readSampleData( 254 JNIEnv *env, jobject thiz, jobject byteBuf, jint offset) { 255 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 256 257 if (extractor == NULL) { 258 jniThrowException(env, "java/lang/IllegalStateException", NULL); 259 return -1; 260 } 261 262 size_t sampleSize; 263 status_t err = extractor->readSampleData(byteBuf, offset, &sampleSize); 264 265 if (err == ERROR_END_OF_STREAM) { 266 return -1; 267 } else if (err != OK) { 268 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 269 return false; 270 } 271 272 return sampleSize; 273} 274 275static jint android_media_MediaExtractor_getSampleTrackIndex( 276 JNIEnv *env, jobject thiz) { 277 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 278 279 if (extractor == NULL) { 280 jniThrowException(env, "java/lang/IllegalStateException", NULL); 281 return -1; 282 } 283 284 size_t trackIndex; 285 status_t err = extractor->getSampleTrackIndex(&trackIndex); 286 287 if (err == ERROR_END_OF_STREAM) { 288 return -1; 289 } else if (err != OK) { 290 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 291 return false; 292 } 293 294 return trackIndex; 295} 296 297static jlong android_media_MediaExtractor_getSampleTime( 298 JNIEnv *env, jobject thiz) { 299 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 300 301 if (extractor == NULL) { 302 jniThrowException(env, "java/lang/IllegalStateException", NULL); 303 return -1ll; 304 } 305 306 int64_t sampleTimeUs; 307 status_t err = extractor->getSampleTime(&sampleTimeUs); 308 309 if (err == ERROR_END_OF_STREAM) { 310 return -1ll; 311 } else if (err != OK) { 312 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 313 return false; 314 } 315 316 return sampleTimeUs; 317} 318 319static void android_media_MediaExtractor_native_init(JNIEnv *env) { 320 jclass clazz = env->FindClass("android/media/MediaExtractor"); 321 CHECK(clazz != NULL); 322 323 gFields.context = env->GetFieldID(clazz, "mNativeContext", "I"); 324 CHECK(gFields.context != NULL); 325 326 DataSource::RegisterDefaultSniffers(); 327} 328 329static void android_media_MediaExtractor_native_setup( 330 JNIEnv *env, jobject thiz, jstring path) { 331 sp<JMediaExtractor> extractor = new JMediaExtractor(env, thiz); 332 333 if (path == NULL) { 334 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 335 return; 336 } 337 338 const char *tmp = env->GetStringUTFChars(path, NULL); 339 340 if (tmp == NULL) { 341 return; 342 } 343 344 status_t err = extractor->setDataSource(tmp); 345 346 env->ReleaseStringUTFChars(path, tmp); 347 tmp = NULL; 348 349 if (err != OK) { 350 jniThrowException( 351 env, 352 "java/io/IOException", 353 "Failed to instantiate extractor."); 354 return; 355 } 356 357 setMediaExtractor(env,thiz, extractor); 358} 359 360static void android_media_MediaExtractor_native_finalize( 361 JNIEnv *env, jobject thiz) { 362 android_media_MediaExtractor_release(env, thiz); 363} 364 365static JNINativeMethod gMethods[] = { 366 { "release", "()V", (void *)android_media_MediaExtractor_release }, 367 368 { "countTracks", "()I", (void *)android_media_MediaExtractor_countTracks }, 369 370 { "getTrackFormat", "(I)Ljava/util/Map;", 371 (void *)android_media_MediaExtractor_getTrackFormat }, 372 373 { "selectTrack", "(I)V", (void *)android_media_MediaExtractor_selectTrack }, 374 375 { "seekTo", "(J)V", (void *)android_media_MediaExtractor_seekTo }, 376 377 { "advance", "()Z", (void *)android_media_MediaExtractor_advance }, 378 379 { "readSampleData", "(Ljava/nio/ByteBuffer;I)I", 380 (void *)android_media_MediaExtractor_readSampleData }, 381 382 { "getSampleTrackIndex", "()I", 383 (void *)android_media_MediaExtractor_getSampleTrackIndex }, 384 385 { "getSampleTime", "()J", 386 (void *)android_media_MediaExtractor_getSampleTime }, 387 388 { "native_init", "()V", (void *)android_media_MediaExtractor_native_init }, 389 390 { "native_setup", "(Ljava/lang/String;)V", 391 (void *)android_media_MediaExtractor_native_setup }, 392 393 { "native_finalize", "()V", 394 (void *)android_media_MediaExtractor_native_finalize }, 395}; 396 397int register_android_media_MediaExtractor(JNIEnv *env) { 398 return AndroidRuntime::registerNativeMethods(env, 399 "android/media/MediaExtractor", gMethods, NELEM(gMethods)); 400} 401