libvlcjni.c 38.6 KB
Newer Older
Rafaël Carré's avatar
Rafaël Carré committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*****************************************************************************
 * libvlcjni.c
 *****************************************************************************
 * Copyright © 2010-2012 VLC authors and VideoLAN
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (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
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU 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.
 *****************************************************************************/

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>
Ludovic Fauvet's avatar
Ludovic Fauvet committed
32
#include <vlc_fourcc.h>
33

34
#include <jni.h>
35

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

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

#define LOG_TAG "VLC/JNI/main"
43
44
#include "log.h"

45
46
47
48
#define AOUT_AUDIOTRACK      0
#define AOUT_AUDIOTRACK_JAVA 1
#define AOUT_OPENSLES        2

Edward Wang's avatar
Edward Wang committed
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
static jint getInt(JNIEnv *env, jobject thiz, const char* field) {
    jclass clazz = (*env)->GetObjectClass(env, thiz);
    jfieldID fieldMP = (*env)->GetFieldID(env, clazz,
                                          field, "I");
    return (*env)->GetIntField(env, thiz, fieldMP);
}
static void setInt(JNIEnv *env, jobject item, const char* field, jint value) {
    jclass cls;
    jfieldID fieldId;

    /* Get a reference to item's class */
    cls = (*env)->GetObjectClass(env, item);

    /* Look for the instance field s in cls */
    fieldId = (*env)->GetFieldID(env, cls, field, "I");
    if (fieldId == NULL)
        return;

    (*env)->SetIntField(env, item, fieldId, value);
}

70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
static jlong getLong(JNIEnv *env, jobject thiz, const char* field) {
    jclass clazz = (*env)->GetObjectClass(env, thiz);
    jfieldID fieldMP = (*env)->GetFieldID(env, clazz,
                                          field, "J");
    return (*env)->GetLongField(env, thiz, fieldMP);
}
static void setLong(JNIEnv *env, jobject item, const char* field, jlong value) {
    jclass cls;
    jfieldID fieldId;

    /* Get a reference to item's class */
    cls = (*env)->GetObjectClass(env, item);

    /* Look for the instance field s in cls */
    fieldId = (*env)->GetFieldID(env, cls, field, "J");
    if (fieldId == NULL)
        return;

    (*env)->SetLongField(env, item, fieldId, value);
}

static void setFloat(JNIEnv *env, jobject item, const char* field, jfloat value) {
    jclass cls;
    jfieldID fieldId;

    /* Get a reference to item's class */
    cls = (*env)->GetObjectClass(env, item);

    /* Look for the instance field s in cls */
    fieldId = (*env)->GetFieldID(env, cls, field, "F");
    if (fieldId == NULL)
        return;

    (*env)->SetFloatField(env, item, fieldId, value);
}
static void setString(JNIEnv *env, jobject item, const char* field, const char* text) {
    jclass cls;
    jfieldID fieldId;
    jstring jstr;

    /* Get a reference to item's class */
    cls = (*env)->GetObjectClass(env, item);

    /* Look for the instance field s in cls */
    fieldId = (*env)->GetFieldID(env, cls, field, "Ljava/lang/String;");
    if (fieldId == NULL)
        return;

    /* Create a new string and overwrite the instance field */
    jstr = (*env)->NewStringUTF(env, text);
    if (jstr == NULL)
        return;
    (*env)->SetObjectField(env, item, fieldId, jstr);
}

125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
struct length_change_monitor {
    pthread_mutex_t doneMutex;
    pthread_cond_t doneCondVar;
    bool length_changed;
};

static void length_changed_callback(const libvlc_event_t *ev, void *data)
{
    struct length_change_monitor *monitor = data;
    pthread_mutex_lock(&monitor->doneMutex);
    monitor->length_changed = true;
    pthread_cond_signal(&monitor->doneCondVar);
    pthread_mutex_unlock(&monitor->doneMutex);
}

140
libvlc_media_t *new_media(jlong instance, JNIEnv *env, jobject thiz, jstring fileLocation, bool noOmx, bool noVideo)
141
{
142
143
    libvlc_instance_t *libvlc = (libvlc_instance_t*)instance;
    jboolean isCopy;
144
145
146
    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);
147
148
149
    if (!p_md)
        return NULL;

150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
    if (!noOmx) {
        jclass cls = (*env)->GetObjectClass(env, thiz);
        jmethodID methodId = (*env)->GetMethodID(env, cls, "useIOMX", "()Z");
        if ((*env)->CallBooleanMethod(env, thiz, methodId)) {
            /*
             * Set higher caching values if using iomx decoding, since some omx
             * decoders have a very high latency, and if the preroll data isn't
             * enough to make the decoder output a frame, the playback timing gets
             * started too soon, and every decoded frame appears to be too late.
             * On Nexus One, the decoder latency seems to be 25 input packets
             * for 320x170 H.264, a few packets less on higher resolutions.
             * On Nexus S, the decoder latency seems to be about 7 packets.
             */
            libvlc_media_add_option(p_md, ":file-caching=1500");
            libvlc_media_add_option(p_md, ":network-caching=1500");
            libvlc_media_add_option(p_md, ":codec=iomx,all");
        }
167
168
        if (noVideo)
            libvlc_media_add_option(p_md, ":no-video");
169
    }
170
    return p_md;
171
172
}

173
174
175
176
177
static libvlc_media_list_t *getMediaList(JNIEnv *env, jobject thiz)
{
    return (libvlc_media_list_t*)getLong(env, thiz, "mMediaListInstance");
}

Rafaël Carré's avatar
Rafaël Carré committed
178
static libvlc_media_player_t *getMediaPlayer(JNIEnv *env, jobject thiz)
179
{
180
181
182
183
184
185
    return (libvlc_media_player_t*)getLong(env, thiz, "mInternalMediaPlayerInstance");
}

static libvlc_media_list_player_t *getMediaListPlayer(JNIEnv *env, jobject thiz)
{
    return (libvlc_media_list_player_t*)getLong(env, thiz, "mMediaListPlayerInstance");
186
187
}

