examples: use dedicated thread for rendering the scene

Produces smother animation and prevents dropping frames due busy
mainloop.
This commit is contained in:
Josep Torra 2013-09-20 09:34:37 +02:00
parent 78dc6235d4
commit e6633182f3

View file

@ -139,7 +139,6 @@ typedef struct
uint32_t screen_width; uint32_t screen_width;
uint32_t screen_height; uint32_t screen_height;
gboolean animate; gboolean animate;
gboolean sync_animation_with_video;
/* OpenGL|ES objects */ /* OpenGL|ES objects */
EGLDisplay display; EGLDisplay display;
@ -179,6 +178,9 @@ typedef struct
GstBuffer *last_buffer; GstBuffer *last_buffer;
GstCaps *current_caps; GstCaps *current_caps;
/* Rendering thread state */
gboolean running;
} APP_STATE_T; } APP_STATE_T;
typedef struct typedef struct
@ -933,14 +935,14 @@ init_textures (APP_STATE_T * state)
glBindTexture (GL_TEXTURE_2D, state->tex); glBindTexture (GL_TEXTURE_2D, state->tex);
} }
static gboolean static void
render_scene (APP_STATE_T * state) render_scene (APP_STATE_T * state)
{ {
update_model (state); update_model (state);
redraw_scene (state); redraw_scene (state);
TRACE_VC_MEMORY_ONCE_FOR_ID ("after render_scene", gid2); TRACE_VC_MEMORY_ONCE_FOR_ID ("after render_scene", gid2);
return !state->sync_animation_with_video; return;
} }
static void static void
@ -964,10 +966,8 @@ update_image (APP_STATE_T * state, GstBuffer * buffer)
TRACE_VC_MEMORY_ONCE_FOR_ID ("after glEGLImageTargetTexture2DOES", gid1); TRACE_VC_MEMORY_ONCE_FOR_ID ("after glEGLImageTargetTexture2DOES", gid1);
if (state->sync_animation_with_video) {
render_scene (state); render_scene (state);
} }
}
static void static void
init_intercom (APP_STATE_T * state) init_intercom (APP_STATE_T * state)
@ -978,6 +978,23 @@ init_intercom (APP_STATE_T * state)
state->cond = g_cond_new (); state->cond = g_cond_new ();
} }
static void
terminate_intercom (APP_STATE_T * state)
{
/* Release intercom */
if (state->queue) {
g_async_queue_unref (state->queue);
}
if (state->lock) {
g_mutex_free (state->lock);
}
if (state->cond) {
g_cond_free (state->cond);
}
}
static void static void
flush_internal (APP_STATE_T * state) flush_internal (APP_STATE_T * state)
{ {
@ -1159,12 +1176,6 @@ queue_object (APP_STATE_T * state, GstMiniObject * obj, gboolean synchronous)
g_async_queue_push (state->queue, obj); g_async_queue_push (state->queue, obj);
if (state->sync_animation_with_video) {
g_idle_add_full (G_PRIORITY_HIGH_IDLE, (GSourceFunc) handle_queued_objects,
state, NULL);
}
if (synchronous) { if (synchronous) {
/* Waiting for object to be handled */ /* Waiting for object to be handled */
do { do {
@ -1176,13 +1187,6 @@ queue_object (APP_STATE_T * state, GstMiniObject * obj, gboolean synchronous)
return TRUE; return TRUE;
} }
static gboolean
handle_msgs_and_render_scene (APP_STATE_T * state)
{
handle_queued_objects (state);
return render_scene (state);
}
static void static void
preroll_cb (GstElement * fakesink, GstBuffer * buffer, GstPad * pad, preroll_cb (GstElement * fakesink, GstBuffer * buffer, GstPad * pad,
gpointer user_data) gpointer user_data)
@ -1509,18 +1513,6 @@ handle_keyboard (GIOChannel * source, GIOCondition cond, APP_STATE_T * state)
flush_start (state); flush_start (state);
gst_element_set_state (state->pipeline, GST_STATE_READY); gst_element_set_state (state->pipeline, GST_STATE_READY);
break; break;
case 'S':
if (state->sync_animation_with_video) {
state->sync_animation_with_video = FALSE;
/* Add the rendering task */
g_idle_add_full (G_PRIORITY_HIGH_IDLE,
(GSourceFunc) handle_msgs_and_render_scene, state, NULL);
g_print ("\nanimation is not synchoronized with video\n");
} else {
state->sync_animation_with_video = TRUE;
g_print ("\nanimation is synchoronized with video\n");
}
break;
} }
} }
g_free (str); g_free (str);
@ -1617,6 +1609,47 @@ close_ogl (void)
//============================================================================== //==============================================================================
static void
open_ogl (void)
{
TRACE_VC_MEMORY ("state 0");
#if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_EGL)
bcm_host_init ();
TRACE_VC_MEMORY ("after bcm_host_init");
#endif
/* Start OpenGLES */
init_ogl (state);
TRACE_VC_MEMORY ("after init_ogl");
/* Wrap the EGL display */
state->gst_display = gst_egl_display_new (state->display, NULL);
/* Setup the model world */
init_model_proj (state);
TRACE_VC_MEMORY ("after init_model_proj");
/* initialize the OGLES texture(s) */
init_textures (state);
TRACE_VC_MEMORY ("after init_textures");
}
static gpointer
render_func (gpointer data)
{
open_ogl ();
state->running = TRUE;
do {
handle_queued_objects (state);
g_usleep (0);
} while (state->running == TRUE);
close_ogl ();
return NULL;
}
int int
main (int argc, char **argv) main (int argc, char **argv)
{ {
@ -1628,11 +1661,11 @@ main (int argc, char **argv)
GOptionEntry options[] = { GOptionEntry options[] = {
{NULL} {NULL}
}; };
GThread *rthread;
/* Clear application state */ /* Clear application state */
memset (state, 0, sizeof (*state)); memset (state, 0, sizeof (*state));
state->animate = TRUE; state->animate = TRUE;
state->sync_animation_with_video = TRUE;
/* must initialise the threading system before using any other GLib funtion */ /* must initialise the threading system before using any other GLib funtion */
if (!g_thread_supported ()) if (!g_thread_supported ())
@ -1655,31 +1688,16 @@ main (int argc, char **argv)
/* Initialize GStreamer */ /* Initialize GStreamer */
gst_init (&argc, &argv); gst_init (&argc, &argv);
TRACE_VC_MEMORY ("state 0");
#if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_EGL)
bcm_host_init ();
TRACE_VC_MEMORY ("after bcm_host_init");
#endif
/* Start OpenGLES */
init_ogl (state);
TRACE_VC_MEMORY ("after init_ogl");
/* Wrap the EGL display */
state->gst_display = gst_egl_display_new (state->display, NULL);
/* Setup the model world */
init_model_proj (state);
TRACE_VC_MEMORY ("after init_model_proj");
/* initialize the OGLES texture(s) */
init_textures (state);
TRACE_VC_MEMORY ("after init_textures");
/* initialize inter thread comunnication */ /* initialize inter thread comunnication */
init_intercom (state); init_intercom (state);
TRACE_VC_MEMORY ("state 0");
if (!(rthread = g_thread_new ("render", (GThreadFunc) render_func, NULL))) {
g_print ("Render thread create failed\n");
exit (1);
}
/* Initialize player */ /* Initialize player */
if (gst_uri_is_valid (argv[1])) { if (gst_uri_is_valid (argv[1])) {
res = init_playbin_player (state, argv[1]); res = init_playbin_player (state, argv[1]);
@ -1706,16 +1724,9 @@ main (int argc, char **argv)
" l - Query position/duration\n" " l - Query position/duration\n"
" f - Seek 30 seconds forward \n" " f - Seek 30 seconds forward \n"
" b - Seek 30 seconds backward \n" " b - Seek 30 seconds backward \n"
" S - Toggle synchronization of video and animation \n"
" q - Quit \n"); " q - Quit \n");
/* *INDENT-ON* */ /* *INDENT-ON* */
if (!state->sync_animation_with_video) {
/* Add the rendering task */
g_idle_add_full (G_PRIORITY_HIGH_IDLE,
(GSourceFunc) handle_msgs_and_render_scene, state, NULL);
}
/* Connect the bus handlers */ /* Connect the bus handlers */
bus = gst_element_get_bus (state->pipeline); bus = gst_element_get_bus (state->pipeline);
@ -1748,25 +1759,16 @@ done:
gst_object_unref (state->pipeline); gst_object_unref (state->pipeline);
} }
/* Release intercom */
if (state->queue) {
g_async_queue_unref (state->queue);
}
if (state->lock) {
g_mutex_free (state->lock);
}
if (state->cond) {
g_cond_free (state->cond);
}
/* Unref the mainloop */ /* Unref the mainloop */
if (state->main_loop) { if (state->main_loop) {
g_main_loop_unref (state->main_loop); g_main_loop_unref (state->main_loop);
} }
close_ogl (); /* Stop rendering thread */
state->running = FALSE;
g_thread_join (rthread);
terminate_intercom (state);
TRACE_VC_MEMORY ("at exit"); TRACE_VC_MEMORY ("at exit");
return 0; return 0;