Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2007-2020
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / JavaScript Compositor extensions
9 : *
10 : * GPAC is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU Lesser General Public License as published by
12 : * the Free Software Foundation; either version 2, or (at your option)
13 : * any later version.
14 : *
15 : * GPAC is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU Lesser General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU Lesser General Public
21 : * License along with this library; see the file COPYING. If not, write to
22 : * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 : *
24 : */
25 :
26 :
27 : #include <gpac/setup.h>
28 :
29 : #if defined(GPAC_HAS_QJS) && !defined(GPAC_DISABLE_PLAYER)
30 :
31 : /*base SVG type*/
32 : #include <gpac/nodes_svg.h>
33 : #include <gpac/nodes_mpeg4.h>
34 : #include <gpac/nodes_x3d.h>
35 : /*dom events*/
36 : #include <gpac/events.h>
37 :
38 : #include <gpac/download.h>
39 : #include <gpac/network.h>
40 : #include <gpac/options.h>
41 : #include <gpac/xml.h>
42 :
43 :
44 : #include <gpac/internal/scenegraph_dev.h>
45 :
46 : #include "../scenegraph/qjs_common.h"
47 :
48 : #include <gpac/internal/compositor_dev.h>
49 : #include <gpac/term_info.h>
50 :
51 : typedef struct
52 : {
53 : GF_Compositor *compositor;
54 : JSValue evt_fun;
55 : GF_FSEventListener evt_filter;
56 : GF_Event *evt;
57 :
58 : JSContext *c;
59 : JSValue evt_filter_obj, evt_obj, scene_obj;
60 :
61 : GF_SystemRTInfo rti;
62 :
63 : //list of config files for storage
64 : GF_List *storages;
65 :
66 : GF_List *event_queue;
67 : GF_Mutex *event_mx;
68 :
69 : } GF_SCENEJSExt;
70 :
71 : enum {
72 : GJS_OM_PROP_ID=1,
73 : GJS_OM_PROP_NB_RES,
74 : GJS_OM_PROP_URL,
75 : GJS_OM_PROP_DUR,
76 : GJS_OM_PROP_CLOCK,
77 : GJS_OM_PROP_DRIFT,
78 : GJS_OM_PROP_STATUS,
79 : GJS_OM_PROP_BUFFER,
80 : GJS_OM_PROP_DB_COUNT,
81 : GJS_OM_PROP_CB_COUNT,
82 : GJS_OM_PROP_CB_CAP,
83 : GJS_OM_PROP_TYPE,
84 : GJS_OM_PROP_SAMPLERATE,
85 : GJS_OM_PROP_CHANNELS,
86 : GJS_OM_PROP_LANG,
87 : GJS_OM_PROP_WIDTH,
88 : GJS_OM_PROP_HEIGHT,
89 : GJS_OM_PROP_PIXELFORMAT,
90 : GJS_OM_PROP_PAR,
91 : GJS_OM_PROP_DEC_FRAMES,
92 : GJS_OM_PROP_DROP_FRAMES,
93 : GJS_OM_PROP_DEC_TIME_MAX,
94 : GJS_OM_PROP_DEC_TIME_TOTAL,
95 : GJS_OM_PROP_AVG_RATE,
96 : GJS_OM_PROP_MAX_RATE,
97 : GJS_OM_PROP_SERVICE_HANDLER,
98 : GJS_OM_PROP_CODEC,
99 : GJS_OM_PROP_NB_QUALITIES,
100 : GJS_OM_PROP_MAX_BUFFER,
101 : GJS_OM_PROP_MIN_BUFFER,
102 : GJS_OM_PROP_FRAME_DUR,
103 : GJS_OM_PROP_NB_IRAP,
104 : GJS_OM_PROP_IRAP_DEC_TIME,
105 : GJS_OM_PROP_IRAP_MAX_TIME,
106 : GJS_OM_PROP_SERVICE_ID,
107 : GJS_OM_PROP_SELECTED_SERVICE,
108 : GJS_OM_PROP_BANDWIDTH_DOWN,
109 : GJS_OM_PROP_NB_HTTP,
110 : GJS_OM_PROP_TIMESHIFT_DEPTH,
111 : GJS_OM_PROP_TIMESHIFT_TIME,
112 : GJS_OM_PROP_IS_ADDON,
113 : GJS_OM_PROP_MAIN_ADDON_ON,
114 : GJS_OM_PROP_IS_OVER,
115 : GJS_OM_PROP_IS_VR_SCENE,
116 : GJS_OM_PROP_DYNAMIC_SCENE,
117 : GJS_OM_PROP_SERVICE_NAME,
118 : GJS_OM_PROP_NTP_DIFF,
119 : GJS_OM_PROP_MAIN_ADDON_URL,
120 : GJS_OM_PROP_REVERSE_PLAYBACK,
121 : GJS_OM_PROP_SCALABLE_ENHANCEMENT,
122 : GJS_OM_PROP_MAIN_ADDON_MEDIATIME,
123 : GJS_OM_PROP_DEPENDENT_GROUPS,
124 : GJS_OM_PROP_DISABLED,
125 : GJS_OM_PROP_NTP_SENDER_DIFF,
126 : GJS_OM_PROP_BUFFERING,
127 : };
128 :
129 : enum {
130 : GJS_SCENE_PROP_FULLSCREEN=1,
131 : GJS_SCENE_PROP_CURRENT_PATH,
132 : GJS_SCENE_PROP_VOLUME,
133 : GJS_SCENE_PROP_NAVIGATION,
134 : GJS_SCENE_PROP_NAVIGATION_TYPE,
135 : GJS_SCENE_PROP_HARDWARE_YUV,
136 : GJS_SCENE_PROP_HARDWARE_RGB,
137 : GJS_SCENE_PROP_HARDWARE_RGBA,
138 : GJS_SCENE_PROP_HARDWARE_STRETCH,
139 : GJS_SCENE_PROP_SCREEN_WIDTH,
140 : GJS_SCENE_PROP_SCREEN_HEIGHT,
141 : GJS_SCENE_PROP_FPS,
142 : GJS_SCENE_PROP_CAPTION,
143 : GJS_SCENE_PROP_FOCUS_HIGHLIGHT,
144 : GJS_SCENE_PROP_DPI_X,
145 : GJS_SCENE_PROP_DPI_Y,
146 : GJS_SCENE_PROP_SENSORS_ACTIVE,
147 : GJS_SCENE_PROP_SIM_FPS,
148 : GJS_SCENE_PROP_HAS_OPENGL,
149 : GJS_SCENE_PROP_ZOOM,
150 : GJS_SCENE_PROP_TEXT_SEL,
151 :
152 : };
153 :
154 : enum {
155 : GJS_EVT_PROP_KEYCODE = 1,
156 : GJS_EVT_PROP_MOUSE_X,
157 : GJS_EVT_PROP_MOUSE_Y,
158 : GJS_EVT_PROP_PICKED,
159 : GJS_EVT_PROP_WHEEL,
160 : GJS_EVT_PROP_BUTTON,
161 : GJS_EVT_PROP_TYPE,
162 : GJS_EVT_PROP_NAME,
163 : GJS_EVT_PROP_HWKEY,
164 : GJS_EVT_PROP_TARGET_URL,
165 : GJS_EVT_PROP_FILES,
166 : };
167 :
168 : static JSClassID scene_class_id = 0;
169 : static JSClassID odm_class_id = 0;
170 : static JSClassID gpacevt_class_id = 0;
171 : static JSClassID any_class_id = 0;
172 :
173 : static void scenejs_finalize(JSRuntime *rt, JSValue obj);
174 :
175 40 : static void scenejs_gc_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func)
176 : {
177 40 : GF_SCENEJSExt *ext = JS_GetOpaque(val, scene_class_id);
178 40 : if (ext) {
179 40 : JS_MarkValue(rt, ext->evt_fun, mark_func);
180 : }
181 40 : }
182 :
183 : JSClassDef sceneClass = {
184 : "JSSCENE",
185 : .finalizer = scenejs_finalize,
186 : .gc_mark = scenejs_gc_mark
187 : };
188 : JSClassDef gpacEvtClass = {
189 : "GPACEVT"
190 : };
191 : JSClassDef odmClass = {
192 : "MediaObject"
193 : };
194 : JSClassDef anyClass = {
195 : "GPACOBJECT"
196 : };
197 :
198 :
199 : static GF_Compositor *scenejs_get_compositor(JSContext *c, JSValue obj)
200 : {
201 68 : GF_SCENEJSExt *ext = JS_GetOpaque(obj, scene_class_id);
202 68 : return ext ? ext->compositor : NULL;
203 : }
204 :
205 176 : static JSValue scenejs_getProperty(JSContext *ctx, JSValueConst this_val, int prop_id)
206 : {
207 : Bool bval;
208 : JSValue ret;
209 : char *str;
210 176 : GF_SCENEJSExt *ext = JS_GetOpaque(this_val, scene_class_id);
211 176 : GF_Compositor *compositor = ext ? ext->compositor : NULL;
212 176 : if (!ext || !compositor) return JS_EXCEPTION;
213 :
214 176 : switch (prop_id) {
215 :
216 122 : case GJS_SCENE_PROP_FULLSCREEN:
217 122 : return JS_NewBool(ctx, compositor->fullscreen);
218 :
219 3 : case GJS_SCENE_PROP_CURRENT_PATH:
220 3 : str = gf_url_concatenate(compositor->root_scene->root_od->scene_ns->url, "");
221 3 : if (!str) str = gf_strdup("");
222 3 : ret = JS_NewString(ctx, str);
223 3 : gf_free(str);
224 3 : return ret;
225 :
226 34 : case GJS_SCENE_PROP_VOLUME:
227 34 : return JS_NewInt32(ctx, gf_sc_get_option(compositor, GF_OPT_AUDIO_VOLUME));
228 :
229 0 : case GJS_SCENE_PROP_NAVIGATION:
230 0 : return JS_NewInt32(ctx, gf_sc_get_option(compositor, GF_OPT_NAVIGATION));
231 :
232 0 : case GJS_SCENE_PROP_NAVIGATION_TYPE:
233 0 : return JS_NewInt32(ctx, gf_sc_get_option(compositor, GF_OPT_NAVIGATION_TYPE) );
234 :
235 0 : case GJS_SCENE_PROP_HARDWARE_YUV:
236 0 : return JS_NewBool(ctx, (compositor->video_out->hw_caps & GF_VIDEO_HW_HAS_YUV) ? 1 : 0 );
237 :
238 0 : case GJS_SCENE_PROP_HARDWARE_RGB:
239 0 : return JS_NewBool(ctx, (compositor->video_out->hw_caps & GF_VIDEO_HW_HAS_RGB) ? 1 : 0 );
240 :
241 0 : case GJS_SCENE_PROP_HARDWARE_RGBA:
242 0 : bval = (compositor->video_out->hw_caps & GF_VIDEO_HW_HAS_RGBA) ? 1 : 0;
243 : #ifndef GPAC_DISABLE_3D
244 0 : if (compositor->hybrid_opengl || compositor->is_opengl) bval = 1;
245 : #endif
246 : return JS_NewBool(ctx, bval);
247 :
248 0 : case GJS_SCENE_PROP_HARDWARE_STRETCH:
249 0 : return JS_NewBool(ctx, (compositor->video_out->hw_caps & GF_VIDEO_HW_HAS_STRETCH) ? 1 : 0 );
250 :
251 3 : case GJS_SCENE_PROP_SCREEN_WIDTH:
252 3 : if (compositor->osize.x)
253 : return JS_NewInt32(ctx, compositor->osize.x);
254 3 : return JS_NewInt32(ctx, compositor->video_out->max_screen_width);
255 :
256 3 : case GJS_SCENE_PROP_SCREEN_HEIGHT:
257 3 : if (compositor->osize.y)
258 : return JS_NewInt32(ctx, compositor->osize.y);
259 3 : return JS_NewInt32(ctx, compositor->video_out->max_screen_height);
260 :
261 :
262 4 : case GJS_SCENE_PROP_FPS:
263 4 : return JS_NewFloat64(ctx, gf_sc_get_fps(compositor, 0) );
264 :
265 2 : case GJS_SCENE_PROP_SIM_FPS:
266 2 : return JS_NewFloat64(ctx, ((Double)compositor->fps.den)/compositor->fps.num);
267 :
268 3 : case GJS_SCENE_PROP_HAS_OPENGL:
269 3 : return JS_NewBool(ctx, (compositor->ogl != GF_SC_GLMODE_OFF) ? 1 : 0);
270 :
271 0 : case GJS_SCENE_PROP_DPI_X:
272 0 : return JS_NewInt32(ctx, compositor->video_out->dpi_x);
273 :
274 0 : case GJS_SCENE_PROP_DPI_Y:
275 0 : return JS_NewInt32(ctx, compositor->video_out->dpi_y);
276 :
277 0 : case GJS_SCENE_PROP_SENSORS_ACTIVE:
278 0 : return JS_NewBool(ctx, compositor->orientation_sensors_active);
279 :
280 1 : case GJS_SCENE_PROP_ZOOM:
281 1 : if (compositor->root_scene && compositor->root_scene->graph->script_action) {
282 : GF_JSAPIParam jspar;
283 : memset(&jspar, 0, sizeof(GF_JSAPIParam));
284 1 : compositor->root_scene->graph->script_action(compositor->root_scene->graph->script_action_cbck, GF_JSAPI_OP_GET_SCALE, NULL, &jspar);
285 : #ifdef GPAC_ENABLE_COVERAGE
286 1 : if (gf_sys_is_cov_mode()) {
287 1 : compositor->root_scene->graph->script_action(compositor->root_scene->graph->script_action_cbck, GF_JSAPI_OP_GET_VIEWPORT, NULL, &jspar);
288 : }
289 : #endif
290 1 : return JS_NewFloat64(ctx, FIX2FLT(jspar.val) );
291 : } else {
292 : return JS_NewFloat64(ctx, 1.0 );
293 : }
294 : break;
295 1 : case GJS_SCENE_PROP_TEXT_SEL:
296 1 : str = (char *) gf_sc_get_selected_text(compositor);
297 1 : if (!str) str = "";
298 1 : return JS_NewString(ctx, str);
299 : }
300 0 : return JS_UNDEFINED;
301 : }
302 :
303 :
304 7 : static JSValue scenejs_setProperty(JSContext *ctx, JSValueConst this_val, JSValueConst value, int magic)
305 : {
306 : #ifndef GPAC_CONFIG_IOS
307 : Bool bval;
308 : #endif
309 : s32 ival;
310 : Double dval;
311 : const char *prop_val;
312 7 : GF_SCENEJSExt *ext = JS_GetOpaque(this_val, scene_class_id);
313 7 : GF_Compositor *compositor = ext ? ext->compositor : NULL;
314 7 : if (!ext || !compositor) return JS_EXCEPTION;
315 :
316 7 : switch (magic) {
317 4 : case GJS_SCENE_PROP_CAPTION:
318 : {
319 : GF_Event evt;
320 4 : if (!JS_IsString(value)) return JS_EXCEPTION;
321 : prop_val = JS_ToCString(ctx, value);
322 4 : evt.type = GF_EVENT_SET_CAPTION;
323 4 : if (prop_val && !strnicmp(prop_val, "gpac://", 7)) {
324 0 : evt.caption.caption = prop_val + 7;
325 : } else {
326 4 : evt.caption.caption = prop_val;
327 : }
328 4 : gf_sc_user_event(compositor, &evt);
329 4 : JS_FreeCString(ctx, prop_val);
330 : }
331 4 : break;
332 0 : case GJS_SCENE_PROP_FULLSCREEN:
333 : /*no fullscreen for iOS (always on)*/
334 : #ifndef GPAC_CONFIG_IOS
335 0 : bval = JS_ToBool(ctx, value);
336 0 : if (compositor->fullscreen != bval) {
337 0 : gf_sc_set_option(compositor, GF_OPT_FULLSCREEN, bval);
338 : }
339 : #endif
340 : break;
341 0 : case GJS_SCENE_PROP_VOLUME:
342 0 : if (!JS_ToFloat64(ctx, &dval, value)) {
343 0 : gf_sc_set_option(compositor, GF_OPT_AUDIO_VOLUME, (u32) dval);
344 0 : } else if (!JS_ToInt32(ctx, &ival, value)) {
345 0 : gf_sc_set_option(compositor, GF_OPT_AUDIO_VOLUME, (u32) ival);
346 : }
347 : break;
348 :
349 0 : case GJS_SCENE_PROP_NAVIGATION:
350 0 : if (JS_ToInt32(ctx, &ival, value)) return JS_EXCEPTION;
351 0 : gf_sc_set_option(compositor, GF_OPT_NAVIGATION, (u32) ival);
352 0 : break;
353 0 : case GJS_SCENE_PROP_NAVIGATION_TYPE:
354 0 : gf_sc_set_option(compositor, GF_OPT_NAVIGATION_TYPE, 0);
355 0 : break;
356 3 : case GJS_SCENE_PROP_FOCUS_HIGHLIGHT:
357 3 : compositor->disable_focus_highlight = JS_ToBool(ctx, value);
358 3 : break;
359 0 : case GJS_SCENE_PROP_SENSORS_ACTIVE:
360 : {
361 : GF_Event evt;
362 0 : compositor->orientation_sensors_active = JS_ToBool(ctx, value);
363 : //send activation for sensors
364 : memset(&evt, 0, sizeof(GF_Event));
365 0 : evt.type = GF_EVENT_SENSOR_REQUEST;
366 0 : evt.activate_sensor.activate = compositor->orientation_sensors_active;
367 0 : evt.activate_sensor.sensor_type = GF_EVENT_SENSOR_ORIENTATION;
368 0 : if (gf_sc_send_event(compositor, &evt) == GF_FALSE) {
369 0 : compositor->orientation_sensors_active = GF_FALSE;
370 : }
371 : }
372 0 : break;
373 : }
374 7 : return JS_UNDEFINED;
375 : }
376 :
377 15 : static JSValue scenejs_get_option(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
378 : {
379 : const char *opt = NULL;
380 : const char *sec_name, *key_name;
381 : char arg_val[GF_PROP_DUMP_ARG_SIZE];
382 15 : s32 idx = -1;
383 : GF_Compositor *compositor = scenejs_get_compositor(ctx, this_val);
384 15 : if (!compositor) return JS_EXCEPTION;
385 15 : if (argc < 2) return JS_EXCEPTION;
386 30 : if (!JS_IsString(argv[0])) return JS_EXCEPTION;
387 30 : if (!JS_IsString(argv[1]) && !JS_IsNumber(argv[1])) return JS_EXCEPTION;
388 :
389 : sec_name = JS_ToCString(ctx, argv[0]);
390 : key_name = NULL;
391 30 : if (JS_IsNumber(argv[1])) {
392 0 : JS_ToInt32(ctx, &idx, argv[1]);
393 15 : } else if (JS_IsString(argv[1]) ) {
394 : key_name = JS_ToCString(ctx, argv[1]);
395 : }
396 :
397 15 : if (sec_name && !stricmp(sec_name, "General") && key_name && !strcmp(key_name, "Version")) {
398 0 : opt = gf_gpac_version();
399 15 : } else if (sec_name && key_name) {
400 15 : if (!strcmp(sec_name, "Compositor")) {
401 0 : opt = gf_filter_get_arg_str(compositor->filter, key_name, arg_val);
402 : } else {
403 15 : opt = gf_opts_get_key(sec_name, key_name);
404 : }
405 0 : } else if (sec_name && (idx>=0)) {
406 0 : opt = gf_opts_get_key_name(sec_name, idx);
407 : } else {
408 : opt = NULL;
409 : }
410 :
411 15 : JS_FreeCString(ctx, key_name);
412 15 : JS_FreeCString(ctx, sec_name);
413 :
414 15 : if (opt) {
415 3 : return JS_NewString(ctx, opt);
416 : }
417 12 : return JS_NULL;
418 : }
419 :
420 8 : static JSValue scenejs_set_option(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
421 : {
422 : const char *sec_name, *key_name, *key_val;
423 : GF_Compositor *compositor = scenejs_get_compositor(ctx, this_val);
424 8 : if (!compositor) return JS_EXCEPTION;
425 8 : if (argc < 3) return JS_EXCEPTION;
426 16 : if (!JS_IsString(argv[0])) return JS_EXCEPTION;
427 16 : if (!JS_IsString(argv[1])) return JS_EXCEPTION;
428 :
429 : sec_name = JS_ToCString(ctx, argv[0]);
430 : key_name = JS_ToCString(ctx, argv[1]);
431 : key_val = NULL;
432 16 : if (JS_IsString(argv[2]))
433 : key_val = JS_ToCString(ctx, argv[2]);
434 :
435 8 : if (!strcmp(sec_name, "Compositor")) {
436 0 : gf_filter_send_update(compositor->filter, NULL, key_name, key_val, 0);
437 : } else {
438 8 : gf_opts_set_key(sec_name, key_name, key_val);
439 : }
440 8 : JS_FreeCString(ctx, sec_name);
441 8 : JS_FreeCString(ctx, key_name);
442 8 : if (key_val) {
443 8 : JS_FreeCString(ctx, key_val);
444 : }
445 8 : return JS_UNDEFINED;
446 : }
447 :
448 :
449 4 : static JSValue scenejs_set_back_color(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
450 : {
451 : u32 r, g, b, a, i;
452 : GF_Compositor *compositor = scenejs_get_compositor(ctx, this_val);
453 4 : if (!compositor) return JS_EXCEPTION;
454 4 : if (argc < 3) return JS_EXCEPTION;
455 : r = g = b = 0;
456 : a = 255;
457 16 : for (i=0; i<(u32) argc; i++) {
458 : Double d;
459 : u32 v;
460 16 : if (! JS_ToFloat64(ctx, &d, argv[i])) {
461 : } else {
462 0 : return JS_EXCEPTION;
463 : }
464 16 : d*=255;
465 : v = 0;
466 16 : if (d>0) {
467 13 : v = (u32) d;
468 13 : if (v>255) v = 255;
469 : }
470 16 : if (i==0) r = v;
471 12 : else if (i==1) g = v;
472 8 : else if (i==2) b = v;
473 4 : else if (i==3) a = v;
474 : }
475 4 : compositor->back_color = compositor->bc = GF_COL_ARGB(a, r, g, b);
476 4 : gf_sc_invalidate(compositor, NULL);
477 4 : return JS_UNDEFINED;
478 : }
479 :
480 :
481 1 : static JSValue scenejs_switch_quality(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
482 : {
483 : GF_Compositor *compositor = scenejs_get_compositor(ctx, this_val);
484 1 : if (!compositor) return JS_EXCEPTION;
485 1 : if (argc < 1) return JS_EXCEPTION;
486 :
487 2 : if (!JS_IsBool(argv[0]))
488 0 : return JS_EXCEPTION;
489 1 : Bool up = JS_ToBool(ctx, argv[0]) ? GF_TRUE : GF_FALSE;
490 1 : gf_scene_switch_quality(compositor->root_scene, up);
491 1 : return JS_UNDEFINED;
492 : }
493 :
494 :
495 : #if 0 //unused
496 : static JSValue scenejs_reload(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
497 : {
498 : GF_Event evt;
499 : GF_Compositor *compositor = scenejs_get_compositor(ctx, this_val);
500 : if (!compositor) return JS_EXCEPTION;
501 :
502 : memset(&evt, 0, sizeof(GF_Event));
503 : evt.type = GF_EVENT_RELOAD;
504 : gf_filter_ui_event(compositor->filter, &evt);
505 : return JS_UNDEFINED;
506 : }
507 : #endif
508 :
509 1 : static JSValue scenejs_navigation_supported(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
510 : {
511 : u32 type;
512 : GF_Compositor *compositor = scenejs_get_compositor(ctx, this_val);
513 1 : if (!compositor) return JS_EXCEPTION;
514 1 : if (argc < 1) return JS_EXCEPTION;
515 :
516 2 : if (! JS_IsInteger(argv[0]) ) {
517 : return JS_NewBool(ctx, 0);
518 : }
519 1 : if (JS_ToInt32(ctx, &type, argv[0]))
520 0 : return JS_EXCEPTION;
521 1 : return JS_NewBool(ctx, gf_sc_navigation_supported(compositor, type) ? 1 : 0 );
522 : }
523 :
524 13 : static JSValue scenejs_set_size(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
525 : {
526 : Bool override_size_info = 0;
527 : u32 w, h;
528 : GF_Compositor *compositor = scenejs_get_compositor(ctx, this_val);
529 13 : if (!compositor) return JS_EXCEPTION;
530 13 : if (argc<2) return JS_EXCEPTION;
531 :
532 13 : w = h = 0;
533 13 : if (JS_ToInt32(ctx, &w, argv[0]))
534 0 : return JS_EXCEPTION;
535 13 : if (JS_ToInt32(ctx, &h, argv[1]))
536 0 : return JS_EXCEPTION;
537 :
538 13 : if (argc > 2)
539 2 : override_size_info = JS_ToBool(ctx, argv[2]);
540 :
541 24 : if (w && h) {
542 : GF_Event evt;
543 13 : if (override_size_info) {
544 2 : compositor->scene_width = w;
545 2 : compositor->scene_height = h;
546 2 : compositor->has_size_info = 1;
547 2 : compositor->recompute_ar = 1;
548 2 : return JS_UNDEFINED;
549 : }
550 11 : if (compositor->os_wnd) {
551 0 : evt.type = GF_EVENT_SCENE_SIZE;
552 0 : evt.size.width = w;
553 0 : evt.size.height = h;
554 0 : gf_sc_send_event(compositor, &evt);
555 : } else {
556 11 : gf_sc_set_size(compositor, w, h);
557 : }
558 0 : } else if (override_size_info) {
559 0 : compositor->has_size_info = 0;
560 0 : compositor->recompute_ar = 1;
561 : }
562 :
563 11 : return JS_UNDEFINED;
564 : }
565 :
566 :
567 1 : static JSValue scenejs_exit(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
568 : {
569 : GF_Event evt;
570 : GF_Compositor *compositor = scenejs_get_compositor(ctx, this_val);
571 : memset(&evt, 0, sizeof(GF_Event));
572 1 : evt.type = GF_EVENT_QUIT;
573 1 : if (argc)
574 1 : JS_ToInt32(ctx, (s32 *) &evt.message.error, argv[0]);
575 :
576 1 : gf_sc_send_event(compositor, &evt);
577 1 : return JS_UNDEFINED;
578 : }
579 :
580 1 : static JSValue scenejs_set_3d(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
581 : {
582 : Bool type_3d;
583 : GF_Compositor *compositor = scenejs_get_compositor(ctx, this_val);
584 1 : if (!argc) return JS_EXCEPTION;
585 1 : type_3d = JS_ToBool(ctx, argv[0]);
586 :
587 1 : if (compositor->inherit_type_3d != type_3d) {
588 0 : compositor->inherit_type_3d = type_3d;
589 0 : compositor->root_visual_setup = 0;
590 0 : gf_sc_reset_graphics(compositor);
591 : }
592 1 : return JS_UNDEFINED;
593 : }
594 :
595 1 : static JSValue scenejs_move_window(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
596 : {
597 : GF_Event evt;
598 : GF_Compositor *compositor = scenejs_get_compositor(ctx, this_val);
599 1 : if (argc < 2) return JS_EXCEPTION;
600 :
601 1 : evt.type = GF_EVENT_MOVE;
602 1 : evt.move.relative = 1;
603 1 : if (JS_ToInt32(ctx, &evt.move.x, argv[0]))
604 0 : return JS_EXCEPTION;
605 1 : if (JS_ToInt32(ctx, &evt.move.y, argv[1]))
606 0 : return JS_EXCEPTION;
607 :
608 1 : if (argc ==3) {
609 1 : evt.move.relative = JS_ToBool(ctx, argv[2]);
610 : }
611 1 : compositor->video_out->ProcessEvent(compositor->video_out, &evt);
612 1 : return JS_UNDEFINED;
613 : }
614 :
615 :
616 : #if 0 //unused
617 : static JSValue scenejs_get_scene_time(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
618 : {
619 : GF_SceneGraph *sg = NULL;
620 : GF_Compositor *compositor = scenejs_get_compositor(ctx, this_val);
621 : if (!compositor) return JS_EXCEPTION;
622 :
623 : if (!argc || !JS_IsObject(argv[0]) ) {
624 : sg = compositor->root_scene->graph;
625 : } else {
626 : GF_Node *n = gf_sg_js_get_node(c, JSVAL_TO_OBJECT(argv[0]));
627 : sg = n ? n->sgprivate->scenegraph : compositor->root_scene->graph;
628 : }
629 : return JS_NewFloat64(ctx, sg->GetSceneTime(sg->userpriv) );
630 : }
631 : #endif
632 :
633 2 : static JSValue scenejs_trigger_gc(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
634 : {
635 : GF_SceneGraph *sg;
636 : GF_Compositor *compositor = scenejs_get_compositor(ctx, this_val);
637 2 : sg = compositor->root_scene->graph;
638 2 : sg->trigger_gc = GF_TRUE;
639 2 : return JS_UNDEFINED;
640 : }
641 :
642 2 : static GF_FilterPid *gjs_enum_pids(void *udta, u32 *idx)
643 : {
644 : GF_Scene *scene = (GF_Scene *)udta;
645 2 : GF_ObjectManager *odm = gf_list_get(scene->resources, *idx);
646 2 : if (odm) return odm->pid;
647 : return NULL;
648 : }
649 :
650 154 : static JSValue odm_getProperty(JSContext *ctx, JSValueConst this_val, int magic)
651 : {
652 154 : GF_ObjectManager *odm = JS_GetOpaque(this_val, odm_class_id);
653 : GF_MediaInfo odi;
654 : char *str;
655 : GF_Scene *scene;
656 : Double dval;
657 : u32 i, count;
658 :
659 154 : switch (magic) {
660 0 : case GJS_OM_PROP_ID:
661 0 : return JS_NewInt32(ctx, odm->ID);
662 15 : case GJS_OM_PROP_NB_RES:
663 15 : return JS_NewInt32(ctx, odm->subscene ? gf_list_count(odm->subscene->resources) : 0);
664 4 : case GJS_OM_PROP_URL:
665 4 : if (odm->scene_ns)
666 4 : return JS_NewString(ctx, odm->scene_ns->url);
667 0 : return JS_NULL;
668 0 : case GJS_OM_PROP_DUR:
669 0 : return JS_NewFloat64(ctx, odm->duration / 1000.0);
670 0 : case GJS_OM_PROP_CLOCK:
671 0 : gf_odm_get_object_info(odm, &odi);
672 0 : return JS_NewFloat64(ctx, odi.current_time);
673 0 : case GJS_OM_PROP_DRIFT:
674 0 : gf_odm_get_object_info(odm, &odi);
675 0 : return JS_NewInt32(ctx, odi.clock_drift);
676 4 : case GJS_OM_PROP_STATUS:
677 4 : gf_odm_get_object_info(odm, &odi);
678 4 : if (odi.status==0) str = "Stopped";
679 4 : else if (odi.status==1) str = "Playing";
680 1 : else if (odi.status==2) str = "Paused";
681 0 : else if (odi.status==3) str = "Not Setup";
682 : else str = "Setup Failed";
683 4 : return JS_NewString(ctx, str);
684 8 : case GJS_OM_PROP_BUFFER:
685 8 : gf_odm_get_object_info(odm, &odi);
686 8 : return JS_NewInt32(ctx, odi.buffer);
687 0 : case GJS_OM_PROP_DB_COUNT:
688 0 : gf_odm_get_object_info(odm, &odi);
689 0 : return JS_NewInt32(ctx, odi.db_unit_count);
690 0 : case GJS_OM_PROP_CB_COUNT:
691 0 : gf_odm_get_object_info(odm, &odi);
692 0 : return JS_NewInt32(ctx, odi.cb_unit_count);
693 0 : case GJS_OM_PROP_CB_CAP:
694 0 : gf_odm_get_object_info(odm, &odi);
695 0 : return JS_NewInt32(ctx, odi.cb_max_count);
696 9 : case GJS_OM_PROP_TYPE:
697 9 : if (odm->type==GF_STREAM_SCENE) str = "Scene";
698 9 : else if (odm->type==GF_STREAM_OD) str = "OD";
699 9 : else if (odm->type==GF_STREAM_VISUAL) str = "Video";
700 0 : else if (odm->type==GF_STREAM_AUDIO) str = "Audio";
701 0 : else if (odm->type==GF_STREAM_TEXT) str = "Text";
702 0 : else if (odm->subscene) str = "Subscene";
703 0 : else str = (char*) gf_stream_type_name(odm->type);
704 9 : return JS_NewString(ctx, str);
705 0 : case GJS_OM_PROP_SAMPLERATE:
706 0 : return JS_NewInt32(ctx, odm->mo ? odm->mo->sample_rate : 0);
707 0 : case GJS_OM_PROP_CHANNELS:
708 0 : return JS_NewInt32(ctx, odm->mo ? odm->mo->num_channels : 0);
709 0 : case GJS_OM_PROP_LANG:
710 0 : gf_odm_get_object_info(odm, &odi);
711 0 : return JS_NewString(ctx, odi.lang_code ? odi.lang_code : gf_4cc_to_str(odi.lang) );
712 10 : case GJS_OM_PROP_WIDTH:
713 10 : return JS_NewInt32(ctx, odm->mo ? odm->mo->width : 0);
714 5 : case GJS_OM_PROP_HEIGHT:
715 5 : return JS_NewInt32(ctx, odm->mo ? odm->mo->height : 0);
716 0 : case GJS_OM_PROP_PIXELFORMAT:
717 0 : return JS_NewString(ctx, odm->mo ? gf_4cc_to_str(odm->mo->pixelformat) : "none");
718 0 : case GJS_OM_PROP_PAR:
719 0 : if (odm->mo && odm->mo->pixel_ar) {
720 : char szPar[50];
721 0 : sprintf(szPar, "%d:%d", (odm->mo->pixel_ar>>16)&0xFF, (odm->mo->pixel_ar)&0xFF );
722 0 : return JS_NewString(ctx, szPar);
723 0 : } else if (odm->mo && odm->mo->width) {
724 0 : return JS_NewString(ctx, "1:1");
725 : }
726 0 : return JS_NULL;
727 0 : case GJS_OM_PROP_DEC_FRAMES:
728 0 : gf_odm_get_object_info(odm, &odi);
729 0 : return JS_NewInt32(ctx, odi.nb_dec_frames);
730 0 : case GJS_OM_PROP_DROP_FRAMES:
731 0 : gf_odm_get_object_info(odm, &odi);
732 0 : return JS_NewInt32(ctx, odi.nb_dropped);
733 0 : case GJS_OM_PROP_DEC_TIME_MAX:
734 0 : gf_odm_get_object_info(odm, &odi);
735 0 : return JS_NewInt32(ctx, odi.max_dec_time);
736 0 : case GJS_OM_PROP_DEC_TIME_TOTAL:
737 0 : gf_odm_get_object_info(odm, &odi);
738 0 : return JS_NewInt64(ctx, odi.total_dec_time);
739 4 : case GJS_OM_PROP_AVG_RATE:
740 4 : gf_odm_get_object_info(odm, &odi);
741 4 : return JS_NewInt32(ctx, odi.avg_bitrate);
742 0 : case GJS_OM_PROP_MAX_RATE:
743 0 : gf_odm_get_object_info(odm, &odi);
744 0 : return JS_NewInt32(ctx, odi.max_bitrate);
745 0 : case GJS_OM_PROP_SERVICE_HANDLER:
746 0 : gf_odm_get_object_info(odm, &odi);
747 0 : return JS_NewString(ctx, odi.service_handler ? odi.service_handler : "unloaded");
748 0 : case GJS_OM_PROP_CODEC:
749 0 : gf_odm_get_object_info(odm, &odi);
750 0 : return JS_NewString(ctx, odi.codec_name ? odi.codec_name : "unloaded");
751 20 : case GJS_OM_PROP_NB_QUALITIES:
752 : //use HAS qualities
753 20 : if (odm->pid) {
754 : u32 nb_qualities = 0;
755 20 : GF_PropertyEntry *pe=NULL;
756 20 : const GF_PropertyValue *prop = gf_filter_pid_get_info_str(odm->pid, "has:qualities", &pe);
757 20 : if (prop) nb_qualities = prop->value.string_list.nb_items;
758 20 : gf_filter_release_property(pe);
759 :
760 20 : if (nb_qualities)
761 40 : return JS_NewInt32(ctx, nb_qualities);
762 : }
763 : //use input channels
764 0 : if (odm->extra_pids) {
765 0 : return JS_NewInt32(ctx, 1 + gf_list_count(odm->extra_pids));
766 : }
767 : //use number of scalable addons
768 0 : if (odm->upper_layer_odm) {
769 : count = 0;
770 0 : while (odm) {
771 0 : odm = odm->upper_layer_odm;
772 0 : count++;
773 : }
774 0 : return JS_NewInt32(ctx, count);
775 : }
776 : return JS_NewInt32(ctx, 1);
777 :
778 9 : case GJS_OM_PROP_MAX_BUFFER:
779 9 : gf_odm_get_object_info(odm, &odi);
780 9 : return JS_NewInt32(ctx, odi.max_buffer);
781 0 : case GJS_OM_PROP_MIN_BUFFER:
782 0 : gf_odm_get_object_info(odm, &odi);
783 0 : return JS_NewInt32(ctx, odi.min_buffer);
784 0 : case GJS_OM_PROP_FRAME_DUR:
785 0 : gf_odm_get_object_info(odm, &odi);
786 0 : return JS_NewInt32(ctx, odi.au_duration);
787 0 : case GJS_OM_PROP_NB_IRAP:
788 0 : gf_odm_get_object_info(odm, &odi);
789 0 : return JS_NewInt32(ctx, odi.nb_iraps);
790 0 : case GJS_OM_PROP_IRAP_DEC_TIME:
791 0 : gf_odm_get_object_info(odm, &odi);
792 0 : return JS_NewInt64(ctx, odi.irap_total_dec_time);
793 0 : case GJS_OM_PROP_IRAP_MAX_TIME:
794 0 : gf_odm_get_object_info(odm, &odi);
795 0 : return JS_NewInt32(ctx, odi.irap_max_dec_time);
796 6 : case GJS_OM_PROP_SERVICE_ID:
797 6 : return JS_NewInt32(ctx, odm->ServiceID);
798 4 : case GJS_OM_PROP_SELECTED_SERVICE:
799 4 : return JS_NewInt32(ctx, (!odm->addon && odm->subscene) ? odm->subscene->selected_service_id : odm->parentscene->selected_service_id);
800 : break;
801 0 : case GJS_OM_PROP_BANDWIDTH_DOWN:
802 0 : if (odm->scene_ns->source_filter) {
803 : JSValue ret;
804 0 : GF_PropertyEntry *pe=NULL;
805 0 : const GF_PropertyValue *prop = gf_filter_get_info(odm->scene_ns->source_filter, GF_PROP_PID_DOWN_RATE, &pe);
806 0 : ret = JS_NewInt32(ctx, prop ? prop->value.uint/1000 : 0);
807 0 : gf_filter_release_property(pe);
808 0 : return ret;
809 : }
810 : return JS_NewInt32(ctx, 0);
811 :
812 2 : case GJS_OM_PROP_NB_HTTP:
813 2 : if (odm->scene_ns->source_filter) {
814 2 : return JS_NewInt32(ctx, gf_filter_count_source_by_protocol(odm->scene_ns->source_filter, "http", GF_TRUE, gjs_enum_pids, odm->subscene ? odm->subscene : odm->parentscene ) );
815 : }
816 : return JS_NewInt32(ctx, 0);
817 0 : case GJS_OM_PROP_TIMESHIFT_DEPTH:
818 0 : if ((s32) odm->timeshift_depth > 0) {
819 0 : return JS_NewFloat64(ctx, ((Double) odm->timeshift_depth) / 1000.0 );
820 : }
821 : return JS_NewFloat64(ctx, 0.0);
822 :
823 0 : case GJS_OM_PROP_TIMESHIFT_TIME:
824 : dval = 0.0;
825 0 : if (!odm->timeshift_depth) {
826 : return JS_NewInt32(ctx, 0);
827 : }
828 :
829 0 : scene = odm->subscene ? odm->subscene : odm->parentscene;
830 : //we may need to check the main addon for timeshifting
831 0 : if (scene->main_addon_selected) {
832 0 : count = gf_list_count(scene->resources);
833 0 : for (i=0; i < count; i++) {
834 0 : GF_ObjectManager *an_odm = gf_list_get(scene->resources, i);
835 0 : if (an_odm && an_odm->addon && (an_odm->addon->addon_type==GF_ADDON_TYPE_MAIN)) {
836 : odm = an_odm;
837 : }
838 : }
839 : }
840 :
841 0 : if (odm->timeshift_depth) {
842 0 : GF_FilterPid *pid = odm->pid;
843 0 : if (!pid && odm->subscene) {
844 0 : odm = gf_list_get(odm->subscene->resources, 0);
845 0 : pid = odm->pid;
846 : }
847 0 : if (pid) {
848 0 : GF_PropertyEntry *pe=NULL;
849 0 : const GF_PropertyValue *p = gf_filter_pid_get_info(pid, GF_PROP_PID_TIMESHIFT_TIME, &pe);
850 0 : if (p) dval = p->value.number;
851 0 : gf_filter_release_property(pe);
852 : }
853 0 : } else if (scene->main_addon_selected) {
854 0 : GF_Clock *ck = scene->root_od->ck;
855 0 : if (ck) {
856 0 : u32 now = gf_clock_time(ck) ;
857 0 : u32 live = scene->obj_clock_at_main_activation + gf_sys_clock() - scene->sys_clock_at_main_activation;
858 0 : dval = ((Double) live) / 1000.0;
859 0 : dval -= ((Double) now) / 1000.0;
860 :
861 0 : if (dval<0) {
862 : GF_Event evt;
863 : memset(&evt, 0, sizeof(evt));
864 0 : evt.type = GF_EVENT_TIMESHIFT_UNDERRUN;
865 0 : gf_sc_send_event(scene->compositor, &evt);
866 : dval=0;
867 0 : } else if (dval && dval*1000 > scene->timeshift_depth) {
868 : GF_Event evt;
869 : memset(&evt, 0, sizeof(evt));
870 0 : evt.type = GF_EVENT_TIMESHIFT_OVERFLOW;
871 0 : gf_sc_send_event(scene->compositor, &evt);
872 0 : dval=scene->timeshift_depth;
873 0 : dval/=1000;
874 : }
875 : }
876 : }
877 : return JS_NewFloat64(ctx, dval);
878 :
879 0 : case GJS_OM_PROP_IS_ADDON:
880 0 : return JS_NewBool(ctx, (odm->addon || (!odm->subscene && odm->parentscene->root_od->addon)) );
881 :
882 18 : case GJS_OM_PROP_MAIN_ADDON_ON:
883 18 : scene = odm->subscene ? odm->subscene : odm->parentscene;
884 18 : return JS_NewBool(ctx, scene->main_addon_selected );
885 0 : case GJS_OM_PROP_IS_OVER:
886 0 : scene = odm->subscene ? odm->subscene : odm->parentscene;
887 0 : return JS_NewBool(ctx, gf_sc_is_over(scene->compositor, scene->graph));
888 :
889 1 : case GJS_OM_PROP_DYNAMIC_SCENE:
890 1 : return JS_NewBool(ctx, odm->subscene && odm->subscene->is_dynamic_scene);
891 :
892 0 : case GJS_OM_PROP_SERVICE_NAME:
893 0 : if (odm->pid) {
894 0 : const GF_PropertyValue *p = gf_filter_pid_get_property(odm->pid, GF_PROP_PID_SERVICE_NAME);
895 0 : if (p && p->value.string)
896 0 : return JS_NewString(ctx, p->value.string);
897 : }
898 0 : return JS_NULL;
899 :
900 9 : case GJS_OM_PROP_NTP_DIFF:
901 9 : gf_odm_get_object_info(odm, &odi);
902 9 : return JS_NewInt32(ctx, odi.ntp_diff);
903 :
904 0 : case GJS_OM_PROP_NTP_SENDER_DIFF:
905 0 : if (odm->last_drawn_frame_ntp_sender && odm->last_drawn_frame_ntp_receive) {
906 0 : s32 diff = gf_net_ntp_diff_ms(odm->last_drawn_frame_ntp_receive, odm->last_drawn_frame_ntp_sender);
907 : return JS_NewInt32(ctx, diff);
908 : }
909 0 : return JS_NULL;
910 :
911 0 : case GJS_OM_PROP_MAIN_ADDON_URL:
912 0 : scene = odm->subscene ? odm->subscene : odm->parentscene;
913 0 : count = gf_list_count(scene->resources);
914 0 : for (i=0; i < count; i++) {
915 0 : GF_ObjectManager *an_odm = gf_list_get(scene->resources, i);
916 0 : if (an_odm && an_odm->addon && (an_odm->addon->addon_type==GF_ADDON_TYPE_MAIN)) {
917 0 : if (!strstr(an_odm->addon->url, "://")) {
918 : char szURL[GF_MAX_PATH];
919 : sprintf(szURL, "gpac://%s", an_odm->addon->url);
920 0 : return JS_NewString(ctx, szURL);
921 : } else {
922 0 : return JS_NewString(ctx, an_odm->addon->url);
923 : }
924 : }
925 : }
926 0 : return JS_NULL;
927 :
928 1 : case GJS_OM_PROP_REVERSE_PLAYBACK:
929 1 : if (odm->pid) {
930 0 : const GF_PropertyValue *p = gf_filter_pid_get_property(odm->pid, GF_PROP_PID_PLAYBACK_MODE);
931 0 : if (p && p->value.uint==GF_PLAYBACK_MODE_REWIND)
932 : return JS_NewBool(ctx, GF_TRUE);
933 : }
934 : return JS_NewBool(ctx, GF_FALSE );
935 :
936 5 : case GJS_OM_PROP_SCALABLE_ENHANCEMENT:
937 5 : return JS_NewBool(ctx, odm && (odm->lower_layer_odm || odm->scalable_addon));
938 :
939 0 : case GJS_OM_PROP_MAIN_ADDON_MEDIATIME:
940 0 : scene = odm->subscene ? odm->subscene : odm->parentscene;
941 0 : count = gf_list_count(scene->resources);
942 :
943 0 : if (! scene->main_addon_selected) count = 0;
944 :
945 0 : for (i=0; i < count; i++) {
946 0 : GF_ObjectManager *an_odm = gf_list_get(scene->resources, i);
947 0 : if (an_odm && an_odm->addon && (an_odm->addon->addon_type==GF_ADDON_TYPE_MAIN)) {
948 0 : if (an_odm->duration) {
949 0 : Double now = gf_clock_time(scene->root_od->ck) / 1000.0;
950 0 : now -= ((Double) an_odm->addon->media_pts) / 90000.0;
951 0 : now += ((Double) an_odm->addon->media_timestamp) / an_odm->addon->media_timescale;
952 : return JS_NewFloat64(ctx, now);
953 : }
954 : }
955 : }
956 : return JS_NewFloat64(ctx, -1);
957 :
958 : case GJS_OM_PROP_DEPENDENT_GROUPS:
959 : {
960 : #if FILTER_FIXME
961 : GF_NetworkCommand com;
962 : memset(&com, 0, sizeof(GF_NetworkCommand));
963 : com.base.command_type = GF_NET_SERVICE_QUALITY_QUERY;
964 : com.base.on_channel = gf_list_get(odm->channels, 0);
965 :
966 : gf_term_service_command(odm->net_service, &com);
967 : if (com.quality_query.index) {
968 : return JS_NewInt32(ctx, com.quality_query.dependent_group_index);
969 : }
970 : #endif
971 : return JS_NewInt32(ctx, 0);
972 : }
973 :
974 18 : case GJS_OM_PROP_IS_VR_SCENE:
975 18 : return JS_NewBool(ctx, odm->subscene && odm->subscene->vr_type);
976 1 : case GJS_OM_PROP_DISABLED:
977 1 : return JS_NewBool(ctx, odm->redirect_url ? 1 : 0);
978 0 : case GJS_OM_PROP_BUFFERING:
979 0 : if (odm->parentscene)
980 0 : return JS_NewBool(ctx, odm->parentscene->nb_buffering ? 1 : 0);
981 0 : return JS_NewBool(ctx, odm->subscene->nb_buffering ? 1 : 0);
982 : }
983 0 : return JS_UNDEFINED;
984 : }
985 :
986 28 : static JSValue gjs_odm_get_quality(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
987 : {
988 28 : GF_ObjectManager *odm = JS_GetOpaque(this_val, odm_class_id);
989 : const GF_PropertyValue *prop;
990 28 : GF_PropertyEntry *pe=NULL;
991 : char *qdesc;
992 : const char *id="", *mime="", *codec="";
993 28 : u32 sr=0, ch=0, w=0, h=0, bw=0, par_n=1, par_d=1, tile_adaptation_mode=0,dependent_group_index=0;
994 : Bool ilced=GF_FALSE, disabled=GF_FALSE, selected=GF_FALSE, automatic=GF_FALSE;
995 : Double fps=30.0;
996 : s32 idx;
997 : #if 0 //FILTER_FIXME
998 : s32 dep_idx=0;
999 : #endif
1000 :
1001 28 : if (!odm) return JS_EXCEPTION;
1002 28 : if (argc<1) return JS_EXCEPTION;
1003 28 : if (JS_ToInt32(ctx, &idx, argv[0]))
1004 0 : return JS_EXCEPTION;
1005 :
1006 : #if 0 //FILTER_FIXME
1007 : if (argc>=2) dep_idx = JSVAL_TO_INT(argv[1]);
1008 : #endif
1009 :
1010 28 : if (!odm->pid) return JS_NULL;
1011 :
1012 28 : prop = gf_filter_pid_get_info_str(odm->pid, "has:qualities", &pe);
1013 28 : if (!prop || (prop->type!=GF_PROP_STRING_LIST)) {
1014 0 : gf_filter_release_property(pe);
1015 0 : return JS_NULL;
1016 : }
1017 : qdesc = NULL;
1018 28 : if (idx < (s32) prop->value.string_list.nb_items)
1019 28 : qdesc = prop->value.string_list.vals[idx];
1020 28 : if (!qdesc) {
1021 0 : gf_filter_release_property(pe);
1022 0 : return JS_NULL;
1023 : }
1024 28 : JSValue a = JS_NewObject(ctx);
1025 28 : if (JS_IsException(a))
1026 0 : return a;
1027 :
1028 196 : while (qdesc) {
1029 196 : char *sep=strstr(qdesc, "::");
1030 196 : if (sep) sep[0]=0;
1031 :
1032 196 : if (!strncmp(qdesc, "id=", 3)) {
1033 : id = NULL;
1034 28 : JS_SetPropertyStr(ctx, a, "ID", JS_NewString(ctx, qdesc+3) );
1035 168 : } else if (!strncmp(qdesc, "mime=", 5)) {
1036 : mime = NULL;
1037 28 : JS_SetPropertyStr(ctx, a, "mime", JS_NewString(ctx, qdesc+5));
1038 140 : } else if (!strncmp(qdesc, "codec=", 6)) {
1039 : codec = NULL;
1040 28 : JS_SetPropertyStr(ctx, a, "codec", JS_NewString(ctx, qdesc+6));
1041 : }
1042 140 : else if (!strncmp(qdesc, "bw=", 3)) bw = atoi(qdesc+3);
1043 112 : else if (!strncmp(qdesc, "w=", 2)) w = atoi(qdesc+2);
1044 84 : else if (!strncmp(qdesc, "h=", 2)) h = atoi(qdesc+2);
1045 28 : else if (!strncmp(qdesc, "sr=", 3)) sr = atoi(qdesc+3);
1046 28 : else if (!strncmp(qdesc, "ch=", 3)) ch = atoi(qdesc+3);
1047 28 : else if (!strcmp(qdesc, "interlaced")) ilced = GF_TRUE;
1048 28 : else if (!strcmp(qdesc, "disabled")) disabled = GF_TRUE;
1049 28 : else if (!strncmp(qdesc, "fps=", 4)) {
1050 28 : u32 fd=25, fn=1;
1051 28 : if (sscanf(qdesc, "fps=%d/%d", &fn, &fd) != 2) {
1052 0 : fd=1;
1053 0 : sscanf(qdesc, "fps=%d", &fn);
1054 : }
1055 28 : fps = ((Double)fn) / fd;
1056 : }
1057 0 : else if (!strncmp(qdesc, "sar=", 4)) {
1058 0 : sscanf(qdesc, "sar=%d/%d", &par_n, &par_d);
1059 : }
1060 196 : if (!sep) break;
1061 168 : sep[0]=':';
1062 168 : qdesc = sep+2;
1063 : }
1064 28 : prop = gf_filter_pid_get_info_str(odm->pid, "has:selected", &pe);
1065 28 : if (prop && (prop->value.uint==idx))
1066 : selected = GF_TRUE;
1067 28 : prop = gf_filter_pid_get_info_str(odm->pid, "has:auto", &pe);
1068 28 : if (prop && prop->value.boolean)
1069 : automatic = GF_TRUE;
1070 28 : prop = gf_filter_pid_get_info_str(odm->pid, "has:tilemode", &pe);
1071 28 : if (prop) tile_adaptation_mode = prop->value.uint;
1072 :
1073 28 : gf_filter_release_property(pe);
1074 :
1075 28 : if (id)
1076 0 : JS_SetPropertyStr(ctx, a, "ID", JS_NewString(ctx, id));
1077 28 : if (mime)
1078 0 : JS_SetPropertyStr(ctx, a, "mime", JS_NewString(ctx, mime));
1079 28 : if (codec)
1080 0 : JS_SetPropertyStr(ctx, a, "codec", JS_NewString(ctx, codec));
1081 :
1082 56 : JS_SetPropertyStr(ctx, a, "width", JS_NewInt32(ctx, w));
1083 56 : JS_SetPropertyStr(ctx, a, "height", JS_NewInt32(ctx, h));
1084 56 : JS_SetPropertyStr(ctx, a, "bandwidth", JS_NewInt32(ctx, bw));
1085 28 : JS_SetPropertyStr(ctx, a, "interlaced", JS_NewBool(ctx, ilced));
1086 28 : JS_SetPropertyStr(ctx, a, "fps", JS_NewFloat64(ctx, fps) );
1087 56 : JS_SetPropertyStr(ctx, a, "samplerate", JS_NewInt32(ctx, sr));
1088 56 : JS_SetPropertyStr(ctx, a, "channels", JS_NewInt32(ctx, ch));
1089 56 : JS_SetPropertyStr(ctx, a, "par_num", JS_NewInt32(ctx, par_n));
1090 56 : JS_SetPropertyStr(ctx, a, "par_den", JS_NewInt32(ctx, par_d));
1091 28 : JS_SetPropertyStr(ctx, a, "disabled", JS_NewBool(ctx, disabled));
1092 28 : JS_SetPropertyStr(ctx, a, "is_selected", JS_NewBool(ctx, selected));
1093 28 : JS_SetPropertyStr(ctx, a, "automatic", JS_NewBool(ctx, automatic));
1094 56 : JS_SetPropertyStr(ctx, a, "tile_mode", JS_NewInt32(ctx, tile_adaptation_mode));
1095 28 : JS_SetPropertyStr(ctx, a, "dependent_groups", JS_NewInt32(ctx, dependent_group_index));
1096 :
1097 28 : return a;
1098 : }
1099 :
1100 7 : static JSValue gjs_odm_get_srd(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
1101 : {
1102 7 : GF_ObjectManager *odm = JS_GetOpaque(this_val, odm_class_id);
1103 : s32 x, y, w, h;
1104 :
1105 7 : if (!odm) return JS_EXCEPTION;
1106 :
1107 : x = y = w = h = 0;
1108 7 : if (argc) {
1109 : #if 0 //FILTER_FIXME
1110 : s32 dep_idx;
1111 : if (JS_ToInt32(ctx, &dep_idx, argv[0]) )
1112 : return JS_EXCEPTION;
1113 :
1114 : memset(&com, 0, sizeof(GF_NetworkCommand));
1115 : com.base.command_type = GF_NET_CHAN_GET_SRD;
1116 : com.base.on_channel = gf_list_get(odm->channels, 0);
1117 : com.srd.dependent_group_index = dep_idx;
1118 :
1119 : if (gf_term_service_command(odm->net_service, &com) == GF_OK) {
1120 : x = com.srd.x;
1121 : y = com.srd.y;
1122 : w = com.srd.w;
1123 : h = com.srd.h;
1124 : }
1125 : #endif
1126 7 : } else if (odm && odm->mo && odm->mo->srd_w && odm->mo->srd_h) {
1127 0 : x = odm->mo->srd_x;
1128 0 : y = odm->mo->srd_y;
1129 0 : w = odm->mo->srd_w;
1130 0 : h = odm->mo->srd_h;
1131 : }
1132 :
1133 7 : if (w && h) {
1134 0 : JSValue a = JS_NewObject(ctx);
1135 0 : if (JS_IsException(a)) return a;
1136 :
1137 0 : JS_SetPropertyStr(ctx, a, "x", JS_NewInt32(ctx, x));
1138 0 : JS_SetPropertyStr(ctx, a, "y", JS_NewInt32(ctx, y));
1139 0 : JS_SetPropertyStr(ctx, a, "w", JS_NewInt32(ctx, w));
1140 0 : JS_SetPropertyStr(ctx, a, "h", JS_NewInt32(ctx, h));
1141 0 : return a;
1142 : }
1143 7 : return JS_NULL;
1144 : }
1145 :
1146 : GF_Filter *jsff_get_filter(JSContext *c, JSValue this_val);
1147 :
1148 13 : static JSValue gjs_odm_in_parent_chain(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
1149 : {
1150 : Bool res;
1151 : GF_Filter *f;
1152 : GF_Scene *scene;
1153 13 : GF_ObjectManager *odm = JS_GetOpaque(this_val, odm_class_id);
1154 13 : if (!odm || !argc) return JS_EXCEPTION;
1155 :
1156 13 : f = jsff_get_filter(ctx, argv[0]);
1157 13 : if (!f) return JS_EXCEPTION;
1158 :
1159 13 : scene = odm->subscene ? odm->subscene : odm->parentscene;
1160 13 : if (!scene) return JS_EXCEPTION;
1161 13 : if (gf_filter_in_parent_chain(f, scene->compositor->filter))
1162 2 : return JS_FALSE;
1163 :
1164 11 : if (odm->pid) {
1165 0 : res = gf_filter_pid_is_filter_in_parents(odm->pid, f);
1166 : } else {
1167 11 : res = gf_filter_in_parent_chain(f, odm->scene_ns->source_filter);
1168 : }
1169 11 : return res ? JS_TRUE : JS_FALSE;
1170 : }
1171 :
1172 2 : static JSValue gjs_odm_select_quality(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
1173 : {
1174 : s32 idx = -1;
1175 2 : s32 tile_mode = -1;
1176 2 : u32 dep_idx = 0;
1177 : GF_FilterEvent evt;
1178 2 : GF_ObjectManager *odm = JS_GetOpaque(this_val, odm_class_id);
1179 :
1180 2 : if (!odm || !odm->pid) return JS_EXCEPTION;
1181 :
1182 4 : if ((argc>=1) && JS_IsString(argv[0])) {
1183 : const char *ID = JS_ToCString(ctx, argv[0]);
1184 2 : if (!strcmp(ID, "auto")) {
1185 : idx = -1;
1186 : } else {
1187 : idx = atoi(ID);
1188 : }
1189 2 : JS_FreeCString(ctx, ID);
1190 :
1191 2 : if (argc>=2) {
1192 2 : if (JS_ToInt32(ctx, &dep_idx, argv[1]))
1193 0 : return JS_EXCEPTION;
1194 : }
1195 : }
1196 0 : else if ((argc==1) && JS_IsInteger(argv[0])) {
1197 0 : if (JS_ToInt32(ctx, &tile_mode, argv[0]))
1198 0 : return JS_EXCEPTION;
1199 0 : if (tile_mode<0)
1200 0 : return JS_UNDEFINED;
1201 : }
1202 :
1203 2 : GF_FEVT_INIT(evt, GF_FEVT_QUALITY_SWITCH, odm->pid);
1204 :
1205 2 : if (tile_mode>=0) {
1206 0 : evt.quality_switch.set_tile_mode_plus_one = 1 + tile_mode;
1207 : } else {
1208 2 : evt.quality_switch.dependent_group_index = dep_idx;
1209 2 : evt.quality_switch.q_idx = idx;
1210 : }
1211 2 : gf_filter_pid_send_event(odm->pid, &evt);
1212 2 : return JS_UNDEFINED;
1213 : }
1214 :
1215 1 : static JSValue gjs_odm_disable_main_addon(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
1216 : {
1217 1 : GF_ObjectManager *odm = JS_GetOpaque(this_val, odm_class_id);
1218 1 : if (!odm) return JS_EXCEPTION;
1219 1 : if (!odm->subscene || !odm->subscene->main_addon_selected) return JS_UNDEFINED;
1220 :
1221 0 : gf_scene_resume_live(odm->subscene);
1222 0 : return JS_UNDEFINED;
1223 : }
1224 :
1225 1 : static JSValue gjs_odm_select_service(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
1226 : {
1227 : u32 sid;
1228 1 : GF_ObjectManager *odm = JS_GetOpaque(this_val, odm_class_id);
1229 1 : if (!odm) return JS_EXCEPTION;
1230 1 : if (argc<1) return JS_EXCEPTION;
1231 :
1232 1 : if (JS_ToInt32(ctx, &sid, argv[0]))
1233 0 : return JS_EXCEPTION;
1234 :
1235 1 : gf_scene_set_service_id(odm->subscene ? odm->subscene : odm->parentscene, sid);
1236 1 : return JS_UNDEFINED;
1237 : }
1238 :
1239 1 : static JSValue gjs_odm_select(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
1240 : {
1241 1 : GF_ObjectManager *odm = JS_GetOpaque(this_val, odm_class_id);
1242 1 : if (!odm) return JS_EXCEPTION;
1243 :
1244 : #ifndef GPAC_DISABLE_PLAYER
1245 1 : gf_scene_select_object(odm->parentscene, odm);
1246 : #endif
1247 1 : return JS_UNDEFINED;
1248 : }
1249 :
1250 5 : static JSValue gjs_odm_get_resource(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
1251 : {
1252 : GF_ObjectManager *an_odm = NULL;
1253 : u32 idx;
1254 5 : GF_ObjectManager *odm = JS_GetOpaque(this_val, odm_class_id);
1255 :
1256 5 : if (!odm) return JS_EXCEPTION;
1257 5 : if (argc<1) return JS_EXCEPTION;
1258 5 : if (JS_ToInt32(ctx, &idx, argv[0])) return JS_EXCEPTION;
1259 :
1260 5 : if (odm->subscene) {
1261 5 : an_odm = gf_list_get(odm->subscene->resources, idx);
1262 : }
1263 5 : if (an_odm && an_odm->scene_ns) {
1264 5 : JSValue anobj = JS_NewObjectClass(ctx, odm_class_id);
1265 5 : JS_SetOpaque(anobj, an_odm);
1266 5 : return anobj;
1267 : }
1268 0 : return JS_NULL;
1269 : }
1270 :
1271 1 : static JSValue gjs_odm_addon_layout(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
1272 : {
1273 : u32 pos, size;
1274 1 : GF_ObjectManager *odm = JS_GetOpaque(this_val, odm_class_id);
1275 1 : if (!odm) return JS_EXCEPTION;
1276 1 : if (argc<2) return JS_EXCEPTION;
1277 1 : if (JS_ToInt32(ctx, &pos, argv[0])) return JS_EXCEPTION;
1278 1 : if (JS_ToInt32(ctx, &size, argv[1])) return JS_EXCEPTION;
1279 1 : if (odm->subscene)
1280 0 : gf_scene_set_addon_layout_info(odm->subscene, pos, size);
1281 1 : return JS_UNDEFINED;
1282 : }
1283 :
1284 : static void do_enable_addon(GF_ObjectManager *odm, char *addon_url, Bool enable_if_defined, Bool disable_if_defined )
1285 : {
1286 : if (addon_url) {
1287 : #ifdef FILTER_FIXME
1288 : GF_AssociatedContentLocation addon_info;
1289 : memset(&addon_info, 0, sizeof(GF_AssociatedContentLocation));
1290 : addon_info.external_URL = addon_url;
1291 : addon_info.timeline_id = -100;
1292 : addon_info.enable_if_defined = enable_if_defined;
1293 : addon_info.disable_if_defined = disable_if_defined;
1294 : gf_scene_register_associated_media(odm->subscene ? odm->subscene : odm->parentscene, &addon_info);
1295 : #endif
1296 : }
1297 : }
1298 :
1299 1 : static JSValue gjs_odm_enable_addon(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
1300 : {
1301 : Bool do_disable = GF_FALSE;
1302 : const char *addon_url = NULL;
1303 1 : GF_ObjectManager *odm = JS_GetOpaque(this_val, odm_class_id);
1304 1 : if (!odm || !argc) return JS_EXCEPTION;
1305 :
1306 2 : if (! JS_IsString(argv[0]) ) {
1307 : #ifdef GPAC_ENABLE_COVERAGE
1308 0 : if (gf_sys_is_cov_mode()) {
1309 : do_enable_addon(odm, NULL, GF_TRUE, GF_FALSE);
1310 : }
1311 : #endif
1312 0 : return JS_UNDEFINED;
1313 : }
1314 1 : if (argc==2)
1315 0 : do_disable = JS_ToBool(ctx, argv[1]);
1316 : addon_url = JS_ToCString(ctx, argv[0]);
1317 : if (addon_url) {
1318 : do_enable_addon(odm, (char *) addon_url, GF_TRUE, do_disable);
1319 : }
1320 1 : JS_FreeCString(ctx, addon_url);
1321 1 : return JS_UNDEFINED;
1322 : }
1323 :
1324 1 : static JSValue gjs_odm_declare_addon(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
1325 : {
1326 : const char *addon_url = NULL;
1327 1 : GF_ObjectManager *odm = JS_GetOpaque(this_val, odm_class_id);
1328 1 : if (!odm || !argc) return JS_EXCEPTION;
1329 2 : if (! JS_IsString(argv[0]) ) return JS_EXCEPTION;
1330 :
1331 : addon_url = JS_ToCString(ctx, argv[0]);
1332 : if (addon_url && strcmp(addon_url, "gtest")) {
1333 : do_enable_addon(odm, (char *)addon_url, GF_FALSE, GF_FALSE);
1334 : }
1335 1 : JS_FreeCString(ctx, addon_url);
1336 1 : return JS_UNDEFINED;
1337 : }
1338 :
1339 1 : static JSValue scenejs_get_object_manager(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
1340 : {
1341 : JSValue anobj;
1342 : u32 i, count;
1343 : GF_ObjectManager *odm = NULL;
1344 : const char *service_url = NULL;
1345 1 : GF_SCENEJSExt *sjs = JS_GetOpaque(this_val, scene_class_id);
1346 : GF_Compositor *compositor = scenejs_get_compositor(ctx, this_val);
1347 1 : GF_Scene *scene = compositor->root_scene;
1348 1 : if (!sjs) return JS_EXCEPTION;
1349 :
1350 2 : if (JS_IsString(argv[0]) ) {
1351 : const char *url;
1352 : char *an_url;
1353 : u32 url_len;
1354 : url = service_url = JS_ToCString(ctx, argv[0]);
1355 1 : if (!service_url) {
1356 0 : return JS_NULL;
1357 : }
1358 1 : if (!strncmp(service_url, "gpac://", 7)) url = service_url + 7;
1359 1 : if (!strncmp(service_url, "file://", 7)) url = service_url + 7;
1360 1 : url_len = (u32) strlen(url);
1361 1 : an_url = strchr(url, '#');
1362 1 : if (an_url) url_len -= (u32) strlen(an_url);
1363 :
1364 1 : count = gf_list_count(scene->resources);
1365 5 : for (i=0; i<count; i++) {
1366 5 : odm = gf_list_get(scene->resources, i);
1367 5 : if (odm->scene_ns) {
1368 5 : an_url = odm->scene_ns->url;
1369 5 : if (!strncmp(an_url, "gpac://", 7)) an_url = an_url + 7;
1370 5 : if (!strncmp(an_url, "file://", 7)) an_url = an_url + 7;
1371 5 : if (!strncmp(an_url, url, url_len))
1372 : break;
1373 : }
1374 : odm = NULL;
1375 : }
1376 : }
1377 :
1378 1 : JS_FreeCString(ctx, service_url);
1379 :
1380 1 : if (!odm) return JS_NULL;
1381 :
1382 1 : anobj = JS_NewObjectClass(ctx, odm_class_id);
1383 1 : if (JS_IsException(anobj)) return anobj;
1384 :
1385 1 : JS_SetOpaque(anobj, odm);
1386 1 : return anobj;
1387 : }
1388 :
1389 :
1390 242 : static JSValue gpacevt_getProperty(JSContext *ctx, JSValueConst this_val, int magic)
1391 : {
1392 242 : GF_SCENEJSExt *sjs = JS_GetOpaque(this_val, gpacevt_class_id);
1393 242 : if (!sjs || !sjs->evt) return JS_EXCEPTION;
1394 : GF_Event *evt = sjs->evt;
1395 :
1396 242 : switch (magic) {
1397 0 : case GJS_EVT_PROP_KEYCODE:
1398 : #ifndef GPAC_DISABLE_SVG
1399 0 : return JS_NewString(ctx, gf_dom_get_key_name(evt->key.key_code) );
1400 : #else
1401 : return JS_NULL;
1402 : #endif
1403 :
1404 0 : case GJS_EVT_PROP_MOUSE_X:
1405 0 : return JS_NewInt32(ctx, evt->mouse.x);
1406 0 : case GJS_EVT_PROP_MOUSE_Y:
1407 0 : return JS_NewInt32(ctx, evt->mouse.y);
1408 0 : case GJS_EVT_PROP_PICKED:
1409 0 : if (sjs->compositor->hit_appear) return JS_NewBool(ctx, 1);
1410 0 : else if (gf_list_count(sjs->compositor->previous_sensors) ) return JS_NewBool(ctx, 1);
1411 0 : else if (sjs->compositor->text_selection) return JS_NewBool(ctx, 1);
1412 : else return JS_NewBool(ctx, 0);
1413 :
1414 0 : case GJS_EVT_PROP_WHEEL:
1415 0 : return JS_NewFloat64(ctx, FIX2FLT(evt->mouse.wheel_pos));
1416 0 : case GJS_EVT_PROP_BUTTON:
1417 0 : return JS_NewInt32(ctx, evt->mouse.button);
1418 242 : case GJS_EVT_PROP_TYPE:
1419 242 : return JS_NewInt32(ctx, evt->type);
1420 0 : case GJS_EVT_PROP_NAME:
1421 : #ifndef GPAC_DISABLE_SVG
1422 0 : return JS_NewString(ctx, gf_dom_event_get_name(evt->type) );
1423 : #else
1424 : return JS_NULL;
1425 : #endif
1426 :
1427 0 : case GJS_EVT_PROP_HWKEY:
1428 0 : return JS_NewInt32(ctx, evt->key.hw_code);
1429 0 : case GJS_EVT_PROP_TARGET_URL:
1430 0 : return JS_NewString(ctx, evt->navigate.to_url);
1431 0 : case GJS_EVT_PROP_FILES:
1432 : {
1433 : u32 i, idx;
1434 0 : JSValue files_array = JS_NewArray(ctx);
1435 : idx=0;
1436 0 : for (i=0; i<evt->open_file.nb_files; i++) {
1437 0 : if (evt->open_file.files[i]) {
1438 0 : JS_SetPropertyUint32(ctx, files_array, idx, JS_NewString(ctx, evt->open_file.files[i]) );
1439 0 : idx++;
1440 : }
1441 : }
1442 0 : return files_array;
1443 : }
1444 : }
1445 0 : return JS_UNDEFINED;
1446 : }
1447 :
1448 55 : static Bool gjs_event_filter_process(GF_SCENEJSExt *sjs, GF_Event *evt)
1449 : {
1450 : s32 res;
1451 : JSValue rval;
1452 :
1453 55 : sjs->evt = evt;
1454 55 : JS_SetOpaque(sjs->evt_obj, sjs);
1455 55 : rval = JS_Call(sjs->c, sjs->evt_fun, sjs->evt_filter_obj, 1, &sjs->evt_obj);
1456 55 : JS_SetOpaque(sjs->evt_obj, NULL);
1457 55 : sjs->evt = NULL;
1458 :
1459 55 : res = 0;
1460 55 : if (JS_IsBool(rval))
1461 55 : res = JS_ToBool(sjs->c, rval);
1462 0 : else if (JS_IsNumber(rval))
1463 0 : JS_ToInt32(sjs->c, &res, rval);
1464 :
1465 55 : JS_FreeValue(sjs->c, rval);
1466 55 : return res ? GF_TRUE : GF_FALSE;
1467 : }
1468 :
1469 55 : static Bool gjs_event_filter(void *udta, GF_Event *evt, Bool consumed_by_compositor)
1470 : {
1471 : u32 lock_fail;
1472 : Bool res;
1473 : GF_SCENEJSExt *sjs = (GF_SCENEJSExt *)udta;
1474 55 : if (consumed_by_compositor) return 0;
1475 :
1476 55 : if (sjs->evt != NULL) return 0;
1477 :
1478 : lock_fail=0;
1479 55 : res = gf_mx_try_lock(sjs->compositor->mx);
1480 55 : if (!res) {
1481 : lock_fail=1;
1482 : } else {
1483 55 : res = gf_js_try_lock(sjs->c);
1484 55 : if (!res) lock_fail=2;
1485 : }
1486 : if (lock_fail) {
1487 : GF_Event *evt_clone;
1488 0 : gf_mx_p(sjs->event_mx);
1489 0 : evt_clone = gf_malloc(sizeof(GF_Event));
1490 : memcpy(evt_clone, evt, sizeof(GF_Event));
1491 0 : gf_list_add(sjs->event_queue, evt_clone);
1492 0 : GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[SCENEJS] Couldn't lock % mutex, queing event\n", (lock_fail==2) ? "JavaScript" : "Compositor"));
1493 0 : gf_mx_v(sjs->event_mx);
1494 :
1495 0 : if (lock_fail==2){
1496 0 : gf_mx_v(sjs->compositor->mx);
1497 : }
1498 : return 0;
1499 : }
1500 :
1501 55 : gf_mx_p(sjs->event_mx);
1502 110 : while (gf_list_count(sjs->event_queue)) {
1503 0 : GF_Event *an_evt = (GF_Event *) gf_list_pop_front(sjs->event_queue);
1504 0 : gjs_event_filter_process(sjs, an_evt);
1505 0 : gf_free(an_evt);
1506 : }
1507 55 : gf_mx_v(sjs->event_mx);
1508 :
1509 55 : res = gjs_event_filter_process(sjs, evt);
1510 :
1511 55 : gf_mx_v(sjs->compositor->mx);
1512 55 : gf_js_lock(sjs->c, 0);
1513 55 : return res;
1514 : }
1515 :
1516 3 : static JSValue scenejs_set_event_filter(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
1517 : {
1518 3 : GF_SCENEJSExt *sjs = JS_GetOpaque(this_val, scene_class_id);
1519 3 : if (!sjs || !argc)
1520 0 : return JS_EXCEPTION;
1521 :
1522 6 : if (!JS_IsNull(argv[0]) && !JS_IsUndefined(argv[0]) && !JS_IsFunction(ctx, argv[0]))
1523 0 : return JS_EXCEPTION;
1524 :
1525 3 : JS_FreeValue(sjs->c, sjs->evt_fun);
1526 3 : sjs->evt_fun = JS_DupValue(ctx, argv[0]);
1527 3 : sjs->evt_filter_obj = this_val;
1528 3 : sjs->c = ctx;
1529 3 : sjs->evt_filter.udta = sjs;
1530 3 : sjs->evt_filter.on_event = gjs_event_filter;
1531 :
1532 3 : gf_filter_add_event_listener(sjs->compositor->filter, &sjs->evt_filter);
1533 3 : return JS_UNDEFINED;
1534 : }
1535 :
1536 : GF_Node *gf_sg_js_get_node(struct JSContext *c, JSValue obj);
1537 :
1538 19 : static JSValue scenejs_set_focus(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
1539 : {
1540 : GF_Node *elt;
1541 : GF_Compositor *compositor = scenejs_get_compositor(ctx, this_val);
1542 19 : if (!compositor || !argc) return JS_EXCEPTION;
1543 :
1544 38 : if (JS_IsNull(argv[0])) {
1545 0 : gf_sc_focus_switch_ring(compositor, 0, NULL, 0);
1546 0 : return JS_UNDEFINED;
1547 : }
1548 :
1549 19 : if (JS_IsString(argv[0])) {
1550 : const char *focus_type = JS_ToCString(ctx, argv[0]);
1551 0 : if (!stricmp(focus_type, "previous")) {
1552 0 : gf_sc_focus_switch_ring(compositor, 1, NULL, 0);
1553 : }
1554 0 : else if (!stricmp(focus_type, "next")) {
1555 0 : gf_sc_focus_switch_ring(compositor, 0, NULL, 0);
1556 : }
1557 0 : JS_FreeCString(ctx, focus_type);
1558 19 : } else if (JS_IsObject(argv[0])) {
1559 19 : elt = gf_sg_js_get_node(ctx, argv[0]);
1560 19 : if (!elt) return JS_EXCEPTION;
1561 19 : gf_sc_focus_switch_ring(compositor, 0, elt, 2);
1562 : }
1563 19 : return JS_UNDEFINED;
1564 : }
1565 :
1566 : #if 0 //unused
1567 : static JSValue scenejs_get_scene(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
1568 : {
1569 : GF_Node *elt;
1570 : u32 w, h;
1571 : JSValue scene_obj;
1572 : #ifndef GPAC_DISABLE_SCENEGRAPH
1573 : GF_SceneGraph *sg;
1574 : #endif
1575 : GF_Scene *scene=NULL;
1576 : GF_SCENEJSExt *sjs = (GF_SCENEJSExt *)JS_GetOpaque(this_val, scene_class_id);
1577 : if (!sjs || !argc || !JS_IsObject(argv[0])) return JS_EXCEPTION;
1578 :
1579 : elt = gf_sg_js_get_node(ctx, argv[0]);
1580 : if (!elt) return JS_EXCEPTION;
1581 : switch (elt->sgprivate->tag) {
1582 : #ifndef GPAC_DISABLE_VRML
1583 : case TAG_MPEG4_Inline:
1584 : scene = (GF_Scene *)gf_node_get_private(elt);
1585 : break;
1586 : #endif
1587 :
1588 : #ifndef GPAC_DISABLE_X3D
1589 : case TAG_X3D_Inline:
1590 : scene = (GF_Scene *)gf_node_get_private(elt);
1591 : break;
1592 : #endif
1593 :
1594 : #ifndef GPAC_DISABLE_SVG
1595 : case TAG_SVG_animation:
1596 : sg = gf_sc_animation_get_scenegraph(elt);
1597 : scene = (GF_Scene *)gf_sg_get_private(sg);
1598 : break;
1599 : #endif
1600 : default:
1601 : return JS_EXCEPTION;
1602 : }
1603 : if (!scene) return JS_EXCEPTION;
1604 :
1605 :
1606 : scene_obj = JS_NewObjectClass(ctx, any_class_id);
1607 : if (JS_IsException(scene_obj)) return scene_obj;
1608 : JS_SetOpaque(scene_obj, scene);
1609 : gf_sg_get_scene_size_info(scene->graph, &w, &h);
1610 : JS_SetPropertyStr(ctx, scene_obj, "width", JS_NewInt32(ctx, w));
1611 : JS_SetPropertyStr(ctx, scene_obj, "height", JS_NewInt32(ctx, h));
1612 : JS_SetPropertyStr(ctx, scene_obj, "connected", JS_NewBool(ctx, scene->graph ? 1 : 0));
1613 : return scene_obj;
1614 : }
1615 : #endif
1616 :
1617 1 : static JSValue scenejs_show_keyboard(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
1618 : {
1619 : GF_Compositor *compositor = scenejs_get_compositor(ctx, this_val);
1620 1 : if (!compositor || !argc) return JS_EXCEPTION;
1621 :
1622 : GF_Event evt;
1623 : memset(&evt, 0, sizeof(GF_Event));
1624 1 : evt.type = JS_ToBool(ctx, argv[0]) ? GF_EVENT_TEXT_EDITING_START : GF_EVENT_TEXT_EDITING_END;
1625 1 : gf_sc_user_event(compositor, &evt);
1626 1 : return JS_UNDEFINED;
1627 : }
1628 :
1629 : static const JSCFunctionListEntry scenejs_evt_funcs[] = {
1630 : JS_CGETSET_MAGIC_DEF("keycode", gpacevt_getProperty, NULL, GJS_EVT_PROP_KEYCODE),
1631 : JS_CGETSET_MAGIC_DEF("mouse_x", gpacevt_getProperty, NULL, GJS_EVT_PROP_MOUSE_X),
1632 : JS_CGETSET_MAGIC_DEF("mouse_y", gpacevt_getProperty, NULL, GJS_EVT_PROP_MOUSE_Y),
1633 : JS_CGETSET_MAGIC_DEF("picked", gpacevt_getProperty, NULL, GJS_EVT_PROP_PICKED),
1634 : JS_CGETSET_MAGIC_DEF("wheel", gpacevt_getProperty, NULL, GJS_EVT_PROP_WHEEL),
1635 : JS_CGETSET_MAGIC_DEF("button", gpacevt_getProperty, NULL, GJS_EVT_PROP_BUTTON),
1636 : JS_CGETSET_MAGIC_DEF("type", gpacevt_getProperty, NULL, GJS_EVT_PROP_TYPE),
1637 : JS_CGETSET_MAGIC_DEF("name", gpacevt_getProperty, NULL, GJS_EVT_PROP_NAME),
1638 : JS_CGETSET_MAGIC_DEF("hwkey", gpacevt_getProperty, NULL, GJS_EVT_PROP_HWKEY),
1639 : JS_CGETSET_MAGIC_DEF("url", gpacevt_getProperty, NULL, GJS_EVT_PROP_TARGET_URL),
1640 : JS_CGETSET_MAGIC_DEF("dropfiles", gpacevt_getProperty, NULL, GJS_EVT_PROP_FILES),
1641 : };
1642 :
1643 : static const JSCFunctionListEntry scenejs_funcs[] = {
1644 : JS_CGETSET_MAGIC_DEF("fullscreen", scenejs_getProperty, scenejs_setProperty, GJS_SCENE_PROP_FULLSCREEN),
1645 : JS_CGETSET_MAGIC_DEF("current_path", scenejs_getProperty, NULL, GJS_SCENE_PROP_CURRENT_PATH),
1646 : JS_CGETSET_MAGIC_DEF("volume", scenejs_getProperty, scenejs_setProperty, GJS_SCENE_PROP_VOLUME),
1647 : JS_CGETSET_MAGIC_DEF("navigation", scenejs_getProperty, scenejs_setProperty, GJS_SCENE_PROP_NAVIGATION),
1648 : JS_CGETSET_MAGIC_DEF("navigation_type", scenejs_getProperty, scenejs_setProperty, GJS_SCENE_PROP_NAVIGATION_TYPE),
1649 : JS_CGETSET_MAGIC_DEF("hardware_yuv", scenejs_getProperty, NULL, GJS_SCENE_PROP_HARDWARE_YUV),
1650 : JS_CGETSET_MAGIC_DEF("hardware_rgb", scenejs_getProperty, NULL, GJS_SCENE_PROP_HARDWARE_RGB),
1651 : JS_CGETSET_MAGIC_DEF("hardware_rgba", scenejs_getProperty, NULL, GJS_SCENE_PROP_HARDWARE_RGBA),
1652 : JS_CGETSET_MAGIC_DEF("hardware_stretch", scenejs_getProperty, NULL, GJS_SCENE_PROP_HARDWARE_STRETCH),
1653 : JS_CGETSET_MAGIC_DEF("screen_width", scenejs_getProperty, NULL, GJS_SCENE_PROP_SCREEN_WIDTH),
1654 : JS_CGETSET_MAGIC_DEF("screen_height", scenejs_getProperty, NULL, GJS_SCENE_PROP_SCREEN_HEIGHT),
1655 : JS_CGETSET_MAGIC_DEF("fps", scenejs_getProperty, NULL, GJS_SCENE_PROP_FPS),
1656 : JS_CGETSET_MAGIC_DEF("sim_fps", scenejs_getProperty, NULL, GJS_SCENE_PROP_SIM_FPS),
1657 : JS_CGETSET_MAGIC_DEF("has_opengl", scenejs_getProperty, NULL, GJS_SCENE_PROP_HAS_OPENGL),
1658 : JS_CGETSET_MAGIC_DEF("caption", scenejs_getProperty, scenejs_setProperty, GJS_SCENE_PROP_CAPTION),
1659 : JS_CGETSET_MAGIC_DEF("focus_highlight", scenejs_getProperty, scenejs_setProperty, GJS_SCENE_PROP_FOCUS_HIGHLIGHT),
1660 : JS_CGETSET_MAGIC_DEF("dpi_x", scenejs_getProperty, NULL, GJS_SCENE_PROP_DPI_X),
1661 : JS_CGETSET_MAGIC_DEF("dpi_y", scenejs_getProperty, NULL, GJS_SCENE_PROP_DPI_Y),
1662 : JS_CGETSET_MAGIC_DEF("sensors_active", scenejs_getProperty, scenejs_setProperty, GJS_SCENE_PROP_SENSORS_ACTIVE),
1663 : JS_CGETSET_MAGIC_DEF("zoom", scenejs_getProperty, NULL, GJS_SCENE_PROP_ZOOM),
1664 : JS_CGETSET_MAGIC_DEF("text_selection", scenejs_getProperty, NULL, GJS_SCENE_PROP_TEXT_SEL),
1665 : JS_CFUNC_DEF("get_option", 0, scenejs_get_option),
1666 : JS_CFUNC_DEF("set_option", 0, scenejs_set_option),
1667 : JS_CFUNC_DEF("set_size", 0, scenejs_set_size),
1668 : JS_CFUNC_DEF("exit", 0, scenejs_exit),
1669 : JS_CFUNC_DEF("set_3d", 0, scenejs_set_3d),
1670 : JS_CFUNC_DEF("move_window", 0, scenejs_move_window),
1671 : JS_CFUNC_DEF("set_event_filter", 0, scenejs_set_event_filter),
1672 : JS_CFUNC_DEF("set_focus", 0, scenejs_set_focus),
1673 : JS_CFUNC_DEF("show_keyboard", 0, scenejs_show_keyboard),
1674 : JS_CFUNC_DEF("trigger_gc", 0, scenejs_trigger_gc),
1675 : JS_CFUNC_DEF("get_object_manager", 0, scenejs_get_object_manager),
1676 : JS_CFUNC_DEF("switch_quality", 0, scenejs_switch_quality),
1677 : JS_CFUNC_DEF("navigation_supported", 0, scenejs_navigation_supported),
1678 : JS_CFUNC_DEF("set_back_color", 0, scenejs_set_back_color)
1679 : };
1680 :
1681 : static const JSCFunctionListEntry odm_funcs[] = {
1682 : JS_CGETSET_MAGIC_DEF("ID", odm_getProperty, NULL, GJS_OM_PROP_ID),
1683 : JS_CGETSET_MAGIC_DEF("nb_resources", odm_getProperty, NULL, GJS_OM_PROP_NB_RES),
1684 : JS_CGETSET_MAGIC_DEF("service_url", odm_getProperty, NULL, GJS_OM_PROP_URL),
1685 : JS_CGETSET_MAGIC_DEF("duration", odm_getProperty, NULL, GJS_OM_PROP_DUR),
1686 : JS_CGETSET_MAGIC_DEF("clock_time", odm_getProperty, NULL, GJS_OM_PROP_CLOCK),
1687 : JS_CGETSET_MAGIC_DEF("clock_drift", odm_getProperty, NULL, GJS_OM_PROP_DRIFT),
1688 : JS_CGETSET_MAGIC_DEF("status", odm_getProperty, NULL, GJS_OM_PROP_STATUS),
1689 : JS_CGETSET_MAGIC_DEF("buffer", odm_getProperty, NULL, GJS_OM_PROP_BUFFER),
1690 : JS_CGETSET_MAGIC_DEF("db_unit_count", odm_getProperty, NULL, GJS_OM_PROP_DB_COUNT),
1691 : JS_CGETSET_MAGIC_DEF("cb_unit_count", odm_getProperty, NULL, GJS_OM_PROP_CB_COUNT),
1692 : JS_CGETSET_MAGIC_DEF("cb_capacity", odm_getProperty, NULL, GJS_OM_PROP_CB_CAP),
1693 : JS_CGETSET_MAGIC_DEF("type", odm_getProperty, NULL, GJS_OM_PROP_TYPE),
1694 : JS_CGETSET_MAGIC_DEF("samplerate", odm_getProperty, NULL, GJS_OM_PROP_SAMPLERATE),
1695 : JS_CGETSET_MAGIC_DEF("channels", odm_getProperty, NULL, GJS_OM_PROP_CHANNELS),
1696 : JS_CGETSET_MAGIC_DEF("lang", odm_getProperty, NULL, GJS_OM_PROP_LANG),
1697 : JS_CGETSET_MAGIC_DEF("width", odm_getProperty, NULL, GJS_OM_PROP_WIDTH),
1698 : JS_CGETSET_MAGIC_DEF("height", odm_getProperty, NULL, GJS_OM_PROP_HEIGHT),
1699 : JS_CGETSET_MAGIC_DEF("pixelformt", odm_getProperty, NULL, GJS_OM_PROP_PIXELFORMAT),
1700 : JS_CGETSET_MAGIC_DEF("par", odm_getProperty, NULL, GJS_OM_PROP_PAR),
1701 : JS_CGETSET_MAGIC_DEF("dec_frames", odm_getProperty, NULL, GJS_OM_PROP_DEC_FRAMES),
1702 : JS_CGETSET_MAGIC_DEF("drop_frames", odm_getProperty, NULL, GJS_OM_PROP_DROP_FRAMES),
1703 : JS_CGETSET_MAGIC_DEF("max_dec_time", odm_getProperty, NULL, GJS_OM_PROP_DEC_TIME_MAX),
1704 : JS_CGETSET_MAGIC_DEF("total_dec_time", odm_getProperty, NULL, GJS_OM_PROP_DEC_TIME_TOTAL),
1705 : JS_CGETSET_MAGIC_DEF("avg_bitrate", odm_getProperty, NULL, GJS_OM_PROP_AVG_RATE),
1706 : JS_CGETSET_MAGIC_DEF("max_bitrate", odm_getProperty, NULL, GJS_OM_PROP_MAX_RATE),
1707 : JS_CGETSET_MAGIC_DEF("service_handler", odm_getProperty, NULL, GJS_OM_PROP_SERVICE_HANDLER),
1708 : JS_CGETSET_MAGIC_DEF("codec", odm_getProperty, NULL, GJS_OM_PROP_CODEC),
1709 : JS_CGETSET_MAGIC_DEF("nb_qualities", odm_getProperty, NULL, GJS_OM_PROP_NB_QUALITIES),
1710 : JS_CGETSET_MAGIC_DEF("max_buffer", odm_getProperty, NULL, GJS_OM_PROP_MAX_BUFFER),
1711 : JS_CGETSET_MAGIC_DEF("min_buffer", odm_getProperty, NULL, GJS_OM_PROP_MIN_BUFFER),
1712 : JS_CGETSET_MAGIC_DEF("frame_duration", odm_getProperty, NULL, GJS_OM_PROP_FRAME_DUR),
1713 : JS_CGETSET_MAGIC_DEF("irap_frames", odm_getProperty, NULL, GJS_OM_PROP_NB_IRAP),
1714 : JS_CGETSET_MAGIC_DEF("irap_dec_time", odm_getProperty, NULL, GJS_OM_PROP_IRAP_DEC_TIME),
1715 : JS_CGETSET_MAGIC_DEF("irap_max_time", odm_getProperty, NULL, GJS_OM_PROP_IRAP_MAX_TIME),
1716 : JS_CGETSET_MAGIC_DEF("service_id", odm_getProperty, NULL, GJS_OM_PROP_SERVICE_ID),
1717 : JS_CGETSET_MAGIC_DEF("selected_service", odm_getProperty, NULL, GJS_OM_PROP_SELECTED_SERVICE),
1718 : JS_CGETSET_MAGIC_DEF("bandwidth_down", odm_getProperty, NULL, GJS_OM_PROP_BANDWIDTH_DOWN),
1719 : JS_CGETSET_MAGIC_DEF("nb_http", odm_getProperty, NULL, GJS_OM_PROP_NB_HTTP),
1720 : JS_CGETSET_MAGIC_DEF("timeshift_depth", odm_getProperty, NULL, GJS_OM_PROP_TIMESHIFT_DEPTH),
1721 : JS_CGETSET_MAGIC_DEF("timeshift_time", odm_getProperty, NULL, GJS_OM_PROP_TIMESHIFT_TIME),
1722 : JS_CGETSET_MAGIC_DEF("is_addon", odm_getProperty, NULL, GJS_OM_PROP_IS_ADDON),
1723 : JS_CGETSET_MAGIC_DEF("main_addon_on", odm_getProperty, NULL, GJS_OM_PROP_MAIN_ADDON_ON),
1724 : JS_CGETSET_MAGIC_DEF("is_over", odm_getProperty, NULL, GJS_OM_PROP_IS_OVER),
1725 : JS_CGETSET_MAGIC_DEF("dynamic_scene", odm_getProperty, NULL, GJS_OM_PROP_DYNAMIC_SCENE),
1726 : JS_CGETSET_MAGIC_DEF("service_name", odm_getProperty, NULL, GJS_OM_PROP_SERVICE_NAME),
1727 : JS_CGETSET_MAGIC_DEF("ntp_diff", odm_getProperty, NULL, GJS_OM_PROP_NTP_DIFF),
1728 : JS_CGETSET_MAGIC_DEF("ntp_sender_diff", odm_getProperty, NULL, GJS_OM_PROP_NTP_SENDER_DIFF),
1729 : JS_CGETSET_MAGIC_DEF("main_addon_url", odm_getProperty, NULL, GJS_OM_PROP_MAIN_ADDON_URL),
1730 : JS_CGETSET_MAGIC_DEF("reverse_playback_supported", odm_getProperty, NULL, GJS_OM_PROP_REVERSE_PLAYBACK),
1731 : JS_CGETSET_MAGIC_DEF("scalable_enhancement", odm_getProperty, NULL, GJS_OM_PROP_SCALABLE_ENHANCEMENT),
1732 : JS_CGETSET_MAGIC_DEF("main_addon_media_time", odm_getProperty, NULL, GJS_OM_PROP_MAIN_ADDON_MEDIATIME),
1733 : JS_CGETSET_MAGIC_DEF("dependent_groups", odm_getProperty, NULL, GJS_OM_PROP_DEPENDENT_GROUPS),
1734 : JS_CGETSET_MAGIC_DEF("vr_scene", odm_getProperty, NULL, GJS_OM_PROP_IS_VR_SCENE),
1735 : JS_CGETSET_MAGIC_DEF("disabled", odm_getProperty, NULL, GJS_OM_PROP_DISABLED),
1736 : JS_CGETSET_MAGIC_DEF("buffering", odm_getProperty, NULL, GJS_OM_PROP_BUFFERING),
1737 :
1738 : JS_CFUNC_DEF("declare_addon", 0, gjs_odm_declare_addon),
1739 : JS_CFUNC_DEF("enable_addon", 0, gjs_odm_enable_addon),
1740 : JS_CFUNC_DEF("addon_layout", 0, gjs_odm_addon_layout),
1741 : JS_CFUNC_DEF("get_resource", 0, gjs_odm_get_resource),
1742 : JS_CFUNC_DEF("get_quality", 0, gjs_odm_get_quality),
1743 : JS_CFUNC_DEF("select_service", 0, gjs_odm_select_service),
1744 : JS_CFUNC_DEF("select_quality", 0, gjs_odm_select_quality),
1745 : JS_CFUNC_DEF("disable_main_addon", 0, gjs_odm_disable_main_addon),
1746 : JS_CFUNC_DEF("select", 0, gjs_odm_select),
1747 : JS_CFUNC_DEF("get_srd", 0, gjs_odm_get_srd),
1748 : JS_CFUNC_DEF("in_parent_chain", 0, gjs_odm_in_parent_chain),
1749 : };
1750 :
1751 : #include "../filter_core/filter_session.h"
1752 :
1753 4 : static void scenejs_finalize(JSRuntime *rt, JSValue obj)
1754 : {
1755 4 : GF_SCENEJSExt *sjs = JS_GetOpaque(obj, scene_class_id);
1756 4 : if (!sjs) return;
1757 :
1758 4 : JS_SetOpaque(obj, NULL);
1759 :
1760 8 : while (gf_list_count(sjs->storages)) {
1761 0 : GF_Config *cfg = (GF_Config *) gf_list_pop_back(sjs->storages);
1762 0 : gf_cfg_discard_changes(cfg);
1763 0 : gf_cfg_del(cfg);
1764 : }
1765 4 : gf_list_del(sjs->storages);
1766 :
1767 8 : while (gf_list_count(sjs->event_queue)) {
1768 0 : GF_Event *evt = (GF_Event *) gf_list_pop_back(sjs->event_queue);
1769 0 : gf_free(evt);
1770 : }
1771 4 : gf_list_del(sjs->event_queue);
1772 4 : gf_mx_del(sjs->event_mx);
1773 :
1774 4 : if (sjs->compositor && sjs->compositor->filter) {
1775 4 : gf_fs_unload_script(sjs->compositor->filter->session, NULL);
1776 : }
1777 : /*if we destroy the script context holding the gpac event filter (only one for the time being), remove the filter*/
1778 : JS_FreeValueRT(rt, sjs->evt_fun);
1779 4 : if (sjs->evt_filter.udta) {
1780 3 : if (sjs->compositor)
1781 3 : gf_filter_remove_event_listener(sjs->compositor->filter, &sjs->evt_filter);
1782 3 : sjs->evt_filter.udta = NULL;
1783 : }
1784 :
1785 4 : gf_free(sjs);
1786 : }
1787 :
1788 4 : static int js_scene_init(JSContext *c, JSModuleDef *m)
1789 : {
1790 : GF_JSAPIParam par;
1791 : GF_SCENEJSExt *sjs;
1792 4 : GF_SAFEALLOC(sjs, GF_SCENEJSExt);
1793 : GF_SceneGraph *scene;
1794 4 : if (!sjs) {
1795 : return -1;
1796 : }
1797 4 : sjs->storages = gf_list_new();
1798 4 : sjs->event_queue = gf_list_new();
1799 4 : sjs->event_mx = gf_mx_new("GPACJSEvt");
1800 4 : sjs->evt_fun = JS_UNDEFINED;
1801 4 : sjs->scene_obj = JS_UNDEFINED;
1802 4 : sjs->evt_obj = JS_UNDEFINED;
1803 :
1804 4 : scene = JS_GetContextOpaque(c);
1805 4 : if (!scene) return -1;
1806 4 : if (scene->__reserved_null) {
1807 4 : GF_Node *n = JS_GetContextOpaque(c);
1808 4 : scene = n->sgprivate->scenegraph;
1809 : }
1810 :
1811 4 : if (!scene_class_id) {
1812 4 : JS_NewClassID(&scene_class_id);
1813 4 : JS_NewClass(JS_GetRuntime(c), scene_class_id, &sceneClass);
1814 :
1815 4 : JS_NewClassID(&odm_class_id);
1816 4 : JS_NewClass(JS_GetRuntime(c), odm_class_id, &odmClass);
1817 : }
1818 4 : JSValue proto = JS_NewObjectClass(c, odm_class_id);
1819 4 : JS_SetPropertyFunctionList(c, proto, odm_funcs, countof(odm_funcs));
1820 4 : JS_SetClassProto(c, odm_class_id, proto);
1821 :
1822 4 : JS_NewClassID(&gpacevt_class_id);
1823 4 : JS_NewClass(JS_GetRuntime(c), gpacevt_class_id, &gpacEvtClass);
1824 :
1825 4 : JS_NewClassID(&any_class_id);
1826 4 : JS_NewClass(JS_GetRuntime(c), any_class_id, &anyClass);
1827 :
1828 4 : JSValue global = JS_GetGlobalObject(c);
1829 :
1830 4 : sjs->scene_obj = JS_NewObjectClass(c, scene_class_id);
1831 4 : JS_SetPropertyFunctionList(c, sjs->scene_obj, scenejs_funcs, countof(scenejs_funcs));
1832 4 : JS_SetOpaque(sjs->scene_obj, sjs);
1833 : // JS_SetPropertyStr(c, global, "gpac", sjs->scene_obj);
1834 :
1835 4 : if (scene->script_action) {
1836 4 : if (scene->script_action(scene->script_action_cbck, GF_JSAPI_OP_GET_COMPOSITOR, scene->RootNode, &par)) {
1837 4 : sjs->compositor = par.compositor;
1838 : }
1839 : }
1840 4 : if (sjs->compositor && sjs->compositor->filter) {
1841 : GF_Err gf_fs_load_js_api(JSContext *c, GF_FilterSession *fs);
1842 4 : GF_FilterSession *fs = sjs->compositor->filter->session;
1843 :
1844 : //don't check error code, this may fail if global JS has been set but the script may still run
1845 4 : if (gf_fs_load_js_api(c, fs) == GF_OK) {
1846 4 : scene->attached_session = fs;
1847 : }
1848 : }
1849 :
1850 4 : sjs->evt_obj = JS_NewObjectClass(c, gpacevt_class_id);
1851 4 : JS_SetPropertyFunctionList(c, sjs->evt_obj, scenejs_evt_funcs, countof(scenejs_evt_funcs));
1852 4 : JS_SetOpaque(sjs->evt_obj, NULL);
1853 4 : JS_SetPropertyStr(c, global, "gpacevt", sjs->evt_obj);
1854 :
1855 : #define DECLARE_CONST(_val) \
1856 : JS_SetPropertyStr(c, global, #_val, JS_NewInt32(c, _val));
1857 :
1858 4 : DECLARE_CONST(GF_EVENT_CLICK);
1859 4 : DECLARE_CONST(GF_EVENT_MOUSEUP);
1860 4 : DECLARE_CONST(GF_EVENT_MOUSEDOWN);
1861 4 : DECLARE_CONST(GF_EVENT_MOUSEMOVE);
1862 4 : DECLARE_CONST(GF_EVENT_MOUSEWHEEL);
1863 4 : DECLARE_CONST(GF_EVENT_DBLCLICK);
1864 4 : DECLARE_CONST(GF_EVENT_KEYUP);
1865 4 : DECLARE_CONST(GF_EVENT_KEYDOWN);
1866 4 : DECLARE_CONST(GF_EVENT_TEXTINPUT);
1867 4 : DECLARE_CONST(GF_EVENT_CONNECT);
1868 4 : DECLARE_CONST(GF_EVENT_NAVIGATE_INFO);
1869 4 : DECLARE_CONST(GF_EVENT_NAVIGATE);
1870 4 : DECLARE_CONST(GF_EVENT_DROPFILE);
1871 4 : DECLARE_CONST(GF_EVENT_ADDON_DETECTED);
1872 4 : DECLARE_CONST(GF_EVENT_QUALITY_SWITCHED);
1873 4 : DECLARE_CONST(GF_EVENT_TIMESHIFT_DEPTH);
1874 4 : DECLARE_CONST(GF_EVENT_TIMESHIFT_UPDATE);
1875 4 : DECLARE_CONST(GF_EVENT_TIMESHIFT_OVERFLOW);
1876 4 : DECLARE_CONST(GF_EVENT_TIMESHIFT_UNDERRUN);
1877 4 : DECLARE_CONST(GF_EVENT_QUIT);
1878 4 : DECLARE_CONST(GF_EVENT_MAIN_ADDON_STATE);
1879 4 : DECLARE_CONST(GF_EVENT_SCENE_SIZE);
1880 :
1881 4 : DECLARE_CONST(GF_NAVIGATE_NONE);
1882 4 : DECLARE_CONST(GF_NAVIGATE_WALK);
1883 4 : DECLARE_CONST(GF_NAVIGATE_FLY);
1884 4 : DECLARE_CONST(GF_NAVIGATE_PAN);
1885 4 : DECLARE_CONST(GF_NAVIGATE_GAME);
1886 4 : DECLARE_CONST(GF_NAVIGATE_SLIDE);
1887 4 : DECLARE_CONST(GF_NAVIGATE_EXAMINE);
1888 4 : DECLARE_CONST(GF_NAVIGATE_ORBIT);
1889 4 : DECLARE_CONST(GF_NAVIGATE_VR);
1890 :
1891 4 : DECLARE_CONST(GF_NAVIGATE_TYPE_NONE);
1892 4 : DECLARE_CONST(GF_NAVIGATE_TYPE_2D);
1893 4 : DECLARE_CONST(GF_NAVIGATE_TYPE_3D);
1894 :
1895 : JS_FreeValue(c, global);
1896 :
1897 4 : JS_SetModuleExport(c, m, "scene", sjs->scene_obj);
1898 4 : return 0;
1899 : }
1900 :
1901 :
1902 404 : void qjs_module_init_scenejs(JSContext *ctx)
1903 : {
1904 : JSModuleDef *m;
1905 404 : m = JS_NewCModule(ctx, "scenejs", js_scene_init);
1906 404 : if (!m) return;
1907 :
1908 404 : JS_AddModuleExport(ctx, m, "scene");
1909 404 : return;
1910 : }
1911 :
1912 :
1913 : #endif
1914 :
|