libvlcjni.c 23.2 KB
Newer Older
Rafaël Carré's avatar
Rafaël Carré committed
1 2 3
/*****************************************************************************
 * libvlcjni.c
 *****************************************************************************
Edward Wang's avatar
Edward Wang committed
4
 * Copyright © 2010-2013 VLC authors and VideoLAN
Rafaël Carré's avatar
Rafaël Carré committed
5
 *
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
6 7 8
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
Rafaël Carré's avatar
Rafaël Carré committed
9 10 11 12
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
13 14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
Rafaël Carré's avatar
Rafaël Carré committed
15
 *
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
16 17 18
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
Rafaël Carré's avatar
Rafaël Carré committed
19 20
 *****************************************************************************/

21 22
#include <dirent.h>
#include <errno.h>
23
#include <string.h>
24
#include <pthread.h>
25
#include <sys/stat.h>
26
#include <sys/types.h>
27
#include <unistd.h>
28

29
#include <vlc/vlc.h>
30 31
#include <vlc_common.h>
#include <vlc_url.h>
32

33
#include <jni.h>
34

35
#include <android/api-level.h>
36

37
#include "libvlcjni.h"
ivoire's avatar
ivoire committed
38
#include "aout.h"
39
#include "vout.h"
40
#include "utils.h"
41
#include "native_crash_handler.h"
42

43 44
#define VOUT_ANDROID_SURFACE 0
#define VOUT_OPENGLES2       1
45
#define VOUT_ANDROID_WINDOW  2
46

47
#define LOG_TAG "VLC/JNI/main"
48 49
#include "log.h"

50 51 52 53 54 55
#ifdef HAVE_IOMX_DR
#define NO_IOMX_DR "--no-omxil-dr"
#else
#define NO_IOMX_DR ""
#endif

56 57
#define VLC_JNI_VERSION JNI_VERSION_1_2

58 59 60 61 62
#define THREAD_NAME "libvlcjni"
int jni_attach_thread(JNIEnv **env, const char *thread_name);
void jni_detach_thread();
int jni_get_env(JNIEnv **env);

63 64 65 66 67 68 69 70 71 72 73 74
static void add_media_options(libvlc_media_t *p_md, JNIEnv *env, jobjectArray mediaOptions)
{
    int stringCount = (*env)->GetArrayLength(env, mediaOptions);
    for(int i = 0; i < stringCount; i++)
    {
        jstring option = (jstring)(*env)->GetObjectArrayElement(env, mediaOptions, i);
        const char* p_st = (*env)->GetStringUTFChars(env, option, 0);
        libvlc_media_add_option(p_md, p_st); // option
        (*env)->ReleaseStringUTFChars(env, option, p_st);
    }
}

75
libvlc_media_t *new_media(JNIEnv *env, jobject thiz, jstring fileLocation, bool noOmx, bool noVideo)
76
{
77
    libvlc_instance_t *libvlc = getLibVlcInstance(env, thiz);
78
    jboolean isCopy;
79 80 81
    const char *psz_location = (*env)->GetStringUTFChars(env, fileLocation, &isCopy);
    libvlc_media_t *p_md = libvlc_media_new_location(libvlc, psz_location);
    (*env)->ReleaseStringUTFChars(env, fileLocation, psz_location);
82 83 84
    if (!p_md)
        return NULL;

85 86 87 88 89 90 91 92 93
    jclass cls = (*env)->GetObjectClass(env, thiz);
    jmethodID methodId = (*env)->GetMethodID(env, cls, "getMediaOptions", "(ZZ)[Ljava/lang/String;");
    if (methodId != NULL)
    {
        jobjectArray mediaOptions = (*env)->CallObjectMethod(env, thiz, methodId, noOmx, noVideo);
        if (mediaOptions != NULL)
        {
            add_media_options(p_md, env, mediaOptions);
            (*env)->DeleteLocalRef(env, mediaOptions);
94
        }
95
    }
96
    return p_md;
97 98
}

