libvlcjni.c 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183
  1. /*****************************************************************************
  2. * libvlcjni.c
  3. *****************************************************************************
  4. * Copyright © 2010-2012 VLC authors and VideoLAN
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  19. *****************************************************************************/
  20. #include <dirent.h>
  21. #include <errno.h>
  22. #include <string.h>
  23. #include <pthread.h>
  24. #include <sys/stat.h>
  25. #include <sys/types.h>
  26. #include <unistd.h>
  27. #include <vlc/vlc.h>
  28. #include <vlc_common.h>
  29. #include <vlc_url.h>
  30. #include <vlc_fourcc.h>
  31. #include <jni.h>
  32. #include <android/api-level.h>
  33. #include "libvlcjni.h"
  34. #include "aout.h"
  35. #include "utils.h"
  36. #define LOG_TAG "VLC/JNI/main"
  37. #include "log.h"
  38. #define AOUT_AUDIOTRACK_JAVA 0
  39. #define AOUT_AUDIOTRACK 1
  40. #define AOUT_OPENSLES 2
  41. static jint getInt(JNIEnv *env, jobject thiz, const char* field) {
  42. jclass clazz = (*env)->GetObjectClass(env, thiz);
  43. jfieldID fieldMP = (*env)->GetFieldID(env, clazz,
  44. field, "I");
  45. return (*env)->GetIntField(env, thiz, fieldMP);
  46. }
  47. static void setInt(JNIEnv *env, jobject item, const char* field, jint value) {
  48. jclass cls;
  49. jfieldID fieldId;
  50. /* Get a reference to item's class */
  51. cls = (*env)->GetObjectClass(env, item);
  52. /* Look for the instance field s in cls */
  53. fieldId = (*env)->GetFieldID(env, cls, field, "I");
  54. if (fieldId == NULL)
  55. return;
  56. (*env)->SetIntField(env, item, fieldId, value);
  57. }
  58. static jlong getLong(JNIEnv *env, jobject thiz, const char* field) {
  59. jclass clazz = (*env)->GetObjectClass(env, thiz);
  60. jfieldID fieldMP = (*env)->GetFieldID(env, clazz,
  61. field, "J");
  62. return (*env)->GetLongField(env, thiz, fieldMP);
  63. }
  64. static void setLong(JNIEnv *env, jobject item, const char* field, jlong value) {
  65. jclass cls;
  66. jfieldID fieldId;
  67. /* Get a reference to item's class */
  68. cls = (*env)->GetObjectClass(env, item);
  69. /* Look for the instance field s in cls */
  70. fieldId = (*env)->GetFieldID(env, cls, field, "J");
  71. if (fieldId == NULL)
  72. return;
  73. (*env)->SetLongField(env, item, fieldId, value);
  74. }
  75. static void setFloat(JNIEnv *env, jobject item, const char* field, jfloat value) {
  76. jclass cls;
  77. jfieldID fieldId;
  78. /* Get a reference to item's class */
  79. cls = (*env)->GetObjectClass(env, item);
  80. /* Look for the instance field s in cls */
  81. fieldId = (*env)->GetFieldID(env, cls, field, "F");
  82. if (fieldId == NULL)
  83. return;
  84. (*env)->SetFloatField(env, item, fieldId, value);
  85. }
  86. static void setString(JNIEnv *env, jobject item, const char* field, const char* text) {
  87. jclass cls;
  88. jfieldID fieldId;
  89. jstring jstr;
  90. /* Get a reference to item's class */
  91. cls = (*env)->GetObjectClass(env, item);
  92. /* Look for the instance field s in cls */
  93. fieldId = (*env)->GetFieldID(env, cls, field, "Ljava/lang/String;");
  94. if (fieldId == NULL)
  95. return;
  96. /* Create a new string and overwrite the instance field */
  97. jstr = (*env)->NewStringUTF(env, text);
  98. if (jstr == NULL)
  99. return;
  100. (*env)->SetObjectField(env, item, fieldId, jstr);
  101. }
  102. struct length_change_monitor {
  103. pthread_mutex_t doneMutex;
  104. pthread_cond_t doneCondVar;
  105. bool length_changed;
  106. };
  107. static void length_changed_callback(const libvlc_event_t *ev, void *data)
  108. {
  109. struct length_change_monitor *monitor = data;
  110. pthread_mutex_lock(&monitor->doneMutex);
  111. monitor->length_changed = true;
  112. pthread_cond_signal(&monitor->doneCondVar);
  113. pthread_mutex_unlock(&monitor->doneMutex);
  114. }
  115. libvlc_media_t *new_media(jlong instance, JNIEnv *env, jobject thiz, jstring fileLocation, bool noOmx, bool noVideo)
  116. {
  117. libvlc_instance_t *libvlc = (libvlc_instance_t*)(intptr_t)instance;
  118. jboolean isCopy;
  119. const char *psz_location = (*env)->GetStringUTFChars(env, fileLocation, &isCopy);
  120. libvlc_media_t *p_md = libvlc_media_new_location(libvlc, psz_location);
  121. (*env)->ReleaseStringUTFChars(env, fileLocation, psz_location);
  122. if (!p_md)
  123. return NULL;
  124. if (!noOmx) {
  125. jclass cls = (*env)->GetObjectClass(env, thiz);
  126. jmethodID methodId = (*env)->GetMethodID(env, cls, "useIOMX", "()Z");
  127. if ((*env)->CallBooleanMethod(env, thiz, methodId)) {
  128. /*
  129. * Set higher caching values if using iomx decoding, since some omx
  130. * decoders have a very high latency, and if the preroll data isn't
  131. * enough to make the decoder output a frame, the playback timing gets
  132. * started too soon, and every decoded frame appears to be too late.
  133. * On Nexus One, the decoder latency seems to be 25 input packets
  134. * for 320x170 H.264, a few packets less on higher resolutions.
  135. * On Nexus S, the decoder latency seems to be about 7 packets.
  136. */
  137. libvlc_media_add_option(p_md, ":file-caching=1500");
  138. libvlc_media_add_option(p_md, ":network-caching=1500");
  139. libvlc_media_add_option(p_md, ":codec=mediacodec,iomx,all");
  140. }
  141. if (noVideo)
  142. libvlc_media_add_option(p_md, ":no-video");
  143. }
  144. return p_md;
  145. }
  146. static libvlc_media_list_t *getMediaList(JNIEnv *env, jobject thiz)
  147. {
  148. return (libvlc_media_list_t*)(intptr_t)getLong(env, thiz, "mMediaListInstance");
  149. }
  150. static libvlc_media_player_t *getMediaPlayer(JNIEnv *env, jobject thiz)
  151. {
  152. return (libvlc_media_player_t*)(intptr_t)getLong(env, thiz, "mInternalMediaPlayerInstance");
  153. }
  154. static libvlc_media_list_player_t *getMediaListPlayer(JNIEnv *env, jobject thiz)
  155. {
  156. return (libvlc_media_list_player_t*)(intptr_t)getLong(env, thiz, "mMediaListPlayerInstance");
  157. }
  158. static void releaseMediaPlayer(JNIEnv *env, jobject thiz)
  159. {
  160. libvlc_media_list_player_t* p_mlp = getMediaListPlayer(env, thiz);
  161. if (p_mlp)
  162. {
  163. libvlc_media_list_player_stop(p_mlp);
  164. libvlc_media_list_player_release(p_mlp);
  165. /* libvlc_media_list_player_release frees the media player, so
  166. * we don't free it ourselves. */
  167. setLong(env, thiz, "mInternalMediaPlayerInstance", 0);
  168. setLong(env, thiz, "mMediaListPlayerInstance", 0);
  169. }
  170. }
  171. /* Pointer to the Java virtual machine
  172. * Note: It's okay to use a static variable for the VM pointer since there
  173. * can only be one instance of this shared library in a single VM
  174. */
  175. JavaVM *myVm;
  176. static jobject eventManagerInstance = NULL;
  177. static pthread_mutex_t vout_android_lock;
  178. static void *vout_android_surf = NULL;
  179. static void *vout_android_gui = NULL;
  180. void *jni_LockAndGetAndroidSurface() {
  181. pthread_mutex_lock(&vout_android_lock);
  182. return vout_android_surf;
  183. }
  184. void jni_UnlockAndroidSurface() {
  185. pthread_mutex_unlock(&vout_android_lock);
  186. }
  187. void jni_SetAndroidSurfaceSize(int width, int height, int sar_num, int sar_den)
  188. {
  189. if (vout_android_gui == NULL)
  190. return;
  191. JNIEnv *p_env;
  192. (*myVm)->AttachCurrentThread (myVm, &p_env, NULL);
  193. jclass cls = (*p_env)->GetObjectClass (p_env, vout_android_gui);
  194. jmethodID methodId = (*p_env)->GetMethodID (p_env, cls, "setSurfaceSize", "(IIII)V");
  195. (*p_env)->CallVoidMethod (p_env, vout_android_gui, methodId, width, height, sar_num, sar_den);
  196. (*p_env)->DeleteLocalRef(p_env, cls);
  197. (*myVm)->DetachCurrentThread (myVm);
  198. }
  199. static void vlc_event_callback(const libvlc_event_t *ev, void *data)
  200. {
  201. JNIEnv *env;
  202. JavaVM *myVm = data;
  203. bool isAttached = false;
  204. if (eventManagerInstance == NULL)
  205. return;
  206. int status = (*myVm)->GetEnv(myVm, (void**) &env, JNI_VERSION_1_2);
  207. if (status < 0) {
  208. LOGD("vlc_event_callback: failed to get JNI environment, "
  209. "assuming native thread");
  210. status = (*myVm)->AttachCurrentThread(myVm, &env, NULL);
  211. if (status < 0)
  212. return;
  213. isAttached = true;
  214. }
  215. /* Creating the bundle in C allows us to subscribe to more events
  216. * and get better flexibility for each event. For example, we can
  217. * have totally different types of data for each event, instead of,
  218. * for example, only an integer and/or string.
  219. */
  220. jclass clsBundle = (*env)->FindClass(env, "android/os/Bundle");
  221. jmethodID clsCtor = (*env)->GetMethodID(env, clsBundle, "<init>", "()V" );
  222. jobject bundle = (*env)->NewObject(env, clsBundle, clsCtor);
  223. jmethodID putInt = (*env)->GetMethodID(env, clsBundle, "putInt", "(Ljava/lang/String;I)V" );
  224. jmethodID putString = (*env)->GetMethodID(env, clsBundle, "putString", "(Ljava/lang/String;Ljava/lang/String;)V" );
  225. if(ev->type == libvlc_MediaPlayerVout) {
  226. /* For determining the vout/ES track change */
  227. jstring sData = (*env)->NewStringUTF(env, "data");
  228. (*env)->CallVoidMethod(env, bundle, putInt, sData, ev->u.media_player_vout.new_count);
  229. (*env)->DeleteLocalRef(env, sData);
  230. } else if(ev->type == libvlc_MediaListItemAdded ||
  231. ev->type == libvlc_MediaListItemDeleted ) {
  232. jstring item_uri = (*env)->NewStringUTF(env, "item_uri");
  233. jstring item_index = (*env)->NewStringUTF(env, "item_index");
  234. char* mrl = libvlc_media_get_mrl(
  235. ev->type == libvlc_MediaListItemAdded ?
  236. ev->u.media_list_item_added.item :
  237. ev->u.media_list_item_deleted.item
  238. );
  239. jstring item_uri_value = (*env)->NewStringUTF(env, mrl);
  240. jint item_index_value;
  241. if(ev->type == libvlc_MediaListItemAdded)
  242. item_index_value = ev->u.media_list_item_added.index;
  243. else
  244. item_index_value = ev->u.media_list_item_deleted.index;
  245. (*env)->CallVoidMethod(env, bundle, putString, item_uri, item_uri_value);
  246. (*env)->CallVoidMethod(env, bundle, putInt, item_index, item_index_value);
  247. (*env)->DeleteLocalRef(env, item_uri);
  248. (*env)->DeleteLocalRef(env, item_uri_value);
  249. (*env)->DeleteLocalRef(env, item_index);
  250. free(mrl);
  251. }
  252. /* Get the object class */
  253. jclass cls = (*env)->GetObjectClass(env, eventManagerInstance);
  254. if (!cls) {
  255. LOGE("EventManager: failed to get class reference");
  256. goto end;
  257. }
  258. /* Find the callback ID */
  259. jmethodID methodID = (*env)->GetMethodID(env, cls, "callback", "(ILandroid/os/Bundle;)V");
  260. if (methodID) {
  261. (*env)->CallVoidMethod(env, eventManagerInstance, methodID, ev->type, bundle);
  262. } else {
  263. LOGE("EventManager: failed to get the callback method");
  264. }
  265. end:
  266. if (isAttached)
  267. (*myVm)->DetachCurrentThread(myVm);
  268. }
  269. jint JNI_OnLoad(JavaVM *vm, void *reserved)
  270. {
  271. // Keep a reference on the Java VM.
  272. myVm = vm;
  273. pthread_mutex_init(&vout_android_lock, NULL);
  274. LOGD("JNI interface loaded.");
  275. return JNI_VERSION_1_2;
  276. }
  277. void JNI_OnUnload(JavaVM* vm, void* reserved) {
  278. pthread_mutex_destroy(&vout_android_lock);
  279. }
  280. void Java_org_videolan_vlc_LibVLC_attachSurface(JNIEnv *env, jobject thiz, jobject surf, jobject gui, jint width, jint height) {
  281. jclass clz;
  282. jfieldID fid;
  283. pthread_mutex_lock(&vout_android_lock);
  284. clz = (*env)->GetObjectClass(env, surf);
  285. fid = (*env)->GetFieldID(env, clz, "mSurface", "I");
  286. if (fid == NULL) {
  287. jthrowable exp = (*env)->ExceptionOccurred(env);
  288. if (exp) {
  289. (*env)->DeleteLocalRef(env, exp);
  290. (*env)->ExceptionClear(env);
  291. }
  292. fid = (*env)->GetFieldID(env, clz, "mNativeSurface", "I");
  293. }
  294. vout_android_surf = (void*)(*env)->GetIntField(env, surf, fid);
  295. (*env)->DeleteLocalRef(env, clz);
  296. vout_android_gui = (*env)->NewGlobalRef(env, gui);
  297. pthread_mutex_unlock(&vout_android_lock);
  298. }
  299. void Java_org_videolan_vlc_LibVLC_detachSurface(JNIEnv *env, jobject thiz) {
  300. pthread_mutex_lock(&vout_android_lock);
  301. vout_android_surf = NULL;
  302. if (vout_android_gui != NULL)
  303. (*env)->DeleteGlobalRef(env, vout_android_gui);
  304. vout_android_gui = NULL;
  305. pthread_mutex_unlock(&vout_android_lock);
  306. }
  307. static void debug_log(void *data, int level, const char *fmt, va_list ap)
  308. {
  309. bool *verbose = data;
  310. static const uint8_t priority[5] = {
  311. [LIBVLC_DEBUG] = ANDROID_LOG_DEBUG,
  312. [1 /* ??? */] = ANDROID_LOG_DEBUG,
  313. [LIBVLC_NOTICE] = ANDROID_LOG_INFO,
  314. [LIBVLC_WARNING] = ANDROID_LOG_WARN,
  315. [LIBVLC_ERROR] = ANDROID_LOG_ERROR,
  316. };
  317. int prio = ANDROID_LOG_DEBUG;
  318. if (level >= LIBVLC_DEBUG && level <= LIBVLC_ERROR)
  319. prio = priority[level];
  320. if (!*verbose && prio < ANDROID_LOG_ERROR)
  321. return;
  322. __android_log_vprint(prio, "VLC", fmt, ap);
  323. }
  324. static libvlc_log_subscriber_t debug_subscriber;
  325. static bool verbosity;
  326. void Java_org_videolan_vlc_LibVLC_changeVerbosity(JNIEnv *env, jobject thiz, jboolean verbose)
  327. {
  328. verbosity = verbose;
  329. libvlc_log_unsubscribe(&debug_subscriber);
  330. libvlc_log_subscribe(&debug_subscriber, debug_log, &verbosity);
  331. }
  332. void Java_org_videolan_vlc_LibVLC_nativeInit(JNIEnv *env, jobject thiz, jboolean verbose)
  333. {
  334. //only use OpenSLES if java side says we can
  335. jclass cls = (*env)->GetObjectClass(env, thiz);
  336. jmethodID methodId = (*env)->GetMethodID(env, cls, "getAout", "()I");
  337. bool use_opensles = (*env)->CallIntMethod(env, thiz, methodId) == AOUT_OPENSLES;
  338. methodId = (*env)->GetMethodID(env, cls, "timeStretchingEnabled", "()Z");
  339. bool enable_time_stretch = (*env)->CallBooleanMethod(env, thiz, methodId);
  340. methodId = (*env)->GetMethodID(env, cls, "getSubtitlesEncoding", "()Ljava/lang/String;");
  341. jstring subsencoding = (*env)->CallObjectMethod(env, thiz, methodId);
  342. const char *subsencodingstr = (*env)->GetStringUTFChars(env, subsencoding, 0);
  343. LOGD("Subtitle encoding set to \"%s\"", subsencodingstr);
  344. verbosity = verbose;
  345. libvlc_log_subscribe(&debug_subscriber, debug_log, &verbosity);
  346. /* Don't add any invalid options, otherwise it causes LibVLC to crash */
  347. const char *argv[] = {
  348. "-I", "dummy",
  349. "--no-osd",
  350. "--no-video-title-show",
  351. "--no-stats",
  352. "--no-plugins-cache",
  353. "--no-drop-late-frames",
  354. "--avcodec-fast",
  355. "--avcodec-threads=0",
  356. "--subsdec-encoding", subsencodingstr,
  357. enable_time_stretch ? "--audio-time-stretch" : "--no-audio-time-stretch",
  358. use_opensles ? "--aout=opensles" : "--aout=android_audiotrack",
  359. };
  360. libvlc_instance_t *instance = libvlc_new(sizeof(argv) / sizeof(*argv), argv);
  361. setLong(env, thiz, "mLibVlcInstance", (jlong)(intptr_t) instance);
  362. (*env)->ReleaseStringUTFChars(env, subsencoding, subsencodingstr);
  363. if (!instance)
  364. {
  365. jclass exc = (*env)->FindClass(env, "org/videolan/vlc/LibVlcException");
  366. (*env)->ThrowNew(env, exc, "Unable to instantiate LibVLC");
  367. }
  368. LOGI("LibVLC initialized: %p", instance);
  369. /* Initialize media list (a.k.a. playlist/history) */
  370. libvlc_media_list_t* pointer = libvlc_media_list_new( instance );
  371. if(!pointer) {
  372. jclass exc = (*env)->FindClass(env, "org/videolan/vlc/LibVlcException");
  373. (*env)->ThrowNew(env, exc, "Unable to create LibVLC media list");
  374. return;
  375. }
  376. /* Connect the event manager */
  377. libvlc_event_manager_t *ev = libvlc_media_list_event_manager(pointer);
  378. static const libvlc_event_type_t mp_events[] = {
  379. libvlc_MediaListItemAdded,
  380. libvlc_MediaListItemDeleted,
  381. };
  382. for(int i = 0; i < (sizeof(mp_events) / sizeof(*mp_events)); i++)
  383. libvlc_event_attach(ev, mp_events[i], vlc_event_callback, myVm);
  384. setLong(env, thiz, "mMediaListInstance", (jlong)(intptr_t)pointer);
  385. }
  386. jstring Java_org_videolan_vlc_LibVLC_nativeToURI(JNIEnv *env, jobject thiz, jstring path)
  387. {
  388. jboolean isCopy;
  389. /* Get C string */
  390. const char* psz_path = (*env)->GetStringUTFChars(env, path, &isCopy);
  391. /* Convert the path to URI */
  392. char* psz_location;
  393. if(unlikely( strstr( psz_path, "://" ) ))
  394. psz_location = strdup(psz_path);
  395. else
  396. psz_location = vlc_path2uri(psz_path, "file");
  397. /* Box into jstring */
  398. jstring t = (*env)->NewStringUTF(env, psz_location);
  399. /* Clean up */
  400. (*env)->ReleaseStringUTFChars(env, path, psz_path);
  401. free(psz_location);
  402. return t;
  403. }
  404. void Java_org_videolan_vlc_LibVLC_nativeDestroy(JNIEnv *env, jobject thiz)
  405. {
  406. releaseMediaPlayer(env, thiz);
  407. jlong libVlcInstance = getLong(env, thiz, "mLibVlcInstance");
  408. if (!libVlcInstance)
  409. return; // Already destroyed
  410. libvlc_instance_t *instance = (libvlc_instance_t*)(intptr_t) libVlcInstance;
  411. libvlc_release(instance);
  412. libvlc_log_unsubscribe(&debug_subscriber);
  413. setLong(env, thiz, "mLibVlcInstance", 0);
  414. }
  415. void Java_org_videolan_vlc_LibVLC_detachEventManager(JNIEnv *env, jobject thiz)
  416. {
  417. if (eventManagerInstance != NULL) {
  418. (*env)->DeleteGlobalRef(env, eventManagerInstance);
  419. eventManagerInstance = NULL;
  420. }
  421. }
  422. void Java_org_videolan_vlc_LibVLC_setEventManager(JNIEnv *env, jobject thiz, jobject eventManager)
  423. {
  424. if (eventManagerInstance != NULL) {
  425. (*env)->DeleteGlobalRef(env, eventManagerInstance);
  426. eventManagerInstance = NULL;
  427. }
  428. jclass cls = (*env)->GetObjectClass(env, eventManager);
  429. if (!cls) {
  430. LOGE("setEventManager: failed to get class reference");
  431. return;
  432. }
  433. jmethodID methodID = (*env)->GetMethodID(env, cls, "callback", "(ILandroid/os/Bundle;)V");
  434. if (!methodID) {
  435. LOGE("setEventManager: failed to get the callback method");
  436. return;
  437. }
  438. eventManagerInstance = (*env)->NewGlobalRef(env, eventManager);
  439. }
  440. jobjectArray Java_org_videolan_vlc_LibVLC_readMediaMeta(JNIEnv *env,
  441. jobject thiz, jlong instance, jstring mrl)
  442. {
  443. jobjectArray array = (*env)->NewObjectArray(env, 8,
  444. (*env)->FindClass(env, "java/lang/String"),
  445. (*env)->NewStringUTF(env, ""));
  446. libvlc_media_t *m = new_media(instance, env, thiz, mrl, false, false);
  447. if (!m)
  448. {
  449. LOGE("readMediaMeta: Could not create the media!");
  450. return array;
  451. }
  452. libvlc_media_parse(m);
  453. static const char str[][7] = {
  454. "artist", "album", "title", "genre",
  455. };
  456. static const libvlc_meta_t meta_id[] = {
  457. libvlc_meta_Artist,
  458. libvlc_meta_Album,
  459. libvlc_meta_Title,
  460. libvlc_meta_Genre,
  461. };
  462. for (int i=0; i < sizeof(str) / sizeof(*str); i++) {
  463. char *meta = libvlc_media_get_meta(m, meta_id[i]);
  464. if (!meta)
  465. meta = strdup("");
  466. jstring k = (*env)->NewStringUTF(env, str[i]);
  467. (*env)->SetObjectArrayElement(env, array, 2*i, k);
  468. jstring v = (*env)->NewStringUTF(env, meta);
  469. (*env)->SetObjectArrayElement(env, array, 2*i+1, v);
  470. free(meta);
  471. }
  472. libvlc_media_release(m);
  473. return array;
  474. }
  475. static void create_player_and_play(JNIEnv* env, jobject thiz,
  476. jlong instance, int position) {
  477. /* Release previous media player, if any */
  478. releaseMediaPlayer(env, thiz);
  479. libvlc_media_list_t* p_mlist = getMediaList(env, thiz);
  480. /* Create a media player playing environment */
  481. libvlc_media_list_player_t* p_mlp = libvlc_media_list_player_new((libvlc_instance_t*)(intptr_t)instance);
  482. libvlc_media_player_t *mp = libvlc_media_player_new((libvlc_instance_t*)(intptr_t)instance);
  483. jobject myJavaLibVLC = (*env)->NewGlobalRef(env, thiz);
  484. //if AOUT_AUDIOTRACK_JAVA, we use amem
  485. jclass cls = (*env)->GetObjectClass(env, thiz);
  486. jmethodID methodId = (*env)->GetMethodID(env, cls, "getAout", "()I");
  487. if ( (*env)->CallIntMethod(env, thiz, methodId) == AOUT_AUDIOTRACK_JAVA )
  488. {
  489. libvlc_audio_set_callbacks(mp, aout_play, aout_pause, NULL, NULL, NULL,
  490. (void*) myJavaLibVLC);
  491. libvlc_audio_set_format_callbacks(mp, aout_open, aout_close);
  492. }
  493. /* Connect the event manager */
  494. libvlc_event_manager_t *ev = libvlc_media_player_event_manager(mp);
  495. static const libvlc_event_type_t mp_events[] = {
  496. libvlc_MediaPlayerPlaying,
  497. libvlc_MediaPlayerPaused,
  498. libvlc_MediaPlayerEndReached,
  499. libvlc_MediaPlayerStopped,
  500. libvlc_MediaPlayerVout,
  501. };
  502. for(int i = 0; i < (sizeof(mp_events) / sizeof(*mp_events)); i++)
  503. libvlc_event_attach(ev, mp_events[i], vlc_event_callback, myVm);
  504. libvlc_media_list_player_set_media_list(p_mlp, p_mlist);
  505. libvlc_media_list_player_set_media_player(p_mlp, mp);
  506. /* Keep a pointer to this media player */
  507. setLong(env, thiz, "mMediaListPlayerInstance", (jlong)(intptr_t)p_mlp);
  508. setLong(env, thiz, "mInternalMediaPlayerInstance", (jlong)(intptr_t)mp);
  509. libvlc_media_list_player_play_item_at_index(p_mlp, position);
  510. }
  511. jint Java_org_videolan_vlc_LibVLC_readMedia(JNIEnv *env, jobject thiz,
  512. jlong instance, jstring mrl, jboolean novideo)
  513. {
  514. /* Create a new item */
  515. libvlc_media_t *m = new_media(instance, env, thiz, mrl, false, novideo);
  516. if (!m)
  517. {
  518. LOGE("readMedia: Could not create the media!");
  519. return -1;
  520. }
  521. libvlc_media_list_t* p_mlist = getMediaList(env, thiz);
  522. libvlc_media_list_lock(p_mlist);
  523. if(libvlc_media_list_add_media(p_mlist, m) != 0) {
  524. LOGE("readMedia: Could not add to the media list!");
  525. libvlc_media_list_unlock(p_mlist);
  526. libvlc_media_release(m);
  527. return -1;
  528. }
  529. int position = libvlc_media_list_index_of_item(p_mlist, m);
  530. libvlc_media_list_unlock(p_mlist);
  531. /* No need to keep the media now */
  532. libvlc_media_release(m);
  533. create_player_and_play(env, thiz, instance, position);
  534. return position;
  535. }
  536. void Java_org_videolan_vlc_LibVLC_playIndex(JNIEnv *env, jobject thiz,
  537. jlong instance, int position) {
  538. create_player_and_play(env, thiz, instance, position);
  539. }
  540. void Java_org_videolan_vlc_LibVLC_getMediaListItems(
  541. JNIEnv *env, jobject thiz, jobject arrayList) {
  542. jclass arrayClass = (*env)->FindClass(env, "java/util/ArrayList");
  543. jmethodID methodID = (*env)->GetMethodID(env, arrayClass, "add", "(Ljava/lang/Object;)Z");
  544. jstring str;
  545. libvlc_media_list_t* p_mlist = getMediaList(env, thiz);
  546. libvlc_media_list_lock( p_mlist );
  547. for(int i = 0; i < libvlc_media_list_count( p_mlist ); i++) {
  548. char* mrl = libvlc_media_get_mrl( libvlc_media_list_item_at_index( p_mlist, i ) );
  549. str = (*env)->NewStringUTF(env, mrl);
  550. (*env)->CallBooleanMethod(env, arrayList, methodID, str);
  551. (*env)->DeleteLocalRef(env, str);
  552. free(mrl);
  553. }
  554. libvlc_media_list_unlock( p_mlist );
  555. }
  556. jfloat Java_org_videolan_vlc_LibVLC_getRate(JNIEnv *env, jobject thiz) {
  557. libvlc_media_player_t* mp = getMediaPlayer(env, thiz);
  558. if(mp)
  559. return libvlc_media_player_get_rate(mp);
  560. else
  561. return 1.00;
  562. }
  563. void Java_org_videolan_vlc_LibVLC_setRate(JNIEnv *env, jobject thiz, jfloat rate) {
  564. libvlc_media_player_t* mp = getMediaPlayer(env, thiz);
  565. if(mp)
  566. libvlc_media_player_set_rate(mp, rate);
  567. }
  568. jboolean Java_org_videolan_vlc_LibVLC_hasVideoTrack(JNIEnv *env, jobject thiz,
  569. jlong i_instance, jstring fileLocation)
  570. {
  571. /* Create a new item and assign it to the media player. */
  572. libvlc_media_t *p_m = new_media(i_instance, env, thiz, fileLocation, false, false);
  573. if (p_m == NULL)
  574. {
  575. LOGE("Could not create the media!");
  576. return JNI_FALSE;
  577. }
  578. /* Get the tracks information of the media. */
  579. libvlc_media_track_info_t *p_tracks;
  580. libvlc_media_parse(p_m);
  581. libvlc_media_player_t* p_mp = libvlc_media_player_new_from_media(p_m);
  582. struct length_change_monitor* monitor;
  583. monitor = malloc(sizeof(struct length_change_monitor));
  584. if (!monitor) return 0;
  585. /* Initialize pthread variables. */
  586. pthread_mutex_init(&monitor->doneMutex, NULL);
  587. pthread_cond_init(&monitor->doneCondVar, NULL);
  588. monitor->length_changed = false;
  589. libvlc_event_manager_t *ev = libvlc_media_player_event_manager(p_mp);
  590. libvlc_event_attach(ev, libvlc_MediaPlayerLengthChanged, length_changed_callback, monitor);
  591. libvlc_media_player_play( p_mp );
  592. pthread_mutex_lock(&monitor->doneMutex);
  593. struct timespec deadline;
  594. clock_gettime(CLOCK_REALTIME, &deadline);
  595. deadline.tv_sec += 2; /* If "VLC can't open the file", return */
  596. int mp_alive = 1;
  597. while( !monitor->length_changed && mp_alive ) {
  598. pthread_cond_timedwait(&monitor->doneCondVar, &monitor->doneMutex, &deadline);
  599. mp_alive = libvlc_media_player_will_play(p_mp);
  600. }
  601. pthread_mutex_unlock(&monitor->doneMutex);
  602. int i_nbTracks;
  603. if( mp_alive )
  604. i_nbTracks = libvlc_video_get_track_count(p_mp);
  605. else
  606. i_nbTracks = -1;
  607. LOGI("Number of video tracks: %d",i_nbTracks);
  608. libvlc_event_detach(ev, libvlc_MediaPlayerLengthChanged, length_changed_callback, monitor);
  609. libvlc_media_player_stop(p_mp);
  610. libvlc_media_player_release(p_mp);
  611. libvlc_media_release(p_m);
  612. pthread_mutex_destroy(&monitor->doneMutex);
  613. pthread_cond_destroy(&monitor->doneCondVar);
  614. free(monitor);
  615. if(i_nbTracks > 0)
  616. return JNI_TRUE;
  617. else if(i_nbTracks < 0)
  618. (*env)->ThrowNew(env, (*env)->FindClass(env, "java/io/IOException"), "VLC can't open the file");
  619. else
  620. return JNI_FALSE;
  621. }
  622. jobjectArray read_track_info_internal(JNIEnv *env, jobject thiz, libvlc_media_t* p_m)
  623. {
  624. /* get java class */
  625. jclass cls = (*env)->FindClass( env, "org/videolan/vlc/TrackInfo" );
  626. if ( !cls )
  627. {
  628. LOGE("Failed to load class (org/videolan/vlc/TrackInfo)" );
  629. return NULL;
  630. }
  631. /* get java class contructor */
  632. jmethodID clsCtor = (*env)->GetMethodID( env, cls, "<init>", "()V" );
  633. if ( !clsCtor )
  634. {
  635. LOGE("Failed to find class constructor (org/videolan/vlc/TrackInfo)" );
  636. return NULL;
  637. }
  638. /* Get the tracks information of the media. */
  639. libvlc_media_track_info_t *p_tracks;
  640. int i_nbTracks = libvlc_media_get_tracks_info(p_m, &p_tracks);
  641. jobjectArray array = (*env)->NewObjectArray(env, i_nbTracks + 1, cls, NULL);
  642. unsigned i;
  643. if (array != NULL)
  644. {
  645. for (i = 0; i <= i_nbTracks; ++i)
  646. {
  647. jobject item = (*env)->NewObject(env, cls, clsCtor);
  648. if (item == NULL)
  649. continue;
  650. (*env)->SetObjectArrayElement(env, array, i, item);
  651. // use last track for metadata
  652. if (i == i_nbTracks)
  653. {
  654. setInt(env, item, "Type", 3 /* TYPE_META */);
  655. setLong(env, item, "Length", libvlc_media_get_duration(p_m));
  656. setString(env, item, "Title", libvlc_media_get_meta(p_m, libvlc_meta_Title));
  657. setString(env, item, "Artist", libvlc_media_get_meta(p_m, libvlc_meta_Artist));
  658. setString(env, item, "Album", libvlc_media_get_meta(p_m, libvlc_meta_Album));
  659. setString(env, item, "Genre", libvlc_media_get_meta(p_m, libvlc_meta_Genre));
  660. setString(env, item, "ArtworkURL", libvlc_media_get_meta(p_m, libvlc_meta_ArtworkURL));
  661. continue;
  662. }
  663. setInt(env, item, "Id", p_tracks[i].i_id);
  664. setInt(env, item, "Type", p_tracks[i].i_type);
  665. setString(env, item, "Codec", (const char*)vlc_fourcc_GetDescription(0,p_tracks[i].i_codec));
  666. setString(env, item, "Language", p_tracks[i].psz_language);
  667. if (p_tracks[i].i_type == libvlc_track_video)
  668. {
  669. setInt(env, item, "Height", p_tracks[i].u.video.i_height);
  670. setInt(env, item, "Width", p_tracks[i].u.video.i_width);
  671. setFloat(env, item, "Framerate", p_tracks[i].u.video.f_frame_rate);
  672. }
  673. if (p_tracks[i].i_type == libvlc_track_audio)
  674. {
  675. setInt(env, item, "Channels", p_tracks[i].u.audio.i_channels);
  676. setInt(env, item, "Samplerate", p_tracks[i].u.audio.i_rate);
  677. }
  678. }
  679. }
  680. libvlc_media_tracks_info_release(p_tracks, i_nbTracks);
  681. return array;
  682. }
  683. jobjectArray Java_org_videolan_vlc_LibVLC_readTracksInfo(JNIEnv *env, jobject thiz,
  684. jlong instance, jstring mrl)
  685. {
  686. /* Create a new item and assign it to the media player. */
  687. libvlc_media_t *p_m = new_media(instance, env, thiz, mrl, false, false);
  688. if (p_m == NULL)
  689. {
  690. LOGE("Could not create the media!");
  691. return NULL;
  692. }
  693. libvlc_media_parse(p_m);
  694. jobjectArray jar = read_track_info_internal(env, thiz, p_m);
  695. libvlc_media_release(p_m);
  696. return jar;
  697. }
  698. jobjectArray Java_org_videolan_vlc_LibVLC_readTracksInfoPosition(JNIEnv *env, jobject thiz,
  699. jint position)
  700. {
  701. libvlc_media_list_t* p_mlist = getMediaList(env, thiz);
  702. libvlc_media_t *p_m = libvlc_media_list_item_at_index( p_mlist, position );
  703. if (p_m == NULL) {
  704. LOGE("Could not load get media @ position %d!", position);
  705. return NULL;
  706. } else
  707. return read_track_info_internal(env, thiz, p_m);
  708. }
  709. jlong Java_org_videolan_vlc_LibVLC_getLengthFromLocation(JNIEnv *env, jobject thiz,
  710. jlong i_instance, jstring fileLocation)
  711. {
  712. jlong length = 0;
  713. struct length_change_monitor *monitor;
  714. monitor = malloc(sizeof(*monitor));
  715. if (!monitor)
  716. return 0;
  717. /* Initialize pthread variables. */
  718. pthread_mutex_init(&monitor->doneMutex, NULL);
  719. pthread_cond_init(&monitor->doneCondVar, NULL);
  720. monitor->length_changed = false;
  721. /* Create a new item and assign it to the media player. */
  722. libvlc_media_t *m = new_media(i_instance, env, thiz, fileLocation, false, false);
  723. if (m == NULL)
  724. {
  725. LOGE("Could not create the media to play!");
  726. goto end;
  727. }
  728. /* Create a media player playing environment */
  729. libvlc_media_player_t *mp = libvlc_media_player_new_from_media (m);
  730. libvlc_event_manager_t *ev = libvlc_media_player_event_manager(mp);
  731. libvlc_event_attach(ev, libvlc_MediaPlayerLengthChanged, length_changed_callback, monitor);
  732. libvlc_media_release (m);
  733. libvlc_media_player_play( mp );
  734. pthread_mutex_lock(&monitor->doneMutex);
  735. while (!monitor->length_changed)
  736. pthread_cond_wait(&monitor->doneCondVar, &monitor->doneMutex);
  737. pthread_mutex_unlock(&monitor->doneMutex);
  738. length = libvlc_media_player_get_length( mp );
  739. libvlc_media_player_stop( mp );
  740. libvlc_media_player_release( mp );
  741. end:
  742. pthread_mutex_destroy(&monitor->doneMutex);
  743. pthread_cond_destroy(&monitor->doneCondVar);
  744. free(monitor);
  745. return length;
  746. }
  747. jboolean Java_org_videolan_vlc_LibVLC_hasMediaPlayer(JNIEnv *env, jobject thiz)
  748. {
  749. return !!getMediaListPlayer(env, thiz);
  750. }
  751. jboolean Java_org_videolan_vlc_LibVLC_isPlaying(JNIEnv *env, jobject thiz)
  752. {
  753. libvlc_media_list_player_t *mp = getMediaListPlayer(env, thiz);
  754. if (mp)
  755. return !!libvlc_media_list_player_is_playing(mp);
  756. else
  757. return 0;
  758. }
  759. jboolean Java_org_videolan_vlc_LibVLC_isSeekable(JNIEnv *env, jobject thiz)
  760. {
  761. libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
  762. if (mp)
  763. return !!libvlc_media_player_is_seekable(mp);
  764. return 0;
  765. }
  766. void Java_org_videolan_vlc_LibVLC_play(JNIEnv *env, jobject thiz)
  767. {
  768. libvlc_media_list_player_t *mp = getMediaListPlayer(env, thiz);
  769. if (mp)
  770. libvlc_media_list_player_play(mp);
  771. }
  772. void Java_org_videolan_vlc_LibVLC_pause(JNIEnv *env, jobject thiz)
  773. {
  774. libvlc_media_list_player_t *mp = getMediaListPlayer(env, thiz);
  775. if (mp)
  776. libvlc_media_list_player_pause(mp);
  777. }
  778. void Java_org_videolan_vlc_LibVLC_stop(JNIEnv *env, jobject thiz)
  779. {
  780. libvlc_media_list_player_t *mp = getMediaListPlayer(env, thiz);
  781. if (mp)
  782. libvlc_media_list_player_stop(mp);
  783. }
  784. void Java_org_videolan_vlc_LibVLC_previous(JNIEnv *env, jobject thiz)
  785. {
  786. libvlc_media_list_player_t *mp = getMediaListPlayer(env, thiz);
  787. if (mp)
  788. libvlc_media_list_player_previous(mp);
  789. }
  790. void Java_org_videolan_vlc_LibVLC_next(JNIEnv *env, jobject thiz)
  791. {
  792. libvlc_media_list_player_t *mp = getMediaListPlayer(env, thiz);
  793. if (mp)
  794. libvlc_media_list_player_next(mp);
  795. }
  796. jint Java_org_videolan_vlc_LibVLC_getVolume(JNIEnv *env, jobject thiz)
  797. {
  798. libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
  799. if (mp)
  800. return (jint) libvlc_audio_get_volume(mp);
  801. return -1;
  802. }
  803. jint Java_org_videolan_vlc_LibVLC_setVolume(JNIEnv *env, jobject thiz, jint volume)
  804. {
  805. libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
  806. if (mp)
  807. //Returns 0 if the volume was set, -1 if it was out of range or error
  808. return (jint) libvlc_audio_set_volume(mp, (int) volume);
  809. return -1;
  810. }
  811. jlong Java_org_videolan_vlc_LibVLC_getTime(JNIEnv *env, jobject thiz)
  812. {
  813. libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
  814. if (mp)
  815. return libvlc_media_player_get_time(mp);
  816. return -1;
  817. }
  818. void Java_org_videolan_vlc_LibVLC_setTime(JNIEnv *env, jobject thiz, jlong time)
  819. {
  820. libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
  821. if (mp)
  822. libvlc_media_player_set_time(mp, time);
  823. }
  824. jfloat Java_org_videolan_vlc_LibVLC_getPosition(JNIEnv *env, jobject thiz)
  825. {
  826. libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
  827. if (mp)
  828. return (jfloat) libvlc_media_player_get_position(mp);
  829. return -1;
  830. }
  831. void Java_org_videolan_vlc_LibVLC_setPosition(JNIEnv *env, jobject thiz, jfloat pos)
  832. {
  833. libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
  834. if (mp)
  835. libvlc_media_player_set_position(mp, pos);
  836. }
  837. jlong Java_org_videolan_vlc_LibVLC_getLength(JNIEnv *env, jobject thiz)
  838. {
  839. libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
  840. if (mp)
  841. return (jlong) libvlc_media_player_get_length(mp);
  842. return -1;
  843. }
  844. jstring Java_org_videolan_vlc_LibVLC_version(JNIEnv* env, jobject thiz)
  845. {
  846. return (*env)->NewStringUTF(env, libvlc_get_version());
  847. }
  848. jstring Java_org_videolan_vlc_LibVLC_compiler(JNIEnv* env, jobject thiz)
  849. {
  850. return (*env)->NewStringUTF(env, libvlc_get_compiler());
  851. }
  852. jstring Java_org_videolan_vlc_LibVLC_changeset(JNIEnv* env, jobject thiz)
  853. {
  854. return (*env)->NewStringUTF(env, libvlc_get_changeset());
  855. }
  856. jint Java_org_videolan_vlc_LibVLC_getAudioTracksCount(JNIEnv *env, jobject thiz)
  857. {
  858. libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
  859. if (mp)
  860. return (jint) libvlc_audio_get_track_count(mp);
  861. return -1;
  862. }
  863. jobjectArray Java_org_videolan_vlc_LibVLC_getAudioTrackDescription(JNIEnv *env, jobject thiz)
  864. {
  865. libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
  866. if (!mp)
  867. return NULL;
  868. int i_nbTracks = libvlc_audio_get_track_count(mp) - 1;
  869. if (i_nbTracks < 0)
  870. i_nbTracks = 0;
  871. jobjectArray array = (*env)->NewObjectArray(env, i_nbTracks,
  872. (*env)->FindClass(env, "java/lang/String"),
  873. NULL);
  874. libvlc_track_description_t *first = libvlc_audio_get_track_description(mp);
  875. libvlc_track_description_t *desc = first != NULL ? first->p_next : NULL;
  876. unsigned i;
  877. for (i = 0; i < i_nbTracks; ++i)
  878. {
  879. jstring name = (*env)->NewStringUTF(env, desc->psz_name);
  880. (*env)->SetObjectArrayElement(env, array, i, name);
  881. desc = desc->p_next;
  882. }
  883. libvlc_track_description_list_release(first);
  884. return array;
  885. }
  886. jint Java_org_videolan_vlc_LibVLC_getAudioTrack(JNIEnv *env, jobject thiz)
  887. {
  888. libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
  889. if (mp)
  890. return libvlc_audio_get_track(mp);
  891. return -1;
  892. }
  893. jint Java_org_videolan_vlc_LibVLC_setAudioTrack(JNIEnv *env, jobject thiz, jint index)
  894. {
  895. libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
  896. if (mp)
  897. return libvlc_audio_set_track(mp, index);
  898. return -1;
  899. }
  900. jint Java_org_videolan_vlc_LibVLC_getVideoTracksCount(JNIEnv *env, jobject thiz)
  901. {
  902. libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
  903. if (mp)
  904. return (jint) libvlc_video_get_track_count(mp);
  905. return -1;
  906. }
  907. jobjectArray Java_org_videolan_vlc_LibVLC_getSpuTrackDescription(JNIEnv *env, jobject thiz)
  908. {
  909. libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
  910. if (!mp)
  911. return NULL;
  912. int i_nbTracks = libvlc_video_get_spu_count(mp);
  913. jobjectArray array = (*env)->NewObjectArray(env, i_nbTracks,
  914. (*env)->FindClass(env, "java/lang/String"),
  915. NULL);
  916. libvlc_track_description_t *first = libvlc_video_get_spu_description(mp);
  917. libvlc_track_description_t *desc = first;
  918. unsigned i;
  919. for (i = 0; i < i_nbTracks; ++i)
  920. {
  921. jstring name = (*env)->NewStringUTF(env, desc->psz_name);
  922. (*env)->SetObjectArrayElement(env, array, i, name);
  923. desc = desc->p_next;
  924. }
  925. libvlc_track_description_list_release(first);
  926. return array;
  927. }
  928. jint Java_org_videolan_vlc_LibVLC_getSpuTracksCount(JNIEnv *env, jobject thiz)
  929. {
  930. libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
  931. if (mp)
  932. return (jint) libvlc_video_get_spu_count(mp);
  933. return -1;
  934. }
  935. jint Java_org_videolan_vlc_LibVLC_getSpuTrack(JNIEnv *env, jobject thiz)
  936. {
  937. libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
  938. if (mp)
  939. return libvlc_video_get_spu(mp);
  940. return -1;
  941. }
  942. jint Java_org_videolan_vlc_LibVLC_setSpuTrack(JNIEnv *env, jobject thiz, jint index)
  943. {
  944. libvlc_media_player_t *mp = getMediaPlayer(env, thiz);
  945. if (mp)
  946. return libvlc_video_set_spu(mp, index);
  947. return -1;
  948. }
  949. void Java_org_videolan_vlc_LibVLC_nativeReadDirectory(JNIEnv *env, jobject thiz, jstring path, jobject arrayList)
  950. {
  951. jboolean isCopy;
  952. /* Get C string */
  953. const char* psz_path = (*env)->GetStringUTFChars(env, path, &isCopy);
  954. DIR* p_dir = opendir(psz_path);
  955. (*env)->ReleaseStringUTFChars(env, path, psz_path);
  956. if(!p_dir)
  957. return;
  958. jclass arrayClass = (*env)->FindClass(env, "java/util/ArrayList");
  959. jmethodID methodID = (*env)->GetMethodID(env, arrayClass, "add", "(Ljava/lang/Object;)Z");
  960. struct dirent* p_dirent;
  961. jstring str;
  962. while(1) {
  963. errno = 0;
  964. p_dirent = readdir(p_dir);
  965. if(p_dirent == NULL) {
  966. if(errno > 0) /* error reading this entry */
  967. continue;
  968. else if(errno == 0) /* end of stream */
  969. break;
  970. }
  971. str = (*env)->NewStringUTF(env, p_dirent->d_name);
  972. (*env)->CallBooleanMethod(env, arrayList, methodID, str);
  973. (*env)->DeleteLocalRef(env, str);
  974. }
  975. closedir(p_dir);
  976. }
  977. jboolean Java_org_videolan_vlc_LibVLC_nativeIsPathDirectory(JNIEnv *env, jobject thiz, jstring path)
  978. {
  979. jboolean isCopy;
  980. /* Get C string */
  981. const char* psz_path = (*env)->GetStringUTFChars(env, path, &isCopy);
  982. jboolean isDirectory;
  983. struct stat buf;
  984. if(stat(psz_path, &buf) != 0)
  985. /* couldn't stat */
  986. isDirectory = JNI_FALSE;
  987. else {
  988. if(S_ISDIR(buf.st_mode))
  989. isDirectory = JNI_TRUE;
  990. else
  991. isDirectory = JNI_FALSE;
  992. }
  993. (*env)->ReleaseStringUTFChars(env, path, psz_path);
  994. return isDirectory;
  995. }