Rafaël Carré's avatar
Rafaël Carré committed
188
static void unsetMediaPlayer(JNIEnv *env, jobject thiz)
189
{
190
    setLong(env, thiz, "mInternalMediaPlayerInstance", (jlong)0);
Rafaël Carré's avatar
Rafaël Carré committed
191
192
193
194
}

static void releaseMediaPlayer(JNIEnv *env, jobject thiz)
{
195
196
    libvlc_media_list_player_t* p_mlp = getMediaListPlayer(env, thiz);
    if (p_mlp)
197
    {
198
199
200
201
        libvlc_media_list_player_stop(p_mlp);
        libvlc_media_list_player_release(p_mlp);
        /* libvlc_media_list_player_release frees the media player, so
         * we don't free it ourselves. */
Rafaël Carré's avatar
Rafaël Carré committed
202
        unsetMediaPlayer(env, thiz);
203
        setLong(env, thiz, "mInternalMediaPlayerInstance", 0);
204
205
206
    }
}

207
208
209
210
211
/* 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
 */
JavaVM *myVm;
212

213
static jobject eventManagerInstance = NULL;
214

215
216
static pthread_mutex_t vout_android_lock;
static void *vout_android_surf = NULL;
217
static void *vout_android_gui = NULL;
218

219
void *jni_LockAndGetAndroidSurface() {
220
    pthread_mutex_lock(&vout_android_lock);
Ludovic Fauvet's avatar
Ludovic Fauvet committed
221
    return vout_android_surf;
222
223
}

224
void jni_UnlockAndroidSurface() {
225
226
227
    pthread_mutex_unlock(&vout_android_lock);
}

228
void jni_SetAndroidSurfaceSize(int width, int height, int sar_num, int sar_den)
229
230
231
232
233
234
235
236
{
    if (vout_android_gui == NULL)
        return;

    JNIEnv *p_env;

    (*myVm)->AttachCurrentThread (myVm, &p_env, NULL);
    jclass cls = (*p_env)->GetObjectClass (p_env, vout_android_gui);
237
    jmethodID methodId = (*p_env)->GetMethodID (p_env, cls, "setSurfaceSize", "(IIII)V");
238

239
    (*p_env)->CallVoidMethod (p_env, vout_android_gui, methodId, width, height, sar_num, sar_den);
240
241
242
243
244

    (*p_env)->DeleteLocalRef(p_env, cls);
    (*myVm)->DetachCurrentThread (myVm);
}

245
246
247
static void vlc_event_callback(const libvlc_event_t *ev, void *data)
{
    JNIEnv *env;
248
    JavaVM *myVm = data;
249

250
    bool isAttached = false;
251

252
    if (eventManagerInstance == NULL)
Sébastien Toque's avatar
Sébastien Toque committed
253
        return;
254

255
    int status = (*myVm)->GetEnv(myVm, (void**) &env, JNI_VERSION_1_2);
256
    if (status < 0) {
257
        LOGD("vlc_event_callback: failed to get JNI environment, "
258
259
260
261
             "assuming native thread");
        status = (*myVm)->AttachCurrentThread(myVm, &env, NULL);
        if (status < 0)
            return;
262
        isAttached = true;
263
264
    }

265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
    /* 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" );
    jmethodID putString = (*env)->GetMethodID(env, clsBundle, "putString", "(Ljava/lang/String;Ljava/lang/String;)V" );

    if(ev->type == libvlc_MediaPlayerVout) {
        /* 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);
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
    } 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);
305
306
    }

307
308
309
310
    /* Get the object class */
    jclass cls = (*env)->GetObjectClass(env, eventManagerInstance);
    if (!cls) {
        LOGE("EventManager: failed to get class reference");
311
        goto end;
312
313
314
    }

    /* Find the callback ID */
315
    jmethodID methodID = (*env)->GetMethodID(env, cls, "callback", "(ILandroid/os/Bundle;)V");
316
    if (methodID) {
317
        (*env)->CallVoidMethod(env, eventManagerInstance, methodID, ev->type, bundle);
318
    } else {
319
320
321
        LOGE("EventManager: failed to get the callback method");
    }

322
323
324
end:
    if (isAttached)
        (*myVm)->DetachCurrentThread(myVm);
325
326
}

327
jint JNI_OnLoad(JavaVM *vm, void *reserved)
328
{
329
330
331
    // Keep a reference on the Java VM.
    myVm = vm;

332
333
    pthread_mutex_init(&vout_android_lock, NULL);

334
    LOGD("JNI interface loaded.");
335
    return JNI_VERSION_1_2;
336
337
}

338
339
340
341
void JNI_OnUnload(JavaVM* vm, void* reserved) {
    pthread_mutex_destroy(&vout_android_lock);
}

Sébastien Toque's avatar
Sébastien Toque committed
342
void Java_org_videolan_vlc_LibVLC_attachSurface(JNIEnv *env, jobject thiz, jobject surf, jobject gui, jint width, jint height) {
343
344
345
346
347
348
349
    jclass clz;
    jfieldID fid;

    pthread_mutex_lock(&vout_android_lock);
    clz = (*env)->GetObjectClass(env, surf);
    fid = (*env)->GetFieldID(env, clz, "mSurface", "I");
    if (fid == NULL) {
350
        jthrowable exp = (*env)->ExceptionOccurred(env);
351
352
353
354
355
356
357
358
        if (exp) {
            (*env)->DeleteLocalRef(env, exp);
            (*env)->ExceptionClear(env);
        }
        fid = (*env)->GetFieldID(env, clz, "mNativeSurface", "I");
    }
    vout_android_surf = (void*)(*env)->GetIntField(env, surf, fid);
    (*env)->DeleteLocalRef(env, clz);
359
360

    vout_android_gui = (*env)->NewGlobalRef(env, gui);
361
362
363
    pthread_mutex_unlock(&vout_android_lock);
}