99 100 101 102 103
libvlc_instance_t *getLibVlcInstance(JNIEnv *env, jobject thiz)
{
    return (libvlc_instance_t*)(intptr_t)getLong(env, thiz, "mLibVlcInstance");
}

104
libvlc_media_player_t *getMediaPlayer(JNIEnv *env, jobject thiz)
105
{
Ludovic Fauvet's avatar
Ludovic Fauvet committed
106
    return (libvlc_media_player_t*)(intptr_t)getLong(env, thiz, "mInternalMediaPlayerInstance");
107 108
}

109

Rafaël Carré's avatar
Rafaël Carré committed
110 111
static void releaseMediaPlayer(JNIEnv *env, jobject thiz)
{
112 113
    libvlc_media_player_t* p_mp = getMediaPlayer(env, thiz);
    if (p_mp)
114
    {
115 116
        libvlc_media_player_stop(p_mp);
        libvlc_media_player_release(p_mp);
117
        setLong(env, thiz, "mInternalMediaPlayerInstance", 0);
118 119 120
    }
}

121 122 123 124
/* Pointer to the Java virtual machine
 * Note: It's okay to use a static variable for the VM pointer since there
 * can only be one instance of this shared library in a single VM
 */
Thomas Guillem's avatar
Thomas Guillem committed
125
static JavaVM *myVm;
126

127
static jobject eventHandlerInstance = NULL;
128 129 130 131 132

static void vlc_event_callback(const libvlc_event_t *ev, void *data)
{
    JNIEnv *env;

133
    bool isAttached = false;
134

135
    if (eventHandlerInstance == NULL)
Sébastien Toque's avatar
Sébastien Toque committed
136
        return;
137

138 139
    if (jni_get_env(&env) < 0) {
        if (jni_attach_thread(&env, THREAD_NAME) < 0)
140
            return;
141
        isAttached = true;
142 143
    }

144 145 146 147 148 149 150 151 152 153
    /* Creating the bundle in C allows us to subscribe to more events
     * and get better flexibility for each event. For example, we can
     * have totally different types of data for each event, instead of,
     * for example, only an integer and/or string.
     */
    jclass clsBundle = (*env)->FindClass(env, "android/os/Bundle");
    jmethodID clsCtor = (*env)->GetMethodID(env, clsBundle, "<init>", "()V" );
    jobject bundle = (*env)->NewObject(env, clsBundle, clsCtor);

    jmethodID putInt = (*env)->GetMethodID(env, clsBundle, "putInt", "(Ljava/lang/String;I)V" );
154
    jmethodID putLong = (*env)->GetMethodID(env, clsBundle, "putLong", "(Ljava/lang/String;J)V" );
155
    jmethodID putFloat = (*env)->GetMethodID(env, clsBundle, "putFloat", "(Ljava/lang/String;F)V" );
156 157
    jmethodID putString = (*env)->GetMethodID(env, clsBundle, "putString", "(Ljava/lang/String;Ljava/lang/String;)V" );

158
    if (ev->type == libvlc_MediaPlayerPositionChanged) {
159 160 161
        jstring sData = (*env)->NewStringUTF(env, "data");
        (*env)->CallVoidMethod(env, bundle, putFloat, sData, ev->u.media_player_position_changed.new_position);
        (*env)->DeleteLocalRef(env, sData);
162 163
    } else if (ev->type == libvlc_MediaPlayerTimeChanged) {
        jstring sData = (*env)->NewStringUTF(env, "data");
164
        (*env)->CallVoidMethod(env, bundle, putLong, sData, ev->u.media_player_time_changed.new_time);
165
        (*env)->DeleteLocalRef(env, sData);
166
    } else if(ev->type == libvlc_MediaPlayerVout) {
167 168 169 170
        /* For determining the vout/ES track change */
        jstring sData = (*env)->NewStringUTF(env, "data");
        (*env)->CallVoidMethod(env, bundle, putInt, sData, ev->u.media_player_vout.new_count);
        (*env)->DeleteLocalRef(env, sData);
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
    } else if(ev->type == libvlc_MediaListItemAdded ||
              ev->type == libvlc_MediaListItemDeleted ) {
        jstring item_uri = (*env)->NewStringUTF(env, "item_uri");
        jstring item_index = (*env)->NewStringUTF(env, "item_index");
        char* mrl = libvlc_media_get_mrl(
            ev->type == libvlc_MediaListItemAdded ?
            ev->u.media_list_item_added.item :
            ev->u.media_list_item_deleted.item
            );
        jstring item_uri_value = (*env)->NewStringUTF(env, mrl);
        jint item_index_value;
        if(ev->type == libvlc_MediaListItemAdded)
            item_index_value = ev->u.media_list_item_added.index;
        else
            item_index_value = ev->u.media_list_item_deleted.index;

        (*env)->CallVoidMethod(env, bundle, putString, item_uri, item_uri_value);
        (*env)->CallVoidMethod(env, bundle, putInt, item_index, item_index_value);

        (*env)->DeleteLocalRef(env, item_uri);
        (*env)->DeleteLocalRef(env, item_uri_value);
        (*env)->DeleteLocalRef(env, item_index);
        free(mrl);
194 195
    }

196
    /* Get the object class */
197
    jclass cls = (*env)->GetObjectClass(env, eventHandlerInstance);
198
    if (!cls) {
199
        LOGE("EventHandler: failed to get class reference");
200
        goto end;
201 202 203
    }

    /* Find the callback ID */
204
    jmethodID methodID = (*env)->GetMethodID(env, cls, "callback", "(ILandroid/os/Bundle;)V");
205
    if (methodID) {
206
        (*env)->CallVoidMethod(env, eventHandlerInstance, methodID, ev->type, bundle);
207
    } else {
208
        LOGE("EventHandler: failed to get the callback method");
209 210
    }

211
end:
Edward Wang's avatar
Edward Wang committed
212
    (*env)->DeleteLocalRef(env, bundle);
213
    if (isAttached)
214
        jni_detach_thread();
215 216
}

