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