Sébastien Toque's avatar
Sébastien Toque committed
364
void Java_org_videolan_vlc_LibVLC_detachSurface(JNIEnv *env, jobject thiz) {
365
366
    pthread_mutex_lock(&vout_android_lock);
    vout_android_surf = NULL;
367
368
369
    if (vout_android_gui != NULL)
        (*env)->DeleteGlobalRef(env, vout_android_gui);
    vout_android_gui = NULL;
370
371
    pthread_mutex_unlock(&vout_android_lock);
}
372

373
374
static void debug_log(void *data, int level, const char *fmt, va_list ap)
{
Rafaël Carré's avatar
Rafaël Carré committed
375
    bool *verbose = data;
376
377
378
379
380
381
382
383
384
385
386
387
388

    static const uint8_t priority[5] = {
        [LIBVLC_DEBUG]   = ANDROID_LOG_DEBUG,
        [1 /* ??? */]    = ANDROID_LOG_DEBUG,
        [LIBVLC_NOTICE]  = ANDROID_LOG_INFO,
        [LIBVLC_WARNING] = ANDROID_LOG_WARN,
        [LIBVLC_ERROR]   = ANDROID_LOG_ERROR,
    };

    int prio = ANDROID_LOG_DEBUG;
    if (level >= LIBVLC_DEBUG && level <= LIBVLC_ERROR)
        prio = priority[level];

Ludovic Fauvet's avatar
Ludovic Fauvet committed
389
    if (!*verbose && prio < ANDROID_LOG_ERROR)
390
391
        return;

392
393
394
395
    __android_log_vprint(prio, "VLC", fmt, ap);
}

static libvlc_log_subscriber_t debug_subscriber;
Rafaël Carré's avatar
Rafaël Carré committed
396
static bool verbosity;
397

398
399
void Java_org_videolan_vlc_LibVLC_changeVerbosity(JNIEnv *env, jobject thiz, jboolean verbose)
{
Rafaël Carré's avatar
Rafaël Carré committed
400
    verbosity = verbose;
401
    libvlc_log_unsubscribe(&debug_subscriber);
Rafaël Carré's avatar
Rafaël Carré committed
402
    libvlc_log_subscribe(&debug_subscriber, debug_log, &verbosity);
403
404
405
}

void Java_org_videolan_vlc_LibVLC_nativeInit(JNIEnv *env, jobject thiz, jboolean verbose)
406
{
407
408
409
410
411
    //only use OpenSLES if java side says we can
    jclass cls = (*env)->GetObjectClass(env, thiz);
    jmethodID methodId = (*env)->GetMethodID(env, cls, "getAout", "()I");
    bool use_opensles = (*env)->CallIntMethod(env, thiz, methodId) == AOUT_OPENSLES;

412
413
414
    methodId = (*env)->GetMethodID(env, cls, "timeStretchingEnabled", "()Z");
    bool enable_time_stretch = (*env)->CallBooleanMethod(env, thiz, methodId);

Rafaël Carré's avatar
Rafaël Carré committed
415
416
    verbosity = verbose;
    libvlc_log_subscribe(&debug_subscriber, debug_log, &verbosity);
417

418
    /* Don't add any invalid options, otherwise it causes LibVLC to crash */
419
    const char *argv[] = {
420
        "-I", "dummy",
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
421
422
423
        "--no-osd",
        "--no-video-title-show",
        "--no-stats",
424
425
        "--no-plugins-cache",
        "--no-drop-late-frames",
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
426
        "--avcodec-fast",
427
        enable_time_stretch ? "--audio-time-stretch" : "--no-audio-time-stretch",
428
        use_opensles ? "--aout=opensles" : "--aout=android_audiotrack",
429
    };
430
    libvlc_instance_t *instance = libvlc_new(sizeof(argv) / sizeof(*argv), argv);
431

Edward Wang's avatar
Edward Wang committed
432
    setLong(env, thiz, "mLibVlcInstance", (jlong) instance);
433

434
435
    if (!instance)
    {
Sébastien Toque's avatar
Sébastien Toque committed
436
        jclass exc = (*env)->FindClass(env, "org/videolan/vlc/LibVlcException");
437
438
439
440
        (*env)->ThrowNew(env, exc, "Unable to instantiate LibVLC");
    }

    LOGI("LibVLC initialized: %p", instance);
441
442
443
444
445
446
447
448
449

    /* Initialize media list (a.k.a. playlist/history) */
    libvlc_media_list_t* pointer = libvlc_media_list_new( instance );
    if(!pointer) {
        jclass exc = (*env)->FindClass(env, "org/videolan/vlc/LibVlcException");
        (*env)->ThrowNew(env, exc, "Unable to create LibVLC media list");
        return;
    }

450
451
452
453
454
455
456
457
458
    /* Connect the event manager */
    libvlc_event_manager_t *ev = libvlc_media_list_event_manager(pointer);
    static const libvlc_event_type_t mp_events[] = {
        libvlc_MediaListItemAdded,
        libvlc_MediaListItemDeleted,
    };
    for(int i = 0; i < (sizeof(mp_events) / sizeof(*mp_events)); i++)
        libvlc_event_attach(ev, mp_events[i], vlc_event_callback, myVm);

459
    setLong(env, thiz, "mMediaListInstance", (jlong)pointer);
460
461
}

462
463
464
465
466
467
jstring Java_org_videolan_vlc_LibVLC_nativeToURI(JNIEnv *env, jobject thiz, jstring path)
{
    jboolean isCopy;
    /* Get C string */
    const char* psz_path = (*env)->GetStringUTFChars(env, path, &isCopy);
    /* Convert the path to URI */
468
469
470
471
472
    char* psz_location;
    if(unlikely( strstr( psz_path, "://" ) ))
        psz_location = strdup(psz_path);
    else
        psz_location = vlc_path2uri(psz_path, "file");
473
474
475
476
477
478
479
    /* Box into jstring */
    jstring t = (*env)->NewStringUTF(env, psz_location);
    /* Clean up */
    (*env)->ReleaseStringUTFChars(env, path, psz_path);
    free(psz_location);
    return t;
}
480