217
jint JNI_OnLoad(JavaVM *vm, void *reserved)
218
{
219 220 221
    // Keep a reference on the Java VM.
    myVm = vm;

222
    pthread_mutex_init(&vout_android_lock, NULL);
223
    pthread_cond_init(&vout_android_surf_attached, NULL);
224

225
    LOGD("JNI interface loaded.");
226
    return VLC_JNI_VERSION;
227 228
}

229 230
void JNI_OnUnload(JavaVM* vm, void* reserved) {
    pthread_mutex_destroy(&vout_android_lock);
231
    pthread_cond_destroy(&vout_android_surf_attached);
232 233
}

234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
int jni_attach_thread(JNIEnv **env, const char *thread_name)
{
    JavaVMAttachArgs args;
    jint result;

    args.version = VLC_JNI_VERSION;
    args.name = thread_name;
    args.group = NULL;

    result = (*myVm)->AttachCurrentThread(myVm, env, &args);
    return result == JNI_OK ? 0 : -1;
}

void jni_detach_thread()
{
    (*myVm)->DetachCurrentThread(myVm);
}

int jni_get_env(JNIEnv **env)
{
254
    return (*myVm)->GetEnv(myVm, (void **)env, VLC_JNI_VERSION) == JNI_OK ? 0 : -1;
255 256
}

Rafaël Carré's avatar
Rafaël Carré committed
257 258
// FIXME: use atomics
static bool verbosity;
259

