1 /*
2 * GPAC - Multimedia Framework C SDK
3 *
4 * Authors: Jean Le Feuvre
5 * Copyright (c) Telecom ParisTech 2000-2020
6 * All rights reserved
7 *
8 * This file is part of GPAC / Scene Compositor 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 #include <gpac/internal/compositor_dev.h>
27 #include <gpac/options.h>
28 #include <gpac/utf.h>
29 #include <gpac/modules/hardcoded_proto.h>
30 #include <gpac/modules/compositor_ext.h>
31
32 #include "nodes_stacks.h"
33
34 #include "visual_manager.h"
35 #include "texturing.h"
36
37 static void gf_sc_recompute_ar(GF_Compositor *compositor, GF_Node *top_node);
38
39 #define SC_DEF_WIDTH 320
40 #define SC_DEF_HEIGHT 240
41
42
43 GF_EXPORT
gf_sc_send_event(GF_Compositor * compositor,GF_Event * evt)44 Bool gf_sc_send_event(GF_Compositor *compositor, GF_Event *evt)
45 {
46 return gf_filter_forward_gf_event(compositor->filter, evt, GF_FALSE, GF_FALSE);
47 }
48
49
gf_sc_next_frame_state(GF_Compositor * compositor,u32 state)50 void gf_sc_next_frame_state(GF_Compositor *compositor, u32 state)
51 {
52 GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Forcing frame redraw state: %d\n", state));
53 if (state==GF_SC_DRAW_FLUSH) {
54 if (!compositor->skip_flush)
55 compositor->skip_flush = 2;
56
57 //if in openGL mode ignore refresh events (content of the window is still OK). This is only used for overlays in 2d
58 if (!compositor->frame_draw_type
59 #ifndef GPAC_DISABLE_3D
60 && !compositor->visual->type_3d && !compositor->hybrid_opengl
61 #endif
62 ) {
63 compositor->frame_draw_type = state;
64 }
65 } else {
66 compositor->frame_draw_type = state;
67 }
68 }
69
70
gf_sc_set_fullscreen(GF_Compositor * compositor)71 static void gf_sc_set_fullscreen(GF_Compositor *compositor)
72 {
73 GF_Err e;
74 if (!compositor->video_out->SetFullScreen) return;
75
76 GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor] Switching fullscreen %s\n", compositor->fullscreen ? "off" : "on"));
77 /*move to FS*/
78 compositor->fullscreen = !compositor->fullscreen;
79
80 //gf_sc_ar_control(compositor->audio_renderer, GF_SC_AR_PAUSE);
81
82 //in windows (and other?) we may get blocked by SetWindowPos in the fullscreen method until another window thread dispatches a resize event,
83 //which would try to grab the compositor mutex and thus deadlock us
84 //to avoid this, unlock the compositor just for the SetFullscreen
85 gf_mx_v(compositor->mx);
86 if (compositor->fullscreen && (compositor->scene_width>=compositor->scene_height)
87 #ifndef GPAC_DISABLE_3D
88 && !compositor->visual->type_3d
89 #endif
90 ) {
91 e = compositor->video_out->SetFullScreen(compositor->video_out, 2, &compositor->display_width, &compositor->display_height);
92 } else {
93 e = compositor->video_out->SetFullScreen(compositor->video_out, compositor->fullscreen, &compositor->display_width, &compositor->display_height);
94 }
95 gf_mx_p(compositor->mx);
96
97 //gf_sc_ar_control(compositor->audio_renderer, GF_SC_AR_RESUME);
98
99 if (e) {
100 GF_Event evt;
101 memset(&evt, 0, sizeof(GF_Event));
102 evt.type = GF_EVENT_MESSAGE;
103 evt.message.message = "Cannot switch to fullscreen";
104 evt.message.error = e;
105 gf_sc_send_event(compositor, &evt);
106 compositor->fullscreen = 0;
107 compositor->video_out->SetFullScreen(compositor->video_out, 0, &compositor->display_width, &compositor->display_height);
108 }
109 GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor] recomputing aspect ratio\n"));
110 compositor->recompute_ar = 1;
111 /*force signaling graphics reset*/
112 if (!compositor->reset_graphics) gf_sc_reset_graphics(compositor);
113 }
114
115
116 /*this is needed for:
117 - audio: since the audio compositor may not be threaded, it must be reconfigured by another thread otherwise
118 we lock the audio module
119 - video: this is typical to OpenGL&co: multithreaded is forbidden, so resizing/fullscreen MUST be done by the same
120 thread accessing the HW ressources
121 */
gf_sc_reconfig_task(GF_Compositor * compositor)122 static void gf_sc_reconfig_task(GF_Compositor *compositor)
123 {
124 GF_Event evt;
125 Bool notif_size=GF_FALSE;
126 u32 width,height;
127
128 /*reconfig audio if needed (non-threaded compositors)*/
129 if (compositor->audio_renderer
130 #ifdef ENABLE_AOUT
131 && !compositor->audio_renderer->th
132 #endif
133 )
134 if (compositor->msg_type) {
135
136 compositor->msg_type |= GF_SR_IN_RECONFIG;
137
138 if (compositor->msg_type & GF_SR_CFG_INITIAL_RESIZE) {
139 memset(&evt, 0, sizeof(GF_Event));
140 evt.type = GF_EVENT_VIDEO_SETUP;
141 evt.setup.width = compositor->new_width;
142 evt.setup.height = compositor->new_height;
143 evt.setup.system_memory = compositor->video_memory ? GF_FALSE : GF_TRUE;
144 evt.setup.disable_vsync = compositor->bench_mode ? GF_TRUE : GF_FALSE;
145
146 #ifndef GPAC_DISABLE_3D
147 if (compositor->hybrid_opengl || compositor->force_opengl_2d) {
148 evt.setup.use_opengl = GF_TRUE;
149 evt.setup.system_memory = GF_FALSE;
150 evt.setup.back_buffer = GF_TRUE;
151 }
152
153 #endif
154 compositor->video_out->ProcessEvent(compositor->video_out, &evt);
155
156 if (evt.setup.use_opengl) {
157 gf_opengl_init();
158 }
159
160 compositor->msg_type &= ~GF_SR_CFG_INITIAL_RESIZE;
161 }
162 /*scene size has been overriden*/
163 if (compositor->msg_type & GF_SR_CFG_OVERRIDE_SIZE) {
164 assert(!(compositor->override_size_flags & 2));
165 compositor->msg_type &= ~GF_SR_CFG_OVERRIDE_SIZE;
166 compositor->override_size_flags |= 2;
167 width = compositor->scene_width;
168 height = compositor->scene_height;
169 compositor->has_size_info = 1;
170 gf_sc_set_size(compositor, width, height);
171
172 evt.type = GF_EVENT_SIZE;
173 evt.size.width = width;
174 evt.size.height = height;
175 gf_sc_send_event(compositor, &evt);
176 }
177 /*size changed from scene cfg: resize window first*/
178 if (compositor->msg_type & GF_SR_CFG_SET_SIZE) {
179 u32 fs_width, fs_height;
180 Bool restore_fs = compositor->fullscreen;
181
182 GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor] Changing display size to %d x %d\n", compositor->new_width, compositor->new_height));
183 fs_width = fs_height = 0;
184 if (restore_fs) {
185 #if defined(GPAC_CONFIG_ANDROID) || defined(GPAC_CONFIG_IOS)
186 if ((compositor->new_width>compositor->display_width) || (compositor->new_height>compositor->display_height)) {
187 u32 w = compositor->display_width;
188 compositor->display_width = compositor->display_height;
189 compositor->display_height = w;
190 compositor->recompute_ar = 1;
191 }
192 #endif
193 fs_width = compositor->display_width;
194 fs_height = compositor->display_height;
195 }
196 evt.type = GF_EVENT_SIZE;
197 evt.size.width = compositor->new_width;
198 evt.size.height = compositor->new_height;
199
200 /*send resize event*/
201 if ( !(compositor->msg_type & GF_SR_CFG_WINDOWSIZE_NOTIF)) {
202 compositor->video_out->ProcessEvent(compositor->video_out, &evt);
203 }
204
205 compositor->msg_type &= ~GF_SR_CFG_WINDOWSIZE_NOTIF;
206
207 if (restore_fs) {
208 if ((compositor->display_width != fs_width) || (compositor->display_height != fs_height)) {
209 compositor->display_width = fs_width;
210 compositor->display_height = fs_height;
211 compositor->recompute_ar = 1;
212 }
213 } else {
214 compositor->display_width = evt.size.width;
215 compositor->display_height = evt.size.height;
216 compositor->recompute_ar = 1;
217 gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
218 }
219 notif_size=1;
220 compositor->new_width = compositor->new_height = 0;
221 compositor->msg_type &= ~GF_SR_CFG_SET_SIZE;
222 GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor] Display size changed to %d x %d\n", compositor->new_width, compositor->new_height));
223 }
224 /*aspect ratio modif*/
225 if (compositor->msg_type & GF_SR_CFG_AR) {
226 compositor->msg_type &= ~GF_SR_CFG_AR;
227 compositor->recompute_ar = 1;
228 }
229 /*fullscreen on/off request*/
230 if (compositor->msg_type & GF_SR_CFG_FULLSCREEN) {
231 compositor->msg_type &= ~GF_SR_CFG_FULLSCREEN;
232 //video is about to resetup, wait for the setup
233 if (compositor->recompute_ar) {
234 compositor->fullscreen_postponed = 1;
235 } else {
236 gf_sc_set_fullscreen(compositor);
237 gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
238 notif_size=1;
239 }
240 }
241 compositor->msg_type &= ~GF_SR_IN_RECONFIG;
242 }
243 if (notif_size) {
244 gf_filter_pid_set_property(compositor->vout, GF_PROP_PID_WIDTH, &PROP_UINT(compositor->display_width));
245 gf_filter_pid_set_property(compositor->vout, GF_PROP_PID_HEIGHT, &PROP_UINT(compositor->display_height));
246 }
247
248 /*3D driver changed message, recheck extensions*/
249 if (compositor->reset_graphics) {
250 #ifndef GPAC_DISABLE_3D
251 compositor->offscreen_width = compositor->offscreen_height = 0;
252 #endif
253 gf_sc_lock(compositor, 0);
254 evt.type = GF_EVENT_SYS_COLORS;
255 if (compositor->video_out->ProcessEvent(compositor->video_out, &evt) ) {
256 u32 i;
257 for (i=0; i<28; i++) {
258 compositor->sys_colors[i] = evt.sys_cols.sys_colors[i] & 0x00FFFFFF;
259 }
260 }
261 gf_sc_lock(compositor, 1);
262 }
263 }
264
265
gf_sc_frame_ifce_done(GF_Filter * filter,GF_FilterPid * pid,GF_FilterPacket * pck)266 static void gf_sc_frame_ifce_done(GF_Filter *filter, GF_FilterPid *pid, GF_FilterPacket *pck)
267 {
268 GF_FilterFrameInterface *frame_ifce = gf_filter_pck_get_frame_interface(pck);
269 GF_Compositor *compositor = gf_filter_get_udta(filter);
270 if (frame_ifce) {
271 compositor->frame_ifce.user_data = NULL;
272 if (compositor->fb.video_buffer) {
273 gf_sc_release_screen_buffer(compositor, &compositor->fb);
274 compositor->fb.video_buffer = NULL;
275 }
276 }
277 compositor->flush_pending = (compositor->skip_flush!=1) ? GF_TRUE : GF_FALSE;
278 compositor->skip_flush = 0;
279 }
280
gf_sc_frame_ifce_get_plane(GF_FilterFrameInterface * frame_ifce,u32 plane_idx,const u8 ** outPlane,u32 * outStride)281 GF_Err gf_sc_frame_ifce_get_plane(GF_FilterFrameInterface *frame_ifce, u32 plane_idx, const u8 **outPlane, u32 *outStride)
282 {
283 GF_Err e = GF_BAD_PARAM;
284 GF_Compositor *compositor = frame_ifce->user_data;
285
286 if (plane_idx==0) {
287 e = GF_OK;
288 if (!compositor->fb.video_buffer)
289 e = gf_sc_get_screen_buffer(compositor, &compositor->fb, 0);
290 }
291 *outPlane = compositor->fb.video_buffer;
292 *outStride = compositor->fb.pitch_y;
293 return e;
294 }
295 #ifndef GPAC_DISABLE_3D
gf_sc_frame_ifce_get_gl_texture(GF_FilterFrameInterface * frame_ifce,u32 plane_idx,u32 * gl_tex_format,u32 * gl_tex_id,GF_Matrix_unexposed * texcoordmatrix)296 GF_Err gf_sc_frame_ifce_get_gl_texture(GF_FilterFrameInterface *frame_ifce, u32 plane_idx, u32 *gl_tex_format, u32 *gl_tex_id, GF_Matrix_unexposed * texcoordmatrix)
297 {
298 GF_Compositor *compositor = frame_ifce->user_data;
299 if (!compositor->fbo_tx_id) return GF_BAD_PARAM;
300 if (plane_idx) return GF_BAD_PARAM;
301 if (gl_tex_id) *gl_tex_id = compositor->fbo_tx_id;
302 if (gl_tex_format) *gl_tex_format = compositor_3d_get_fbo_pixfmt();
303 //framebuffer is already oriented as a GL texture not as an image
304 if (texcoordmatrix)
305 gf_mx_add_scale(texcoordmatrix, FIX_ONE, -FIX_ONE, FIX_ONE);
306 return GF_OK;
307 }
308 #endif
309
gf_sc_flush_video(GF_Compositor * compositor,Bool locked)310 static void gf_sc_flush_video(GF_Compositor *compositor, Bool locked)
311 {
312 GF_Window rc;
313
314 //release compositor in case we have vsync
315 if (locked) gf_sc_lock(compositor, 0);
316 rc.x = rc.y = 0;
317 rc.w = compositor->display_width;
318 rc.h = compositor->display_height;
319 compositor->video_out->Flush(compositor->video_out, &rc);
320 compositor->flush_pending = GF_FALSE;
321 if (locked) gf_sc_lock(compositor, 1);
322 }
323
324 void gf_sc_render_frame(GF_Compositor *compositor);
325
326 GF_EXPORT
gf_sc_draw_frame(GF_Compositor * compositor,Bool no_flush,s32 * ms_till_next)327 Bool gf_sc_draw_frame(GF_Compositor *compositor, Bool no_flush, s32 *ms_till_next)
328 {
329 Bool ret = GF_FALSE;
330
331 gf_sc_ar_send_or_reconfig(compositor->audio_renderer);
332
333 //frame still pending
334 if (compositor->frame_ifce.user_data)
335 return GF_TRUE;
336
337 if (compositor->flush_pending) {
338 gf_sc_flush_video(compositor, GF_FALSE);
339 }
340 compositor->skip_flush = no_flush ? 1 : 0;
341
342 gf_sc_render_frame(compositor);
343
344 if (ms_till_next) {
345 if ( compositor->ms_until_next_frame == GF_INT_MAX)
346 *ms_till_next = compositor->frame_duration;
347 else
348 *ms_till_next = compositor->ms_until_next_frame;
349 }
350 //next frame is late, we should redraw
351 if (compositor->ms_until_next_frame < 0) ret = GF_TRUE;
352 else if (compositor->frame_draw_type) ret = GF_TRUE;
353 else if (compositor->fonts_pending>0) ret = GF_TRUE;
354
355 return ret;
356 }
357
358
359 /*forces graphics redraw*/
360 GF_EXPORT
gf_sc_reset_graphics(GF_Compositor * compositor)361 void gf_sc_reset_graphics(GF_Compositor *compositor)
362 {
363 if (compositor) {
364 Bool locked = gf_mx_try_lock(compositor->mx);
365 compositor->reset_graphics = 1;
366 if (locked) gf_mx_v(compositor->mx);
367 }
368 }
369
gf_sc_reset_framerate(GF_Compositor * compositor)370 static void gf_sc_reset_framerate(GF_Compositor *compositor)
371 {
372 u32 i;
373 for (i=0; i<GF_SR_FPS_COMPUTE_SIZE; i++) compositor->frame_time[i] = compositor->frame_dur[i] = 0;
374 compositor->current_frame = 0;
375 }
376
377
378 enum
379 {
380 GF_COMPOSITOR_THREAD_START = 0,
381 GF_COMPOSITOR_THREAD_RUN,
382 GF_COMPOSITOR_THREAD_ABORTING,
383 GF_COMPOSITOR_THREAD_DONE,
384 GF_COMPOSITOR_THREAD_INIT_FAILED,
385 };
386
nullvout_setup(struct _video_out * vout,void * os_handle,void * os_display,u32 init_flags)387 static GF_Err nullvout_setup(struct _video_out *vout, void *os_handle, void *os_display, u32 init_flags)
388 {
389 return GF_OK;
390 }
nullvout_shutdown(struct _video_out * vout)391 static void nullvout_shutdown(struct _video_out *vout)
392 {
393 return;
394 }
nullvout_flush(struct _video_out * vout,GF_Window * dest)395 static GF_Err nullvout_flush(struct _video_out *vout, GF_Window *dest)
396 {
397 return GF_OK;
398 }
nullvout_fullscreen(struct _video_out * vout,Bool fs_on,u32 * new_disp_width,u32 * new_disp_height)399 static GF_Err nullvout_fullscreen(struct _video_out *vout, Bool fs_on, u32 *new_disp_width, u32 *new_disp_height)
400 {
401 return GF_OK;
402 }
nullvout_evt(struct _video_out * vout,GF_Event * event)403 static GF_Err nullvout_evt(struct _video_out *vout, GF_Event *event)
404 {
405 return GF_OK;
406 }
nullvout_lock(struct _video_out * vout,GF_VideoSurface * video_info,Bool do_lock)407 static GF_Err nullvout_lock(struct _video_out *vout, GF_VideoSurface *video_info, Bool do_lock)
408 {
409 return GF_IO_ERR;
410 }
nullvout_blit(struct _video_out * vout,GF_VideoSurface * video_src,GF_Window * src_wnd,GF_Window * dst_wnd,u32 overlay_type)411 static GF_Err nullvout_blit(struct _video_out *vout, GF_VideoSurface *video_src, GF_Window *src_wnd, GF_Window *dst_wnd, u32 overlay_type)
412 {
413 return GF_OK;
414 }
415
416 GF_VideoOutput null_vout = {
417 .Setup = nullvout_setup,
418 .Shutdown = nullvout_shutdown,
419 .Flush = nullvout_flush,
420 .SetFullScreen = nullvout_fullscreen,
421 .ProcessEvent = nullvout_evt,
422 .LockBackBuffer = nullvout_lock,
423 .Blit = nullvout_blit,
424 .hw_caps = GF_VIDEO_HW_HAS_RGB | GF_VIDEO_HW_HAS_RGBA | GF_VIDEO_HW_HAS_YUV | GF_VIDEO_HW_HAS_YUV_OVERLAY | GF_VIDEO_HW_HAS_STRETCH
425 };
426
gl_vout_evt(struct _video_out * vout,GF_Event * evt)427 static GF_Err gl_vout_evt(struct _video_out *vout, GF_Event *evt)
428 {
429 GF_Compositor *compositor = (GF_Compositor *)vout->opaque;
430 if (!evt || (evt->type != GF_EVENT_VIDEO_SETUP)) return GF_OK;
431
432 if (!compositor->player && (compositor->passthrough_pfmt != GF_PIXEL_RGB)) {
433 u32 pfmt = compositor->dyn_filter_mode ? GF_PIXEL_RGBA : GF_PIXEL_RGB;
434 compositor->passthrough_pfmt = pfmt;
435 compositor->opfmt = pfmt;
436 if (compositor->vout) {
437 u32 stride = compositor->output_width * ( (pfmt == GF_PIXEL_RGBA) ? 4 : 3 );
438 gf_filter_pid_set_property(compositor->vout, GF_PROP_PID_PIXFMT, &PROP_UINT(pfmt));
439 gf_filter_pid_set_property(compositor->vout, GF_PROP_PID_STRIDE, &PROP_UINT(stride));
440 }
441 }
442
443
444 #ifndef GPAC_DISABLE_3D
445 return compositor_3d_setup_fbo(evt->setup.width, evt->setup.height, &compositor->fbo_id, &compositor->fbo_tx_id, &compositor->fbo_depth_id);
446 #else
447 return GF_NOT_SUPPORTED;
448 #endif
449 }
450
451 GF_VideoOutput gl_vout = {
452 .Setup = nullvout_setup,
453 .Shutdown = nullvout_shutdown,
454 .Flush = nullvout_flush,
455 .SetFullScreen = nullvout_fullscreen,
456 .ProcessEvent = gl_vout_evt,
457 .LockBackBuffer = NULL,
458 .Blit = NULL,
459 .hw_caps = GF_VIDEO_HW_OPENGL
460 };
461
rawvout_lock(struct _video_out * vout,GF_VideoSurface * vi,Bool do_lock)462 static GF_Err rawvout_lock(struct _video_out *vout, GF_VideoSurface *vi, Bool do_lock)
463 {
464 GF_Compositor *compositor = (GF_Compositor *)vout->opaque;
465
466 if (do_lock) {
467 u32 pfmt;
468 if (!vi) return GF_BAD_PARAM;
469 pfmt = compositor->opfmt;
470 if (!pfmt && compositor->passthrough_txh) pfmt = compositor->passthrough_txh->pixelformat;
471
472 if (!pfmt) {
473 pfmt = compositor->dyn_filter_mode ? GF_PIXEL_RGBA : GF_PIXEL_RGB;
474 }
475
476 memset(vi, 0, sizeof(GF_VideoSurface));
477 vi->width = compositor->display_width;
478 vi->height = compositor->display_height;
479 gf_pixel_get_size_info(pfmt, compositor->display_width, compositor->display_height, NULL, &vi->pitch_y, NULL, NULL, NULL);
480 if (compositor->passthrough_txh && !compositor->passthrough_txh->frame_ifce && (pfmt == compositor->passthrough_txh->pixelformat)) {
481 if (!compositor->passthrough_pck)
482 compositor->passthrough_pck = gf_filter_pck_new_clone(compositor->vout, compositor->passthrough_txh->stream->pck, &compositor->passthrough_data);
483
484 vi->video_buffer = compositor->passthrough_data;
485 vi->pitch_y = compositor->passthrough_txh->stride;
486 } else {
487 vi->video_buffer = compositor->framebuffer;
488 }
489 vi->pitch_x = gf_pixel_get_bytes_per_pixel(pfmt);
490 vi->pixel_format = pfmt;
491 compositor->passthrough_pfmt = pfmt;
492 }
493 return GF_OK;
494 }
495
rawvout_evt(struct _video_out * vout,GF_Event * evt)496 static GF_Err rawvout_evt(struct _video_out *vout, GF_Event *evt)
497 {
498 u32 pfmt, stride, stride_uv;
499 GF_Compositor *compositor = (GF_Compositor *)vout->opaque;
500 if (!evt || (evt->type != GF_EVENT_VIDEO_SETUP)) return GF_OK;
501
502 pfmt = compositor->opfmt;
503 if (!pfmt) {
504 pfmt = compositor->dyn_filter_mode ? GF_PIXEL_RGBA : GF_PIXEL_RGB;
505 }
506
507 compositor->passthrough_pfmt = pfmt;
508 stride=0;
509 stride_uv = 0;
510 gf_pixel_get_size_info(pfmt, evt->setup.width, evt->setup.height, &compositor->framebuffer_size, &stride, &stride_uv, NULL, NULL);
511
512 if (compositor->vout) {
513 gf_filter_pid_set_property(compositor->vout, GF_PROP_PID_PIXFMT, &PROP_UINT(pfmt));
514 gf_filter_pid_set_property(compositor->vout, GF_PROP_PID_STRIDE, &PROP_UINT(stride));
515 gf_filter_pid_set_property(compositor->vout, GF_PROP_PID_STRIDE_UV, stride_uv ? &PROP_UINT(stride_uv) : NULL);
516 }
517
518 if (compositor->framebuffer_size > compositor->framebuffer_alloc) {
519 compositor->framebuffer_alloc = compositor->framebuffer_size;
520 compositor->framebuffer = gf_realloc(compositor->framebuffer, sizeof(char)*compositor->framebuffer_size);
521 }
522 if (!compositor->framebuffer) return GF_OUT_OF_MEM;
523 memset(compositor->framebuffer, 0, sizeof(char)*compositor->framebuffer_size);
524
525 #ifndef GPAC_DISABLE_3D
526 if (compositor->needs_offscreen_gl && (compositor->ogl != GF_SC_GLMODE_OFF))
527 return compositor_3d_setup_fbo(evt->setup.width, evt->setup.height, &compositor->fbo_id, &compositor->fbo_tx_id, &compositor->fbo_depth_id);
528 #endif
529
530 evt->setup.use_opengl = GF_FALSE;
531 return GF_OK;
532 }
533
534 GF_VideoOutput raw_vout = {
535 .Setup = nullvout_setup,
536 .Shutdown = nullvout_shutdown,
537 .Flush = nullvout_flush,
538 .SetFullScreen = nullvout_fullscreen,
539 .ProcessEvent = rawvout_evt,
540 .LockBackBuffer = rawvout_lock,
541 .Blit = NULL,
542 .hw_caps = GF_VIDEO_HW_HAS_RGB | GF_VIDEO_HW_HAS_RGBA
543 };
544
gf_sc_setup_passthrough(GF_Compositor * compositor)545 void gf_sc_setup_passthrough(GF_Compositor *compositor)
546 {
547 u32 timescale;
548 Bool is_raw_out = GF_FALSE;
549 u32 update_pfmt = 0;
550 compositor->passthrough_inplace = GF_FALSE;
551
552 if (!compositor->passthrough_txh) {
553 compositor->passthrough_timescale = 0;
554 return;
555 }
556
557 timescale = gf_filter_pck_get_timescale(compositor->passthrough_txh->stream->pck);
558 if (compositor->passthrough_timescale != timescale) {
559
560 compositor->passthrough_timescale = timescale;
561 gf_filter_pid_copy_properties(compositor->vout, compositor->passthrough_txh->stream->odm->pid);
562 if (compositor->video_out==&raw_vout) {
563 update_pfmt = compositor->opfmt ? compositor->opfmt : compositor->passthrough_txh->pixelformat;
564 } else {
565 update_pfmt = GF_PIXEL_RGB;
566 }
567 }
568 if (compositor->video_out == &raw_vout) {
569 is_raw_out = GF_TRUE;
570 if (!compositor->opfmt || (compositor->opfmt == compositor->passthrough_txh->pixelformat) ) {
571 if (!compositor->passthrough_txh->frame_ifce) {
572 compositor->passthrough_inplace = GF_TRUE;
573 update_pfmt = GF_FALSE;
574 }
575 if (!compositor->opfmt && (compositor->passthrough_pfmt != compositor->passthrough_txh->pixelformat)) {
576 compositor->passthrough_pfmt = compositor->passthrough_txh->pixelformat;
577 gf_filter_pid_copy_properties(compositor->vout, compositor->passthrough_txh->stream->odm->pid);
578 }
579 }
580 }
581
582 if (update_pfmt) {
583 u32 stride=0, stride_uv=0, out_size=0;
584 gf_pixel_get_size_info(update_pfmt, compositor->display_width, compositor->display_width, &out_size, &stride, &stride_uv, NULL, NULL);
585 gf_filter_pid_set_property(compositor->vout, GF_PROP_PID_PIXFMT, &PROP_UINT(update_pfmt));
586 gf_filter_pid_set_property(compositor->vout, GF_PROP_PID_STRIDE, &PROP_UINT(stride));
587 gf_filter_pid_set_property(compositor->vout, GF_PROP_PID_STRIDE_UV, stride_uv ? &PROP_UINT(stride_uv) : NULL);
588
589 if (is_raw_out && !compositor->passthrough_inplace && (compositor->framebuffer_size != out_size) ) {
590 compositor->framebuffer_size = out_size;
591 if (out_size > compositor->framebuffer_alloc) {
592 compositor->framebuffer_alloc = out_size;
593 compositor->framebuffer = gf_realloc(compositor->framebuffer, out_size);
594 }
595 }
596 }
597 }
598
gf_sc_load_driver(GF_Compositor * compositor)599 static GF_Err gf_sc_load_driver(GF_Compositor *compositor)
600 {
601 GF_Err e;
602 const char *sOpt;
603 void *os_disp=NULL;
604
605 //filter mode
606 if (!compositor->player) {
607 compositor->video_out = &null_vout;
608
609 #ifdef GPAC_ENABLE_COVERAGE
610 if (gf_sys_is_cov_mode()) {
611 nullvout_setup(NULL, NULL, NULL, 0);
612 nullvout_fullscreen(NULL, GF_FALSE, NULL, NULL);
613 nullvout_evt(NULL, NULL);
614 nullvout_lock(NULL, NULL, GF_FALSE);
615 nullvout_blit(NULL, NULL, NULL, NULL, 0);
616 }
617 #endif
618
619 e = gf_filter_request_opengl(compositor->filter);
620 if (e) return e;
621 #ifndef GPAC_DISABLE_3D
622 gf_sc_load_opengl_extensions(compositor, GF_TRUE);
623 if (!compositor->gl_caps.fbo)
624 #endif
625 {
626 GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Compositor] No support for OpenGL framebuffer object, cannot run in GL mode.\n"));
627 compositor->drv = GF_SC_DRV_OFF;
628 return GF_NOT_SUPPORTED;
629 }
630 compositor->video_out = &gl_vout;
631 compositor->video_out->opaque = compositor;
632 return GF_OK;
633 }
634
635 //player mode
636 #ifndef GPAC_DISABLE_3D
637 sOpt = gf_opts_get_key("core", "video-output");
638 if (sOpt && !strcmp(sOpt, "glfbo")) {
639 compositor->video_out = &gl_vout;
640 compositor->video_out->opaque = compositor;
641 sOpt = gf_opts_get_key("core", "glfbo-txid");
642 if (sOpt) {
643 compositor->fbo_tx_id = atoi(sOpt);
644 compositor->external_tx_id = GF_TRUE;
645 }
646 if (!compositor->fbo_tx_id) {
647 GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Compositor] glfbo driver specified but no target texture ID found, cannot initialize\n"));
648 compositor->drv = GF_SC_DRV_OFF;
649 return GF_BAD_PARAM;
650 }
651 gf_sc_load_opengl_extensions(compositor, GF_TRUE);
652 if (!compositor->gl_caps.fbo) {
653 GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Compositor] No support for OpenGL framebuffer object, cannot run in glfbo mode.\n"));
654 compositor->drv = GF_SC_DRV_OFF;
655 return GF_NOT_SUPPORTED;
656 }
657 return GF_OK;
658 }
659 #endif
660
661 compositor->video_out = (GF_VideoOutput *) gf_module_load(GF_VIDEO_OUTPUT_INTERFACE, NULL);
662
663 if (!compositor->video_out ) {
664 GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Compositor] Failed to load a video output module.\n"));
665 return GF_IO_ERR;
666 }
667
668 sOpt = gf_opts_get_key("Temp", "OSDisp");
669 if (sOpt) sscanf(sOpt, "%p", &os_disp);
670
671 compositor->video_out->evt_cbk_hdl = compositor;
672 compositor->video_out->on_event = gf_sc_on_event;
673 /*init hw*/
674 e = compositor->video_out->Setup(compositor->video_out, compositor->os_wnd, os_disp, compositor->init_flags);
675 if (e != GF_OK) {
676 GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Compositor] Error setuing up video output: %s\n", gf_error_to_string(e) ));
677 return e;
678 }
679 if (!gf_opts_get_key("core", "video-output")) {
680 gf_opts_set_key("core", "video-output", compositor->video_out->module_name);
681 }
682 gf_filter_register_opengl_provider(compositor->filter, GF_TRUE);
683 return GF_OK;
684 }
685
686 #ifndef GPAC_DISABLE_3D
gf_sc_check_video_driver(GF_Compositor * compositor)687 static void gf_sc_check_video_driver(GF_Compositor *compositor)
688 {
689 Bool force_gl_out = GF_FALSE;
690 if (compositor->player) return;
691 if (compositor->video_out == &null_vout) return;
692
693 if (compositor->visual->type_3d || compositor->hybrid_opengl) {
694 force_gl_out = GF_TRUE;
695 } else if (compositor->needs_offscreen_gl && (compositor->ogl!=GF_SC_GLMODE_OFF) ) {
696 force_gl_out = GF_TRUE;
697 }
698
699 if (force_gl_out) {
700 GF_Err e;
701 if (compositor->video_out != &raw_vout) return;
702 e = gf_sc_load_driver(compositor);
703 if (e) {
704 compositor->video_out = &raw_vout;
705 compositor->video_memory = 2;
706 }
707 return;
708 }
709
710 if (compositor->video_out == &raw_vout) {
711 if (compositor->needs_offscreen_gl) {
712 gf_filter_request_opengl(compositor->filter);
713 }
714 return;
715 }
716 compositor->video_out = &raw_vout;
717 compositor->video_memory = 2;
718 }
719 #endif
720
gf_sc_load(GF_Compositor * compositor)721 GF_Err gf_sc_load(GF_Compositor *compositor)
722 {
723 u32 i;
724 const char *sOpt;
725
726 compositor->mx = gf_mx_new("Compositor");
727 if (!compositor->mx) return GF_OUT_OF_MEM;
728
729 /*load proto modules*/
730 compositor->proto_modules = gf_list_new();
731 if (!compositor->proto_modules) return GF_OUT_OF_MEM;
732 for (i=0; i< gf_modules_count(); i++) {
733 GF_HardcodedProto *ifce = (GF_HardcodedProto *) gf_modules_load(i, GF_HARDCODED_PROTO_INTERFACE);
734 if (ifce) gf_list_add(compositor->proto_modules, ifce);
735 }
736
737 compositor->init_flags = 0;
738 compositor->os_wnd = NULL;
739 sOpt = gf_opts_get_key("Temp", "OSWnd");
740 if (sOpt) sscanf(sOpt, "%p", &compositor->os_wnd);
741 sOpt = gf_opts_get_key("Temp", "InitFlags");
742 if (sOpt) compositor->init_flags = atoi(sOpt);
743
744 if (compositor->noaudio)
745 compositor->init_flags |= GF_TERM_NO_AUDIO;
746
747 /*force initial for 2D/3D setup*/
748 compositor->msg_type |= GF_SR_CFG_INITIAL_RESIZE;
749 /*set default size if owning output*/
750 if (!compositor->os_wnd) {
751 compositor->new_width = compositor->osize.x>0 ? compositor->osize.x : SC_DEF_WIDTH;
752 compositor->new_height = compositor->osize.y>0 ? compositor->osize.y : SC_DEF_HEIGHT;
753 compositor->msg_type |= GF_SR_CFG_SET_SIZE;
754 }
755
756 if (!compositor->player)
757 compositor->init_flags = GF_TERM_INIT_HIDE;
758
759 if (gf_opts_get_bool("temp", "gpac-help")) {
760 compositor->init_flags |= GF_TERM_NO_VIDEO | GF_TERM_NO_AUDIO;
761 }
762
763 if (compositor->init_flags & GF_TERM_NO_VIDEO) {
764 compositor->video_out = &null_vout;
765 compositor->ogl = GF_SC_GLMODE_OFF;
766 } else if (compositor->player || (compositor->drv==GF_SC_DRV_ON) || (compositor->ogl==GF_SC_GLMODE_HYBRID) ){
767 GF_Err e;
768
769 e = gf_sc_load_driver(compositor);
770 if (e) return e;
771 } else {
772 raw_vout.opaque = compositor;
773 compositor->video_out = &raw_vout;
774 compositor->video_memory = 2;
775 }
776
777 compositor->strike_bank = gf_list_new();
778 if (!compositor->strike_bank) return GF_OUT_OF_MEM;
779 compositor->visuals = gf_list_new();
780 if (!compositor->visuals) return GF_OUT_OF_MEM;
781
782 GF_SAFEALLOC(compositor->traverse_state, GF_TraverseState);
783 if (!compositor->traverse_state) return GF_OUT_OF_MEM;
784
785 compositor->traverse_state->vrml_sensors = gf_list_new();
786 if (!compositor->traverse_state->vrml_sensors) return GF_OUT_OF_MEM;
787 compositor->traverse_state->use_stack = gf_list_new();
788 if (!compositor->traverse_state->use_stack) return GF_OUT_OF_MEM;
789 #ifndef GPAC_DISABLE_3D
790 compositor->traverse_state->local_lights = gf_list_new();
791 if (!compositor->traverse_state->local_lights) return GF_OUT_OF_MEM;
792 #endif
793 compositor->sensors = gf_list_new();
794 if (!compositor->sensors) return GF_OUT_OF_MEM;
795 compositor->previous_sensors = gf_list_new();
796 if (!compositor->previous_sensors) return GF_OUT_OF_MEM;
797 compositor->hit_use_stack = gf_list_new();
798 if (!compositor->hit_use_stack) return GF_OUT_OF_MEM;
799 compositor->prev_hit_use_stack = gf_list_new();
800 if (!compositor->prev_hit_use_stack) return GF_OUT_OF_MEM;
801 compositor->focus_ancestors = gf_list_new();
802 if (!compositor->focus_ancestors) return GF_OUT_OF_MEM;
803 compositor->focus_use_stack = gf_list_new();
804 if (!compositor->focus_use_stack) return GF_OUT_OF_MEM;
805
806 compositor->env_tests = gf_list_new();
807 if (!compositor->env_tests) return GF_OUT_OF_MEM;
808
809 /*setup main visual*/
810 compositor->visual = visual_new(compositor);
811 if (!compositor->visual) return GF_OUT_OF_MEM;
812 compositor->visual->GetSurfaceAccess = compositor_2d_get_video_access;
813 compositor->visual->ReleaseSurfaceAccess = compositor_2d_release_video_access;
814 compositor->visual->CheckAttached = compositor_2d_check_attached;
815 compositor->visual->ClearSurface = compositor_2d_clear_surface;
816
817 compositor_2d_init_callbacks(compositor);
818
819 if (compositor->video_out->FlushRectangles)
820 compositor->visual->direct_flush = GF_TRUE;
821
822 // default value for depth gain is not zero
823 #ifdef GF_SR_USE_DEPTH
824 compositor->traverse_state->depth_gain = FIX_ONE;
825 #endif
826
827 gf_list_add(compositor->visuals, compositor->visual);
828
829 compositor->zoom = compositor->scale_x = compositor->scale_y = FIX_ONE;
830
831 /*create a drawable for focus highlight*/
832 compositor->focus_highlight = drawable_new();
833 if (!compositor->focus_highlight) return GF_OUT_OF_MEM;
834 /*associate a dummy node for traversing*/
835 compositor->focus_highlight->node = gf_node_new(NULL, TAG_UndefinedNode);
836 if (!compositor->focus_highlight->node) return GF_OUT_OF_MEM;
837 gf_node_register(compositor->focus_highlight->node, NULL);
838 gf_node_set_callback_function(compositor->focus_highlight->node, drawable_traverse_focus);
839
840
841 #ifndef GPAC_DISABLE_3D
842 /*default collision mode*/
843 compositor->collide_mode = GF_COLLISION_DISPLACEMENT; //GF_COLLISION_NORMAL
844 compositor->gravity_on = GF_TRUE;
845
846 /*create default unit sphere and box for bounds*/
847 compositor->unit_bbox = new_mesh();
848 if (!compositor->unit_bbox) return GF_OUT_OF_MEM;
849 mesh_new_unit_bbox(compositor->unit_bbox);
850 gf_mx_init(compositor->traverse_state->model_matrix);
851 #endif
852
853 compositor->was_system_memory=1;
854
855 compositor->systems_pids = gf_list_new();
856 if (!compositor->systems_pids) return GF_OUT_OF_MEM;
857 compositor->textures = gf_list_new();
858 if (!compositor->textures) return GF_OUT_OF_MEM;
859 compositor->textures_gc = gf_list_new();
860 if (!compositor->textures_gc) return GF_OUT_OF_MEM;
861 if (!compositor->fps.num || !compositor->fps.den) {
862 compositor->fps.num = 30;
863 compositor->fps.den = 1;
864 }
865 compositor->frame_duration = compositor->fps.num * 1000;
866 compositor->frame_duration /= compositor->fps.den;
867
868 compositor->time_nodes = gf_list_new();
869 if (!compositor->time_nodes) return GF_OUT_OF_MEM;
870 compositor->event_queue = gf_list_new();
871 if (!compositor->event_queue) return GF_OUT_OF_MEM;
872 compositor->event_queue_back = gf_list_new();
873 if (!compositor->event_queue_back) return GF_OUT_OF_MEM;
874 compositor->evq_mx = gf_mx_new("EventQueue");
875 if (!compositor->evq_mx) return GF_OUT_OF_MEM;
876
877 #ifdef GF_SR_USE_VIDEO_CACHE
878 compositor->cached_groups = gf_list_new();
879 if (!compositor->cached_groups) return GF_OUT_OF_MEM;
880 compositor->cached_groups_queue = gf_list_new();
881 if (!compositor->cached_groups_queue) return GF_OUT_OF_MEM;
882 #endif
883
884 /*load audio renderer*/
885 if (!compositor->audio_renderer)
886 compositor->audio_renderer = gf_sc_ar_load(compositor, compositor->init_flags);
887
888 gf_sc_reset_framerate(compositor);
889 compositor->font_manager = gf_filter_get_font_manager(compositor->filter);
890 if (!compositor->font_manager) return GF_OUT_OF_MEM;
891
892 compositor->extra_scenes = gf_list_new();
893 if (!compositor->extra_scenes) return GF_OUT_OF_MEM;
894 compositor->interaction_level = GF_INTERACT_NORMAL | GF_INTERACT_INPUT_SENSOR | GF_INTERACT_NAVIGATION;
895
896 compositor->scene_sampled_clock = 0;
897 compositor->video_th_id = gf_th_id();
898
899 /*load extensions*/
900 compositor->extensions = gf_list_new();
901 if (!compositor->extensions) return GF_OUT_OF_MEM;
902 compositor->unthreaded_extensions = gf_list_new();
903 if (!compositor->unthreaded_extensions) return GF_OUT_OF_MEM;
904 for (i=0; i< gf_modules_count(); i++) {
905 GF_CompositorExt *ifce = (GF_CompositorExt *) gf_modules_load(i, GF_COMPOSITOR_EXT_INTERFACE);
906 if (ifce) {
907
908 if (!ifce->process(ifce, GF_COMPOSITOR_EXT_START, compositor)) {
909 gf_modules_close_interface((GF_BaseInterface *) ifce);
910 continue;
911 }
912 gf_list_add(compositor->extensions, ifce);
913 if (ifce->caps & GF_COMPOSITOR_EXTENSION_NOT_THREADED)
914 gf_list_add(compositor->unthreaded_extensions, ifce);
915 }
916 }
917
918 if (!gf_list_count(compositor->unthreaded_extensions)) {
919 gf_list_del(compositor->unthreaded_extensions);
920 compositor->unthreaded_extensions = NULL;
921 }
922
923 compositor->display_width = 320;
924 compositor->display_height = 240;
925 compositor->recompute_ar = GF_TRUE;
926 compositor->scene_sampled_clock = 0;
927 if (compositor->autoconfig_opengl || compositor->hybrid_opengl)
928 gf_sc_recompute_ar(compositor, NULL);
929
930 /*try to load GL extensions*/
931 #ifndef GPAC_DISABLE_3D
932 gf_sc_load_opengl_extensions(compositor, GF_FALSE);
933 #endif
934
935 gf_sc_reload_config(compositor);
936
937
938 GF_LOG(GF_LOG_DEBUG, GF_LOG_RTI, ("[RTI]\tCompositor Cycle Log\tNetworks\tDecoders\tFrame\tDirect Draw\tVisual Config\tEvent\tRoute\tSMIL Timing\tTime node\tTexture\tSMIL Anim\tTraverse setup\tTraverse (and direct Draw)\tTraverse (and direct Draw) without anim\tIndirect Draw\tTraverse And Draw (Indirect or Not)\tFlush\tCycle\n"));
939 return GF_OK;
940 }
941
gf_sc_unload(GF_Compositor * compositor)942 void gf_sc_unload(GF_Compositor *compositor)
943 {
944 u32 i;
945 if (!compositor) return;
946
947 GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Destroying\n"));
948 compositor->discard_input_events = GF_TRUE;
949 gf_sc_lock(compositor, GF_TRUE);
950
951 #ifndef GPAC_DISABLE_3D
952 compositor_2d_reset_gl_auto(compositor);
953 #endif
954 gf_sc_texture_cleanup_hw(compositor);
955
956 if (compositor->video_out) {
957 GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Closing video output\n"));
958 compositor->video_out->Shutdown(compositor->video_out);
959 gf_modules_close_interface((GF_BaseInterface *)compositor->video_out);
960 }
961 GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Closing visual compositor\n"));
962
963 if (compositor->focus_highlight) {
964 gf_node_unregister(compositor->focus_highlight->node, NULL);
965 drawable_del_ex(compositor->focus_highlight, compositor);
966 }
967 if (compositor->selected_text) gf_free(compositor->selected_text);
968 if (compositor->sel_buffer) gf_free(compositor->sel_buffer);
969
970 if (compositor->visual) visual_del(compositor->visual);
971 if (compositor->sensors) gf_list_del(compositor->sensors);
972 if (compositor->previous_sensors) gf_list_del(compositor->previous_sensors);
973 if (compositor->visuals) gf_list_del(compositor->visuals);
974 if (compositor->strike_bank) gf_list_del(compositor->strike_bank);
975 if (compositor->hit_use_stack) gf_list_del(compositor->hit_use_stack);
976 if (compositor->prev_hit_use_stack) gf_list_del(compositor->prev_hit_use_stack);
977 if (compositor->focus_ancestors) gf_list_del(compositor->focus_ancestors);
978 if (compositor->focus_use_stack) gf_list_del(compositor->focus_use_stack);
979 if (compositor->env_tests) gf_list_del(compositor->env_tests);
980 if (compositor->systems_pids) gf_list_del(compositor->systems_pids);
981
982 if (compositor->traverse_state) {
983 gf_list_del(compositor->traverse_state->vrml_sensors);
984 gf_list_del(compositor->traverse_state->use_stack);
985 #ifndef GPAC_DISABLE_3D
986 gf_list_del(compositor->traverse_state->local_lights);
987 #endif
988 gf_free(compositor->traverse_state);
989 }
990
991 #ifndef GPAC_DISABLE_3D
992 if (compositor->unit_bbox) mesh_free(compositor->unit_bbox);
993
994 if (compositor->screen_buffer) gf_free(compositor->screen_buffer);
995 if (compositor->line_buffer) gf_free(compositor->line_buffer);
996 #endif
997 if (compositor->framebuffer) gf_free(compositor->framebuffer);
998
999 GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Unloading visual compositor module\n"));
1000
1001 if (compositor->audio_renderer) gf_sc_ar_del(compositor->audio_renderer);
1002 compositor->audio_renderer = NULL;
1003
1004 /*unload proto modules*/
1005 if (compositor->proto_modules) {
1006 for (i=0; i< gf_list_count(compositor->proto_modules); i++) {
1007 GF_HardcodedProto *ifce = gf_list_get(compositor->proto_modules, i);
1008 gf_modules_close_interface((GF_BaseInterface *) ifce);
1009 }
1010 gf_list_del(compositor->proto_modules);
1011 }
1012 if (compositor->evq_mx) gf_mx_p(compositor->evq_mx);
1013 while (gf_list_count(compositor->event_queue)) {
1014 GF_QueuedEvent *qev = (GF_QueuedEvent *)gf_list_get(compositor->event_queue, 0);
1015 gf_list_rem(compositor->event_queue, 0);
1016 gf_free(qev);
1017 }
1018 while (gf_list_count(compositor->event_queue_back)) {
1019 GF_QueuedEvent *qev = (GF_QueuedEvent *)gf_list_get(compositor->event_queue_back, 0);
1020 gf_list_rem(compositor->event_queue, 0);
1021 gf_free(qev);
1022 }
1023 if (compositor->evq_mx) {
1024 gf_mx_v(compositor->evq_mx);
1025 gf_mx_del(compositor->evq_mx);
1026 }
1027 gf_list_del(compositor->event_queue);
1028 gf_list_del(compositor->event_queue_back);
1029
1030 #ifdef GF_SR_USE_VIDEO_CACHE
1031 gf_list_del(compositor->cached_groups);
1032 gf_list_del(compositor->cached_groups_queue);
1033 #endif
1034
1035 if (compositor->textures) gf_list_del(compositor->textures);
1036 if (compositor->textures_gc) gf_list_del(compositor->textures_gc);
1037 if (compositor->time_nodes) gf_list_del(compositor->time_nodes);
1038 if (compositor->extra_scenes) gf_list_del(compositor->extra_scenes);
1039 if (compositor->input_streams) gf_list_del(compositor->input_streams);
1040 if (compositor->x3d_sensors) gf_list_del(compositor->x3d_sensors);
1041
1042
1043 /*unload extensions*/
1044 for (i=0; i< gf_list_count(compositor->extensions); i++) {
1045 GF_CompositorExt *ifce = gf_list_get(compositor->extensions, i);
1046 ifce->process(ifce, GF_COMPOSITOR_EXT_STOP, NULL);
1047 }
1048
1049 /*remove all event filters*/
1050 // gf_list_reset(term->event_filters);
1051
1052 /*unload extensions*/
1053 for (i=0; i< gf_list_count(compositor->extensions); i++) {
1054 GF_CompositorExt *ifce = gf_list_get(compositor->extensions, i);
1055 gf_modules_close_interface((GF_BaseInterface *) ifce);
1056 }
1057 gf_list_del(compositor->extensions);
1058 gf_list_del(compositor->unthreaded_extensions);
1059
1060 gf_sc_lock(compositor, GF_FALSE);
1061 gf_mx_del(compositor->mx);
1062 GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Destroyed\n"));
1063 }
1064
gf_sc_set_fps(GF_Compositor * compositor,GF_Fraction fps)1065 void gf_sc_set_fps(GF_Compositor *compositor, GF_Fraction fps)
1066 {
1067 if (fps.den) {
1068 u64 dur;
1069 compositor->fps = fps;
1070 dur = fps.den;
1071 dur *= 1000;
1072 dur /= fps.num;
1073
1074 compositor->frame_duration = (u32) dur;
1075 gf_sc_reset_framerate(compositor);
1076
1077 if (compositor->vout && !compositor->timescale) {
1078 gf_filter_pid_set_property(compositor->vout, GF_PROP_PID_TIMESCALE, &PROP_UINT(fps.num) );
1079
1080 }
1081 }
1082 }
1083
gf_sc_set_play_state(GF_Compositor * compositor,u32 PlayState)1084 static void gf_sc_set_play_state(GF_Compositor *compositor, u32 PlayState)
1085 {
1086 if (!compositor || !compositor->audio_renderer) return;
1087 if (!compositor->paused && !PlayState) return;
1088 if (compositor->paused && (PlayState==GF_STATE_PAUSED)) return;
1089
1090 /*step mode*/
1091 if (PlayState==GF_STATE_STEP_PAUSE) {
1092 compositor->step_mode = GF_TRUE;
1093 compositor->paused = 1;
1094 } else {
1095 compositor->step_mode = GF_FALSE;
1096 if (compositor->audio_renderer) gf_sc_ar_control(compositor->audio_renderer, (compositor->paused && (PlayState==0xFF)) ? GF_SC_AR_RESET_HW_AND_PLAY : (compositor->paused ? GF_SC_AR_RESUME : GF_SC_AR_PAUSE) );
1097 compositor->paused = (PlayState==GF_STATE_PAUSED) ? 1 : 0;
1098 }
1099 }
1100
1101 GF_EXPORT
gf_sc_get_clock(GF_Compositor * compositor)1102 u32 gf_sc_get_clock(GF_Compositor *compositor)
1103 {
1104 if (!compositor->bench_mode && compositor->player) {
1105 return gf_sc_ar_get_clock(compositor->audio_renderer);
1106 }
1107 return compositor->scene_sampled_clock;
1108 }
1109
1110 GF_EXPORT
gf_sc_set_scene_size(GF_Compositor * compositor,u32 Width,u32 Height,Bool force_size)1111 GF_Err gf_sc_set_scene_size(GF_Compositor *compositor, u32 Width, u32 Height, Bool force_size)
1112 {
1113 if (!Width || !Height) {
1114 if (compositor->override_size_flags) {
1115 /*specify a small size to detect biggest bitmap but not 0 in case only audio..*/
1116 compositor->scene_height = SC_DEF_HEIGHT;
1117 compositor->scene_width = SC_DEF_WIDTH;
1118 } else {
1119 /*use current res*/
1120 compositor->scene_width = compositor->new_width ? compositor->new_width : compositor->display_width;
1121 compositor->scene_height = compositor->new_height ? compositor->new_height : compositor->display_height;
1122 }
1123 } else {
1124 compositor->scene_height = Height;
1125 compositor->scene_width = Width;
1126 }
1127 if (force_size)
1128 compositor->has_size_info = 1;
1129 return GF_OK;
1130 }
1131
1132 #ifndef GPAC_DISABLE_SVG
1133 GF_EXPORT
gf_sc_svg_convert_length_to_display(GF_Compositor * compositor,SVG_Length * length)1134 Fixed gf_sc_svg_convert_length_to_display(GF_Compositor *compositor, SVG_Length *length)
1135 {
1136 /* Assuming the environment is 90dpi*/
1137 u32 dpi = 90;
1138 if (!length) return 0;
1139
1140 switch (length->type) {
1141 case SVG_NUMBER_PERCENTAGE:
1142 break;
1143 case SVG_NUMBER_EMS:
1144 break;
1145 case SVG_NUMBER_EXS:
1146 break;
1147 case SVG_NUMBER_VALUE:
1148 break;
1149 case SVG_NUMBER_PX:
1150 return length->value;
1151 case SVG_NUMBER_CM:
1152 return gf_mulfix(length->value, dpi*FLT2FIX(0.39));
1153 break;
1154 case SVG_NUMBER_MM:
1155 return gf_mulfix(length->value, dpi*FLT2FIX(0.039));
1156 case SVG_NUMBER_IN:
1157 return length->value * dpi;
1158 case SVG_NUMBER_PT:
1159 return (dpi * length->value) / 12;
1160 case SVG_NUMBER_PC:
1161 return (dpi*length->value) / 6;
1162 case SVG_NUMBER_INHERIT:
1163 break;
1164 }
1165 return length->value;
1166 }
1167 #endif
1168
compositor_set_ar_scale(GF_Compositor * compositor,Fixed scaleX,Fixed scaleY)1169 void compositor_set_ar_scale(GF_Compositor *compositor, Fixed scaleX, Fixed scaleY)
1170 {
1171 compositor->trans_x = gf_muldiv(compositor->trans_x, scaleX, compositor->scale_x);
1172 compositor->trans_y = gf_muldiv(compositor->trans_y, scaleY, compositor->scale_y);
1173
1174 compositor->zoom_changed = 1;
1175 compositor->scale_x = scaleX;
1176 compositor->scale_y = scaleY;
1177
1178 compositor_2d_set_user_transform(compositor, compositor->zoom, compositor->trans_x, compositor->trans_y, 1);
1179 }
1180
gf_sc_reset(GF_Compositor * compositor,Bool has_scene)1181 static void gf_sc_reset(GF_Compositor *compositor, Bool has_scene)
1182 {
1183 Bool mode2d;
1184 GF_VisualManager *visual;
1185 u32 i=0;
1186
1187 //init failed
1188 if (!compositor->traverse_state)
1189 return;
1190
1191 while ((visual = (GF_VisualManager *)gf_list_enum(compositor->visuals, &i))) {
1192 /*reset display list*/
1193 visual->cur_context = visual->context;
1194 if (visual->cur_context) visual->cur_context->drawable = NULL;
1195 while (visual->prev_nodes) {
1196 struct _drawable_store *cur = visual->prev_nodes;
1197 visual->prev_nodes = cur->next;
1198 gf_free(cur);
1199 }
1200 visual->last_prev_entry = NULL;
1201 visual->to_redraw.count = 0;
1202
1203 /*reset the surface as well*/
1204 if (visual->raster_surface) gf_evg_surface_delete(visual->raster_surface);
1205 visual->raster_surface = NULL;
1206 }
1207
1208 gf_list_reset(compositor->sensors);
1209 gf_list_reset(compositor->previous_sensors);
1210
1211 /*reset traverse state*/
1212 mode2d = compositor->traverse_state->immediate_draw;
1213 gf_list_del(compositor->traverse_state->vrml_sensors);
1214 gf_list_del(compositor->traverse_state->use_stack);
1215 #ifndef GPAC_DISABLE_3D
1216 gf_list_del(compositor->traverse_state->local_lights);
1217
1218 compositor_3d_delete_fbo(&compositor->fbo_id, &compositor->fbo_tx_id, &compositor->fbo_depth_id, compositor->external_tx_id);
1219 #endif
1220
1221 memset(compositor->traverse_state, 0, sizeof(GF_TraverseState));
1222
1223 compositor->traverse_state->vrml_sensors = gf_list_new();
1224 compositor->traverse_state->use_stack = gf_list_new();
1225 #ifndef GPAC_DISABLE_3D
1226 compositor->traverse_state->local_lights = gf_list_new();
1227 #endif
1228
1229 gf_mx2d_init(compositor->traverse_state->transform);
1230 gf_cmx_init(&compositor->traverse_state->color_mat);
1231 compositor->traverse_state->immediate_draw = mode2d;
1232
1233 #ifdef GF_SR_USE_DEPTH
1234 compositor->traverse_state->depth_gain = FIX_ONE;
1235 compositor->traverse_state->depth_offset = 0;
1236 #endif
1237
1238 #ifndef GPAC_DISABLE_3D
1239 //force a recompute of the canvas
1240 if (has_scene && compositor->hybgl_txh) {
1241 compositor->hybgl_txh->width = compositor->hybgl_txh->height = 0;
1242 }
1243 #endif
1244
1245 assert(!compositor->visual->overlays);
1246
1247 compositor->reset_graphics = 0;
1248 compositor->trans_x = compositor->trans_y = 0;
1249 compositor->zoom = FIX_ONE;
1250 compositor->grab_node = NULL;
1251 compositor->grab_use = NULL;
1252 compositor->focus_node = NULL;
1253 compositor->focus_text_type = 0;
1254 compositor->frame_number = 0;
1255 if (compositor->video_memory!=2)
1256 compositor->video_memory = compositor->was_system_memory ? 0 : 1;
1257 compositor->rotation = 0;
1258
1259 gf_list_reset(compositor->focus_ancestors);
1260 gf_list_reset(compositor->focus_use_stack);
1261
1262 #ifdef GF_SR_USE_VIDEO_CACHE
1263 gf_list_reset(compositor->cached_groups);
1264 compositor->video_cache_current_size = 0;
1265 gf_list_reset(compositor->cached_groups_queue);
1266 #endif
1267
1268 /*force resetup in case we're switching coord system*/
1269 compositor->root_visual_setup = 0;
1270 compositor_set_ar_scale(compositor, compositor->scale_x, compositor->scale_x);
1271 }
1272
gf_sc_set_scene(GF_Compositor * compositor,GF_SceneGraph * scene_graph)1273 GF_Err gf_sc_set_scene(GF_Compositor *compositor, GF_SceneGraph *scene_graph)
1274 {
1275 u32 width, height;
1276 Bool do_notif;
1277
1278 if (!compositor) return GF_BAD_PARAM;
1279
1280 gf_sc_lock(compositor, 1);
1281 if (scene_graph && !compositor->scene) {
1282 GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor] Attaching new scene\n"));
1283 } else if (!scene_graph && compositor->scene) {
1284 GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor] Detaching scene\n"));
1285 }
1286
1287 if (compositor->audio_renderer && (compositor->scene != scene_graph)) {
1288 GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Reseting audio compositor\n"));
1289 gf_sc_ar_reset(compositor->audio_renderer);
1290 }
1291
1292 GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Reseting event queue\n"));
1293 gf_mx_p(compositor->evq_mx);
1294 while (gf_list_count(compositor->event_queue)) {
1295 GF_QueuedEvent *qev = (GF_QueuedEvent*)gf_list_get(compositor->event_queue, 0);
1296 gf_list_rem(compositor->event_queue, 0);
1297 gf_free(qev);
1298 }
1299 gf_mx_v(compositor->evq_mx);
1300
1301 GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Reseting compositor module\n"));
1302 /*reset main surface*/
1303 gf_sc_reset(compositor, scene_graph ? 1 : 0);
1304
1305 /*set current graph*/
1306 compositor->scene = scene_graph;
1307 do_notif = GF_FALSE;
1308 if (scene_graph) {
1309 GF_Scene *scene_ctx = gf_sg_get_private(scene_graph);
1310 #ifndef GPAC_DISABLE_SVG
1311 SVG_Length *w, *h;
1312 SVG_ViewBox *vb;
1313 Bool is_svg = GF_FALSE;
1314 u32 tag;
1315 GF_Node *top_node;
1316 #endif
1317 Bool had_size_info = compositor->has_size_info;
1318
1319 compositor->timed_nodes_valid = GF_TRUE;
1320 if (scene_ctx && scene_ctx->is_dynamic_scene)
1321 compositor->timed_nodes_valid = GF_FALSE;
1322
1323 /*get pixel size if any*/
1324 gf_sg_get_scene_size_info(compositor->scene, &width, &height);
1325 compositor->has_size_info = (width && height) ? 1 : 0;
1326 if (compositor->has_size_info != had_size_info) compositor->scene_width = compositor->scene_height = 0;
1327
1328 if (compositor->video_memory!=2)
1329 compositor->video_memory = gf_scene_is_dynamic_scene(scene_graph);
1330
1331 #ifndef GPAC_DISABLE_3D
1332 compositor->visual->camera.world_bbox.is_set = 0;
1333 #endif
1334
1335 /*default back color is black*/
1336 if (! (compositor->init_flags & GF_TERM_WINDOWLESS)) {
1337 if (compositor->bc) {
1338 compositor->back_color = compositor->bc;
1339 } else {
1340 compositor->back_color = 0xFF000000;
1341 }
1342 }
1343
1344 #ifndef GPAC_DISABLE_SVG
1345 top_node = gf_sg_get_root_node(compositor->scene);
1346 tag = 0;
1347 if (top_node) tag = gf_node_get_tag(top_node);
1348
1349 w = h = NULL;
1350 vb = NULL;
1351 if ((tag>=GF_NODE_RANGE_FIRST_SVG) && (tag<=GF_NODE_RANGE_LAST_SVG)) {
1352 GF_FieldInfo info;
1353 is_svg = 1;
1354 if (gf_node_get_attribute_by_tag(top_node, TAG_SVG_ATT_width, 0, 0, &info)==GF_OK)
1355 w = info.far_ptr;
1356 if (gf_node_get_attribute_by_tag(top_node, TAG_SVG_ATT_height, 0, 0, &info)==GF_OK)
1357 h = info.far_ptr;
1358 if (gf_node_get_attribute_by_tag(top_node, TAG_SVG_ATT_viewBox, 0, 0, &info)==GF_OK)
1359 vb = info.far_ptr;
1360 }
1361 /*default back color is white*/
1362 if (is_svg && ! (compositor->init_flags & GF_TERM_WINDOWLESS)) compositor->back_color = 0xFFFFFFFF;
1363
1364 /*hack for SVG where size is set in % - negotiate a canvas size*/
1365 if (!compositor->has_size_info && w && h && vb) {
1366 do_notif = 1;
1367 if (w->type!=SVG_NUMBER_PERCENTAGE) {
1368 width = FIX2INT(gf_sc_svg_convert_length_to_display(compositor, w) );
1369 } else if ((u32) FIX2INT(vb->width)<compositor->video_out->max_screen_width) {
1370 width = FIX2INT(vb->width);
1371 } else {
1372 width = SC_DEF_WIDTH;
1373 do_notif = 0;
1374 }
1375 if (h->type!=SVG_NUMBER_PERCENTAGE) {
1376 height = FIX2INT(gf_sc_svg_convert_length_to_display(compositor, h) );
1377 } else if ((u32) FIX2INT(vb->height)<compositor->video_out->max_screen_height) {
1378 height = FIX2INT(vb->height);
1379 } else {
1380 height = SC_DEF_HEIGHT;
1381 do_notif = 0;
1382 }
1383 }
1384 /*we consider that SVG has no size onfo per say, everything is handled by the viewBox if any*/
1385 if (is_svg) {
1386 compositor->has_size_info = 0;
1387 gf_sc_focus_switch_ring(compositor, 0, NULL, 0);
1388 } else
1389 #endif
1390 {
1391 GF_Node *keynav = gf_scene_get_keynav(compositor->scene, NULL);
1392 if (keynav) gf_sc_change_key_navigator(compositor, keynav);
1393 }
1394
1395 /*default back color is key color*/
1396 if (compositor->init_flags & GF_TERM_WINDOWLESS) {
1397 if (compositor->ckey) compositor->back_color = compositor->ckey;
1398 }
1399
1400 /*set scene size only if different, otherwise keep scaling/FS*/
1401 if ( !width || (compositor->scene_width!=width) || !height || (compositor->scene_height!=height)) {
1402 do_notif = do_notif || compositor->has_size_info || (!compositor->scene_width && !compositor->scene_height);
1403 gf_sc_set_scene_size(compositor, width, height, 0);
1404
1405 /*get actual size in pixels*/
1406 width = compositor->scene_width;
1407 height = compositor->scene_height;
1408
1409 if (!compositor->os_wnd) {
1410 /*only notify user if we are attached to a window*/
1411 //do_notif = 0;
1412 if (compositor->video_out->max_screen_width && (width > compositor->video_out->max_screen_width))
1413 width = compositor->video_out->max_screen_width;
1414 if (compositor->video_out->max_screen_height && (height > compositor->video_out->max_screen_height))
1415 height = compositor->video_out->max_screen_height;
1416
1417 gf_sc_set_size(compositor,width, height);
1418 }
1419 }
1420 } else {
1421 gf_sc_ar_reset(compositor->audio_renderer);
1422 compositor->needs_offscreen_gl = GF_FALSE;
1423 }
1424
1425 gf_sc_reset_framerate(compositor);
1426
1427 gf_sc_lock(compositor, 0);
1428 if (scene_graph)
1429 gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
1430
1431 /*here's a nasty trick: the app may respond to this by calling a gf_sc_set_size from a different
1432 thread, but in an atomic way (typically happen on Win32 when changing the window size). WE MUST
1433 NOTIFY THE SIZE CHANGE AFTER RELEASING THE RENDERER MUTEX*/
1434 if (do_notif) {
1435 GF_Event evt;
1436 /*wait for user ack*/
1437 // gf_sc_next_frame_state(compositor, GF_SC_DRAW_NONE);
1438
1439 evt.type = GF_EVENT_SCENE_SIZE;
1440 evt.size.width = width;
1441 evt.size.height = height;
1442 gf_sc_send_event(compositor, &evt);
1443 }
1444 return GF_OK;
1445 }
1446
1447 GF_EXPORT
gf_sc_lock(GF_Compositor * compositor,Bool doLock)1448 void gf_sc_lock(GF_Compositor *compositor, Bool doLock)
1449 {
1450 //GF_LOG(GF_LOG_DEBUG, GF_LOG_CORE, ("[Compositor] Thread ID %d is %s the scene\n", gf_th_id(), doLock ? "locking" : "unlocking" ));
1451 if (doLock)
1452 gf_mx_p(compositor->mx);
1453 else {
1454 gf_mx_v(compositor->mx);
1455 }
1456 }
1457
1458 GF_EXPORT
gf_sc_set_size(GF_Compositor * compositor,u32 NewWidth,u32 NewHeight)1459 GF_Err gf_sc_set_size(GF_Compositor *compositor, u32 NewWidth, u32 NewHeight)
1460 {
1461 Bool lock_ok;
1462
1463 GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("sc_set_size %dx%d\n", NewWidth, NewHeight));
1464 if (compositor->osize.x && compositor->osize.y) {
1465 NewWidth = compositor->osize.x;
1466 NewHeight = compositor->osize.y;
1467 }
1468
1469 if ((compositor->display_width == NewWidth) && (compositor->display_height == NewHeight))
1470 return GF_OK;
1471
1472 if (!NewWidth || !NewHeight) {
1473 compositor->override_size_flags &= ~2;
1474 compositor->msg_type |= GF_SR_CFG_AR;
1475 return GF_OK;
1476 }
1477 /*EXTRA CARE HERE: the caller (user app) is likely a different thread than the compositor one, and depending on window
1478 manager we may get called here as a result of a message sent to user but not yet returned */
1479 lock_ok = gf_mx_try_lock(compositor->mx);
1480 GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("line %d lock_ok %d\n", __LINE__, lock_ok));
1481
1482 compositor->new_width = NewWidth;
1483 compositor->new_height = NewHeight;
1484 compositor->msg_type |= GF_SR_CFG_SET_SIZE;
1485 assert(compositor->new_width);
1486
1487 /*if same size only request for video setup */
1488 compositor->msg_type &= ~GF_SR_CFG_WINDOWSIZE_NOTIF;
1489 if ((compositor->display_width == NewWidth) && (compositor->display_height == NewHeight) ) {
1490 compositor->msg_type |= GF_SR_CFG_WINDOWSIZE_NOTIF;
1491 }
1492 if (lock_ok) gf_sc_lock(compositor, 0);
1493
1494 //forward scene size event before actual resize in case the user cancels the resize
1495 {
1496 GF_Event evt;
1497 evt.type = GF_EVENT_SCENE_SIZE;
1498 evt.size.width = NewWidth;
1499 evt.size.height = NewHeight;
1500 gf_sc_send_event(compositor, &evt);
1501 }
1502
1503 return GF_OK;
1504 }
1505
1506 GF_EXPORT
gf_sc_reload_config(GF_Compositor * compositor)1507 void gf_sc_reload_config(GF_Compositor *compositor)
1508 {
1509 /*changing drivers needs exclusive access*/
1510 gf_sc_lock(compositor, 1);
1511
1512 gf_sc_set_fps(compositor, compositor->fps);
1513
1514 if (compositor->fsize)
1515 compositor->override_size_flags |= 1;
1516 else
1517 compositor->override_size_flags &= ~1;
1518
1519
1520 #ifndef GPAC_DISABLE_3D
1521
1522 if (! (compositor->video_out->hw_caps & GF_VIDEO_HW_OPENGL)) {
1523 if (compositor->player && (compositor->ogl > GF_SC_GLMODE_OFF)) {
1524 GF_LOG(GF_LOG_WARNING, GF_LOG_COMPOSE, ("[Compositor] OpenGL mode requested but no opengl-capable output - disabling openGL\n"));
1525 }
1526 compositor->force_opengl_2d = 0;
1527 compositor->autoconfig_opengl = 0;
1528 compositor->hybrid_opengl = 0;
1529 } else {
1530 compositor->force_opengl_2d = (compositor->ogl==GF_SC_GLMODE_ON) ? 1 : 0;
1531 if (compositor->ogl == GF_SC_GLMODE_AUTO) {
1532 compositor->recompute_ar = 1;
1533 compositor->autoconfig_opengl = 1;
1534 } else {
1535 compositor->hybrid_opengl = (compositor->ogl==GF_SC_GLMODE_HYBRID) ? 1 : 0;
1536 }
1537 }
1538
1539 #ifdef GPAC_USE_GLES1X
1540 compositor->linegl = 1;
1541 compositor->epow2 = 1;
1542 #endif
1543
1544 compositor->visual->nb_views = compositor->nbviews;
1545 compositor->visual->camlay = compositor->camlay;
1546 compositor->visual->autostereo_type = compositor->stereo;
1547 if (compositor->visual->autostereo_type == GF_3D_STEREO_5VSP19) {
1548 if (compositor->visual->nb_views != 5) {
1549 if (compositor->visual->nb_views) {
1550 GF_LOG(GF_LOG_WARNING, GF_LOG_COMPOSE, ("[Compositor] SPV19 interleaving used but only %d views indicated - adjusting to 5 view\n", compositor->visual->nb_views ));
1551 }
1552 compositor->visual->nb_views = 5;
1553 }
1554 }
1555 else if (compositor->visual->autostereo_type == GF_3D_STEREO_8VALIO) {
1556 if (compositor->visual->nb_views != 8) {
1557 if (compositor->visual->nb_views) {
1558 GF_LOG(GF_LOG_WARNING, GF_LOG_COMPOSE, ("[Compositor] ALIO interleaving used but only %d views indicated - adjusting to 8 view\n", compositor->visual->nb_views ));
1559 compositor->visual->nb_views = 8;
1560 }
1561 }
1562 }
1563
1564 if ((compositor->visual->autostereo_type!=GF_3D_STEREO_NONE) && (compositor->visual->autostereo_type <= GF_3D_STEREO_HEADSET)) {
1565 compositor->visual->nb_views = 2;
1566 }
1567
1568 if (compositor->visual->autostereo_type)
1569 compositor->force_opengl_2d = 1;
1570
1571 switch (compositor->visual->autostereo_type) {
1572 case GF_3D_STEREO_ANAGLYPH:
1573 case GF_3D_STEREO_COLUMNS:
1574 case GF_3D_STEREO_ROWS:
1575 if (compositor->visual->nb_views != 2) {
1576 if (compositor->visual->nb_views) {
1577 GF_LOG(GF_LOG_WARNING, GF_LOG_COMPOSE, ("[Compositor] Stereo interleaving used but %d views indicated - adjusting to 2 view\n", compositor->visual->nb_views ));
1578 }
1579 compositor->visual->nb_views = 2;
1580 }
1581 break;
1582 }
1583 if (!compositor->visual->nb_views) compositor->visual->nb_views = 1;
1584
1585 #endif //GPAC_DISABLE_3D
1586
1587 /*load defer mode only once hybrid_opengl is known. If no hybrid openGL and no backbuffer 2D, disable defer rendering*/
1588 if (!compositor->hybrid_opengl && compositor->video_out->hw_caps & GF_VIDEO_HW_DIRECT_ONLY) {
1589 compositor->traverse_state->immediate_draw = 1;
1590 } else {
1591 if (compositor->mode2d==GF_DRAW_MODE_IMMEDIATE)
1592 compositor->traverse_state->immediate_draw = 1;
1593 else if (compositor->mode2d==GF_DRAW_MODE_DEFER_DEBUG) {
1594 compositor->traverse_state->immediate_draw = 0;
1595 compositor->debug_defer = 1;
1596 } else {
1597 compositor->traverse_state->immediate_draw = 0;
1598 }
1599 }
1600
1601
1602 #ifdef GF_SR_USE_DEPTH
1603
1604 #ifndef GPAC_DISABLE_3D
1605 /*if auto-stereo mode, turn on display depth by default*/
1606 if (compositor->visual->autostereo_type && !compositor->dispdepth) {
1607 compositor->dispdepth = -1;
1608 }
1609 #endif
1610
1611 #endif
1612
1613 if (!compositor->video_out->dispdist) {
1614 compositor->video_out->dispdist = compositor->dispdist;
1615 }
1616 if (compositor->sgaze) compositor->gazer_enabled = GF_TRUE;
1617
1618 if (!compositor->video_out->dpi_x) {
1619 compositor->video_out->dpi_x = compositor->dpi.x;
1620 compositor->video_out->dpi_y = compositor->dpi.y;
1621 }
1622
1623 gf_sc_reset_graphics(compositor);
1624 gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
1625
1626 if (compositor->audio_renderer) {
1627 gf_sc_ar_set_volume(compositor->audio_renderer, compositor->avol);
1628 gf_sc_ar_set_pan(compositor->audio_renderer, compositor->apan);
1629 }
1630 gf_sc_lock(compositor, 0);
1631 }
1632
1633 GF_EXPORT
gf_sc_set_option(GF_Compositor * compositor,u32 type,u32 value)1634 GF_Err gf_sc_set_option(GF_Compositor *compositor, u32 type, u32 value)
1635 {
1636 GF_Err e;
1637 gf_sc_lock(compositor, 1);
1638
1639 e = GF_OK;
1640 switch (type) {
1641 case GF_OPT_PLAY_STATE:
1642 gf_sc_set_play_state(compositor, value);
1643 break;
1644 case GF_OPT_AUDIO_VOLUME:
1645 gf_sc_ar_set_volume(compositor->audio_renderer, value);
1646 break;
1647 case GF_OPT_AUDIO_PAN:
1648 gf_sc_ar_set_pan(compositor->audio_renderer, value);
1649 break;
1650 case GF_OPT_AUDIO_MUTE:
1651 gf_sc_ar_mute(compositor->audio_renderer, value);
1652 break;
1653 case GF_OPT_OVERRIDE_SIZE:
1654 compositor->override_size_flags = value ? 1 : 0;
1655 gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
1656 break;
1657 case GF_OPT_STRESS_MODE:
1658 compositor->stress = value;
1659 break;
1660 case GF_OPT_ANTIALIAS:
1661 compositor->aa = value;
1662 gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
1663 break;
1664 case GF_OPT_HIGHSPEED:
1665 compositor->fast = value;
1666 gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
1667 break;
1668 case GF_OPT_DRAW_BOUNDS:
1669 compositor->bvol = value;
1670 gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
1671 break;
1672 case GF_OPT_TEXTURE_TEXT:
1673 compositor->textxt = value;
1674 gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
1675 break;
1676 case GF_OPT_ASPECT_RATIO:
1677 compositor->aspect_ratio = value;
1678 compositor->msg_type |= GF_SR_CFG_AR;
1679 break;
1680 case GF_OPT_INTERACTION_LEVEL:
1681 compositor->interaction_level = value;
1682 gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
1683 break;
1684 case GF_OPT_REFRESH:
1685 gf_sc_reset_graphics(compositor);
1686 compositor->traverse_state->invalidate_all = 1;
1687 gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
1688 break;
1689 case GF_OPT_FULLSCREEN:
1690 if (compositor->fullscreen != value) compositor->msg_type |= GF_SR_CFG_FULLSCREEN;
1691 gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
1692 break;
1693 case GF_OPT_ORIGINAL_VIEW:
1694 compositor_2d_set_user_transform(compositor, FIX_ONE, 0, 0, 0);
1695 gf_sc_set_size(compositor, compositor->scene_width, compositor->scene_height);
1696 break;
1697 case GF_OPT_VISIBLE:
1698 compositor->is_hidden = !value;
1699 if (compositor->video_out->ProcessEvent) {
1700 GF_Event evt;
1701 evt.type = GF_EVENT_SHOWHIDE;
1702 evt.show.show_type = value ? 1 : 0;
1703 e = compositor->video_out->ProcessEvent(compositor->video_out, &evt);
1704 }
1705 gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
1706 break;
1707 case GF_OPT_FREEZE_DISPLAY:
1708 compositor->freeze_display = value;
1709 gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
1710 break;
1711 case GF_OPT_FORCE_AUDIO_CONFIG:
1712 if (value) {
1713 compositor->audio_renderer->config_forced++;
1714 } else if (compositor->audio_renderer->config_forced) {
1715 compositor->audio_renderer->config_forced --;
1716 }
1717 break;
1718 case GF_OPT_RELOAD_CONFIG:
1719 gf_sc_reload_config(compositor);
1720 gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
1721 break;
1722 case GF_OPT_DRAW_MODE:
1723 if (!(compositor->video_out->hw_caps & GF_VIDEO_HW_DIRECT_ONLY)) {
1724 compositor->traverse_state->immediate_draw = (value==GF_DRAW_MODE_IMMEDIATE) ? 1 : 0;
1725 compositor->debug_defer = (value==GF_DRAW_MODE_DEFER_DEBUG) ? 1 : 0;
1726 /*force redraw*/
1727 gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
1728 }
1729 break;
1730 case GF_OPT_SCALABLE_ZOOM:
1731 compositor->sz = value;
1732 /*emulate size message to force AR recompute*/
1733 compositor->msg_type |= GF_SR_CFG_AR;
1734 break;
1735 case GF_OPT_USE_OPENGL:
1736 if (compositor->force_opengl_2d != value) {
1737 compositor->force_opengl_2d = value;
1738 /*force resetup*/
1739 compositor->root_visual_setup = 0;
1740 /*force texture setup when switching to OpenGL*/
1741 if (value) gf_sc_reset_graphics(compositor);
1742 /*force redraw*/
1743 gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
1744 }
1745 break;
1746 case GF_OPT_VIDEO_BENCH:
1747 compositor->bench_mode = value ? GF_TRUE : GF_FALSE;
1748 break;
1749
1750 case GF_OPT_YUV_HARDWARE:
1751 compositor->yuvhw = value;
1752 break;
1753 case GF_OPT_NAVIGATION_TYPE:
1754 compositor->rotation = 0;
1755 compositor_2d_set_user_transform(compositor, FIX_ONE, 0, 0, 0);
1756 #ifndef GPAC_DISABLE_3D
1757 compositor_3d_reset_camera(compositor);
1758 #endif
1759 gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
1760 break;
1761 case GF_OPT_NAVIGATION:
1762 if (! gf_sc_navigation_supported(compositor, value)) {
1763 e = GF_NOT_SUPPORTED;
1764 }
1765 #ifndef GPAC_DISABLE_3D
1766 else if (compositor->visual->type_3d || compositor->active_layer) {
1767 GF_Camera *cam = compositor_3d_get_camera(compositor);
1768 cam->navigate_mode = value;
1769 }
1770 #endif
1771 else {
1772 compositor->navigate_mode = value;
1773 }
1774 break;
1775
1776 case GF_OPT_HEADLIGHT:
1777 #ifndef GPAC_DISABLE_3D
1778 if (compositor->visual->type_3d || compositor->active_layer) {
1779 GF_Camera *cam = compositor_3d_get_camera(compositor);
1780 if (cam->navigation_flags & NAV_ANY) {
1781 if (value)
1782 cam->navigation_flags |= NAV_HEADLIGHT;
1783 else
1784 cam->navigation_flags &= ~NAV_HEADLIGHT;
1785 break;
1786 }
1787 }
1788 #endif
1789 e = GF_NOT_SUPPORTED;
1790 break;
1791
1792 #ifndef GPAC_DISABLE_3D
1793
1794 case GF_OPT_EMULATE_POW2:
1795 compositor->epow2 = value;
1796 break;
1797 case GF_OPT_POLYGON_ANTIALIAS:
1798 compositor->paa = value;
1799 break;
1800 case GF_OPT_BACK_CULL:
1801 compositor->bcull = value;
1802 break;
1803 case GF_OPT_WIREFRAME:
1804 compositor->wire = value;
1805 break;
1806 case GF_OPT_NORMALS:
1807 compositor->norms = value;
1808 break;
1809 #ifdef GPAC_HAS_GLU
1810 case GF_OPT_RASTER_OUTLINES:
1811 compositor->linegl = value;
1812 break;
1813 #endif
1814
1815 case GF_OPT_NO_RECT_TEXTURE:
1816 if (value != compositor->rext) {
1817 compositor->rext = value;
1818 /*RECT texture support - we must reload HW*/
1819 gf_sc_reset_graphics(compositor);
1820 }
1821 break;
1822 case GF_OPT_COLLISION:
1823 compositor->collide_mode = value;
1824 break;
1825 case GF_OPT_GRAVITY:
1826 {
1827 GF_Camera *cam = compositor_3d_get_camera(compositor);
1828 compositor->gravity_on = value;
1829 /*force collision pass*/
1830 cam->last_pos.z -= 1;
1831 gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
1832 }
1833 break;
1834 #endif
1835
1836 case GF_OPT_VIDEO_CACHE_SIZE:
1837 #ifdef GF_SR_USE_VIDEO_CACHE
1838 compositor_set_cache_memory(compositor, 1024*value);
1839 #else
1840 e = GF_NOT_SUPPORTED;
1841 #endif
1842 break;
1843 case GF_OPT_MULTIVIEW_MODE:
1844 compositor->multiview_mode = value;
1845 break;
1846
1847
1848 default:
1849 e = GF_BAD_PARAM;
1850 break;
1851 }
1852 gf_sc_lock(compositor, 0);
1853 return e;
1854 }
1855
1856 GF_EXPORT
gf_sc_is_over(GF_Compositor * compositor,GF_SceneGraph * scene_graph)1857 Bool gf_sc_is_over(GF_Compositor *compositor, GF_SceneGraph *scene_graph)
1858 {
1859 u32 i, count;
1860 count = gf_list_count(compositor->time_nodes);
1861 for (i=0; i<count; i++) {
1862 GF_TimeNode *tn = (GF_TimeNode *)gf_list_get(compositor->time_nodes, i);
1863 if (tn->needs_unregister) continue;
1864
1865 if (scene_graph && (gf_node_get_graph((GF_Node *)tn->udta) != scene_graph))
1866 continue;
1867
1868 switch (gf_node_get_tag((GF_Node *)tn->udta)) {
1869 #ifndef GPAC_DISABLE_VRML
1870 case TAG_MPEG4_TimeSensor:
1871 #endif
1872 #ifndef GPAC_DISABLE_X3D
1873 case TAG_X3D_TimeSensor:
1874 #endif
1875 return 0;
1876
1877 #ifndef GPAC_DISABLE_VRML
1878 case TAG_MPEG4_MovieTexture:
1879 #ifndef GPAC_DISABLE_X3D
1880 case TAG_X3D_MovieTexture:
1881 #endif
1882 if (((M_MovieTexture *)tn->udta)->loop) return 0;
1883 break;
1884 case TAG_MPEG4_AudioClip:
1885 #ifndef GPAC_DISABLE_X3D
1886 case TAG_X3D_AudioClip:
1887 #endif
1888 if (((M_AudioClip*)tn->udta)->loop) return 0;
1889 break;
1890 case TAG_MPEG4_AnimationStream:
1891 if (((M_AnimationStream*)tn->udta)->loop) return 0;
1892 break;
1893 #endif
1894 }
1895 }
1896 /*FIXME - this does not work with SVG/SMIL*/
1897 return 1;
1898 }
1899
1900 GF_EXPORT
gf_sc_get_option(GF_Compositor * compositor,u32 type)1901 u32 gf_sc_get_option(GF_Compositor *compositor, u32 type)
1902 {
1903 switch (type) {
1904 case GF_OPT_PLAY_STATE:
1905 return compositor->paused ? 1 : 0;
1906 case GF_OPT_OVERRIDE_SIZE:
1907 return (compositor->override_size_flags & 1) ? 1 : 0;
1908 case GF_OPT_IS_FINISHED:
1909 if (compositor->interaction_sensors) return 0;
1910 case GF_OPT_IS_OVER:
1911 return gf_sc_is_over(compositor, NULL);
1912 case GF_OPT_STRESS_MODE:
1913 return compositor->stress;
1914 case GF_OPT_AUDIO_VOLUME:
1915 return compositor->audio_renderer->volume;
1916 case GF_OPT_AUDIO_PAN:
1917 return compositor->audio_renderer->pan;
1918 case GF_OPT_AUDIO_MUTE:
1919 return compositor->audio_renderer->mute;
1920
1921 case GF_OPT_ANTIALIAS:
1922 return compositor->aa;
1923 case GF_OPT_HIGHSPEED:
1924 return compositor->fast;
1925 case GF_OPT_ASPECT_RATIO:
1926 return compositor->aspect_ratio;
1927 case GF_OPT_FULLSCREEN:
1928 return compositor->fullscreen;
1929 case GF_OPT_INTERACTION_LEVEL:
1930 return compositor->interaction_level;
1931 case GF_OPT_VISIBLE:
1932 return !compositor->is_hidden;
1933 case GF_OPT_FREEZE_DISPLAY:
1934 return compositor->freeze_display;
1935 case GF_OPT_TEXTURE_TEXT:
1936 return compositor->textxt;
1937 case GF_OPT_USE_OPENGL:
1938 return compositor->force_opengl_2d;
1939
1940 case GF_OPT_DRAW_MODE:
1941 if (compositor->traverse_state->immediate_draw) return GF_DRAW_MODE_IMMEDIATE;
1942 if (compositor->debug_defer) return GF_DRAW_MODE_DEFER_DEBUG;
1943 return GF_DRAW_MODE_DEFER;
1944 case GF_OPT_SCALABLE_ZOOM:
1945 return compositor->sz;
1946 case GF_OPT_YUV_HARDWARE:
1947 return compositor->yuvhw;
1948 case GF_OPT_YUV_FORMAT:
1949 return compositor->yuvhw ? compositor->video_out->yuv_pixel_format : 0;
1950 case GF_OPT_NAVIGATION_TYPE:
1951 #ifndef GPAC_DISABLE_3D
1952 if (compositor->navigation_disabled) return GF_NAVIGATE_TYPE_NONE;
1953 if (compositor->visual->type_3d || compositor->active_layer) {
1954 GF_Camera *cam = compositor_3d_get_camera(compositor);
1955 if ((cam->navigation_flags & NAV_SELECTABLE)) return GF_NAVIGATE_TYPE_3D;
1956 if (!(cam->navigation_flags & NAV_ANY)) return GF_NAVIGATE_TYPE_NONE;
1957 // return ((cam->is_3D || compositor->active_layer) ? GF_NAVIGATE_TYPE_3D : GF_NAVIGATE_TYPE_2D);
1958 return GF_NAVIGATE_TYPE_3D;
1959 } else
1960 #endif
1961 {
1962 return GF_NAVIGATE_TYPE_2D;
1963 }
1964 case GF_OPT_NAVIGATION:
1965 #ifndef GPAC_DISABLE_3D
1966 if (compositor->visual->type_3d || compositor->active_layer) {
1967 GF_Camera *cam = compositor_3d_get_camera(compositor);
1968 return cam->navigate_mode;
1969 }
1970 #endif
1971 return compositor->navigate_mode;
1972
1973 case GF_OPT_HEADLIGHT:
1974 return 0;
1975 case GF_OPT_COLLISION:
1976 return GF_COLLISION_NONE;
1977 case GF_OPT_GRAVITY:
1978 return 0;
1979
1980 case GF_OPT_VIDEO_CACHE_SIZE:
1981 #ifdef GF_SR_USE_VIDEO_CACHE
1982 return compositor->vcsize/1024;
1983 #else
1984 return 0;
1985 #endif
1986 break;
1987 case GF_OPT_NUM_STEREO_VIEWS:
1988 #ifndef GPAC_DISABLE_3D
1989 if (compositor->visual->type_3d) {
1990 if (compositor->visual->nb_views && compositor->visual->autostereo_type > GF_3D_STEREO_LAST_SINGLE_BUFFER)
1991 return compositor->visual->nb_views;
1992 }
1993 #endif
1994 return 1;
1995
1996 default:
1997 return 0;
1998 }
1999 }
2000
2001 GF_EXPORT
gf_sc_map_point(GF_Compositor * compositor,s32 X,s32 Y,Fixed * bifsX,Fixed * bifsY)2002 void gf_sc_map_point(GF_Compositor *compositor, s32 X, s32 Y, Fixed *bifsX, Fixed *bifsY)
2003 {
2004 /*coordinates are in user-like OS....*/
2005 X = X - compositor->display_width/2;
2006 Y = compositor->display_height/2 - Y;
2007 *bifsX = INT2FIX(X);
2008 *bifsY = INT2FIX(Y);
2009 }
2010
2011
2012 GF_EXPORT
gf_sc_get_screen_buffer(GF_Compositor * compositor,GF_VideoSurface * framebuffer,u32 depth_dump_mode)2013 GF_Err gf_sc_get_screen_buffer(GF_Compositor *compositor, GF_VideoSurface *framebuffer, u32 depth_dump_mode)
2014 {
2015 GF_Err e;
2016 if (!compositor || !framebuffer) return GF_BAD_PARAM;
2017 gf_mx_p(compositor->mx);
2018
2019 #ifndef GPAC_DISABLE_3D
2020 if (compositor->visual->type_3d || compositor->hybrid_opengl)
2021 e = compositor_3d_get_screen_buffer(compositor, framebuffer, depth_dump_mode);
2022 else
2023 #endif
2024 /*no depth dump in 2D mode*/
2025 if (depth_dump_mode) e = GF_NOT_SUPPORTED;
2026 else e = compositor->video_out->LockBackBuffer(compositor->video_out, framebuffer, 1);
2027
2028 if (e != GF_OK) gf_mx_v(compositor->mx);
2029 return e;
2030 }
2031
gf_sc_get_offscreen_buffer(GF_Compositor * compositor,GF_VideoSurface * framebuffer,u32 view_idx,GF_CompositorGrabMode depth_dump_mode)2032 GF_Err gf_sc_get_offscreen_buffer(GF_Compositor *compositor, GF_VideoSurface *framebuffer, u32 view_idx, GF_CompositorGrabMode depth_dump_mode)
2033 {
2034 if (!compositor || !framebuffer) return GF_BAD_PARAM;
2035 #ifndef GPAC_DISABLE_3D
2036 if (compositor->visual->type_3d && compositor->visual->nb_views && (compositor->visual->autostereo_type > GF_3D_STEREO_LAST_SINGLE_BUFFER)) {
2037 GF_Err e;
2038 gf_mx_p(compositor->mx);
2039 e = compositor_3d_get_offscreen_buffer(compositor, framebuffer, view_idx, depth_dump_mode);
2040 if (e != GF_OK) gf_mx_v(compositor->mx);
2041 return e;
2042 }
2043 #endif
2044 return GF_BAD_PARAM;
2045 }
2046
2047
2048 GF_EXPORT
gf_sc_release_screen_buffer(GF_Compositor * compositor,GF_VideoSurface * framebuffer)2049 GF_Err gf_sc_release_screen_buffer(GF_Compositor *compositor, GF_VideoSurface *framebuffer)
2050 {
2051 GF_Err e;
2052 if (!compositor || !framebuffer) return GF_BAD_PARAM;
2053
2054 #ifndef GPAC_DISABLE_3D
2055 if (compositor->visual->type_3d || compositor->hybrid_opengl)
2056 e = compositor_3d_release_screen_buffer(compositor, framebuffer);
2057 else
2058 #endif
2059 e = compositor->video_out->LockBackBuffer(compositor->video_out, framebuffer, 0);
2060
2061 gf_mx_v(compositor->mx);
2062 return e;
2063 }
2064
2065 GF_EXPORT
gf_sc_get_fps(GF_Compositor * compositor,Bool absoluteFPS)2066 Double gf_sc_get_fps(GF_Compositor *compositor, Bool absoluteFPS)
2067 {
2068 Double fps;
2069 u32 fidx, num, frames, run_time;
2070
2071 gf_mx_p(compositor->mx);
2072
2073 if (absoluteFPS) {
2074 /*start from last frame and get first frame time*/
2075 fidx = compositor->current_frame;
2076 frames = 0;
2077 run_time = compositor->frame_dur[fidx];
2078 for (num=0; num<GF_SR_FPS_COMPUTE_SIZE; num++) {
2079 run_time += compositor->frame_dur[fidx];
2080 frames++;
2081 if (frames==GF_SR_FPS_COMPUTE_SIZE) break;
2082 if (!fidx) {
2083 fidx = GF_SR_FPS_COMPUTE_SIZE-1;
2084 } else {
2085 fidx--;
2086 }
2087 }
2088 } else {
2089 /*start from last frame and get first frame time*/
2090 fidx = compositor->current_frame;
2091 run_time = compositor->frame_time[fidx];
2092 fidx = (fidx+1)% GF_SR_FPS_COMPUTE_SIZE;
2093 assert(run_time >= compositor->frame_time[fidx]);
2094 run_time -= compositor->frame_time[fidx];
2095 frames = GF_SR_FPS_COMPUTE_SIZE-1;
2096 }
2097
2098
2099 gf_mx_v(compositor->mx);
2100
2101 if (!run_time) return ((Double) compositor->fps.num)/compositor->fps.den;
2102 fps = 1000*frames;
2103 fps /= run_time;
2104 return fps;
2105 }
2106
2107 GF_EXPORT
gf_sc_register_time_node(GF_Compositor * compositor,GF_TimeNode * tn)2108 void gf_sc_register_time_node(GF_Compositor *compositor, GF_TimeNode *tn)
2109 {
2110 /*may happen with DEF/USE */
2111 if (tn->is_registered) return;
2112 if (tn->needs_unregister) return;
2113 gf_list_add(compositor->time_nodes, tn);
2114 tn->is_registered = 1;
2115 }
2116
2117 GF_EXPORT
gf_sc_unregister_time_node(GF_Compositor * compositor,GF_TimeNode * tn)2118 void gf_sc_unregister_time_node(GF_Compositor *compositor, GF_TimeNode *tn)
2119 {
2120 gf_list_del_item(compositor->time_nodes, tn);
2121 }
2122
gf_sc_recompute_ar(GF_Compositor * compositor,GF_Node * top_node)2123 static void gf_sc_recompute_ar(GF_Compositor *compositor, GF_Node *top_node)
2124 {
2125 Bool force_pause;
2126
2127 // force_pause = compositor->audio_renderer->Frozen ? 0 : 1;
2128 force_pause = GF_FALSE;
2129
2130 #ifndef GPAC_DISABLE_LOG
2131 compositor->visual_config_time = 0;
2132 #endif
2133 if (compositor->recompute_ar) {
2134 #ifndef GPAC_DISABLE_3D
2135 u32 prev_type_3d = compositor->visual->type_3d;
2136 #endif
2137 #ifndef GPAC_DISABLE_LOG
2138 u32 time=0;
2139
2140 if (gf_log_tool_level_on(GF_LOG_RTI, GF_LOG_DEBUG)) {
2141 time = gf_sys_clock();
2142 }
2143 #endif
2144 if (force_pause)
2145 gf_sc_ar_control(compositor->audio_renderer, GF_SC_AR_PAUSE);
2146
2147 #ifndef GPAC_DISABLE_3D
2148 if (compositor->autoconfig_opengl) {
2149 compositor->visual->type_3d = 1;
2150 }
2151 if (compositor->visual->type_3d) {
2152 compositor_3d_set_aspect_ratio(compositor);
2153 gf_sc_load_opengl_extensions(compositor, compositor->visual->type_3d ? GF_TRUE : GF_FALSE);
2154 #ifndef GPAC_USE_GLES1X
2155 visual_3d_init_shaders(compositor->visual);
2156 #endif
2157 if (compositor->autoconfig_opengl) {
2158 u32 mode = compositor->ogl;
2159 compositor->autoconfig_opengl = 0;
2160 compositor->force_opengl_2d = 0;
2161 compositor->hybrid_opengl = GF_FALSE;
2162 compositor->visual->type_3d = prev_type_3d;
2163
2164 #if !defined(GPAC_USE_TINYGL) && !defined(GPAC_USE_GLES1X)
2165 //enable hybrid mode by default
2166 if (compositor->visual->compositor->shader_mode_disabled && (mode==GF_SC_GLMODE_HYBRID) ) {
2167 mode = GF_SC_GLMODE_OFF;
2168 }
2169 #endif
2170 switch (mode) {
2171 case GF_SC_GLMODE_OFF:
2172 break;
2173 case GF_SC_GLMODE_ON:
2174 compositor->force_opengl_2d = 1;
2175 if (!compositor->visual->type_3d)
2176 compositor->visual->type_3d = 1;
2177 break;
2178 case GF_SC_GLMODE_AUTO:
2179 case GF_SC_GLMODE_HYBRID:
2180 compositor->hybrid_opengl = GF_TRUE;
2181 break;
2182 }
2183 }
2184
2185 }
2186 if (!compositor->visual->type_3d)
2187 #endif
2188 {
2189 compositor_2d_set_aspect_ratio(compositor);
2190 #ifndef GPAC_DISABLE_3D
2191 if (compositor->hybrid_opengl) {
2192 gf_sc_load_opengl_extensions(compositor, GF_TRUE);
2193 #ifndef GPAC_USE_GLES1X
2194 visual_3d_init_shaders(compositor->visual);
2195 #endif
2196 if (!compositor->visual->hybgl_drawn.list) {
2197 ra_init(&compositor->visual->hybgl_drawn);
2198 }
2199 }
2200 #endif
2201 }
2202
2203 if (force_pause )
2204 gf_sc_ar_control(compositor->audio_renderer, GF_SC_AR_RESUME);
2205
2206 #ifndef GPAC_DISABLE_LOG
2207 if (gf_log_tool_level_on(GF_LOG_RTI, GF_LOG_DEBUG)) {
2208 compositor->visual_config_time = gf_sys_clock() - time;
2209 }
2210 #endif
2211
2212 #ifndef GPAC_DISABLE_VRML
2213 compositor_evaluate_envtests(compositor, 0);
2214 #endif
2215 //fullscreen was postponed, retry now that the AR has been recomputed
2216 if (compositor->fullscreen_postponed) {
2217 compositor->fullscreen_postponed = 0;
2218 compositor->msg_type |= GF_SR_CFG_FULLSCREEN;
2219 }
2220
2221 if (compositor->vout) {
2222 gf_filter_pid_set_property(compositor->vout, GF_PROP_PID_WIDTH, &PROP_UINT(compositor->output_width) );
2223 gf_filter_pid_set_property(compositor->vout, GF_PROP_PID_HEIGHT, &PROP_UINT(compositor->output_height) );
2224 gf_filter_pid_set_property(compositor->vout, GF_PROP_PID_FPS, &PROP_FRAC(compositor->fps) );
2225 }
2226 }
2227 }
2228
2229
2230
gf_sc_setup_root_visual(GF_Compositor * compositor,GF_Node * top_node)2231 static void gf_sc_setup_root_visual(GF_Compositor *compositor, GF_Node *top_node)
2232 {
2233 if (top_node && !compositor->root_visual_setup) {
2234 GF_SceneGraph *scene = compositor->scene;
2235 u32 node_tag;
2236 #ifndef GPAC_DISABLE_3D
2237 Bool force_navigate=0;
2238 Bool was_3d = compositor->visual->type_3d;
2239 #endif
2240 compositor->root_visual_setup = 1;
2241 compositor->visual->center_coords = 1;
2242
2243 compositor->traverse_state->pixel_metrics = 1;
2244 compositor->traverse_state->min_hsize = INT2FIX(MIN(compositor->scene_width, compositor->scene_height)) / 2;
2245
2246 node_tag = gf_node_get_tag(top_node);
2247 switch (node_tag) {
2248
2249 #ifndef GPAC_DISABLE_VRML
2250 case TAG_MPEG4_OrderedGroup:
2251 case TAG_MPEG4_Layer2D:
2252 #ifndef GPAC_DISABLE_3D
2253 /*move to perspective 3D when simulating depth*/
2254 #ifdef GF_SR_USE_DEPTH
2255 if (compositor->dispdepth) {
2256 compositor->visual->type_3d = 0;
2257 compositor->visual->camera.is_3D = 0;
2258 } else
2259 #endif
2260 {
2261 compositor->visual->type_3d = 0;
2262 compositor->visual->camera.is_3D = 0;
2263 }
2264 #endif
2265 compositor->traverse_state->pixel_metrics = gf_sg_use_pixel_metrics(scene);
2266 break;
2267 case TAG_MPEG4_Group:
2268 case TAG_MPEG4_Layer3D:
2269 #ifndef GPAC_DISABLE_3D
2270 compositor->visual->type_3d = 2;
2271 compositor->visual->camera.is_3D = 1;
2272 #endif
2273 compositor->traverse_state->pixel_metrics = gf_sg_use_pixel_metrics(scene);
2274 break;
2275 #ifndef GPAC_DISABLE_X3D
2276 case TAG_X3D_Group:
2277 #ifndef GPAC_DISABLE_3D
2278 compositor->visual->type_3d = 3;
2279 #endif
2280 compositor->traverse_state->pixel_metrics = gf_sg_use_pixel_metrics(scene);
2281 break;
2282 #endif /*GPAC_DISABLE_X3D*/
2283
2284
2285
2286 #endif /*GPAC_DISABLE_VRML*/
2287
2288 #ifndef GPAC_DISABLE_SVG
2289 case TAG_SVG_svg:
2290 #ifndef GPAC_DISABLE_3D
2291 #ifdef GF_SR_USE_DEPTH
2292 if (compositor->dispdepth>=0) {
2293 compositor->visual->type_3d = 2;
2294 compositor->visual->camera.is_3D = 1;
2295 } else
2296 #endif
2297 {
2298 compositor->visual->type_3d = 0;
2299 compositor->visual->camera.is_3D = 0;
2300 }
2301 #endif
2302 compositor->visual->center_coords = 0;
2303 compositor->root_visual_setup = 2;
2304 break;
2305 #endif /*GPAC_DISABLE_SVG*/
2306 }
2307
2308 /*!! by default we don't set the focus on the content - this is conform to SVG and avoids displaying the
2309 focus box for MPEG-4 !! */
2310
2311 /*setup OpenGL & camera mode*/
2312 #ifndef GPAC_DISABLE_3D
2313 if (compositor->inherit_type_3d && !compositor->visual->type_3d) {
2314 compositor->visual->type_3d = 2;
2315 compositor->visual->camera.is_3D = 1;
2316 }
2317 /*request for OpenGL drawing in 2D*/
2318 else if ( (compositor->force_opengl_2d && !compositor->visual->type_3d)
2319 || (compositor->hybrid_opengl && compositor->force_type_3d)) {
2320
2321 compositor->force_type_3d=0;
2322 compositor->visual->type_3d = 1;
2323 if (compositor->force_opengl_2d==2) force_navigate=1;
2324 }
2325
2326 if (compositor->drv==GF_SC_DRV_AUTO)
2327 gf_sc_check_video_driver(compositor);
2328
2329 if (! (compositor->video_out->hw_caps & GF_VIDEO_HW_OPENGL)) {
2330 compositor->visual->type_3d = 0;
2331 compositor->visual->camera.is_3D = 0;
2332 }
2333 compositor->visual->camera.is_3D = (compositor->visual->type_3d>1) ? 1 : 0;
2334 if (!compositor->visual->camera.is_3D)
2335 camera_set_2d(&compositor->visual->camera);
2336
2337 camera_invalidate(&compositor->visual->camera);
2338 if (force_navigate) {
2339 compositor->visual->camera.navigate_mode = GF_NAVIGATE_EXAMINE;
2340 compositor->visual->camera.had_nav_info = 0;
2341 }
2342 #endif
2343
2344 GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor] Main scene setup - pixel metrics %d - center coords %d\n", compositor->traverse_state->pixel_metrics, compositor->visual->center_coords));
2345
2346 compositor->recompute_ar = 1;
2347 #ifndef GPAC_DISABLE_3D
2348 /*change in 2D/3D config, force AR recompute/video restup*/
2349 if (was_3d != compositor->visual->type_3d) compositor->recompute_ar = was_3d ? 1 : 2;
2350 #endif
2351 }
2352 }
2353
2354
gf_sc_draw_scene(GF_Compositor * compositor)2355 static Bool gf_sc_draw_scene(GF_Compositor *compositor)
2356 {
2357 u32 flags;
2358
2359 GF_Node *top_node = gf_sg_get_root_node(compositor->scene);
2360
2361 if (!top_node && !compositor->visual->last_had_back && !compositor->visual->cur_context) {
2362 //GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Scene has no root node, nothing to draw\n"));
2363 //nothing to draw, skip flush
2364 compositor->skip_flush = 1;
2365 return GF_FALSE;
2366 }
2367
2368 #ifdef GF_SR_USE_VIDEO_CACHE
2369 if (!compositor->vcsize)
2370 compositor->traverse_state->in_group_cache = 1;
2371 #endif
2372
2373 flags = compositor->traverse_state->immediate_draw;
2374 if (compositor->video_setup_failed) {
2375 compositor->skip_flush = 1;
2376 }
2377 else {
2378 if (compositor->nodes_pending) {
2379 u32 i, count, n_count;
2380 i=0;
2381 count = gf_list_count(compositor->nodes_pending);
2382 while (i<count) {
2383 GF_Node *n = (GF_Node *)gf_list_get(compositor->nodes_pending, i);
2384 gf_node_traverse(n, NULL);
2385 if (!compositor->nodes_pending) break;
2386 n_count = gf_list_count(compositor->nodes_pending);
2387 if (n_count==count) i++;
2388 else count=n_count;
2389 }
2390 }
2391 if (compositor->passthrough_txh) {
2392 gf_sc_setup_passthrough(compositor);
2393 compositor->traverse_state->immediate_draw = 1;
2394 }
2395
2396 if (! visual_draw_frame(compositor->visual, top_node, compositor->traverse_state, 1)) {
2397 /*android backend uses opengl without telling it to us, we need an ugly hack here ...*/
2398 #ifdef GPAC_CONFIG_ANDROID
2399 compositor->skip_flush = 0;
2400 #else
2401 if (compositor->skip_flush==2) {
2402 compositor->skip_flush = 0;
2403 } else {
2404 compositor->skip_flush = 1;
2405 }
2406 #endif
2407 }
2408
2409 }
2410
2411
2412 compositor->traverse_state->immediate_draw = flags;
2413 #ifdef GF_SR_USE_VIDEO_CACHE
2414 gf_list_reset(compositor->cached_groups_queue);
2415 #endif
2416 GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Frame %d - drawing done\n", compositor->frame_number));
2417
2418 /*only send the resize notification once the frame has been dra*/
2419 if (compositor->recompute_ar) {
2420 compositor_send_resize_event(compositor, NULL, 0, 0, 0, 1);
2421 compositor->recompute_ar = 0;
2422 }
2423 compositor->zoom_changed = 0;
2424 compositor->audio_renderer->scene_ready = GF_TRUE;
2425 return GF_TRUE;
2426 }
2427
2428
2429 #ifndef GPAC_DISABLE_LOG
2430 //defined in smil_anim ...
2431 extern u32 time_spent_in_anim;
2432 #endif
2433
compositor_release_textures(GF_Compositor * compositor,Bool frame_drawn)2434 static void compositor_release_textures(GF_Compositor *compositor, Bool frame_drawn)
2435 {
2436 u32 i, count;
2437 /*release all textures - we must release them to handle a same OD being used by several textures*/
2438 count = gf_list_count(compositor->textures);
2439 for (i=0; i<count; i++) {
2440 GF_TextureHandler *txh = (GF_TextureHandler *)gf_list_get(compositor->textures, i);
2441 gf_sc_texture_release_stream(txh);
2442 if (frame_drawn && txh->tx_io && !(txh->flags & GF_SR_TEXTURE_USED))
2443 gf_sc_texture_reset(txh);
2444 /*remove the use flag*/
2445 txh->flags &= ~GF_SR_TEXTURE_USED;
2446 }
2447 }
2448
2449
gf_sc_render_frame(GF_Compositor * compositor)2450 void gf_sc_render_frame(GF_Compositor *compositor)
2451 {
2452 #ifndef GPAC_DISABLE_SCENEGRAPH
2453 GF_SceneGraph *sg;
2454 #endif
2455 GF_List *temp_queue;
2456 u32 in_time, end_time, i, count, frame_duration, frame_ts, frame_draw_type_bck;
2457 Bool frame_drawn, has_timed_nodes=GF_FALSE, has_tx_streams=GF_FALSE, all_tx_done=GF_TRUE;
2458
2459 #ifndef GPAC_DISABLE_LOG
2460 s32 event_time, route_time, smil_timing_time=0, time_node_time, texture_time, traverse_time, flush_time, txtime;
2461 #endif
2462
2463 /*lock compositor for the whole cycle*/
2464 gf_sc_lock(compositor, 1);
2465 // GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Entering render_frame \n"));
2466
2467 in_time = gf_sys_clock();
2468
2469 gf_sc_texture_cleanup_hw(compositor);
2470
2471 /*first thing to do, let the video output handle user event if it is not threaded*/
2472 compositor->video_out->ProcessEvent(compositor->video_out, NULL);
2473
2474 //handle all unthreaded extensions
2475 if (compositor->unthreaded_extensions) {
2476 count = gf_list_count(compositor->unthreaded_extensions);
2477 for (i=0; i<count; i++) {
2478 GF_CompositorExt *ifce = gf_list_get(compositor->unthreaded_extensions, i);
2479 ifce->process(ifce, GF_COMPOSITOR_EXT_PROCESS, NULL);
2480 }
2481 }
2482
2483 if (compositor->freeze_display) {
2484 gf_sc_lock(compositor, 0);
2485 if (!compositor->bench_mode && compositor->player) {
2486 compositor->scene_sampled_clock = gf_sc_ar_get_clock(compositor->audio_renderer);
2487 }
2488 return;
2489 }
2490
2491 gf_sc_reconfig_task(compositor);
2492
2493 /* if there is no scene*/
2494 if (!compositor->scene && !gf_list_count(compositor->extra_scenes) ) {
2495 gf_sc_draw_scene(compositor);
2496 if (compositor->player) {
2497 //increase clock in bench mode before releasing mutex
2498 if (compositor->bench_mode && (compositor->force_bench_frame==1)) {
2499 compositor->scene_sampled_clock += compositor->frame_duration;
2500 }
2501 } else {
2502 if (compositor->root_scene && compositor->root_scene->graph_attached) {
2503 compositor->check_eos_state = 2;
2504 }
2505 }
2506 gf_sc_lock(compositor, 0);
2507 compositor->force_bench_frame=0;
2508 compositor->frame_draw_type = 0;
2509 compositor->recompute_ar = 0;
2510 compositor->ms_until_next_frame = compositor->frame_duration;
2511 return;
2512 }
2513
2514 if (compositor->reset_graphics) {
2515 gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
2516 visual_reset_graphics(compositor->visual);
2517
2518 #ifndef GPAC_DISABLE_3D
2519 compositor_3d_delete_fbo(&compositor->fbo_id, &compositor->fbo_tx_id, &compositor->fbo_depth_id, compositor->external_tx_id);
2520 #endif
2521
2522 }
2523
2524 /*process pending user events*/
2525 #ifndef GPAC_DISABLE_LOG
2526 event_time = gf_sys_clock();
2527 #endif
2528 //swap event queus
2529 gf_mx_p(compositor->evq_mx);
2530 temp_queue = compositor->event_queue;
2531 compositor->event_queue = compositor->event_queue_back;
2532 compositor->event_queue_back = temp_queue;
2533 gf_mx_v(compositor->evq_mx);
2534 while (gf_list_count(compositor->event_queue_back)) {
2535 GF_QueuedEvent *qev = (GF_QueuedEvent*)gf_list_get(compositor->event_queue_back, 0);
2536 gf_list_rem(compositor->event_queue_back, 0);
2537
2538 if (qev->target) {
2539 #ifndef GPAC_DISABLE_SVG
2540 gf_sg_fire_dom_event(qev->target, &qev->dom_evt, qev->sg, NULL);
2541 #endif
2542 } else if (qev->node) {
2543 #ifndef GPAC_DISABLE_SVG
2544 gf_dom_event_fire(qev->node, &qev->dom_evt);
2545 #endif
2546 } else {
2547 gf_sc_exec_event(compositor, &qev->evt);
2548 }
2549 gf_free(qev);
2550 }
2551 #ifndef GPAC_DISABLE_LOG
2552 event_time = gf_sys_clock() - event_time;
2553 #endif
2554
2555 if (compositor->player) {
2556 if (!compositor->bench_mode) {
2557 compositor->scene_sampled_clock = gf_sc_ar_get_clock(compositor->audio_renderer);
2558 } else {
2559 if (compositor->force_bench_frame==1) {
2560 //a system frame is pending on a future frame - we must increase our time
2561 compositor->scene_sampled_clock += compositor->frame_duration;
2562 }
2563 compositor->force_bench_frame = 0;
2564 }
2565 }
2566
2567
2568 //first update all natural textures to figure out timing
2569 compositor->frame_delay = 0;
2570 compositor->ms_until_next_frame = GF_INT_MAX;
2571 frame_duration = compositor->frame_duration;
2572
2573 if (compositor->auto_rotate)
2574 compositor_handle_auto_navigation(compositor);
2575
2576 /*first update time nodes since they may trigger play/stop request*/
2577
2578 compositor->force_late_frame_draw = GF_FALSE;
2579
2580 #ifndef GPAC_DISABLE_SVG
2581
2582 #ifndef GPAC_DISABLE_LOG
2583 smil_timing_time = gf_sys_clock();
2584 #endif
2585 if (gf_smil_notify_timed_elements(compositor->scene)) {
2586 gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
2587 }
2588 #ifndef GPAC_DISABLE_SCENEGRAPH
2589 i = 0;
2590 while ((sg = (GF_SceneGraph*)gf_list_enum(compositor->extra_scenes, &i))) {
2591 if (gf_smil_notify_timed_elements(sg)) {
2592 gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
2593 }
2594 }
2595 #endif
2596
2597 #ifndef GPAC_DISABLE_LOG
2598 smil_timing_time = gf_sys_clock() - smil_timing_time;
2599 #endif
2600
2601 #endif //GPAC_DISABLE_SVG
2602
2603
2604 #ifndef GPAC_DISABLE_LOG
2605 time_node_time = gf_sys_clock();
2606 #endif
2607 /*update all timed nodes */
2608 count = gf_list_count(compositor->time_nodes);
2609 for (i=0; i<count; i++) {
2610 GF_TimeNode *tn = (GF_TimeNode *)gf_list_get(compositor->time_nodes, i);
2611 if (!tn->needs_unregister) tn->UpdateTimeNode(tn);
2612 if (tn->needs_unregister) {
2613 tn->is_registered = 0;
2614 tn->needs_unregister = 0;
2615 gf_list_rem(compositor->time_nodes, i);
2616 i--;
2617 count--;
2618 continue;
2619 }
2620 has_timed_nodes = compositor->timed_nodes_valid;
2621 }
2622 #ifndef GPAC_DISABLE_LOG
2623 time_node_time = gf_sys_clock() - time_node_time;
2624 #endif
2625
2626
2627 compositor->passthrough_txh = NULL;
2628 #ifndef GPAC_DISABLE_LOG
2629 texture_time = gf_sys_clock();
2630 #endif
2631 //compute earliest frame TS in all textures that need refresh (skip textures with same timing)
2632 frame_ts = (u32) -1;
2633
2634 /*update all video textures*/
2635 frame_draw_type_bck = compositor->frame_draw_type;
2636 compositor->frame_draw_type = 0;
2637 has_tx_streams = GF_FALSE;
2638 count = gf_list_count(compositor->textures);
2639 for (i=0; i<count; i++) {
2640 GF_TextureHandler *txh = (GF_TextureHandler *)gf_list_get(compositor->textures, i);
2641 if (!txh) break;
2642 //this is not a natural (video) texture
2643 if (! txh->stream) continue;
2644 has_tx_streams = GF_TRUE;
2645
2646 /*signal graphics reset before updating*/
2647 if (compositor->reset_graphics && txh->tx_io) gf_sc_texture_reset(txh);
2648 txh->update_texture_fcnt(txh);
2649
2650 if (!txh->stream_finished) {
2651 u32 d = gf_mo_get_min_frame_dur(txh->stream);
2652 if (d && (d < frame_duration)) frame_duration = d;
2653 //if the texture needs update (new frame), compute its timestamp in system timebase
2654 if (txh->needs_refresh) {
2655 u32 ts = gf_mo_map_timestamp_to_sys_clock(txh->stream, txh->stream->timestamp);
2656 if (ts<frame_ts) frame_ts = ts;
2657 }
2658 all_tx_done=0;
2659 }
2660 }
2661 #ifndef GPAC_DISABLE_LOG
2662 texture_time = gf_sys_clock() - texture_time;
2663 #endif
2664 if (compositor->player) {
2665 if (frame_draw_type_bck)
2666 compositor->frame_draw_type = frame_draw_type_bck;
2667 }
2668 //in non player mode, don't redraw frame if due to end of streams on textures
2669 else if (!frame_draw_type_bck && compositor->frame_draw_type && all_tx_done)
2670 compositor->frame_draw_type = 0;
2671
2672
2673 if (!compositor->player) {
2674 if (compositor->passthrough_txh && compositor->passthrough_txh->frame_ifce && !compositor->passthrough_txh->frame_ifce->get_plane) {
2675 compositor->passthrough_txh = NULL;
2676 }
2677 if (!compositor->passthrough_txh && frame_draw_type_bck)
2678 compositor->frame_draw_type = frame_draw_type_bck;
2679
2680 if (compositor->passthrough_txh && compositor->passthrough_txh->width && compositor->passthrough_txh->needs_refresh) {
2681 compositor->scene_sampled_clock = compositor->passthrough_txh->last_frame_time/* + dur*/;
2682 }
2683 //we were buffering and are now no longer, update scene clock
2684 if (compositor->passthrough_txh && compositor->passthrough_check_buffer && !gf_mo_is_buffering(compositor->passthrough_txh->stream)) {
2685 u32 dur = gf_mo_get_min_frame_dur(compositor->passthrough_txh->stream);
2686 compositor->passthrough_check_buffer = GF_FALSE;
2687 compositor->scene_sampled_clock = compositor->passthrough_txh->last_frame_time + dur;
2688 }
2689 }
2690
2691 //it may happen that we have a reconfigure request at this stage, especially if updating one of the textures
2692 //forced a relayout - do it right away
2693 if (compositor->msg_type) {
2694 gf_sc_lock(compositor, 0);
2695 return;
2696 }
2697
2698
2699 if (compositor->focus_text_type) {
2700 if (!compositor->caret_next_draw_time) {
2701 compositor->caret_next_draw_time = gf_sys_clock();
2702 compositor->show_caret = 1;
2703 }
2704 if (compositor->caret_next_draw_time <= compositor->last_frame_time) {
2705 compositor->frame_draw_type = GF_SC_DRAW_FRAME;
2706 compositor->caret_next_draw_time+=500;
2707 compositor->show_caret = !compositor->show_caret;
2708 compositor->text_edit_changed = 1;
2709 }
2710 }
2711
2712
2713 #ifndef GPAC_DISABLE_VRML
2714 /*execute all routes:
2715 before updating composite textures, otherwise nodes inside composite texture may never see their dirty flag set
2716 after updating timed nodes to trigger all events based on time
2717 */
2718 #ifndef GPAC_DISABLE_LOG
2719 route_time = gf_sys_clock();
2720 #endif
2721
2722 gf_sg_activate_routes(compositor->scene);
2723
2724 #ifndef GPAC_DISABLE_SCENEGRAPH
2725 i = 0;
2726 while ((sg = (GF_SceneGraph*)gf_list_enum(compositor->extra_scenes, &i))) {
2727 gf_sg_activate_routes(sg);
2728 }
2729 #endif
2730
2731 #ifndef GPAC_DISABLE_LOG
2732 route_time = gf_sys_clock() - route_time;
2733 #endif
2734
2735 #else
2736 #ifndef GPAC_DISABLE_LOG
2737 route_time = 0;
2738 #endif
2739 #endif /*GPAC_DISABLE_VRML*/
2740
2741
2742 /*setup root visual BEFORE updating the composite textures (since they may depend on root setup)*/
2743 gf_sc_setup_root_visual(compositor, gf_sg_get_root_node(compositor->scene));
2744
2745 /*setup display before updating composite textures (some may require a valid openGL context)*/
2746 gf_sc_recompute_ar(compositor, gf_sg_get_root_node(compositor->scene) );
2747
2748 if (compositor->video_setup_failed) {
2749 gf_sc_lock(compositor, 0);
2750 return;
2751 }
2752
2753 #ifndef GPAC_DISABLE_LOG
2754 txtime = gf_sys_clock();
2755 #endif
2756 /*update all composite textures*/
2757 compositor->texture_inserted = GF_FALSE;
2758 count = gf_list_count(compositor->textures);
2759 for (i=0; i<count; i++) {
2760 GF_TextureHandler *txh = (GF_TextureHandler *)gf_list_get(compositor->textures, i);
2761 if (!txh) break;
2762 //this is not a composite texture
2763 if (txh->stream) continue;
2764 /*signal graphics reset before updating*/
2765 if (compositor->reset_graphics && txh->tx_io) gf_sc_texture_reset(txh);
2766 txh->update_texture_fcnt(txh);
2767 if (compositor->texture_inserted) {
2768 compositor->texture_inserted = GF_FALSE;
2769 count = gf_list_count(compositor->textures);
2770 i = gf_list_find(compositor->textures, txh);
2771 }
2772 }
2773
2774 //it may happen that we have a reconfigure request at this stage, especially if updating one of the textures update
2775 //forced a relayout - do it right away
2776 if (compositor->msg_type) {
2777 //reset AR recompute flag, it will be reset when msg is handled
2778 compositor->recompute_ar = 0;
2779 gf_sc_lock(compositor, 0);
2780 return;
2781 }
2782 #ifndef GPAC_DISABLE_LOG
2783 texture_time += gf_sys_clock() - txtime;
2784 #endif
2785
2786 compositor->text_edit_changed = 0;
2787 compositor->rebuild_offscreen_textures = 0;
2788
2789 if (compositor->force_next_frame_redraw) {
2790 compositor->force_next_frame_redraw=0;
2791 compositor->frame_draw_type = GF_SC_DRAW_FRAME;
2792 }
2793
2794 //if hidden and player mode, do not draw the scene
2795 if (compositor->is_hidden && compositor->player) {
2796 compositor->frame_draw_type = 0;
2797 }
2798
2799 if (!compositor->player) {
2800 if (compositor->check_eos_state<=1) {
2801 compositor->check_eos_state = 0;
2802 /*check if we have to force a frame dispatch */
2803
2804 //no passthrough texture
2805 if (!compositor->passthrough_txh) {
2806 if (!compositor->vfr) {
2807 //in CFR and no texture associated, always force a redraw
2808 if (!has_tx_streams && has_timed_nodes)
2809 compositor->frame_draw_type = GF_SC_DRAW_FRAME;
2810 //otherwise if texture(s) but not all done, force a redraw
2811 else if (!all_tx_done)
2812 compositor->frame_draw_type = GF_SC_DRAW_FRAME;
2813 //we still have active system pids (BIFS/LASeR/DIMS commands), force a redraw
2814 if (gf_list_count(compositor->systems_pids))
2815 compositor->frame_draw_type = GF_SC_DRAW_FRAME;
2816 //validator always triggers redraw to make sure the scene clock is incremented so that events can be fired
2817 if (compositor->validator_mode)
2818 compositor->frame_draw_type = GF_SC_DRAW_FRAME;
2819 }
2820 }
2821 //we have a passthrough texture, only generate an output frame when we have a new input on the passthrough
2822 else {
2823 //still waiting for initialization either from the passthrough stream or a texture used in the scene
2824 if (!compositor->passthrough_txh->width || !compositor->passthrough_txh->stream->pck || (compositor->ms_until_next_frame<0) ) {
2825 compositor->frame_draw_type = GF_SC_DRAW_NONE;
2826 //prevent release of frame
2827 if (compositor->passthrough_txh->needs_release)
2828 compositor->passthrough_txh->needs_release = 2;
2829 }
2830 //done
2831 else if ((compositor->passthrough_txh->stream_finished) && (compositor->ms_until_next_frame >= 0)) {
2832 compositor->check_eos_state = 2;
2833 }
2834 }
2835 }
2836
2837 }
2838
2839 frame_drawn = (compositor->frame_draw_type==GF_SC_DRAW_FRAME) ? 1 : 0;
2840
2841 /*if invalidated, draw*/
2842 if (compositor->frame_draw_type) {
2843 Bool emit_frame = GF_FALSE;
2844 Bool textures_released = 0;
2845
2846 #ifndef GPAC_DISABLE_LOG
2847 traverse_time = gf_sys_clock();
2848 time_spent_in_anim = 0;
2849 #endif
2850
2851 if (compositor->traverse_state->immediate_draw) {
2852 compositor->frame_draw_type = GF_SC_DRAW_FRAME;
2853 }
2854
2855 /*video flush only*/
2856 if (compositor->frame_draw_type==GF_SC_DRAW_FLUSH) {
2857 compositor->frame_draw_type = 0;
2858 }
2859 /*full render*/
2860 else {
2861 Bool scene_drawn;
2862 compositor->frame_draw_type = 0;
2863
2864 GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Redrawing scene - STB %d\n", compositor->scene_sampled_clock));
2865
2866 scene_drawn = gf_sc_draw_scene(compositor);
2867
2868 #ifndef GPAC_DISABLE_LOG
2869 traverse_time = gf_sys_clock() - traverse_time;
2870 #endif
2871
2872 if (compositor->ms_until_next_frame < 0) {
2873 emit_frame = GF_FALSE;
2874 compositor->last_error = GF_OK;
2875 }
2876 else if (!scene_drawn) emit_frame = GF_FALSE;
2877 else if (compositor->frame_draw_type) emit_frame = GF_FALSE;
2878 else if (compositor->fonts_pending>0) emit_frame = GF_FALSE;
2879 else emit_frame = GF_TRUE;
2880 }
2881 /*and flush*/
2882 #ifndef GPAC_DISABLE_LOG
2883 flush_time = gf_sys_clock();
2884 #endif
2885
2886 if (compositor->init_flags & GF_TERM_INIT_HIDE)
2887 compositor->skip_flush = 1;
2888
2889 //new frame generated, emit packet
2890 if (emit_frame) {
2891 u64 pck_frame_ts=0;
2892 GF_FilterPacket *pck;
2893 frame_ts = 0;
2894 if (compositor->passthrough_pck) {
2895 pck = compositor->passthrough_pck;
2896 compositor->passthrough_pck = NULL;
2897 pck_frame_ts = gf_filter_pck_get_cts(pck);
2898 } else {
2899 if (compositor->video_out==&raw_vout) {
2900 pck = gf_filter_pck_new_shared(compositor->vout, compositor->framebuffer, compositor->framebuffer_size, gf_sc_frame_ifce_done);
2901 } else {
2902 compositor->frame_ifce.user_data = compositor;
2903 compositor->frame_ifce.get_plane = gf_sc_frame_ifce_get_plane;
2904 compositor->frame_ifce.get_gl_texture = NULL;
2905 #ifndef GPAC_DISABLE_3D
2906 if (compositor->fbo_tx_id) {
2907 compositor->frame_ifce.get_gl_texture = gf_sc_frame_ifce_get_gl_texture;
2908 }
2909 #endif
2910 compositor->frame_ifce.flags = GF_FRAME_IFCE_BLOCKING;
2911 pck = gf_filter_pck_new_frame_interface(compositor->vout, &compositor->frame_ifce, gf_sc_frame_ifce_done);
2912 }
2913
2914 if (compositor->passthrough_txh) {
2915 gf_filter_pck_merge_properties(compositor->passthrough_txh->stream->pck, pck);
2916 pck_frame_ts = gf_filter_pck_get_cts(compositor->passthrough_txh->stream->pck);
2917 } else {
2918 //no texture found/updated, use scene sampled clock
2919 if (compositor->timescale) {
2920 frame_ts = compositor->frame_number * compositor->fps.den * compositor->timescale;
2921 frame_ts /= compositor->fps.num;
2922 } else {
2923 frame_ts = compositor->frame_number * compositor->fps.den;
2924 }
2925 gf_filter_pck_set_cts(pck, frame_ts);
2926 }
2927 }
2928 if (pck_frame_ts) {
2929 u64 ts = pck_frame_ts;
2930 ts *= 1000;
2931 ts /= compositor->passthrough_timescale;
2932 frame_ts = (u32) ts;
2933 }
2934 gf_filter_pck_send(pck);
2935 gf_sc_ar_update_video_clock(compositor->audio_renderer, frame_ts);
2936
2937 if (!compositor->player) {
2938 if (compositor->passthrough_txh) {
2939 // update clock if not buffering
2940 if (!gf_mo_is_buffering(compositor->passthrough_txh->stream))
2941 {
2942 u64 next_frame;
2943 next_frame = pck_frame_ts + gf_filter_pck_get_duration(pck);
2944 next_frame *= 1000;
2945 next_frame /= compositor->passthrough_timescale;
2946 assert(next_frame>=compositor->scene_sampled_clock);
2947 compositor->scene_sampled_clock = (u32) next_frame;
2948 }
2949 // if buffering, remember to update clock at next frame
2950 else {
2951 compositor->passthrough_check_buffer = GF_TRUE;
2952 }
2953 if (compositor->passthrough_txh->stream_finished)
2954 compositor->check_eos_state = 2;
2955 } else {
2956 u64 res;
2957 compositor->last_frame_ts = frame_ts;
2958 res = (compositor->frame_number+1);
2959 res *= compositor->fps.den;
2960 res *= 1000;
2961 res /= compositor->fps.num;
2962 assert(res>=compositor->scene_sampled_clock);
2963 compositor->scene_sampled_clock = (u32) res;
2964 }
2965 GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor] Send video frame TS %u (%u ms) - next frame scene clock %d ms - passthrough %p\n", frame_ts, (frame_ts*1000)/compositor->fps.num, compositor->scene_sampled_clock, compositor->passthrough_txh));
2966 } else {
2967 GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor] Send video frame TS %u - AR clock %d\n", frame_ts, compositor->audio_renderer->current_time));
2968 if (compositor->bench_mode) {
2969 compositor->force_bench_frame = 1;
2970 }
2971 compositor->frame_was_produced = GF_TRUE;
2972 }
2973 } else if (!compositor->player) {
2974 frame_drawn = GF_FALSE;
2975 //prevent release of frame
2976 if (compositor->passthrough_txh && compositor->passthrough_txh->needs_release)
2977 compositor->passthrough_txh->needs_release = 2;
2978 }
2979
2980 if (compositor->passthrough_pck) {
2981 gf_filter_pck_discard(compositor->passthrough_pck);
2982 compositor->passthrough_pck = NULL;
2983 }
2984
2985 //if no overlays, release textures before flushing, otherwise we might loose time waiting for vsync
2986 if (!compositor->visual->has_overlays) {
2987 compositor_release_textures(compositor, frame_drawn);
2988 textures_released = 1;
2989 }
2990
2991 //no flush pending
2992 if (!compositor->flush_pending && !compositor->skip_flush) {
2993 gf_sc_flush_video(compositor, GF_TRUE);
2994 }
2995
2996 #ifndef GPAC_DISABLE_LOG
2997 flush_time = gf_sys_clock() - flush_time;
2998 GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Compositor] done flushing frame in %d ms\n", flush_time));
2999 #endif
3000
3001 visual_2d_draw_overlays(compositor->visual);
3002 compositor->last_had_overlays = compositor->visual->has_overlays;
3003
3004 if (!textures_released) {
3005 GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Compositor] Releasing textures after flush\n" ));
3006 compositor_release_textures(compositor, frame_drawn);
3007 }
3008
3009 if (compositor->stress) {
3010 gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
3011 gf_sc_reset_graphics(compositor);
3012 }
3013 compositor->reset_fonts = 0;
3014
3015 } else {
3016
3017 //frame not drawn, release textures
3018 compositor_release_textures(compositor, frame_drawn);
3019
3020 #ifndef GPAC_DISABLE_LOG
3021 traverse_time = 0;
3022 time_spent_in_anim = 0;
3023 flush_time = 0;
3024 compositor->traverse_setup_time = 0;
3025 compositor->traverse_and_direct_draw_time = 0;
3026 compositor->indirect_draw_time = 0;
3027 #endif
3028
3029 if (!compositor->player) {
3030 //if systems frames are pending (not executed because too early), increase clock
3031 if ((compositor->sys_frames_pending && (compositor->ms_until_next_frame>=0) )
3032 //if timed nodes or validator mode (which acts as a timed node firing events), increase scene clock
3033 //in vfr mode
3034 || (compositor->vfr && (has_timed_nodes || compositor->validator_mode) )
3035 ) {
3036 u64 res;
3037 compositor->sys_frames_pending = GF_FALSE;
3038 compositor->frame_number++;
3039 res = compositor->frame_number;
3040 res *= compositor->fps.den;
3041 res *= 1000;
3042 res /= compositor->fps.num;
3043 assert(res >= compositor->scene_sampled_clock);
3044 compositor->scene_sampled_clock = (u32) res;
3045 }
3046 }
3047 }
3048 compositor->reset_graphics = 0;
3049
3050 compositor->last_frame_time = gf_sys_clock();
3051 end_time = compositor->last_frame_time - in_time;
3052
3053 GF_LOG(GF_LOG_DEBUG, GF_LOG_RTI, ("[RTI]\tCompositor Cycle Log\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n",
3054 compositor->networks_time,
3055 compositor->decoders_time,
3056 compositor->frame_number,
3057 compositor->traverse_state->immediate_draw,
3058 compositor->visual_config_time,
3059 event_time,
3060 route_time,
3061 smil_timing_time,
3062 time_node_time,
3063 texture_time,
3064 time_spent_in_anim,
3065 compositor->traverse_setup_time,
3066 compositor->traverse_and_direct_draw_time,
3067 compositor->traverse_and_direct_draw_time - time_spent_in_anim,
3068 compositor->indirect_draw_time,
3069 traverse_time,
3070 flush_time,
3071 end_time));
3072
3073 if (frame_drawn) {
3074 compositor->current_frame = (compositor->current_frame+1) % GF_SR_FPS_COMPUTE_SIZE;
3075 compositor->frame_dur[compositor->current_frame] = end_time;
3076 compositor->frame_time[compositor->current_frame] = compositor->last_frame_time;
3077 compositor->frame_number++;
3078 }
3079 if (compositor->bench_mode && (frame_drawn || (has_timed_nodes&&all_tx_done) )) {
3080 //in bench mode we always increase the clock of the fixed target simulation rate - this needs refinement if video is used ...
3081 compositor->scene_sampled_clock += frame_duration;
3082 }
3083 gf_sc_lock(compositor, 0);
3084
3085 if (frame_drawn) compositor->step_mode = GF_FALSE;
3086
3087 /*old arch code kept for reference*/
3088 #if 0
3089 /*let the owner decide*/
3090 if (compositor->no_regulation)
3091 return;
3092
3093 /*we are in bench mode, just release for a moment the composition, oherwise we will constantly lock the compositor wich may have impact on scene decoding*/
3094 if (compositor->bench_mode) {
3095 gf_sleep(0);
3096 return;
3097 }
3098
3099 //we have a pending frame, return asap - we could sleep until frames matures but this give weird regulation
3100 if (compositor->ms_until_next_frame != GF_INT_MAX) {
3101 compositor->ms_until_next_frame -= end_time;
3102
3103 if (compositor->ms_until_next_frame<=0) {
3104 GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Next frame already due (%d ms late) - not going to sleep\n", - compositor->ms_until_next_frame));
3105 compositor->ms_until_next_frame=0;
3106 return;
3107 }
3108
3109 compositor->ms_until_next_frame = MIN(compositor->ms_until_next_frame, (s32) frame_duration );
3110 GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Next frame due in %d ms\n", compositor->ms_until_next_frame));
3111 if (compositor->ms_until_next_frame > 2) {
3112 u64 start = gf_sys_clock_high_res();
3113 u64 diff=0;
3114 u64 wait_for = 1000 * (u64) compositor->ms_until_next_frame;
3115 while (! compositor->msg_type) {
3116 gf_sleep(1);
3117 diff = gf_sys_clock_high_res() - start;
3118 if (diff >= wait_for)
3119 break;
3120 }
3121 GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Compositor slept %d ms until next frame (msg type %d)\n", diff/1000, compositor->msg_type));
3122 }
3123 return;
3124 }
3125
3126 if (end_time > frame_duration) {
3127 GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Compositor did not go to sleep\n"));
3128 return;
3129 }
3130
3131 /*compute sleep time till next frame*/
3132 end_time %= frame_duration;
3133 gf_sleep(frame_duration - end_time);
3134 GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Compositor slept for %d ms\n", frame_duration - end_time));
3135 #endif
3136
3137 }
3138
gf_sc_visual_is_registered(GF_Compositor * compositor,GF_VisualManager * visual)3139 Bool gf_sc_visual_is_registered(GF_Compositor *compositor, GF_VisualManager *visual)
3140 {
3141 GF_VisualManager *tmp;
3142 u32 i = 0;
3143 while ((tmp = (GF_VisualManager *)gf_list_enum(compositor->visuals, &i))) {
3144 if (tmp == visual) return 1;
3145 }
3146 return 0;
3147 }
3148
gf_sc_visual_register(GF_Compositor * compositor,GF_VisualManager * visual)3149 void gf_sc_visual_register(GF_Compositor *compositor, GF_VisualManager *visual)
3150 {
3151 if (gf_sc_visual_is_registered(compositor, visual)) return;
3152 gf_list_add(compositor->visuals, visual);
3153 }
3154
gf_sc_visual_unregister(GF_Compositor * compositor,GF_VisualManager * visual)3155 void gf_sc_visual_unregister(GF_Compositor *compositor, GF_VisualManager *visual)
3156 {
3157 gf_list_del_item(compositor->visuals, visual);
3158 }
3159
gf_sc_traverse_subscene_ex(GF_Compositor * compositor,GF_Node * inline_parent,GF_SceneGraph * subscene,void * rs)3160 void gf_sc_traverse_subscene_ex(GF_Compositor *compositor, GF_Node *inline_parent, GF_SceneGraph *subscene, void *rs)
3161 {
3162 Fixed min_hsize, vp_scale;
3163 Bool use_pm, prev_pm, prev_coord;
3164 SFVec2f prev_vp;
3165 s32 flip_coords;
3166 u32 h, w, tag;
3167 GF_Matrix2D transf;
3168 GF_SceneGraph *in_scene;
3169 GF_Node *inline_root;
3170 GF_TraverseState *tr_state = (GF_TraverseState *)rs;
3171
3172 /*we don't traverse subscenes until the root one is setup*/
3173 if (!compositor->root_visual_setup) return;
3174
3175 inline_root = gf_sg_get_root_node(subscene);
3176 if (!inline_root) return;
3177
3178 if (!gf_scene_is_over(subscene))
3179 tr_state->subscene_not_over ++;
3180
3181 flip_coords = 0;
3182 in_scene = gf_node_get_graph(inline_root);
3183 w = h = 0;
3184
3185 /*check parent/child doc orientation*/
3186
3187 /*check child doc*/
3188 tag = gf_node_get_tag(inline_root);
3189 if (tag < GF_NODE_RANGE_LAST_VRML) {
3190 #ifndef GPAC_DISABLE_VRML
3191 u32 new_tag = 0;
3192 use_pm = gf_sg_use_pixel_metrics(in_scene);
3193 if (gf_node_get_tag(inline_parent)>GF_NODE_RANGE_LAST_VRML) {
3194 /*moving from SVG to VRML-based, need positive translation*/
3195 flip_coords = 1;
3196
3197 /*if our root nodes are not LayerXD ones, insert one. This prevents mixing
3198 of bindable stacks and gives us free 2D/3D integration*/
3199 if (tag==TAG_MPEG4_OrderedGroup) {
3200 new_tag = TAG_MPEG4_Layer2D;
3201 } else if (tag==TAG_MPEG4_Group) {
3202 new_tag = TAG_MPEG4_Layer3D;
3203 }
3204 #ifndef GPAC_DISABLE_X3D
3205 else if (tag==TAG_X3D_Group) {
3206 new_tag = TAG_MPEG4_Layer3D;
3207 }
3208 #endif
3209 }
3210 #if !defined(GPAC_DISABLE_X3D) && !defined(GPAC_DISABLE_3D)
3211 /*if the inlined root node is a 3D one except Layer3D and we are not in a 3D context, insert
3212 a Layer3D at the root*/
3213 else if (!tr_state->visual->type_3d && ((tag==TAG_MPEG4_Group) || (tag==TAG_X3D_Group))) {
3214 new_tag = TAG_MPEG4_Layer3D;
3215 }
3216 #endif
3217
3218 /*create new root*/
3219 if (new_tag) {
3220 GF_SceneGraph *sg = gf_node_get_graph(inline_root);
3221 GF_Node *new_root = gf_node_new(sg, new_tag);
3222 gf_node_register(new_root, NULL);
3223 gf_sg_set_root_node(sg, new_root);
3224 gf_node_list_add_child(& ((GF_ParentNode*)new_root)->children, inline_root);
3225 gf_node_register(inline_root, new_root);
3226 gf_node_unregister(inline_root, NULL);
3227 inline_root = new_root;
3228 gf_node_init(new_root);
3229 }
3230
3231 #endif /*GPAC_DISABLE_VRML*/
3232
3233 gf_sg_get_scene_size_info(in_scene, &w, &h);
3234
3235 } else {
3236 use_pm = 1;
3237 if (gf_node_get_tag(inline_parent)<GF_NODE_RANGE_LAST_VRML) {
3238 /*moving from VRML-based to SVG, need negative translation*/
3239 flip_coords = -1;
3240 }
3241 }
3242
3243 min_hsize = tr_state->min_hsize;
3244 prev_pm = tr_state->pixel_metrics;
3245 prev_vp = tr_state->vp_size;
3246 prev_coord = tr_state->fliped_coords;
3247 vp_scale = FIX_ONE;
3248 gf_mx2d_init(transf);
3249
3250 /*compute center<->top-left transform*/
3251 if (flip_coords)
3252 gf_mx2d_add_scale(&transf, FIX_ONE, -FIX_ONE);
3253
3254 /*if scene size is given in the child document, scale to fit the entire vp unless our VP is the full output*/
3255 if (w && h) {
3256 if ((compositor->scene_width != tr_state->vp_size.x) || (compositor->scene_height != tr_state->vp_size.y)) {
3257 Fixed scale_w = tr_state->vp_size.x/w;
3258 Fixed scale_h = tr_state->vp_size.y/h;
3259 vp_scale = MIN(scale_w, scale_h);
3260 gf_mx2d_add_scale(&transf, vp_scale, vp_scale);
3261 }
3262 }
3263 if (flip_coords) {
3264 gf_mx2d_add_translation(&transf, flip_coords * tr_state->vp_size.x/2, tr_state->vp_size.y/2);
3265 tr_state->fliped_coords = !tr_state->fliped_coords;
3266 }
3267
3268 /*if scene size is given in the child document, scale back vp to take into account the above scale
3269 otherwise the scene won't be properly clipped*/
3270 if (w && h) {
3271 tr_state->vp_size.x = gf_divfix(tr_state->vp_size.x, vp_scale);
3272 tr_state->vp_size.y = gf_divfix(tr_state->vp_size.y, vp_scale);
3273 }
3274
3275
3276 /*compute pixel<->meter transform*/
3277 if (use_pm != tr_state->pixel_metrics) {
3278 /*override aspect ratio if any size info is given in the scene*/
3279 if (w && h) {
3280 Fixed scale = INT2FIX( MIN(w, h) / 2);
3281 if (scale) tr_state->min_hsize = scale;
3282 }
3283 if (!use_pm) {
3284 gf_mx2d_add_scale(&transf, tr_state->min_hsize, tr_state->min_hsize);
3285 } else {
3286 Fixed inv_scale = gf_invfix(tr_state->min_hsize);
3287 gf_mx2d_add_scale(&transf, inv_scale, inv_scale);
3288 }
3289 tr_state->pixel_metrics = use_pm;
3290 }
3291
3292 #ifndef GPAC_DISABLE_3D
3293 if (tr_state->visual->type_3d) {
3294 GF_Matrix mx_bck, mx;
3295 gf_mx_copy(mx_bck, tr_state->model_matrix);
3296
3297 gf_mx_from_mx2d(&mx, &transf);
3298
3299 /*copy over z scale*/
3300 mx.m[10] = mx.m[5];
3301 gf_mx_add_matrix(&tr_state->model_matrix, &mx);
3302 gf_node_traverse(inline_root, rs);
3303 gf_mx_copy(tr_state->model_matrix, mx_bck);
3304
3305 } else
3306 #endif
3307 {
3308 GF_Matrix2D mx_bck;
3309 gf_mx2d_copy(mx_bck, tr_state->transform);
3310 gf_mx2d_pre_multiply(&tr_state->transform, &transf);
3311 gf_node_traverse(inline_root, rs);
3312 gf_mx2d_copy(tr_state->transform, mx_bck);
3313 }
3314
3315 tr_state->pixel_metrics = prev_pm;
3316 tr_state->min_hsize = min_hsize;
3317 tr_state->vp_size = prev_vp;
3318 tr_state->fliped_coords = prev_coord;
3319 }
3320
3321
gf_sc_handle_event_intern(GF_Compositor * compositor,GF_Event * event,Bool from_user)3322 static Bool gf_sc_handle_event_intern(GF_Compositor *compositor, GF_Event *event, Bool from_user)
3323 {
3324 Bool ret;
3325
3326 if ( (compositor->interaction_level & GF_INTERACT_INPUT_SENSOR) && (event->type<=GF_EVENT_MOUSEWHEEL)) {
3327 GF_Event evt = *event;
3328 gf_sc_input_sensor_mouse_input(compositor, &evt.mouse);
3329 }
3330
3331 /* if (!compositor->interaction_level || (compositor->interaction_level==GF_INTERACT_INPUT_SENSOR) ) {
3332 if (!from_user) {
3333 GF_USER_SENDEVENT(compositor->user, event);
3334 }
3335 return 0;
3336 }
3337 */
3338 gf_mx_p(compositor->mx);
3339 ret = gf_sc_exec_event(compositor, event);
3340 gf_sc_lock(compositor, GF_FALSE);
3341
3342 // if (!from_user) { }
3343 return ret;
3344 }
3345
gf_sc_traverse_subscene(GF_Compositor * compositor,GF_Node * inline_parent,GF_SceneGraph * subscene,void * rs)3346 void gf_sc_traverse_subscene(GF_Compositor *compositor, GF_Node *inline_parent, GF_SceneGraph *subscene, void *rs)
3347 {
3348 u32 i=0;
3349 GF_SceneGraph *subsg;
3350
3351 gf_sc_traverse_subscene_ex(compositor, inline_parent, subscene, rs);
3352
3353 while ( (subsg = gf_scene_enum_extra_scene(subscene, &i)))
3354 gf_sc_traverse_subscene_ex(compositor, inline_parent, subsg, rs);
3355
3356 }
3357
gf_sc_on_event_ex(GF_Compositor * compositor,GF_Event * event,Bool from_user)3358 static Bool gf_sc_on_event_ex(GF_Compositor *compositor , GF_Event *event, Bool from_user)
3359 {
3360 /*not assigned yet*/
3361 if (!compositor || !compositor->visual || compositor->discard_input_events) return GF_FALSE;
3362 /*we're reconfiguring the video output, cancel all messages except GL reconfig (context lost)*/
3363 if (compositor->msg_type & GF_SR_IN_RECONFIG) {
3364 if (event->type==GF_EVENT_VIDEO_SETUP) {
3365 if (event->setup.hw_reset)
3366 gf_sc_reset_graphics(compositor);
3367
3368 if (event->setup.back_buffer)
3369 compositor->recompute_ar = 1;
3370 }
3371 return GF_FALSE;
3372 }
3373 switch (event->type) {
3374 case GF_EVENT_SHOWHIDE:
3375 case GF_EVENT_SET_CAPTION:
3376 case GF_EVENT_MOVE:
3377 compositor->video_out->ProcessEvent(compositor->video_out, event);
3378 break;
3379
3380 case GF_EVENT_MOVE_NOTIF:
3381 if (compositor->last_had_overlays) {
3382 gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
3383 }
3384 break;
3385 case GF_EVENT_REFRESH:
3386 /*when refreshing a window with overlays we redraw the scene */
3387 gf_sc_next_frame_state(compositor, compositor->last_had_overlays ? GF_SC_DRAW_FRAME : GF_SC_DRAW_FLUSH);
3388 break;
3389 case GF_EVENT_VIDEO_SETUP:
3390 {
3391 Bool locked = gf_mx_try_lock(compositor->mx);
3392 if (event->setup.hw_reset) {
3393 gf_sc_reset_graphics(compositor);
3394 compositor->reset_graphics = 2;
3395 }
3396
3397 if (event->setup.back_buffer)
3398 compositor->recompute_ar = 1;
3399 if (locked) gf_mx_v(compositor->mx);
3400 }
3401 break;
3402 case GF_EVENT_SIZE:
3403 /*user consummed the resize event, do nothing*/
3404 if ( gf_sc_send_event(compositor, event) )
3405 return GF_TRUE;
3406
3407 /*not consummed and compositor "owns" the output window (created by the output module), resize*/
3408 if (!compositor->os_wnd) {
3409 /*EXTRA CARE HERE: the caller (video output) is likely a different thread than the compositor one, and the
3410 compositor may be locked on the video output (flush or whatever)!!
3411 */
3412 Bool lock_ok = gf_mx_try_lock(compositor->mx);
3413 if ((compositor->display_width!=event->size.width)
3414 || (compositor->display_height!=event->size.height)
3415 || (compositor->new_width && (compositor->new_width!=event->size.width))
3416 || (compositor->new_width && (compositor->new_height!=event->size.height))
3417 ) {
3418
3419 //OSX bug with SDL when requesting 4k window we get max screen height but 4k width ...
3420 #if defined(GPAC_CONFIG_DARWIN) && !defined(GPAC_CONFIG_IOS)
3421 if (compositor->display_width==event->size.width) {
3422 if (compositor->display_height > 2*event->size.height) {
3423 event->size.width = compositor->display_width * event->size.height / compositor->display_height;
3424 }
3425 }
3426 #endif
3427 compositor->new_width = event->size.width;
3428 compositor->new_height = event->size.height;
3429
3430 compositor->msg_type |= GF_SR_CFG_SET_SIZE;
3431 if (from_user) compositor->msg_type &= ~GF_SR_CFG_WINDOWSIZE_NOTIF;
3432 } else {
3433 /*remove pending resize notif but not resize requests*/
3434 compositor->msg_type &= ~GF_SR_CFG_WINDOWSIZE_NOTIF;
3435 }
3436 if (lock_ok) gf_sc_lock(compositor, GF_FALSE);
3437 }
3438 return GF_FALSE;
3439
3440 case GF_EVENT_KEYDOWN:
3441 case GF_EVENT_KEYUP:
3442 {
3443 Bool ret;
3444 switch (event->key.key_code) {
3445 case GF_KEY_SHIFT:
3446 if (event->type==GF_EVENT_KEYDOWN) {
3447 compositor->key_states |= GF_KEY_MOD_SHIFT;
3448 } else {
3449 compositor->key_states &= ~GF_KEY_MOD_SHIFT;
3450 }
3451 break;
3452 case GF_KEY_CONTROL:
3453 if (event->type==GF_EVENT_KEYDOWN) {
3454 compositor->key_states |= GF_KEY_MOD_CTRL;
3455 } else {
3456 compositor->key_states &= ~GF_KEY_MOD_CTRL;
3457 }
3458 break;
3459 case GF_KEY_ALT:
3460 if (event->type==GF_EVENT_KEYDOWN) {
3461 compositor->key_states |= GF_KEY_MOD_ALT;
3462 } else {
3463 compositor->key_states &= ~GF_KEY_MOD_ALT;
3464 }
3465 break;
3466
3467 }
3468
3469 ret = GF_FALSE;
3470 event->key.flags |= compositor->key_states;
3471 /*key sensor*/
3472 if ((compositor->interaction_level & GF_INTERACT_INPUT_SENSOR) ) {
3473 ret = gf_sc_input_sensor_keyboard_input(compositor, event->key.key_code, event->key.hw_code, (event->type==GF_EVENT_KEYUP) ? GF_TRUE : GF_FALSE);
3474 }
3475 ret += gf_sc_handle_event_intern(compositor, event, from_user);
3476 return ret;
3477 }
3478
3479 case GF_EVENT_TEXTINPUT:
3480 if (compositor->interaction_level & GF_INTERACT_INPUT_SENSOR)
3481 gf_sc_input_sensor_string_input(compositor , event->character.unicode_char);
3482
3483 return gf_sc_handle_event_intern(compositor, event, from_user);
3484 /*switch fullscreen off!!!*/
3485 case GF_EVENT_SHOWHIDE_NOTIF:
3486 compositor->is_hidden = event->show.show_type ? GF_FALSE : GF_TRUE;
3487 break;
3488
3489 case GF_EVENT_MOUSEMOVE:
3490 event->mouse.button = 0;
3491 case GF_EVENT_MOUSEDOWN:
3492 case GF_EVENT_MOUSEUP:
3493 case GF_EVENT_MOUSEWHEEL:
3494 event->mouse.key_states = compositor->key_states;
3495 case GF_EVENT_SENSOR_ORIENTATION:
3496 case GF_EVENT_MULTITOUCH:
3497 return gf_sc_handle_event_intern(compositor, event, from_user);
3498
3499 case GF_EVENT_PASTE_TEXT:
3500 gf_sc_paste_text(compositor, event->message.message);
3501 break;
3502 case GF_EVENT_COPY_TEXT:
3503 if (gf_sc_has_text_selection(compositor)) {
3504 event->message.message = gf_sc_get_selected_text(compositor);
3505 } else {
3506 event->message.message = NULL;
3507 }
3508 break;
3509 /*when we process events we don't forward them to the user*/
3510 default:
3511 return gf_sc_send_event(compositor, event);
3512 }
3513 /*if we get here, event has been consumed*/
3514 return GF_TRUE;
3515 }
3516
3517 GF_EXPORT
gf_sc_on_event(void * cbck,GF_Event * event)3518 Bool gf_sc_on_event(void *cbck, GF_Event *event)
3519 {
3520 return gf_sc_on_event_ex((GF_Compositor *)cbck, event, GF_FALSE);
3521 }
3522
3523 GF_EXPORT
gf_sc_user_event(GF_Compositor * compositor,GF_Event * event)3524 Bool gf_sc_user_event(GF_Compositor *compositor, GF_Event *event)
3525 {
3526 switch (event->type) {
3527 case GF_EVENT_SHOWHIDE:
3528 case GF_EVENT_MOVE:
3529 case GF_EVENT_SET_CAPTION:
3530 compositor->video_out->ProcessEvent(compositor->video_out, event);
3531 return GF_FALSE;
3532 default:
3533 return gf_sc_on_event_ex(compositor, event, GF_TRUE);
3534 }
3535 }
3536
3537 GF_EXPORT
gf_sc_register_extra_graph(GF_Compositor * compositor,GF_SceneGraph * extra_scene,Bool do_remove)3538 void gf_sc_register_extra_graph(GF_Compositor *compositor, GF_SceneGraph *extra_scene, Bool do_remove)
3539 {
3540 gf_sc_lock(compositor, GF_TRUE);
3541 if (do_remove) gf_list_del_item(compositor->extra_scenes, extra_scene);
3542 else if (gf_list_find(compositor->extra_scenes, extra_scene)<0) gf_list_add(compositor->extra_scenes, extra_scene);
3543 gf_sc_lock(compositor, GF_FALSE);
3544 }
3545
gf_sc_script_action(GF_Compositor * compositor,GF_JSAPIActionType type,GF_Node * n,GF_JSAPIParam * param)3546 Bool gf_sc_script_action(GF_Compositor *compositor, GF_JSAPIActionType type, GF_Node *n, GF_JSAPIParam *param)
3547 {
3548 switch (type) {
3549 case GF_JSAPI_OP_GET_SCALE:
3550 param->val = compositor->zoom;
3551 return GF_TRUE;
3552 case GF_JSAPI_OP_SET_SCALE:
3553 compositor_2d_set_user_transform(compositor, param->val, compositor->trans_x, compositor->trans_y, GF_FALSE);
3554 return GF_TRUE;
3555 case GF_JSAPI_OP_GET_ROTATION:
3556 param->val = gf_divfix(180*compositor->rotation, GF_PI);
3557 return GF_TRUE;
3558 case GF_JSAPI_OP_SET_ROTATION:
3559 compositor->rotation = gf_mulfix(GF_PI, param->val/180);
3560 compositor_2d_set_user_transform(compositor, compositor->zoom, compositor->trans_x, compositor->trans_y, GF_FALSE);
3561 return GF_TRUE;
3562 case GF_JSAPI_OP_GET_TRANSLATE:
3563 param->pt.x = compositor->trans_x;
3564 param->pt.y = compositor->trans_y;
3565 return GF_TRUE;
3566 case GF_JSAPI_OP_SET_TRANSLATE:
3567 compositor_2d_set_user_transform(compositor, compositor->zoom, param->pt.x, param->pt.y, GF_FALSE);
3568 return GF_TRUE;
3569 /*FIXME - better SMIL timelines support*/
3570 case GF_JSAPI_OP_GET_TIME:
3571 param->time = gf_node_get_scene_time(n);
3572 return GF_TRUE;
3573 case GF_JSAPI_OP_SET_TIME: /*seek_to(param->time);*/
3574 return GF_FALSE;
3575 /*FIXME - this will not work for inline docs, we will have to store the clipper at the <svg> level*/
3576 case GF_JSAPI_OP_GET_VIEWPORT:
3577 #ifndef GPAC_DISABLE_SVG
3578 if (compositor_svg_get_viewport(n, ¶m->rc)) return GF_TRUE;
3579 #endif
3580 param->rc = gf_rect_center(compositor->traverse_state->vp_size.x, compositor->traverse_state->vp_size.y);
3581 if (!compositor->visual->center_coords) {
3582 param->rc.x = 0;
3583 param->rc.y = 0;
3584 }
3585 return GF_TRUE;
3586 case GF_JSAPI_OP_SET_FOCUS:
3587 compositor->focus_node = param->node;
3588 return GF_TRUE;
3589 case GF_JSAPI_OP_GET_FOCUS:
3590 param->node = compositor->focus_node;
3591 return GF_TRUE;
3592
3593 /*same routine: traverse tree from root to target, collecting both bounds and transform matrix*/
3594 case GF_JSAPI_OP_GET_LOCAL_BBOX:
3595 case GF_JSAPI_OP_GET_SCREEN_BBOX:
3596 case GF_JSAPI_OP_GET_TRANSFORM:
3597 {
3598 GF_TraverseState tr_state;
3599 memset(&tr_state, 0, sizeof(tr_state));
3600 tr_state.traversing_mode = TRAVERSE_GET_BOUNDS;
3601 tr_state.visual = compositor->visual;
3602 tr_state.vp_size = compositor->traverse_state->vp_size;
3603 tr_state.for_node = n;
3604 tr_state.ignore_strike = GF_TRUE;
3605 tr_state.min_hsize = compositor->traverse_state->min_hsize;
3606 tr_state.pixel_metrics = compositor->traverse_state->pixel_metrics;
3607 gf_mx2d_init(tr_state.transform);
3608 gf_mx2d_init(tr_state.mx_at_node);
3609
3610
3611 if (type==GF_JSAPI_OP_GET_LOCAL_BBOX) {
3612 #ifndef GPAC_DISABLE_SVG
3613 GF_SAFEALLOC(tr_state.svg_props, SVGPropertiesPointers);
3614 if (tr_state.svg_props) {
3615 gf_svg_properties_init_pointers(tr_state.svg_props);
3616 tr_state.abort_bounds_traverse = GF_TRUE;
3617 gf_node_traverse(n, &tr_state);
3618 gf_svg_properties_reset_pointers(tr_state.svg_props);
3619 gf_free(tr_state.svg_props);
3620 }
3621 #endif
3622 } else {
3623 gf_node_traverse(gf_sg_get_root_node(compositor->scene), &tr_state);
3624 }
3625 if (!tr_state.bounds.height && !tr_state.bounds.width && !tr_state.bounds.x && !tr_state.bounds.y)
3626 tr_state.abort_bounds_traverse = GF_FALSE;
3627
3628 gf_mx2d_pre_multiply(&tr_state.mx_at_node, &compositor->traverse_state->transform);
3629
3630 if (type==GF_JSAPI_OP_GET_LOCAL_BBOX) {
3631 gf_bbox_from_rect(¶m->bbox, &tr_state.bounds);
3632 } else if (type==GF_JSAPI_OP_GET_TRANSFORM) {
3633 gf_mx_from_mx2d(¶m->mx, &tr_state.mx_at_node);
3634 } else {
3635 gf_mx2d_apply_rect(&tr_state.mx_at_node, &tr_state.bounds);
3636 gf_bbox_from_rect(¶m->bbox, &tr_state.bounds);
3637 }
3638 if (!tr_state.abort_bounds_traverse) param->bbox.is_set = GF_FALSE;
3639 }
3640 return GF_TRUE;
3641 case GF_JSAPI_OP_LOAD_URL:
3642 {
3643 #ifndef GPAC_DISABLE_VRML
3644 GF_Node *target;
3645 char *sub_url = strrchr(param->uri.url, '#');
3646 if (!sub_url) return GF_FALSE;
3647 target = gf_sg_find_node_by_name(gf_node_get_graph(n), sub_url+1);
3648 if (target && (gf_node_get_tag(target)==TAG_MPEG4_Viewport) ) {
3649 ((M_Viewport *)target)->set_bind = 1;
3650 ((M_Viewport *)target)->on_set_bind(n, NULL);
3651 return GF_TRUE;
3652 }
3653 #endif
3654 return GF_FALSE;
3655 }
3656 case GF_JSAPI_OP_GET_FPS:
3657 param->time = gf_sc_get_fps(compositor, GF_FALSE);
3658 return GF_TRUE;
3659 case GF_JSAPI_OP_GET_SPEED:
3660 param->time = 0;
3661 #ifndef GPAC_DISABLE_3D
3662 if (compositor->visual->type_3d==2) {
3663 param->time = FIX2FLT(compositor->visual->camera.speed);
3664 }
3665 #endif
3666 return GF_TRUE;
3667 case GF_JSAPI_OP_PAUSE_SVG:
3668 if (n) {
3669 u32 tag = gf_node_get_tag(n);
3670 switch(tag) {
3671 #ifndef GPAC_DISABLE_SVG
3672 case TAG_SVG_audio:
3673 svg_pause_audio(n, GF_TRUE);
3674 break;
3675 case TAG_SVG_video:
3676 svg_pause_video(n, GF_TRUE);
3677 break;
3678 case TAG_SVG_animation:
3679 svg_pause_animation(n, GF_TRUE);
3680 break;
3681 #endif
3682 }
3683 } else {
3684 return GF_FALSE;
3685 }
3686 return GF_TRUE;
3687 case GF_JSAPI_OP_RESUME_SVG:
3688 {
3689 u32 tag = gf_node_get_tag(n);
3690 switch(tag) {
3691 #ifndef GPAC_DISABLE_SVG
3692 case TAG_SVG_audio:
3693 svg_pause_audio(n, GF_FALSE);
3694 break;
3695 case TAG_SVG_video:
3696 svg_pause_video(n, GF_FALSE);
3697 break;
3698 case TAG_SVG_animation:
3699 svg_pause_animation(n, GF_FALSE);
3700 break;
3701 #endif
3702 }
3703 }
3704 return GF_TRUE;
3705 case GF_JSAPI_OP_GET_DPI_X:
3706 param->opt = compositor->video_out->dpi_x;
3707 return GF_TRUE;
3708 case GF_JSAPI_OP_GET_DPI_Y:
3709 param->opt = compositor->video_out->dpi_y;
3710 return GF_TRUE;
3711 default:
3712 return GF_FALSE;
3713 }
3714 return GF_FALSE;
3715 }
3716
gf_sc_pick_in_clipper(GF_TraverseState * tr_state,GF_Rect * clip)3717 Bool gf_sc_pick_in_clipper(GF_TraverseState *tr_state, GF_Rect *clip)
3718 {
3719 #ifndef GPAC_DISABLE_3D
3720 if (tr_state->visual->type_3d) {
3721 SFVec3f pos;
3722 GF_Matrix mx;
3723 GF_Ray r;
3724 gf_mx_copy(mx, tr_state->model_matrix);
3725 gf_mx_inverse(&mx);
3726 r = tr_state->ray;
3727 gf_mx_apply_ray(&mx, &r);
3728 if (!compositor_get_2d_plane_intersection(&r, &pos)) return GF_FALSE;
3729 if ( (pos.x < clip->x) || (pos.y > clip->y)
3730 || (pos.x > clip->x + clip->width) || (pos.y < clip->y - clip->height) ) return GF_FALSE;
3731
3732 } else
3733 #endif
3734 {
3735 GF_Rect rc = *clip;
3736 GF_Point2D pt;
3737 gf_mx2d_apply_rect(&tr_state->transform, &rc);
3738 pt.x = tr_state->ray.orig.x;
3739 pt.y = tr_state->ray.orig.y;
3740
3741 if ( (pt.x < rc.x) || (pt.y > rc.y)
3742 || (pt.x > rc.x + rc.width) || (pt.y < rc.y - rc.height) ) return GF_FALSE;
3743 }
3744 return GF_TRUE;
3745 }
3746
3747
gf_sc_has_text_selection(GF_Compositor * compositor)3748 Bool gf_sc_has_text_selection(GF_Compositor *compositor)
3749 {
3750 return (compositor->store_text_state==GF_SC_TSEL_FROZEN) ? GF_TRUE : GF_FALSE;
3751 }
3752
3753 GF_EXPORT
gf_sc_get_selected_text(GF_Compositor * compositor)3754 const char *gf_sc_get_selected_text(GF_Compositor *compositor)
3755 {
3756 const u16 *srcp;
3757 size_t len;
3758 if (compositor->store_text_state != GF_SC_TSEL_FROZEN) return NULL;
3759
3760 gf_sc_lock(compositor, GF_TRUE);
3761
3762 compositor->traverse_state->traversing_mode = TRAVERSE_GET_TEXT;
3763 if (compositor->sel_buffer) {
3764 gf_free(compositor->sel_buffer);
3765 compositor->sel_buffer = NULL;
3766 }
3767 compositor->sel_buffer_len = 0;
3768 compositor->sel_buffer_alloc = 0;
3769 gf_node_traverse(compositor->text_selection, compositor->traverse_state);
3770 compositor->traverse_state->traversing_mode = 0;
3771 if (compositor->sel_buffer) compositor->sel_buffer[compositor->sel_buffer_len]=0;
3772 srcp = compositor->sel_buffer;
3773
3774 if (compositor->selected_text) gf_free(compositor->selected_text);
3775 compositor->selected_text = gf_malloc(sizeof(char)*2*compositor->sel_buffer_len);
3776 len = gf_utf8_wcstombs((char *) compositor->selected_text, 2*compositor->sel_buffer_len, &srcp);
3777 if ((s32)len<0) len = 0;
3778 compositor->selected_text[len] = 0;
3779 gf_sc_lock(compositor, GF_FALSE);
3780
3781 return (const char *) compositor->selected_text;
3782 }
3783
3784
gf_sc_check_focus_upon_destroy(GF_Node * n)3785 void gf_sc_check_focus_upon_destroy(GF_Node *n)
3786 {
3787 GF_Compositor *compositor = gf_sc_get_compositor(n);
3788 if (!compositor) return;
3789
3790 if (compositor->focus_node==n) {
3791 compositor->focus_node = NULL;
3792 compositor->focus_text_type = 0;
3793 compositor->focus_uses_dom_events = GF_FALSE;
3794 gf_list_reset(compositor->focus_ancestors);
3795 gf_list_reset(compositor->focus_use_stack);
3796 }
3797 if (compositor->hit_node==n) compositor->hit_node = NULL;
3798 if (compositor->hit_text==n) compositor->hit_text = NULL;
3799 }
3800
3801 #if 0 //unused
3802 void gf_sc_set_system_pending_frame(GF_Compositor *compositor, Bool frame_pending)
3803 {
3804 if (frame_pending) {
3805 if (!compositor->force_bench_frame)
3806 compositor->force_bench_frame = 1;
3807 } else {
3808 //do not increase clock
3809 compositor->force_bench_frame = 2;
3810 }
3811 }
3812
3813 void gf_sc_queue_event(GF_Compositor *compositor, GF_Event *evt)
3814 {
3815 u32 i, count;
3816 GF_QueuedEvent *qev;
3817 gf_mx_p(compositor->evq_mx);
3818
3819 count = gf_list_count(compositor->event_queue);
3820 for (i=0; i<count; i++) {
3821 qev = gf_list_get(compositor->event_queue, i);
3822 if (!qev->node && (qev->evt.type==evt->type)) {
3823 qev->evt = *evt;
3824 gf_mx_v(compositor->evq_mx);
3825 return;
3826 }
3827 }
3828 GF_SAFEALLOC(qev, GF_QueuedEvent);
3829 if (!qev) {
3830 GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate event for queuing\n"));
3831 } else {
3832 qev->evt = *evt;
3833 gf_list_add(compositor->event_queue, qev);
3834 }
3835 gf_mx_v(compositor->evq_mx);
3836 }
3837 #endif
3838
3839
gf_sc_queue_dom_event(GF_Compositor * compositor,GF_Node * node,GF_DOM_Event * evt)3840 void gf_sc_queue_dom_event(GF_Compositor *compositor, GF_Node *node, GF_DOM_Event *evt)
3841 {
3842 u32 i, count;
3843 GF_QueuedEvent *qev;
3844 gf_mx_p(compositor->evq_mx);
3845
3846 count = gf_list_count(compositor->event_queue);
3847 for (i=0; i<count; i++) {
3848 qev = gf_list_get(compositor->event_queue, i);
3849 if ((qev->node==node) && (qev->dom_evt.type==evt->type)) {
3850 qev->dom_evt = *evt;
3851 gf_mx_v(compositor->evq_mx);
3852 return;
3853 }
3854 }
3855 GF_SAFEALLOC(qev, GF_QueuedEvent);
3856 if (!qev) {
3857 GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate event for queuing\n"));
3858 } else {
3859 qev->node = node;
3860 qev->dom_evt = *evt;
3861 gf_list_add(compositor->event_queue, qev);
3862 }
3863 gf_mx_v(compositor->evq_mx);
3864 }
3865
gf_sc_queue_dom_event_on_target(GF_Compositor * compositor,GF_DOM_Event * evt,GF_DOMEventTarget * target,GF_SceneGraph * sg)3866 void gf_sc_queue_dom_event_on_target(GF_Compositor *compositor, GF_DOM_Event *evt, GF_DOMEventTarget *target, GF_SceneGraph *sg)
3867 {
3868 u32 i, count;
3869 GF_QueuedEvent *qev;
3870 gf_mx_p(compositor->evq_mx);
3871
3872 count = gf_list_count(compositor->event_queue);
3873 for (i=0; i<count; i++) {
3874 qev = gf_list_get(compositor->event_queue, i);
3875 if ((qev->target==target) && (qev->dom_evt.type==evt->type) && (qev->sg==sg) ) {
3876 //do not override any pending dowload progress event by new buffer state events
3877 if ((evt->type!=GF_EVENT_MEDIA_PROGRESS) || !qev->dom_evt.media_event.loaded_size) {
3878 qev->dom_evt = *evt;
3879 }
3880 gf_mx_v(compositor->evq_mx);
3881 return;
3882 }
3883 }
3884
3885 GF_SAFEALLOC(qev, GF_QueuedEvent);
3886 if (!qev) {
3887 GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate event for queuing\n"));
3888 } else {
3889 qev->sg = sg;
3890 qev->target = target;
3891 qev->dom_evt = *evt;
3892 gf_list_add(compositor->event_queue, qev);
3893 }
3894 gf_mx_v(compositor->evq_mx);
3895 }
3896
sc_cleanup_event_queue(GF_List * evq,GF_Node * node,GF_SceneGraph * sg)3897 static void sc_cleanup_event_queue(GF_List *evq, GF_Node *node, GF_SceneGraph *sg)
3898 {
3899 u32 i, count = gf_list_count(evq);
3900 for (i=0; i<count; i++) {
3901 Bool del = 0;
3902 GF_QueuedEvent *qev = gf_list_get(evq, i);
3903 if (qev->node) {
3904 if (node == qev->node)
3905 del = 1;
3906 if (sg && (gf_node_get_graph(qev->node)==sg))
3907 del = 1;
3908 }
3909 if (qev->sg && (qev->sg==sg))
3910 del = 1;
3911 else if (qev->target && (qev->target->ptr_type == GF_DOM_EVENT_TARGET_NODE)) {
3912 if (node && ((GF_Node *)qev->target->ptr==node))
3913 del = 1;
3914 if (sg && (gf_node_get_graph((GF_Node *)qev->target->ptr)==sg))
3915 del = 1;
3916 }
3917
3918 if (del) {
3919 gf_list_rem(evq, i);
3920 i--;
3921 count--;
3922 gf_free(qev);
3923 }
3924 }
3925 }
3926
gf_sc_node_destroy(GF_Compositor * compositor,GF_Node * node,GF_SceneGraph * sg)3927 void gf_sc_node_destroy(GF_Compositor *compositor, GF_Node *node, GF_SceneGraph *sg)
3928 {
3929 gf_mx_p(compositor->evq_mx);
3930 sc_cleanup_event_queue(compositor->event_queue, node, sg);
3931 sc_cleanup_event_queue(compositor->event_queue_back, node, sg);
3932 gf_mx_v(compositor->evq_mx);
3933 }
3934
3935 GF_EXPORT
gf_sc_navigation_supported(GF_Compositor * compositor,u32 type)3936 Bool gf_sc_navigation_supported(GF_Compositor *compositor, u32 type)
3937 {
3938 if (compositor->navigation_disabled ) return GF_FALSE;
3939 #ifndef GPAC_DISABLE_3D
3940 if (compositor->visual->type_3d || compositor->active_layer) {
3941 GF_Camera *cam = compositor_3d_get_camera(compositor);
3942 if (cam->navigation_flags & NAV_ANY) {
3943 return GF_TRUE;
3944 } else {
3945 #ifndef GPAC_DISABLE_VRML
3946 M_NavigationInfo *ni = (M_NavigationInfo *)gf_list_get(compositor->visual->navigation_stack, 0);
3947 if (ni) {
3948 u32 i;
3949 for (i=0; i<ni->type.count; i++) {
3950 if (!ni->type.vals[i]) continue;
3951 if (!stricmp(ni->type.vals[i], "WALK") && (type==GF_NAVIGATE_WALK)) return GF_TRUE;
3952 else if (!stricmp(ni->type.vals[i], "NONE") && (type==GF_NAVIGATE_NONE)) return GF_TRUE;
3953 else if (!stricmp(ni->type.vals[i], "EXAMINE") && (type==GF_NAVIGATE_EXAMINE)) return GF_TRUE;
3954 else if (!stricmp(ni->type.vals[i], "FLY") && (type==GF_NAVIGATE_FLY)) return GF_TRUE;
3955 else if (!stricmp(ni->type.vals[i], "VR") && (type==GF_NAVIGATE_VR)) return GF_TRUE;
3956 else if (!stricmp(ni->type.vals[i], "GAME") && (type==GF_NAVIGATE_GAME)) return GF_TRUE;
3957 else if (!stricmp(ni->type.vals[i], "ORBIT") && (type==GF_NAVIGATE_ORBIT)) return GF_TRUE;
3958 }
3959 }
3960 #endif
3961 return GF_FALSE;
3962 }
3963 } else
3964 #endif
3965 if ((type!=GF_NAVIGATE_NONE) && (type!=GF_NAVIGATE_SLIDE) && (type!=GF_NAVIGATE_EXAMINE)) {
3966 return GF_FALSE;
3967 }
3968 return GF_TRUE;
3969 }
3970
3971
gf_sc_check_end_of_scene(GF_Compositor * compositor,Bool skip_interactions)3972 u32 gf_sc_check_end_of_scene(GF_Compositor *compositor, Bool skip_interactions)
3973 {
3974 if (!compositor->root_scene || !compositor->root_scene->root_od || !compositor->root_scene->root_od->scene_ns) return 1;
3975
3976 if (!skip_interactions) {
3977 /*if input sensors consider the scene runs forever*/
3978 if (gf_list_count(compositor->input_streams)) return 0;
3979 if (gf_list_count(compositor->x3d_sensors)) return 0;
3980 }
3981
3982 /*check no clocks are still running*/
3983 if (!gf_scene_check_clocks(compositor->root_scene->root_od->scene_ns, compositor->root_scene, 0)) return 0;
3984 if (compositor->root_scene->is_dynamic_scene) return 1;
3985
3986 /*ask compositor if there are sensors*/
3987 return gf_sc_get_option(compositor, skip_interactions ? GF_OPT_IS_OVER : GF_OPT_IS_FINISHED);
3988 }
3989
gf_sc_queue_node_traverse(GF_Compositor * compositor,GF_Node * node)3990 void gf_sc_queue_node_traverse(GF_Compositor *compositor, GF_Node *node)
3991 {
3992 gf_sc_lock(compositor, GF_TRUE);
3993 if (!compositor->nodes_pending) compositor->nodes_pending = gf_list_new();
3994 gf_list_add(compositor->nodes_pending, node);
3995 gf_sc_lock(compositor, GF_FALSE);
3996 }
gf_sc_unqueue_node_traverse(GF_Compositor * compositor,GF_Node * node)3997 void gf_sc_unqueue_node_traverse(GF_Compositor *compositor, GF_Node *node)
3998 {
3999 gf_sc_lock(compositor, GF_TRUE);
4000 if (compositor->nodes_pending) {
4001 gf_list_del_item(compositor->nodes_pending, node);
4002 if (!gf_list_count(compositor->nodes_pending)) {
4003 gf_list_del(compositor->nodes_pending);
4004 compositor->nodes_pending = NULL;
4005 }
4006 }
4007 gf_sc_lock(compositor, GF_FALSE);
4008 }
4009
4010 GF_EXPORT
gf_sc_get_downloader(GF_Compositor * compositor)4011 GF_DownloadManager *gf_sc_get_downloader(GF_Compositor *compositor)
4012 {
4013 return gf_filter_get_download_manager(compositor->filter);
4014 }
4015
gf_sc_sys_frame_pending(GF_Compositor * compositor,Double ts_offset,u32 obj_time,GF_Filter * from_filter)4016 void gf_sc_sys_frame_pending(GF_Compositor *compositor, Double ts_offset, u32 obj_time, GF_Filter *from_filter)
4017 {
4018 if (!compositor->player) {
4019 compositor->sys_frames_pending = GF_TRUE;
4020 if (from_filter)
4021 gf_filter_ask_rt_reschedule(from_filter, 0);
4022 } else {
4023 u32 wait_ms = (u32) (ts_offset * 1000 - obj_time);
4024
4025 if (!compositor->ms_until_next_frame || ((s32) wait_ms < compositor->ms_until_next_frame)) {
4026 compositor->ms_until_next_frame = (s32) wait_ms;
4027 }
4028 if (from_filter) {
4029 gf_filter_ask_rt_reschedule(from_filter, wait_ms*500);
4030 }
4031 }
4032 }
4033
gf_sc_check_gl_support(GF_Compositor * compositor)4034 Bool gf_sc_check_gl_support(GF_Compositor *compositor)
4035 {
4036 #ifdef GPAC_DISABLE_3D
4037 return GF_FALSE;
4038 #else
4039 if (!compositor->player && !compositor->is_opengl) {
4040 if (compositor->drv==GF_SC_DRV_OFF) {
4041 return GF_FALSE;
4042 }
4043 compositor->needs_offscreen_gl = GF_TRUE;
4044 compositor->autoconfig_opengl = 1;
4045 compositor->recompute_ar = 1;
4046 return GF_TRUE;
4047 }
4048 return GF_TRUE;
4049 #endif
4050
4051 }
4052
4053