Sébastien Toque's avatar
Sébastien Toque committed
481
void Java_org_videolan_vlc_LibVLC_nativeDestroy(JNIEnv *env, jobject thiz)
482
{
483
    releaseMediaPlayer(env, thiz);
Edward Wang's avatar
Edward Wang committed
484
    jlong libVlcInstance = getLong(env, thiz, "mLibVlcInstance");
485
486
487
488
489
    if (!libVlcInstance)
        return; // Already destroyed

    libvlc_instance_t *instance = (libvlc_instance_t*) libVlcInstance;
    libvlc_release(instance);
490
    libvlc_log_unsubscribe(&debug_subscriber);
491

Edward Wang's avatar
Edward Wang committed
492
    setLong(env, thiz, "mLibVlcInstance", 0);
493
494
}

Sébastien Toque's avatar
Sébastien Toque committed
495
void Java_org_videolan_vlc_LibVLC_detachEventManager(JNIEnv *env, jobject thiz)
496
497
498
499
500
501
502
{
    if (eventManagerInstance != NULL) {
        (*env)->DeleteGlobalRef(env, eventManagerInstance);
        eventManagerInstance = NULL;
    }
}

Sébastien Toque's avatar
Sébastien Toque committed
503
void Java_org_videolan_vlc_LibVLC_setEventManager(JNIEnv *env, jobject thiz, jobject eventManager)
504
{
505
506
507
508
509
    if (eventManagerInstance != NULL) {
        (*env)->DeleteGlobalRef(env, eventManagerInstance);
        eventManagerInstance = NULL;
    }

510
511
512
513
514
515
    jclass cls = (*env)->GetObjectClass(env, eventManager);
    if (!cls) {
        LOGE("setEventManager: failed to get class reference");
        return;
    }

516
    jmethodID methodID = (*env)->GetMethodID(env, cls, "callback", "(ILandroid/os/Bundle;)V");
517
518
519
520
    if (!methodID) {
        LOGE("setEventManager: failed to get the callback method");
        return;
    }
521

522
523
524
    eventManagerInstance = (*env)->NewGlobalRef(env, eventManager);
}

Sébastien Toque's avatar
Sébastien Toque committed
525
jobjectArray Java_org_videolan_vlc_LibVLC_readMediaMeta(JNIEnv *env,
526
                                                        jobject thiz, jlong instance, jstring mrl)
Rafaël Carré's avatar
Rafaël Carré committed
527
528
529
530
531
{
    jobjectArray array = (*env)->NewObjectArray(env, 8,
            (*env)->FindClass(env, "java/lang/String"),
            (*env)->NewStringUTF(env, ""));

532
    libvlc_media_t *m = new_media(instance, env, thiz, mrl, false, false);
533
534
    if (!m)
    {
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
535
        LOGE("readMediaMeta: Could not create the media!");
536
        return array;
537
538
539
    }

    libvlc_media_parse(m);
Rafaël Carré's avatar
Rafaël Carré committed
540

541
    static const char str[][7] = {
Rafaël Carré's avatar
Rafaël Carré committed
542
543
        "artist", "album", "title", "genre",
    };
544
    static const libvlc_meta_t meta_id[] = {
Rafaël Carré's avatar
Rafaël Carré committed
545
546
547
548
549
        libvlc_meta_Artist,
        libvlc_meta_Album,
        libvlc_meta_Title,
        libvlc_meta_Genre,
    };
550
    for (int i=0; i < sizeof(str) / sizeof(*str); i++) {
Rafaël Carré's avatar
Rafaël Carré committed
551
552
        char *meta = libvlc_media_get_meta(m, meta_id[i]);
        if (!meta)
553
            meta = strdup("");
Rafaël Carré's avatar
Rafaël Carré committed
554
555
556
557
558
559
560
561
562
563
564
565
566

        jstring k = (*env)->NewStringUTF(env, str[i]);
        (*env)->SetObjectArrayElement(env, array, 2*i, k);
        jstring v = (*env)->NewStringUTF(env, meta);
        (*env)->SetObjectArrayElement(env, array, 2*i+1, v);

        free(meta);
   }

   libvlc_media_release(m);
   return array;
}

567
568
static void create_player_and_play(JNIEnv* env, jobject thiz,
                                   jlong instance, int position) {
569
570
571
    /* Release previous media player, if any */
    releaseMediaPlayer(env, thiz);

572
573
    libvlc_media_list_t* p_mlist = getMediaList(env, thiz);

574
    /* Create a media player playing environment */
575
    libvlc_media_list_player_t* p_mlp = libvlc_media_list_player_new((libvlc_instance_t*)instance);
576
577
    libvlc_media_player_t *mp = libvlc_media_player_new((libvlc_instance_t*)instance);

578
579
    jobject myJavaLibVLC = (*env)->NewGlobalRef(env, thiz);

580
581
582
583
    //if AOUT_AUDIOTRACK_JAVA, we use amem
    jclass cls = (*env)->GetObjectClass(env, thiz);
    jmethodID methodId = (*env)->GetMethodID(env, cls, "getAout", "()I");
    if ( (*env)->CallIntMethod(env, thiz, methodId) == AOUT_AUDIOTRACK_JAVA )
584
    {
Sébastien Toque's avatar
Sébastien Toque committed
585
586
587
        libvlc_audio_set_callbacks(mp, aout_play, NULL, NULL, NULL, NULL,
                                   (void*) myJavaLibVLC);
        libvlc_audio_set_format_callbacks(mp, aout_open, aout_close);
588
589
    }

590
591
    /* Connect the event manager */
    libvlc_event_manager_t *ev = libvlc_media_player_event_manager(mp);
592
593
594
595
596
    static const libvlc_event_type_t mp_events[] = {
        libvlc_MediaPlayerPlaying,
        libvlc_MediaPlayerPaused,
        libvlc_MediaPlayerEndReached,
        libvlc_MediaPlayerStopped,
597
        libvlc_MediaPlayerVout,
598
    };
599
    for(int i = 0; i < (sizeof(mp_events) / sizeof(*mp_events)); i++)
600
601
        libvlc_event_attach(ev, mp_events[i], vlc_event_callback, myVm);

602
603
604
    libvlc_media_list_player_set_media_list(p_mlp, p_mlist);
    libvlc_media_list_player_set_media_player(p_mlp, mp);

605
    /* Keep a pointer to this media player */
606
607
    setLong(env, thiz, "mMediaListPlayerInstance", (jlong)p_mlp);
    setLong(env, thiz, "mInternalMediaPlayerInstance", (jlong)mp);
608

609
    libvlc_media_list_player_play_item_at_index(p_mlp, position);
610
611
}