260
void Java_org_videolan_libvlc_LibVLC_nativeInit(JNIEnv *env, jobject thiz)
261
{
262 263 264
    //only use OpenSLES if java side says we can
    jclass cls = (*env)->GetObjectClass(env, thiz);
    jmethodID methodId = (*env)->GetMethodID(env, cls, "getAout", "()I");
Thomas Guillem's avatar
Thomas Guillem committed
265
    int aout = (*env)->CallIntMethod(env, thiz, methodId);
266

267
    methodId = (*env)->GetMethodID(env, cls, "getVout", "()I");
268
    int vout = (*env)->CallIntMethod(env, thiz, methodId);
269

270 271 272
    methodId = (*env)->GetMethodID(env, cls, "timeStretchingEnabled", "()Z");
    bool enable_time_stretch = (*env)->CallBooleanMethod(env, thiz, methodId);

Edward Wang's avatar
Edward Wang committed
273 274 275
    methodId = (*env)->GetMethodID(env, cls, "frameSkipEnabled", "()Z");
    bool enable_frame_skip = (*env)->CallBooleanMethod(env, thiz, methodId);

Edward Wang's avatar
Edward Wang committed
276 277
    methodId = (*env)->GetMethodID(env, cls, "getDeblocking", "()I");
    int deblocking = (*env)->CallIntMethod(env, thiz, methodId);
Rafaël Carré's avatar
Rafaël Carré committed
278 279
    char deblockstr[2];
    snprintf(deblockstr, sizeof(deblockstr), "%d", deblocking);
Edward Wang's avatar
Edward Wang committed
280
    LOGD("Using deblocking level %d", deblocking);
281

Edward Wang's avatar
Edward Wang committed
282 283
    methodId = (*env)->GetMethodID(env, cls, "getNetworkCaching", "()I");
    int networkCaching = (*env)->CallIntMethod(env, thiz, methodId);
Rafaël Carré's avatar
Rafaël Carré committed
284
    char networkCachingstr[25];
Edward Wang's avatar
Edward Wang committed
285
    if(networkCaching > 0) {
Rafaël Carré's avatar
Rafaël Carré committed
286
        snprintf(networkCachingstr, sizeof(networkCachingstr), "--network-caching=%d", networkCaching);
Edward Wang's avatar
Edward Wang committed
287 288 289
        LOGD("Using network caching of %d ms", networkCaching);
    }

290 291 292
    methodId = (*env)->GetMethodID(env, cls, "getHttpReconnect", "()Z");
    bool enable_http_reconnect = (*env)->CallBooleanMethod(env, thiz, methodId);

293 294 295 296
    methodId = (*env)->GetMethodID(env, cls, "getChroma", "()Ljava/lang/String;");
    jstring chroma = (*env)->CallObjectMethod(env, thiz, methodId);
    const char *chromastr = (*env)->GetStringUTFChars(env, chroma, 0);
    LOGD("Chroma set to \"%s\"", chromastr);
Edward Wang's avatar
Edward Wang committed
297

298 299 300
    methodId = (*env)->GetMethodID(env, cls, "getSubtitlesEncoding", "()Ljava/lang/String;");
    jstring subsencoding = (*env)->CallObjectMethod(env, thiz, methodId);
    const char *subsencodingstr = (*env)->GetStringUTFChars(env, subsencoding, 0);
Edward Wang's avatar
Edward Wang committed
301
    LOGD("Subtitle encoding set to \"%s\"", subsencodingstr);
302

303 304 305
    methodId = (*env)->GetMethodID(env, cls, "isVerboseMode", "()Z");
    verbosity = (*env)->CallBooleanMethod(env, thiz, methodId);

306 307
    methodId = (*env)->GetMethodID(env, cls, "isDirectRendering", "()Z");
    bool direct_rendering = (*env)->CallBooleanMethod(env, thiz, methodId);
308
    /* With the MediaCodec opaque mode we cannot use the OpenGL ES vout. */
309
    if (direct_rendering)
310
        vout = VOUT_ANDROID_WINDOW;
311

flx42's avatar
flx42 committed
312 313
    methodId = (*env)->GetMethodID(env, cls, "getCachePath", "()Ljava/lang/String;");
    jstring cachePath = (*env)->CallObjectMethod(env, thiz, methodId);
314 315 316 317 318
    if (cachePath) {
        const char *cache_path = (*env)->GetStringUTFChars(env, cachePath, 0);
        setenv("DVDCSS_CACHE", cache_path, 1);
        (*env)->ReleaseStringUTFChars(env, cachePath, cache_path);
    }
flx42's avatar
flx42 committed
319

320
    /* Don't add any invalid options, otherwise it causes LibVLC to crash */
321
    const char *argv[] = {
322
        /* CPU intensive plugin, setting for slow devices */
323
        enable_time_stretch ? "--audio-time-stretch" : "--no-audio-time-stretch",
324 325

        /* avcodec speed settings for slow devices */
326
        //"--avcodec-fast", // non-spec-compliant speedup tricks
Edward Wang's avatar
Edward Wang committed
327
        "--avcodec-skiploopfilter", deblockstr,
328 329
        "--avcodec-skip-frame", enable_frame_skip ? "2" : "0",
        "--avcodec-skip-idct", enable_frame_skip ? "2" : "0",
330 331 332 333

        /* Remove me when UTF-8 is enforced by law */
        "--subsdec-encoding", subsencodingstr,

334 335 336
        /* Enable statistics */
        "--stats",

337
        /* XXX: why can't the default be fine ? #7792 */
Edward Wang's avatar
Edward Wang committed
338
        (networkCaching > 0) ? networkCachingstr : "",
339 340

        /* Android audio API is a mess */
Thomas Guillem's avatar
Thomas Guillem committed
341 342
        aout == AOUT_OPENSLES ? "--aout=opensles" :
            (aout == AOUT_AUDIOTRACK ? "--aout=android_audiotrack" : "--aout=dummy"),
343 344

        /* Android video API is a mess */
345 346
        vout == VOUT_ANDROID_WINDOW ? "--vout=androidwindow" :
            (vout == VOUT_OPENGLES2 ? "--vout=gles2" : "--vout=androidsurface"),
347
        "--androidsurface-chroma", chromastr != NULL && chromastr[0] != 0 ? chromastr : "RV32",
348
        /* XXX: we can't recover from direct rendering failure */
349 350
        direct_rendering ? "" : "--no-mediacodec-dr",
        direct_rendering ? "" : NO_IOMX_DR,
351 352 353

        /* Reconnect on lost HTTP streams, e.g. network change */
        enable_http_reconnect ? "--http-reconnect" : "",
354
    };
355
    libvlc_instance_t *instance = libvlc_new(sizeof(argv) / sizeof(*argv), argv);
356

Ludovic Fauvet's avatar
Ludovic Fauvet committed
357
    setLong(env, thiz, "mLibVlcInstance", (jlong)(intptr_t) instance);
358

359
    (*env)->ReleaseStringUTFChars(env, chroma, chromastr);
360 361
    (*env)->ReleaseStringUTFChars(env, subsencoding, subsencodingstr);

362 363
    if (!instance)
    {
364
        jclass exc = (*env)->FindClass(env, "org/videolan/libvlc/LibVlcException");
365 366 367 368
        (*env)->ThrowNew(env, exc, "Unable to instantiate LibVLC");
    }

    LOGI("LibVLC initialized: %p", instance);
369

Rafaël Carré's avatar
Rafaël Carré committed
370
    libvlc_log_set(instance, debug_log, &verbosity);
371 372

    init_native_crash_handler(env, thiz);
373 374
}

