Skip to content

Commit 5737b66

Browse files
committed
Notify Java side of events and property changes
1 parent 52910ee commit 5737b66

File tree

13 files changed

+373
-96
lines changed

13 files changed

+373
-96
lines changed

Player/app/src/main/cpp/event_thread.c

Lines changed: 73 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,24 @@
22
#include <pthread.h>
33

44
#include <android/looper.h>
5+
#include <jni.h>
56

67
#include "logger.h"
78

9+
#include "player_interface.h"
810
#include "event_thread.h"
11+
#include "player.h"
912

1013
static void *event_thread_run(void *event_thread);
1114

12-
struct event_thread *event_thread_create(mpv_handle *mpv) {
15+
struct event_thread *event_thread_create(struct player_context *player_context) {
1316
struct event_thread *event_thread = malloc(sizeof(struct event_thread));
1417
pthread_mutex_init(&event_thread->lock, NULL);
1518
pthread_cond_init(&event_thread->ready, NULL);
1619

1720
event_thread->running = 0;
1821

19-
event_thread->mpv = mpv;
22+
event_thread->player_context = player_context;
2023

2124
return event_thread;
2225
}
@@ -46,9 +49,14 @@ void event_thread_destroy(struct event_thread *event_thread) {
4649
static void *event_thread_run(void *data) {
4750
struct event_thread *event_thread = data;
4851

49-
mpv_handle *mpv;
52+
JNIEnv *env = event_thread->player_context->env;
53+
JavaVM *vm = event_thread->player_context->vm;
54+
mpv_handle *mpv = event_thread->player_context->mpv;
55+
jobject core_instance = event_thread->player_context->core_instance;
56+
57+
(*vm)->AttachCurrentThread(vm, &env, NULL);
58+
5059
pthread_mutex_lock(&event_thread->lock);
51-
mpv = event_thread->mpv;
5260
event_thread->running = 1;
5361
pthread_cond_broadcast(&event_thread->ready);
5462
pthread_mutex_unlock(&event_thread->lock);
@@ -64,24 +72,79 @@ static void *event_thread_run(void *data) {
6472
}
6573

6674
event = mpv_wait_event(mpv, -1.0);
75+
76+
// Ignoring all deprecated and async() events
6777
switch (event->event_id) {
78+
case MPV_EVENT_SHUTDOWN: {
79+
// TODO
80+
break;
81+
}
82+
case MPV_EVENT_START_FILE:
83+
case MPV_EVENT_FILE_LOADED:
84+
case MPV_EVENT_IDLE:
85+
case MPV_EVENT_VIDEO_RECONFIG:
86+
case MPV_EVENT_AUDIO_RECONFIG:
87+
case MPV_EVENT_SEEK:
88+
case MPV_EVENT_PLAYBACK_RESTART: {
89+
const char *event_name = mpv_event_name(event->event_id);
90+
event_no_data(env, core_instance, event_name);
91+
break;
92+
}
93+
case MPV_EVENT_END_FILE: {
94+
mpv_event_end_file *end_file = event->data;
95+
int reason = end_file->reason;
96+
break;
97+
}
6898
case MPV_EVENT_LOG_MESSAGE: {
6999
mpv_event_log_message *msg = event->data;
70100
LOGI("[%s:%s] %s", msg->prefix, msg->level, msg->text);
71101
break;
72102
}
73103
case MPV_EVENT_PROPERTY_CHANGE: {
74104
mpv_event_property *property = event->data;
75-
LOGI("Property %s changed", property->name);
105+
uint64_t userdata = event->reply_userdata;
106+
107+
switch (property->format) {
108+
case MPV_FORMAT_NONE: {
109+
LOGE("Received MPV_FORMAT_NONE");
110+
break;
111+
}
112+
case MPV_FORMAT_STRING:
113+
case MPV_FORMAT_OSD_STRING: {
114+
event_property_string(env, core_instance, userdata, property->name, property->data);
115+
break;
116+
}
117+
case MPV_FORMAT_FLAG: {
118+
int flag = *(int *) property->data;
119+
event_property_flag(env, core_instance, userdata, property->name, flag);
120+
break;
121+
}
122+
case MPV_FORMAT_INT64: {
123+
int64_t value = *(int64_t *) property->data;
124+
event_property_long(env, core_instance, userdata, property->name, value);
125+
break;
126+
}
127+
case MPV_FORMAT_DOUBLE: {
128+
double value = *(double *) property->data;
129+
event_property_double(env, core_instance, userdata, property->name, value);
130+
break;
131+
}
132+
default: {
133+
LOGE("Property format %d not handled", property->format);
134+
break;
135+
}
136+
}
137+
break;
138+
}
139+
case MPV_EVENT_QUEUE_OVERFLOW: {
140+
LOGE("MPV_EVENT_QUEUE_OVERFLOW received");
76141
break;
77142
}
78143
default: {
79-
LOGI("Unhandled event %s", mpv_event_name(event->event_id));
144+
// Ignore
80145
break;
81146
}
82147
}
83-
84-
// loop
85148
}
86149

87150
pthread_mutex_lock(&event_thread->lock);
@@ -90,5 +153,7 @@ static void *event_thread_run(void *data) {
90153

91154
pthread_mutex_unlock(&event_thread->lock);
92155

156+
(*vm)->DetachCurrentThread(vm);
157+
93158
return NULL;
94159
}

Player/app/src/main/cpp/event_thread.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ struct event_thread {
1313

1414
int running;
1515

16-
mpv_handle *mpv;
16+
struct player_context *player_context;
1717
};
1818

19-
struct event_thread *event_thread_create(mpv_handle *mpv);
19+
struct event_thread *event_thread_create(struct player_context *player_context);
2020

2121
void event_thread_start(struct event_thread *event_thread);
2222

Player/app/src/main/cpp/player.c

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,22 @@
66

77
static struct player_context context = {0};
88

9-
int player_initialize(JNIEnv *env) {
9+
int player_initialize(JNIEnv *env, jobject core_instance) {
1010
// Requirement of mpv, see client.h
1111
setlocale(LC_NUMERIC, "C");
1212

1313
LOGI("Mpv client version %lx", mpv_client_api_version());
1414

15+
context.env = env;
1516
if ((*env)->GetJavaVM(env, &context.vm)) {
1617
LOGE("Failed to get java vm");
1718
return 1;
1819
}
1920

2021
av_jni_set_java_vm(context.vm, NULL);
2122

23+
context.core_instance = (*env)->NewGlobalRef(env, core_instance);
24+
2225
context.mpv = mpv_create();
2326
if (!context.mpv) {
2427
LOGE("Failed to create mpv handle");
@@ -34,14 +37,16 @@ int player_initialize(JNIEnv *env) {
3437
log_mpv_error("hwdec mediacodec", res);
3538
}*/
3639

37-
if (mpv_initialize(context.mpv)) {
38-
LOGE("Failed to initialize mpv");
40+
// mpv_request_log_messages(context.mpv, "info");
41+
mpv_request_log_messages(context.mpv, "v");
42+
43+
res = mpv_initialize(context.mpv);
44+
if (res < 0) {
45+
log_mpv_error("mpv_initialize()", res);
3946
return 1;
4047
}
4148

42-
mpv_request_log_messages(context.mpv, "info");
43-
44-
context.event_thread = event_thread_create(context.mpv);
49+
context.event_thread = event_thread_create(&context);
4550
event_thread_start(context.event_thread);
4651

4752
context.opengl_cb_context = mpv_get_sub_api(context.mpv, MPV_SUB_API_OPENGL_CB);
@@ -53,6 +58,12 @@ int player_initialize(JNIEnv *env) {
5358
return 0;
5459
}
5560

61+
void player_destroy() {
62+
// TODO: after the context is not global anymore
63+
JNIEnv *env = context.env;
64+
(*env)->DeleteGlobalRef(env, context.core_instance);
65+
}
66+
5667
int player_bind() {
5768
// Get the egl params and unbind them from this thread to give them to
5869
// the render thread
@@ -81,6 +92,13 @@ void player_unbind() {
8192
context.render_thread = NULL;
8293
}
8394

95+
void player_observe_property(uint64_t userdata, const char *name, mpv_format format) {
96+
mpv_observe_property(context.mpv, userdata, name, format);
97+
}
98+
8499
void player_handle_command(const char **command) {
85-
mpv_command(context.mpv, command);
100+
int res = mpv_command(context.mpv, command);
101+
if (res < 0) {
102+
log_mpv_error("mpv_command failed", res);
103+
}
86104
}

Player/app/src/main/cpp/player.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@
1414
#include "render_thread.h"
1515

1616
struct player_context {
17+
JNIEnv *env;
1718
JavaVM *vm;
19+
jobject core_instance;
1820

1921
mpv_handle *mpv;
2022
mpv_opengl_cb_context *opengl_cb_context;
@@ -23,12 +25,16 @@ struct player_context {
2325
struct render_thread *render_thread;
2426
};
2527

26-
int player_initialize(JNIEnv *env);
28+
int player_initialize(JNIEnv *env, jobject core_instance);
29+
30+
void player_destroy();
2731

2832
int player_bind();
2933

3034
void player_resize(int width, int height);
3135

3236
void player_unbind();
3337

38+
void player_observe_property(uint64_t userdata, const char *name, mpv_format format);
39+
3440
void player_handle_command(const char **command);
Lines changed: 83 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,65 @@
1+
#include "player.h"
2+
13
#include "player_interface.h"
24

3-
#include "player.h"
5+
// Interface that glues to the MpvCore class
6+
7+
static jmethodID nativeEventNoData;
8+
9+
static jmethodID nativeEventPropertyString;
10+
static jmethodID nativeEventPropertyFlag;
11+
static jmethodID nativeEventPropertyLong;
12+
static jmethodID nativeEventPropertyDouble;
13+
14+
void event_no_data(JNIEnv *env, jobject core_instance, const char *event_name) {
15+
jstring namestr = (*env)->NewStringUTF(env, event_name);
16+
(*env)->CallVoidMethod(env, core_instance, nativeEventNoData, namestr);
17+
(*env)->DeleteLocalRef(env, namestr);
18+
}
19+
20+
void event_property_string(JNIEnv *env, jobject core_instance, uint64_t userdata, const char *name, const char *data) {
21+
jstring namestr = (*env)->NewStringUTF(env, name);
22+
jstring datastr = (*env)->NewStringUTF(env, data);
23+
(*env)->CallVoidMethod(env, core_instance, nativeEventPropertyString, userdata, namestr, datastr);
24+
(*env)->DeleteLocalRef(env, namestr);
25+
(*env)->DeleteLocalRef(env, datastr);
26+
}
27+
28+
void event_property_flag(JNIEnv *env, jobject core_instance, uint64_t userdata, const char *name, int flag) {
29+
jstring namestr = (*env)->NewStringUTF(env, name);
30+
(*env)->CallVoidMethod(env, core_instance, nativeEventPropertyFlag, userdata, namestr, flag);
31+
(*env)->DeleteLocalRef(env, namestr);
32+
}
433

5-
JNIEXPORT jint JNICALL
6-
Java_org_floens_mpv_MpvCore_nativeInitialize(
7-
JNIEnv *env, jobject instance) {
8-
return player_initialize(env);
34+
void event_property_long(JNIEnv *env, jobject core_instance, uint64_t userdata, const char *name, int64_t value) {
35+
jstring namestr = (*env)->NewStringUTF(env, name);
36+
(*env)->CallVoidMethod(env, core_instance, nativeEventPropertyLong, userdata, namestr, value);
37+
(*env)->DeleteLocalRef(env, namestr);
938
}
1039

11-
JNIEXPORT int JNICALL
12-
Java_org_floens_mpv_MpvCore_nativeBind(
13-
JNIEnv *env, jobject instance) {
40+
void event_property_double(JNIEnv *env, jobject core_instance, uint64_t userdata, const char *name, double value) {
41+
jstring namestr = (*env)->NewStringUTF(env, name);
42+
(*env)->CallVoidMethod(env, core_instance, nativeEventPropertyDouble, userdata, namestr, value);
43+
(*env)->DeleteLocalRef(env, namestr);
44+
}
45+
46+
static jint JNICALL jni_native_initialize(JNIEnv *env, jobject instance) {
47+
return player_initialize(env, instance);
48+
}
49+
50+
static jint JNICALL jni_native_bind(JNIEnv *env, jobject instance) {
1451
return player_bind();
1552
}
1653

17-
JNIEXPORT void
18-
JNICALL Java_org_floens_mpv_MpvCore_nativeResize(
19-
JNIEnv *env, jobject instance, jint width, jint height) {
54+
static void JNICALL jni_native_resize(JNIEnv *env, jobject instance, jint width, jint height) {
2055
player_resize(width, height);
2156
}
2257

23-
JNIEXPORT void JNICALL
24-
Java_org_floens_mpv_MpvCore_nativeUnbind(
25-
JNIEnv *env, jobject instance) {
58+
static void JNICALL jni_native_unbind(JNIEnv *env, jobject instance) {
2659
player_unbind();
2760
}
2861

29-
JNIEXPORT void
30-
JNICALL Java_org_floens_mpv_MpvCore_nativeCommand(
31-
JNIEnv *env, jobject instance, jobjectArray array) {
62+
static void JNICALL jni_native_command(JNIEnv *env, jobject instance, jobjectArray array) {
3263
int length = (*env)->GetArrayLength(env, array);
3364

3465
const char *command[length + 1];
@@ -46,3 +77,38 @@ JNICALL Java_org_floens_mpv_MpvCore_nativeCommand(
4677
env, (*env)->GetObjectArrayElement(env, array, i), command[i]);
4778
}
4879
}
80+
81+
static void JNICALL jni_native_observe_property
82+
(JNIEnv *env, jobject instance, jlong userdata, jstring name, jint format) {
83+
uint64_t mpvuserdata = (uint64_t) userdata;
84+
const char *namestr = (*env)->GetStringUTFChars(env, name, 0);
85+
mpv_format mpvformat = (mpv_format) format;
86+
player_observe_property(mpvuserdata, namestr, mpvformat);
87+
(*env)->ReleaseStringUTFChars(env, name, namestr);
88+
}
89+
90+
static JNINativeMethod methods[] = {
91+
{"nativeInitialize", "()I", &jni_native_initialize},
92+
{"nativeBind", "()I", &jni_native_bind},
93+
{"nativeResize", "(II)V", &jni_native_resize},
94+
{"nativeUnbind", "()V", &jni_native_unbind},
95+
{"nativeCommand", "([Ljava/lang/String;)V", &jni_native_command},
96+
{"nativeObserveProperty", "(JLjava/lang/String;I)V", &jni_native_observe_property}
97+
};
98+
99+
JNIEXPORT void JNICALL Java_org_floens_mpv_MpvCore_registerNatives(JNIEnv *env, jclass cls) {
100+
(*env)->RegisterNatives(env, cls, methods, sizeof(methods) / sizeof(methods[0]));
101+
102+
nativeEventNoData =
103+
(*env)->GetMethodID(env, cls, "nativeEventNoData", "(Ljava/lang/String;)V");
104+
105+
nativeEventPropertyString =
106+
(*env)->GetMethodID(env, cls, "nativeEventPropertyString",
107+
"(JLjava/lang/String;Ljava/lang/String;)V");
108+
nativeEventPropertyFlag =
109+
(*env)->GetMethodID(env, cls, "nativeEventPropertyFlag", "(JLjava/lang/String;I)V");
110+
nativeEventPropertyLong =
111+
(*env)->GetMethodID(env, cls, "nativeEventPropertyLong", "(JLjava/lang/String;J)V");
112+
nativeEventPropertyDouble =
113+
(*env)->GetMethodID(env, cls, "nativeEventPropertyDouble", "(JLjava/lang/String;D)V");
114+
}

0 commit comments

Comments
 (0)