612
jint Java_org_videolan_vlc_LibVLC_readMedia(JNIEnv *env, jobject thiz,
613
614
615
616
617
618
619
620
621
622
623
624
625
                                            jlong instance, jstring mrl, jboolean novideo)
{
    /* Create a new item */
    libvlc_media_t *m = new_media(instance, env, thiz, mrl, false, novideo);
    if (!m)
    {
        LOGE("readMedia: Could not create the media!");
        return;
    }

    libvlc_media_list_t* p_mlist = getMediaList(env, thiz);

    libvlc_media_list_lock(p_mlist);
626
627
628
629
630
631
    if(libvlc_media_list_add_media(p_mlist, m) != 0) {
        LOGE("readMedia: Could not add to the media list!");
        libvlc_media_list_unlock(p_mlist);
        libvlc_media_release(m);
        return;
    }
632
633
634
635
636
637
638
    int position = libvlc_media_list_index_of_item(p_mlist, m);
    libvlc_media_list_unlock(p_mlist);

    /* No need to keep the media now */
    libvlc_media_release(m);

    create_player_and_play(env, thiz, instance, position);
639
640

    return position;
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
}

void Java_org_videolan_vlc_LibVLC_playIndex(JNIEnv *env, jobject thiz,
                                            jlong instance, int position) {
    create_player_and_play(env, thiz, instance, position);
}

void Java_org_videolan_vlc_LibVLC_getMediaListItems(
                JNIEnv *env, jobject thiz, jobject arrayList) {
    jclass arrayClass = (*env)->FindClass(env, "java/util/ArrayList");
    jmethodID methodID = (*env)->GetMethodID(env, arrayClass, "add", "(Ljava/lang/Object;)Z");
    jstring str;

    libvlc_media_list_t* p_mlist = getMediaList(env, thiz);
    libvlc_media_list_lock( p_mlist );
    for(int i = 0; i < libvlc_media_list_count( p_mlist ); i++) {
        char* mrl = libvlc_media_get_mrl( libvlc_media_list_item_at_index( p_mlist, i ) );
        str = (*env)->NewStringUTF(env, mrl);
        (*env)->CallBooleanMethod(env, arrayList, methodID, str);
        (*env)->DeleteLocalRef(env, str);
        free(mrl);
    }
    libvlc_media_list_unlock( p_mlist );
}

Edward Wang's avatar
Edward Wang committed
666
667
668
669
670
671
672
673
674
675
676
677
678
679
jfloat Java_org_videolan_vlc_LibVLC_getRate(JNIEnv *env, jobject thiz) {
    libvlc_media_player_t* mp = getMediaPlayer(env, thiz);
    if(mp)
        return libvlc_media_player_get_rate(mp);
    else
        return 1.00;
}

void Java_org_videolan_vlc_LibVLC_setRate(JNIEnv *env, jobject thiz, jfloat rate) {
    libvlc_media_player_t* mp = getMediaPlayer(env, thiz);
    if(mp)
        libvlc_media_player_set_rate(mp, rate);
}

Sébastien Toque's avatar
Sébastien Toque committed
680
jboolean Java_org_videolan_vlc_LibVLC_hasVideoTrack(JNIEnv *env, jobject thiz,
Edward Wang's avatar
Edward Wang committed
681
                                                    jlong i_instance, jstring fileLocation)
682
{
683
    /* Create a new item and assign it to the media player. */
684
    libvlc_media_t *p_m = new_media(i_instance, env, thiz, fileLocation, false, false);
685
686
    if (p_m == NULL)
    {
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
687
        LOGE("Could not create the media!");
Rafaël Carré's avatar
Rafaël Carré committed
688
        return JNI_FALSE;
689
690
691
692
693
    }

    /* Get the tracks information of the media. */
    libvlc_media_track_info_t *p_tracks;
    libvlc_media_parse(p_m);
694

695
696
697
698
699
700
701
702
703
704
    libvlc_media_player_t* p_mp = libvlc_media_player_new_from_media(p_m);

    struct length_change_monitor* monitor;
    monitor = malloc(sizeof(struct length_change_monitor));
    if (!monitor) return 0;

    /* Initialize pthread variables. */
    pthread_mutex_init(&monitor->doneMutex, NULL);
    pthread_cond_init(&monitor->doneCondVar, NULL);
    monitor->length_changed = false;
Rafaël Carré's avatar
Rafaël Carré committed
705

706
707
708
709
710
    libvlc_event_manager_t *ev = libvlc_media_player_event_manager(p_mp);
    libvlc_event_attach(ev, libvlc_MediaPlayerLengthChanged, length_changed_callback, monitor);
    libvlc_media_player_play( p_mp );

    pthread_mutex_lock(&monitor->doneMutex);
711
712
713
714
715
716
717
718
719

    struct timespec deadline;
    clock_gettime(CLOCK_REALTIME, &deadline);
    deadline.tv_sec += 2; /* If "VLC can't open the file", return */
    int mp_alive = 1;
    while( !monitor->length_changed && mp_alive ) {
        pthread_cond_timedwait(&monitor->doneCondVar, &monitor->doneMutex, &deadline);
        mp_alive = libvlc_media_player_will_play(p_mp);
    }
720
721
    pthread_mutex_unlock(&monitor->doneMutex);

722
723
724
725
726
    int i_nbTracks;
    if( mp_alive )
        i_nbTracks = libvlc_video_get_track_count(p_mp);
    else
        i_nbTracks = -1;
727
728
    LOGI("Number of video tracks: %d",i_nbTracks);

Edward Wang's avatar
Edward Wang committed
729
    libvlc_event_detach(ev, libvlc_MediaPlayerLengthChanged, length_changed_callback, monitor);
730
731
    libvlc_media_player_stop(p_mp);
    libvlc_media_player_release(p_mp);
Rafaël Carré's avatar
Rafaël Carré committed
732
733
    libvlc_media_release(p_m);

Edward Wang's avatar
Edward Wang committed
734
735
736
737
    pthread_mutex_destroy(&monitor->doneMutex);
    pthread_cond_destroy(&monitor->doneCondVar);
    free(monitor);

738
739
    if(i_nbTracks > 0)
        return JNI_TRUE;
740
741
    else if(i_nbTracks < 0)
        (*env)->ThrowNew(env, (*env)->FindClass(env, "java/io/IOException"), "VLC can't open the file");
742
743
    else
        return JNI_FALSE;
744
745
}