375
void Java_org_videolan_libvlc_LibVLC_nativeDestroy(JNIEnv *env, jobject thiz)
376
{
377 378
    destroy_native_crash_handler(env);

379
    releaseMediaPlayer(env, thiz);
Edward Wang's avatar
Edward Wang committed
380
    jlong libVlcInstance = getLong(env, thiz, "mLibVlcInstance");
381 382 383
    if (!libVlcInstance)
        return; // Already destroyed

Ludovic Fauvet's avatar
Ludovic Fauvet committed
384
    libvlc_instance_t *instance = (libvlc_instance_t*)(intptr_t) libVlcInstance;
Rafaël Carré's avatar
Rafaël Carré committed
385
    libvlc_log_unset(instance);
386 387
    libvlc_release(instance);

Edward Wang's avatar
Edward Wang committed
388
    setLong(env, thiz, "mLibVlcInstance", 0);
389 390
}

391
void Java_org_videolan_libvlc_LibVLC_detachEventHandler(JNIEnv *env, jobject thiz)
392
{
393 394 395
    if (eventHandlerInstance != NULL) {
        (*env)->DeleteGlobalRef(env, eventHandlerInstance);
        eventHandlerInstance = NULL;
396 397 398
    }
}

399
void Java_org_videolan_libvlc_LibVLC_setEventHandler(JNIEnv *env, jobject thiz, jobject eventHandler)
400
{
401 402 403
    if (eventHandlerInstance != NULL) {
        (*env)->DeleteGlobalRef(env, eventHandlerInstance);
        eventHandlerInstance = NULL;
404 405
    }

406
    eventHandlerInstance = getEventHandlerReference(env, thiz, eventHandler);
407 408
}

