1 /*
2 * GPAC - Multimedia Framework C SDK
3 *
4 * Authors: Jean Le Feuvre
5 * Copyright (c) Telecom ParisTech 2007-2012
6 * All rights reserved
7 *
8 * This file is part of GPAC / User Event Recorder sub-project
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 /*base SVG type*/
27 #include <gpac/modules/term_ext.h>
28 #include <gpac/internal/terminal_dev.h>
29 #include <gpac/internal/compositor_dev.h>
30
31
32 typedef struct __ui_rec
33 {
34 FILE *uif;
35 GF_BitStream *bs;
36 GF_Terminal *term;
37 GF_Clock *ck;
38
39 GF_Event next_event;
40 u32 next_time;
41 Bool evt_loaded;
42
43 GF_TermEventFilter evt_filter;
44 } GF_UIRecord;
45
uir_on_event_play(GF_UIRecord * uir,GF_Event * event,Bool consumed_by_compositor)46 Bool uir_on_event_play(GF_UIRecord *uir , GF_Event *event, Bool consumed_by_compositor)
47 {
48 switch (event->type) {
49 case GF_EVENT_CONNECT:
50 if (event->connect.is_connected) {
51 uir->ck = uir->term->root_scene->scene_codec ? uir->term->root_scene->scene_codec->ck : uir->term->root_scene->dyn_ck;
52 }
53 break;
54 }
55 return GF_FALSE;
56 }
57
uir_on_event_record(GF_UIRecord * uir,GF_Event * event,Bool consumed_by_compositor)58 Bool uir_on_event_record(GF_UIRecord *uir , GF_Event *event, Bool consumed_by_compositor)
59 {
60 switch (event->type) {
61 case GF_EVENT_CONNECT:
62 if (event->connect.is_connected) {
63 uir->ck = uir->term->root_scene->scene_codec ? uir->term->root_scene->scene_codec->ck : uir->term->root_scene->dyn_ck;
64 }
65 break;
66 case GF_EVENT_CLICK:
67 case GF_EVENT_MOUSEUP:
68 case GF_EVENT_MOUSEDOWN:
69 case GF_EVENT_MOUSEOVER:
70 case GF_EVENT_MOUSEOUT:
71 /*!! ALL MOUSE EVENTS SHALL BE DECLARED BEFORE MOUSEMOVE !! */
72 case GF_EVENT_MOUSEMOVE:
73 /*mouse wheel event*/
74 case GF_EVENT_MOUSEWHEEL:
75 gf_bs_write_u32(uir->bs, gf_clock_time(uir->ck) );
76 gf_bs_write_u8(uir->bs, event->type);
77 gf_bs_write_u8(uir->bs, event->mouse.button);
78 gf_bs_write_u32(uir->bs, event->mouse.x);
79 gf_bs_write_u32(uir->bs, event->mouse.y);
80 gf_bs_write_float(uir->bs, FIX2FLT(event->mouse.wheel_pos) );
81 gf_bs_write_u8(uir->bs, event->mouse.key_states);
82 break;
83 /*Key Events*/
84 case GF_EVENT_KEYUP:
85 case GF_EVENT_KEYDOWN:
86 case GF_EVENT_LONGKEYPRESS:
87 gf_bs_write_u32(uir->bs, gf_clock_time(uir->ck) );
88 gf_bs_write_u8(uir->bs, event->type);
89 gf_bs_write_u32(uir->bs, event->key.key_code);
90 gf_bs_write_u32(uir->bs, event->key.hw_code);
91 gf_bs_write_u32(uir->bs, event->key.flags);
92 break;
93 /*character input*/
94 case GF_EVENT_TEXTINPUT:
95 gf_bs_write_u32(uir->bs, gf_clock_time(uir->ck) );
96 gf_bs_write_u8(uir->bs, event->type);
97 gf_bs_write_u32(uir->bs, event->character.unicode_char);
98 break;
99 }
100 return GF_FALSE;
101 }
102
uir_load_event(GF_UIRecord * uir)103 void uir_load_event(GF_UIRecord *uir)
104 {
105 memset(&uir->next_event, 0, sizeof(GF_Event));
106 uir->evt_loaded = GF_FALSE;
107 if (!gf_bs_available(uir->bs)) return;
108
109
110 uir->next_time = gf_bs_read_u32(uir->bs);
111 uir->next_event.type = gf_bs_read_u8(uir->bs);
112 switch (uir->next_event.type) {
113 case GF_EVENT_CLICK:
114 case GF_EVENT_MOUSEUP:
115 case GF_EVENT_MOUSEDOWN:
116 case GF_EVENT_MOUSEOVER:
117 case GF_EVENT_MOUSEOUT:
118 /*!! ALL MOUSE EVENTS SHALL BE DECLARED BEFORE MOUSEMOVE !! */
119 case GF_EVENT_MOUSEMOVE:
120 /*mouse wheel event*/
121 case GF_EVENT_MOUSEWHEEL:
122 uir->next_event.mouse.button = gf_bs_read_u8(uir->bs);
123 uir->next_event.mouse.x = gf_bs_read_u32(uir->bs);
124 uir->next_event.mouse.y = gf_bs_read_u32(uir->bs);
125 uir->next_event.mouse.wheel_pos = FLT2FIX( gf_bs_read_float(uir->bs) );
126 uir->next_event.mouse.key_states = gf_bs_read_u8(uir->bs);
127 break;
128 /*Key Events*/
129 case GF_EVENT_KEYUP:
130 case GF_EVENT_KEYDOWN:
131 case GF_EVENT_LONGKEYPRESS:
132 uir->next_event.key.key_code = gf_bs_read_u32(uir->bs);
133 uir->next_event.key.hw_code = gf_bs_read_u32(uir->bs);
134 uir->next_event.key.flags = gf_bs_read_u32(uir->bs);
135 break;
136 /*character input*/
137 case GF_EVENT_TEXTINPUT:
138 uir->next_event.character.unicode_char = gf_bs_read_u32(uir->bs);
139 break;
140 }
141 uir->evt_loaded = GF_TRUE;
142 }
143
uir_process(GF_TermExt * termext,u32 action,void * param)144 static Bool uir_process(GF_TermExt *termext, u32 action, void *param)
145 {
146 const char *opt, *uifile;
147 GF_UIRecord *uir = (GF_UIRecord*)termext->udta;
148
149 switch (action) {
150 case GF_TERM_EXT_START:
151 uir->term = (GF_Terminal *) param;
152 opt = gf_opts_get_key("UIRecord", "Mode");
153 if (!opt) return GF_FALSE;
154 uifile = gf_opts_get_key("UIRecord", "File");
155 if (!uifile) return GF_FALSE;
156
157 if (!strcmp(opt, "Play")) {
158 uir->uif = gf_fopen(uifile, "rb");
159 if (!uir->uif) return GF_FALSE;
160 uir->bs = gf_bs_from_file(uir->uif, GF_BITSTREAM_READ);
161 termext->caps |= GF_TERM_EXTENSION_NOT_THREADED;
162
163 uir->evt_filter.on_event = uir_on_event_play;
164 uir->evt_filter.udta = uir;
165 gf_term_add_event_filter(uir->term, &uir->evt_filter);
166
167 uir_load_event(uir);
168 } else if (!strcmp(opt, "Record")) {
169 uir->uif = gf_fopen(uifile, "wb");
170 if (!uir->uif) return GF_FALSE;
171 uir->bs = gf_bs_from_file(uir->uif, GF_BITSTREAM_WRITE);
172
173 uir->evt_filter.on_event = uir_on_event_record;
174 uir->evt_filter.udta = uir;
175 gf_term_add_event_filter(uir->term, &uir->evt_filter);
176 } else {
177 return GF_FALSE;
178 }
179 return GF_TRUE;
180
181 case GF_TERM_EXT_STOP:
182 if (uir->uif) gf_fclose(uir->uif);
183 if (uir->bs) gf_bs_del(uir->bs);
184 gf_term_remove_event_filter(uir->term, &uir->evt_filter);
185 uir->term = NULL;
186 /*auto-disable the plugin by default*/
187 gf_opts_set_key("UIRecord", "Mode", "Disable");
188 break;
189
190 case GF_TERM_EXT_PROCESS:
191 /*flush all events until current time if reached*/
192 while (uir->evt_loaded && uir->ck && (uir->next_time <= gf_clock_time(uir->ck) )) {
193 uir->term->compositor->video_out->on_event(uir->term->compositor->video_out->evt_cbk_hdl, &uir->next_event);
194 uir_load_event(uir);
195 }
196 break;
197 }
198 return GF_FALSE;
199 }
200
201
uir_new()202 GF_TermExt *uir_new()
203 {
204 GF_TermExt *dr;
205 GF_UIRecord *uir;
206 dr = (GF_TermExt*)gf_malloc(sizeof(GF_TermExt));
207 memset(dr, 0, sizeof(GF_TermExt));
208 GF_REGISTER_MODULE_INTERFACE(dr, GF_TERM_EXT_INTERFACE, "GPAC UI Recorder", "gpac distribution");
209
210 GF_SAFEALLOC(uir, GF_UIRecord);
211 dr->process = uir_process;
212 dr->udta = uir;
213 return dr;
214 }
215
216
uir_delete(GF_BaseInterface * ifce)217 void uir_delete(GF_BaseInterface *ifce)
218 {
219 GF_TermExt *dr = (GF_TermExt *) ifce;
220 GF_UIRecord *uir = (GF_UIRecord*)dr->udta;
221 gf_free(uir);
222 gf_free(dr);
223 }
224
225 GPAC_MODULE_EXPORT
QueryInterfaces()226 const u32 *QueryInterfaces()
227 {
228 static u32 si [] = {
229 GF_TERM_EXT_INTERFACE,
230 0
231 };
232 return si;
233 }
234
235 GPAC_MODULE_EXPORT
LoadInterface(u32 InterfaceType)236 GF_BaseInterface *LoadInterface(u32 InterfaceType)
237 {
238 if (InterfaceType == GF_TERM_EXT_INTERFACE) return (GF_BaseInterface *)uir_new();
239 return NULL;
240 }
241
242 GPAC_MODULE_EXPORT
ShutdownInterface(GF_BaseInterface * ifce)243 void ShutdownInterface(GF_BaseInterface *ifce)
244 {
245 switch (ifce->InterfaceType) {
246 case GF_TERM_EXT_INTERFACE:
247 uir_delete(ifce);
248 break;
249 }
250 }
251
252 GPAC_MODULE_STATIC_DECLARATION( ui_rec )
253