746
jobjectArray read_track_info_internal(JNIEnv *env, jobject thiz, libvlc_media_t* p_m)
747
748
749
750
751
{
    /* get java class */
    jclass cls = (*env)->FindClass( env, "org/videolan/vlc/TrackInfo" );
    if ( !cls )
    {
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
752
        LOGE("Failed to load class (org/videolan/vlc/TrackInfo)" );
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
        return NULL;
    }

    /* get java class contructor */
    jmethodID clsCtor = (*env)->GetMethodID( env, cls, "<init>", "()V" );
    if ( !clsCtor )
    {
        LOGE("Failed to find class constructor (org/videolan/vlc/TrackInfo)" );
        return NULL;
    }

    /* Get the tracks information of the media. */
    libvlc_media_track_info_t *p_tracks;

    int i_nbTracks = libvlc_media_get_tracks_info(p_m, &p_tracks);
768
    jobjectArray array = (*env)->NewObjectArray(env, i_nbTracks + 1, cls, NULL);
769
770
771
772

    unsigned i;
    if (array != NULL)
    {
773
        for (i = 0; i <= i_nbTracks; ++i)
774
775
776
777
778
        {
            jobject item = (*env)->NewObject(env, cls, clsCtor);
            if (item == NULL)
                continue;
            (*env)->SetObjectArrayElement(env, array, i, item);
779
780
781
782
783
784
785
786
787
788

            // use last track for metadata
            if (i == i_nbTracks)
            {
                setInt(env, item, "Type", 3 /* TYPE_META */);
                setLong(env, item, "Length", libvlc_media_get_duration(p_m));
                setString(env, item, "Title", libvlc_media_get_meta(p_m, libvlc_meta_Title));
                setString(env, item, "Artist", libvlc_media_get_meta(p_m, libvlc_meta_Artist));
                setString(env, item, "Album", libvlc_media_get_meta(p_m, libvlc_meta_Album));
                setString(env, item, "Genre", libvlc_media_get_meta(p_m, libvlc_meta_Genre));
789
                setString(env, item, "ArtworkURL", libvlc_media_get_meta(p_m, libvlc_meta_ArtworkURL));
790
791
792
                continue;
            }

793
794
795
            setInt(env, item, "Id", p_tracks[i].i_id);
            setInt(env, item, "Type", p_tracks[i].i_type);
            setString(env, item, "Codec", (const char*)vlc_fourcc_GetDescription(0,p_tracks[i].i_codec));
796
            setString(env, item, "Language", p_tracks[i].psz_language);
797
798
799
800
801

            if (p_tracks[i].i_type == libvlc_track_video)
            {
                setInt(env, item, "Height", p_tracks[i].u.video.i_height);
                setInt(env, item, "Width", p_tracks[i].u.video.i_width);
802
                setFloat(env, item, "Framerate", p_tracks[i].u.video.f_frame_rate);
803
804
805
806
807
808
809
810
811
            }
            if (p_tracks[i].i_type == libvlc_track_audio)
            {
                setInt(env, item, "Channels", p_tracks[i].u.audio.i_channels);
                setInt(env, item, "Samplerate", p_tracks[i].u.audio.i_rate);
            }
        }
    }

812
    libvlc_media_tracks_info_release(p_tracks, i_nbTracks);
813
814
815
    return array;
}

816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846

jobjectArray Java_org_videolan_vlc_LibVLC_readTracksInfo(JNIEnv *env, jobject thiz,
                                                         jlong instance, jstring mrl)
{
    /* Create a new item and assign it to the media player. */
    libvlc_media_t *p_m = new_media(instance, env, thiz, mrl, false, false);
    if (p_m == NULL)
    {
        LOGE("Could not create the media!");
        return NULL;
    }

    libvlc_media_parse(p_m);
    jobjectArray jar = read_track_info_internal(env, thiz, p_m);
    libvlc_media_release(p_m);
    return jar;
}


jobjectArray Java_org_videolan_vlc_LibVLC_readTracksInfoPosition(JNIEnv *env, jobject thiz,
                                                         jint position)
{
    libvlc_media_list_t* p_mlist = getMediaList(env, thiz);
    libvlc_media_t *p_m = libvlc_media_list_item_at_index( p_mlist, position );
    if (p_m == NULL) {
        LOGE("Could not load get media @ position %d!", position);
        return NULL;
    } else
        return read_track_info_internal(env, thiz, p_m);
}

847
jlong Java_org_videolan_vlc_LibVLC_getLengthFromLocation(JNIEnv *env, jobject thiz,
Edward Wang's avatar
Edward Wang committed
848
                                                     jlong i_instance, jstring fileLocation)