409
void Java_org_videolan_libvlc_LibVLC_playMRL(JNIEnv *env, jobject thiz,
410 411
                                             jstring mrl, jobjectArray mediaOptions)
{
412 413 414
    /* Release previous media player, if any */
    releaseMediaPlayer(env, thiz);

415 416
    libvlc_instance_t *p_instance = getLibVlcInstance(env, thiz);

417
    /* Create a media player playing environment */
418
    libvlc_media_player_t *mp = libvlc_media_player_new(p_instance);
Rafaël Carré's avatar
Rafaël Carré committed
419
    libvlc_media_player_set_video_title_display(mp, libvlc_position_disable, 0);
420
    jobject myJavaLibVLC = (*env)->NewGlobalRef(env, thiz); // freed in aout_close
421

422
    // If AOUT_AUDIOTRACK_JAVA, use amem
423 424 425
    jclass cls = (*env)->GetObjectClass(env, thiz);
    jmethodID methodId = (*env)->GetMethodID(env, cls, "getAout", "()I");
    if ( (*env)->CallIntMethod(env, thiz, methodId) == AOUT_AUDIOTRACK_JAVA )
426
    {
427
        libvlc_audio_set_callbacks(mp, aout_play, aout_pause, NULL, NULL, NULL,
Sébastien Toque's avatar
Sébastien Toque committed
428 429
                                   (void*) myJavaLibVLC);
        libvlc_audio_set_format_callbacks(mp, aout_open, aout_close);
430 431
    }

432 433
    /* Connect the event manager */
    libvlc_event_manager_t *ev = libvlc_media_player_event_manager(mp);
434 435 436 437 438
    static const libvlc_event_type_t mp_events[] = {
        libvlc_MediaPlayerPlaying,
        libvlc_MediaPlayerPaused,
        libvlc_MediaPlayerEndReached,
        libvlc_MediaPlayerStopped,
439
        libvlc_MediaPlayerVout,
440
        libvlc_MediaPlayerPositionChanged,
441
        libvlc_MediaPlayerTimeChanged,
442
        libvlc_MediaPlayerEncounteredError
443
    };
444
    for(int i = 0; i < (sizeof(mp_events) / sizeof(*mp_events)); i++)
445 446
        libvlc_event_attach(ev, mp_events[i], vlc_event_callback, myVm);

447
    /* Keep a pointer to this media player */
Ludovic Fauvet's avatar
Ludovic Fauvet committed
448
    setLong(env, thiz, "mInternalMediaPlayerInstance", (jlong)(intptr_t)mp);
449

450 451 452 453
    cls = (*env)->GetObjectClass(env, thiz);
    jmethodID methodID = (*env)->GetMethodID(env, cls, "applyEqualizer", "()V");
    (*env)->CallVoidMethod(env, thiz, methodID);

454 455
    const char* p_mrl = (*env)->GetStringUTFChars(env, mrl, 0);

456
    libvlc_media_t* p_md = libvlc_media_new_location(p_instance, p_mrl);
457
    /* media options */
458
    if (mediaOptions != NULL)
459
        add_media_options(p_md, env, mediaOptions);
460

461 462
    (*env)->ReleaseStringUTFChars(env, mrl, p_mrl);

463 464 465
    /* Connect the media event manager. */
    libvlc_event_manager_t *ev_media = libvlc_media_event_manager(p_md);
    static const libvlc_event_type_t mp_media_events[] = {
Alexandre Perraud's avatar
Alexandre Perraud committed
466 467
        libvlc_MediaParsedChanged,
        libvlc_MediaMetaChanged,
468 469 470 471
    };
    for(int i = 0; i < (sizeof(mp_media_events) / sizeof(*mp_media_events)); i++)
        libvlc_event_attach(ev_media, mp_media_events[i], vlc_event_callback, myVm);

472 473
    libvlc_media_player_set_media(mp, p_md);
    libvlc_media_player_play(mp);
474 475
}

