LCOV - code coverage report
Current view: top level - filters - jsfilter.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1828 2685 68.1 %
Date: 2021-04-29 23:48:07 Functions: 112 118 94.9 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2019-2021
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / QuickJS bindings for GF_Filter
       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             : /*
      28             :         ANY CHANGE TO THE API MUST BE REFLECTED IN THE DOCUMENTATION IN gpac/share/doc/idl/jsf.idl
      29             :         (no way to define inline JS doc with doxygen)
      30             : */
      31             : 
      32             : #include <gpac/filters.h>
      33             : #include <gpac/list.h>
      34             : #include <gpac/constants.h>
      35             : #include <gpac/network.h>
      36             : 
      37             : #ifdef GPAC_HAS_QJS
      38             : 
      39             : #include <gpac/internal/scenegraph_dev.h>
      40             : #include "../scenegraph/qjs_common.h"
      41             : 
      42             : 
      43             : //to load session API
      44             : #include "../filter_core/filter_session.h"
      45             : 
      46             : /*
      47             :         Currently unmapped functions
      48             : 
      49             : //likely not needed
      50             : u32     gf_filter_count_source_by_protocol (GF_Filter *filter, const char *protocol_scheme, Bool expand_proto, GF_FilterPid *(*enum_pids)(void *udta, u32 *idx), void *udta)
      51             : GF_FilterPacket *       gf_filter_pck_new_frame_interface (GF_FilterPid *PID, GF_FilterFrameInterface *frame_ifce, gf_fsess_packet_destructor destruct)
      52             : GF_FilterFrameInterface *       gf_filter_pck_get_frame_interface (GF_FilterPacket *pck)
      53             : 
      54             : //todo
      55             : GF_Err  gf_filter_add_event_listener (GF_Filter *filter, GF_FSEventListener *el)
      56             : GF_Err  gf_filter_remove_event_listener (GF_Filter *filter, GF_FSEventListener *el)
      57             : Bool    gf_filter_forward_gf_event (GF_Filter *filter, GF_Event *evt, Bool consumed, Bool skip_user)
      58             : Bool    gf_filter_send_gf_event (GF_Filter *filter, GF_Event *evt)
      59             : Bool    gf_filter_ui_event (GF_Filter *filter, GF_Event *uievt)
      60             : void    gf_filter_register_opengl_provider (GF_Filter *filter, Bool do_register)
      61             : GF_Err  gf_filter_request_opengl (GF_Filter *filter)
      62             : 
      63             : //either not needed or require a dedicated module
      64             : GF_DownloadManager *gf_filter_get_download_manager (GF_Filter *filter)
      65             : 
      66             : 
      67             : */
      68             : 
      69             : enum
      70             : {
      71             :         JSF_EVT_INITIALIZE=0,
      72             :         JSF_EVT_FINALIZE,
      73             :         JSF_EVT_CONFIGURE_PID,
      74             :         JSF_EVT_PROCESS,
      75             :         JSF_EVT_PROCESS_EVENT,
      76             :         JSF_EVT_UPDATE_ARG,
      77             :         JSF_EVT_PROBE_URL,
      78             :         JSF_EVT_PROBE_DATA,
      79             :         JSF_EVT_RECONFIGURE_OUTPUT,
      80             :         JSF_EVT_REMOVE_PID,
      81             : 
      82             :         JSF_EVT_LAST_DEFINED,
      83             : 
      84             :         JSF_FILTER_MAX_PIDS,
      85             :         JSF_FILTER_BLOCK_ENABLED,
      86             :         JSF_FILTER_OUTPUT_BUFFER,
      87             :         JSF_FILTER_OUTPUT_PLAYOUT,
      88             :         JSF_FILTER_SEP_ARGS,
      89             :         JSF_FILTER_SEP_NAME,
      90             :         JSF_FILTER_SEP_LIST,
      91             :         JSF_FILTER_DST_ARGS,
      92             :         JSF_FILTER_DST_NAME,
      93             :         JSF_FILTER_SINKS_DONE,
      94             :         JSF_FILTER_REPORTING_ENABLED,
      95             : 
      96             :         JSF_FILTER_CAPS_MAX_WIDTH,
      97             :         JSF_FILTER_CAPS_MAX_HEIGHT,
      98             :         JSF_FILTER_CAPS_MAX_DISPLAY_DEPTH,
      99             :         JSF_FILTER_CAPS_MAX_FPS,
     100             :         JSF_FILTER_CAPS_MAX_VIEWS,
     101             :         JSF_FILTER_CAPS_MAX_CHANNELS,
     102             :         JSF_FILTER_CAPS_MAX_SAMPLERATE,
     103             :         JSF_FILTER_CAPS_MAX_AUDIO_DEPTH,
     104             :         JSF_FILTER_NB_EVTS_QUEUED,
     105             :         JSF_FILTER_CLOCK_HINT_TIME,
     106             :         JSF_FILTER_CLOCK_HINT_MEDIATIME,
     107             :         JSF_FILTER_CONNECTIONS_PENDING,
     108             :         JSF_FILTER_INAME
     109             : };
     110             : 
     111             : enum
     112             : {
     113             :         JSF_SETUP_ERROR=0,
     114             :         JSF_NOTIF_ERROR,
     115             :         JSF_NOTIF_ERROR_AND_DISCONNECT
     116             : };
     117             : 
     118             : 
     119             : typedef struct
     120             : {
     121             :         //options
     122             :         const char *js;
     123             : 
     124             :         GF_Filter *filter;
     125             :         Bool is_custom;
     126             : 
     127             :         JSContext *ctx;
     128             : 
     129             :         Bool initialized;
     130             :         JSValue funcs[JSF_EVT_LAST_DEFINED];
     131             :         JSValue filter_obj;
     132             : 
     133             :         GF_FilterArgs *args;
     134             :         u32 nb_args;
     135             :         Bool has_wilcard_arg;
     136             : 
     137             :         GF_FilterCapability *caps;
     138             :         u32 nb_caps;
     139             : 
     140             :         GF_List *pids;
     141             :         char *log_name;
     142             : 
     143             :         GF_List *pck_res;
     144             : 
     145             :         Bool unload_session_api;
     146             :         Bool disable_filter;
     147             : } GF_JSFilterCtx;
     148             : 
     149             : enum
     150             : {
     151             :         JSF_PID_NAME=0,
     152             :         JSF_PID_EOS,
     153             :         JSF_PID_EOS_SEEN,
     154             :         JSF_PID_EOS_RECEIVED,
     155             :         JSF_PID_WOULD_BLOCK,
     156             :         JSF_PID_FILTER_NAME,
     157             :         JSF_PID_FILTER_SRC,
     158             :         JSF_PID_FILTER_ARGS,
     159             :         JSF_PID_FILTER_SRC_ARGS,
     160             :         JSF_PID_FILTER_UNICITY_ARGS,
     161             :         JSF_PID_MAX_BUFFER,
     162             :         JSF_PID_LOOSE_CONNECT,
     163             :         JSF_PID_FRAMING_MODE,
     164             :         JSF_PID_BUFFER,
     165             :         JSF_PID_IS_FULL,
     166             :         JSF_PID_FIRST_EMPTY,
     167             :         JSF_PID_FIRST_CTS,
     168             :         JSF_PID_NB_PACKETS,
     169             :         JSF_PID_TIMESCALE,
     170             :         JSF_PID_CLOCK_MODE,
     171             :         JSF_PID_DISCARD,
     172             :         JSF_PID_SRC_URL,
     173             :         JSF_PID_DST_URL,
     174             :         JSF_PID_REQUIRE_SOURCEID,
     175             :         JSF_PID_RECOMPUTE_DTS,
     176             :         JSF_PID_MIN_PCK_DUR,
     177             :         JSF_PID_IS_PLAYING,
     178             : };
     179             : typedef struct
     180             : {
     181             :         GF_JSFilterCtx *jsf;
     182             :         GF_FilterPid *pid;
     183             :         JSValue jsobj;
     184             :         struct _js_pck_ctx *pck_head;
     185             :         GF_List *shared_pck;
     186             : } GF_JSPidCtx;
     187             : 
     188             : enum
     189             : {
     190             :         GF_JS_PCK_IS_REF = 1,
     191             :         GF_JS_PCK_IS_SHARED = 1<<1,
     192             :         GF_JS_PCK_IS_OUTPUT = 1<<2
     193             : };
     194             : 
     195             : typedef struct _js_pck_ctx
     196             : {
     197             :         GF_JSPidCtx *jspid;
     198             :         GF_FilterPacket *pck;
     199             :         JSValue jsobj;
     200             :         //shared packet, this is a string or an array buffer
     201             :         JSValue ref_val;
     202             :         //shared packet callback
     203             :         JSValue cbck_val;
     204             :         //array buffer
     205             :         JSValue data_ab;
     206             :         u32 flags;
     207             : } GF_JSPckCtx;
     208             : 
     209             : typedef enum
     210             : {
     211             :         JSF_FINST_SOURCE=0,
     212             :         JSF_FINST_DEST,
     213             :         JSF_FINST_FILTER,
     214             : } GF_JSFilterMode;
     215             : typedef struct
     216             : {
     217             :         GF_JSFilterCtx *jsf;
     218             :         GF_Filter *filter;
     219             :         JSValue filter_obj;
     220             :         GF_JSFilterMode fmode;
     221             :         JSValue setup_failure_fun;
     222             : 
     223             : } GF_JSFilterInstanceCtx;
     224             : 
     225             : 
     226             : static JSClassID jsf_filter_class_id;
     227             : 
     228         196 : static void jsf_filter_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func)
     229             : {
     230         196 :     GF_JSFilterCtx *jsf = JS_GetOpaque(val, jsf_filter_class_id);
     231         196 :     if (jsf) {
     232             :         u32 i;
     233         680 :         for (i=0; i<JSF_EVT_LAST_DEFINED; i++) {
     234         680 :             JS_MarkValue(rt, jsf->funcs[i], mark_func);
     235             :                 }
     236             :     }
     237         196 : }
     238             : static JSClassDef jsf_filter_class = {
     239             :     "JSFilter",
     240             :         .gc_mark = jsf_filter_mark
     241             : };
     242             : 
     243             : static JSClassID jsf_filter_inst_class_id;
     244             : 
     245         252 : static void jsf_filter_inst_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func)
     246             : {
     247         252 :     GF_JSFilterInstanceCtx *f_inst = JS_GetOpaque(val, jsf_filter_inst_class_id);
     248         252 :     if (f_inst) {
     249          16 :                 JS_MarkValue(rt, f_inst->setup_failure_fun, mark_func);
     250             :     }
     251         252 : }
     252          47 : static void jsf_filter_inst_finalizer(JSRuntime *rt, JSValue val) {
     253          47 :     GF_JSFilterInstanceCtx *f_inst = JS_GetOpaque(val, jsf_filter_inst_class_id);
     254          47 :     if (!f_inst) return;
     255             :     JS_FreeValueRT(rt, f_inst->setup_failure_fun);
     256           5 :     gf_free(f_inst);
     257             : }
     258             : static JSClassDef jsf_filter_inst_class = {
     259             :     "FilterInstance",
     260             :     .finalizer = jsf_filter_inst_finalizer,
     261             :         .gc_mark = jsf_filter_inst_mark
     262             : };
     263             : 
     264             : static JSClassID jsf_pid_class_id;
     265             : static JSClassDef jsf_pid_class = {
     266             :     "FilterPid",
     267             : };
     268             : 
     269             : static JSClassID jsf_event_class_id;
     270         496 : static void jsf_evt_finalizer(JSRuntime *rt, JSValue val)
     271             : {
     272         496 :         GF_FilterEvent *evt = JS_GetOpaque(val, jsf_event_class_id);
     273         496 :     if (!evt) return;
     274           7 :     if (evt->base.type==GF_FEVT_USER) {
     275           1 :                 if (evt->user_event.event.type==GF_EVENT_SET_CAPTION) {
     276           1 :                         if (evt->user_event.event.caption.caption)
     277           1 :                                 gf_free((char *) evt->user_event.event.caption.caption);
     278             :                 }
     279             :         }
     280           7 :         gf_free(evt);
     281             : }
     282             : static JSClassDef jsf_event_class = {
     283             :     "FilterEvent",
     284             :     .finalizer = jsf_evt_finalizer
     285             : };
     286             : 
     287             : static JSClassID jsf_pck_class_id;
     288             : 
     289         158 : static void jsf_pck_detach_ab(JSContext *ctx, GF_JSPckCtx *pckctx)
     290             : {
     291         316 :         if (!JS_IsUndefined(pckctx->data_ab)) {
     292           0 :                 JS_DetachArrayBuffer(ctx, pckctx->data_ab);
     293             :                 JS_FreeValue(ctx, pckctx->data_ab);
     294           0 :                 pckctx->data_ab = JS_UNDEFINED;
     295             :         }
     296         158 : }
     297             : 
     298        3104 : static void jsf_pck_finalizer(JSRuntime *rt, JSValue val)
     299             : {
     300        3104 :     GF_JSPckCtx *pckctx = JS_GetOpaque(val, jsf_pck_class_id);
     301        3104 :     if (!pckctx) return;
     302        1409 :     pckctx->jspid->pck_head = NULL;
     303             : 
     304             :         /*we only keep a ref for input packet(s)*/
     305        1409 :         if (pckctx->pck && !(pckctx->flags & GF_JS_PCK_IS_OUTPUT))
     306             :                 JS_FreeValueRT(rt, pckctx->jsobj);
     307             : 
     308        2818 :         if (!JS_IsUndefined(pckctx->data_ab)) {
     309             :                 JS_FreeValueRT(rt, pckctx->data_ab);
     310         348 :                 pckctx->data_ab = JS_UNDEFINED;
     311             :         }
     312             : 
     313        2818 :     if (JS_IsUndefined(pckctx->ref_val) && pckctx->jspid && pckctx->jspid->jsf) {
     314        1409 :                 gf_list_add(pckctx->jspid->jsf->pck_res, pckctx);
     315             :                 memset(pckctx, 0, sizeof(GF_JSPckCtx));
     316             :         }
     317             : }
     318             : 
     319         274 : static void jsf_filter_pck_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func)
     320             : {
     321         274 :     GF_JSPckCtx *pckctx = JS_GetOpaque(val, jsf_pck_class_id);
     322         274 :     if (!pckctx) return;
     323             : 
     324          38 :         if (!(pckctx->flags & GF_JS_PCK_IS_OUTPUT))
     325           2 :                 JS_MarkValue(rt, pckctx->jsobj, mark_func);
     326             : 
     327          76 :     if (!JS_IsUndefined(pckctx->ref_val)) {
     328           0 :                 JS_MarkValue(rt, pckctx->ref_val, mark_func);
     329             :         }
     330             : 
     331          76 :     if (!JS_IsUndefined(pckctx->data_ab)) {
     332          36 :                 JS_MarkValue(rt, pckctx->data_ab, mark_func);
     333             :         }
     334             : }
     335             : 
     336             : static JSClassDef jsf_pck_class = {
     337             :     "FilterPacket",
     338             :     .finalizer = jsf_pck_finalizer,
     339             :         .gc_mark = jsf_filter_pck_mark
     340             : };
     341             : 
     342           4 : GF_DownloadManager *jsf_get_download_manager(JSContext *c)
     343             : {
     344             :         GF_JSFilterCtx *jsf;
     345           4 :         JSValue global = JS_GetGlobalObject(c);
     346             : 
     347           4 :         JSValue filter_obj = JS_GetPropertyStr(c, global, "filter");
     348             :         JS_FreeValue(c, global);
     349           8 :         if (JS_IsNull(filter_obj) || JS_IsException(filter_obj)) return NULL;
     350           4 :         jsf = JS_GetOpaque(filter_obj, jsf_filter_class_id);
     351             :         JS_FreeValue(c, filter_obj);
     352           4 :         if (!jsf) return NULL;
     353           4 :         return gf_filter_get_download_manager(jsf->filter);
     354             : }
     355             : 
     356             : GF_FilterSession *jsff_get_session(JSContext *c, JSValue this_val);
     357             : struct _gf_ft_mgr *gf_fs_get_font_manager(GF_FilterSession *fsess);
     358             : 
     359          37 : struct _gf_ft_mgr *jsf_get_font_manager(JSContext *c)
     360             : {
     361          37 :         JSValue global = JS_GetGlobalObject(c);
     362             :         JSValue obj;
     363             : 
     364          37 :         obj = JS_GetPropertyStr(c, global, "session");
     365          74 :         if (!JS_IsNull(obj) && !JS_IsException(obj)) {
     366          37 :                 GF_FilterSession *fs = jsff_get_session(c, obj);
     367             :                 JS_FreeValue(c, obj);
     368          37 :                 if (fs) {
     369             :                         JS_FreeValue(c, global);
     370          28 :                         return gf_fs_get_font_manager(fs);
     371             :                 }
     372             :         }
     373             : 
     374           9 :         obj = JS_GetPropertyStr(c, global, "filter");
     375             :         JS_FreeValue(c, global);
     376          18 :         if (!JS_IsNull(obj) && !JS_IsException(obj)) {
     377           9 :                 GF_JSFilterCtx *jsf = JS_GetOpaque(obj, jsf_filter_class_id);
     378             :                 JS_FreeValue(c, obj);
     379           9 :                 if (jsf)
     380           9 :                         return gf_filter_get_font_manager(jsf->filter);
     381             :         }
     382             :         return NULL;
     383             : }
     384             : 
     385           3 : GF_Err jsf_request_opengl(JSContext *c)
     386             : {
     387             :         GF_JSFilterCtx *jsf;
     388           3 :         JSValue global = JS_GetGlobalObject(c);
     389             : 
     390           3 :         JSValue filter_obj = JS_GetPropertyStr(c, global, "filter");
     391             :         JS_FreeValue(c, global);
     392           6 :         if (JS_IsNull(filter_obj) || JS_IsException(filter_obj)) return GF_BAD_PARAM;
     393           3 :         jsf = JS_GetOpaque(filter_obj, jsf_filter_class_id);
     394             :         JS_FreeValue(c, filter_obj);
     395             : 
     396           3 :         return gf_filter_request_opengl(jsf->filter);
     397             : }
     398         607 : GF_Err jsf_set_gl_active(JSContext *c)
     399             : {
     400             :         GF_JSFilterCtx *jsf;
     401         607 :         JSValue global = JS_GetGlobalObject(c);
     402             : 
     403         607 :         JSValue filter_obj = JS_GetPropertyStr(c, global, "filter");
     404             :         JS_FreeValue(c, global);
     405        1214 :         if (JS_IsNull(filter_obj) || JS_IsException(filter_obj)) return GF_BAD_PARAM;
     406         607 :         jsf = JS_GetOpaque(filter_obj, jsf_filter_class_id);
     407             :         JS_FreeValue(c, filter_obj);
     408             : 
     409         607 :         return gf_filter_set_active_opengl_context(jsf->filter);
     410             : }
     411             : 
     412         708 : Bool jsf_is_packet(JSContext *c, JSValue obj)
     413             : {
     414         708 :         GF_JSPckCtx *pckc = JS_GetOpaque(obj, jsf_pck_class_id);
     415         708 :         if (pckc) return GF_TRUE;
     416           2 :         return GF_FALSE;
     417             : }
     418         504 : const GF_FilterPacket *jsf_get_packet(JSContext *c, JSValue obj)
     419             : {
     420         504 :         GF_JSPckCtx *pckc = JS_GetOpaque(obj, jsf_pck_class_id);
     421         504 :         if (pckc) return pckc->pck;
     422             :         return NULL;
     423             : }
     424             : 
     425         204 : GF_Err jsf_get_filter_packet_planes(JSContext *c, JSValue obj, u32 *width, u32 *height, u32 *pf, u32 *stride, u32 *stride_uv, const u8 **data, const u8 **p_u, const u8 **p_v, const u8 **p_a)
     426             : {
     427             :         u32 cid;
     428             :         GF_FilterFrameInterface *frame_ifce;
     429             :         const GF_PropertyValue *p;
     430         204 :         GF_JSPckCtx *pckc = JS_GetOpaque(obj, jsf_pck_class_id);
     431         204 :         if (!pckc) return GF_BAD_PARAM;
     432             : 
     433             : #define GETPROP(_code, _v, opt)\
     434             :         p = gf_filter_pid_get_property(pckc->jspid->pid, _code);\
     435             :         if (!opt && !p) return GF_BAD_PARAM;\
     436             :         _v = p ? p->value.uint : 0;\
     437             : 
     438         204 :         GETPROP(GF_PROP_PID_CODECID, cid, 0)
     439         204 :         if (cid != GF_CODECID_RAW) return GF_BAD_PARAM;
     440         204 :         GETPROP(GF_PROP_PID_WIDTH, *width, 0)
     441         204 :         GETPROP(GF_PROP_PID_HEIGHT, *height, 0)
     442         204 :         GETPROP(GF_PROP_PID_PIXFMT, *pf, 0)
     443         204 :         GETPROP(GF_PROP_PID_STRIDE, *stride, 1)
     444         204 :         GETPROP(GF_PROP_PID_STRIDE_UV, *stride_uv, 1)
     445             : #undef GETPROP
     446             : 
     447         204 :         if (!data || !p_u || !p_v || !p_a) return GF_OK;
     448             : 
     449         202 :         frame_ifce = gf_filter_pck_get_frame_interface(pckc->pck);
     450         202 :         if (!frame_ifce) {
     451         202 :                 u32 size=0;
     452         202 :                 *data = (u8 *) gf_filter_pck_get_data(pckc->pck, &size);
     453             :         } else {
     454             :                 u32 st_o;
     455           0 :                 frame_ifce->get_plane(frame_ifce, 0, data, stride);
     456           0 :                 frame_ifce->get_plane(frame_ifce, 1, p_u, stride_uv);
     457             :                 //todo we need to cleanup alpha frame fetch, how do we differentiate between NV12+alpha (3 planes) and YUV420 ?
     458           0 :                 frame_ifce->get_plane(frame_ifce, 2, p_v, &st_o);
     459           0 :                 frame_ifce->get_plane(frame_ifce, 3, p_a, &st_o);
     460             :         }
     461             :         return GF_OK;
     462             : }
     463             : 
     464          11 : const char *jsf_get_script_filename(JSContext *c)
     465             : {
     466             :         GF_JSFilterCtx *jsf;
     467          11 :         JSValue global = JS_GetGlobalObject(c);
     468          11 :         JSValue filter_obj = JS_GetPropertyStr(c, global, "filter");
     469             :         JS_FreeValue(c, global);
     470          22 :         if (JS_IsNull(filter_obj) || JS_IsException(filter_obj)) return NULL;
     471          11 :         jsf = JS_GetOpaque(filter_obj, jsf_filter_class_id);
     472             :         JS_FreeValue(c, filter_obj);
     473          11 :         if (!jsf) return NULL;
     474          11 :         return jsf->js;
     475             : }
     476             : 
     477         426 : JSValue jsf_NewProp(JSContext *ctx, const GF_PropertyValue *new_val)
     478             : {
     479             :         JSValue res;
     480             :         u32 i;
     481         426 :         if (!new_val) return JS_NULL;
     482             : 
     483         426 :         switch (new_val->type) {
     484         164 :         case GF_PROP_BOOL:
     485         164 :                 return JS_NewBool(ctx, new_val->value.boolean);
     486         107 :         case GF_PROP_UINT:
     487             :         case GF_PROP_SINT:
     488         107 :                 return JS_NewInt32(ctx, new_val->value.sint);
     489           0 :         case GF_PROP_4CC:
     490           0 :                 return JS_NewString(ctx, gf_4cc_to_str(new_val->value.uint) );
     491           6 :         case GF_PROP_LUINT:
     492           6 :                 return JS_NewInt64(ctx, new_val->value.longuint);
     493           0 :         case GF_PROP_LSINT:
     494           0 :                 return JS_NewInt64(ctx, new_val->value.longsint);
     495           0 :         case GF_PROP_FLOAT:
     496           0 :                 return JS_NewFloat64(ctx, FIX2FLT(new_val->value.fnumber));
     497          36 :         case GF_PROP_DOUBLE:
     498          36 :                 return JS_NewFloat64(ctx, new_val->value.number);
     499          55 :         case GF_PROP_STRING:
     500             :         case GF_PROP_STRING_NO_COPY:
     501             :         case GF_PROP_NAME:
     502          55 :                 if (!new_val->value.string) return JS_NULL;
     503          45 :                 return JS_NewString(ctx, new_val->value.string);
     504           0 :         case GF_PROP_VEC2:
     505           0 :                 res = JS_NewObject(ctx);
     506           0 :                 JS_SetPropertyStr(ctx, res, "x", JS_NewFloat64(ctx, new_val->value.vec2.x));
     507           0 :                 JS_SetPropertyStr(ctx, res, "y", JS_NewFloat64(ctx, new_val->value.vec2.y));
     508           0 :                 return res;
     509           0 :         case GF_PROP_VEC2I:
     510           0 :                 res = JS_NewObject(ctx);
     511           0 :                 JS_SetPropertyStr(ctx, res, "x", JS_NewInt32(ctx, new_val->value.vec2i.x));
     512           0 :                 JS_SetPropertyStr(ctx, res, "y", JS_NewInt32(ctx, new_val->value.vec2i.y));
     513           0 :                 return res;
     514           0 :         case GF_PROP_VEC3I:
     515           0 :                 res = JS_NewObject(ctx);
     516           0 :                 JS_SetPropertyStr(ctx, res, "x", JS_NewInt32(ctx, new_val->value.vec3i.x));
     517           0 :                 JS_SetPropertyStr(ctx, res, "y", JS_NewInt32(ctx, new_val->value.vec3i.y));
     518           0 :                 JS_SetPropertyStr(ctx, res, "z", JS_NewInt32(ctx, new_val->value.vec3i.z));
     519           0 :                 return res;
     520           0 :         case GF_PROP_VEC4I:
     521           0 :                 res = JS_NewObject(ctx);
     522           0 :                 JS_SetPropertyStr(ctx, res, "x", JS_NewInt32(ctx, new_val->value.vec4i.x));
     523           0 :                 JS_SetPropertyStr(ctx, res, "y", JS_NewInt32(ctx, new_val->value.vec4i.y));
     524           0 :                 JS_SetPropertyStr(ctx, res, "z", JS_NewInt32(ctx, new_val->value.vec4i.z));
     525           0 :                 JS_SetPropertyStr(ctx, res, "w", JS_NewInt32(ctx, new_val->value.vec4i.w));
     526           0 :                 return res;
     527          16 :         case GF_PROP_FRACTION:
     528          16 :                 res = JS_NewObject(ctx);
     529          32 :                 JS_SetPropertyStr(ctx, res, "n", JS_NewInt32(ctx, new_val->value.frac.num));
     530          32 :                 JS_SetPropertyStr(ctx, res, "d", JS_NewInt32(ctx, new_val->value.frac.den));
     531          16 :                 return res;
     532           5 :         case GF_PROP_FRACTION64:
     533           5 :                 res = JS_NewObject(ctx);
     534           5 :                 JS_SetPropertyStr(ctx, res, "n", JS_NewInt64(ctx, new_val->value.lfrac.num));
     535          10 :                 JS_SetPropertyStr(ctx, res, "d", JS_NewInt64(ctx, new_val->value.lfrac.den));
     536           5 :                 return res;
     537           0 :         case GF_PROP_UINT_LIST:
     538           0 :                 res = JS_NewArray(ctx);
     539           0 :                 for (i=0; i<new_val->value.uint_list.nb_items; i++) {
     540           0 :                 JS_SetPropertyUint32(ctx, res, i, JS_NewInt64(ctx, new_val->value.uint_list.vals[i]) );
     541             :                 }
     542           0 :                 return res;
     543           0 :         case GF_PROP_4CC_LIST:
     544           0 :                 res = JS_NewArray(ctx);
     545           0 :                 for (i=0; i<new_val->value.uint_list.nb_items; i++) {
     546           0 :                 JS_SetPropertyUint32(ctx, res, i, JS_NewString(ctx, gf_4cc_to_str(new_val->value.uint_list.vals[i]) ) );
     547             :                 }
     548           0 :                 return res;
     549           0 :         case GF_PROP_SINT_LIST:
     550           0 :                 res = JS_NewArray(ctx);
     551           0 :                 for (i=0; i<new_val->value.sint_list.nb_items; i++) {
     552           0 :                 JS_SetPropertyUint32(ctx, res, i, JS_NewInt32(ctx, new_val->value.sint_list.vals[i]) );
     553             :                 }
     554           0 :                 return res;
     555           5 :         case GF_PROP_VEC2I_LIST:
     556           5 :                 res = JS_NewArray(ctx);
     557          10 :                 for (i=0; i<new_val->value.v2i_list.nb_items; i++) {
     558           5 :                         JSValue item = JS_NewObject(ctx);
     559          10 :                         JS_SetPropertyStr(ctx, item, "x", JS_NewInt32(ctx, new_val->value.v2i_list.vals[i].x));
     560          10 :                         JS_SetPropertyStr(ctx, item, "y", JS_NewInt32(ctx, new_val->value.v2i_list.vals[i].y));
     561           5 :                 JS_SetPropertyUint32(ctx, res, i, item);
     562             :                 }
     563           5 :                 return res;
     564           0 :         case GF_PROP_STRING_LIST:
     565           0 :                 res = JS_NewArray(ctx);
     566           0 :                 for (i=0; i<new_val->value.string_list.nb_items; i++) {
     567           0 :                 JS_SetPropertyUint32(ctx, res, i, JS_NewString(ctx, new_val->value.string_list.vals[i] ) );
     568             :                 }
     569           0 :                 return res;
     570           2 :         case GF_PROP_DATA:
     571           2 :                 return JS_NewArrayBufferCopy(ctx, new_val->value.data.ptr, new_val->value.data.size);
     572             : 
     573          30 :         default:
     574          30 :                 if (gf_props_type_is_enum(new_val->type)) {
     575          30 :                         return JS_NewString(ctx, gf_props_enum_name(new_val->type, new_val->value.uint));
     576             :                 }
     577           0 :                 return JS_NULL;
     578             :         }
     579             : }
     580             : 
     581          56 : JSValue jsf_NewPropTranslate(JSContext *ctx, const GF_PropertyValue *prop, u32 p4cc)
     582             : {
     583             :         const char *cid;
     584             :         JSValue res;
     585          56 :         switch (p4cc) {
     586           2 :         case GF_PROP_PID_CODECID:
     587           2 :                 cid = gf_codecid_file_ext(prop->value.uint);
     588           2 :                 if (!cid) res = JS_EXCEPTION;
     589             :                 else {
     590           2 :                         char *sep = strchr(cid, '|');
     591           2 :                         if (sep)
     592           2 :                                 res = JS_NewStringLen(ctx, cid, sep-cid);
     593             :                         else
     594           0 :                                 res = JS_NewString(ctx, cid);
     595             :                 }
     596             :                 break;
     597           4 :         case GF_PROP_PID_STREAM_TYPE:
     598           4 :                 res = JS_NewString(ctx, gf_stream_type_name(prop->value.uint));
     599           4 :                 break;
     600           0 :         case GF_PROP_PID_CHANNEL_LAYOUT:
     601           0 :                 res = JS_NewString(ctx, gf_audio_fmt_get_layout_name(prop->value.longuint));
     602           0 :                 break;
     603          50 :         default:
     604          50 :                 res = jsf_NewProp(ctx, prop);
     605          50 :                 break;
     606             :         }
     607          56 :         return res;
     608             : }
     609             : 
     610         530 : GF_Err jsf_ToProp_ex(GF_Filter *filter, JSContext *ctx, JSValue value, u32 p4cc, GF_PropertyValue *prop, u32 prop_type)
     611             : {
     612             :         u32 type;
     613             :         memset(prop, 0, sizeof(GF_PropertyValue));
     614             : 
     615         530 :         type = prop_type ? prop_type : GF_PROP_STRING;
     616         530 :         if (p4cc)
     617         253 :                 type = gf_props_4cc_get_type(p4cc);
     618             : 
     619         530 :         if (JS_IsString(value)) {
     620             :                 const char *val_str = JS_ToCString(ctx, value);
     621         380 :                 if (p4cc==GF_PROP_PID_STREAM_TYPE) {
     622          31 :                         prop->type = GF_PROP_UINT;
     623          31 :                         prop->value.uint = gf_stream_type_by_name(val_str);
     624         349 :                 } else if (p4cc==GF_PROP_PID_CODECID) {
     625          31 :                         prop->type = GF_PROP_UINT;
     626          31 :                         prop->value.uint = gf_codecid_parse(val_str);
     627         318 :                 } else if (p4cc==GF_PROP_PID_CHANNEL_LAYOUT) {
     628           0 :                         prop->type = GF_PROP_LUINT;
     629           0 :                         prop->value.longuint = gf_audio_fmt_get_layout_from_name(val_str);
     630             :                 } else {
     631         318 :                         *prop = gf_props_parse_value(type, NULL, val_str, NULL, gf_filter_get_sep(filter, GF_FS_SEP_LIST));
     632             :                 }
     633         380 :                 JS_FreeCString(ctx, val_str);
     634         380 :                 if (prop->type==GF_PROP_FORBIDEN) return GF_BAD_PARAM;
     635         380 :                 return GF_OK;
     636             :         }
     637         150 :         if (JS_IsBool(value)) {
     638          11 :                 prop->type = GF_PROP_BOOL;
     639          11 :                 prop->value.boolean = JS_ToBool(ctx, value);
     640             :         }
     641         139 :         else if (JS_IsInteger(value)) {
     642         110 :                 if (!JS_ToInt32(ctx, &prop->value.sint, value)) {
     643         110 :                         prop->type = GF_PROP_SINT;
     644           0 :                 } else if (!JS_ToInt64(ctx, &prop->value.longsint, value)) {
     645           0 :                         prop->type = GF_PROP_LSINT;
     646             :                 }
     647             :         }
     648          29 :         else if (JS_IsNumber(value)) {
     649           0 :                 JS_ToFloat64(ctx, &prop->value.number, value);
     650           0 :                 prop->type = GF_PROP_DOUBLE;
     651             :         }
     652          29 :         else if (JS_IsArray(ctx, value)) {
     653           0 :                 u64 len = 0;
     654             :                 u32 i;
     655             :                 u32 atype = 0;
     656           0 :                 JSValue js_length = JS_GetPropertyStr(ctx, value, "length");
     657           0 :                 if (JS_ToIndex(ctx, &len, js_length)) {
     658             :                         JS_FreeValue(ctx, js_length);
     659           0 :                         return GF_BAD_PARAM;
     660             :                 }
     661             :                 JS_FreeValue(ctx, js_length);
     662           0 :                 for (i=0; i<len; i++) {
     663           0 :                         JSValue v = JS_GetPropertyUint32(ctx, value, i);
     664           0 :                         if (JS_IsString(v)) {
     665           0 :                                 if (!i) atype = 1;
     666           0 :                                 else if (atype!=1) {
     667             :                                         JS_FreeValue(ctx, v);
     668           0 :                                         return GF_BAD_PARAM;
     669             :                                 }
     670           0 :                         } else if (JS_IsInteger(v)) {
     671           0 :                                 if (!i) atype = 2;
     672           0 :                                 else if (atype!=2) {
     673             :                                         JS_FreeValue(ctx, v);
     674             :                                         return GF_BAD_PARAM;
     675             :                                 }
     676             :                         }
     677             :                         else {
     678             :                                 JS_FreeValue(ctx, v);
     679             :                                 return GF_BAD_PARAM;
     680             :                         }
     681           0 :                         if (!i) {
     682           0 :                                 if (atype==1) {
     683           0 :                                         prop->value.uint_list.nb_items = (u32) len;
     684           0 :                                         prop->value.uint_list.vals = gf_malloc((u32) (sizeof(char *)*len));
     685             :                                 } else {
     686           0 :                                         prop->value.uint_list.nb_items = (u32) len;
     687           0 :                                         prop->value.uint_list.vals = gf_malloc((u32) (sizeof(s32)*len));
     688             :                                 }
     689             :                         }
     690           0 :                         if (atype==1) {
     691             :                                 const char *str = JS_ToCString(ctx, v);
     692           0 :                                 prop->value.string_list.vals[i] = gf_strdup(str);
     693           0 :                                 JS_FreeCString(ctx, str);
     694             :                         } else {
     695           0 :                                 JS_ToInt32(ctx, &prop->value.uint_list.vals[i], v);
     696             :                         }
     697             :                         JS_FreeValue(ctx, v);
     698             :                 }
     699             :         }
     700          29 :         else if (JS_IsObject(value)) {
     701             :                 Bool is_vec4 = 0;
     702             :                 Bool is_vec3 = 0;
     703             :                 u32 is_vec2 = 0;
     704             :                 u32 is_frac = 0;
     705             :                 Bool is_vec = GF_FALSE;
     706             :                 GF_PropVec2 val_d;
     707             :                 GF_PropVec4i val_i;
     708             :                 GF_Fraction frac;
     709             :                 GF_Fraction64 frac_l;
     710             : 
     711          29 :                 JSValue res = JS_GetPropertyStr(ctx, value, "w");
     712          29 :                 if (!JS_IsUndefined(res)) {
     713           0 :                         JS_ToInt32(ctx, &val_i.w, res);
     714             :                         is_vec4 = 1;
     715             :                 }
     716             :                 JS_FreeValue(ctx, res);
     717             : 
     718          29 :                 res = JS_GetPropertyStr(ctx, value, "z");
     719          29 :                 if (!JS_IsUndefined(res)) {
     720           0 :                         JS_ToInt32(ctx, &val_i.z, res);
     721             :                         is_vec3 = 1;
     722             :                 }
     723             :                 JS_FreeValue(ctx, res);
     724             : 
     725          29 :                 res = JS_GetPropertyStr(ctx, value, "y");
     726          29 :                 if (!JS_IsUndefined(res)) {
     727             :                         is_vec2 = 1;
     728           0 :                         if (JS_ToFloat64(ctx, &val_d.y, res)) {
     729           0 :                                 JS_ToInt32(ctx, &val_i.y, res);
     730             :                                 is_vec2 = 2;
     731             :                         }
     732             :                 }
     733             :                 JS_FreeValue(ctx, res);
     734             : 
     735          29 :                 res = JS_GetPropertyStr(ctx, value, "x");
     736          29 :                 if (!JS_IsUndefined(res)) {
     737             :                         is_vec = GF_TRUE;
     738           0 :                         if (JS_ToFloat64(ctx, &val_d.x, res)) {
     739           0 :                                 JS_ToInt32(ctx, &val_i.x, res);
     740             :                         }
     741             :                 }
     742             :                 JS_FreeValue(ctx, res);
     743             : 
     744          29 :                 res = JS_GetPropertyStr(ctx, value, "d");
     745          29 :                 if (!JS_IsUndefined(res)) {
     746             :                         is_frac = 2;
     747          26 :                         if (JS_ToInt32(ctx, &frac.den, res)) {
     748           0 :                                 JS_ToInt64(ctx, &frac_l.den, res);
     749             :                                 is_frac = 1;
     750             :                         }
     751             :                 }
     752             :                 JS_FreeValue(ctx, res);
     753          29 :                 if (is_frac) {
     754          26 :                         res = JS_GetPropertyStr(ctx, value, "n");
     755          26 :                         if (!JS_IsUndefined(res)) {
     756             :                                 is_frac = 2;
     757          26 :                                 if (JS_ToInt32(ctx, &frac.num, res)) {
     758           0 :                                         JS_ToInt64(ctx, &frac_l.num, res);
     759             :                                         is_frac = 1;
     760             :                                 }
     761             :                         } else {
     762             :                                 is_frac = 0;
     763             :                         }
     764             :                         JS_FreeValue(ctx, res);
     765             :                 }
     766             : 
     767          29 :                 if (is_vec) {
     768           0 :                         if (is_vec4) {
     769           0 :                                 prop->type = GF_PROP_VEC4I;
     770           0 :                                 prop->value.vec4i = val_i;
     771           0 :                         } else if (is_vec3) {
     772           0 :                                 prop->type = GF_PROP_VEC3I;
     773           0 :                                 prop->value.vec3i.x = val_i.x;
     774           0 :                                 prop->value.vec3i.y = val_i.y;
     775           0 :                                 prop->value.vec3i.z = val_i.z;
     776           0 :                         } else if (is_vec2==2) {
     777           0 :                                 prop->type = GF_PROP_VEC2I;
     778           0 :                                 prop->value.vec2i.x = val_i.x;
     779           0 :                                 prop->value.vec2i.y = val_i.y;
     780           0 :                         } else if (is_vec2==1) {
     781           0 :                                 prop->type = GF_PROP_VEC2;
     782           0 :                                 prop->value.vec2.x = val_d.x;
     783           0 :                                 prop->value.vec2.y = val_d.y;
     784             :                         }
     785          29 :                 } else if (is_frac) {
     786          26 :                         if (is_frac==2) {
     787          26 :                                 prop->type = GF_PROP_FRACTION;
     788          26 :                                 prop->value.frac = frac;
     789             :                         } else {
     790           0 :                                 prop->type = GF_PROP_FRACTION64;
     791           0 :                                 prop->value.lfrac = frac_l;
     792             :                         }
     793             :                 }
     794             :                 //try array buffer
     795             :                 else {
     796             :                         size_t ab_size;
     797           3 :                         u8 *data = JS_GetArrayBuffer(ctx, &ab_size, value);
     798           3 :                         if (!data)
     799           0 :                                 return GF_BAD_PARAM;
     800             : 
     801           3 :                         if (prop_type==GF_PROP_CONST_DATA) {
     802           0 :                                 prop->value.data.ptr = data;
     803           0 :                                 prop->value.data.size = (u32) ab_size;
     804           0 :                                 prop->type = GF_PROP_CONST_DATA;
     805             :                         } else {
     806           3 :                                 prop->value.data.ptr = gf_malloc(ab_size);
     807           3 :                                 memcpy(prop->value.data.ptr, data, ab_size);
     808           3 :                                 prop->value.data.size = (u32) ab_size;
     809           3 :                                 prop->type = GF_PROP_DATA;
     810             :                         }
     811             :                 }
     812           0 :         } else if (JS_IsNull(value)) {
     813           0 :                 prop->value.data.ptr = NULL;
     814           0 :                 prop->value.data.size = 0;
     815           0 :                 if (prop_type==GF_PROP_CONST_DATA) {
     816           0 :                         prop->type = GF_PROP_CONST_DATA;
     817             :                 } else {
     818           0 :                         prop->type = GF_PROP_DATA;
     819             :                 }
     820             :         } else {
     821           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_SCRIPT, ("[JSF] Unmapped JS object type, cannot convert back to property\n"));
     822             :                 return GF_NOT_SUPPORTED;
     823             :         }
     824             : 
     825         150 :         if (prop->type==GF_PROP_STRING) {
     826           0 :                 if ((type==GF_PROP_DATA) || (type==GF_PROP_CONST_DATA)) {
     827           0 :                         char *str = prop->value.string;
     828             :                         prop->value.data.ptr = str;
     829           0 :                         prop->value.data.size = (u32) strlen(str);
     830           0 :                         prop->type = GF_PROP_DATA;
     831             :                 }
     832             :         }
     833             :         return GF_OK;
     834             : }
     835             : 
     836           0 : GF_Err jsf_ToProp(GF_Filter *filter, JSContext *ctx, JSValue value, u32 p4cc, GF_PropertyValue *prop)
     837             : {
     838         530 :         return jsf_ToProp_ex(filter, ctx, value, p4cc, prop, 0);
     839             : 
     840             : }
     841         134 : static JSValue jsf_filter_prop_set(JSContext *ctx, JSValueConst this_val, JSValueConst value, int magic)
     842             : {
     843             :         u32 ival;
     844             :         GF_FilterSessionCaps caps;
     845         134 :         GF_JSFilterCtx *jsf = JS_GetOpaque(this_val, jsf_filter_class_id);
     846         134 :         if (!jsf)
     847           0 :                 return JS_EXCEPTION;
     848             : 
     849         134 :         if (magic < JSF_EVT_LAST_DEFINED) {
     850         121 :                 if (JS_IsFunction(ctx, value) || JS_IsUndefined(value) || JS_IsNull(value)) {
     851             :                         JS_FreeValue(ctx, jsf->funcs[magic]);
     852         121 :                         jsf->funcs[magic] = JS_DupValue(ctx, value);
     853             :                 }
     854         121 :         return JS_UNDEFINED;
     855             :         }
     856          13 :         switch (magic) {
     857           5 :         case JSF_FILTER_MAX_PIDS:
     858           5 :                 if (JS_ToInt32(ctx, &ival, value))
     859           0 :                         return JS_EXCEPTION;
     860           5 :                 gf_filter_set_max_extra_input_pids(jsf->filter, ival);
     861           5 :                 break;
     862             : 
     863           1 :         case JSF_FILTER_CAPS_MAX_WIDTH:
     864           1 :                 gf_filter_get_session_caps(jsf->filter, &caps);
     865           1 :                 if (JS_ToInt32(ctx, &caps.max_screen_width, value)) return JS_EXCEPTION;
     866           1 :                 gf_filter_set_session_caps(jsf->filter, &caps);
     867           1 :                 break;
     868           1 :         case JSF_FILTER_CAPS_MAX_HEIGHT:
     869           1 :                 gf_filter_get_session_caps(jsf->filter, &caps);
     870           1 :                 if (JS_ToInt32(ctx, &caps.max_screen_height, value)) return JS_EXCEPTION;
     871           1 :                 gf_filter_set_session_caps(jsf->filter, &caps);
     872           1 :                 break;
     873           1 :         case JSF_FILTER_CAPS_MAX_DISPLAY_DEPTH:
     874           1 :                 gf_filter_get_session_caps(jsf->filter, &caps);
     875           1 :                 if (JS_ToInt32(ctx, &caps.max_screen_bpp, value)) return JS_EXCEPTION;
     876           1 :                 gf_filter_set_session_caps(jsf->filter, &caps);
     877           1 :                 break;
     878           1 :         case JSF_FILTER_CAPS_MAX_FPS:
     879           1 :                 gf_filter_get_session_caps(jsf->filter, &caps);
     880           1 :                 if (JS_ToInt32(ctx, &caps.max_screen_fps, value)) return JS_EXCEPTION;
     881           1 :                 gf_filter_set_session_caps(jsf->filter, &caps);
     882           1 :                 break;
     883           1 :         case JSF_FILTER_CAPS_MAX_VIEWS:
     884           1 :                 gf_filter_get_session_caps(jsf->filter, &caps);
     885           1 :                 if (JS_ToInt32(ctx, &caps.max_screen_nb_views, value)) return JS_EXCEPTION;
     886           1 :                 gf_filter_set_session_caps(jsf->filter, &caps);
     887           1 :                 break;
     888           1 :         case JSF_FILTER_CAPS_MAX_CHANNELS:
     889           1 :                 gf_filter_get_session_caps(jsf->filter, &caps);
     890           1 :                 if (JS_ToInt32(ctx, &caps.max_audio_channels, value)) return JS_EXCEPTION;
     891           1 :                 gf_filter_set_session_caps(jsf->filter, &caps);
     892           1 :                 break;
     893           1 :         case JSF_FILTER_CAPS_MAX_SAMPLERATE:
     894           1 :                 gf_filter_get_session_caps(jsf->filter, &caps);
     895           1 :                 if (JS_ToInt32(ctx, &caps.max_audio_sample_rate, value)) return JS_EXCEPTION;
     896           1 :                 gf_filter_set_session_caps(jsf->filter, &caps);
     897           1 :                 break;
     898           1 :         case JSF_FILTER_CAPS_MAX_AUDIO_DEPTH:
     899           1 :                 gf_filter_get_session_caps(jsf->filter, &caps);
     900           1 :                 if (JS_ToInt32(ctx, &caps.max_audio_bit_depth, value)) return JS_EXCEPTION;
     901           1 :                 gf_filter_set_session_caps(jsf->filter, &caps);
     902           1 :                 break;
     903             : 
     904           0 :         case JSF_FILTER_INAME:
     905             :         {
     906             :                 const char *val = JS_ToCString(ctx, value);
     907           0 :                 if (jsf->filter->iname) gf_free(jsf->filter->iname);
     908           0 :                 if (val)
     909           0 :                         jsf->filter->iname = gf_strdup(val);
     910             :                 else
     911           0 :                         jsf->filter->iname = NULL;
     912           0 :                 JS_FreeCString(ctx, val);
     913             :         }
     914           0 :                 break;
     915             :         }
     916          13 :     return JS_UNDEFINED;
     917             : }
     918             : 
     919          21 : static JSValue jsf_filter_prop_get(JSContext *ctx, JSValueConst this_val, int magic)
     920             : {
     921             :         u32 ival;
     922             :         s64 lival;
     923             :         Double dval;
     924             :         char *str;
     925             :         char szSep[2];
     926             :         GF_FilterSessionCaps caps;
     927             :         JSValue res;
     928          21 :         GF_JSFilterCtx *jsf = JS_GetOpaque(this_val, jsf_filter_class_id);
     929          21 :         if (!jsf)
     930           0 :                 return JS_EXCEPTION;
     931             : 
     932          21 :         if (magic<JSF_EVT_LAST_DEFINED)
     933             :                 return JS_DupValue(jsf->ctx, jsf->funcs[magic]);
     934             : 
     935          21 :         switch (magic) {
     936           0 :         case JSF_FILTER_MAX_PIDS:
     937           0 :                 return JS_NewInt32(ctx, gf_filter_get_max_extra_input_pids(jsf->filter));
     938           1 :         case JSF_FILTER_BLOCK_ENABLED:
     939           1 :         return JS_NewBool(jsf->ctx, gf_filter_block_enabled(jsf->filter));
     940           1 :         case JSF_FILTER_OUTPUT_BUFFER:
     941           1 :                 gf_filter_get_output_buffer_max(jsf->filter, &ival, NULL);
     942           1 :         return JS_NewInt32(jsf->ctx, ival);
     943           1 :         case JSF_FILTER_OUTPUT_PLAYOUT:
     944           1 :                 gf_filter_get_output_buffer_max(jsf->filter, NULL, &ival);
     945           1 :         return JS_NewInt32(jsf->ctx, ival);
     946             : 
     947           1 :         case JSF_FILTER_SEP_ARGS:
     948           1 :                 szSep[1]=0;
     949           1 :                 szSep[0] = gf_filter_get_sep(jsf->filter, GF_FS_SEP_ARGS);
     950           1 :         return JS_NewString(jsf->ctx, szSep);
     951           1 :         case JSF_FILTER_SEP_NAME:
     952           1 :                 szSep[1]=0;
     953           1 :                 szSep[0] = gf_filter_get_sep(jsf->filter, GF_FS_SEP_NAME);
     954           1 :         return JS_NewString(jsf->ctx, szSep);
     955           1 :         case JSF_FILTER_SEP_LIST:
     956           1 :                 szSep[1]=0;
     957           1 :                 szSep[0] = gf_filter_get_sep(jsf->filter, GF_FS_SEP_LIST);
     958           1 :         return JS_NewString(jsf->ctx, szSep);
     959             : 
     960           1 :         case JSF_FILTER_DST_ARGS:
     961           1 :                 str = (char *) gf_filter_get_dst_args(jsf->filter);
     962           1 :         return str ? JS_NewString(jsf->ctx, str) : JS_NULL;
     963           1 :         case JSF_FILTER_DST_NAME:
     964           1 :                 str = gf_filter_get_dst_name(jsf->filter);
     965           1 :                 res = str ? JS_NewString(jsf->ctx, str) : JS_NULL;
     966           1 :                 if (str) gf_free(str);
     967           1 :                 return res;
     968           1 :         case JSF_FILTER_SINKS_DONE:
     969           1 :         return JS_NewBool(jsf->ctx, gf_filter_all_sinks_done(jsf->filter) );
     970           1 :         case JSF_FILTER_REPORTING_ENABLED:
     971           1 :         return JS_NewBool(jsf->ctx, gf_filter_reporting_enabled(jsf->filter) );
     972             : 
     973           1 :         case JSF_FILTER_CAPS_MAX_WIDTH:
     974           1 :                 gf_filter_get_session_caps(jsf->filter, &caps);
     975           1 :                 return JS_NewInt32(ctx, caps.max_screen_width);
     976           1 :         case JSF_FILTER_CAPS_MAX_HEIGHT:
     977           1 :                 gf_filter_get_session_caps(jsf->filter, &caps);
     978           1 :                 return JS_NewInt32(ctx, caps.max_screen_height);
     979           1 :         case JSF_FILTER_CAPS_MAX_DISPLAY_DEPTH:
     980           1 :                 gf_filter_get_session_caps(jsf->filter, &caps);
     981           1 :                 return JS_NewInt32(ctx, caps.max_screen_bpp);
     982           1 :         case JSF_FILTER_CAPS_MAX_FPS:
     983           1 :                 gf_filter_get_session_caps(jsf->filter, &caps);
     984           1 :                 return JS_NewInt32(ctx, caps.max_screen_fps);
     985           1 :         case JSF_FILTER_CAPS_MAX_VIEWS:
     986           1 :                 gf_filter_get_session_caps(jsf->filter, &caps);
     987           1 :                 return JS_NewInt32(ctx, caps.max_screen_nb_views);
     988           1 :         case JSF_FILTER_CAPS_MAX_CHANNELS:
     989           1 :                 gf_filter_get_session_caps(jsf->filter, &caps);
     990           1 :                 return JS_NewInt32(ctx, caps.max_audio_channels);
     991           1 :         case JSF_FILTER_CAPS_MAX_SAMPLERATE:
     992           1 :                 gf_filter_get_session_caps(jsf->filter, &caps);
     993           1 :                 return JS_NewInt32(ctx, caps.max_audio_sample_rate);
     994           1 :         case JSF_FILTER_CAPS_MAX_AUDIO_DEPTH:
     995           1 :                 gf_filter_get_session_caps(jsf->filter, &caps);
     996           1 :                 return JS_NewInt32(ctx, caps.max_audio_bit_depth);
     997             : 
     998           1 :         case JSF_FILTER_NB_EVTS_QUEUED:
     999           1 :                 return JS_NewInt32(ctx, gf_filter_get_num_events_queued(jsf->filter) );
    1000           1 :         case JSF_FILTER_CLOCK_HINT_TIME:
    1001           1 :                 gf_filter_get_clock_hint(jsf->filter, &lival, NULL);
    1002           1 :                 return JS_NewInt64(ctx, lival);
    1003           1 :         case JSF_FILTER_CLOCK_HINT_MEDIATIME:
    1004             :         {
    1005             :                 GF_Fraction64 frac;
    1006           1 :                 gf_filter_get_clock_hint(jsf->filter, NULL, &frac);
    1007           1 :                 if (!frac.den) return JS_NULL;
    1008           0 :                 dval = ((Double)frac.num) / frac.den;
    1009             :         }
    1010             :                 return JS_NewFloat64(ctx, dval);
    1011           0 :         case JSF_FILTER_CONNECTIONS_PENDING:
    1012           0 :                 return JS_NewBool(ctx, gf_filter_connections_pending(jsf->filter) );
    1013           0 :         case JSF_FILTER_INAME:
    1014           0 :                 if (jsf->filter->iname) return JS_NewString(ctx, jsf->filter->iname);
    1015           0 :                 return JS_NULL;
    1016             :         }
    1017             : 
    1018           0 :     return JS_UNDEFINED;
    1019             : }
    1020             : 
    1021         146 : static JSValue jsf_filter_set_arg(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    1022             : {
    1023             :         JSValue v;
    1024             :         const char *desc=NULL;
    1025             :         const char *name=NULL;
    1026             :         const char *def = NULL;
    1027             :         const char *min_enum = NULL;
    1028         146 :         u32 type = 0;
    1029             :         Bool is_wildcard=GF_FALSE;
    1030         146 :         GF_JSFilterCtx *jsf = JS_GetOpaque(this_val, jsf_filter_class_id);
    1031         146 :     if (!jsf || !argc) return JS_EXCEPTION;
    1032             : 
    1033         146 :         v = JS_GetPropertyStr(ctx, argv[0], "name");
    1034         146 :         if (!JS_IsUndefined(v)) name = JS_ToCString(ctx, v);
    1035             :         JS_FreeValue(ctx, v);
    1036         146 :         if (!name) return JS_EXCEPTION;
    1037             : 
    1038         146 :         if (!strcmp(name, "*")) {
    1039           0 :                 if (jsf->has_wilcard_arg) return JS_UNDEFINED;
    1040             :                 is_wildcard = GF_TRUE;
    1041           0 :                 jsf->has_wilcard_arg = GF_TRUE;
    1042             :         }
    1043             : 
    1044         146 :         v = JS_GetPropertyStr(ctx, argv[0], "desc");
    1045         146 :         if (!JS_IsUndefined(v)) desc = JS_ToCString(ctx, v);
    1046             :         JS_FreeValue(ctx, v);
    1047         146 :         if (!desc) {
    1048           0 :                 JS_FreeCString(ctx, name);
    1049           0 :                 return JS_EXCEPTION;
    1050             :         }
    1051             : 
    1052         146 :         v = JS_GetPropertyStr(ctx, argv[0], "type");
    1053         146 :         if (!JS_IsUndefined(v))
    1054         146 :                 JS_ToInt32(ctx, &type, v);
    1055             :         JS_FreeValue(ctx, v);
    1056         146 :         if (!type) {
    1057           0 :                 if (is_wildcard) {
    1058           0 :                         type = GF_PROP_STRING;
    1059             :                 } else {
    1060           0 :                         JS_FreeCString(ctx, name);
    1061           0 :                         JS_FreeCString(ctx, desc);
    1062           0 :                         return JS_EXCEPTION;
    1063             :                 }
    1064             :         }
    1065             : 
    1066         146 :         v = JS_GetPropertyStr(ctx, argv[0], "def");
    1067         146 :         if (!JS_IsUndefined(v)) def = JS_ToCString(ctx, v);
    1068             :         JS_FreeValue(ctx, v);
    1069             : 
    1070         146 :         v = JS_GetPropertyStr(ctx, argv[0], "minmax_enum");
    1071         146 :         if (!JS_IsUndefined(v)) min_enum = JS_ToCString(ctx, v);
    1072             :         JS_FreeValue(ctx, v);
    1073             : 
    1074         146 :         jsf->args = gf_realloc(jsf->args, sizeof(GF_FilterArgs)*(jsf->nb_args+2));
    1075         146 :         memset(&jsf->args[jsf->nb_args], 0, 2*sizeof(GF_FilterArgs));
    1076         146 :         jsf->args[jsf->nb_args].arg_name = gf_strdup(name);
    1077         146 :         jsf->args[jsf->nb_args].arg_desc = desc ? gf_strdup(desc) : NULL;
    1078         146 :         jsf->args[jsf->nb_args].arg_default_val = def ? gf_strdup(def) : NULL;
    1079         146 :         jsf->args[jsf->nb_args].min_max_enum = min_enum ? gf_strdup(min_enum) : NULL;
    1080         146 :         jsf->args[jsf->nb_args].arg_type = type;
    1081         146 :         jsf->args[jsf->nb_args].offset_in_private = -1;
    1082             : 
    1083         146 :         jsf->nb_args ++;
    1084             : 
    1085         146 :         gf_filter_define_args(jsf->filter, jsf->args);
    1086             : 
    1087         146 :         JS_FreeCString(ctx, name);
    1088         146 :         JS_FreeCString(ctx, desc);
    1089         146 :         JS_FreeCString(ctx, def);
    1090         146 :         JS_FreeCString(ctx, min_enum);
    1091         146 :     return JS_UNDEFINED;
    1092             : }
    1093             : 
    1094             : 
    1095          74 : static JSValue jsf_filter_set_cap(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    1096             : {
    1097             :         u32 prop_id = 0;
    1098             :         Bool is_output=GF_FALSE;
    1099             :         Bool is_inputoutput=GF_FALSE;
    1100             :         Bool is_excluded=GF_FALSE;
    1101             :         Bool is_static=GF_FALSE;
    1102             :         Bool is_loaded_filter_only=GF_FALSE;
    1103             :         Bool is_optional=GF_FALSE;
    1104             :         GF_PropertyValue p;
    1105          74 :         GF_JSFilterCtx *jsf = JS_GetOpaque(this_val, jsf_filter_class_id);
    1106          74 :     if (!jsf) return JS_EXCEPTION;
    1107          74 :         jsf->disable_filter = GF_FALSE;
    1108             : 
    1109             :         memset(&p, 0, sizeof(GF_PropertyValue));
    1110          74 :     if (argc) {
    1111             :                 u32 prop_type;
    1112             :         JSValue v;
    1113             :                 const char *name = NULL;
    1114             : 
    1115          74 :                 v = JS_GetPropertyStr(ctx, argv[0], "id");
    1116          74 :                 if (!JS_IsUndefined(v)) name = JS_ToCString(ctx, v);
    1117             :                 JS_FreeValue(ctx, v);
    1118          74 :                 if (!name) return JS_EXCEPTION;
    1119          74 :                 prop_id = gf_props_get_id(name);
    1120          74 :                 JS_FreeCString(ctx, name);
    1121          74 :                 if (!prop_id)
    1122           0 :                         return js_throw_err(ctx, GF_BAD_PARAM);
    1123          74 :                 prop_type = gf_props_4cc_get_type(prop_id);
    1124             : 
    1125             :                 name = NULL;
    1126          74 :                 v = JS_GetPropertyStr(ctx, argv[0], "value");
    1127          74 :                 if (!JS_IsUndefined(v)) name = JS_ToCString(ctx, v);
    1128             :                 JS_FreeValue(ctx, v);
    1129             : 
    1130          74 :                 if (prop_id==GF_PROP_PID_STREAM_TYPE) {
    1131          44 :                         p.type = GF_PROP_UINT;
    1132          44 :                         p.value.uint = gf_stream_type_by_name(name);
    1133          30 :                 } else if (prop_id==GF_PROP_PID_CODECID) {
    1134          30 :                         p.type = GF_PROP_UINT;
    1135          30 :                         p.value.uint = gf_codecid_parse(name);
    1136             :                 } else {
    1137           0 :                         p = gf_props_parse_value(prop_type, NULL, name, NULL, gf_filter_get_sep(jsf->filter, GF_FS_SEP_LIST) );
    1138             :                 }
    1139          74 :                 JS_FreeCString(ctx, name);
    1140             : 
    1141             : #define GETB(_v, _n)\
    1142             :                 v = JS_GetPropertyStr(ctx, argv[0], _n);\
    1143             :                 if (!JS_IsUndefined(v)) _v = JS_ToBool(ctx, v);\
    1144             :                 JS_FreeValue(ctx, v);\
    1145             : 
    1146         148 :                 GETB(is_output, "output");
    1147         148 :                 GETB(is_inputoutput, "inout");
    1148         148 :                 GETB(is_excluded, "excluded");
    1149         148 :                 GETB(is_loaded_filter_only, "loaded_filter_only");
    1150         148 :                 GETB(is_static, "static");
    1151         148 :                 GETB(is_optional, "optional");
    1152             : #undef GETB
    1153             : 
    1154             :         }
    1155             : 
    1156          74 :         jsf->caps = gf_realloc(jsf->caps, sizeof(GF_FilterCapability)*(jsf->nb_caps+1));
    1157          74 :         memset(&jsf->caps[jsf->nb_caps], 0, sizeof(GF_FilterCapability));
    1158          74 :         if (prop_id) {
    1159          74 :                 GF_FilterCapability *cap = &jsf->caps[jsf->nb_caps];
    1160          74 :                 cap->code = prop_id;
    1161          74 :                 cap->val = p;
    1162          74 :                 cap->flags = GF_CAPFLAG_IN_BUNDLE;
    1163          74 :                 if (is_inputoutput) {
    1164           8 :                         cap->flags |= GF_CAPFLAG_INPUT|GF_CAPFLAG_OUTPUT;
    1165          66 :                 } else if (is_output) {
    1166          40 :                         cap->flags |= GF_CAPFLAG_OUTPUT;
    1167             :                 } else {
    1168          26 :                         cap->flags |= GF_CAPFLAG_INPUT;
    1169             :                 }
    1170          74 :                 if (is_excluded)
    1171           8 :                         cap->flags |= GF_CAPFLAG_EXCLUDED;
    1172          74 :                 if (is_static)
    1173           0 :                         cap->flags |= GF_CAPFLAG_STATIC;
    1174          74 :                 if (is_loaded_filter_only)
    1175           0 :                         cap->flags |= GF_CAPFLAG_LOADED_FILTER;
    1176          74 :                 if (is_optional)
    1177           0 :                         cap->flags |= GF_CAPFLAG_OPTIONAL;
    1178             :         }
    1179          74 :         jsf->nb_caps ++;
    1180          74 :         gf_filter_override_caps(jsf->filter, jsf->caps, jsf->nb_caps);
    1181          74 :         return JS_UNDEFINED;
    1182             : }
    1183             : 
    1184          41 : static JSValue jsf_filter_set_desc(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    1185             : {
    1186          41 :         GF_JSFilterCtx *jsf = JS_GetOpaque(this_val, jsf_filter_class_id);
    1187          41 :     if (!jsf) return JS_EXCEPTION;
    1188             :         const char *str = JS_ToCString(ctx, argv[0]);
    1189          41 :     if (!str) return JS_EXCEPTION;
    1190          41 :         gf_filter_set_description(jsf->filter, str);
    1191          41 :         JS_FreeCString(ctx, str);
    1192          41 :     return JS_UNDEFINED;
    1193             : }
    1194             : 
    1195          41 : static JSValue jsf_filter_set_version(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    1196             : {
    1197          41 :         GF_JSFilterCtx *jsf = JS_GetOpaque(this_val, jsf_filter_class_id);
    1198          41 :     if (!jsf) return JS_EXCEPTION;
    1199             :         const char *str = JS_ToCString(ctx, argv[0]);
    1200          41 :     if (!str) return JS_EXCEPTION;
    1201          41 :         gf_filter_set_version(jsf->filter, str);
    1202          41 :         JS_FreeCString(ctx, str);
    1203          41 :     return JS_UNDEFINED;
    1204             : }
    1205             : 
    1206          41 : static JSValue jsf_filter_set_author(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    1207             : {
    1208          41 :         GF_JSFilterCtx *jsf = JS_GetOpaque(this_val, jsf_filter_class_id);
    1209          41 :     if (!jsf) return JS_EXCEPTION;
    1210             :         const char *str = JS_ToCString(ctx, argv[0]);
    1211          41 :     if (!str) return JS_EXCEPTION;
    1212          41 :         gf_filter_set_author(jsf->filter, str);
    1213          41 :         JS_FreeCString(ctx, str);
    1214          41 :     return JS_UNDEFINED;
    1215             : }
    1216             : 
    1217             : 
    1218          41 : static JSValue jsf_filter_set_help(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    1219             : {
    1220          41 :         GF_JSFilterCtx *jsf = JS_GetOpaque(this_val, jsf_filter_class_id);
    1221          41 :     if (!jsf) return JS_EXCEPTION;
    1222             :         const char *str = JS_ToCString(ctx, argv[0]);
    1223          41 :     if (!str) return JS_EXCEPTION;
    1224          41 :         gf_filter_set_help(jsf->filter, str);
    1225          41 :         JS_FreeCString(ctx, str);
    1226          41 :     return JS_UNDEFINED;
    1227             : }
    1228             : 
    1229          41 : static JSValue jsf_filter_set_name(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    1230             : {
    1231          41 :         GF_JSFilterCtx *jsf = JS_GetOpaque(this_val, jsf_filter_class_id);
    1232          41 :     if (!jsf) return JS_EXCEPTION;
    1233          41 :     if (jsf->log_name) gf_free(jsf->log_name);
    1234          41 :     jsf->log_name = NULL;
    1235          41 :     if (argc) {
    1236             :         JSValue global;
    1237             :                 const char *str = JS_ToCString(ctx, argv[0]);
    1238          41 :                 if (!str) return JS_EXCEPTION;
    1239          41 :         jsf->log_name = gf_strdup(str);
    1240          41 :                 JS_FreeCString(ctx, str);
    1241          41 :                 gf_filter_set_name(jsf->filter, jsf->log_name);
    1242             : 
    1243          41 :                 global = JS_GetGlobalObject(ctx);
    1244          41 :         JS_SetPropertyStr(ctx, global, "_gpac_log_name", JS_NewString(ctx, jsf->log_name));
    1245             :         JS_FreeValue(ctx, global);
    1246             :     }
    1247          41 :     return JS_UNDEFINED;
    1248             : }
    1249             : 
    1250             : 
    1251          38 : static JSValue jsf_filter_new_pid(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    1252             : {
    1253             :         GF_JSPidCtx *pctx;
    1254          38 :         GF_JSFilterCtx *jsf = JS_GetOpaque(this_val, jsf_filter_class_id);
    1255          38 :     if (!jsf) return JS_EXCEPTION;
    1256          38 :     GF_FilterPid *opid = gf_filter_pid_new(jsf->filter);
    1257          38 :         if (!opid) return JS_EXCEPTION;
    1258          38 :         jsf->disable_filter = GF_FALSE;
    1259             : 
    1260          38 :         GF_SAFEALLOC(pctx, GF_JSPidCtx);
    1261          38 :         if (!pctx)
    1262           0 :                 return js_throw_err(ctx, GF_OUT_OF_MEM);
    1263          38 :         gf_list_add(jsf->pids, pctx);
    1264          38 :         pctx->jsf = jsf;
    1265          38 :         pctx->pid = opid;
    1266          38 :         pctx->jsobj = JS_NewObjectClass(ctx, jsf_pid_class_id);
    1267             :         //keep ref to value we destroy it upon pid removal or filter desctruction
    1268          38 :         pctx->jsobj = JS_DupValue(ctx, pctx->jsobj);
    1269          38 :         JS_SetOpaque(pctx->jsobj, pctx);
    1270          38 :         gf_filter_pid_set_udta(pctx->pid, pctx);
    1271          38 :         return pctx->jsobj;
    1272             : }
    1273             : 
    1274           1 : static JSValue jsf_filter_send_event(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    1275             : {
    1276             :         Bool upstream = GF_FALSE;
    1277           1 :         GF_JSFilterCtx *jsf = JS_GetOpaque(this_val, jsf_filter_class_id);
    1278           1 :         GF_JSFilterInstanceCtx *jsfi = JS_GetOpaque(this_val, jsf_filter_inst_class_id);
    1279           1 :     if (!jsf && !jsfi) return JS_EXCEPTION;
    1280           1 :         GF_FilterEvent *evt = JS_GetOpaque(argv[0], jsf_event_class_id);
    1281           1 :     if (!evt) return JS_EXCEPTION;
    1282           1 :     if (argc>1) {
    1283           0 :                 upstream = JS_ToBool(ctx, argv[1]);
    1284             :         }
    1285             : 
    1286           1 :         if (jsf)
    1287           1 :                 gf_filter_send_event(jsf->filter, evt, upstream);
    1288             :         else
    1289           0 :                 gf_filter_send_event(jsfi->filter, evt, upstream);
    1290           1 :     return JS_UNDEFINED;
    1291             : }
    1292             : 
    1293           1 : static JSValue jsf_filter_get_info(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    1294             : {
    1295             :         JSValue res;
    1296             :         const char *name=NULL;
    1297             :         const GF_PropertyValue *prop;
    1298             :         GF_Filter *filter;
    1299           1 :         GF_PropertyEntry *pe = NULL;
    1300           1 :         GF_JSFilterCtx *jsf = JS_GetOpaque(this_val, jsf_filter_class_id);
    1301           1 :         GF_JSFilterInstanceCtx *jsfi = JS_GetOpaque(this_val, jsf_filter_inst_class_id);
    1302           1 :     if (!jsf && !jsfi) return JS_EXCEPTION;
    1303             :     name = JS_ToCString(ctx, argv[0]);
    1304           1 :         if (!name) return JS_EXCEPTION;
    1305           1 :         filter = jsf ? jsf->filter : jsfi->filter;
    1306             : 
    1307           1 :         if ((argc>1) && JS_ToBool(ctx, argv[1])) {
    1308           0 :                 prop = gf_filter_get_info_str(filter, name, &pe);
    1309           0 :                 JS_FreeCString(ctx, name);
    1310           0 :                 if (!prop) return JS_NULL;
    1311           0 :                 res = jsf_NewProp(ctx, prop);
    1312           0 :                 JS_SetPropertyStr(ctx, res, "type", JS_NewInt32(ctx, prop->type));
    1313             :         } else {
    1314           1 :                 u32 p4cc = gf_props_get_id(name);
    1315           1 :                 JS_FreeCString(ctx, name);
    1316           1 :                 if (!p4cc)
    1317           0 :                         return js_throw_err(ctx, GF_BAD_PARAM);
    1318           1 :                 prop = gf_filter_get_info(filter, p4cc, &pe);
    1319           1 :                 if (!prop) return JS_NULL;
    1320           1 :                 res = jsf_NewPropTranslate(ctx, prop, p4cc);
    1321             :         }
    1322           1 :         gf_filter_release_property(pe);
    1323           1 :     return res;
    1324             : }
    1325             : 
    1326             : 
    1327             : 
    1328           1 : static JSValue jsf_filter_is_supported_mime(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    1329             : {
    1330             :         const char *mime=NULL;
    1331             :         JSValue res;
    1332           1 :         GF_JSFilterCtx *jsf = JS_GetOpaque(this_val, jsf_filter_class_id);
    1333           1 :     if (!jsf || !argc) return JS_EXCEPTION;
    1334             :     mime = JS_ToCString(ctx, argv[0]);
    1335           1 :         if (!mime) return JS_EXCEPTION;
    1336           1 :         res = JS_NewBool(ctx, gf_filter_is_supported_mime(jsf->filter, mime));
    1337           1 :         JS_FreeCString(ctx, mime);
    1338           1 :         return res;
    1339             : }
    1340             : 
    1341           1 : static JSValue jsf_filter_is_supported_source(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    1342             : {
    1343             :         const char *src=NULL;
    1344             :         const char *parent=NULL;
    1345             :         JSValue res;
    1346           1 :         GF_JSFilterCtx *jsf = JS_GetOpaque(this_val, jsf_filter_class_id);
    1347           1 :     if (!jsf || !argc) return JS_EXCEPTION;
    1348             :     src = JS_ToCString(ctx, argv[0]);
    1349           1 :         if (!src) return JS_EXCEPTION;
    1350           1 :         if (argc>1) {
    1351             :                 parent = JS_ToCString(ctx, argv[1]);
    1352           0 :                 if (!parent) {
    1353           0 :                         JS_FreeCString(ctx, src);
    1354           0 :                         return JS_EXCEPTION;
    1355             :                 }
    1356             :         }
    1357           1 :         res = JS_NewBool(ctx, gf_filter_is_supported_source(jsf->filter, src, parent) );
    1358           1 :         JS_FreeCString(ctx, src);
    1359           1 :         JS_FreeCString(ctx, parent);
    1360           1 :         return res;
    1361             : }
    1362             : 
    1363           1 : static JSValue jsf_filter_update_status(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    1364             : {
    1365             :     const char *status;
    1366           1 :     u32 pc=0;
    1367           1 :         GF_JSFilterCtx *jsf = JS_GetOpaque(this_val, jsf_filter_class_id);
    1368           1 :     if (!jsf || (argc<1))  return JS_EXCEPTION;
    1369             : 
    1370             :     status = JS_ToCString(ctx, argv[0]);
    1371           1 :         if (argc>1)
    1372           0 :                 JS_ToInt32(ctx, &pc, argv[1]);
    1373           1 :     gf_filter_update_status(jsf->filter, pc, (char*) status);
    1374           1 :         JS_FreeCString(ctx, status);
    1375           1 :         return JS_UNDEFINED;
    1376             : }
    1377             : 
    1378         348 : static JSValue jsf_filter_reschedule_in(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    1379             : {
    1380         348 :     u32 rt_delay=0;
    1381         348 :         GF_JSFilterCtx *jsf = JS_GetOpaque(this_val, jsf_filter_class_id);
    1382         348 :     if (!jsf) return JS_EXCEPTION;
    1383             : 
    1384         348 :     if (argc) {
    1385         348 :                 if (JS_ToInt32(ctx, &rt_delay, argv[0]))
    1386           0 :                         return JS_EXCEPTION;
    1387             : 
    1388         348 :                 gf_filter_ask_rt_reschedule(jsf->filter, rt_delay);
    1389             :         } else {
    1390           0 :                 gf_filter_post_process_task(jsf->filter);
    1391             :         }
    1392         348 :         return JS_UNDEFINED;
    1393             : }
    1394             : 
    1395             : typedef struct
    1396             : {
    1397             :         JSValue func;
    1398             :         JSValue obj;
    1399             :         GF_JSFilterCtx *jsf;
    1400             : } JS_ScriptTask;
    1401             : 
    1402           1 : Bool jsf_task_exec(GF_Filter *filter, void *callback, u32 *reschedule_ms)
    1403             : {
    1404           1 :         s32 fun_result = -1;
    1405             :         JS_ScriptTask *task = (JS_ScriptTask *) callback;
    1406             :         JSValue ret;
    1407           1 :         gf_js_lock(task->jsf->ctx, GF_TRUE);
    1408             : 
    1409           2 :         if (JS_IsUndefined(task->obj)) {
    1410           1 :                 ret = JS_Call(task->jsf->ctx, task->func, task->jsf->filter_obj, 0, NULL);
    1411             :         } else {
    1412           0 :                 ret = JS_Call(task->jsf->ctx, task->func, task->obj, 0, NULL);
    1413             :         }
    1414             : 
    1415           1 :         if (JS_IsException(ret)) {
    1416           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_SCRIPT, ("[%s] Error processing JS-defined task\n", task->jsf->log_name));
    1417           0 :                 js_dump_error(task->jsf->ctx);
    1418             :         }
    1419           1 :         else if (JS_IsInteger(ret)) {
    1420           1 :                 JS_ToInt32(task->jsf->ctx, &fun_result, ret);
    1421             :         }
    1422           1 :         JS_FreeValue(task->jsf->ctx, ret);
    1423             : 
    1424           1 :         gf_js_lock(task->jsf->ctx, GF_FALSE);
    1425           1 :         js_do_loop(task->jsf->ctx);
    1426             : 
    1427           1 :         if (fun_result>=0) {
    1428           0 :                 *reschedule_ms = (u32) fun_result;
    1429           0 :                 return GF_TRUE;
    1430             :         }
    1431           2 :         if (!JS_IsUndefined(task->obj)) {
    1432           0 :                 JS_FreeValue(task->jsf->ctx, task->obj);
    1433             :         }
    1434           1 :         JS_FreeValue(task->jsf->ctx, task->func);
    1435           1 :         gf_free(task);
    1436           1 :         return GF_FALSE;
    1437             : }
    1438           1 : static JSValue jsf_filter_post_task(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    1439             : {
    1440             :         JS_ScriptTask *task;
    1441           1 :         GF_JSFilterCtx *jsf = JS_GetOpaque(this_val, jsf_filter_class_id);
    1442           1 :     if (!jsf || !argc) return JS_EXCEPTION;
    1443           1 :         jsf->disable_filter = GF_FALSE;
    1444           1 :         if (!JS_IsFunction(ctx, argv[0]))
    1445           0 :                 return JS_EXCEPTION;
    1446           1 :         if ((argc>1) && !JS_IsObject(argv[1]))
    1447           0 :                 return JS_EXCEPTION;
    1448             : 
    1449           1 :         GF_SAFEALLOC(task, JS_ScriptTask);
    1450           1 :         if (!task)
    1451           0 :                 return js_throw_err(ctx, GF_OUT_OF_MEM);
    1452           1 :         task->jsf = jsf;
    1453           1 :         task->func = JS_DupValue(ctx, argv[0]);
    1454           1 :         task->obj = JS_UNDEFINED;
    1455           1 :         if (argc>1)
    1456           0 :                 task->obj = JS_DupValue(ctx, argv[1]);
    1457             : 
    1458           1 :         gf_filter_post_task(jsf->filter, jsf_task_exec, task, "jsf_task");
    1459           1 :         return JS_UNDEFINED;
    1460             : }
    1461             : 
    1462           1 : static JSValue jsf_filter_notify_failure(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    1463             : {
    1464             :         GF_Err e;
    1465           1 :         s32 error_type=0;
    1466           1 :         GF_JSFilterCtx *jsf = JS_GetOpaque(this_val, jsf_filter_class_id);
    1467           1 :     if (!jsf || !argc) return JS_EXCEPTION;
    1468           1 :         if (JS_ToInt32(ctx, (int *) &e, argv[0]))
    1469           0 :                 return JS_EXCEPTION;
    1470             : 
    1471           1 :         if (e==GF_OK) return JS_UNDEFINED;
    1472             : 
    1473           0 :         if ((argc>1) && JS_ToInt32(ctx, &error_type, argv[1]))
    1474           0 :                 return JS_EXCEPTION;
    1475           0 :         if (error_type==JSF_NOTIF_ERROR_AND_DISCONNECT)
    1476           0 :                 gf_filter_notification_failure(jsf->filter, e, GF_TRUE);
    1477           0 :         else if (error_type==JSF_NOTIF_ERROR)
    1478           0 :                 gf_filter_notification_failure(jsf->filter, e, GF_FALSE);
    1479             :         else
    1480           0 :                 gf_filter_setup_failure(jsf->filter, e);
    1481           0 :         return JS_UNDEFINED;
    1482             : }
    1483             : 
    1484           1 : static JSValue jsf_filter_hint_clock(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    1485             : {
    1486           1 :         s64 time_in_us=0;
    1487             :         GF_Fraction64 media_timestamp;
    1488           1 :         GF_JSFilterCtx *jsf = JS_GetOpaque(this_val, jsf_filter_class_id);
    1489           1 :     if (!jsf || (argc<2))  return JS_EXCEPTION;
    1490           1 :         if (JS_ToInt64(ctx, &time_in_us, argv[0]))
    1491           0 :                 return JS_EXCEPTION;
    1492           1 :         if (argc==2) {
    1493           1 :                 Double t=0;
    1494           1 :                 if (JS_ToFloat64(ctx, &t, argv[0]))
    1495           0 :                         return JS_EXCEPTION;
    1496           1 :                 media_timestamp.den = 1000000;
    1497           1 :                 media_timestamp.num = (s64) (t*media_timestamp.den);
    1498             :         } else {
    1499           0 :                 if (JS_ToInt64(ctx, &media_timestamp.num, argv[0]))
    1500           0 :                         return JS_EXCEPTION;
    1501           0 :                 if (JS_ToInt64(ctx, &media_timestamp.den, argv[0]))
    1502           0 :                         return JS_EXCEPTION;
    1503             :         }
    1504           1 :         gf_filter_hint_single_clock(jsf->filter, time_in_us, media_timestamp);
    1505           1 :         return JS_UNDEFINED;
    1506             : }
    1507             : 
    1508           1 : static JSValue jsf_filter_send_update(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    1509             : {
    1510             :         const char *filter_id=NULL;
    1511             :         const char *arg_name=NULL;
    1512             :         const char *arg_val=NULL;
    1513           1 :         GF_EventPropagateType prop_mask = 0;
    1514           1 :         JSValue ret = JS_UNDEFINED;
    1515           1 :         GF_JSFilterCtx *jsf = JS_GetOpaque(this_val, jsf_filter_class_id);
    1516           1 :         GF_JSFilterInstanceCtx *jsfi = JS_GetOpaque(this_val, jsf_filter_inst_class_id);
    1517           1 :     if ((!jsf && !jsfi) || (argc!=4))  return JS_EXCEPTION;
    1518             : 
    1519             :         filter_id = JS_ToCString(ctx, argv[0]);
    1520             :         arg_name = JS_ToCString(ctx, argv[1]);
    1521             :         arg_val = JS_ToCString(ctx, argv[2]);
    1522           1 :         if (!arg_name || !arg_val || JS_ToInt32(ctx, (s32 *) &prop_mask, argv[3])) {
    1523           0 :                 ret = JS_EXCEPTION;
    1524           0 :                 goto exit;
    1525             :         }
    1526           1 :         if (jsf)
    1527           1 :                 gf_filter_send_update(jsf->filter, filter_id, arg_name, arg_val, prop_mask);
    1528             :         else
    1529           0 :                 gf_filter_send_update(jsfi->filter, filter_id, arg_name, arg_val, prop_mask);
    1530             : 
    1531           1 : exit:
    1532           1 :         JS_FreeCString(ctx, filter_id);
    1533           1 :         JS_FreeCString(ctx, arg_name);
    1534           1 :         JS_FreeCString(ctx, arg_val);
    1535           1 :         return ret;
    1536             : }
    1537             : 
    1538           5 : static JSValue jsf_filter_load_filter(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, GF_JSFilterMode mode)
    1539             : {
    1540             :         const char *url=NULL;
    1541             :         const char *parent=NULL;
    1542           5 :         GF_Err e=GF_OK;
    1543             :         Bool inherit_args = GF_FALSE;
    1544             :         GF_JSFilterInstanceCtx *f_ctx;
    1545           5 :         GF_JSFilterCtx *jsf = JS_GetOpaque(this_val, jsf_filter_class_id);
    1546           5 :     if (!jsf || !argc) return JS_EXCEPTION;
    1547             :     url = JS_ToCString(ctx, argv[0]);
    1548           5 :         if (!url) return JS_EXCEPTION;
    1549             : 
    1550           5 :         if ((mode==JSF_FINST_SOURCE) && (argc>1)) {
    1551             :                 parent = JS_ToCString(ctx, argv[1]);
    1552           0 :                 if (!parent) {
    1553           0 :                         JS_FreeCString(ctx, url);
    1554           0 :                         return JS_EXCEPTION;
    1555             :                 }
    1556           0 :                 if (argc>2) {
    1557           0 :                         inherit_args = JS_ToBool(ctx, argv[2]);
    1558             :                 }
    1559             :         }
    1560           5 :         GF_SAFEALLOC(f_ctx, GF_JSFilterInstanceCtx);
    1561           5 :         if (!f_ctx) {
    1562           0 :                 JS_FreeCString(ctx, url);
    1563           0 :                 JS_FreeCString(ctx, parent);
    1564           0 :                 return js_throw_err(ctx, GF_OUT_OF_MEM);
    1565             :         }
    1566             : 
    1567           5 :         f_ctx->fmode = mode;
    1568           5 :         if (mode==JSF_FINST_SOURCE) {
    1569           2 :                 f_ctx->filter = gf_filter_connect_source(jsf->filter, url, parent, inherit_args, &e);
    1570           3 :         } else if (mode==JSF_FINST_DEST) {
    1571           1 :                 f_ctx->filter = gf_filter_connect_destination(jsf->filter, url, &e);
    1572             :         } else {
    1573           2 :                 f_ctx->filter = gf_filter_load_filter(jsf->filter, url, &e);
    1574             :         }
    1575           5 :         JS_FreeCString(ctx, url);
    1576           5 :         JS_FreeCString(ctx, parent);
    1577           5 :         if (!f_ctx->filter) {
    1578           0 :                 gf_free(f_ctx);
    1579           0 :                 return js_throw_err(ctx, e);
    1580             :         }
    1581           5 :         f_ctx->jsf = jsf;
    1582           5 :         f_ctx->setup_failure_fun = JS_UNDEFINED;
    1583           5 :         f_ctx->filter_obj = JS_NewObjectClass(ctx, jsf_filter_inst_class_id);
    1584           5 :         JS_SetOpaque(f_ctx->filter_obj, f_ctx);
    1585           5 :         return f_ctx->filter_obj;
    1586             : }
    1587             : 
    1588           2 : static JSValue jsf_filter_add_source(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    1589             : {
    1590           2 :         return jsf_filter_load_filter(ctx, this_val, argc, argv, JSF_FINST_SOURCE);
    1591             : 
    1592             : }
    1593           1 : static JSValue jsf_filter_add_dest(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    1594             : {
    1595           1 :         return jsf_filter_load_filter(ctx, this_val, argc, argv, JSF_FINST_DEST);
    1596             : }
    1597           2 : static JSValue jsf_filter_add_filter(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    1598             : {
    1599           2 :         return jsf_filter_load_filter(ctx, this_val, argc, argv, JSF_FINST_FILTER);
    1600             : }
    1601           1 : static JSValue jsf_filter_make_sticky(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    1602             : {
    1603           1 :         GF_JSFilterCtx *jsf = JS_GetOpaque(this_val, jsf_filter_class_id);
    1604           1 :     if (!jsf) return JS_EXCEPTION;
    1605           1 :         gf_filter_make_sticky(jsf->filter);
    1606           1 :         return JS_UNDEFINED;
    1607             : }
    1608           1 : static JSValue jsf_filter_prevent_blocking(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    1609             : {
    1610           1 :         GF_JSFilterCtx *jsf = JS_GetOpaque(this_val, jsf_filter_class_id);
    1611           1 :     if (!jsf || !argc) return JS_EXCEPTION;
    1612           1 :         gf_filter_prevent_blocking(jsf->filter, JS_ToBool(ctx, argv[0]) ? GF_TRUE : GF_FALSE);
    1613           1 :         return JS_UNDEFINED;
    1614             : }
    1615           1 : static JSValue jsf_filter_block_eos(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    1616             : {
    1617           1 :         GF_JSFilterCtx *jsf = JS_GetOpaque(this_val, jsf_filter_class_id);
    1618           1 :     if (!jsf || !argc) return JS_EXCEPTION;
    1619           1 :         gf_filter_block_eos(jsf->filter, JS_ToBool(ctx, argv[0]) ? GF_TRUE : GF_FALSE);
    1620           1 :         return JS_UNDEFINED;
    1621             : }
    1622             : 
    1623             : 
    1624           0 : static JSValue jsf_filter_abort(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    1625             : {
    1626           0 :         GF_JSFilterCtx *jsf = JS_GetOpaque(this_val, jsf_filter_class_id);
    1627           0 :     if (!jsf) return JS_EXCEPTION;
    1628           0 :         gf_filter_abort(jsf->filter);
    1629           0 :         return JS_UNDEFINED;
    1630             : }
    1631             : 
    1632             : static const JSCFunctionListEntry jsf_filter_funcs[] = {
    1633             :     JS_CGETSET_MAGIC_DEF("initialize", jsf_filter_prop_get, jsf_filter_prop_set, JSF_EVT_INITIALIZE),
    1634             :     JS_CGETSET_MAGIC_DEF("finalize", jsf_filter_prop_get, jsf_filter_prop_set, JSF_EVT_FINALIZE),
    1635             :     JS_CGETSET_MAGIC_DEF("configure_pid", jsf_filter_prop_get, jsf_filter_prop_set, JSF_EVT_CONFIGURE_PID),
    1636             :     JS_CGETSET_MAGIC_DEF("process", jsf_filter_prop_get, jsf_filter_prop_set, JSF_EVT_PROCESS),
    1637             :     JS_CGETSET_MAGIC_DEF("process_event", jsf_filter_prop_get, jsf_filter_prop_set, JSF_EVT_PROCESS_EVENT),
    1638             :     JS_CGETSET_MAGIC_DEF("update_arg", jsf_filter_prop_get, jsf_filter_prop_set, JSF_EVT_UPDATE_ARG),
    1639             :     JS_CGETSET_MAGIC_DEF("probe_data", jsf_filter_prop_get, jsf_filter_prop_set, JSF_EVT_PROBE_DATA),
    1640             :     JS_CGETSET_MAGIC_DEF("probe_url", jsf_filter_prop_get, jsf_filter_prop_set, JSF_EVT_PROBE_URL),
    1641             :     JS_CGETSET_MAGIC_DEF("reconfigure_output", jsf_filter_prop_get, jsf_filter_prop_set, JSF_EVT_RECONFIGURE_OUTPUT),
    1642             :     JS_CGETSET_MAGIC_DEF("remove_pid", jsf_filter_prop_get, jsf_filter_prop_set, JSF_EVT_REMOVE_PID),
    1643             :     JS_CGETSET_MAGIC_DEF("max_pids", jsf_filter_prop_get, jsf_filter_prop_set, JSF_FILTER_MAX_PIDS),
    1644             :     JS_CGETSET_MAGIC_DEF("block_enabled", jsf_filter_prop_get, NULL, JSF_FILTER_BLOCK_ENABLED),
    1645             :     JS_CGETSET_MAGIC_DEF("output_buffer", jsf_filter_prop_get, NULL, JSF_FILTER_OUTPUT_BUFFER),
    1646             :     JS_CGETSET_MAGIC_DEF("output_playout", jsf_filter_prop_get, NULL, JSF_FILTER_OUTPUT_PLAYOUT),
    1647             :     JS_CGETSET_MAGIC_DEF("sep_args", jsf_filter_prop_get, NULL, JSF_FILTER_SEP_ARGS),
    1648             :     JS_CGETSET_MAGIC_DEF("sep_name", jsf_filter_prop_get, NULL, JSF_FILTER_SEP_NAME),
    1649             :     JS_CGETSET_MAGIC_DEF("sep_list", jsf_filter_prop_get, NULL, JSF_FILTER_SEP_LIST),
    1650             :     JS_CGETSET_MAGIC_DEF("dst_args", jsf_filter_prop_get, NULL, JSF_FILTER_DST_ARGS),
    1651             :     JS_CGETSET_MAGIC_DEF("dst_name", jsf_filter_prop_get, NULL, JSF_FILTER_DST_NAME),
    1652             :     JS_CGETSET_MAGIC_DEF("sinks_done", jsf_filter_prop_get, NULL, JSF_FILTER_SINKS_DONE),
    1653             :     JS_CGETSET_MAGIC_DEF("reports_on", jsf_filter_prop_get, NULL, JSF_FILTER_REPORTING_ENABLED),
    1654             :     JS_CGETSET_MAGIC_DEF("max_screen_width", jsf_filter_prop_get, jsf_filter_prop_set, JSF_FILTER_CAPS_MAX_WIDTH),
    1655             :     JS_CGETSET_MAGIC_DEF("max_screen_height", jsf_filter_prop_get, jsf_filter_prop_set, JSF_FILTER_CAPS_MAX_HEIGHT),
    1656             :     JS_CGETSET_MAGIC_DEF("max_screen_depth", jsf_filter_prop_get, jsf_filter_prop_set, JSF_FILTER_CAPS_MAX_DISPLAY_DEPTH),
    1657             :     JS_CGETSET_MAGIC_DEF("max_screen_fps", jsf_filter_prop_get, jsf_filter_prop_set, JSF_FILTER_CAPS_MAX_FPS),
    1658             :     JS_CGETSET_MAGIC_DEF("max_screen_views", jsf_filter_prop_get, jsf_filter_prop_set, JSF_FILTER_CAPS_MAX_VIEWS),
    1659             :     JS_CGETSET_MAGIC_DEF("max_audio_channels", jsf_filter_prop_get, jsf_filter_prop_set, JSF_FILTER_CAPS_MAX_CHANNELS),
    1660             :     JS_CGETSET_MAGIC_DEF("max_audio_samplerate", jsf_filter_prop_get, jsf_filter_prop_set, JSF_FILTER_CAPS_MAX_SAMPLERATE),
    1661             :     JS_CGETSET_MAGIC_DEF("max_audio_depth", jsf_filter_prop_get, jsf_filter_prop_set, JSF_FILTER_CAPS_MAX_AUDIO_DEPTH),
    1662             :     JS_CGETSET_MAGIC_DEF("events_queued", jsf_filter_prop_get, NULL, JSF_FILTER_NB_EVTS_QUEUED),
    1663             :     JS_CGETSET_MAGIC_DEF("clock_hint_us", jsf_filter_prop_get, NULL, JSF_FILTER_CLOCK_HINT_TIME),
    1664             :     JS_CGETSET_MAGIC_DEF("clock_hint_mediatime", jsf_filter_prop_get, NULL, JSF_FILTER_CLOCK_HINT_MEDIATIME),
    1665             :     JS_CGETSET_MAGIC_DEF("connections_pending", jsf_filter_prop_get, NULL, JSF_FILTER_CONNECTIONS_PENDING),
    1666             :         JS_CGETSET_MAGIC_DEF("iname", jsf_filter_prop_get, jsf_filter_prop_set, JSF_FILTER_INAME),
    1667             : 
    1668             : 
    1669             :     JS_CFUNC_DEF("set_desc", 0, jsf_filter_set_desc),
    1670             :     JS_CFUNC_DEF("set_version", 0, jsf_filter_set_version),
    1671             :     JS_CFUNC_DEF("set_author", 0, jsf_filter_set_author),
    1672             :     JS_CFUNC_DEF("set_help", 0, jsf_filter_set_help),
    1673             :     JS_CFUNC_DEF("set_arg", 0, jsf_filter_set_arg),
    1674             :     JS_CFUNC_DEF("set_cap", 0, jsf_filter_set_cap),
    1675             :     JS_CFUNC_DEF("set_name", 0, jsf_filter_set_name),
    1676             :     JS_CFUNC_DEF("new_pid", 0, jsf_filter_new_pid),
    1677             :     JS_CFUNC_DEF("send_event", 0, jsf_filter_send_event),
    1678             :     JS_CFUNC_DEF("get_info", 0, jsf_filter_get_info),
    1679             :     JS_CFUNC_DEF("is_supported_mime", 0, jsf_filter_is_supported_mime),
    1680             :     JS_CFUNC_DEF("update_status", 0, jsf_filter_update_status),
    1681             :     JS_CFUNC_DEF("reschedule", 0, jsf_filter_reschedule_in),
    1682             :     JS_CFUNC_DEF("post_task", 0, jsf_filter_post_task),
    1683             :     JS_CFUNC_DEF("notify_failure", 0, jsf_filter_notify_failure),
    1684             :     JS_CFUNC_DEF("is_supported_source", 0, jsf_filter_is_supported_source),
    1685             :     JS_CFUNC_DEF("hint_clock", 0, jsf_filter_hint_clock),
    1686             :     JS_CFUNC_DEF("send_update", 0, jsf_filter_send_update),
    1687             :     JS_CFUNC_DEF("add_source", 0, jsf_filter_add_source),
    1688             :     JS_CFUNC_DEF("add_destination", 0, jsf_filter_add_dest),
    1689             :     JS_CFUNC_DEF("add_filter", 0, jsf_filter_add_filter),
    1690             :     JS_CFUNC_DEF("make_sticky", 0, jsf_filter_make_sticky),
    1691             :         JS_CFUNC_DEF("prevent_blocking", 1, jsf_filter_prevent_blocking),
    1692             :         JS_CFUNC_DEF("block_eos", 1, jsf_filter_block_eos),
    1693             :     JS_CFUNC_DEF("abort", 0, jsf_filter_abort),
    1694             : };
    1695             : 
    1696             : 
    1697             : 
    1698           3 : static JSValue jsf_filter_set_source_internal(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, Bool use_restricted)
    1699             : {
    1700             :         GF_Err e=GF_OK;
    1701             :         const char *source_id=NULL;
    1702           3 :         GF_JSFilterInstanceCtx *f_inst = JS_GetOpaque(this_val, jsf_filter_inst_class_id);
    1703           3 :     if (!f_inst || (argc<1))  return JS_EXCEPTION;
    1704             : 
    1705           3 :         GF_JSFilterCtx *f_from = JS_GetOpaque(argv[0], jsf_filter_class_id);
    1706           3 :         GF_JSFilterInstanceCtx *fi_from = JS_GetOpaque(argv[0], jsf_filter_inst_class_id);
    1707           3 :     if (!f_from && !fi_from)  return JS_EXCEPTION;
    1708             : 
    1709             :     source_id = NULL;
    1710           3 :     if (argc>1) {
    1711             :         source_id = JS_ToCString(ctx, argv[2]);
    1712           0 :                 if (!source_id) return JS_EXCEPTION;
    1713             :         }
    1714             : 
    1715           3 :         if (use_restricted)
    1716           0 :                 e = gf_filter_set_source_restricted(f_inst->filter, fi_from ? fi_from->filter : f_from->filter, source_id);
    1717             :         else
    1718           3 :                 e = gf_filter_set_source(f_inst->filter, fi_from ? fi_from->filter : f_from->filter, source_id);
    1719             : 
    1720           3 :         JS_FreeCString(ctx, source_id);
    1721           3 :         if (e) return js_throw_err(ctx, e);
    1722           3 :         return JS_UNDEFINED;
    1723             : }
    1724             : 
    1725           3 : static JSValue jsf_filter_set_source(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    1726             : {
    1727           3 :         return jsf_filter_set_source_internal(ctx, this_val, argc, argv, GF_FALSE);
    1728             : }
    1729             : 
    1730           0 : static JSValue jsf_filter_set_source_restricted(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    1731             : {
    1732           0 :         return jsf_filter_set_source_internal(ctx, this_val, argc, argv, GF_TRUE);
    1733             : }
    1734             : 
    1735           2 : static JSValue jsf_filter_reset_source(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    1736             : {
    1737           2 :         GF_JSFilterInstanceCtx *jsfi = JS_GetOpaque(this_val, jsf_filter_inst_class_id);
    1738           2 :         if (!jsfi) return JS_EXCEPTION;
    1739           2 :         gf_filter_reset_source(jsfi->jsf->filter);
    1740           2 :         return JS_UNDEFINED;
    1741             : }
    1742             : 
    1743           1 : static JSValue jsf_filter_remove(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    1744             : {
    1745           1 :         GF_JSFilterInstanceCtx *jsfi = JS_GetOpaque(this_val, jsf_filter_inst_class_id);
    1746           1 :         if (!jsfi) return JS_EXCEPTION;
    1747           1 :         if (jsfi->fmode==JSF_FINST_SOURCE)
    1748           1 :                 gf_filter_remove_src(jsfi->jsf->filter, jsfi->filter);
    1749           1 :         return JS_UNDEFINED;
    1750             : }
    1751             : 
    1752             : 
    1753             : 
    1754         183 : static JSValue jsf_filter_has_pid_connections_pending(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    1755             : {
    1756             :         GF_Filter *stop_at = NULL;
    1757         183 :         GF_JSFilterInstanceCtx *jsfi = JS_GetOpaque(this_val, jsf_filter_inst_class_id);
    1758         183 :         if (!jsfi) return JS_EXCEPTION;
    1759         183 :         if (argc && (JS_IsNull(argv[0]) || JS_IsObject(argv[0]) ) )  {
    1760           0 :                 GF_JSFilterInstanceCtx *fi_stop = JS_GetOpaque(this_val, jsf_filter_inst_class_id);
    1761           0 :                 GF_JSFilterCtx *f_stop = JS_GetOpaque(this_val, jsf_filter_class_id);
    1762           0 :                 if (fi_stop) stop_at = fi_stop->filter;
    1763           0 :                 else if (f_stop) stop_at = f_stop->filter;
    1764         183 :         } else if (jsfi->fmode==JSF_FINST_SOURCE) {
    1765         183 :                 stop_at = jsfi->jsf->filter;
    1766             :         }
    1767         183 :         return JS_NewBool(ctx, gf_filter_has_pid_connection_pending(jsfi->filter, stop_at) );
    1768             : }
    1769             : 
    1770           0 : static void jsf_on_setup_error(GF_Filter *f, void *on_setup_error_udta, GF_Err e)
    1771             : {
    1772             :         GF_JSFilterInstanceCtx *f_inst = on_setup_error_udta;
    1773             :         JSValue ret, argv[1];
    1774           0 :         gf_js_lock(f_inst->jsf->ctx, GF_TRUE);
    1775             : 
    1776           0 :         argv[0] = JS_NewInt32(f_inst->jsf->ctx, e);
    1777             : 
    1778           0 :         ret = JS_Call(f_inst->jsf->ctx, f_inst->setup_failure_fun, f_inst->filter_obj, 0, NULL);
    1779             : 
    1780           0 :         JS_FreeValue(f_inst->jsf->ctx, argv[0]);
    1781           0 :         JS_FreeValue(f_inst->jsf->ctx, ret);
    1782           0 :         gf_js_lock(f_inst->jsf->ctx, GF_FALSE);
    1783           0 :         js_do_loop(f_inst->jsf->ctx);
    1784           0 : }
    1785             : 
    1786           2 : static JSValue jsf_filter_inst_prop_set(JSContext *ctx, JSValueConst this_val, JSValueConst value, int magic)
    1787             : {
    1788           2 :         GF_JSFilterInstanceCtx *f_inst = JS_GetOpaque(this_val, jsf_filter_inst_class_id);
    1789           2 :     if (!f_inst) return JS_EXCEPTION;
    1790             : 
    1791           2 :         if (magic==0) {
    1792           2 :                 if (JS_IsFunction(ctx, value) || JS_IsUndefined(value) || JS_IsNull(value)) {
    1793           6 :                         if (JS_IsUndefined(f_inst->setup_failure_fun) && !JS_IsUndefined(value)) {
    1794             : 
    1795           2 :                                 gf_filter_set_setup_failure_callback(f_inst->jsf->filter, f_inst->filter, jsf_on_setup_error, f_inst);
    1796             :                         }
    1797             :                         JS_FreeValue(ctx, f_inst->setup_failure_fun);
    1798           2 :                         f_inst->setup_failure_fun = JS_DupValue(ctx, value);
    1799             :                 }
    1800           2 :         return JS_UNDEFINED;
    1801             :         }
    1802           0 :         return JS_UNDEFINED;
    1803             : }
    1804             : 
    1805           2 : static JSValue jsf_filter_inst_get_arg(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    1806             : {
    1807             :         const char *arg_name=NULL;
    1808             :         JSValue res;
    1809           2 :         GF_JSFilterInstanceCtx *f_inst = JS_GetOpaque(this_val, jsf_filter_inst_class_id);
    1810           2 :     if (!f_inst || !argc) return JS_EXCEPTION;
    1811             :     arg_name = JS_ToCString(ctx, argv[0]);
    1812           2 :         if (!arg_name) return JS_EXCEPTION;
    1813           2 :         if ((argc>1) && JS_ToBool(ctx, argv[1])) {
    1814             :                 char dump[GF_PROP_DUMP_ARG_SIZE];
    1815           0 :                 const char *arg_val = gf_filter_get_arg_str(f_inst->filter, arg_name, dump);
    1816           0 :                 res = arg_val ? JS_NewString(ctx, dump) : JS_NULL;
    1817             :         } else {
    1818             :                 GF_PropertyValue p;
    1819           2 :                 if (gf_filter_get_arg(f_inst->filter, arg_name, &p))
    1820           2 :                         res = jsf_NewProp(ctx, &p);
    1821             :                 else
    1822           0 :                         res = JS_NULL;
    1823             :         }
    1824           2 :         JS_FreeCString(ctx, arg_name);
    1825           2 :         return res;
    1826             : }
    1827             : 
    1828             : 
    1829           2 : static JSValue jsf_filter_inst_disable_probe(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    1830             : {
    1831           2 :         GF_JSFilterInstanceCtx *jsfi = JS_GetOpaque(this_val, jsf_filter_inst_class_id);
    1832           2 :     if (!jsfi) return JS_EXCEPTION;
    1833           2 :         gf_filter_disable_probe(jsfi->filter);
    1834           2 :         return JS_UNDEFINED;
    1835             : }
    1836           2 : static JSValue jsf_filter_inst_disable_inputs(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    1837             : {
    1838           2 :         GF_JSFilterInstanceCtx *jsfi = JS_GetOpaque(this_val, jsf_filter_inst_class_id);
    1839           2 :     if (!jsfi) return JS_EXCEPTION;
    1840           2 :     gf_filter_disable_inputs(jsfi->filter);
    1841           2 :         return JS_UNDEFINED;
    1842             : }
    1843             : 
    1844             : static const JSCFunctionListEntry jsf_filter_inst_funcs[] = {
    1845             :     JS_CGETSET_MAGIC_DEF("on_setup_failure", NULL, jsf_filter_inst_prop_set, 0),
    1846             :     JS_CFUNC_DEF("send_event", 0, jsf_filter_send_event),
    1847             :     JS_CFUNC_DEF("get_info", 0, jsf_filter_get_info),
    1848             :     JS_CFUNC_DEF("send_update", 0, jsf_filter_send_update),
    1849             :     JS_CFUNC_DEF("set_source", 0, jsf_filter_set_source),
    1850             :     JS_CFUNC_DEF("set_source_restricted", 0, jsf_filter_set_source_restricted),
    1851             :     JS_CFUNC_DEF("remove", 0, jsf_filter_remove),
    1852             :     JS_CFUNC_DEF("has_pid_connections_pending", 0, jsf_filter_has_pid_connections_pending),
    1853             :     JS_CFUNC_DEF("get_arg", 0, jsf_filter_inst_get_arg),
    1854             :     JS_CFUNC_DEF("disable_probe", 0, jsf_filter_inst_disable_probe),
    1855             :     JS_CFUNC_DEF("disable_inputs", 0, jsf_filter_inst_disable_inputs),
    1856             :     JS_CFUNC_DEF("reset_source", 0, jsf_filter_reset_source),
    1857             : };
    1858             : 
    1859             : 
    1860          39 : static JSValue jsf_pid_set_prop(JSContext *ctx, JSValueConst this_val, JSValueConst value, int magic)
    1861             : {
    1862             :         u32 ival;
    1863             :         GF_Err e = GF_OK;
    1864             :         const char *str=NULL;
    1865          39 :         GF_JSPidCtx *pctx = JS_GetOpaque(this_val, jsf_pid_class_id);
    1866          39 :     if (!pctx) return JS_EXCEPTION;
    1867          39 :         switch (magic) {
    1868          11 :         case JSF_PID_NAME:
    1869             :                 str = JS_ToCString(ctx, value);
    1870          11 :                 gf_filter_pid_set_name(pctx->pid, str);
    1871             :         break;
    1872          25 :         case JSF_PID_EOS:
    1873          25 :                 if (JS_ToBool(ctx, value))
    1874          25 :                         gf_filter_pid_set_eos(pctx->pid);
    1875             :         break;
    1876           1 :         case JSF_PID_MAX_BUFFER:
    1877           1 :                 if (JS_ToInt32(ctx, &ival, value))
    1878           0 :                         return JS_EXCEPTION;
    1879           1 :                 gf_filter_pid_set_max_buffer(pctx->pid, ival);
    1880             :         break;
    1881           1 :         case JSF_PID_LOOSE_CONNECT:
    1882           1 :                 if (JS_ToBool(ctx, value))
    1883           1 :                         gf_filter_pid_set_loose_connect(pctx->pid);
    1884             :         break;
    1885           0 :         case JSF_PID_FRAMING_MODE:
    1886           0 :                 gf_filter_pid_set_framing_mode(pctx->pid, JS_ToBool(ctx, value) );
    1887             :         break;
    1888           0 :         case JSF_PID_CLOCK_MODE:
    1889           0 :                 gf_filter_pid_set_clock_mode(pctx->pid, JS_ToBool(ctx, value) );
    1890             :                 break;
    1891           1 :         case JSF_PID_DISCARD:
    1892           1 :                 gf_filter_pid_set_discard(pctx->pid, JS_ToBool(ctx, value) );
    1893             :                 break;
    1894           0 :         case JSF_PID_REQUIRE_SOURCEID:
    1895           0 :                 if (JS_ToBool(ctx, value))
    1896           0 :                         gf_filter_pid_require_source_id(pctx->pid);
    1897             :                 break;
    1898           0 :         case JSF_PID_RECOMPUTE_DTS:
    1899           0 :                 gf_filter_pid_recompute_dts(pctx->pid, JS_ToBool(ctx, value));
    1900             :                 break;
    1901             :         }
    1902             : 
    1903          11 :         if (str)
    1904          11 :                 JS_FreeCString(ctx, str);
    1905             :         if (e) return js_throw_err(ctx, e);
    1906          39 :     return JS_UNDEFINED;
    1907             : }
    1908             : 
    1909        1063 : static JSValue jsf_pid_get_prop(JSContext *ctx, JSValueConst this_val, int magic)
    1910             : {
    1911             :         u64 dur;
    1912             :         char *str;
    1913        1063 :         GF_JSPidCtx *pctx = JS_GetOpaque(this_val, jsf_pid_class_id);
    1914        1063 :     if (!pctx) return JS_EXCEPTION;
    1915        1063 :         switch (magic) {
    1916         524 :         case JSF_PID_NAME:
    1917         524 :                 return JS_NewString(ctx, gf_filter_pid_get_name(pctx->pid) );
    1918         531 :         case JSF_PID_EOS:
    1919         531 :                 return JS_NewBool (ctx, gf_filter_pid_is_eos(pctx->pid) );
    1920           0 :         case JSF_PID_EOS_SEEN:
    1921           0 :                 return JS_NewBool (ctx, gf_filter_pid_has_seen_eos(pctx->pid) );
    1922           0 :         case JSF_PID_EOS_RECEIVED:
    1923           0 :                 return JS_NewBool (ctx, gf_filter_pid_eos_received(pctx->pid) );
    1924           0 :         case JSF_PID_WOULD_BLOCK:
    1925           0 :                 return JS_NewBool(ctx, gf_filter_pid_would_block(pctx->pid) );
    1926           2 :         case JSF_PID_FILTER_NAME:
    1927           2 :                 return JS_NewString(ctx, gf_filter_pid_get_filter_name(pctx->pid) );
    1928           2 :         case JSF_PID_FILTER_SRC:
    1929           2 :                 return JS_NewString(ctx, gf_filter_pid_get_source_filter_name(pctx->pid) );
    1930           2 :         case JSF_PID_FILTER_ARGS:
    1931           2 :                 return JS_NewString(ctx, gf_filter_pid_get_args(pctx->pid) );
    1932           2 :         case JSF_PID_FILTER_SRC_ARGS:
    1933           2 :                 return JS_NewString(ctx, gf_filter_pid_orig_src_args(pctx->pid, GF_FALSE) );
    1934           0 :         case JSF_PID_FILTER_UNICITY_ARGS:
    1935           0 :                 return JS_NewString(ctx, gf_filter_pid_orig_src_args(pctx->pid, GF_TRUE) );
    1936           0 :         case JSF_PID_MAX_BUFFER:
    1937           0 :                 return JS_NewInt32(ctx, gf_filter_pid_get_max_buffer(pctx->pid) );
    1938           0 :         case JSF_PID_BUFFER:
    1939           0 :                 return JS_NewInt64(ctx, gf_filter_pid_query_buffer_duration(pctx->pid, GF_FALSE) );
    1940           0 :         case JSF_PID_IS_FULL:
    1941           0 :                 dur = gf_filter_pid_query_buffer_duration(pctx->pid, GF_TRUE);
    1942           0 :                 return JS_NewBool(ctx, !dur ? 0 : 1);
    1943           0 :         case JSF_PID_FIRST_EMPTY:
    1944           0 :                 return JS_NewBool (ctx, gf_filter_pid_first_packet_is_empty(pctx->pid) );
    1945           0 :         case JSF_PID_FIRST_CTS:
    1946           0 :                 if (gf_filter_pid_get_first_packet_cts(pctx->pid, &dur))
    1947           0 :                         return JS_NewInt64(ctx, dur);
    1948             :                 else
    1949           0 :                         return JS_NULL;
    1950           0 :         case JSF_PID_NB_PACKETS:
    1951           0 :                 return JS_NewInt32(ctx, gf_filter_pid_get_packet_count(pctx->pid) );
    1952           0 :         case JSF_PID_TIMESCALE:
    1953           0 :                 return JS_NewInt32(ctx, gf_filter_pid_get_timescale(pctx->pid) );
    1954           0 :         case JSF_PID_SRC_URL:
    1955           0 :                 str = gf_filter_pid_get_source(pctx->pid);
    1956           0 :                 if (str) {
    1957           0 :                         JSValue res = JS_NewString(ctx, str);
    1958           0 :                         gf_free(str);
    1959           0 :                         return res;
    1960             :                 }
    1961           0 :                 return JS_NULL;
    1962           0 :         case JSF_PID_DST_URL:
    1963           0 :                 str = gf_filter_pid_get_destination(pctx->pid);
    1964           0 :                 if (str) {
    1965           0 :                         JSValue res = JS_NewString(ctx, str);
    1966           0 :                         gf_free(str);
    1967           0 :                         return res;
    1968             :                 }
    1969           0 :                 return JS_NULL;
    1970           0 :         case JSF_PID_MIN_PCK_DUR:
    1971           0 :                 return JS_NewInt32(ctx, gf_filter_pid_get_min_pck_duration(pctx->pid) );
    1972           0 :         case JSF_PID_IS_PLAYING:
    1973           0 :                 return JS_NewBool(ctx, gf_filter_pid_is_playing(pctx->pid) );
    1974             :         }
    1975           0 :     return JS_UNDEFINED;
    1976             : }
    1977             : 
    1978           5 : static JSValue jsf_pid_send_event(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    1979             : {
    1980           5 :         GF_JSPidCtx *pctx = JS_GetOpaque(this_val, jsf_pid_class_id);
    1981           5 :     if (!pctx) return JS_EXCEPTION;
    1982           5 :         GF_FilterEvent *evt = JS_GetOpaque(argv[0], jsf_event_class_id);
    1983           5 :     if (!evt) return JS_EXCEPTION;
    1984           5 :     evt->base.on_pid = pctx->pid;
    1985           5 :     if (evt->base.type == GF_FEVT_PLAY) {
    1986           5 :                 gf_filter_pid_init_play_event(pctx->pid, evt, evt->play.start_range, evt->play.speed, pctx->jsf->log_name);
    1987             :         }
    1988           5 :         gf_filter_pid_send_event(pctx->pid, evt);
    1989           5 :     return JS_UNDEFINED;
    1990             : }
    1991             : 
    1992          34 : static JSValue jsf_pid_enum_properties(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    1993             : {
    1994             :         s32 idx;
    1995             :         u32 p4cc;
    1996             :         const char *pname;
    1997             :         JSValue res;
    1998             :         const GF_PropertyValue *prop;
    1999          34 :         GF_JSPidCtx *pctx = JS_GetOpaque(this_val, jsf_pid_class_id);
    2000          34 :     if (!pctx) return JS_EXCEPTION;
    2001          34 :     if (JS_ToInt32(ctx, &idx, argv[0]))
    2002           0 :                 return JS_EXCEPTION;
    2003             : 
    2004          34 :         if ((argc>1) && JS_ToBool(ctx, argv[1])) {
    2005           0 :                 prop = gf_filter_pid_enum_info(pctx->pid, &idx, &p4cc, &pname);
    2006             :         } else {
    2007          34 :                 prop = gf_filter_pid_enum_properties(pctx->pid, &idx, &p4cc, &pname);
    2008             :         }
    2009          34 :         if (!prop) return JS_NULL;
    2010          32 :         if (!pname) pname = gf_props_4cc_get_name(p4cc);
    2011          32 :         if (!pname) return JS_EXCEPTION;
    2012             : 
    2013          32 :         res = JS_NewObject(ctx);
    2014          32 :     JS_SetPropertyStr(ctx, res, "name", JS_NewString(ctx, pname));
    2015          64 :     JS_SetPropertyStr(ctx, res, "type", JS_NewInt32(ctx, prop->type));
    2016          32 :     JS_SetPropertyStr(ctx, res, "value", jsf_NewProp(ctx, prop));
    2017          32 :     return res;
    2018             : }
    2019             : 
    2020          27 : static JSValue jsf_pid_get_property_ex(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, Bool is_info)
    2021             : {
    2022             :         JSValue res;
    2023             :         const char *name=NULL;
    2024             :         const GF_PropertyValue *prop;
    2025          27 :         GF_PropertyEntry *pe = NULL;
    2026          27 :         GF_JSPidCtx *pctx = JS_GetOpaque(this_val, jsf_pid_class_id);
    2027          27 :     if (!pctx) return JS_EXCEPTION;
    2028             :     name = JS_ToCString(ctx, argv[0]);
    2029          27 :         if (!name) return JS_EXCEPTION;
    2030          27 :         if ((argc>1) && JS_ToBool(ctx, argv[1])) {
    2031           0 :                 if (is_info) {
    2032           0 :                         prop = gf_filter_pid_get_info_str(pctx->pid, name, &pe);
    2033             :                 } else {
    2034           0 :                         prop = gf_filter_pid_get_property_str(pctx->pid, name);
    2035             :                 }
    2036           0 :                 JS_FreeCString(ctx, name);
    2037           0 :                 if (!prop) return JS_NULL;
    2038           0 :                 res = jsf_NewProp(ctx, prop);
    2039           0 :                 JS_SetPropertyStr(ctx, res, "type", JS_NewInt32(ctx, prop->type));
    2040             :         } else {
    2041          27 :                 u32 p4cc = gf_props_get_id(name);
    2042          27 :                 JS_FreeCString(ctx, name);
    2043          27 :                 if (!p4cc) return JS_EXCEPTION;
    2044          27 :                 if (is_info) {
    2045           1 :                         prop = gf_filter_pid_get_info(pctx->pid, p4cc, &pe);
    2046             :                 } else {
    2047          26 :                         prop = gf_filter_pid_get_property(pctx->pid, p4cc);
    2048             :                 }
    2049          27 :                 if (!prop) return JS_NULL;
    2050          27 :                 res = jsf_NewPropTranslate(ctx, prop, p4cc);
    2051             :         }
    2052          27 :         gf_filter_release_property(pe);
    2053          27 :     return res;
    2054             : }
    2055          26 : static JSValue jsf_pid_get_property(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    2056             : {
    2057          26 :         return jsf_pid_get_property_ex(ctx, this_val, argc, argv, GF_FALSE);
    2058             : }
    2059           1 : static JSValue jsf_pid_get_info(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    2060             : {
    2061           1 :         return jsf_pid_get_property_ex(ctx, this_val, argc, argv, GF_TRUE);
    2062             : }
    2063             : 
    2064             : 
    2065        2619 : static JSValue jsf_pid_get_packet(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    2066             : {
    2067             :         JSValue res;
    2068             :         GF_FilterPacket *pck;
    2069             :         GF_JSPckCtx *pckctx;
    2070        2619 :         GF_JSPidCtx *pctx = JS_GetOpaque(this_val, jsf_pid_class_id);
    2071        2619 :     if (!pctx) return JS_EXCEPTION;
    2072        2619 :         if (!pctx->jsf->filter->in_process)
    2073           0 :                 return js_throw_err_msg(ctx, GF_BAD_PARAM, "Filter %s attempt to query packet outside process callback not allowed!\n", pctx->jsf->filter->name);
    2074             :                 
    2075        2619 :     pck = gf_filter_pid_get_packet(pctx->pid);
    2076        2619 :         if (!pck) return JS_NULL;
    2077             : 
    2078        1407 :         if (pctx->pck_head) {
    2079             :                 pckctx = pctx->pck_head;
    2080             :                 assert(pckctx->pck == pck);
    2081             :                 return JS_DupValue(ctx, pckctx->jsobj);
    2082             :         }
    2083             : 
    2084        1407 :         res = JS_NewObjectClass(ctx, jsf_pck_class_id);
    2085        1407 :         pckctx = gf_list_pop_back(pctx->jsf->pck_res);
    2086        1407 :         if (!pckctx) {
    2087           9 :                 GF_SAFEALLOC(pckctx, GF_JSPckCtx);
    2088           9 :                 if (!pckctx) return js_throw_err(ctx, GF_OUT_OF_MEM);
    2089             :         }
    2090             :         memset(pckctx, 0, sizeof(GF_JSPckCtx));
    2091        1407 :         pckctx->jspid = pctx;
    2092        1407 :         pckctx->pck = pck;
    2093        1407 :         pckctx->jsobj = JS_DupValue(ctx, res);
    2094        1407 :         pckctx->ref_val = JS_UNDEFINED;
    2095        1407 :         pckctx->data_ab = JS_UNDEFINED;
    2096        1407 :         pctx->pck_head = pckctx;
    2097             : 
    2098        1407 :         JS_SetOpaque(res, pckctx);
    2099        1407 :     return res;
    2100             : }
    2101        1407 : static JSValue jsf_pid_drop_packet(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    2102             : {
    2103             :         GF_JSPckCtx *pckctx;
    2104        1407 :         GF_JSPidCtx *pctx = JS_GetOpaque(this_val, jsf_pid_class_id);
    2105        1407 :     if (!pctx) return JS_EXCEPTION;
    2106        1407 :         if (!pctx->jsf->filter->in_process)
    2107           0 :                 return js_throw_err_msg(ctx, GF_BAD_PARAM, "Filter %s attempt to drop packet outside process callback not allowed!\n", pctx->jsf->filter->name);
    2108             : 
    2109        1407 :         if (!pctx->pck_head) {
    2110           0 :                 if (gf_filter_pid_get_packet_count(pctx->pid)) {
    2111           0 :                 gf_filter_pid_drop_packet(pctx->pid);
    2112             :                 }
    2113           0 :                 return JS_UNDEFINED;
    2114             :         }
    2115             : 
    2116             :         pckctx = pctx->pck_head;
    2117        1407 :         pckctx->pck = NULL;
    2118        1407 :         pctx->pck_head = NULL;
    2119             :         JS_FreeValue(ctx, pckctx->jsobj);
    2120        1407 :         pckctx->jsobj = JS_UNDEFINED;
    2121        1407 :     gf_filter_pid_drop_packet(pctx->pid);
    2122        1407 :     return JS_UNDEFINED;
    2123             : }
    2124             : 
    2125           2 : static JSValue jsf_pid_is_filter_in_parents(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    2126             : {
    2127           2 :         GF_JSPidCtx *pctx = JS_GetOpaque(this_val, jsf_pid_class_id);
    2128           2 :     if (!pctx || !argc) return JS_EXCEPTION;
    2129           2 :         GF_JSFilterCtx *f_ctx = JS_GetOpaque(argv[0], jsf_filter_class_id);
    2130           2 :         GF_JSFilterInstanceCtx *fi_ctx = JS_GetOpaque(argv[0], jsf_filter_inst_class_id);
    2131           2 :     if (!f_ctx && !fi_ctx) return JS_EXCEPTION;
    2132           2 :         return JS_NewBool(ctx, gf_filter_pid_is_filter_in_parents(pctx->pid, f_ctx ? f_ctx->filter : fi_ctx->filter));
    2133             : }
    2134             : 
    2135           2 : static JSValue jsf_pid_get_buffer_occupancy(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    2136             : {
    2137             :         JSValue res;
    2138             :         Bool in_final_flush;
    2139             :         u32 max_units, nb_pck, max_dur, dur;
    2140           2 :         GF_JSPidCtx *pctx = JS_GetOpaque(this_val, jsf_pid_class_id);
    2141           2 :     if (!pctx) return JS_EXCEPTION;
    2142             : 
    2143           2 :         in_final_flush = !gf_filter_pid_get_buffer_occupancy(pctx->pid, &max_units, &nb_pck, &max_dur, &dur);
    2144           2 :         res = JS_NewObject(ctx);
    2145           4 :     JS_SetPropertyStr(ctx, res, "max_units", JS_NewInt32(ctx, max_units));
    2146           4 :     JS_SetPropertyStr(ctx, res, "nb_pck", JS_NewInt32(ctx, nb_pck));
    2147           4 :     JS_SetPropertyStr(ctx, res, "max_dur", JS_NewInt32(ctx, max_dur));
    2148           4 :     JS_SetPropertyStr(ctx, res, "dur", JS_NewInt32(ctx, dur));
    2149           4 :     JS_SetPropertyStr(ctx, res, "final_flush", JS_NewBool(ctx, in_final_flush));
    2150           2 :     return res;
    2151             : }
    2152           2 : static JSValue jsf_pid_clear_eos(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    2153             : {
    2154           2 :         GF_JSPidCtx *pctx = JS_GetOpaque(this_val, jsf_pid_class_id);
    2155           2 :     if (!pctx || !argc) return JS_EXCEPTION;
    2156           2 :         gf_filter_pid_clear_eos(pctx->pid, JS_ToBool(ctx, argv[0]));
    2157           2 :         return JS_UNDEFINED;
    2158             : }
    2159           2 : static JSValue jsf_pid_check_caps(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    2160             : {
    2161           2 :         GF_JSPidCtx *pctx = JS_GetOpaque(this_val, jsf_pid_class_id);
    2162           2 :     if (!pctx) return JS_EXCEPTION;
    2163           2 :         return JS_NewBool(ctx, gf_filter_pid_check_caps(pctx->pid));
    2164             : }
    2165           2 : static JSValue jsf_pid_discard_block(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    2166             : {
    2167           2 :         GF_JSPidCtx *pctx = JS_GetOpaque(this_val, jsf_pid_class_id);
    2168           2 :     if (!pctx) return JS_EXCEPTION;
    2169           2 :     gf_filter_pid_discard_block(pctx->pid);
    2170           2 :         return JS_UNDEFINED;
    2171             : }
    2172           1 : static JSValue jsf_pid_allow_direct_dispatch(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    2173             : {
    2174           1 :         GF_JSPidCtx *pctx = JS_GetOpaque(this_val, jsf_pid_class_id);
    2175           1 :     if (!pctx) return JS_EXCEPTION;
    2176           1 :     gf_filter_pid_allow_direct_dispatch(pctx->pid);
    2177           1 :         return JS_UNDEFINED;
    2178             : }
    2179           1 : static JSValue jsf_pid_resolve_file_template(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    2180             : {
    2181           1 :         u32 fileidx=0;
    2182             :         GF_Err e;
    2183             :         char szFinal[GF_MAX_PATH];
    2184             :         const char *templ, *suffix=NULL;
    2185           1 :         GF_JSPidCtx *pctx = JS_GetOpaque(this_val, jsf_pid_class_id);
    2186           1 :     if (!pctx || !argc) return JS_EXCEPTION;
    2187             : 
    2188             :         templ = JS_ToCString(ctx, argv[0]);
    2189           1 :         if (!templ)
    2190           0 :         return JS_EXCEPTION;
    2191             : 
    2192           1 :         if ((argc>=2) && JS_ToInt32(ctx, &fileidx, argv[1])) {
    2193           0 :                 JS_FreeCString(ctx, templ);
    2194           0 :         return JS_EXCEPTION;
    2195             :         }
    2196             : 
    2197           1 :         if (argc==3)
    2198             :                 suffix = JS_ToCString(ctx, argv[2]);
    2199             : 
    2200           1 :         e = gf_filter_pid_resolve_file_template(pctx->pid, (char *)templ, szFinal, fileidx, suffix);
    2201           1 :         JS_FreeCString(ctx, templ);
    2202             : 
    2203           1 :         if (e)
    2204           0 :         return js_throw_err(ctx, e);
    2205           1 :         return JS_NewString(ctx, szFinal);
    2206             : }
    2207             : 
    2208           2 : static JSValue jsf_pid_query_caps(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    2209             : {
    2210             :         const char *name=NULL;
    2211             :         const GF_PropertyValue *prop;
    2212           2 :         GF_JSPidCtx *pctx = JS_GetOpaque(this_val, jsf_pid_class_id);
    2213           2 :     if (!pctx || !argc) return JS_EXCEPTION;
    2214             : 
    2215             :         name = JS_ToCString(ctx, argv[0]);
    2216           2 :         if (!name) return JS_EXCEPTION;
    2217             : 
    2218           2 :         if ((argc>1) && JS_ToBool(ctx, argv[1])) {
    2219             :                 JSValue res;
    2220           1 :                 prop = gf_filter_pid_caps_query_str(pctx->pid, name);
    2221           1 :                 JS_FreeCString(ctx, name);
    2222           1 :                 if (!prop) return JS_NULL;
    2223           0 :                 res = jsf_NewProp(ctx, prop);
    2224           0 :                 JS_SetPropertyStr(ctx, res, "type", JS_NewInt32(ctx, prop->type));
    2225             :         } else {
    2226           1 :                 u32 p4cc = gf_props_get_id(name);
    2227           1 :                 JS_FreeCString(ctx, name);
    2228           1 :                 if (!p4cc)
    2229           0 :                         return js_throw_err(ctx, GF_BAD_PARAM);
    2230             : 
    2231           1 :                 prop = gf_filter_pid_caps_query(pctx->pid, p4cc);
    2232           1 :                 if (!prop) return JS_NULL;
    2233           0 :                 return jsf_NewPropTranslate(ctx, prop, p4cc);
    2234             :         }
    2235           0 :         return JS_UNDEFINED;
    2236             : }
    2237             : 
    2238           2 : static JSValue jsf_pid_get_statistics(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    2239             : {
    2240             :         JSValue res;
    2241             :         u32 mode;
    2242             :         GF_Err e;
    2243             :         GF_FilterPidStatistics stats;
    2244           2 :         GF_JSPidCtx *pctx = JS_GetOpaque(this_val, jsf_pid_class_id);
    2245           2 :     if (!pctx || !argc) return JS_EXCEPTION;
    2246           2 :         if (JS_ToInt32(ctx, &mode, argv[0]))
    2247           0 :                 return JS_EXCEPTION;
    2248             : 
    2249           2 :         e = gf_filter_pid_get_statistics(pctx->pid, &stats, mode);
    2250           2 :         if (e)
    2251           0 :         return js_throw_err(ctx, e);
    2252             : 
    2253           2 :         res = JS_NewObject(ctx);
    2254             : #define SET_PROP32(_val)\
    2255             :     JS_SetPropertyStr(ctx, res, #_val, JS_NewInt32(ctx, stats._val));
    2256             : #define SET_PROP64(_val)\
    2257             :     JS_SetPropertyStr(ctx, res, #_val, JS_NewInt64(ctx, stats._val));
    2258             : #define SET_PROPB(_val)\
    2259             :     JS_SetPropertyStr(ctx, res, #_val, JS_NewBool(ctx, stats._val));
    2260             : 
    2261           4 :         SET_PROPB(disconnected)
    2262           4 :         SET_PROP32(average_process_rate)
    2263           4 :         SET_PROP32(max_process_rate)
    2264           4 :         SET_PROP32(avgerage_bitrate)
    2265           4 :         SET_PROP32(max_bitrate)
    2266           4 :         SET_PROP32(nb_processed)
    2267           4 :         SET_PROP32(max_process_time)
    2268           4 :         SET_PROP64(total_process_time)
    2269           4 :         SET_PROP64(first_process_time)
    2270           4 :         SET_PROP64(last_process_time)
    2271           4 :         SET_PROP32(min_frame_dur)
    2272           4 :         SET_PROP32(nb_saps)
    2273           4 :         SET_PROP32(max_sap_process_time)
    2274           4 :         SET_PROP64(total_sap_process_time)
    2275           4 :         SET_PROP64(max_buffer_time)
    2276           4 :         SET_PROP64(max_playout_time)
    2277           4 :         SET_PROP64(min_playout_time)
    2278           4 :         SET_PROP64(buffer_time)
    2279           4 :         SET_PROP32(nb_buffer_units)
    2280           2 :     return res;
    2281             : }
    2282             : 
    2283          98 : void jsf_pck_shared_del(GF_Filter *filter, GF_FilterPid *PID, GF_FilterPacket *pck)
    2284             : {
    2285             :         u32 i, count;
    2286          98 :         GF_JSPidCtx *pctx = gf_filter_pid_get_udta(PID);
    2287          98 :         count = gf_list_count(pctx->shared_pck);
    2288          98 :         for (i=0; i<count; i++) {
    2289          98 :                 GF_JSPckCtx *pckc = gf_list_get(pctx->shared_pck, i);
    2290          98 :                 if (pckc->pck == pck) {
    2291         196 :                         if (!JS_IsUndefined(pckc->cbck_val)) {
    2292           0 :                                 JSValue res = JS_Call(pctx->jsf->ctx, pckc->cbck_val, pctx->jsobj, 0, NULL);
    2293           0 :                                 JS_FreeValue(pctx->jsf->ctx, res);
    2294           0 :                                 JS_FreeValue(pctx->jsf->ctx, pckc->cbck_val);
    2295           0 :                                 pckc->cbck_val = JS_UNDEFINED;
    2296             :                         }
    2297          98 :                         JS_FreeValue(pctx->jsf->ctx, pckc->ref_val);
    2298          98 :                         pckc->ref_val = JS_UNDEFINED;
    2299          98 :                         jsf_pck_detach_ab(pctx->jsf->ctx, pckc);
    2300             :                         memset(pckc, 0, sizeof(GF_JSPckCtx));
    2301          98 :                         gf_list_add(pctx->jsf->pck_res, pckc);
    2302          98 :                         gf_list_rem(pctx->shared_pck, i);
    2303          98 :                         return;
    2304             :                 }
    2305             :         }
    2306             : }
    2307             : 
    2308             : 
    2309             : #if !defined(GPAC_DISABLE_3D) && !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES1X)
    2310             : JSValue webgl_get_frame_interface(JSContext *ctx, int argc, JSValueConst *argv, gf_fsess_packet_destructor *pck_del, GF_FilterFrameInterface **f_ifce);
    2311             : #endif
    2312             : 
    2313        1307 : static JSValue jsf_pid_new_packet(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    2314             : {
    2315             :         size_t ab_size;
    2316             :         u8 *data, *ab_data;
    2317             :         JSValue obj;
    2318             :         Bool use_shared=GF_FALSE;
    2319             :         GF_JSPckCtx *pckc;
    2320        1307 :         GF_JSPidCtx *pctx = JS_GetOpaque(this_val, jsf_pid_class_id);
    2321             : 
    2322        1307 :     if (!pctx) return JS_EXCEPTION;
    2323        1307 :         if (!pctx->jsf->filter->in_process)
    2324           0 :                 return js_throw_err_msg(ctx, GF_BAD_PARAM, "Filter %s attempt to create a new packet outside process callback not allowed!\n", pctx->jsf->filter->name);
    2325             : 
    2326             : 
    2327        1307 :         pckc = gf_list_pop_back(pctx->jsf->pck_res);
    2328        1307 :         if (!pckc) {
    2329          25 :                 GF_SAFEALLOC(pckc, GF_JSPckCtx);
    2330          25 :                 if (!pckc)
    2331           0 :                         return js_throw_err(ctx, GF_OUT_OF_MEM);
    2332             :         }
    2333        1307 :         obj = JS_NewObjectClass(ctx, jsf_pck_class_id);
    2334        1307 :     if (JS_IsException(obj)) {
    2335           0 :         gf_list_add(pctx->jsf->pck_res, pckc);
    2336           0 :                 return JS_EXCEPTION;
    2337             :         }
    2338        1307 :         JS_SetOpaque(obj, pckc);
    2339        1307 :         pckc->jspid = pctx;
    2340        1307 :         pckc->jsobj = obj;
    2341        1307 :         pckc->cbck_val = JS_UNDEFINED;
    2342        1307 :         pckc->ref_val = JS_UNDEFINED;
    2343        1307 :         pckc->data_ab = JS_UNDEFINED;
    2344             : 
    2345        1307 :         if (argc>1)
    2346         980 :                 use_shared = JS_ToBool(ctx, argv[1]);
    2347             : 
    2348        1307 :         if (!argc) {
    2349           0 :                 pckc->pck = gf_filter_pck_new_alloc(pctx->pid, 0, NULL);
    2350           0 :                 goto pck_done;
    2351             :         }
    2352             :         /*string or true alloc*/
    2353        2614 :         if (JS_IsString(argv[0]) || JS_IsInteger(argv[0]) ) {
    2354             :                 u32 len;
    2355             :                 const char *str = NULL;
    2356         425 :                 if (JS_IsInteger(argv[0]) ) {
    2357         225 :                         if (use_shared)
    2358           0 :                                 return js_throw_err(ctx, GF_BAD_PARAM);
    2359         225 :                         if (JS_ToInt32(ctx, &len, argv[0])) {
    2360           0 :                         gf_list_add(pctx->jsf->pck_res, pckc);
    2361           0 :                                 return JS_EXCEPTION;
    2362             :                         }
    2363             :                 } else {
    2364             :                         str = JS_ToCString(ctx, argv[0]);
    2365         200 :                         len = (u32) strlen(str);
    2366             :                 }
    2367         425 :                 if (use_shared) {
    2368          98 :                         pckc->pck = gf_filter_pck_new_shared(pctx->pid, str, len, jsf_pck_shared_del);
    2369          98 :                         pckc->ref_val = JS_DupValue(ctx, argv[0]);
    2370          98 :                         JS_FreeCString(ctx, str);
    2371          98 :                         if (!pctx->shared_pck) pctx->shared_pck = gf_list_new();
    2372          98 :                         gf_list_add(pctx->shared_pck, pckc);
    2373          98 :                         pckc->flags = GF_JS_PCK_IS_SHARED;
    2374          98 :                         if ((argc>2) && JS_IsFunction(ctx, argv[2]))
    2375           0 :                                 pckc->cbck_val = JS_DupValue(ctx, argv[2]);
    2376             :                 } else {
    2377         327 :                         u8 *pdata=NULL;
    2378         327 :                         pckc->pck = gf_filter_pck_new_alloc(pctx->pid, len, &pdata);
    2379         327 :                         if (str) {
    2380         102 :                                 memcpy(pdata, str, len);
    2381         102 :                                 JS_FreeCString(ctx, str);
    2382             :                         }
    2383             :                 }
    2384         425 :                 goto pck_done;
    2385             :         }
    2386             :         //check packet reference
    2387         882 :         GF_JSPckCtx *pckc_ref = JS_GetOpaque(argv[0], jsf_pck_class_id);
    2388         882 :         if (pckc_ref) {
    2389         277 :                 if (use_shared) {
    2390          75 :                         pckc->pck = gf_filter_pck_new_ref(pctx->pid, 0, 0, pckc_ref->pck);
    2391          75 :                         if ((argc>2) && JS_IsFunction(ctx, argv[2]))
    2392           0 :                                 pckc->cbck_val = JS_DupValue(ctx, argv[2]);
    2393             :                 } else {
    2394             :                         u8 *new_data;
    2395         202 :                         if ((argc>2) && JS_ToBool(ctx, argv[2])) {
    2396           0 :                                 pckc->pck = gf_filter_pck_new_copy(pctx->pid, pckc_ref->pck, &new_data);
    2397             :                         } else {
    2398         202 :                                 pckc->pck = gf_filter_pck_new_clone(pctx->pid, pckc_ref->pck, &new_data);
    2399             :                         }
    2400             :                 }
    2401             :                 goto pck_done;
    2402             :         }
    2403             :         //check array buffer
    2404             : 
    2405        1210 :         if (!JS_IsObject(argv[0])) {
    2406             :                 JS_FreeValue(ctx, obj);
    2407           0 :                 return JS_EXCEPTION;
    2408             :         }
    2409         605 :         ab_data = JS_GetArrayBuffer(ctx, &ab_size, argv[0]);
    2410             :         //this is an array buffer
    2411         605 :         if (ab_data) {
    2412           0 :                 if (use_shared) {
    2413           0 :                         pckc->pck = gf_filter_pck_new_shared(pctx->pid, ab_data, (u32) ab_size, jsf_pck_shared_del);
    2414           0 :                         pckc->ref_val = JS_DupValue(ctx, argv[0]);
    2415           0 :                         if (!pctx->shared_pck) pctx->shared_pck = gf_list_new();
    2416           0 :                         gf_list_add(pctx->shared_pck, pckc);
    2417           0 :                         pckc->flags = GF_JS_PCK_IS_SHARED;
    2418           0 :                         if ((argc>2) && JS_IsFunction(ctx, argv[2]))
    2419           0 :                                 pckc->cbck_val = JS_DupValue(ctx, argv[2]);
    2420             :                 } else {
    2421           0 :                         pckc->pck = gf_filter_pck_new_alloc(pctx->pid, (u32) ab_size, &data);
    2422           0 :                         if (!data) {
    2423             :                                 JS_FreeValue(ctx, obj);
    2424           0 :                                 return js_throw_err(ctx, GF_OUT_OF_MEM);
    2425             :                         }
    2426           0 :                         memcpy(data, ab_data, ab_size);
    2427             :                 }
    2428             :                 goto pck_done;
    2429             :         }
    2430             :         /*try WebGL canvas*/
    2431             : #if !defined(GPAC_DISABLE_3D) && !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES1X)
    2432         605 :         gf_fsess_packet_destructor pck_del = NULL;
    2433         605 :         GF_FilterFrameInterface *f_ifce = NULL;
    2434         605 :         JSValue res = webgl_get_frame_interface(ctx, argc, argv, &pck_del, &f_ifce);
    2435         605 :         if (!JS_IsNull(res)) {
    2436         605 :                 if (JS_IsException(res)) {
    2437             :                         JS_FreeValue(ctx, obj);
    2438           0 :                         return res;
    2439             :                 }
    2440             :                 assert(f_ifce);
    2441         605 :                 pckc->pck = gf_filter_pck_new_frame_interface(pctx->pid, f_ifce, pck_del);
    2442         605 :                 goto pck_done;
    2443             :         }
    2444             : #endif
    2445             : 
    2446             :         JS_FreeValue(ctx, obj);
    2447           0 :         return JS_EXCEPTION;
    2448             : 
    2449             : 
    2450        1307 : pck_done:
    2451        1307 :         if (!pckc->pck) {
    2452             :                 JS_FreeValue(ctx, obj);
    2453           0 :                 return js_throw_err(ctx, GF_OUT_OF_MEM);
    2454             :         }
    2455        1307 :         pckc->flags |= GF_JS_PCK_IS_OUTPUT;
    2456        1307 :         return obj;
    2457             : }
    2458             : 
    2459           1 : static JSValue jsf_pid_get_clock_info(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    2460             : {
    2461             :         u32 timescale;
    2462             :         u64 val;
    2463             :         GF_FilterClockType cktype;
    2464             :         JSValue res;
    2465           1 :         GF_JSPidCtx *pctx = JS_GetOpaque(this_val, jsf_pid_class_id);
    2466           1 :     if (!pctx) return JS_EXCEPTION;
    2467           1 :     cktype = gf_filter_pid_get_clock_info(pctx->pid, &val, &timescale);
    2468           1 :         res = JS_NewObject(ctx);
    2469           2 :     JS_SetPropertyStr(ctx, res, "type", JS_NewInt32(ctx, cktype));
    2470           2 :     JS_SetPropertyStr(ctx, res, "timescale", JS_NewInt32(ctx, timescale));
    2471           2 :     JS_SetPropertyStr(ctx, res, "value", JS_NewInt64(ctx, val));
    2472           1 :         return res;
    2473             : }
    2474             : 
    2475             : 
    2476         263 : static JSValue jsf_pid_set_property_ex(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, u32 mode)
    2477             : {
    2478             :         GF_Err e;
    2479             :         GF_PropertyValue prop;
    2480             :         const GF_PropertyValue *the_prop = NULL;
    2481             :         const char *name=NULL;
    2482         263 :         GF_JSPidCtx *pctx = JS_GetOpaque(this_val, jsf_pid_class_id);
    2483         263 :     if (!pctx) return JS_EXCEPTION;
    2484             :     name = JS_ToCString(ctx, argv[0]);
    2485         263 :         if (!name) return JS_EXCEPTION;
    2486             : 
    2487         263 :         if ((argc>2) && JS_ToBool(ctx, argv[2])) {
    2488           4 :                 if (!JS_IsNull(argv[1])) {
    2489           2 :                         e = jsf_ToProp(pctx->jsf->filter, ctx, argv[1], 0, &prop);
    2490           2 :                         JS_FreeCString(ctx, name);
    2491           2 :                         if (e)
    2492           0 :                                 return js_throw_err(ctx, e);
    2493             :                         the_prop = &prop;
    2494             :                 }
    2495           2 :                 if (mode==1) {
    2496           1 :                         e = gf_filter_pid_set_info_dyn(pctx->pid, (char *) name, &prop);
    2497           1 :                 } else if (mode==2) {
    2498           0 :                         e = gf_filter_pid_negociate_property_dyn(pctx->pid, (char *) name, &prop);
    2499             :                 } else {
    2500           1 :                         e = gf_filter_pid_set_property_dyn(pctx->pid, (char *) name, &prop);
    2501             :                 }
    2502             :         } else {
    2503         261 :                 u32 p4cc = gf_props_get_id(name);
    2504         261 :                 JS_FreeCString(ctx, name);
    2505         261 :                 if (!p4cc) return JS_EXCEPTION;
    2506         522 :                 if (!JS_IsNull(argv[1])) {
    2507         253 :                         e = jsf_ToProp(pctx->jsf->filter, ctx, argv[1], p4cc, &prop);
    2508         253 :                         if (e)
    2509           0 :                                 return js_throw_err(ctx, e);
    2510             : 
    2511             :                         the_prop = &prop;
    2512             :                 }
    2513         261 :                 if (mode==1) {
    2514           0 :                         e = gf_filter_pid_set_info(pctx->pid, p4cc, the_prop);
    2515         261 :                 } else if (mode==2) {
    2516           0 :                         e = gf_filter_pid_negociate_property(pctx->pid, p4cc, the_prop);
    2517             :                 } else {
    2518         261 :                         e = gf_filter_pid_set_property(pctx->pid, p4cc, the_prop);
    2519             :                 }
    2520             :         }
    2521             : 
    2522         263 :         if (the_prop)
    2523         255 :                 gf_props_reset_single(&prop);
    2524         263 :         if (e) return js_throw_err(ctx, e);
    2525         263 :     return JS_UNDEFINED;
    2526             : }
    2527         262 : static JSValue jsf_pid_set_property(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    2528             : {
    2529         262 :         return jsf_pid_set_property_ex(ctx, this_val, argc, argv, 0);
    2530             : }
    2531           1 : static JSValue jsf_pid_set_info(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    2532             : {
    2533           1 :         return jsf_pid_set_property_ex(ctx, this_val, argc, argv, 1);
    2534             : }
    2535           0 : static JSValue jsf_pid_negociate_prop(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    2536             : {
    2537           0 :         return jsf_pid_set_property_ex(ctx, this_val, argc, argv, 2);
    2538             : }
    2539             : 
    2540           0 : static JSValue jsf_pid_ignore_blocking(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    2541             : {
    2542             :         Bool do_ignore = GF_TRUE;
    2543           0 :         GF_JSPidCtx *pctx = JS_GetOpaque(this_val, jsf_pid_class_id);
    2544           0 :     if (!pctx) return JS_EXCEPTION;
    2545           0 :     if (argc) do_ignore = JS_ToBool(ctx, argv[0]) ? GF_TRUE : GF_FALSE;
    2546           0 :     gf_filter_pid_ignore_blocking(pctx->pid, do_ignore);
    2547           0 :         return JS_UNDEFINED;
    2548             : 
    2549             : }
    2550             : 
    2551           1 : static JSValue jsf_pid_remove(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    2552             : {
    2553           1 :         GF_JSPidCtx *pctx = JS_GetOpaque(this_val, jsf_pid_class_id);
    2554           1 :     if (!pctx) return JS_EXCEPTION;
    2555           1 :     if (pctx->pid) {
    2556           1 :                 gf_filter_pid_remove(pctx->pid);
    2557           1 :                 pctx->pid = NULL;
    2558             :     }
    2559           1 :     JS_SetOpaque(this_val, NULL);
    2560           1 :         return JS_UNDEFINED;
    2561             : }
    2562             : 
    2563           1 : static JSValue jsf_pid_reset_props(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    2564             : {
    2565             :         GF_Err e;
    2566           1 :         GF_JSPidCtx *pctx = JS_GetOpaque(this_val, jsf_pid_class_id);
    2567           1 :     if (!pctx) return JS_EXCEPTION;
    2568           1 :     e = gf_filter_pid_reset_properties(pctx->pid);
    2569           1 :         if (e) return js_throw_err(ctx, e);
    2570           1 :         return JS_UNDEFINED;
    2571             : }
    2572             : 
    2573          11 : static JSValue jsf_pid_copy_props(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    2574             : {
    2575             :         GF_Err e;
    2576          11 :         GF_JSPidCtx *pctx_this = JS_GetOpaque(this_val, jsf_pid_class_id);
    2577          11 :     if (!pctx_this || !argc) return JS_EXCEPTION;
    2578          11 :         GF_JSPidCtx *pctx_from = JS_GetOpaque(argv[0], jsf_pid_class_id);
    2579          11 :     if (!pctx_from) return JS_EXCEPTION;
    2580          11 :     e = gf_filter_pid_copy_properties(pctx_this->pid, pctx_from->pid);
    2581          11 :         if (e) return js_throw_err(ctx, e);
    2582          11 :     return JS_UNDEFINED;
    2583             : }
    2584             : 
    2585         278 : static JSValue jsf_pid_forward(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    2586             : {
    2587             :         GF_Err e;
    2588             :         GF_JSPckCtx *pckc;
    2589         278 :         GF_JSPidCtx *pctx = JS_GetOpaque(this_val, jsf_pid_class_id);
    2590         278 :     if (!pctx || !argc) return JS_EXCEPTION;
    2591         556 :     if (!JS_IsObject(argv[0])) return JS_EXCEPTION;
    2592         278 :         pckc = JS_GetOpaque(argv[0], jsf_pck_class_id);
    2593         278 :     if (!pckc || !pckc->pck) return JS_EXCEPTION;
    2594         278 :     e = gf_filter_pck_forward(pckc->pck, pctx->pid);
    2595         278 :         if (e) return js_throw_err(ctx, e);
    2596         278 :     return JS_UNDEFINED;
    2597             : }
    2598             : 
    2599             : 
    2600             : static const JSCFunctionListEntry jsf_pid_funcs[] = {
    2601             :     JS_CGETSET_MAGIC_DEF("name", jsf_pid_get_prop, jsf_pid_set_prop, JSF_PID_NAME),
    2602             :     JS_CGETSET_MAGIC_DEF("eos", jsf_pid_get_prop, jsf_pid_set_prop, JSF_PID_EOS),
    2603             :     JS_CGETSET_MAGIC_DEF("eos_seen", jsf_pid_get_prop, NULL, JSF_PID_EOS_SEEN),
    2604             :     JS_CGETSET_MAGIC_DEF("eos_received", jsf_pid_get_prop, NULL, JSF_PID_EOS_RECEIVED),
    2605             :     JS_CGETSET_MAGIC_DEF("would_block", jsf_pid_get_prop, NULL, JSF_PID_WOULD_BLOCK),
    2606             :     JS_CGETSET_MAGIC_DEF("filter_name", jsf_pid_get_prop, NULL, JSF_PID_FILTER_NAME),
    2607             :     JS_CGETSET_MAGIC_DEF("src_name", jsf_pid_get_prop, NULL, JSF_PID_FILTER_SRC),
    2608             :     JS_CGETSET_MAGIC_DEF("args", jsf_pid_get_prop, NULL, JSF_PID_FILTER_ARGS),
    2609             :     JS_CGETSET_MAGIC_DEF("src_args", jsf_pid_get_prop, NULL, JSF_PID_FILTER_SRC_ARGS),
    2610             :     JS_CGETSET_MAGIC_DEF("unicity_args", jsf_pid_get_prop, NULL, JSF_PID_FILTER_UNICITY_ARGS),
    2611             :     JS_CGETSET_MAGIC_DEF("max_buffer", jsf_pid_get_prop, jsf_pid_set_prop, JSF_PID_MAX_BUFFER),
    2612             :     JS_CGETSET_MAGIC_DEF("loose_connect", NULL, jsf_pid_set_prop, JSF_PID_LOOSE_CONNECT),
    2613             :     JS_CGETSET_MAGIC_DEF("framing", NULL, jsf_pid_set_prop, JSF_PID_FRAMING_MODE),
    2614             :     JS_CGETSET_MAGIC_DEF("buffer", jsf_pid_get_prop, NULL, JSF_PID_BUFFER),
    2615             :     JS_CGETSET_MAGIC_DEF("full", jsf_pid_get_prop, NULL, JSF_PID_IS_FULL),
    2616             :     JS_CGETSET_MAGIC_DEF("first_empty", jsf_pid_get_prop, NULL, JSF_PID_FIRST_EMPTY),
    2617             :     JS_CGETSET_MAGIC_DEF("first_cts", jsf_pid_get_prop, NULL, JSF_PID_FIRST_CTS),
    2618             :     JS_CGETSET_MAGIC_DEF("nb_pck_queued", jsf_pid_get_prop, NULL, JSF_PID_NB_PACKETS),
    2619             :     JS_CGETSET_MAGIC_DEF("timescale", jsf_pid_get_prop, NULL, JSF_PID_TIMESCALE),
    2620             :     JS_CGETSET_MAGIC_DEF("clock_mode", NULL, jsf_pid_set_prop, JSF_PID_CLOCK_MODE),
    2621             :     JS_CGETSET_MAGIC_DEF("discard", NULL, jsf_pid_set_prop, JSF_PID_DISCARD),
    2622             :     JS_CGETSET_MAGIC_DEF("src_url", jsf_pid_get_prop, NULL, JSF_PID_SRC_URL),
    2623             :     JS_CGETSET_MAGIC_DEF("dst_url", jsf_pid_get_prop, NULL, JSF_PID_DST_URL),
    2624             :     JS_CGETSET_MAGIC_DEF("require_source_id", NULL, jsf_pid_set_prop, JSF_PID_REQUIRE_SOURCEID),
    2625             :     JS_CGETSET_MAGIC_DEF("recompute_dts", NULL, jsf_pid_set_prop, JSF_PID_RECOMPUTE_DTS),
    2626             :     JS_CGETSET_MAGIC_DEF("min_pck_dur", jsf_pid_get_prop, NULL, JSF_PID_MIN_PCK_DUR),
    2627             :     JS_CGETSET_MAGIC_DEF("playing", jsf_pid_get_prop, NULL, JSF_PID_IS_PLAYING),
    2628             :     JS_CFUNC_DEF("send_event", 0, jsf_pid_send_event),
    2629             :     JS_CFUNC_DEF("enum_properties", 0, jsf_pid_enum_properties),
    2630             :     JS_CFUNC_DEF("get_prop", 0, jsf_pid_get_property),
    2631             :     JS_CFUNC_DEF("get_info", 0, jsf_pid_get_info),
    2632             :     JS_CFUNC_DEF("get_packet", 0, jsf_pid_get_packet),
    2633             :     JS_CFUNC_DEF("drop_packet", 0, jsf_pid_drop_packet),
    2634             :     JS_CFUNC_DEF("is_filter_in_parents", 0, jsf_pid_is_filter_in_parents),
    2635             :     JS_CFUNC_DEF("get_buffer_occupancy", 0, jsf_pid_get_buffer_occupancy),
    2636             :     JS_CFUNC_DEF("clear_eos", 0, jsf_pid_clear_eos),
    2637             :     JS_CFUNC_DEF("check_caps", 0, jsf_pid_check_caps),
    2638             :     JS_CFUNC_DEF("discard_block", 0, jsf_pid_discard_block),
    2639             :     JS_CFUNC_DEF("allow_direct_dispatch", 0, jsf_pid_allow_direct_dispatch),
    2640             :     JS_CFUNC_DEF("resolve_file_template", 0, jsf_pid_resolve_file_template),
    2641             :     JS_CFUNC_DEF("query_caps", 0, jsf_pid_query_caps),
    2642             :     JS_CFUNC_DEF("get_stats", 0, jsf_pid_get_statistics),
    2643             :     JS_CFUNC_DEF("get_clock_info", 0, jsf_pid_get_clock_info),
    2644             :     JS_CFUNC_DEF("set_prop", 0, jsf_pid_set_property),
    2645             :     JS_CFUNC_DEF("set_info", 0, jsf_pid_set_info),
    2646             :     JS_CFUNC_DEF("new_packet", 0, jsf_pid_new_packet),
    2647             :     JS_CFUNC_DEF("remove", 0, jsf_pid_remove),
    2648             :     JS_CFUNC_DEF("reset_props", 0, jsf_pid_reset_props),
    2649             :     JS_CFUNC_DEF("copy_props", 0, jsf_pid_copy_props),
    2650             :     JS_CFUNC_DEF("forward", 0, jsf_pid_forward),
    2651             :     JS_CFUNC_DEF("negociate_prop", 0, jsf_pid_negociate_prop),
    2652             :     JS_CFUNC_DEF("ignore_blocking", 0, jsf_pid_ignore_blocking),
    2653             : };
    2654             : 
    2655             : enum
    2656             : {
    2657             :         JSF_EVENT_TYPE,
    2658             :         JSF_EVENT_NAME,
    2659             :         /*PLAY event*/
    2660             :         JSF_EVENT_START_RANGE,
    2661             :         JSF_EVENT_SPEED,
    2662             :         JSF_EVENT_HW_BUFFER_RESET,
    2663             :         JSF_EVENT_INITIAL_BROADCAST_PLAY,
    2664             :         JSF_EVENT_TIMESTAMP_BASED,
    2665             :         JSF_EVENT_FULL_FILE_ONLY,
    2666             :         JSF_EVENT_FORCE_DASH_SEG_SWITCH,
    2667             :         JSF_EVENT_FROM_PCK,
    2668             :         /*source switch*/
    2669             :         JSF_EVENT_START_OFFSET,
    2670             :         JSF_EVENT_END_OFFSET,
    2671             :         JSF_EVENT_SOURCE_SWITCH,
    2672             :         JSF_EVENT_SKIP_CACHE_EXPIRATION,
    2673             :         JSF_EVENT_HINT_BLOCK_SIZE,
    2674             :         /*segment size*/
    2675             :         JSF_EVENT_SEG_URL,
    2676             :         JSF_EVENT_SEG_IS_INIT,
    2677             :         JSF_EVENT_MEDIA_START_RANGE,
    2678             :         JSF_EVENT_MEDIA_END_RANGE,
    2679             :         JSF_EVENT_IDX_START_RANGE,
    2680             :         JSF_EVENT_IDX_END_RANGE,
    2681             :         /*quality switch*/
    2682             :         JSF_EVENT_SWITCH_UP,
    2683             :         JSF_EVENT_SWITCH_GROUP_IDX,
    2684             :         JSF_EVENT_SWITCH_QUALITY_IDX,
    2685             :         JSF_EVENT_SWITCH_TILE_MODE,
    2686             :         JSF_EVENT_SWITCH_QUALITY_DEGRADATION,
    2687             :         /*visibility hint*/
    2688             :         JSF_EVENT_VIS_MIN_X,
    2689             :         JSF_EVENT_VIS_MIN_Y,
    2690             :         JSF_EVENT_VIS_MAX_X,
    2691             :         JSF_EVENT_VIS_MAX_Y,
    2692             :         JSF_EVENT_VIS_IS_GAZE,
    2693             :         /*buffer requirements*/
    2694             :         JSF_EVENT_BUFREQ_MAX_BUFFER_US,
    2695             :         JSF_EVENT_BUFREQ_MAX_PLAYOUT_US,
    2696             :         JSF_EVENT_BUFREQ_MIN_PLAYOUT_US,
    2697             :         JSF_EVENT_BUFREQ_PID_ONLY,
    2698             : 
    2699             :         JSF_EVENT_USER_TYPE,
    2700             :         JSF_EVENT_USER_KEYCODE,
    2701             :         JSF_EVENT_USER_KEYNAME,
    2702             :         JSF_EVENT_USER_KEYMODS,
    2703             :         JSF_EVENT_USER_MOUSE_X,
    2704             :         JSF_EVENT_USER_MOUSE_Y,
    2705             :         JSF_EVENT_USER_WHEEL,
    2706             :         JSF_EVENT_USER_BUTTON,
    2707             :         JSF_EVENT_USER_HWKEY,
    2708             :         JSF_EVENT_USER_DROPFILES,
    2709             :         JSF_EVENT_USER_TEXT,
    2710             :         JSF_EVENT_USER_MT_ROTATION,
    2711             :         JSF_EVENT_USER_MT_PINCH,
    2712             :         JSF_EVENT_USER_MT_FINGERS,
    2713             :         JSF_EVENT_USER_WIDTH,
    2714             :         JSF_EVENT_USER_HEIGHT,
    2715             :         JSF_EVENT_USER_SHOWTYPE,
    2716             :         JSF_EVENT_USER_MOVE_X,
    2717             :         JSF_EVENT_USER_MOVE_Y,
    2718             :         JSF_EVENT_USER_MOVE_RELATIVE,
    2719             :         JSF_EVENT_USER_MOVE_ALIGN_X,
    2720             :         JSF_EVENT_USER_MOVE_ALIGN_Y,
    2721             :         JSF_EVENT_USER_CAPTION,
    2722             : };
    2723             : 
    2724         505 : static Bool jsf_check_evt(u32 evt_type, u8 ui_type, int magic)
    2725             : {
    2726         505 :         if (magic==JSF_EVENT_TYPE) return GF_TRUE;
    2727          93 :         if (magic==JSF_EVENT_NAME) return GF_TRUE;
    2728          91 :         switch (evt_type) {
    2729           6 :         case GF_FEVT_PLAY:
    2730           6 :                 switch (magic) {
    2731             :                 case JSF_EVENT_START_RANGE:
    2732             :                 case JSF_EVENT_SPEED:
    2733             :                 case JSF_EVENT_HW_BUFFER_RESET:
    2734             :                 case JSF_EVENT_INITIAL_BROADCAST_PLAY:
    2735             :                 case JSF_EVENT_TIMESTAMP_BASED:
    2736             :                 case JSF_EVENT_FULL_FILE_ONLY:
    2737             :                 case JSF_EVENT_FORCE_DASH_SEG_SWITCH:
    2738             :                 case JSF_EVENT_FROM_PCK:
    2739             :                         return GF_TRUE;
    2740           0 :                 default:
    2741           0 :                         return GF_FALSE;
    2742             :                 }
    2743             :                 break;
    2744           0 :         case GF_FEVT_SET_SPEED:
    2745           0 :                 return (magic == JSF_EVENT_SPEED) ? GF_TRUE : GF_FALSE;
    2746           0 :         case GF_FEVT_SOURCE_SWITCH:
    2747           0 :                 switch (magic) {
    2748             :                 case JSF_EVENT_START_OFFSET:
    2749             :                 case JSF_EVENT_END_OFFSET:
    2750             :                 case JSF_EVENT_SOURCE_SWITCH:
    2751             :                 case JSF_EVENT_SKIP_CACHE_EXPIRATION:
    2752             :                 case JSF_EVENT_HINT_BLOCK_SIZE:
    2753             :                         return GF_TRUE;
    2754           0 :                 default:
    2755           0 :                         return GF_FALSE;
    2756             :                 }
    2757             :                 break;
    2758           0 :         case GF_FEVT_SEGMENT_SIZE:
    2759           0 :                 switch (magic) {
    2760             :                 case JSF_EVENT_SEG_URL:
    2761             :                 case JSF_EVENT_SEG_IS_INIT:
    2762             :                 case JSF_EVENT_MEDIA_START_RANGE:
    2763             :                 case JSF_EVENT_MEDIA_END_RANGE:
    2764             :                 case JSF_EVENT_IDX_START_RANGE:
    2765             :                 case JSF_EVENT_IDX_END_RANGE:
    2766             :                         return GF_TRUE;
    2767           0 :                 default:
    2768           0 :                         return GF_FALSE;
    2769             :                 }
    2770             :                 break;
    2771           0 :         case GF_FEVT_QUALITY_SWITCH:
    2772           0 :                 switch (magic) {
    2773             :                 case JSF_EVENT_SWITCH_UP:
    2774             :                 case JSF_EVENT_SWITCH_GROUP_IDX:
    2775             :                 case JSF_EVENT_SWITCH_QUALITY_IDX:
    2776             :                 case JSF_EVENT_SWITCH_TILE_MODE:
    2777             :                 case JSF_EVENT_SWITCH_QUALITY_DEGRADATION:
    2778             :                         return GF_TRUE;
    2779           0 :                 default:
    2780           0 :                         return GF_FALSE;
    2781             :                 }
    2782             :                 break;
    2783           0 :         case GF_FEVT_VISIBILITY_HINT:
    2784           0 :                 switch (magic) {
    2785             :                 case JSF_EVENT_VIS_MIN_X:
    2786             :                 case JSF_EVENT_VIS_MIN_Y:
    2787             :                 case JSF_EVENT_VIS_MAX_X:
    2788             :                 case JSF_EVENT_VIS_MAX_Y:
    2789             :                 case JSF_EVENT_VIS_IS_GAZE:
    2790             :                         return GF_TRUE;
    2791           0 :                 default:
    2792           0 :                         return GF_FALSE;
    2793             :                 }
    2794             :                 break;
    2795           0 :         case GF_FEVT_BUFFER_REQ:
    2796           0 :                 switch (magic) {
    2797             :                 case JSF_EVENT_BUFREQ_MAX_BUFFER_US:
    2798             :                 case JSF_EVENT_BUFREQ_MAX_PLAYOUT_US:
    2799             :                 case JSF_EVENT_BUFREQ_MIN_PLAYOUT_US:
    2800             :                 case JSF_EVENT_BUFREQ_PID_ONLY:
    2801             :                         return GF_TRUE;
    2802           0 :                 default:
    2803           0 :                         return GF_FALSE;
    2804             :                 }
    2805             :                 break;
    2806          85 :         case GF_FEVT_USER:
    2807          85 :                 if (magic==JSF_EVENT_USER_TYPE)
    2808             :                         return GF_TRUE;
    2809             : 
    2810           1 :                 switch (ui_type) {
    2811           0 :                 case GF_EVENT_CLICK:
    2812             :                 case GF_EVENT_MOUSEUP:
    2813             :                 case GF_EVENT_MOUSEDOWN:
    2814             :                 case GF_EVENT_MOUSEOVER:
    2815             :                 case GF_EVENT_MOUSEOUT:
    2816             :                 case GF_EVENT_MOUSEMOVE:
    2817             :                 case GF_EVENT_MOUSEWHEEL:
    2818           0 :                         switch (magic) {
    2819             :                         case JSF_EVENT_USER_MOUSE_X:
    2820             :                         case JSF_EVENT_USER_MOUSE_Y:
    2821             :                         case JSF_EVENT_USER_WHEEL:
    2822             :                         case JSF_EVENT_USER_BUTTON:
    2823             :                                 return GF_TRUE;
    2824             :                         default:
    2825             :                                 break;
    2826             :                         }
    2827           0 :                         return GF_FALSE;
    2828           0 :                 case GF_EVENT_MULTITOUCH:
    2829             :                         switch (magic) {
    2830             :                         case JSF_EVENT_USER_MOUSE_X:
    2831             :                         case JSF_EVENT_USER_MOUSE_Y:
    2832             :                         case JSF_EVENT_USER_MT_ROTATION:
    2833             :                         case JSF_EVENT_USER_MT_PINCH:
    2834             :                         case JSF_EVENT_USER_MT_FINGERS:
    2835             :                                 return GF_TRUE;
    2836             :                         default:
    2837             :                                 break;
    2838             :                         }
    2839           0 :                         return GF_FALSE;
    2840             : 
    2841           0 :                 case GF_EVENT_KEYUP:
    2842             :                 case GF_EVENT_KEYDOWN:
    2843             :                 case GF_EVENT_LONGKEYPRESS:
    2844             :                 case GF_EVENT_TEXTINPUT:
    2845             :                         switch (magic) {
    2846             :                         case JSF_EVENT_USER_KEYCODE:
    2847             :                         case JSF_EVENT_USER_KEYNAME:
    2848             :                         case JSF_EVENT_USER_KEYMODS:
    2849             :                         case JSF_EVENT_USER_HWKEY:
    2850             :                         case JSF_EVENT_USER_DROPFILES:
    2851             :                                 return GF_TRUE;
    2852             :                         default:
    2853             :                                 break;
    2854             :                         }
    2855           0 :                         return GF_FALSE;
    2856           0 :                 case GF_EVENT_DROPFILE:
    2857           0 :                         switch (magic) {
    2858             :                         case JSF_EVENT_USER_DROPFILES:
    2859             :                                 return GF_TRUE;
    2860             :                         default:
    2861             :                                 break;
    2862             :                         }
    2863           0 :                         return GF_FALSE;
    2864           0 :                 case GF_EVENT_PASTE_TEXT:
    2865             :                 case GF_EVENT_COPY_TEXT:
    2866           0 :                         switch (magic) {
    2867             :                         case JSF_EVENT_USER_TEXT:
    2868             :                                 return GF_TRUE;
    2869             :                         default:
    2870             :                                 break;
    2871             :                         }
    2872           0 :                         return GF_FALSE;
    2873           0 :                 case GF_EVENT_SIZE:
    2874           0 :                         switch (magic) {
    2875             :                         case JSF_EVENT_USER_WIDTH:
    2876             :                         case JSF_EVENT_USER_HEIGHT:
    2877             :                                 return GF_TRUE;
    2878             :                         default:
    2879             :                                 break;
    2880             :                         }
    2881           0 :                         return GF_FALSE;
    2882           0 :                 case GF_EVENT_MOVE:
    2883           0 :                         switch (magic) {
    2884             :                         case JSF_EVENT_USER_MOVE_X:
    2885             :                         case JSF_EVENT_USER_MOVE_Y:
    2886             :                         case JSF_EVENT_USER_MOVE_RELATIVE:
    2887             :                         case JSF_EVENT_USER_MOVE_ALIGN_X:
    2888             :                         case JSF_EVENT_USER_MOVE_ALIGN_Y:
    2889             :                                 return GF_TRUE;
    2890             :                         default:
    2891             :                                 break;
    2892             :                         }
    2893           0 :                         return GF_FALSE;
    2894           1 :                 case GF_EVENT_SET_CAPTION:
    2895           1 :                         if (magic==JSF_EVENT_USER_CAPTION) return GF_TRUE;
    2896           0 :                         return GF_FALSE;
    2897             :                 }
    2898             :         }
    2899             :         return GF_FALSE;
    2900             : }
    2901             : 
    2902             : 
    2903           5 : static JSValue jsf_event_set_prop(JSContext *ctx, JSValueConst this_val, JSValueConst value, int magic)
    2904             : {
    2905             :         GF_Err e = GF_OK;
    2906             :         u32 ival;
    2907             :         Double dval;
    2908             :         const char *str=NULL;
    2909           5 :         GF_FilterEvent *evt = JS_GetOpaque(this_val, jsf_event_class_id);
    2910           5 :     if (!evt) return JS_EXCEPTION;
    2911           5 :         if (!jsf_check_evt(evt->base.type, evt->user_event.event.type, magic))
    2912           0 :                 return JS_EXCEPTION;
    2913             : 
    2914           5 :         switch (magic) {
    2915           0 :         case JSF_EVENT_TYPE:
    2916           0 :                 return JS_EXCEPTION;
    2917             :         /*PLAY*/
    2918           3 :         case JSF_EVENT_START_RANGE:
    2919           3 :                 return JS_ToFloat64(ctx, &evt->play.start_range, value) ? JS_EXCEPTION : JS_UNDEFINED;
    2920           0 :         case JSF_EVENT_SPEED:
    2921           0 :                 return JS_ToFloat64(ctx, &evt->play.speed, value) ? JS_EXCEPTION : JS_UNDEFINED;
    2922           0 :         case JSF_EVENT_HW_BUFFER_RESET:
    2923           0 :                 evt->play.hw_buffer_reset = JS_ToBool(ctx, value);
    2924           0 :                 return JS_UNDEFINED;
    2925           0 :         case JSF_EVENT_INITIAL_BROADCAST_PLAY:
    2926           0 :                 evt->play.initial_broadcast_play = JS_ToBool(ctx, value);
    2927           0 :                 return JS_UNDEFINED;
    2928           0 :         case JSF_EVENT_TIMESTAMP_BASED:
    2929           0 :                 if (JS_ToInt32(ctx, &ival, value)) return JS_EXCEPTION;
    2930           0 :                 evt->play.timestamp_based = (u8) ival;
    2931           0 :                 return JS_UNDEFINED;
    2932           0 :         case JSF_EVENT_FULL_FILE_ONLY:
    2933           0 :                 evt->play.full_file_only = JS_ToBool(ctx, value);
    2934           0 :                 return JS_UNDEFINED;
    2935           0 :         case JSF_EVENT_FORCE_DASH_SEG_SWITCH:
    2936           0 :                 evt->play.forced_dash_segment_switch = JS_ToBool(ctx, value);
    2937           0 :                 return JS_UNDEFINED;
    2938           0 :         case JSF_EVENT_FROM_PCK:
    2939           0 :                 return JS_ToInt32(ctx, &evt->play.from_pck, value) ? JS_EXCEPTION : JS_UNDEFINED;
    2940             :         /*source switch*/
    2941           0 :         case JSF_EVENT_START_OFFSET:
    2942           0 :                 return JS_ToInt64(ctx, &evt->seek.start_offset, value) ? JS_EXCEPTION : JS_UNDEFINED;
    2943           0 :         case JSF_EVENT_END_OFFSET:
    2944           0 :                 return JS_ToInt64(ctx, &evt->seek.end_offset, value) ? JS_EXCEPTION : JS_UNDEFINED;
    2945           0 :         case JSF_EVENT_SOURCE_SWITCH:
    2946             :                 /*TODO check leak!*/
    2947           0 :                 evt->seek.source_switch = JS_ToCString(ctx, value);
    2948           0 :                 return JS_UNDEFINED;
    2949           0 :         case JSF_EVENT_SKIP_CACHE_EXPIRATION:
    2950           0 :                 evt->seek.skip_cache_expiration = JS_ToBool(ctx, value);
    2951           0 :                 return JS_UNDEFINED;
    2952           0 :         case JSF_EVENT_HINT_BLOCK_SIZE:
    2953           0 :                 return JS_ToInt32(ctx, &evt->seek.hint_block_size, value) ? JS_EXCEPTION : JS_UNDEFINED;
    2954             :         /*segment size*/
    2955           0 :         case JSF_EVENT_SEG_URL:
    2956             :                 /*TODO check leak!*/
    2957           0 :                 evt->seg_size.seg_url = JS_ToCString(ctx, value);
    2958           0 :                 return JS_UNDEFINED;
    2959           0 :         case JSF_EVENT_SEG_IS_INIT:
    2960           0 :                 evt->seg_size.is_init = JS_ToBool(ctx, value);
    2961           0 :                 return JS_UNDEFINED;
    2962           0 :         case JSF_EVENT_MEDIA_START_RANGE:
    2963           0 :                 return JS_ToInt64(ctx, &evt->seg_size.media_range_start, value) ? JS_EXCEPTION : JS_UNDEFINED;
    2964           0 :         case JSF_EVENT_MEDIA_END_RANGE:
    2965           0 :                 return JS_ToInt64(ctx, &evt->seg_size.media_range_end, value) ? JS_EXCEPTION : JS_UNDEFINED;
    2966           0 :         case JSF_EVENT_IDX_START_RANGE:
    2967           0 :                 return JS_ToInt64(ctx, &evt->seg_size.idx_range_start, value) ? JS_EXCEPTION : JS_UNDEFINED;
    2968           0 :         case JSF_EVENT_IDX_END_RANGE:
    2969           0 :                 return JS_ToInt64(ctx, &evt->seg_size.idx_range_end, value) ? JS_EXCEPTION : JS_UNDEFINED;
    2970             :         /*quality switch*/
    2971           0 :         case JSF_EVENT_SWITCH_UP:
    2972           0 :                 evt->quality_switch.up = JS_ToBool(ctx, value);
    2973           0 :                 return JS_UNDEFINED;
    2974           0 :         case JSF_EVENT_SWITCH_GROUP_IDX:
    2975           0 :                 return JS_ToInt32(ctx, &evt->quality_switch.dependent_group_index, value) ? JS_EXCEPTION : JS_UNDEFINED;
    2976           0 :         case JSF_EVENT_SWITCH_QUALITY_IDX:
    2977           0 :                 return JS_ToInt32(ctx, &evt->quality_switch.q_idx, value) ? JS_EXCEPTION : JS_UNDEFINED;
    2978           0 :         case JSF_EVENT_SWITCH_TILE_MODE:
    2979           0 :                 return JS_ToInt32(ctx, &evt->quality_switch.set_tile_mode_plus_one, value) ? JS_EXCEPTION : JS_UNDEFINED;
    2980           0 :         case JSF_EVENT_SWITCH_QUALITY_DEGRADATION:
    2981           0 :                 return JS_ToInt32(ctx, &evt->quality_switch.quality_degradation, value) ? JS_EXCEPTION : JS_UNDEFINED;
    2982             :         /*visibility hint*/
    2983           0 :         case JSF_EVENT_VIS_MIN_X: return JS_ToInt32(ctx, &evt->visibility_hint.min_x, value) ? JS_EXCEPTION : JS_UNDEFINED;
    2984           0 :         case JSF_EVENT_VIS_MIN_Y: return JS_ToInt32(ctx, &evt->visibility_hint.min_y, value) ? JS_EXCEPTION : JS_UNDEFINED;
    2985           0 :         case JSF_EVENT_VIS_MAX_X: return JS_ToInt32(ctx, &evt->visibility_hint.max_x, value) ? JS_EXCEPTION : JS_UNDEFINED;
    2986           0 :         case JSF_EVENT_VIS_MAX_Y: return JS_ToInt32(ctx, &evt->visibility_hint.max_y, value) ? JS_EXCEPTION : JS_UNDEFINED;
    2987           0 :         case JSF_EVENT_VIS_IS_GAZE:
    2988           0 :                 evt->visibility_hint.is_gaze = JS_ToBool(ctx, value);
    2989           0 :                 return JS_UNDEFINED;
    2990             :         /*buffer reqs*/
    2991           0 :         case JSF_EVENT_BUFREQ_MAX_BUFFER_US: return JS_ToInt32(ctx, &evt->buffer_req.max_buffer_us, value) ? JS_EXCEPTION : JS_UNDEFINED;
    2992           0 :         case JSF_EVENT_BUFREQ_MAX_PLAYOUT_US: return JS_ToInt32(ctx, &evt->buffer_req.max_playout_us, value) ? JS_EXCEPTION : JS_UNDEFINED;
    2993           0 :         case JSF_EVENT_BUFREQ_MIN_PLAYOUT_US: return JS_ToInt32(ctx, &evt->buffer_req.min_playout_us, value) ? JS_EXCEPTION : JS_UNDEFINED;
    2994           0 :         case JSF_EVENT_BUFREQ_PID_ONLY:
    2995           0 :                 evt->buffer_req.pid_only = JS_ToBool(ctx, value);
    2996           0 :                 return JS_UNDEFINED;
    2997             : 
    2998           1 :         case JSF_EVENT_USER_TYPE:
    2999           1 :                 if (JS_ToInt32(ctx, &ival, value)) return JS_EXCEPTION;
    3000           1 :                 evt->user_event.event.type = (u8) ival;
    3001           1 :                 return JS_UNDEFINED;
    3002             : 
    3003             : 
    3004           0 :         case JSF_EVENT_USER_MOUSE_X:
    3005           0 :                 if (evt->user_event.event.type==GF_EVENT_MULTITOUCH) {
    3006           0 :                         if (JS_ToFloat64(ctx, &dval, value)) return JS_EXCEPTION;
    3007           0 :                         evt->user_event.event.mtouch.x = FLT2FIX(dval);
    3008           0 :                         return JS_UNDEFINED;
    3009             :                 }
    3010           0 :                 return JS_ToInt32(ctx, &evt->user_event.event.mouse.x, value) ? JS_EXCEPTION : JS_UNDEFINED;
    3011           0 :         case JSF_EVENT_USER_MOUSE_Y:
    3012           0 :                 if (evt->user_event.event.type==GF_EVENT_MULTITOUCH) {
    3013           0 :                         if (JS_ToFloat64(ctx, &dval, value)) return JS_EXCEPTION;
    3014           0 :                         evt->user_event.event.mtouch.y = FLT2FIX(dval);
    3015           0 :                         return JS_UNDEFINED;
    3016             :                 }
    3017           0 :                 return JS_ToInt32(ctx, &evt->user_event.event.mouse.y, value) ? JS_EXCEPTION : JS_UNDEFINED;
    3018             : 
    3019           0 :         case JSF_EVENT_USER_WHEEL:
    3020           0 :                 if (JS_ToFloat64(ctx, &dval, value)) return JS_EXCEPTION;
    3021           0 :                 evt->user_event.event.mouse.wheel_pos = FLT2FIX(dval);
    3022           0 :                 return JS_UNDEFINED;
    3023           0 :         case JSF_EVENT_USER_BUTTON: return JS_ToInt32(ctx, &evt->user_event.event.mouse.button, value) ? JS_EXCEPTION : JS_UNDEFINED;
    3024           0 :         case JSF_EVENT_USER_HWKEY: return JS_ToInt32(ctx, &evt->user_event.event.key.hw_code, value) ? JS_EXCEPTION : JS_UNDEFINED;
    3025           0 :         case JSF_EVENT_USER_KEYCODE: return JS_ToInt32(ctx, &evt->user_event.event.key.key_code, value) ? JS_EXCEPTION : JS_UNDEFINED;
    3026           0 :         case JSF_EVENT_USER_KEYMODS: return JS_ToInt32(ctx, &evt->user_event.event.key.flags, value) ? JS_EXCEPTION : JS_UNDEFINED;
    3027             : 
    3028           0 :         case JSF_EVENT_USER_MT_ROTATION:
    3029           0 :                 if (JS_ToFloat64(ctx, &dval, value)) return JS_EXCEPTION;
    3030           0 :                 evt->user_event.event.mtouch.rotation = FLT2FIX(dval);
    3031           0 :                 return JS_UNDEFINED;
    3032           0 :         case JSF_EVENT_USER_MT_PINCH:
    3033           0 :                 if (JS_ToFloat64(ctx, &dval, value)) return JS_EXCEPTION;
    3034           0 :                 evt->user_event.event.mtouch.pinch = FLT2FIX(dval);
    3035           0 :                 return JS_UNDEFINED;
    3036           0 :         case JSF_EVENT_USER_MT_FINGERS:
    3037           0 :                 return JS_ToInt32(ctx, &evt->user_event.event.mtouch.num_fingers, value) ? JS_EXCEPTION : JS_UNDEFINED;
    3038             : 
    3039           0 :         case JSF_EVENT_USER_TEXT:
    3040             :         {
    3041             :                 str = JS_ToCString(ctx, value);
    3042           0 :                 evt->user_event.event.clipboard.text = gf_strdup(str ? str : "");
    3043           0 :                 if (str) JS_FreeCString(ctx, str);
    3044           0 :                 return JS_UNDEFINED;
    3045             :         }
    3046             : 
    3047           0 :         case JSF_EVENT_USER_WIDTH: return JS_ToInt32(ctx, &evt->user_event.event.size.width, value) ? JS_EXCEPTION : JS_UNDEFINED;
    3048           0 :         case JSF_EVENT_USER_HEIGHT: return JS_ToInt32(ctx, &evt->user_event.event.size.height, value) ? JS_EXCEPTION : JS_UNDEFINED;
    3049           0 :         case JSF_EVENT_USER_SHOWTYPE: return JS_ToInt32(ctx, &evt->user_event.event.show.show_type, value) ? JS_EXCEPTION : JS_UNDEFINED;
    3050           0 :         case JSF_EVENT_USER_MOVE_X: return JS_ToInt32(ctx, &evt->user_event.event.move.x, value) ? JS_EXCEPTION : JS_UNDEFINED;
    3051           0 :         case JSF_EVENT_USER_MOVE_Y: return JS_ToInt32(ctx, &evt->user_event.event.move.y, value) ? JS_EXCEPTION : JS_UNDEFINED;
    3052           0 :         case JSF_EVENT_USER_MOVE_RELATIVE: return JS_ToInt32(ctx, &evt->user_event.event.move.relative, value) ? JS_EXCEPTION : JS_UNDEFINED;
    3053           0 :         case JSF_EVENT_USER_MOVE_ALIGN_X:
    3054             :         case JSF_EVENT_USER_MOVE_ALIGN_Y:
    3055           0 :                 if (JS_ToInt32(ctx, &ival, value)) return JS_EXCEPTION;
    3056           0 :                 if (magic==JSF_EVENT_USER_MOVE_ALIGN_X)
    3057           0 :                         evt->user_event.event.move.align_x = ival;
    3058             :                 else
    3059           0 :                         evt->user_event.event.move.align_x = ival;
    3060           0 :                 return JS_UNDEFINED;
    3061             : 
    3062           1 :         case JSF_EVENT_USER_CAPTION:
    3063             :         {
    3064             :                 str = JS_ToCString(ctx, value);
    3065           1 :                 evt->user_event.event.caption.caption = gf_strdup(str ? str : "");
    3066           1 :                 if (str) JS_FreeCString(ctx, str);
    3067           1 :                 return JS_UNDEFINED;
    3068             :         }
    3069             :         }
    3070             : 
    3071             :         if (str)
    3072             :                 JS_FreeCString(ctx, str);
    3073             :         if (e) return js_throw_err(ctx, e);
    3074           0 :     return JS_UNDEFINED;
    3075             : }
    3076             : 
    3077         500 : static JSValue jsf_event_get_prop(JSContext *ctx, JSValueConst this_val, int magic)
    3078             : {
    3079         500 :         GF_FilterEvent *evt = JS_GetOpaque(this_val, jsf_event_class_id);
    3080         500 :     if (!evt) return JS_EXCEPTION;
    3081         500 :         if (!jsf_check_evt(evt->base.type, evt->user_event.event.type, magic))
    3082           0 :                 return JS_EXCEPTION;
    3083         500 :         switch (magic) {
    3084         412 :         case JSF_EVENT_TYPE: return JS_NewInt32(ctx, evt->base.type);
    3085           2 :         case JSF_EVENT_NAME:
    3086           2 :                 if (evt->base.type==GF_FEVT_USER) {
    3087             :                         const char *ename=NULL;
    3088           2 :                         switch (evt->user_event.event.type) {
    3089             :                         case GF_EVENT_CLICK: ename = "click"; break;
    3090           0 :                         case GF_EVENT_MOUSEUP: ename = "mouseup"; break;
    3091           0 :                         case GF_EVENT_MOUSEDOWN: ename = "mousedown"; break;
    3092           0 :                         case GF_EVENT_MOUSEMOVE: ename = "mousemove"; break;
    3093           0 :                         case GF_EVENT_MOUSEWHEEL: ename = "mousewheel"; break;
    3094           0 :                         case GF_EVENT_DBLCLICK: ename = "dblclick"; break;
    3095           0 :                         case GF_EVENT_MULTITOUCH: ename = "touch"; break;
    3096           0 :                         case GF_EVENT_KEYUP: ename = "keyup"; break;
    3097           0 :                         case GF_EVENT_KEYDOWN: ename = "keydown"; break;
    3098           0 :                         case GF_EVENT_TEXTINPUT: ename = "text"; break;
    3099           0 :                         case GF_EVENT_DROPFILE: ename = "dropfile"; break;
    3100           0 :                         case GF_EVENT_TIMESHIFT_DEPTH: ename = "timeshift_depth"; break;
    3101           0 :                         case GF_EVENT_TIMESHIFT_UPDATE: ename = "timeshift_update"; break;
    3102           0 :                         case GF_EVENT_TIMESHIFT_OVERFLOW: ename = "timeshift_overflow"; break;
    3103           0 :                         case GF_EVENT_TIMESHIFT_UNDERRUN: ename = "timeshift_underrun"; break;
    3104           0 :                         case GF_EVENT_PASTE_TEXT: ename = "paste_text"; break;
    3105           0 :                         case GF_EVENT_COPY_TEXT: ename = "copy_text"; break;
    3106           0 :                         case GF_EVENT_SIZE: ename = "size"; break;
    3107           0 :                         case GF_EVENT_SHOWHIDE: ename = "showhide"; break;
    3108           0 :                         case GF_EVENT_MOVE: ename = "move"; break;
    3109           0 :                         case GF_EVENT_SET_CAPTION: ename = "caption"; break;
    3110           0 :                         case GF_EVENT_REFRESH: ename = "refresh"; break;
    3111           0 :                         case GF_EVENT_QUIT: ename = "quit"; break;
    3112           0 :                         case GF_EVENT_VIDEO_SETUP: ename = "video_setup"; break;
    3113           2 :                         default:
    3114           2 :                                 ename = "unknown"; break;
    3115             :                         }
    3116           2 :                         return JS_NewString(ctx, ename);
    3117             :                 }
    3118           0 :                 return JS_NewString(ctx, gf_filter_event_name(evt->base.type));
    3119             :         /*PLAY*/
    3120           3 :         case JSF_EVENT_START_RANGE: return JS_NewFloat64(ctx, evt->play.start_range);
    3121           0 :         case JSF_EVENT_SPEED: return JS_NewFloat64(ctx, evt->play.speed);
    3122           0 :         case JSF_EVENT_HW_BUFFER_RESET: return JS_NewBool(ctx, evt->play.hw_buffer_reset);
    3123           0 :         case JSF_EVENT_INITIAL_BROADCAST_PLAY: return JS_NewBool(ctx, evt->play.initial_broadcast_play);
    3124           0 :         case JSF_EVENT_TIMESTAMP_BASED: return JS_NewInt32(ctx, evt->play.timestamp_based);
    3125           0 :         case JSF_EVENT_FULL_FILE_ONLY: return JS_NewBool(ctx, evt->play.full_file_only);
    3126           0 :         case JSF_EVENT_FORCE_DASH_SEG_SWITCH: return JS_NewBool(ctx, evt->play.forced_dash_segment_switch);
    3127           0 :         case JSF_EVENT_FROM_PCK: return JS_NewInt32(ctx, evt->play.from_pck);
    3128             :         /*source switch*/
    3129           0 :         case JSF_EVENT_START_OFFSET: return JS_NewInt64(ctx, evt->seek.start_offset);
    3130           0 :         case JSF_EVENT_END_OFFSET: return JS_NewInt64(ctx, evt->seek.end_offset);
    3131           0 :         case JSF_EVENT_SOURCE_SWITCH: return JS_NewString(ctx, evt->seek.source_switch);
    3132           0 :         case JSF_EVENT_SKIP_CACHE_EXPIRATION: return JS_NewBool(ctx, evt->seek.skip_cache_expiration);
    3133           0 :         case JSF_EVENT_HINT_BLOCK_SIZE: return JS_NewInt32(ctx, evt->seek.hint_block_size);
    3134             :         /*segment size*/
    3135           0 :         case JSF_EVENT_SEG_URL: return JS_NewString(ctx, evt->seg_size.seg_url);
    3136           0 :         case JSF_EVENT_SEG_IS_INIT: return JS_NewBool(ctx, evt->seg_size.is_init);
    3137           0 :         case JSF_EVENT_MEDIA_START_RANGE: return JS_NewInt64(ctx, evt->seg_size.media_range_start);
    3138           0 :         case JSF_EVENT_MEDIA_END_RANGE: return JS_NewInt64(ctx, evt->seg_size.media_range_end);
    3139           0 :         case JSF_EVENT_IDX_START_RANGE: return JS_NewInt64(ctx, evt->seg_size.media_range_start);
    3140           0 :         case JSF_EVENT_IDX_END_RANGE: return JS_NewInt64(ctx, evt->seg_size.idx_range_end);
    3141             :         /*quality switch*/
    3142           0 :         case JSF_EVENT_SWITCH_UP: return JS_NewBool(ctx, evt->quality_switch.up);
    3143           0 :         case JSF_EVENT_SWITCH_GROUP_IDX: return JS_NewInt32(ctx, evt->quality_switch.dependent_group_index);
    3144           0 :         case JSF_EVENT_SWITCH_QUALITY_IDX: return JS_NewInt32(ctx, evt->quality_switch.q_idx);
    3145           0 :         case JSF_EVENT_SWITCH_TILE_MODE: return JS_NewInt32(ctx, evt->quality_switch.set_tile_mode_plus_one);
    3146           0 :         case JSF_EVENT_SWITCH_QUALITY_DEGRADATION: return JS_NewInt32(ctx, evt->quality_switch.quality_degradation);
    3147             :         /*visibility hint*/
    3148           0 :         case JSF_EVENT_VIS_MIN_X: return JS_NewInt32(ctx, evt->visibility_hint.min_x);
    3149           0 :         case JSF_EVENT_VIS_MIN_Y: return JS_NewInt32(ctx, evt->visibility_hint.min_y);
    3150           0 :         case JSF_EVENT_VIS_MAX_X: return JS_NewInt32(ctx, evt->visibility_hint.max_x);
    3151           0 :         case JSF_EVENT_VIS_MAX_Y: return JS_NewInt32(ctx, evt->visibility_hint.max_y);
    3152           0 :         case JSF_EVENT_VIS_IS_GAZE: return JS_NewBool(ctx, evt->visibility_hint.is_gaze);
    3153             :         /*buffer reqs*/
    3154           0 :         case JSF_EVENT_BUFREQ_MAX_BUFFER_US: return JS_NewInt32(ctx, evt->buffer_req.max_buffer_us);
    3155           0 :         case JSF_EVENT_BUFREQ_MAX_PLAYOUT_US: return JS_NewInt32(ctx, evt->buffer_req.max_playout_us);
    3156           0 :         case JSF_EVENT_BUFREQ_MIN_PLAYOUT_US: return JS_NewInt32(ctx, evt->buffer_req.min_playout_us);
    3157           0 :         case JSF_EVENT_BUFREQ_PID_ONLY: return JS_NewBool(ctx, evt->buffer_req.pid_only);
    3158             :         /*user event*/
    3159          83 :         case JSF_EVENT_USER_TYPE: return JS_NewInt32(ctx, evt->user_event.event.type);
    3160           0 :         case JSF_EVENT_USER_KEYCODE: return JS_NewInt32(ctx, evt->user_event.event.key.key_code);
    3161           0 :         case JSF_EVENT_USER_KEYMODS:
    3162           0 :                 return JS_NewInt32(ctx, evt->user_event.event.key.flags);
    3163           0 :         case JSF_EVENT_USER_KEYNAME:
    3164             : #ifndef GPAC_DISABLE_SVG
    3165           0 :                 return JS_NewString(ctx, gf_dom_get_key_name(evt->user_event.event.key.key_code) );
    3166             : #else
    3167             :                 return JS_NULL;
    3168             : #endif
    3169             : 
    3170           0 :         case JSF_EVENT_USER_MOUSE_X:
    3171           0 :                 if (evt->user_event.event.type==GF_EVENT_MULTITOUCH)
    3172           0 :                         return JS_NewFloat64(ctx, FIX2FLT(evt->user_event.event.mtouch.x) );
    3173           0 :                 return JS_NewInt32(ctx, evt->user_event.event.mouse.x);
    3174           0 :         case JSF_EVENT_USER_MOUSE_Y:
    3175           0 :                 if (evt->user_event.event.type==GF_EVENT_MULTITOUCH)
    3176           0 :                         return JS_NewFloat64(ctx, FIX2FLT(evt->user_event.event.mtouch.y) );
    3177           0 :                 return JS_NewInt32(ctx, evt->user_event.event.mouse.y);
    3178           0 :         case JSF_EVENT_USER_WHEEL: return JS_NewFloat64(ctx, FIX2FLT(evt->user_event.event.mouse.wheel_pos));
    3179           0 :         case JSF_EVENT_USER_BUTTON: return JS_NewInt32(ctx,  evt->user_event.event.mouse.button);
    3180           0 :         case JSF_EVENT_USER_HWKEY: return JS_NewInt32(ctx, evt->user_event.event.key.hw_code);
    3181           0 :         case JSF_EVENT_USER_DROPFILES:
    3182             :         {
    3183             :                 u32 i, idx;
    3184           0 :                 JSValue files_array = JS_NewArray(ctx);
    3185             :                 idx=0;
    3186           0 :                 for (i=0; i<evt->user_event.event.open_file.nb_files; i++) {
    3187           0 :                         if (evt->user_event.event.open_file.files[i]) {
    3188           0 :                                 JS_SetPropertyUint32(ctx, files_array, idx, JS_NewString(ctx, evt->user_event.event.open_file.files[i]) );
    3189           0 :                                 idx++;
    3190             :                         }
    3191             :                 }
    3192           0 :                 return files_array;
    3193             :         }
    3194           0 :         case JSF_EVENT_USER_TEXT:
    3195           0 :                 return JS_NewString(ctx, evt->user_event.event.clipboard.text ? evt->user_event.event.clipboard.text : "");
    3196             : 
    3197           0 :         case JSF_EVENT_USER_MT_ROTATION:
    3198           0 :                 return JS_NewFloat64(ctx, FIX2FLT(evt->user_event.event.mtouch.rotation) );
    3199           0 :         case JSF_EVENT_USER_MT_PINCH:
    3200           0 :                 return JS_NewFloat64(ctx, FIX2FLT(evt->user_event.event.mtouch.pinch) );
    3201           0 :         case JSF_EVENT_USER_MT_FINGERS:
    3202           0 :                 return JS_NewInt32(ctx, evt->user_event.event.mtouch.num_fingers);
    3203           0 :         case JSF_EVENT_USER_WIDTH: return JS_NewInt32(ctx, evt->user_event.event.size.width);
    3204           0 :         case JSF_EVENT_USER_HEIGHT: return JS_NewInt32(ctx, evt->user_event.event.size.height);
    3205           0 :         case JSF_EVENT_USER_SHOWTYPE: return JS_NewInt32(ctx, evt->user_event.event.show.show_type);
    3206             : 
    3207           0 :         case JSF_EVENT_USER_MOVE_X: return JS_NewInt32(ctx, evt->user_event.event.move.x);
    3208           0 :         case JSF_EVENT_USER_MOVE_Y: return JS_NewInt32(ctx, evt->user_event.event.move.y);
    3209           0 :         case JSF_EVENT_USER_MOVE_RELATIVE: return JS_NewInt32(ctx, evt->user_event.event.move.relative);
    3210           0 :         case JSF_EVENT_USER_MOVE_ALIGN_X: return JS_NewInt32(ctx, evt->user_event.event.move.align_x);
    3211           0 :         case JSF_EVENT_USER_MOVE_ALIGN_Y: return JS_NewInt32(ctx, evt->user_event.event.move.align_y);
    3212             : 
    3213           0 :         case JSF_EVENT_USER_CAPTION:
    3214           0 :                 return JS_NewString(ctx, evt->user_event.event.caption.caption ? evt->user_event.event.caption.caption : "");
    3215             :         }
    3216           0 :     return JS_UNDEFINED;
    3217             : }
    3218             : 
    3219           1 : GF_FilterEvent *jsf_get_event(JSContext *ctx, JSValueConst this_val)
    3220             : {
    3221           1 :         GF_FilterEvent *evt = JS_GetOpaque(this_val, jsf_event_class_id);
    3222           1 :         return evt;
    3223             : }
    3224             : 
    3225             : static const JSCFunctionListEntry jsf_event_funcs[] =
    3226             : {
    3227             :     JS_CGETSET_MAGIC_DEF("type", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_TYPE),
    3228             :     JS_CGETSET_MAGIC_DEF("name", jsf_event_get_prop, NULL, JSF_EVENT_NAME),
    3229             :     /*PLAY event*/
    3230             :     JS_CGETSET_MAGIC_DEF("start_range", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_START_RANGE),
    3231             :     JS_CGETSET_MAGIC_DEF("speed", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_SPEED),
    3232             :     JS_CGETSET_MAGIC_DEF("hw_buffer_reset", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_HW_BUFFER_RESET),
    3233             :     JS_CGETSET_MAGIC_DEF("initial_broadcast_play", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_INITIAL_BROADCAST_PLAY),
    3234             :     JS_CGETSET_MAGIC_DEF("timestamp_based", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_TIMESTAMP_BASED),
    3235             :     JS_CGETSET_MAGIC_DEF("full_file_only", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_FULL_FILE_ONLY),
    3236             :     JS_CGETSET_MAGIC_DEF("forced_dash_segment_switch", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_FORCE_DASH_SEG_SWITCH),
    3237             :     JS_CGETSET_MAGIC_DEF("from_pck", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_FROM_PCK),
    3238             :         /*source switch*/
    3239             :     JS_CGETSET_MAGIC_DEF("start_offset", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_START_OFFSET),
    3240             :     JS_CGETSET_MAGIC_DEF("end_offset", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_END_OFFSET),
    3241             :     JS_CGETSET_MAGIC_DEF("switch_url", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_SOURCE_SWITCH),
    3242             :     JS_CGETSET_MAGIC_DEF("skip_cache_exp", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_SKIP_CACHE_EXPIRATION),
    3243             :     JS_CGETSET_MAGIC_DEF("hint_block_size", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_HINT_BLOCK_SIZE),
    3244             :         /*segment size*/
    3245             :     JS_CGETSET_MAGIC_DEF("seg_url", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_SEG_URL),
    3246             :     JS_CGETSET_MAGIC_DEF("is_init", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_SEG_IS_INIT),
    3247             :     JS_CGETSET_MAGIC_DEF("media_start_range", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_MEDIA_START_RANGE),
    3248             :     JS_CGETSET_MAGIC_DEF("media_end_range", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_MEDIA_END_RANGE),
    3249             :     JS_CGETSET_MAGIC_DEF("index_start_range", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_IDX_START_RANGE),
    3250             :     JS_CGETSET_MAGIC_DEF("index_end_range", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_IDX_END_RANGE),
    3251             :         /*quality switch*/
    3252             :     JS_CGETSET_MAGIC_DEF("up", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_SWITCH_UP),
    3253             :     JS_CGETSET_MAGIC_DEF("dependent_group_index", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_SWITCH_GROUP_IDX),
    3254             :     JS_CGETSET_MAGIC_DEF("q_idx", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_SWITCH_QUALITY_IDX),
    3255             :     JS_CGETSET_MAGIC_DEF("set_tile_mode_plus_one", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_SWITCH_TILE_MODE),
    3256             :     JS_CGETSET_MAGIC_DEF("quality_degradation", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_SWITCH_QUALITY_DEGRADATION),
    3257             :     /*visibility hint*/
    3258             :     JS_CGETSET_MAGIC_DEF("min_x", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_VIS_MIN_X),
    3259             :     JS_CGETSET_MAGIC_DEF("min_y", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_VIS_MIN_Y),
    3260             :     JS_CGETSET_MAGIC_DEF("max_x", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_VIS_MAX_X),
    3261             :     JS_CGETSET_MAGIC_DEF("max_y", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_VIS_MAX_Y),
    3262             :     JS_CGETSET_MAGIC_DEF("is_gaze", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_VIS_IS_GAZE),
    3263             :     /*buffer reqs*/
    3264             :     JS_CGETSET_MAGIC_DEF("max_buffer_us", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_BUFREQ_MAX_BUFFER_US),
    3265             :     JS_CGETSET_MAGIC_DEF("max_playout_us", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_BUFREQ_MAX_PLAYOUT_US),
    3266             :     JS_CGETSET_MAGIC_DEF("min_playout_us", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_BUFREQ_MIN_PLAYOUT_US),
    3267             :     JS_CGETSET_MAGIC_DEF("pid_only", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_BUFREQ_PID_ONLY),
    3268             :     /*ui events*/
    3269             :     JS_CGETSET_MAGIC_DEF("ui_type", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_USER_TYPE),
    3270             :     JS_CGETSET_MAGIC_DEF("keycode", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_USER_KEYCODE),
    3271             :     JS_CGETSET_MAGIC_DEF("keyname", jsf_event_get_prop, NULL, JSF_EVENT_USER_KEYNAME),
    3272             :     JS_CGETSET_MAGIC_DEF("keymods", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_USER_KEYMODS),
    3273             :     JS_CGETSET_MAGIC_DEF("mouse_x", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_USER_MOUSE_X),
    3274             :     JS_CGETSET_MAGIC_DEF("mouse_y", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_USER_MOUSE_Y),
    3275             :     JS_CGETSET_MAGIC_DEF("wheel", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_USER_WHEEL),
    3276             :     JS_CGETSET_MAGIC_DEF("button", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_USER_BUTTON),
    3277             :     JS_CGETSET_MAGIC_DEF("hwkey", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_USER_HWKEY),
    3278             :     JS_CGETSET_MAGIC_DEF("dropfiles", jsf_event_get_prop, NULL, JSF_EVENT_USER_DROPFILES),
    3279             :     JS_CGETSET_MAGIC_DEF("clipboard", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_USER_TEXT),
    3280             : 
    3281             :     JS_CGETSET_MAGIC_DEF("mt_x", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_USER_MOUSE_X),
    3282             :     JS_CGETSET_MAGIC_DEF("mt_y", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_USER_MOUSE_Y),
    3283             :     JS_CGETSET_MAGIC_DEF("mt_rotate", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_USER_MT_ROTATION),
    3284             :     JS_CGETSET_MAGIC_DEF("mt_pinch", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_USER_MT_PINCH),
    3285             :     JS_CGETSET_MAGIC_DEF("mt_fingers", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_USER_MT_FINGERS),
    3286             : 
    3287             :     JS_CGETSET_MAGIC_DEF("width", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_USER_WIDTH),
    3288             :     JS_CGETSET_MAGIC_DEF("height", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_USER_HEIGHT),
    3289             :     JS_CGETSET_MAGIC_DEF("showtype", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_USER_SHOWTYPE),
    3290             :     JS_CGETSET_MAGIC_DEF("move_x", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_USER_MOVE_X),
    3291             :     JS_CGETSET_MAGIC_DEF("move_y", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_USER_MOVE_Y),
    3292             :     JS_CGETSET_MAGIC_DEF("move_relative", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_USER_MOVE_RELATIVE),
    3293             :     JS_CGETSET_MAGIC_DEF("move_alignx", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_USER_MOVE_ALIGN_X),
    3294             :     JS_CGETSET_MAGIC_DEF("move_aligny", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_USER_MOVE_ALIGN_Y),
    3295             :     JS_CGETSET_MAGIC_DEF("caption", jsf_event_get_prop, jsf_event_set_prop, JSF_EVENT_USER_CAPTION),
    3296             : };
    3297             : 
    3298           7 : static JSValue jsf_event_constructor(JSContext *ctx, JSValueConst new_target, int argc, JSValueConst *argv)
    3299             : {
    3300             :         GF_FilterEvent *evt;
    3301             :     JSValue obj;
    3302             :     s32 type;
    3303           7 :         if (argc!=1)
    3304           0 :                 return JS_EXCEPTION;
    3305           7 :         if (JS_ToInt32(ctx, &type, argv[0]))
    3306           0 :                 return JS_EXCEPTION;
    3307           7 :         if (!type)
    3308           0 :         return JS_EXCEPTION;
    3309           7 :     obj = JS_NewObjectClass(ctx, jsf_event_class_id);
    3310           7 :     if (JS_IsException(obj)) return obj;
    3311             : 
    3312           7 :         GF_SAFEALLOC(evt, GF_FilterEvent);
    3313           7 :     if (!evt) {
    3314             :         JS_FreeValue(ctx, obj);
    3315           0 :                 return js_throw_err(ctx, GF_OUT_OF_MEM);
    3316             :     }
    3317           7 :     evt->base.type = type;
    3318           7 :     if (type==GF_FEVT_PLAY)
    3319           5 :         evt->play.speed = 1.0;
    3320           7 :     JS_SetOpaque(obj, evt);
    3321           7 :     return obj;
    3322             : }
    3323             : 
    3324             : enum
    3325             : {
    3326             :         JSF_PCK_START = 0,
    3327             :         JSF_PCK_END,
    3328             :         JSF_PCK_DTS,
    3329             :         JSF_PCK_CTS,
    3330             :         JSF_PCK_DUR,
    3331             :         JSF_PCK_SAP,
    3332             :         JSF_PCK_TIMESCALE,
    3333             :         JSF_PCK_INTERLACED,
    3334             :         JSF_PCK_SEEK,
    3335             :         JSF_PCK_CORRUPTED,
    3336             :         JSF_PCK_BYTE_OFFSET,
    3337             :         JSF_PCK_ROLL,
    3338             :         JSF_PCK_CRYPT,
    3339             :         JSF_PCK_CLOCK_TYPE,
    3340             :         JSF_PCK_CAROUSEL,
    3341             :         JSF_PCK_SEQNUM,
    3342             :         JSF_PCK_BLOCKING_REF,
    3343             :         JSF_PCK_DEPENDS_ON,
    3344             :         JSF_PCK_DEPENDED_ON,
    3345             :         JSF_PCK_IS_LEADING,
    3346             :         JSF_PCK_HAS_REDUNDANT,
    3347             :         JSF_PCK_SIZE,
    3348             :         JSF_PCK_DATA,
    3349             :         JSF_PCK_FRAME_IFCE,
    3350             : };
    3351             : 
    3352        1426 : static JSValue jsf_pck_set_prop(JSContext *ctx, JSValueConst this_val, JSValueConst value, int magic)
    3353             : {
    3354             :         GF_Err e = GF_OK;
    3355             :         u32 ival, flags;
    3356             :         u64 lival;
    3357             :         Bool a1, a2;
    3358             :         const char *str=NULL;
    3359             :         GF_FilterPacket *pck;
    3360        1426 :         GF_JSPckCtx *pckctx = JS_GetOpaque(this_val, jsf_pck_class_id);
    3361        1426 :     if (!pckctx || !pckctx->pck) return JS_EXCEPTION;
    3362             :     pck = pckctx->pck;
    3363             : 
    3364        1426 :     switch (magic) {
    3365           0 :         case JSF_PCK_START:
    3366           0 :                 gf_filter_pck_get_framing(pck, &a1, &a2);
    3367           0 :                 gf_filter_pck_set_framing(pck, JS_ToBool(ctx, value), a2);
    3368           0 :                 break;
    3369           0 :         case JSF_PCK_END:
    3370           0 :                 gf_filter_pck_get_framing(pck, &a1, &a2);
    3371           0 :                 gf_filter_pck_set_framing(pck, a1, JS_ToBool(ctx, value));
    3372           0 :                 break;
    3373         200 :         case JSF_PCK_DTS:
    3374         200 :                 if (JS_IsNull(value))
    3375           0 :                         gf_filter_pck_set_dts(pck, GF_FILTER_NO_TS);
    3376             :                 else {
    3377         200 :                         if (JS_ToInt64(ctx, &lival, value)) return JS_EXCEPTION;
    3378         200 :                         gf_filter_pck_set_dts(pck, lival);
    3379             :                 }
    3380             :                 break;
    3381         601 :         case JSF_PCK_CTS:
    3382         601 :                 if (JS_IsNull(value))
    3383           0 :                         gf_filter_pck_set_cts(pck, GF_FILTER_NO_TS);
    3384             :                 else {
    3385         601 :                         if (JS_ToInt64(ctx, &lival, value)) return JS_EXCEPTION;
    3386         601 :                         gf_filter_pck_set_cts(pck, lival);
    3387             :                 }
    3388             :                 break;
    3389         200 :         case JSF_PCK_DUR:
    3390         200 :                 if (JS_ToInt32(ctx, &ival, value)) return JS_EXCEPTION;
    3391         200 :                 gf_filter_pck_set_duration(pck, ival);
    3392         200 :                 break;
    3393         425 :         case JSF_PCK_SAP:
    3394         425 :                 if (JS_ToInt32(ctx, &ival, value)) return JS_EXCEPTION;
    3395         425 :                 gf_filter_pck_set_sap(pck, ival);
    3396         425 :                 break;
    3397           0 :         case JSF_PCK_INTERLACED:
    3398           0 :                 if (JS_ToInt32(ctx, &ival, value)) return JS_EXCEPTION;
    3399           0 :                 gf_filter_pck_set_interlaced(pck, ival);
    3400           0 :                 break;
    3401           0 :         case JSF_PCK_SEEK:
    3402           0 :                 gf_filter_pck_set_seek_flag(pck, JS_ToBool(ctx, value));
    3403           0 :                 break;
    3404           0 :         case JSF_PCK_CORRUPTED:
    3405           0 :                 gf_filter_pck_set_corrupted(pck, JS_ToBool(ctx, value));
    3406           0 :                 break;
    3407           0 :         case JSF_PCK_BYTE_OFFSET:
    3408           0 :                 if (JS_IsNull(value))
    3409           0 :                         gf_filter_pck_set_byte_offset(pck, GF_FILTER_NO_BO);
    3410             :                 else {
    3411           0 :                         if (JS_ToInt64(ctx, &lival, value)) return JS_EXCEPTION;
    3412           0 :                         gf_filter_pck_set_byte_offset(pck, lival);
    3413             :                 }
    3414             :                 break;
    3415           0 :         case JSF_PCK_ROLL:
    3416           0 :                 if (JS_ToInt32(ctx, &ival, value)) return JS_EXCEPTION;
    3417           0 :                 gf_filter_pck_set_roll_info(pck, (s16) ival);
    3418           0 :                 break;
    3419           0 :         case JSF_PCK_CRYPT:
    3420           0 :                 if (JS_ToInt32(ctx, &ival, value)) return JS_EXCEPTION;
    3421           0 :                 gf_filter_pck_set_crypt_flags(pck, ival);
    3422           0 :                 break;
    3423           0 :         case JSF_PCK_CLOCK_TYPE:
    3424           0 :                 if (JS_ToInt32(ctx, &ival, value)) return JS_EXCEPTION;
    3425           0 :                 gf_filter_pck_set_clock_type(pck, ival);
    3426           0 :                 break;
    3427           0 :         case JSF_PCK_CAROUSEL:
    3428           0 :                 if (JS_ToInt32(ctx, &ival, value)) return JS_EXCEPTION;
    3429           0 :                 gf_filter_pck_set_carousel_version(pck, ival);
    3430           0 :                 break;
    3431           0 :         case JSF_PCK_SEQNUM:
    3432           0 :                 if (JS_ToInt32(ctx, &ival, value)) return JS_EXCEPTION;
    3433           0 :                 gf_filter_pck_set_seq_num(pck, ival);
    3434           0 :                 break;
    3435           0 :         case JSF_PCK_IS_LEADING:
    3436           0 :                 if (JS_ToInt32(ctx, &ival, value)) return JS_EXCEPTION;
    3437           0 :                 flags = gf_filter_pck_get_dependency_flags(pck);
    3438           0 :                 flags &= 0x3F;
    3439           0 :                 flags |= (ival & 0x3)<<6;
    3440           0 :                 gf_filter_pck_set_seq_num(pck, flags);
    3441           0 :                 break;
    3442           0 :         case JSF_PCK_DEPENDS_ON:
    3443           0 :                 if (JS_ToInt32(ctx, &ival, value)) return JS_EXCEPTION;
    3444           0 :                 flags = gf_filter_pck_get_dependency_flags(pck);
    3445           0 :                 flags &= 0xCF;
    3446           0 :                 flags |= (ival & 0x3)<<4;
    3447           0 :                 gf_filter_pck_set_seq_num(pck, flags);
    3448           0 :                 break;
    3449           0 :         case JSF_PCK_DEPENDED_ON:
    3450           0 :                 if (JS_ToInt32(ctx, &ival, value)) return JS_EXCEPTION;
    3451           0 :                 flags = gf_filter_pck_get_dependency_flags(pck);
    3452           0 :                 flags &= 0xF3;
    3453           0 :                 flags |= (ival & 0x3)<<2;
    3454           0 :                 gf_filter_pck_set_seq_num(pck, flags);
    3455           0 :                 break;
    3456           0 :         case JSF_PCK_HAS_REDUNDANT:
    3457           0 :                 if (JS_ToInt32(ctx, &ival, value)) return JS_EXCEPTION;
    3458           0 :                 flags = gf_filter_pck_get_dependency_flags(pck);
    3459           0 :                 flags &= 0xFC;
    3460           0 :                 flags |= (ival & 0x3);
    3461           0 :                 gf_filter_pck_set_seq_num(pck, flags);
    3462           0 :                 break;
    3463             :         }
    3464             :         if (str)
    3465             :                 JS_FreeCString(ctx, str);
    3466             :         if (e) return js_throw_err(ctx, e);
    3467        1426 :     return JS_UNDEFINED;
    3468             : }
    3469             : 
    3470        3073 : static JSValue jsf_pck_get_prop(JSContext *ctx, JSValueConst this_val, int magic)
    3471             : {
    3472             :         Bool a1, a2;
    3473             :         u64 lival;
    3474             :         u32 ival;
    3475             :         GF_FilterPacket *pck;
    3476        3073 :         GF_JSPckCtx *pckctx = JS_GetOpaque(this_val, jsf_pck_class_id);
    3477        3073 :     if (!pckctx || !pckctx->pck) return JS_EXCEPTION;
    3478             :     pck = pckctx->pck;
    3479             : 
    3480        3073 :         switch (magic) {
    3481           0 :         case JSF_PCK_START:
    3482           0 :                 gf_filter_pck_get_framing(pck, &a1, &a2);
    3483           0 :                 return JS_NewBool(ctx, a1);
    3484           0 :         case JSF_PCK_END:
    3485           0 :                 gf_filter_pck_get_framing(pck, &a1, &a2);
    3486           0 :                 return JS_NewBool(ctx, a2);
    3487         522 :         case JSF_PCK_DTS:
    3488         522 :                 lival = gf_filter_pck_get_dts(pck);
    3489         522 :                 if (lival==GF_FILTER_NO_TS) return JS_NULL;
    3490         519 :                 return JS_NewInt64(ctx, lival);
    3491         637 :         case JSF_PCK_CTS:
    3492         637 :                 lival = gf_filter_pck_get_cts(pck);
    3493         637 :                 if (lival==GF_FILTER_NO_TS) return JS_NULL;
    3494         634 :                 return JS_NewInt64(ctx, lival);
    3495           0 :         case JSF_PCK_DUR:
    3496           0 :                 return JS_NewInt32(ctx, gf_filter_pck_get_duration(pck));
    3497         522 :         case JSF_PCK_SAP:
    3498         522 :                 return JS_NewInt32(ctx, gf_filter_pck_get_sap(pck));
    3499           0 :         case JSF_PCK_TIMESCALE:
    3500           0 :                 return JS_NewInt32(ctx, gf_filter_pck_get_timescale(pck));
    3501           0 :         case JSF_PCK_INTERLACED:
    3502           0 :                 return JS_NewInt32(ctx, gf_filter_pck_get_interlaced(pck));
    3503           0 :         case JSF_PCK_SEEK:
    3504           0 :                 return JS_NewBool(ctx, gf_filter_pck_get_seek_flag(pck));
    3505           0 :         case JSF_PCK_CORRUPTED:
    3506           0 :                 return JS_NewBool(ctx, gf_filter_pck_get_corrupted(pck));
    3507           0 :         case JSF_PCK_BYTE_OFFSET:
    3508           0 :                 lival = gf_filter_pck_get_byte_offset(pck);
    3509           0 :                 if (lival==GF_FILTER_NO_TS) return JS_NULL;
    3510           0 :                 return JS_NewInt64(ctx, lival);
    3511           0 :         case JSF_PCK_ROLL:
    3512           0 :                 return JS_NewInt32(ctx, gf_filter_pck_get_roll_info(pck));
    3513           0 :         case JSF_PCK_CRYPT:
    3514           0 :                 return JS_NewInt32(ctx, gf_filter_pck_get_crypt_flags(pck));
    3515           0 :         case JSF_PCK_CLOCK_TYPE:
    3516           0 :                 return JS_NewInt32(ctx, gf_filter_pck_get_clock_type(pck));
    3517           0 :         case JSF_PCK_CAROUSEL:
    3518           0 :                 return JS_NewInt32(ctx, gf_filter_pck_get_carousel_version(pck));
    3519           0 :         case JSF_PCK_SEQNUM:
    3520           0 :                 return JS_NewInt32(ctx, gf_filter_pck_get_seq_num(pck));
    3521           0 :         case JSF_PCK_BLOCKING_REF:
    3522           0 :                 return JS_NewBool(ctx, gf_filter_pck_is_blocking_ref(pck));
    3523           0 :         case JSF_PCK_IS_LEADING:
    3524           0 :                 ival = gf_filter_pck_get_dependency_flags(pck);
    3525           0 :                 return JS_NewBool(ctx, (ival>>6) & 0x3);
    3526           0 :         case JSF_PCK_DEPENDS_ON:
    3527           0 :                 ival = gf_filter_pck_get_dependency_flags(pck);
    3528           0 :                 return JS_NewBool(ctx, (ival>>4) & 0x3);
    3529           0 :         case JSF_PCK_DEPENDED_ON:
    3530           0 :                 ival = gf_filter_pck_get_dependency_flags(pck);
    3531           0 :                 return JS_NewBool(ctx, (ival>>2) & 0x3);
    3532           0 :         case JSF_PCK_HAS_REDUNDANT:
    3533           0 :                 ival = gf_filter_pck_get_dependency_flags(pck);
    3534           0 :                 return JS_NewBool(ctx, (ival) & 0x3);
    3535         542 :         case JSF_PCK_SIZE:
    3536         542 :                 gf_filter_pck_get_data(pck, &ival);
    3537         542 :                 return JS_NewInt32(ctx, ival);
    3538         850 :         case JSF_PCK_DATA:
    3539        1700 :                 if (JS_IsUndefined(pckctx->data_ab)) {
    3540         775 :                         const u8 *data = gf_filter_pck_get_data(pck, &ival);
    3541         775 :                         if (!data) return JS_NULL;
    3542         775 :                         pckctx->data_ab = JS_NewArrayBuffer(ctx, (u8 *) data, ival, NULL, NULL, GF_TRUE);
    3543             :                 }
    3544             :                 return JS_DupValue(ctx, pckctx->data_ab);
    3545           0 :         case JSF_PCK_FRAME_IFCE:
    3546           0 :                 if (gf_filter_pck_get_frame_interface(pck) != NULL) return JS_NewBool(ctx, 1);
    3547             :                 else return JS_NewBool(ctx, 0);
    3548             :         }
    3549           0 :     return JS_UNDEFINED;
    3550             : }
    3551             : 
    3552          75 : static JSValue jsf_pck_set_readonly(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    3553             : {
    3554             :         GF_FilterPacket *pck;
    3555          75 :         GF_JSPckCtx *pckctx = JS_GetOpaque(this_val, jsf_pck_class_id);
    3556          75 :     if (!pckctx || !pckctx->pck) return JS_EXCEPTION;
    3557             :     pck = pckctx->pck;
    3558             : 
    3559          75 :         gf_filter_pck_set_readonly(pck);
    3560          75 :     return JS_UNDEFINED;
    3561             : }
    3562         348 : static JSValue jsf_pck_enum_properties(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    3563             : {
    3564             :         s32 idx;
    3565             :         u32 p4cc;
    3566             :         const char *pname;
    3567             :         JSValue res;
    3568             :         const GF_PropertyValue *prop;
    3569             :         GF_FilterPacket *pck;
    3570         348 :         GF_JSPckCtx *pckctx = JS_GetOpaque(this_val, jsf_pck_class_id);
    3571         348 :     if (!pckctx || !pckctx->pck) return JS_EXCEPTION;
    3572             :     pck = pckctx->pck;
    3573             : 
    3574         348 :     if (JS_ToInt32(ctx, &idx, argv[0]))
    3575           0 :                 return JS_EXCEPTION;
    3576             : 
    3577         348 :         prop = gf_filter_pck_enum_properties(pck, &idx, &p4cc, &pname);
    3578         348 :         if (!prop) return JS_NULL;
    3579           0 :         if (!pname) pname = gf_props_4cc_get_name(p4cc);
    3580           0 :         if (!pname) return JS_EXCEPTION;
    3581             : 
    3582           0 :         res = JS_NewObject(ctx);
    3583           0 :     JS_SetPropertyStr(ctx, res, "name", JS_NewString(ctx, pname));
    3584           0 :     JS_SetPropertyStr(ctx, res, "type", JS_NewInt32(ctx, prop->type));
    3585           0 :     JS_SetPropertyStr(ctx, res, "value", jsf_NewProp(ctx, prop));
    3586           0 :     return res;
    3587             : }
    3588             : 
    3589          75 : static JSValue jsf_pck_get_property(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    3590             : {
    3591             :         JSValue res;
    3592             :         const char *name=NULL;
    3593             :         const GF_PropertyValue *prop;
    3594             :         GF_FilterPacket *pck;
    3595          75 :         GF_JSPckCtx *pckctx = JS_GetOpaque(this_val, jsf_pck_class_id);
    3596          75 :     if (!pckctx || !pckctx->pck) return JS_EXCEPTION;
    3597             :     pck = pckctx->pck;
    3598             : 
    3599             :     name = JS_ToCString(ctx, argv[0]);
    3600          75 :         if (!name) return JS_EXCEPTION;
    3601          75 :         if ((argc>1) && JS_ToBool(ctx, argv[1])) {
    3602          75 :                 prop = gf_filter_pck_get_property_str(pck, name);
    3603          75 :                 JS_FreeCString(ctx, name);
    3604          75 :                 if (!prop) return JS_NULL;
    3605           0 :                 res = jsf_NewProp(ctx, prop);
    3606           0 :                 JS_SetPropertyStr(ctx, res, "type", JS_NewInt32(ctx, prop->type));
    3607             :         } else {
    3608           0 :                 u32 p4cc = gf_props_get_id(name);
    3609           0 :                 JS_FreeCString(ctx, name);
    3610           0 :                 if (!p4cc)
    3611           0 :                         return js_throw_err(ctx, GF_BAD_PARAM);
    3612             : 
    3613           0 :                 prop = gf_filter_pck_get_property(pck, p4cc);
    3614           0 :                 if (!prop) return JS_NULL;
    3615           0 :                 res = jsf_NewPropTranslate(ctx, prop, p4cc);
    3616             :         }
    3617           0 :     return res;
    3618             : }
    3619             : 
    3620         348 : static JSValue jsf_pck_ref(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    3621             : {
    3622             :         Bool is_ref_props = GF_FALSE;
    3623             :         GF_JSPckCtx *ref_pckctx;
    3624         348 :         GF_JSPckCtx *pckctx = JS_GetOpaque(this_val, jsf_pck_class_id);
    3625         348 :     if (!pckctx || !pckctx->pck) return JS_EXCEPTION;
    3626             : 
    3627         348 :     if (argc && JS_ToBool(ctx, argv[0])) is_ref_props = GF_TRUE;
    3628             : 
    3629         348 :         ref_pckctx = gf_list_pop_back(pckctx->jspid->jsf->pck_res);
    3630         348 :         if (!ref_pckctx) {
    3631           2 :                 GF_SAFEALLOC(ref_pckctx, GF_JSPckCtx);
    3632           2 :                 if (!ref_pckctx)
    3633           0 :                         return js_throw_err(ctx, GF_OUT_OF_MEM);
    3634             :         }
    3635             :         memcpy(ref_pckctx, pckctx, sizeof(GF_JSPckCtx));
    3636         348 :         if (is_ref_props)
    3637           0 :                 gf_filter_pck_ref_props(&ref_pckctx->pck);
    3638             :         else {
    3639         348 :                 gf_filter_pck_ref(&ref_pckctx->pck);
    3640             :         }
    3641         348 :         ref_pckctx->flags = GF_JS_PCK_IS_REF;
    3642         348 :         ref_pckctx->jsobj = JS_NewObjectClass(ctx, jsf_pck_class_id);
    3643         348 :         ref_pckctx->data_ab = JS_UNDEFINED;
    3644         348 :         ref_pckctx->ref_val = JS_UNDEFINED;
    3645         348 :         JS_SetOpaque(ref_pckctx->jsobj, ref_pckctx);
    3646             :         return JS_DupValue(ctx, ref_pckctx->jsobj);
    3647             : }
    3648             : 
    3649         348 : static JSValue jsf_pck_unref(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    3650             : {
    3651         348 :         GF_JSPckCtx *pckctx = JS_GetOpaque(this_val, jsf_pck_class_id);
    3652         348 :     if (!pckctx || !pckctx->pck) return JS_EXCEPTION;
    3653         348 :         if (!(pckctx->flags & GF_JS_PCK_IS_REF))
    3654           0 :                 return js_throw_err_msg(ctx, GF_BAD_PARAM, "Attempt to unref a non-reference packet");
    3655             : 
    3656         348 :         gf_filter_pck_unref(pckctx->pck);
    3657         348 :         pckctx->pck = NULL;
    3658             :         JS_FreeValue(ctx, pckctx->jsobj);
    3659         348 :         JS_SetOpaque(this_val, NULL);
    3660         348 :         gf_list_add(pckctx->jspid->jsf->pck_res, pckctx);
    3661             :         memset(pckctx, 0, sizeof(GF_JSPckCtx));
    3662         348 :         return JS_UNDEFINED;
    3663             : }
    3664             : 
    3665        1305 : static JSValue jsf_pck_send(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    3666             : {
    3667             :         GF_FilterPacket *pck;
    3668        1305 :         GF_JSPckCtx *pckctx = JS_GetOpaque(this_val, jsf_pck_class_id);
    3669        1305 :     if (!pckctx || !pckctx->pck) return JS_EXCEPTION;
    3670        1305 :         if (! pckctx->jspid->jsf->filter->in_process)
    3671           0 :                 return js_throw_err_msg(ctx, GF_BAD_PARAM, "Filter %s attempt to send packet outside process callback not allowed!\n", pckctx->jspid->jsf->filter->name);
    3672             : 
    3673             :     pck = pckctx->pck;
    3674        2610 :     if (!JS_IsUndefined(pckctx->data_ab)) {
    3675             :         JS_FreeValue(ctx, pckctx->data_ab);
    3676         427 :         pckctx->data_ab = JS_UNDEFINED;
    3677             :         }
    3678        1305 :         gf_filter_pck_send(pck);
    3679        1305 :         JS_SetOpaque(this_val, NULL);
    3680        1305 :         if (!(pckctx->flags & GF_JS_PCK_IS_SHARED)) {
    3681        1207 :                 if (pckctx->jspid) {
    3682        1207 :                         gf_list_add(pckctx->jspid->jsf->pck_res, pckctx);
    3683             :                         memset(pckctx, 0, sizeof(GF_JSPckCtx));
    3684             :                 }
    3685             :         }
    3686        1305 :         return JS_UNDEFINED;
    3687             : }
    3688           2 : static JSValue jsf_pck_discard(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    3689             : {
    3690             :         GF_FilterPacket *pck;
    3691           2 :         GF_JSPckCtx *pckctx = JS_GetOpaque(this_val, jsf_pck_class_id);
    3692           2 :     if (!pckctx || !pckctx->pck) return JS_EXCEPTION;
    3693             :     pck = pckctx->pck;
    3694           2 :     pckctx->pck = NULL;
    3695           2 :         gf_filter_pck_discard(pck);
    3696           2 :         return JS_UNDEFINED;
    3697             : }
    3698             : 
    3699         275 : static JSValue jsf_pck_set_property(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    3700             : {
    3701             :         GF_Err e;
    3702             :         GF_PropertyValue prop;
    3703             :         const char *name=NULL;
    3704             :         GF_FilterPacket *pck;
    3705         275 :         GF_JSPckCtx *pckctx = JS_GetOpaque(this_val, jsf_pck_class_id);
    3706         275 :     if (!pckctx || !pckctx->pck) return JS_EXCEPTION;
    3707             :     pck = pckctx->pck;
    3708             : 
    3709             :     name = JS_ToCString(ctx, argv[0]);
    3710         275 :         if (!name) return JS_EXCEPTION;
    3711             : 
    3712         275 :         if ((argc>2) && JS_ToBool(ctx, argv[2])) {
    3713         550 :                 if (!JS_IsNull(argv[2])) {
    3714         275 :                         e = jsf_ToProp(pckctx->jspid->jsf->filter, ctx, argv[1], 0, &prop);
    3715         275 :                         JS_FreeCString(ctx, name);
    3716         275 :                         if (e) return js_throw_err(ctx, e);
    3717         275 :                         e = gf_filter_pck_set_property_dyn(pck, (char *) name, &prop);
    3718         275 :                         gf_props_reset_single(&prop);
    3719             :                 } else {
    3720           0 :                         e = gf_filter_pck_set_property_dyn(pck, (char *) name, NULL);
    3721             :                 }
    3722             :         } else {
    3723           0 :                 u32 p4cc = gf_props_get_id(name);
    3724           0 :                 if (!p4cc) {
    3725             :                         JSValue ret;
    3726           0 :                         JS_FreeCString(ctx, name);
    3727           0 :                         ret = js_throw_err_msg(ctx, GF_BAD_PARAM, "Urecognized builtin property name %s\n", name);
    3728           0 :                         return ret;
    3729             :                 }
    3730           0 :                 JS_FreeCString(ctx, name);
    3731           0 :                 if ( ((p4cc==GF_PROP_PCK_SENDER_NTP) || (p4cc==GF_PROP_PCK_RECEIVER_NTP))
    3732           0 :                         && JS_IsBool(argv[1]) && JS_ToBool(ctx, argv[1])
    3733             :                 ) {
    3734           0 :                         e = gf_filter_pck_set_property(pck, p4cc, &PROP_LONGUINT(gf_net_get_ntp_ts()) );
    3735             :                 }
    3736           0 :                 else if (JS_IsNull(argv[1])) {
    3737           0 :                         e = gf_filter_pck_set_property(pck, p4cc, NULL);
    3738             :                 }
    3739             :                 else {
    3740           0 :                         e = jsf_ToProp(pckctx->jspid->jsf->filter, ctx, argv[1], p4cc, &prop);
    3741           0 :                         if (e) return js_throw_err(ctx, e);
    3742           0 :                         if ( ((p4cc==GF_PROP_PCK_SENDER_NTP) || (p4cc==GF_PROP_PCK_RECEIVER_NTP)) && (prop.type==GF_PROP_FRACTION)) {
    3743           0 :                                 u64 ntp = (u32) prop.value.frac.num;
    3744           0 :                                 ntp <<= 32;
    3745           0 :                                 ntp |= prop.value.frac.den;
    3746           0 :                                 prop.type = GF_PROP_LUINT;
    3747           0 :                                 prop.value.longuint = ntp;
    3748             :                         }
    3749             : 
    3750           0 :                         e = gf_filter_pck_set_property(pck, p4cc, &prop);
    3751           0 :                         gf_props_reset_single(&prop);
    3752             :                 }
    3753             :         }
    3754         275 :         if (e) return js_throw_err(ctx, e);
    3755         275 :     return JS_UNDEFINED;
    3756             : }
    3757             : 
    3758          40 : static JSValue jsf_pck_append_data(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    3759             : {
    3760          40 :         u8 *data_start=NULL;
    3761          40 :         u32 data_size=0;
    3762             :         u8 *new_start;
    3763             :         GF_Err e;
    3764             :         GF_FilterPacket *pck;
    3765          40 :         GF_JSPckCtx *pckctx = JS_GetOpaque(this_val, jsf_pck_class_id);
    3766          40 :     if (!pckctx || !pckctx->pck || !argc) return JS_EXCEPTION;
    3767             :     pck = pckctx->pck;
    3768             : 
    3769          80 :         if (JS_IsString(argv[0])  || JS_IsInteger(argv[0])) {
    3770             :         u32 len;
    3771             :         const char *str = NULL;
    3772             : 
    3773          40 :                 if (JS_IsInteger(argv[0])) {
    3774           0 :                         JS_ToInt32(ctx, &len, argv[0]);
    3775             :                 } else {
    3776             :                         str = JS_ToCString(ctx, argv[0]);
    3777          40 :                         if (!str) return JS_EXCEPTION;
    3778          40 :                         len = (u32) strlen(str);
    3779             :                 }
    3780             : 
    3781          40 :                 e = gf_filter_pck_expand(pck, len, &data_start, &new_start, &data_size);
    3782          40 :                 if (!new_start || e) {
    3783           0 :                         if (str) JS_FreeCString(ctx, str);
    3784           0 :                         return js_throw_err(ctx, e);
    3785             :                 }
    3786          40 :                 if (str) {
    3787          40 :                         memcpy(new_start, str, len);
    3788          40 :                         JS_FreeCString(ctx, str);
    3789             :                 }
    3790             : 
    3791          40 :                 jsf_pck_detach_ab(ctx, pckctx);
    3792          40 :                 return JS_NewArrayBuffer(ctx, (u8 *) new_start, len, NULL, NULL, GF_TRUE);
    3793             :         }
    3794             : 
    3795           0 :         if (!JS_IsObject(argv[0])) return JS_EXCEPTION;
    3796             : 
    3797             :         size_t ab_size;
    3798           0 :         u8 *data = JS_GetArrayBuffer(ctx, &ab_size, argv[0]);
    3799           0 :         if (!data)
    3800           0 :                 return JS_EXCEPTION;
    3801             : 
    3802           0 :         e = gf_filter_pck_expand(pck, (u32) ab_size, &data_start, &new_start, &data_size);
    3803           0 :         if (!new_start || e) {
    3804           0 :                 return js_throw_err(ctx, e);
    3805             :         }
    3806           0 :         memcpy(new_start, data, ab_size);
    3807             : 
    3808           0 :         jsf_pck_detach_ab(ctx, pckctx);
    3809             : 
    3810           0 :         return JS_NewArrayBuffer(ctx, (u8 *) new_start, ab_size, NULL, NULL, GF_TRUE);
    3811             : }
    3812             : 
    3813          20 : static JSValue jsf_pck_truncate(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    3814             : {
    3815          20 :         u32 len=0;
    3816             :         GF_Err e;
    3817             :         GF_FilterPacket *pck;
    3818          20 :         GF_JSPckCtx *pckctx = JS_GetOpaque(this_val, jsf_pck_class_id);
    3819          20 :     if (!pckctx || !pckctx->pck) return JS_EXCEPTION;
    3820             :     pck = pckctx->pck;
    3821          20 :         if (argc) {
    3822          20 :                 JS_ToInt32(ctx, &len, argv[0]);
    3823             :         }
    3824          20 :         e = gf_filter_pck_truncate(pck, len);
    3825          20 :         if (e) return js_throw_err(ctx, e);
    3826             : 
    3827          20 :         jsf_pck_detach_ab(ctx, pckctx);
    3828          20 :     return JS_UNDEFINED;
    3829             : }
    3830         579 : static JSValue jsf_pck_copy_props(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
    3831             : {
    3832             :         GF_Err e;
    3833         579 :         GF_JSPckCtx *pck_dst = JS_GetOpaque(this_val, jsf_pck_class_id);
    3834         579 :         if (!pck_dst || !pck_dst->pck || !argc)
    3835           0 :                 return JS_EXCEPTION;
    3836         579 :         GF_JSPckCtx *pck_from = JS_GetOpaque(argv[0], jsf_pck_class_id);
    3837         579 :     if (!pck_from || !pck_from->pck)
    3838           0 :         return JS_EXCEPTION;
    3839         579 :     e = gf_filter_pck_merge_properties(pck_from->pck, pck_dst->pck);
    3840         579 :         if (e) return js_throw_err(ctx, e);
    3841         579 :     return JS_UNDEFINED;
    3842             : }
    3843             : 
    3844             : static const JSCFunctionListEntry jsf_pck_funcs[] =
    3845             : {
    3846             :     JS_CGETSET_MAGIC_DEF("start", jsf_pck_get_prop, jsf_pck_set_prop, JSF_PCK_START),
    3847             :     JS_CGETSET_MAGIC_DEF("end", jsf_pck_get_prop, jsf_pck_set_prop, JSF_PCK_END),
    3848             :     JS_CGETSET_MAGIC_DEF("dts", jsf_pck_get_prop, jsf_pck_set_prop, JSF_PCK_DTS),
    3849             :     JS_CGETSET_MAGIC_DEF("cts", jsf_pck_get_prop, jsf_pck_set_prop, JSF_PCK_CTS),
    3850             :     JS_CGETSET_MAGIC_DEF("dur", jsf_pck_get_prop, jsf_pck_set_prop, JSF_PCK_DUR),
    3851             :     JS_CGETSET_MAGIC_DEF("sap", jsf_pck_get_prop, jsf_pck_set_prop, JSF_PCK_SAP),
    3852             :     JS_CGETSET_MAGIC_DEF("timescale", jsf_pck_get_prop, NULL, JSF_PCK_TIMESCALE),
    3853             :     JS_CGETSET_MAGIC_DEF("interlaced", jsf_pck_get_prop, jsf_pck_set_prop, JSF_PCK_INTERLACED),
    3854             :     JS_CGETSET_MAGIC_DEF("corrupted", jsf_pck_get_prop, jsf_pck_set_prop, JSF_PCK_CORRUPTED),
    3855             :     JS_CGETSET_MAGIC_DEF("seek", jsf_pck_get_prop, jsf_pck_set_prop, JSF_PCK_SEEK),
    3856             :     JS_CGETSET_MAGIC_DEF("byte_offset", jsf_pck_get_prop, jsf_pck_set_prop, JSF_PCK_BYTE_OFFSET),
    3857             :     JS_CGETSET_MAGIC_DEF("roll", jsf_pck_get_prop, jsf_pck_set_prop, JSF_PCK_ROLL),
    3858             :     JS_CGETSET_MAGIC_DEF("crypt", jsf_pck_get_prop, jsf_pck_set_prop, JSF_PCK_CRYPT),
    3859             :     JS_CGETSET_MAGIC_DEF("clock_type", jsf_pck_get_prop, jsf_pck_set_prop, JSF_PCK_CLOCK_TYPE),
    3860             :     JS_CGETSET_MAGIC_DEF("carousel", jsf_pck_get_prop, jsf_pck_set_prop, JSF_PCK_CAROUSEL),
    3861             :     JS_CGETSET_MAGIC_DEF("seqnum", jsf_pck_get_prop, jsf_pck_set_prop, JSF_PCK_SEQNUM),
    3862             :     JS_CGETSET_MAGIC_DEF("blocking_ref", jsf_pck_get_prop, NULL, JSF_PCK_BLOCKING_REF),
    3863             :     JS_CGETSET_MAGIC_DEF("is_leading", jsf_pck_get_prop, jsf_pck_set_prop, JSF_PCK_IS_LEADING),
    3864             :     JS_CGETSET_MAGIC_DEF("depends_on", jsf_pck_get_prop, jsf_pck_set_prop, JSF_PCK_DEPENDS_ON),
    3865             :     JS_CGETSET_MAGIC_DEF("depended_on", jsf_pck_get_prop, jsf_pck_set_prop, JSF_PCK_DEPENDED_ON),
    3866             :     JS_CGETSET_MAGIC_DEF("redundant", jsf_pck_get_prop, jsf_pck_set_prop, JSF_PCK_HAS_REDUNDANT),
    3867             :     JS_CGETSET_MAGIC_DEF("size", jsf_pck_get_prop, NULL, JSF_PCK_SIZE),
    3868             :     JS_CGETSET_MAGIC_DEF("data", jsf_pck_get_prop, NULL, JSF_PCK_DATA),
    3869             :     JS_CGETSET_MAGIC_DEF("frame_ifce", jsf_pck_get_prop, NULL, JSF_PCK_DATA),
    3870             : 
    3871             :     JS_CFUNC_DEF("set_readonly", 0, jsf_pck_set_readonly),
    3872             :     JS_CFUNC_DEF("enum_properties", 0, jsf_pck_enum_properties),
    3873             :     JS_CFUNC_DEF("get_prop", 0, jsf_pck_get_property),
    3874             :     JS_CFUNC_DEF("ref", 0, jsf_pck_ref),
    3875             :     JS_CFUNC_DEF("unref", 0, jsf_pck_unref),
    3876             :     JS_CFUNC_DEF("send", 0, jsf_pck_send),
    3877             :     JS_CFUNC_DEF("discard", 0, jsf_pck_discard),
    3878             :     JS_CFUNC_DEF("set_prop", 0, jsf_pck_set_property),
    3879             :     JS_CFUNC_DEF("append", 0, jsf_pck_append_data),
    3880             :     JS_CFUNC_DEF("truncate", 0, jsf_pck_truncate),
    3881             :     JS_CFUNC_DEF("copy_props", 0, jsf_pck_copy_props),
    3882             : };
    3883             : 
    3884             : 
    3885        2449 : static GF_Err jsfilter_process(GF_Filter *filter)
    3886             : {
    3887             :         JSValue ret;
    3888        2449 :         GF_Err e = GF_OK;
    3889        2449 :         GF_JSFilterCtx *jsf = gf_filter_get_udta(filter);
    3890        2449 :         if (!jsf) return GF_BAD_PARAM;
    3891             : 
    3892        2449 :         gf_js_lock(jsf->ctx, GF_TRUE);
    3893        2449 :         ret = JS_Call(jsf->ctx, jsf->funcs[JSF_EVT_PROCESS], jsf->filter_obj, 0, NULL);
    3894        2449 :         if (JS_IsException(ret)) {
    3895           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_SCRIPT, ("[%s] Error processing\n", jsf->log_name));
    3896           0 :                 js_dump_error(jsf->ctx);
    3897           0 :                 e = GF_BAD_PARAM;
    3898             :         }
    3899        2449 :         else if (JS_IsInteger(ret))
    3900        1532 :                 JS_ToInt32(jsf->ctx, (int*)&e, ret);
    3901             : 
    3902        2449 :         JS_FreeValue(jsf->ctx, ret);
    3903        2449 :         gf_js_lock(jsf->ctx, GF_FALSE);
    3904             : 
    3905        2449 :         js_do_loop(jsf->ctx);
    3906        2449 :         return e;
    3907             : }
    3908             : 
    3909             : 
    3910             : 
    3911          14 : static GF_Err jsfilter_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
    3912             : {
    3913             :         JSValue ret;
    3914          14 :         GF_Err e = GF_OK;
    3915          14 :         GF_JSFilterCtx *jsf = gf_filter_get_udta(filter);
    3916             :         GF_JSPidCtx *pctx;
    3917             : 
    3918          14 :         if (!jsf) return GF_BAD_PARAM;
    3919             : 
    3920          14 :         pctx = gf_filter_pid_get_udta(pid);
    3921             : 
    3922          14 :         if (is_remove) {
    3923             :                 assert(pctx);
    3924           1 :                 gf_js_lock(jsf->ctx, GF_TRUE);
    3925           1 :                 ret = JS_Call(jsf->ctx, jsf->funcs[JSF_EVT_REMOVE_PID], jsf->filter_obj, 1, &pctx->jsobj);
    3926           1 :                 if (JS_IsException(ret)) {
    3927           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_SCRIPT, ("[%s] Error removing pid\n", jsf->log_name));
    3928           0 :                         js_dump_error(jsf->ctx);
    3929           0 :                         e = GF_BAD_PARAM;
    3930             :                 }
    3931           1 :                 else if (JS_IsInteger(ret))
    3932           0 :                         JS_ToInt32(jsf->ctx, (int*)&e, ret);
    3933           1 :                 JS_FreeValue(jsf->ctx, ret);
    3934           1 :                 JS_FreeValue(jsf->ctx, pctx->jsobj);
    3935           1 :                 gf_list_del_item(jsf->pids, pctx);
    3936           1 :                 gf_filter_pid_set_udta(pid, NULL);
    3937           1 :                 gf_free(pctx);
    3938           1 :                 gf_js_lock(jsf->ctx, GF_FALSE);
    3939           1 :                 js_do_loop(jsf->ctx);
    3940           1 :                 return e;
    3941             :         }
    3942             : 
    3943          13 :         gf_js_lock(jsf->ctx, GF_TRUE);
    3944             : 
    3945          13 :         if (!pctx) {
    3946           9 :                 GF_SAFEALLOC(pctx, GF_JSPidCtx);
    3947           9 :                 if (!pctx) return GF_OUT_OF_MEM;
    3948             :                 
    3949           9 :                 pctx->jsf = jsf;
    3950           9 :                 pctx->pid = pid;
    3951           9 :                 pctx->jsobj = JS_NewObjectClass(jsf->ctx, jsf_pid_class_id);
    3952           9 :                 gf_filter_pid_set_udta(pid, pctx);
    3953           9 :                 gf_list_add(jsf->pids, pctx);
    3954           9 :                 JS_SetOpaque(pctx->jsobj, pctx);
    3955             :         }
    3956             : 
    3957          13 :         ret = JS_Call(jsf->ctx, jsf->funcs[JSF_EVT_CONFIGURE_PID], jsf->filter_obj, 1, &pctx->jsobj);
    3958          13 :         if (JS_IsException(ret)) {
    3959           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_SCRIPT, ("[%s] Error configure pid\n", jsf->log_name));
    3960           0 :                 js_dump_error(jsf->ctx);
    3961           0 :                 e = GF_BAD_PARAM;
    3962             :         }
    3963          13 :         else if (JS_IsInteger(ret))
    3964           0 :                         JS_ToInt32(jsf->ctx, (int*)&e, ret);
    3965          13 :         JS_FreeValue(jsf->ctx, ret);
    3966             : 
    3967          13 :         gf_js_lock(jsf->ctx, GF_FALSE);
    3968          13 :         js_do_loop(jsf->ctx);
    3969          13 :         return e;
    3970             : }
    3971             : 
    3972          77 : void js_load_constants(JSContext *ctx, JSValue global_obj)
    3973             : {
    3974             :     JSValue val;
    3975             : 
    3976          77 :     val = JS_NewObject(ctx);
    3977          77 :     JS_SetPropertyStr(ctx, val, "log", JS_NewCFunction(ctx, js_print, "log", 1));
    3978          77 :     JS_SetPropertyStr(ctx, global_obj, "console", val);
    3979             : 
    3980             : #define DEF_CONST( _val ) \
    3981             :     JS_SetPropertyStr(ctx, global_obj, #_val, JS_NewInt32(ctx, _val));
    3982             : 
    3983          77 :         DEF_CONST(GF_LOG_ERROR)
    3984          77 :         DEF_CONST(GF_LOG_WARNING)
    3985          77 :         DEF_CONST(GF_LOG_INFO)
    3986          77 :         DEF_CONST(GF_LOG_DEBUG)
    3987             : 
    3988          77 :         DEF_CONST(GF_PROP_BOOL)
    3989          77 :         DEF_CONST(GF_PROP_UINT)
    3990          77 :         DEF_CONST(GF_PROP_SINT)
    3991          77 :         DEF_CONST(GF_PROP_LUINT)
    3992          77 :         DEF_CONST(GF_PROP_LSINT)
    3993          77 :         DEF_CONST(GF_PROP_FRACTION)
    3994          77 :         DEF_CONST(GF_PROP_FRACTION64)
    3995          77 :         DEF_CONST(GF_PROP_FLOAT)
    3996          77 :         DEF_CONST(GF_PROP_DOUBLE)
    3997          77 :         DEF_CONST(GF_PROP_VEC2I)
    3998          77 :         DEF_CONST(GF_PROP_VEC2)
    3999          77 :         DEF_CONST(GF_PROP_VEC3I)
    4000          77 :         DEF_CONST(GF_PROP_VEC4I)
    4001          77 :         DEF_CONST(GF_PROP_STRING)
    4002          77 :         DEF_CONST(GF_PROP_STRING)
    4003          77 :         DEF_CONST(GF_PROP_STRING_NO_COPY)
    4004          77 :         DEF_CONST(GF_PROP_DATA)
    4005          77 :         DEF_CONST(GF_PROP_NAME)
    4006          77 :         DEF_CONST(GF_PROP_DATA_NO_COPY)
    4007          77 :         DEF_CONST(GF_PROP_CONST_DATA)
    4008          77 :         DEF_CONST(GF_PROP_POINTER)
    4009          77 :         DEF_CONST(GF_PROP_STRING_LIST)
    4010          77 :         DEF_CONST(GF_PROP_UINT_LIST)
    4011          77 :         DEF_CONST(GF_PROP_SINT_LIST)
    4012          77 :         DEF_CONST(GF_PROP_VEC2I_LIST)
    4013          77 :         DEF_CONST(GF_PROP_4CC)
    4014          77 :         DEF_CONST(GF_PROP_4CC_LIST)
    4015             : 
    4016          77 :         DEF_CONST(GF_PROP_PIXFMT)
    4017          77 :         DEF_CONST(GF_PROP_PCMFMT)
    4018          77 :         DEF_CONST(GF_PROP_CICP_COL_PRIM)
    4019          77 :         DEF_CONST(GF_PROP_CICP_COL_TFC)
    4020          77 :         DEF_CONST(GF_PROP_CICP_COL_MX)
    4021             : 
    4022             : 
    4023          77 :         DEF_CONST(GF_FEVT_PLAY)
    4024          77 :         DEF_CONST(GF_FEVT_SET_SPEED)
    4025          77 :         DEF_CONST(GF_FEVT_STOP)
    4026          77 :         DEF_CONST(GF_FEVT_PAUSE)
    4027          77 :         DEF_CONST(GF_FEVT_RESUME)
    4028          77 :         DEF_CONST(GF_FEVT_SOURCE_SEEK)
    4029          77 :         DEF_CONST(GF_FEVT_SOURCE_SWITCH)
    4030          77 :         DEF_CONST(GF_FEVT_SEGMENT_SIZE)
    4031          77 :         DEF_CONST(GF_FEVT_QUALITY_SWITCH)
    4032          77 :         DEF_CONST(GF_FEVT_VISIBILITY_HINT)
    4033          77 :         DEF_CONST(GF_FEVT_INFO_UPDATE)
    4034          77 :         DEF_CONST(GF_FEVT_BUFFER_REQ)
    4035          77 :         DEF_CONST(GF_FEVT_CAPS_CHANGE)
    4036          77 :         DEF_CONST(GF_FEVT_CONNECT_FAIL)
    4037          77 :         DEF_CONST(GF_FEVT_USER)
    4038             : 
    4039          77 :         DEF_CONST(GF_STATS_LOCAL)
    4040          77 :         DEF_CONST(GF_STATS_LOCAL_INPUTS)
    4041          77 :         DEF_CONST(GF_STATS_DECODER_SINK)
    4042          77 :         DEF_CONST(GF_STATS_DECODER_SOURCE)
    4043          77 :         DEF_CONST(GF_STATS_ENCODER_SINK)
    4044          77 :         DEF_CONST(GF_STATS_ENCODER_SOURCE)
    4045             : 
    4046          77 :         DEF_CONST(GF_FILTER_CLOCK_NONE)
    4047          77 :         DEF_CONST(GF_FILTER_CLOCK_PCR)
    4048          77 :         DEF_CONST(GF_FILTER_CLOCK_PCR_DISC)
    4049             : 
    4050          77 :         DEF_CONST(GF_FILTER_SAP_NONE)
    4051          77 :         DEF_CONST(GF_FILTER_SAP_1)
    4052          77 :         DEF_CONST(GF_FILTER_SAP_2)
    4053          77 :         DEF_CONST(GF_FILTER_SAP_3)
    4054          77 :         DEF_CONST(GF_FILTER_SAP_4)
    4055          77 :         DEF_CONST(GF_FILTER_SAP_4_PROL)
    4056             : 
    4057          77 :         DEF_CONST(GF_EOS);
    4058          77 :         DEF_CONST(GF_OK)
    4059          77 :         DEF_CONST(GF_BAD_PARAM)
    4060          77 :         DEF_CONST(GF_OUT_OF_MEM)
    4061          77 :         DEF_CONST(GF_IO_ERR)
    4062          77 :         DEF_CONST(GF_NOT_SUPPORTED)
    4063          77 :         DEF_CONST(GF_CORRUPTED_DATA)
    4064          77 :         DEF_CONST(GF_SG_UNKNOWN_NODE)
    4065          77 :         DEF_CONST(GF_SG_INVALID_PROTO)
    4066          77 :         DEF_CONST(GF_SCRIPT_ERROR)
    4067          77 :         DEF_CONST(GF_BUFFER_TOO_SMALL)
    4068          77 :         DEF_CONST(GF_NON_COMPLIANT_BITSTREAM)
    4069          77 :         DEF_CONST(GF_FILTER_NOT_FOUND)
    4070          77 :         DEF_CONST(GF_URL_ERROR)
    4071          77 :         DEF_CONST(GF_SERVICE_ERROR)
    4072          77 :         DEF_CONST(GF_REMOTE_SERVICE_ERROR)
    4073          77 :         DEF_CONST(GF_STREAM_NOT_FOUND)
    4074          77 :         DEF_CONST(GF_ISOM_INVALID_FILE)
    4075          77 :         DEF_CONST(GF_ISOM_INCOMPLETE_FILE)
    4076          77 :         DEF_CONST(GF_ISOM_INVALID_MEDIA)
    4077          77 :         DEF_CONST(GF_ISOM_INVALID_MODE)
    4078          77 :         DEF_CONST(GF_ISOM_UNKNOWN_DATA_REF)
    4079          77 :         DEF_CONST(GF_ODF_INVALID_DESCRIPTOR)
    4080          77 :         DEF_CONST(GF_ODF_FORBIDDEN_DESCRIPTOR)
    4081          77 :         DEF_CONST(GF_ODF_INVALID_COMMAND)
    4082          77 :         DEF_CONST(GF_BIFS_UNKNOWN_VERSION)
    4083          77 :         DEF_CONST(GF_IP_ADDRESS_NOT_FOUND)
    4084          77 :         DEF_CONST(GF_IP_CONNECTION_FAILURE)
    4085          77 :         DEF_CONST(GF_IP_NETWORK_FAILURE)
    4086          77 :         DEF_CONST(GF_IP_CONNECTION_CLOSED)
    4087          77 :         DEF_CONST(GF_IP_NETWORK_EMPTY)
    4088          77 :         DEF_CONST(GF_IP_SOCK_WOULD_BLOCK)
    4089          77 :         DEF_CONST(GF_IP_UDP_TIMEOUT)
    4090          77 :         DEF_CONST(GF_AUTHENTICATION_FAILURE)
    4091          77 :         DEF_CONST(GF_SCRIPT_NOT_READY)
    4092          77 :         DEF_CONST(GF_INVALID_CONFIGURATION)
    4093          77 :         DEF_CONST(GF_NOT_FOUND)
    4094          77 :         DEF_CONST(GF_PROFILE_NOT_SUPPORTED)
    4095          77 :         DEF_CONST(GF_REQUIRES_NEW_INSTANCE)
    4096          77 :         DEF_CONST(GF_FILTER_NOT_SUPPORTED)
    4097             : 
    4098          77 :         DEF_CONST(JSF_SETUP_ERROR)
    4099          77 :         DEF_CONST(JSF_NOTIF_ERROR)
    4100          77 :         DEF_CONST(JSF_NOTIF_ERROR_AND_DISCONNECT)
    4101             : 
    4102          77 :         DEF_CONST(GF_FILTER_UPDATE_DOWNSTREAM)
    4103          77 :         DEF_CONST(GF_FILTER_UPDATE_UPSTREAM)
    4104             : 
    4105          77 :         DEF_CONST(GF_EVENT_CLICK)
    4106          77 :         DEF_CONST(GF_EVENT_MOUSEUP)
    4107          77 :         DEF_CONST(GF_EVENT_MOUSEDOWN)
    4108          77 :         DEF_CONST(GF_EVENT_MOUSEMOVE)
    4109          77 :         DEF_CONST(GF_EVENT_MOUSEWHEEL)
    4110          77 :         DEF_CONST(GF_EVENT_DBLCLICK)
    4111          77 :         DEF_CONST(GF_EVENT_MULTITOUCH)
    4112          77 :         DEF_CONST(GF_EVENT_KEYUP)
    4113          77 :         DEF_CONST(GF_EVENT_KEYDOWN)
    4114          77 :         DEF_CONST(GF_EVENT_TEXTINPUT)
    4115          77 :         DEF_CONST(GF_EVENT_DROPFILE)
    4116          77 :         DEF_CONST(GF_EVENT_TIMESHIFT_DEPTH)
    4117          77 :         DEF_CONST(GF_EVENT_TIMESHIFT_UPDATE)
    4118          77 :         DEF_CONST(GF_EVENT_TIMESHIFT_OVERFLOW)
    4119          77 :         DEF_CONST(GF_EVENT_TIMESHIFT_UNDERRUN)
    4120          77 :         DEF_CONST(GF_EVENT_PASTE_TEXT)
    4121          77 :         DEF_CONST(GF_EVENT_COPY_TEXT)
    4122          77 :         DEF_CONST(GF_EVENT_SIZE)
    4123          77 :         DEF_CONST(GF_EVENT_SHOWHIDE)
    4124          77 :         DEF_CONST(GF_EVENT_MOVE)
    4125          77 :         DEF_CONST(GF_EVENT_SET_CAPTION)
    4126          77 :         DEF_CONST(GF_EVENT_REFRESH)
    4127          77 :         DEF_CONST(GF_EVENT_QUIT)
    4128             : 
    4129          77 :         DEF_CONST(GF_KEY_UNIDENTIFIED)
    4130          77 :         DEF_CONST(GF_KEY_ACCEPT)
    4131          77 :         DEF_CONST(GF_KEY_AGAIN)
    4132          77 :         DEF_CONST(GF_KEY_ALLCANDIDATES)
    4133          77 :         DEF_CONST(GF_KEY_ALPHANUM)
    4134          77 :         DEF_CONST(GF_KEY_ALT)
    4135          77 :         DEF_CONST(GF_KEY_ALTGRAPH)
    4136          77 :         DEF_CONST(GF_KEY_APPS)
    4137          77 :         DEF_CONST(GF_KEY_ATTN)
    4138          77 :         DEF_CONST(GF_KEY_BROWSERBACK)
    4139          77 :         DEF_CONST(GF_KEY_BROWSERFAVORITES)
    4140          77 :         DEF_CONST(GF_KEY_BROWSERFORWARD)
    4141          77 :         DEF_CONST(GF_KEY_BROWSERHOME)
    4142          77 :         DEF_CONST(GF_KEY_BROWSERREFRESH)
    4143          77 :         DEF_CONST(GF_KEY_BROWSERSEARCH)
    4144          77 :         DEF_CONST(GF_KEY_BROWSERSTOP)
    4145          77 :         DEF_CONST(GF_KEY_CAPSLOCK)
    4146          77 :         DEF_CONST(GF_KEY_CLEAR)
    4147          77 :         DEF_CONST(GF_KEY_CODEINPUT)
    4148          77 :         DEF_CONST(GF_KEY_COMPOSE)
    4149          77 :         DEF_CONST(GF_KEY_CONTROL)
    4150          77 :         DEF_CONST(GF_KEY_CRSEL)
    4151          77 :         DEF_CONST(GF_KEY_CONVERT)
    4152          77 :         DEF_CONST(GF_KEY_COPY)
    4153          77 :         DEF_CONST(GF_KEY_CUT)
    4154          77 :         DEF_CONST(GF_KEY_DOWN)
    4155          77 :         DEF_CONST(GF_KEY_END)
    4156          77 :         DEF_CONST(GF_KEY_ENTER)
    4157          77 :         DEF_CONST(GF_KEY_ERASEEOF)
    4158          77 :         DEF_CONST(GF_KEY_EXECUTE)
    4159          77 :         DEF_CONST(GF_KEY_EXSEL)
    4160          77 :         DEF_CONST(GF_KEY_F1)
    4161          77 :         DEF_CONST(GF_KEY_F2)
    4162          77 :         DEF_CONST(GF_KEY_F3)
    4163          77 :         DEF_CONST(GF_KEY_F4)
    4164          77 :         DEF_CONST(GF_KEY_F5)
    4165          77 :         DEF_CONST(GF_KEY_F6)
    4166          77 :         DEF_CONST(GF_KEY_F7)
    4167          77 :         DEF_CONST(GF_KEY_F8)
    4168          77 :         DEF_CONST(GF_KEY_F9)
    4169          77 :         DEF_CONST(GF_KEY_F10)
    4170          77 :         DEF_CONST(GF_KEY_F11)
    4171          77 :         DEF_CONST(GF_KEY_F12)
    4172          77 :         DEF_CONST(GF_KEY_F13)
    4173          77 :         DEF_CONST(GF_KEY_F14)
    4174          77 :         DEF_CONST(GF_KEY_F15)
    4175          77 :         DEF_CONST(GF_KEY_F16)
    4176          77 :         DEF_CONST(GF_KEY_F17)
    4177          77 :         DEF_CONST(GF_KEY_F18)
    4178          77 :         DEF_CONST(GF_KEY_F19)
    4179          77 :         DEF_CONST(GF_KEY_F20)
    4180          77 :         DEF_CONST(GF_KEY_F21)
    4181          77 :         DEF_CONST(GF_KEY_F22)
    4182          77 :         DEF_CONST(GF_KEY_F23)
    4183          77 :         DEF_CONST(GF_KEY_F24)
    4184          77 :         DEF_CONST(GF_KEY_FINALMODE)
    4185          77 :         DEF_CONST(GF_KEY_FIND)
    4186          77 :         DEF_CONST(GF_KEY_FULLWIDTH)
    4187          77 :         DEF_CONST(GF_KEY_HALFWIDTH)
    4188          77 :         DEF_CONST(GF_KEY_HANGULMODE)
    4189          77 :         DEF_CONST(GF_KEY_HANJAMODE)
    4190          77 :         DEF_CONST(GF_KEY_HELP)
    4191          77 :         DEF_CONST(GF_KEY_HIRAGANA)
    4192          77 :         DEF_CONST(GF_KEY_HOME)
    4193          77 :         DEF_CONST(GF_KEY_INSERT)
    4194          77 :         DEF_CONST(GF_KEY_JAPANESEHIRAGANA)
    4195          77 :         DEF_CONST(GF_KEY_JAPANESEKATAKANA)
    4196          77 :         DEF_CONST(GF_KEY_JAPANESEROMAJI)
    4197          77 :         DEF_CONST(GF_KEY_JUNJAMODE)
    4198          77 :         DEF_CONST(GF_KEY_KANAMODE)
    4199          77 :         DEF_CONST(GF_KEY_KANJIMODE)
    4200          77 :         DEF_CONST(GF_KEY_KATAKANA)
    4201          77 :         DEF_CONST(GF_KEY_LAUNCHAPPLICATION1)
    4202          77 :         DEF_CONST(GF_KEY_LAUNCHAPPLICATION2)
    4203          77 :         DEF_CONST(GF_KEY_LAUNCHMAIL)
    4204          77 :         DEF_CONST(GF_KEY_LEFT)
    4205          77 :         DEF_CONST(GF_KEY_META)
    4206          77 :         DEF_CONST(GF_KEY_MEDIANEXTTRACK)
    4207          77 :         DEF_CONST(GF_KEY_MEDIAPLAYPAUSE)
    4208          77 :         DEF_CONST(GF_KEY_MEDIAPREVIOUSTRACK)
    4209          77 :         DEF_CONST(GF_KEY_MEDIASTOP)
    4210          77 :         DEF_CONST(GF_KEY_MODECHANGE)
    4211          77 :         DEF_CONST(GF_KEY_NONCONVERT)
    4212          77 :         DEF_CONST(GF_KEY_NUMLOCK)
    4213          77 :         DEF_CONST(GF_KEY_PAGEDOWN)
    4214          77 :         DEF_CONST(GF_KEY_PAGEUP)
    4215          77 :         DEF_CONST(GF_KEY_PASTE)
    4216          77 :         DEF_CONST(GF_KEY_PAUSE)
    4217          77 :         DEF_CONST(GF_KEY_PLAY)
    4218          77 :         DEF_CONST(GF_KEY_PREVIOUSCANDIDATE)
    4219          77 :         DEF_CONST(GF_KEY_PRINTSCREEN)
    4220          77 :         DEF_CONST(GF_KEY_PROCESS)
    4221          77 :         DEF_CONST(GF_KEY_PROPS)
    4222          77 :         DEF_CONST(GF_KEY_RIGHT)
    4223          77 :         DEF_CONST(GF_KEY_ROMANCHARACTERS)
    4224          77 :         DEF_CONST(GF_KEY_SCROLL)
    4225          77 :         DEF_CONST(GF_KEY_SELECT)
    4226          77 :         DEF_CONST(GF_KEY_SELECTMEDIA)
    4227          77 :         DEF_CONST(GF_KEY_SHIFT)
    4228          77 :         DEF_CONST(GF_KEY_STOP)
    4229          77 :         DEF_CONST(GF_KEY_UP)
    4230          77 :         DEF_CONST(GF_KEY_UNDO)
    4231          77 :         DEF_CONST(GF_KEY_VOLUMEDOWN)
    4232          77 :         DEF_CONST(GF_KEY_VOLUMEMUTE)
    4233          77 :         DEF_CONST(GF_KEY_VOLUMEUP)
    4234          77 :         DEF_CONST(GF_KEY_WIN)
    4235          77 :         DEF_CONST(GF_KEY_ZOOM)
    4236          77 :         DEF_CONST(GF_KEY_BACKSPACE)
    4237          77 :         DEF_CONST(GF_KEY_TAB)
    4238          77 :         DEF_CONST(GF_KEY_CANCEL)
    4239          77 :         DEF_CONST(GF_KEY_ESCAPE)
    4240          77 :         DEF_CONST(GF_KEY_SPACE)
    4241          77 :         DEF_CONST(GF_KEY_EXCLAMATION)
    4242          77 :         DEF_CONST(GF_KEY_QUOTATION)
    4243          77 :         DEF_CONST(GF_KEY_NUMBER)
    4244          77 :         DEF_CONST(GF_KEY_DOLLAR)
    4245          77 :         DEF_CONST(GF_KEY_AMPERSAND)
    4246          77 :         DEF_CONST(GF_KEY_APOSTROPHE)
    4247          77 :         DEF_CONST(GF_KEY_LEFTPARENTHESIS)
    4248          77 :         DEF_CONST(GF_KEY_RIGHTPARENTHESIS)
    4249          77 :         DEF_CONST(GF_KEY_STAR)
    4250          77 :         DEF_CONST(GF_KEY_PLUS)
    4251          77 :         DEF_CONST(GF_KEY_COMMA)
    4252          77 :         DEF_CONST(GF_KEY_HYPHEN)
    4253          77 :         DEF_CONST(GF_KEY_FULLSTOP)
    4254          77 :         DEF_CONST(GF_KEY_SLASH)
    4255          77 :         DEF_CONST(GF_KEY_0)
    4256          77 :         DEF_CONST(GF_KEY_1)
    4257          77 :         DEF_CONST(GF_KEY_2)
    4258          77 :         DEF_CONST(GF_KEY_3)
    4259          77 :         DEF_CONST(GF_KEY_4)
    4260          77 :         DEF_CONST(GF_KEY_5)
    4261          77 :         DEF_CONST(GF_KEY_6)
    4262          77 :         DEF_CONST(GF_KEY_7)
    4263          77 :         DEF_CONST(GF_KEY_8)
    4264          77 :         DEF_CONST(GF_KEY_9)
    4265          77 :         DEF_CONST(GF_KEY_COLON)
    4266          77 :         DEF_CONST(GF_KEY_SEMICOLON)
    4267          77 :         DEF_CONST(GF_KEY_LESSTHAN)
    4268          77 :         DEF_CONST(GF_KEY_EQUALS)
    4269          77 :         DEF_CONST(GF_KEY_GREATERTHAN)
    4270          77 :         DEF_CONST(GF_KEY_QUESTION)
    4271          77 :         DEF_CONST(GF_KEY_AT)
    4272          77 :         DEF_CONST(GF_KEY_A)
    4273          77 :         DEF_CONST(GF_KEY_B)
    4274          77 :         DEF_CONST(GF_KEY_C)
    4275          77 :         DEF_CONST(GF_KEY_D)
    4276          77 :         DEF_CONST(GF_KEY_E)
    4277          77 :         DEF_CONST(GF_KEY_F)
    4278          77 :         DEF_CONST(GF_KEY_G)
    4279          77 :         DEF_CONST(GF_KEY_H)
    4280          77 :         DEF_CONST(GF_KEY_I)
    4281          77 :         DEF_CONST(GF_KEY_J)
    4282          77 :         DEF_CONST(GF_KEY_K)
    4283          77 :         DEF_CONST(GF_KEY_L)
    4284          77 :         DEF_CONST(GF_KEY_M)
    4285          77 :         DEF_CONST(GF_KEY_N)
    4286          77 :         DEF_CONST(GF_KEY_O)
    4287          77 :         DEF_CONST(GF_KEY_P)
    4288          77 :         DEF_CONST(GF_KEY_Q)
    4289          77 :         DEF_CONST(GF_KEY_R)
    4290          77 :         DEF_CONST(GF_KEY_S)
    4291          77 :         DEF_CONST(GF_KEY_T)
    4292          77 :         DEF_CONST(GF_KEY_U)
    4293          77 :         DEF_CONST(GF_KEY_V)
    4294          77 :         DEF_CONST(GF_KEY_W)
    4295          77 :         DEF_CONST(GF_KEY_X)
    4296          77 :         DEF_CONST(GF_KEY_Y)
    4297          77 :         DEF_CONST(GF_KEY_Z)
    4298          77 :         DEF_CONST(GF_KEY_LEFTSQUAREBRACKET)
    4299          77 :         DEF_CONST(GF_KEY_BACKSLASH)
    4300          77 :         DEF_CONST(GF_KEY_RIGHTSQUAREBRACKET)
    4301          77 :         DEF_CONST(GF_KEY_CIRCUM)
    4302          77 :         DEF_CONST(GF_KEY_UNDERSCORE)
    4303          77 :         DEF_CONST(GF_KEY_GRAVEACCENT)
    4304          77 :         DEF_CONST(GF_KEY_LEFTCURLYBRACKET)
    4305          77 :         DEF_CONST(GF_KEY_PIPE)
    4306          77 :         DEF_CONST(GF_KEY_RIGHTCURLYBRACKET)
    4307          77 :         DEF_CONST(GF_KEY_DEL)
    4308          77 :         DEF_CONST(GF_KEY_INVERTEXCLAMATION)
    4309          77 :         DEF_CONST(GF_KEY_DEADGRAVE)
    4310          77 :         DEF_CONST(GF_KEY_DEADEACUTE)
    4311          77 :         DEF_CONST(GF_KEY_DEADCIRCUM)
    4312          77 :         DEF_CONST(GF_KEY_DEADTILDE)
    4313          77 :         DEF_CONST(GF_KEY_DEADMACRON)
    4314          77 :         DEF_CONST(GF_KEY_DEADBREVE)
    4315          77 :         DEF_CONST(GF_KEY_DEADABOVEDOT)
    4316          77 :         DEF_CONST(GF_KEY_DEADDIARESIS)
    4317          77 :         DEF_CONST(GF_KEY_DEADRINGABOVE)
    4318          77 :         DEF_CONST(GF_KEY_DEADDOUBLEACUTE)
    4319          77 :         DEF_CONST(GF_KEY_DEADCARON)
    4320          77 :         DEF_CONST(GF_KEY_DEADCEDILLA)
    4321          77 :         DEF_CONST(GF_KEY_DEADOGONEK)
    4322          77 :         DEF_CONST(GF_KEY_DEADIOTA)
    4323          77 :         DEF_CONST(GF_KEY_EURO)
    4324          77 :         DEF_CONST(GF_KEY_DEADVOICESOUND)
    4325          77 :         DEF_CONST(GF_KEY_DEADSEMIVOICESOUND)
    4326          77 :         DEF_CONST(GF_KEY_CHANNELUP)
    4327          77 :         DEF_CONST(GF_KEY_CHANNELDOWN)
    4328          77 :         DEF_CONST(GF_KEY_TEXT)
    4329          77 :         DEF_CONST(GF_KEY_INFO)
    4330          77 :         DEF_CONST(GF_KEY_EPG)
    4331          77 :         DEF_CONST(GF_KEY_RECORD)
    4332          77 :         DEF_CONST(GF_KEY_BEGINPAGE)
    4333          77 :         DEF_CONST(GF_KEY_CELL_SOFT1)
    4334          77 :         DEF_CONST(GF_KEY_CELL_SOFT2)
    4335          77 :         DEF_CONST(GF_KEY_JOYSTICK)
    4336             : 
    4337          77 :         DEF_CONST(GF_KEY_MOD_SHIFT)
    4338          77 :         DEF_CONST(GF_KEY_MOD_CTRL)
    4339          77 :         DEF_CONST(GF_KEY_MOD_ALT)
    4340          77 :         DEF_CONST(GF_KEY_EXT_NUMPAD)
    4341          77 :         DEF_CONST(GF_KEY_EXT_LEFT)
    4342          77 :         DEF_CONST(GF_KEY_EXT_RIGHT)
    4343             : 
    4344             : 
    4345          77 :     JS_SetPropertyStr(ctx, global_obj, "print", JS_NewCFunction(ctx, js_print, "print", 1));
    4346          77 :     JS_SetPropertyStr(ctx, global_obj, "alert", JS_NewCFunction(ctx, js_print, "alert", 1));
    4347             : 
    4348             : 
    4349             :         //initialize filter event class
    4350          77 :         JS_NewClassID(&jsf_event_class_id);
    4351          77 :         JS_NewClass(JS_GetRuntime(ctx), jsf_event_class_id, &jsf_event_class);
    4352          77 :         JSValue evt_proto = JS_NewObjectClass(ctx, jsf_event_class_id);
    4353          77 :     JS_SetPropertyFunctionList(ctx, evt_proto, jsf_event_funcs, countof(jsf_event_funcs));
    4354          77 :     JS_SetClassProto(ctx, jsf_event_class_id, evt_proto);
    4355             : 
    4356          77 :         JSValue evt_ctor = JS_NewCFunction2(ctx, jsf_event_constructor, "FilterEvent", 1, JS_CFUNC_constructor, 0);
    4357          77 :     JS_SetPropertyStr(ctx, global_obj, "FilterEvent", evt_ctor);
    4358             : 
    4359          77 : }
    4360             : 
    4361          42 : static GF_Err jsfilter_initialize_ex(GF_Filter *filter, JSContext *custom_ctx)
    4362             : {
    4363             :         u8 *buf;
    4364             :         u32 buf_len;
    4365             :         u32 flags = JS_EVAL_TYPE_GLOBAL;
    4366             :     JSValue ret;
    4367             :     JSValue global_obj;
    4368             :     u32 i;
    4369             :     JSRuntime *rt;
    4370          42 :         GF_JSFilterCtx *jsf = gf_filter_get_udta(filter);
    4371             : 
    4372          42 :         if (custom_ctx) {
    4373           1 :                 GF_SAFEALLOC(jsf, GF_JSFilterCtx);
    4374           1 :                 filter->filter_udta = jsf;
    4375             :         }
    4376             : 
    4377          42 :         jsf->filter = filter;
    4378          42 :         jsf->pids = gf_list_new();
    4379          42 :         jsf->pck_res = gf_list_new();
    4380          42 :         jsf->log_name = gf_strdup(custom_ctx ? filter->name : "JSF");
    4381             : 
    4382          42 :         if (custom_ctx) {
    4383           1 :                 jsf->ctx = custom_ctx;
    4384           1 :                 jsf->is_custom = GF_TRUE;
    4385           1 :                 global_obj = JS_GetGlobalObject(jsf->ctx);
    4386             :         } else {
    4387          41 :                 if (!jsf->js) {
    4388           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_SCRIPT, ("[JSF] Missing script file\n"));
    4389             :                         return GF_BAD_PARAM;
    4390             :                 }
    4391          41 :                 if (!gf_file_exists(jsf->js)) {
    4392           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_SCRIPT, ("[JSF] Script file %s does not exist\n", jsf->js));
    4393             :                         return GF_BAD_PARAM;
    4394             :                 }
    4395          41 :                 jsf->filter_obj = JS_UNDEFINED;
    4396             : 
    4397          41 :                 jsf->ctx = gf_js_create_context();
    4398          41 :                 if (!jsf->ctx) {
    4399           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_SCRIPT, ("[JSF] Failed to load QuickJS context\n"));
    4400             :                         return GF_IO_ERR;
    4401             :                 }
    4402          41 :                 JS_SetContextOpaque(jsf->ctx, jsf);
    4403          41 :                 global_obj = JS_GetGlobalObject(jsf->ctx);
    4404          41 :                 js_load_constants(jsf->ctx, global_obj);
    4405             :         }
    4406          42 :         rt = JS_GetRuntime(jsf->ctx);
    4407             : 
    4408             : 
    4409             : 
    4410             :         //initialize filter class and create a single filter object in global scope
    4411          42 :         JS_NewClassID(&jsf_filter_class_id);
    4412          42 :         JS_NewClass(rt, jsf_filter_class_id, &jsf_filter_class);
    4413             : 
    4414          42 :         jsf->filter_obj = JS_NewObjectClass(jsf->ctx, jsf_filter_class_id);
    4415          42 :     JS_SetPropertyFunctionList(jsf->ctx, jsf->filter_obj, jsf_filter_funcs, countof(jsf_filter_funcs));
    4416          42 :     JS_SetOpaque(jsf->filter_obj, jsf);
    4417          42 :     if (!custom_ctx)
    4418          41 :                 JS_SetPropertyStr(jsf->ctx, global_obj, "filter", jsf->filter_obj);
    4419             : 
    4420             :         //initialize filter instance class
    4421          42 :         JS_NewClassID(&jsf_filter_inst_class_id);
    4422          42 :         JS_NewClass(rt, jsf_filter_inst_class_id, &jsf_filter_inst_class);
    4423          42 :         JSValue finst_proto = JS_NewObjectClass(jsf->ctx, jsf_filter_inst_class_id);
    4424          42 :     JS_SetPropertyFunctionList(jsf->ctx, finst_proto, jsf_filter_inst_funcs, countof(jsf_filter_inst_funcs));
    4425          42 :     JS_SetClassProto(jsf->ctx, jsf_filter_inst_class_id, finst_proto);
    4426             : 
    4427             :         //initialize filter pid class
    4428          42 :         JS_NewClassID(&jsf_pid_class_id);
    4429          42 :         JS_NewClass(rt, jsf_pid_class_id, &jsf_pid_class);
    4430          42 :         JSValue pid_proto = JS_NewObjectClass(jsf->ctx, jsf_pid_class_id);
    4431          42 :     JS_SetPropertyFunctionList(jsf->ctx, pid_proto, jsf_pid_funcs, countof(jsf_pid_funcs));
    4432          42 :     JS_SetClassProto(jsf->ctx, jsf_pid_class_id, pid_proto);
    4433             : 
    4434             : 
    4435             :         //initialize filter packet class
    4436          42 :         JS_NewClassID(&jsf_pck_class_id);
    4437          42 :         JS_NewClass(rt, jsf_pck_class_id, &jsf_pck_class);
    4438          42 :         JSValue pck_proto = JS_NewObjectClass(jsf->ctx, jsf_pck_class_id);
    4439          42 :     JS_SetPropertyFunctionList(jsf->ctx, pck_proto, jsf_pck_funcs, countof(jsf_pck_funcs));
    4440          42 :     JS_SetClassProto(jsf->ctx, jsf_pck_class_id, pck_proto);
    4441             : 
    4442          42 :     if (!custom_ctx)
    4443          41 :                 JS_SetPropertyStr(jsf->ctx, global_obj, "_gpac_log_name", JS_NewString(jsf->ctx, gf_file_basename(jsf->js) ) );
    4444             : 
    4445          42 :     JS_FreeValue(jsf->ctx, global_obj);
    4446             : 
    4447          42 :     if (custom_ctx) return GF_OK;
    4448             : 
    4449             : 
    4450             :         //load script
    4451          41 :         GF_Err e = gf_file_load_data(jsf->js, &buf, &buf_len);
    4452          41 :         if (e) {
    4453           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_SCRIPT, ("[JSF] Error loading script file %s: %s\n", jsf->js, gf_error_to_string(e) ));
    4454             :                 return e;
    4455             :         }
    4456             : 
    4457          41 :         if (strstr(buf, "session.")) {
    4458             :                 GF_Err gf_fs_load_js_api(JSContext *c, GF_FilterSession *fs);
    4459             : //              GF_FilterSession *fs = sjs->compositor->filter->session;
    4460             : 
    4461           0 :                 e = gf_fs_load_js_api(jsf->ctx, filter->session);
    4462           0 :                 if (e) {
    4463           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_SCRIPT, ("[JSF] Error loading session API: %s\n", gf_error_to_string(e) ));
    4464             :                         return e;
    4465             :                 }
    4466           0 :                 jsf->unload_session_api = GF_TRUE;
    4467             :         }
    4468             : 
    4469         410 :         for (i=0; i<JSF_EVT_LAST_DEFINED; i++) {
    4470         410 :         jsf->funcs[i] = JS_UNDEFINED;
    4471             :     }
    4472             : 
    4473             : 
    4474          41 :         if (!gf_opts_get_bool("core", "no-js-mods") && JS_DetectModule((char *)buf, buf_len)) {
    4475             :                 //init modules
    4476          33 :                 qjs_module_init_gpaccore(jsf->ctx);
    4477          33 :                 qjs_module_init_xhr(jsf->ctx);
    4478          33 :                 qjs_module_init_evg(jsf->ctx);
    4479          33 :                 qjs_module_init_storage(jsf->ctx);
    4480          33 :                 qjs_module_init_webgl(jsf->ctx);
    4481             :                 flags = JS_EVAL_TYPE_MODULE;
    4482             :         }
    4483          41 :         jsf->disable_filter = GF_TRUE;
    4484          41 :         ret = JS_Eval(jsf->ctx, (char *)buf, buf_len, jsf->js, flags);
    4485          41 :         gf_free(buf);
    4486             : 
    4487          41 :         if (JS_IsException(ret)) {
    4488           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_SCRIPT, ("[JSF] Error loading script %s\n", jsf->js));
    4489           0 :         js_dump_error(jsf->ctx);
    4490           0 :                 JS_FreeValue(jsf->ctx, ret);
    4491             :                 return GF_BAD_PARAM;
    4492             :         }
    4493          41 :         JS_FreeValue(jsf->ctx, ret);
    4494             :         return GF_OK;
    4495             : }
    4496             : 
    4497             : 
    4498          41 : static GF_Err jsfilter_initialize(GF_Filter *filter)
    4499             : {
    4500          41 :         return jsfilter_initialize_ex(filter, NULL);
    4501             : }
    4502             : 
    4503          42 : static void jsfilter_finalize(GF_Filter *filter)
    4504             : {
    4505             :         u32 i, count;
    4506          42 :         GF_JSFilterCtx *jsf = gf_filter_get_udta(filter);
    4507          42 :         if (!jsf->ctx) return;
    4508             : 
    4509             :         //reset references but do not destroy PIDs yet
    4510          42 :         count = gf_list_count(jsf->pids);
    4511          88 :         for (i=0; i<count; i++) {
    4512          46 :                 GF_JSPidCtx *pctx = gf_list_get(jsf->pids, i);
    4513          46 :                 JS_FreeValue(jsf->ctx, pctx->jsobj);
    4514          46 :                 if (pctx->shared_pck) {
    4515           2 :                         while (gf_list_count(pctx->shared_pck)) {
    4516           0 :                                 GF_JSPckCtx *pckc = gf_list_pop_back(pctx->shared_pck);
    4517           0 :                                 JS_FreeValue(jsf->ctx, pckc->ref_val);
    4518           0 :                                 pckc->ref_val = JS_UNDEFINED;
    4519           0 :                                 jsf_pck_detach_ab(jsf->ctx, pckc);
    4520             : 
    4521             :                                 //do not free here since pck->jsobj may already have been GCed/destroyed
    4522             :                         }
    4523             :                 }
    4524             :         }
    4525             : 
    4526         420 :         for (i=0; i<JSF_EVT_LAST_DEFINED; i++) {
    4527         420 :                 JS_FreeValue(jsf->ctx, jsf->funcs[i]);
    4528             :         }
    4529             : 
    4530          42 :         JS_SetOpaque(jsf->filter_obj, NULL);
    4531             : 
    4532          42 :         if (jsf->unload_session_api)
    4533           0 :                 gf_fs_unload_script(filter->session, jsf->ctx);
    4534             : 
    4535          42 :         if (!jsf->is_custom)
    4536          41 :                 gf_js_delete_context(jsf->ctx);
    4537             : 
    4538          88 :         while (gf_list_count(jsf->pids)) {
    4539          46 :                 GF_JSPidCtx *pctx = gf_list_pop_back(jsf->pids);
    4540          46 :                 if (pctx->shared_pck)
    4541           2 :                         gf_list_del(pctx->shared_pck);
    4542          46 :                 gf_free(pctx);
    4543             :         }
    4544          42 :         gf_list_del(jsf->pids);
    4545             : 
    4546          42 :         if (jsf->log_name) gf_free(jsf->log_name);
    4547             : 
    4548          78 :         while (gf_list_count(jsf->pck_res)) {
    4549          36 :                 GF_JSPckCtx *pck = gf_list_pop_back(jsf->pck_res);
    4550          36 :                 gf_free(pck);
    4551             :         }
    4552          42 :         gf_list_del(jsf->pck_res);
    4553             : 
    4554          42 :         if (jsf->args) {
    4555         146 :                 for (i=0; i<jsf->nb_args; i++) {
    4556         146 :                         if (jsf->args[i].arg_default_val)
    4557         132 :                                 gf_free((char *) jsf->args[i].arg_default_val);
    4558         146 :                         if (jsf->args[i].arg_desc)
    4559         146 :                                 gf_free((char *) jsf->args[i].arg_desc);
    4560         146 :                         if (jsf->args[i].arg_name)
    4561         146 :                                 gf_free((char *) jsf->args[i].arg_name);
    4562         146 :                         if (jsf->args[i].min_max_enum)
    4563          10 :                                 gf_free((char *) jsf->args[i].min_max_enum);
    4564             :                 }
    4565          36 :                 gf_free(jsf->args);
    4566             :         }
    4567             : 
    4568          42 :         if (jsf->caps) gf_free(jsf->caps);
    4569             : }
    4570             : 
    4571             : 
    4572             : 
    4573         200 : static GF_Err jsfilter_update_arg(GF_Filter *filter, const char *arg_name, const GF_PropertyValue *new_val)
    4574             : {
    4575         200 :         GF_JSFilterCtx *jsf = gf_filter_get_udta(filter);
    4576             :         JSValue ret, val;
    4577             :         const GF_FilterArgs *the_arg = NULL;
    4578             :         u32 i;
    4579         200 :         GF_Err e = GF_OK;
    4580         200 :         if (!jsf->ctx)
    4581             :                 return GF_OK;
    4582             : 
    4583         200 :         if (!arg_name && !new_val) {
    4584          41 :                 gf_js_lock(jsf->ctx, GF_TRUE);
    4585          41 :                 if (JS_IsFunction(jsf->ctx, jsf->funcs[JSF_EVT_INITIALIZE]) ) {
    4586          41 :                         ret = JS_Call(jsf->ctx, jsf->funcs[JSF_EVT_INITIALIZE], jsf->filter_obj, 0, NULL);
    4587          41 :                         if (JS_IsException(ret)) {
    4588           1 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_SCRIPT, ("[%s] Error initializing filter\n", jsf->log_name));
    4589           1 :                                 js_dump_error(jsf->ctx);
    4590           1 :                                 JS_FreeValue(jsf->ctx, ret);
    4591           1 :                                 gf_js_lock(jsf->ctx, GF_FALSE);
    4592           1 :                                 return GF_BAD_PARAM;
    4593             :                         }
    4594          40 :                         if (JS_IsInteger(ret))
    4595           1 :                                 JS_ToInt32(jsf->ctx, (int*)&e, ret);
    4596             : 
    4597          40 :                         JS_FreeValue(jsf->ctx, ret);
    4598             :                 }
    4599          40 :                 jsf->initialized = GF_TRUE;
    4600             :                 //we still call initialize even in help-only mode to properly print links and cap bundles
    4601          40 :                 if (gf_opts_get_bool("temp", "helponly"))
    4602           6 :                         jsf->disable_filter = GF_TRUE;
    4603             : 
    4604             :                 //filter object not used (no new_pid, post_task or set_cap), disable it
    4605          40 :                 if (jsf->disable_filter) {
    4606             :                         JSAtom prop;
    4607          10 :                         JSValue global_obj = JS_GetGlobalObject(jsf->ctx);
    4608          10 :                         prop = JS_NewAtom(jsf->ctx, "filter");
    4609          10 :                         JS_DeleteProperty(jsf->ctx, global_obj, prop, 0);
    4610          10 :                         JS_FreeValue(jsf->ctx, global_obj);
    4611          10 :                         JS_FreeAtom(jsf->ctx, prop);
    4612          10 :                         filter->disabled = GF_TRUE;
    4613          10 :                         jsf->filter_obj = JS_UNDEFINED;
    4614             :                 }
    4615          40 :                 gf_js_lock(jsf->ctx, GF_FALSE);
    4616          40 :                 return e;
    4617             :         }
    4618         159 :         if (!arg_name || (jsf->initialized && jsf->disable_filter))
    4619             :                 return GF_OK;
    4620             : 
    4621         875 :         for (i=0; i<jsf->nb_args; i++) {
    4622        1034 :                 if (jsf->args[i].arg_name && !strcmp(jsf->args[i].arg_name, arg_name)) {
    4623             :                         the_arg = &jsf->args[i];
    4624             :                         break;
    4625             :                 }
    4626             :         }
    4627         159 :         if (!the_arg && !jsf->has_wilcard_arg) return GF_OK;
    4628             : 
    4629         159 :         gf_js_lock(jsf->ctx, GF_TRUE);
    4630             : 
    4631         159 :         val = jsf_NewProp(jsf->ctx, new_val);
    4632         159 :         if (!jsf->initialized) {
    4633         159 :         JS_SetPropertyStr(jsf->ctx, jsf->filter_obj, arg_name, val);
    4634         159 :                 gf_js_lock(jsf->ctx, GF_FALSE);
    4635         159 :                 return GF_OK;
    4636             :         }
    4637             : 
    4638             :         JSValue args[2];
    4639           0 :         args[0] = JS_NewString(jsf->ctx, arg_name);
    4640           0 :         args[1] = val;
    4641           0 :         ret = JS_Call(jsf->ctx, jsf->funcs[JSF_EVT_UPDATE_ARG], jsf->filter_obj, 2, args);
    4642           0 :         if (JS_IsException(ret)) {
    4643           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_SCRIPT, ("[%s] Error updating arg\n", jsf->log_name));
    4644           0 :         js_dump_error(jsf->ctx);
    4645           0 :                 e = GF_BAD_PARAM;
    4646             :         }
    4647           0 :         if (JS_IsInteger(ret))
    4648           0 :                 JS_ToInt32(jsf->ctx, (int*)&e, ret);
    4649           0 :         JS_FreeValue(jsf->ctx, ret);
    4650           0 :         JS_FreeValue(jsf->ctx, args[0]);
    4651           0 :         JS_FreeValue(jsf->ctx, args[1]);
    4652           0 :         gf_js_lock(jsf->ctx, GF_FALSE);
    4653           0 :         return e;
    4654             : }
    4655             : 
    4656         412 : JSValue js_init_evt_obj(JSContext *ctx, const GF_FilterEvent *evt)
    4657             : {
    4658         412 :         JSValue v = JS_NewObjectClass(ctx, jsf_event_class_id);
    4659         412 :         JS_SetOpaque(v, (void *) evt);
    4660         412 :         return v;
    4661             : }
    4662             : 
    4663         996 : static Bool jsfilter_process_event(GF_Filter *filter, const GF_FilterEvent *evt)
    4664             : {
    4665             :         JSValue argv[2];
    4666             :         JSValue ret;
    4667             :         Bool canceled=GF_TRUE;
    4668         996 :         GF_JSFilterCtx *jsf = gf_filter_get_udta(filter);
    4669         996 :         if (!jsf) return GF_TRUE;
    4670             : 
    4671         996 :         if (!JS_IsFunction(jsf->ctx, jsf->funcs[JSF_EVT_PROCESS_EVENT]))
    4672             :                 return GF_FALSE;
    4673             : 
    4674         327 :         gf_js_lock(jsf->ctx, GF_TRUE);
    4675         327 :         if (evt->base.on_pid) {
    4676         326 :                 GF_JSPidCtx *pctx = gf_filter_pid_get_udta(evt->base.on_pid);
    4677         652 :                 argv[0] = pctx ? JS_DupValue(jsf->ctx, pctx->jsobj) : JS_NULL;
    4678             :         } else {
    4679           1 :                 argv[0] = JS_NULL;
    4680             :         }
    4681         327 :         argv[1] = js_init_evt_obj(jsf->ctx, evt);
    4682             : 
    4683         327 :         ret = JS_Call(jsf->ctx, jsf->funcs[JSF_EVT_PROCESS_EVENT], jsf->filter_obj, 2, argv);
    4684         327 :         if (JS_IsException(ret)) {
    4685           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_SCRIPT, ("[%s] Error processing event\n", jsf->log_name));
    4686           0 :                 js_dump_error(jsf->ctx);
    4687             :         }
    4688             :         else {
    4689         327 :                 canceled = JS_ToBool(jsf->ctx, ret);
    4690             :         }
    4691         327 :         JS_FreeValue(jsf->ctx, ret);
    4692         327 :         JS_FreeValue(jsf->ctx, argv[0]);
    4693         327 :         JS_SetOpaque(argv[1], NULL);
    4694         327 :         JS_FreeValue(jsf->ctx, argv[1]);
    4695         327 :         gf_js_lock(jsf->ctx, GF_FALSE);
    4696             : 
    4697         327 :         js_do_loop(jsf->ctx);
    4698         327 :         return canceled;
    4699             : }
    4700             : 
    4701             : /*static GF_Err jsfilter_reconfigure_output(GF_Filter *filter, GF_FilterPid *PID)
    4702             : {
    4703             :         return GF_NOT_SUPPORTED;
    4704             : }
    4705             : 
    4706             : static GF_FilterProbeScore jsfilter_probe_url(const char *url, const char *mime)
    4707             : {
    4708             :         return GF_FPROBE_NOT_SUPPORTED;
    4709             : }
    4710             : 
    4711             : static const char * jsfilter_probe_data(const u8 *data, u32 size, GF_FilterProbeScore *score)
    4712             : {
    4713             :         return NULL;
    4714             : }
    4715             : */
    4716             : 
    4717             : #define OFFS(_n)        #_n, offsetof(GF_JSFilterCtx, _n)
    4718             : static GF_FilterArgs JSFilterArgs[] =
    4719             : {
    4720             :         { OFFS(js), "location of script source", GF_PROP_NAME, NULL, NULL, 0},
    4721             :         { "*", -1, "any possible options defined for the script. See `gpac -hx jsf:js=$YOURSCRIPT`", GF_PROP_STRING, NULL, NULL, GF_FS_ARG_META},
    4722             :         {0}
    4723             : };
    4724             : 
    4725             : static const GF_FilterCapability JSFilterCaps[] =
    4726             : {
    4727             :         CAP_UINT(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_STREAM_TYPE, GF_STREAM_UNKNOWN),
    4728             :         CAP_UINT(GF_CAPS_OUTPUT_EXCLUDED, GF_PROP_PID_STREAM_TYPE, GF_STREAM_UNKNOWN),
    4729             : };
    4730             : 
    4731             : GF_FilterRegister JSFilterRegister = {
    4732             :         .name = "jsf",
    4733             :         GF_FS_SET_DESCRIPTION("JavaScript filter")
    4734             :         GF_FS_SET_HELP("This filter runs a javascript file specified in [-js]() defining a new JavaScript filter.\n"
    4735             :         "  \n"
    4736             :         "For more information on how to use JS filters, please check https://wiki.gpac.io/jsfilter\n")
    4737             :         .private_size = sizeof(GF_JSFilterCtx),
    4738             :         .flags = GF_FS_REG_SCRIPT,
    4739             :         .args = JSFilterArgs,
    4740             :         SETCAPS(JSFilterCaps),
    4741             :         .initialize = jsfilter_initialize,
    4742             :         .finalize = jsfilter_finalize,
    4743             :         .configure_pid = jsfilter_configure_pid,
    4744             :         .process = jsfilter_process,
    4745             :         .update_arg = jsfilter_update_arg,
    4746             :         .process_event = jsfilter_process_event,
    4747             : //      .probe_url = jsfilter_probe_url,
    4748             : //      .probe_data = jsfilter_probe_data
    4749             : //      .reconfigure_output = jsfilter_reconfigure_output
    4750             : };
    4751             : 
    4752             : 
    4753        2877 : const GF_FilterRegister *jsfilter_register(GF_FilterSession *session)
    4754             : {
    4755        2877 :         return &JSFilterRegister;
    4756             : }
    4757             : 
    4758             : 
    4759           1 : JSValue jsfilter_initialize_custom(GF_Filter *filter, JSContext *ctx)
    4760             : {
    4761             :         GF_JSFilterCtx *jsf;
    4762           1 :         GF_Err e = jsfilter_initialize_ex(filter, ctx);
    4763           1 :         if (e) return js_throw_err(ctx, e);
    4764           1 :         jsf = gf_filter_get_udta(filter);
    4765           1 :         ((GF_FilterRegister *) filter->freg)->finalize = jsfilter_finalize;
    4766           1 :         ((GF_FilterRegister *) filter->freg)->process = jsfilter_process;
    4767           1 :         ((GF_FilterRegister *) filter->freg)->configure_pid = jsfilter_configure_pid;
    4768           1 :         ((GF_FilterRegister *) filter->freg)->process_event = jsfilter_process_event;
    4769             : //      ((GF_FilterRegister *) filter->freg)->reconfigure_output = jsfilter_reconfigure_output;
    4770             : //      ((GF_FilterRegister *) filter->freg)->probe_data = jsfilter_probe_data;
    4771             :         //signal reg is script, so we don't free the filter reg caps as with custom filters
    4772           1 :         ((GF_FilterRegister *) filter->freg)->flags |= GF_FS_REG_SCRIPT;
    4773           1 :         return jsf->filter_obj;
    4774             : }
    4775             : 
    4776             : #else
    4777             : 
    4778             : const GF_FilterRegister *jsfilter_register(GF_FilterSession *session)
    4779             : {
    4780             :         return NULL;
    4781             : }
    4782             : 
    4783             : #endif
    4784             : 

Generated by: LCOV version 1.13