849
{
850
851
852
853
854
    jlong length = 0;
    struct length_change_monitor *monitor;
    monitor = malloc(sizeof(*monitor));
    if (!monitor)
        return 0;
855
856

    /* Initialize pthread variables. */
857
858
859
    pthread_mutex_init(&monitor->doneMutex, NULL);
    pthread_cond_init(&monitor->doneCondVar, NULL);
    monitor->length_changed = false;
860

861
    /* Create a new item and assign it to the media player. */
862
    libvlc_media_t *m = new_media(i_instance, env, thiz, fileLocation, false, false);
863
    if (m == NULL)
864
    {
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
865
        LOGE("Could not create the media to play!");
866
        goto end;
867
868
    }

869
    /* Create a media player playing environment */
870
    libvlc_media_player_t *mp = libvlc_media_player_new_from_media (m);
871
    libvlc_event_manager_t *ev = libvlc_media_player_event_manager(mp);
872
    libvlc_event_attach(ev, libvlc_MediaPlayerLengthChanged, length_changed_callback, monitor);
873
874
    libvlc_media_release (m);
    libvlc_media_player_play( mp );
875
876
877
878
879
880
881

    pthread_mutex_lock(&monitor->doneMutex);
    while (!monitor->length_changed)
        pthread_cond_wait(&monitor->doneCondVar, &monitor->doneMutex);
    pthread_mutex_unlock(&monitor->doneMutex);

    length = libvlc_media_player_get_length( mp );
882
    libvlc_media_player_stop( mp );
883
    libvlc_media_player_release( mp );
884

885
886
887
888
end:
    pthread_mutex_destroy(&monitor->doneMutex);
    pthread_cond_destroy(&monitor->doneCondVar);
    free(monitor);
889
890

    return length;
891
892
}

Sébastien Toque's avatar
Sébastien Toque committed
893
jboolean Java_org_videolan_vlc_LibVLC_hasMediaPlayer(JNIEnv *env, jobject thiz)
894
{
895
    return !!getMediaListPlayer(env, thiz);
896
897
}

Sébastien Toque's avatar
Sébastien Toque committed
898
jboolean Java_org_videolan_vlc_LibVLC_isPlaying(JNIEnv *env, jobject thiz)
899
{
900
    libvlc_media_list_player_t *mp = getMediaListPlayer(env, thiz);
901
    if (mp)
902
903
904
        return !!libvlc_media_list_player_is_playing(mp);
    else
        return 0;
905
906
}

Sébastien Toque's avatar
Sébastien Toque committed
907
jboolean Java_org_videolan_vlc_LibVLC_isSeekable(JNIEnv *env, jobject thiz)
908
{
909
910
911
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return !!libvlc_media_player_is_seekable(mp);
912
    return 0;
913
914
}

Sébastien Toque's avatar
Sébastien Toque committed
915
void Java_org_videolan_vlc_LibVLC_play(JNIEnv *env, jobject thiz)
916
{
917
    libvlc_media_list_player_t *mp = getMediaListPlayer(env, thiz);
918
    if (mp)
919
        libvlc_media_list_player_play(mp);
920
921
}

Sébastien Toque's avatar
Sébastien Toque committed
922
void Java_org_videolan_vlc_LibVLC_pause(JNIEnv *env, jobject thiz)
923
{
924
    libvlc_media_list_player_t *mp = getMediaListPlayer(env, thiz);
925
    if (mp)
926
        libvlc_media_list_player_pause(mp);
927
928
}

Sébastien Toque's avatar
Sébastien Toque committed
929
void Java_org_videolan_vlc_LibVLC_stop(JNIEnv *env, jobject thiz)
930
{
931
    libvlc_media_list_player_t *mp = getMediaListPlayer(env, thiz);
932
    if (mp)
933
        libvlc_media_list_player_stop(mp);
934
935
}

Edward Wang's avatar
Edward Wang committed
936
937
938
939
940
941
942
943
944
945
946
947
948
949
void Java_org_videolan_vlc_LibVLC_previous(JNIEnv *env, jobject thiz)
{
    libvlc_media_list_player_t *mp = getMediaListPlayer(env, thiz);
    if (mp)
        libvlc_media_list_player_previous(mp);
}

void Java_org_videolan_vlc_LibVLC_next(JNIEnv *env, jobject thiz)
{
    libvlc_media_list_player_t *mp = getMediaListPlayer(env, thiz);
    if (mp)
        libvlc_media_list_player_next(mp);
}

Sébastien Toque's avatar
Sébastien Toque committed
950
jint Java_org_videolan_vlc_LibVLC_getVolume(JNIEnv *env, jobject thiz)
951
{
952
953
954
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return (jint) libvlc_audio_get_volume(mp);
955
956
957
    return -1;
}

Sébastien Toque's avatar
Sébastien Toque committed
958
jint Java_org_videolan_vlc_LibVLC_setVolume(JNIEnv *env, jobject thiz, jint volume)
959
{
960
961
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
962
        //Returns 0 if the volume was set, -1 if it was out of range or error
963
        return (jint) libvlc_audio_set_volume(mp, (int) volume);
964
965
966
    return -1;
}

Sébastien Toque's avatar
Sébastien Toque committed
967
jlong Java_org_videolan_vlc_LibVLC_getTime(JNIEnv *env, jobject thiz)
968
{
969
970
971
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return libvlc_media_player_get_time(mp);
972
973
974
    return -1;
}

Sébastien Toque's avatar
Sébastien Toque committed
975
void Java_org_videolan_vlc_LibVLC_setTime(JNIEnv *env, jobject thiz, jlong time)
976
{
977
978
979
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        libvlc_media_player_set_time(mp, time);
980
981
}

Sébastien Toque's avatar
Sébastien Toque committed
982
jfloat Java_org_videolan_vlc_LibVLC_getPosition(JNIEnv *env, jobject thiz)
983
{
984
985
986
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return (jfloat) libvlc_media_player_get_position(mp);
987
988
989
    return -1;
}