476
jfloat Java_org_videolan_libvlc_LibVLC_getRate(JNIEnv *env, jobject thiz) {
Edward Wang's avatar
Edward Wang committed
477 478 479 480 481 482 483
    libvlc_media_player_t* mp = getMediaPlayer(env, thiz);
    if(mp)
        return libvlc_media_player_get_rate(mp);
    else
        return 1.00;
}

484
void Java_org_videolan_libvlc_LibVLC_setRate(JNIEnv *env, jobject thiz, jfloat rate) {
Edward Wang's avatar
Edward Wang committed
485 486 487 488 489
    libvlc_media_player_t* mp = getMediaPlayer(env, thiz);
    if(mp)
        libvlc_media_player_set_rate(mp, rate);
}

490
jboolean Java_org_videolan_libvlc_LibVLC_isPlaying(JNIEnv *env, jobject thiz)
491
{
492
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
493
    if (mp)
494
        return !!libvlc_media_player_is_playing(mp);
495 496
    else
        return 0;
497 498
}

499
jboolean Java_org_videolan_libvlc_LibVLC_isSeekable(JNIEnv *env, jobject thiz)
500
{
501 502 503
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return !!libvlc_media_player_is_seekable(mp);
504
    return 0;
505 506
}

507
void Java_org_videolan_libvlc_LibVLC_play(JNIEnv *env, jobject thiz)
508
{
509
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
510
    if (mp)
511
        libvlc_media_player_play(mp);
512 513
}

514
void Java_org_videolan_libvlc_LibVLC_pause(JNIEnv *env, jobject thiz)
515
{
516
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
517
    if (mp)
518
        libvlc_media_player_pause(mp);
519 520
}

521
void Java_org_videolan_libvlc_LibVLC_stop(JNIEnv *env, jobject thiz)
522
{
523
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
524
    if (mp)
525
        libvlc_media_player_stop(mp);
526 527
}

528 529 530 531 532 533 534 535
jint Java_org_videolan_libvlc_LibVLC_getPlayerState(JNIEnv *env, jobject thiz)
{
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return (jint) libvlc_media_player_get_state(mp);
    return -1;
}

536
jint Java_org_videolan_libvlc_LibVLC_getVolume(JNIEnv *env, jobject thiz)
537
{
538 539 540
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return (jint) libvlc_audio_get_volume(mp);
541 542 543
    return -1;
}

544
jint Java_org_videolan_libvlc_LibVLC_setVolume(JNIEnv *env, jobject thiz, jint volume)
545
{
546 547
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
548
        //Returns 0 if the volume was set, -1 if it was out of range or error
549
        return (jint) libvlc_audio_set_volume(mp, (int) volume);
550 551 552
    return -1;
}

553
jlong Java_org_videolan_libvlc_LibVLC_getTime(JNIEnv *env, jobject thiz)
554
{
555 556 557
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return libvlc_media_player_get_time(mp);
558 559 560
    return -1;
}

561
void Java_org_videolan_libvlc_LibVLC_setTime(JNIEnv *env, jobject thiz, jlong time)
562
{
563 564 565
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        libvlc_media_player_set_time(mp, time);
566 567
}

