tests: simple-decoder: honour framerate from the bitstream.

Try to honour the framerate from the bitstream, or cap the playback to
60 fps by default.
This commit is contained in:
Gwenole Beauchesne 2013-01-16 13:29:06 +01:00
parent 7b4dadc8ae
commit 14242cda5d
2 changed files with 57 additions and 2 deletions

View file

@ -105,8 +105,8 @@ test_textures_LDADD = libutils.la $(TEST_LIBS)
simple_decoder_source_c = simple-decoder.c simple_decoder_source_c = simple-decoder.c
simple_decoder_source_h = simple_decoder_source_h =
simple_decoder_SOURCES = $(simple_decoder_source_c) simple_decoder_SOURCES = $(simple_decoder_source_c)
simple_decoder_CFLAGS = $(TEST_CFLAGS) simple_decoder_CFLAGS = $(TEST_CFLAGS) $(GST_VIDEO_CFLAGS)
simple_decoder_LDADD = libutils.la $(TEST_LIBS) simple_decoder_LDADD = libutils.la $(TEST_LIBS) $(GST_VIDEO_LIBS)
EXTRA_DIST = \ EXTRA_DIST = \
test-subpicture-data.h \ test-subpicture-data.h \

View file

@ -74,6 +74,9 @@ typedef struct {
GCond decoder_ready; GCond decoder_ready;
GAsyncQueue *decoder_queue; GAsyncQueue *decoder_queue;
GstVaapiCodec codec; GstVaapiCodec codec;
guint fps_n;
guint fps_d;
guint32 frame_duration;
guint surface_width; guint surface_width;
guint surface_height; guint surface_height;
GstVaapiWindow *window; GstVaapiWindow *window;
@ -81,6 +84,7 @@ typedef struct {
guint window_height; guint window_height;
GThread *render_thread; GThread *render_thread;
volatile gboolean render_thread_cancel; volatile gboolean render_thread_cancel;
GCond render_ready;
GstBuffer *last_buffer; GstBuffer *last_buffer;
GError *error; GError *error;
AppEvent event; AppEvent event;
@ -193,6 +197,7 @@ decoder_thread(gpointer data)
GstVaapiSurfaceProxy *proxy; GstVaapiSurfaceProxy *proxy;
GstVaapiVideoMeta *meta; GstVaapiVideoMeta *meta;
GstBuffer *buffer; GstBuffer *buffer;
GstClockTime pts;
gboolean got_surface; gboolean got_surface;
gint64 end_time; gint64 end_time;
guint ofs; guint ofs;
@ -205,6 +210,7 @@ decoder_thread(gpointer data)
goto send_error; \ goto send_error; \
} while (0) } while (0)
pts = g_get_monotonic_time();
ofs = 0; ofs = 0;
while (!app->decoder_thread_cancel) { while (!app->decoder_thread_cancel) {
if (G_UNLIKELY(ofs == app->file_size)) if (G_UNLIKELY(ofs == app->file_size))
@ -235,6 +241,9 @@ decoder_thread(gpointer data)
buffer = gst_buffer_new(); buffer = gst_buffer_new();
if (!buffer) if (!buffer)
SEND_ERROR("failed to allocate output buffer"); SEND_ERROR("failed to allocate output buffer");
GST_BUFFER_TIMESTAMP(buffer) = pts;
GST_BUFFER_DURATION(buffer) = app->frame_duration;
pts += app->frame_duration;
gst_buffer_set_vaapi_video_meta(buffer, meta); gst_buffer_set_vaapi_video_meta(buffer, meta);
gst_vaapi_video_meta_unref(meta); gst_vaapi_video_meta_unref(meta);
g_async_queue_push(app->decoder_queue, buffer); g_async_queue_push(app->decoder_queue, buffer);
@ -272,6 +281,35 @@ send_error:
return NULL; return NULL;
} }
static void
app_set_framerate(App *app, guint fps_n, guint fps_d)
{
if (!fps_n || !fps_d)
return;
g_mutex_lock(&app->mutex);
if (fps_n != app->fps_n || fps_d != app->fps_d) {
app->fps_n = fps_n;
app->fps_d = fps_d;
app->frame_duration = gst_util_uint64_scale(
GST_TIME_AS_USECONDS(GST_SECOND), fps_d, fps_n);
}
g_mutex_unlock(&app->mutex);
}
static void
handle_decoder_caps(GObject *obj, GParamSpec *pspec, void *user_data)
{
App * const app = user_data;
GstVideoCodecState *codec_state;
g_assert(app->decoder == GST_VAAPI_DECODER(obj));
codec_state = gst_vaapi_decoder_get_codec_state(app->decoder);
app_set_framerate(app, codec_state->info.fps_n, codec_state->info.fps_d);
gst_video_codec_state_unref(codec_state);
}
static gboolean static gboolean
start_decoder(App *app) start_decoder(App *app)
{ {
@ -312,6 +350,9 @@ start_decoder(App *app)
if (!app->decoder) if (!app->decoder)
return FALSE; return FALSE;
g_signal_connect(G_OBJECT(app->decoder), "notify::caps",
G_CALLBACK(handle_decoder_caps), app);
app->decoder_thread = g_thread_create(decoder_thread, app, TRUE, NULL); app->decoder_thread = g_thread_create(decoder_thread, app, TRUE, NULL);
if (!app->decoder_thread) if (!app->decoder_thread)
return FALSE; return FALSE;
@ -346,6 +387,15 @@ ensure_window_size(App *app, GstVaapiSurface *surface)
&app->window_width, &app->window_height); &app->window_width, &app->window_height);
} }
static inline void
renderer_wait_until(App *app, GstClockTime pts)
{
g_mutex_lock(&app->mutex);
do {
} while (g_cond_wait_until(&app->render_ready, &app->mutex, pts));
g_mutex_unlock(&app->mutex);
}
static gboolean static gboolean
renderer_process(App *app, GstBuffer *buffer) renderer_process(App *app, GstBuffer *buffer)
{ {
@ -369,6 +419,8 @@ renderer_process(App *app, GstBuffer *buffer)
ensure_window_size(app, surface); ensure_window_size(app, surface);
renderer_wait_until(app, GST_BUFFER_TIMESTAMP(buffer));
if (!gst_vaapi_window_put_surface(app->window, surface, NULL, NULL, if (!gst_vaapi_window_put_surface(app->window, surface, NULL, NULL,
GST_VAAPI_PICTURE_STRUCTURE_FRAME)) GST_VAAPI_PICTURE_STRUCTURE_FRAME))
SEND_ERROR("failed to render surface %" GST_VAAPI_ID_FORMAT, SEND_ERROR("failed to render surface %" GST_VAAPI_ID_FORMAT,
@ -459,6 +511,7 @@ app_free(App *app)
} }
g_cond_clear(&app->decoder_ready); g_cond_clear(&app->decoder_ready);
g_cond_clear(&app->render_ready);
g_cond_clear(&app->event_cond); g_cond_clear(&app->event_cond);
g_mutex_clear(&app->mutex); g_mutex_clear(&app->mutex);
g_slice_free(App, app); g_slice_free(App, app);
@ -476,7 +529,9 @@ app_new(void)
g_mutex_init(&app->mutex); g_mutex_init(&app->mutex);
g_cond_init(&app->event_cond); g_cond_init(&app->event_cond);
g_cond_init(&app->decoder_ready); g_cond_init(&app->decoder_ready);
g_cond_init(&app->render_ready);
app_set_framerate(app, 60, 1);
app->window_width = 640; app->window_width = 640;
app->window_height = 480; app->window_height = 480;