Sébastien Toque's avatar
Sébastien Toque committed
990
void Java_org_videolan_vlc_LibVLC_setPosition(JNIEnv *env, jobject thiz, jfloat pos)
991
{
992
993
994
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        libvlc_media_player_set_position(mp, pos);
995
996
}

Sébastien Toque's avatar
Sébastien Toque committed
997
jlong Java_org_videolan_vlc_LibVLC_getLength(JNIEnv *env, jobject thiz)
998
{
999
1000
1001
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return (jlong) libvlc_media_player_get_length(mp);
1002
1003
1004
    return -1;
}

Sébastien Toque's avatar
Sébastien Toque committed
1005
jstring Java_org_videolan_vlc_LibVLC_version(JNIEnv* env, jobject thiz)
1006
{
1007
1008
    return (*env)->NewStringUTF(env, libvlc_get_version());
}
1009

Sébastien Toque's avatar
Sébastien Toque committed
1010
jstring Java_org_videolan_vlc_LibVLC_compiler(JNIEnv* env, jobject thiz)
1011
1012
1013
1014
{
    return (*env)->NewStringUTF(env, libvlc_get_compiler());
}

Sébastien Toque's avatar
Sébastien Toque committed
1015
jstring Java_org_videolan_vlc_LibVLC_changeset(JNIEnv* env, jobject thiz)
1016
1017
1018
{
    return (*env)->NewStringUTF(env, libvlc_get_changeset());
}
1019

Sébastien Toque's avatar
Sébastien Toque committed
1020
jint Java_org_videolan_vlc_LibVLC_getAudioTracksCount(JNIEnv *env, jobject thiz)
1021
1022
1023
1024
1025
1026
1027
{
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return (jint) libvlc_audio_get_track_count(mp);
    return -1;
}

1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
jobjectArray Java_org_videolan_vlc_LibVLC_getAudioTrackDescription(JNIEnv *env, jobject thiz)
{
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (!mp)
        return NULL;

    int i_nbTracks = libvlc_audio_get_track_count(mp) - 1;
    if (i_nbTracks < 0)
        i_nbTracks = 0;
    jobjectArray array = (*env)->NewObjectArray(env, i_nbTracks,
            (*env)->FindClass(env, "java/lang/String"),
            NULL);

    libvlc_track_description_t *first = libvlc_audio_get_track_description(mp);
    libvlc_track_description_t *desc = first != NULL ? first->p_next : NULL;
    unsigned i;
    for (i = 0; i < i_nbTracks; ++i)
    {
        jstring name = (*env)->NewStringUTF(env, desc->psz_name);
        (*env)->SetObjectArrayElement(env, array, i, name);
        desc = desc->p_next;
    }
    libvlc_track_description_list_release(first);
    return array;
}

jint Java_org_videolan_vlc_LibVLC_getAudioTrack(JNIEnv *env, jobject thiz)
{
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return libvlc_audio_get_track(mp);
    return -1;
}

jint Java_org_videolan_vlc_LibVLC_setAudioTrack(JNIEnv *env, jobject thiz, jint index)
{
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return libvlc_audio_set_track(mp, index);
    return -1;
}

Sébastien Toque's avatar
Sébastien Toque committed
1070
jint Java_org_videolan_vlc_LibVLC_getVideoTracksCount(JNIEnv *env, jobject thiz)
1071
1072
1073
1074
1075
1076
1077
{
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return (jint) libvlc_video_get_track_count(mp);
    return -1;
}

Sébastien Toque's avatar
Sébastien Toque committed
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
jobjectArray Java_org_videolan_vlc_LibVLC_getSpuTrackDescription(JNIEnv *env, jobject thiz)
{
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (!mp)
        return NULL;

    int i_nbTracks = libvlc_video_get_spu_count(mp);
    jobjectArray array = (*env)->NewObjectArray(env, i_nbTracks,
            (*env)->FindClass(env, "java/lang/String"),
            NULL);

    libvlc_track_description_t *first = libvlc_video_get_spu_description(mp);
    libvlc_track_description_t *desc = first;
    unsigned i;
    for (i = 0; i < i_nbTracks; ++i)
    {
        jstring name = (*env)->NewStringUTF(env, desc->psz_name);
        (*env)->SetObjectArrayElement(env, array, i, name);
        desc = desc->p_next;
    }
    libvlc_track_description_list_release(first);
    return array;
}

Sébastien Toque's avatar
Sébastien Toque committed
1102
jint Java_org_videolan_vlc_LibVLC_getSpuTracksCount(JNIEnv *env, jobject thiz)
1103
1104
1105
1106
1107
1108
1109
{
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return (jint) libvlc_video_get_spu_count(mp);
    return -1;
}

Sébastien Toque's avatar
Sébastien Toque committed
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
jint Java_org_videolan_vlc_LibVLC_getSpuTrack(JNIEnv *env, jobject thiz)
{
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return libvlc_video_get_spu(mp);
    return -1;
}

jint Java_org_videolan_vlc_LibVLC_setSpuTrack(JNIEnv *env, jobject thiz, jint index)
{
    libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
    if (mp)
        return libvlc_video_set_spu(mp, index);
    return -1;
}
1125

1126
void Java_org_videolan_vlc_LibVLC_nativeReadDirectory(JNIEnv *env, jobject thiz, jstring path, jobject arrayList)
1127
1128
1129
1130
1131
1132
{
    jboolean isCopy;
    /* Get C string */
    const char* psz_path = (*env)->GetStringUTFChars(env, path, &isCopy);

    DIR* p_dir = opendir(psz_path);
1133
    (*env)->ReleaseStringUTFChars(env, path, psz_path);
1134
    if(!p_dir)
1135
1136
1137
1138
        return;

    jclass arrayClass = (*env)->FindClass(env, "java/util/ArrayList");
    jmethodID methodID = (*env)->GetMethodID(env, arrayClass, "add", "(Ljava/lang/Object;)Z");
1139
1140

    struct dirent* p_dirent;
1141
    jstring str;