568
jfloat Java_org_videolan_libvlc_LibVLC_getPosition(JNIEnv *env, jobject thiz)
569
{
570 571 572
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return (jfloat) libvlc_media_player_get_position(mp);
573 574 575
    return -1;
}

576
void Java_org_videolan_libvlc_LibVLC_setPosition(JNIEnv *env, jobject thiz, jfloat pos)
577
{
578 579 580
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        libvlc_media_player_set_position(mp, pos);
581 582
}

583
jlong Java_org_videolan_libvlc_LibVLC_getLength(JNIEnv *env, jobject thiz)
584
{
585 586 587
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return (jlong) libvlc_media_player_get_length(mp);
588 589 590
    return -1;
}

591
jstring Java_org_videolan_libvlc_LibVLC_version(JNIEnv* env, jobject thiz)
592
{
593 594
    return (*env)->NewStringUTF(env, libvlc_get_version());
}
595

596
jstring Java_org_videolan_libvlc_LibVLC_compiler(JNIEnv* env, jobject thiz)
597 598 599 600
{
    return (*env)->NewStringUTF(env, libvlc_get_compiler());
}

601
jstring Java_org_videolan_libvlc_LibVLC_changeset(JNIEnv* env, jobject thiz)
602 603 604
{
    return (*env)->NewStringUTF(env, libvlc_get_changeset());
}
605

606 607 608
jstring Java_org_videolan_libvlc_LibVLC_getMeta(JNIEnv *env, jobject thiz, int meta)
{
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
609 610
    char *psz_meta;
    jstring string = NULL;
611 612 613 614 615 616 617
    if (!mp)
        return NULL;

    libvlc_media_t *p_mp = libvlc_media_player_get_media(mp);
    if (!p_mp)
        return NULL;

618 619 620 621 622 623
    psz_meta = libvlc_media_get_meta(p_mp, meta);
    if (psz_meta) {
        string = (*env)->NewStringUTF(env, psz_meta);
        free(psz_meta);
    }
    return string;
624 625
}

626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647
jint Java_org_videolan_libvlc_LibVLC_getTitle(JNIEnv *env, jobject thiz)
{
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return libvlc_media_player_get_title(mp);
    return -1;
}

void Java_org_videolan_libvlc_LibVLC_setTitle(JNIEnv *env, jobject thiz, jint title)
{
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        libvlc_media_player_set_title(mp, title);
}

jint Java_org_videolan_libvlc_LibVLC_getChapterCountForTitle(JNIEnv *env, jobject thiz, jint title)
{
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return libvlc_media_player_get_chapter_count_for_title(mp, title);
    return -1;
}
Edward Wang's avatar
Edward Wang committed
648 649 650 651 652 653 654 655

jint Java_org_videolan_libvlc_LibVLC_getTitleCount(JNIEnv *env, jobject thiz)
{
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return libvlc_media_player_get_title_count(mp);
    return -1;
}
Geoffrey Métais's avatar
Geoffrey Métais committed
656 657 658 659 660 661 662 663 664

void Java_org_videolan_libvlc_LibVLC_playerNavigate(JNIEnv *env, jobject thiz, jint navigate)
{
    unsigned nav = navigate;
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        libvlc_media_player_navigate(mp, (unsigned) nav);
}

Thomas Guillem's avatar
Thomas Guillem committed
665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684
// TODO: remove static variables
static int i_window_width = 0;
static int i_window_height = 0;

void Java_org_videolan_libvlc_LibVLC_setWindowSize(JNIEnv *env, jobject thiz, jint width, jint height)
{
    pthread_mutex_lock(&vout_android_lock);
    i_window_width = width;
    i_window_height = height;
    pthread_mutex_unlock(&vout_android_lock);
}

int jni_GetWindowSize(int *width, int *height)
{
    pthread_mutex_lock(&vout_android_lock);
    *width = i_window_width;
    *height = i_window_height;
    pthread_mutex_unlock(&vout_android_lock);
    return 0;
}