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_height;
gboolean animate;
gboolean sync_animation_with_video;
/* OpenGL|ES objects */
EGLDisplay display;
@ -179,6 +178,9 @@ typedef struct
GstBuffer *last_buffer;
GstCaps *current_caps;
/* Rendering thread state */
gboolean running;
} APP_STATE_T;
typedef struct
@ -933,14 +935,14 @@ init_textures (APP_STATE_T * state)
glBindTexture (GL_TEXTURE_2D, state->tex);
}
static gboolean
static void
render_scene (APP_STATE_T * state)
{
update_model (state);
redraw_scene (state);
TRACE_VC_MEMORY_ONCE_FOR_ID ("after render_scene", gid2);
return !state->sync_animation_with_video;
return;
}
static void
@ -964,9 +966,7 @@ update_image (APP_STATE_T * state, GstBuffer * buffer)
TRACE_VC_MEMORY_ONCE_FOR_ID ("after glEGLImageTargetTexture2DOES", gid1);
if (state->sync_animation_with_video) {
render_scene (state);
}
render_scene (state);
}
static void
@ -978,6 +978,23 @@ init_intercom (APP_STATE_T * state)
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
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);
if (state->sync_animation_with_video) {
g_idle_add_full (G_PRIORITY_HIGH_IDLE, (GSourceFunc) handle_queued_objects,
state, NULL);
}
if (synchronous) {
/* Waiting for object to be handled */
do {
@ -1176,13 +1187,6 @@ queue_object (APP_STATE_T * state, GstMiniObject * obj, gboolean synchronous)
return TRUE;
}
static gboolean
handle_msgs_and_render_scene (APP_STATE_T * state)
{
handle_queued_objects (state);
return render_scene (state);
}
static void
preroll_cb (GstElement * fakesink, GstBuffer * buffer, GstPad * pad,
gpointer user_data)
@ -1509,18 +1513,6 @@ handle_keyboard (GIOChannel * source, GIOCondition cond, APP_STATE_T * state)
flush_start (state);
gst_element_set_state (state->pipeline, GST_STATE_READY);
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);
@ -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
main (int argc, char **argv)
{
@ -1628,11 +1661,11 @@ main (int argc, char **argv)
GOptionEntry options[] = {
{NULL}
};
GThread *rthread;
/* Clear application state */
memset (state, 0, sizeof (*state));
state->animate = TRUE;
state->sync_animation_with_video = TRUE;
/* must initialise the threading system before using any other GLib funtion */
if (!g_thread_supported ())
@ -1655,31 +1688,16 @@ main (int argc, char **argv)
/* Initialize GStreamer */
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 */
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 */
if (gst_uri_is_valid (argv[1])) {
res = init_playbin_player (state, argv[1]);
@ -1706,16 +1724,9 @@ main (int argc, char **argv)
" l - Query position/duration\n"
" f - Seek 30 seconds forward \n"
" b - Seek 30 seconds backward \n"
" S - Toggle synchronization of video and animation \n"
" q - Quit \n");
/* *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 */
bus = gst_element_get_bus (state->pipeline);
@ -1748,25 +1759,16 @@ done:
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 */
if (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");
return 0;