tests: videodecoder: add test for reverse playback

Checks that buffers are pushed backwards in reverse playback

https://bugzilla.gnome.org/show_bug.cgi?id=721666
This commit is contained in:
Thiago Santos 2014-01-08 11:29:29 -03:00
parent 5b8e1925b5
commit b1e728a854

View file

@ -45,6 +45,9 @@ typedef struct _GstVideoDecoderTesterClass GstVideoDecoderTesterClass;
struct _GstVideoDecoderTester struct _GstVideoDecoderTester
{ {
GstVideoDecoder parent; GstVideoDecoder parent;
guint64 last_buf_num;
guint64 last_kf_num;
}; };
struct _GstVideoDecoderTesterClass struct _GstVideoDecoderTesterClass
@ -58,6 +61,11 @@ G_DEFINE_TYPE (GstVideoDecoderTester, gst_video_decoder_tester,
static gboolean static gboolean
gst_video_decoder_tester_start (GstVideoDecoder * dec) gst_video_decoder_tester_start (GstVideoDecoder * dec)
{ {
GstVideoDecoderTester *dectester = (GstVideoDecoderTester *) dec;
dectester->last_buf_num = -1;
dectester->last_kf_num = -1;
return TRUE; return TRUE;
} }
@ -67,12 +75,23 @@ gst_video_decoder_tester_stop (GstVideoDecoder * dec)
return TRUE; return TRUE;
} }
static gboolean
gst_video_decoder_tester_flush (GstVideoDecoder * dec)
{
GstVideoDecoderTester *dectester = (GstVideoDecoderTester *) dec;
dectester->last_buf_num = -1;
dectester->last_kf_num = -1;
return TRUE;
}
static gboolean static gboolean
gst_video_decoder_tester_set_format (GstVideoDecoder * dec, gst_video_decoder_tester_set_format (GstVideoDecoder * dec,
GstVideoCodecState * state) GstVideoCodecState * state)
{ {
GstVideoCodecState *res = gst_video_decoder_set_output_state (dec, GstVideoCodecState *res = gst_video_decoder_set_output_state (dec,
GST_VIDEO_FORMAT_GRAY8, 640, 480, NULL); GST_VIDEO_FORMAT_GRAY8, TEST_VIDEO_WIDTH, TEST_VIDEO_HEIGHT, NULL);
gst_video_codec_state_unref (res); gst_video_codec_state_unref (res);
return TRUE; return TRUE;
@ -82,23 +101,40 @@ static GstFlowReturn
gst_video_decoder_tester_handle_frame (GstVideoDecoder * dec, gst_video_decoder_tester_handle_frame (GstVideoDecoder * dec,
GstVideoCodecFrame * frame) GstVideoCodecFrame * frame)
{ {
GstVideoDecoderTester *dectester = (GstVideoDecoderTester *) dec;
guint64 input_num;
guint8 *data; guint8 *data;
gint size; gint size;
GstMapInfo map; GstMapInfo map;
/* the output is gray8 */
size = TEST_VIDEO_WIDTH * TEST_VIDEO_HEIGHT;
data = g_malloc0 (size);
gst_buffer_map (frame->input_buffer, &map, GST_MAP_READ); gst_buffer_map (frame->input_buffer, &map, GST_MAP_READ);
memcpy (data, map.data, sizeof (guint64));
input_num = *((guint64 *) map.data);
if (input_num == dectester->last_buf_num + 1
|| !GST_BUFFER_FLAG_IS_SET (frame->input_buffer,
GST_BUFFER_FLAG_DELTA_UNIT)) {
/* the output is gray8 */
size = TEST_VIDEO_WIDTH * TEST_VIDEO_HEIGHT;
data = g_malloc0 (size);
memcpy (data, map.data, sizeof (guint64));
frame->output_buffer = gst_buffer_new_wrapped (data, size);
frame->pts = GST_BUFFER_PTS (frame->input_buffer);
frame->duration = GST_BUFFER_DURATION (frame->input_buffer);
dectester->last_buf_num = input_num;
if (!GST_BUFFER_FLAG_IS_SET (frame->input_buffer,
GST_BUFFER_FLAG_DELTA_UNIT))
dectester->last_kf_num = input_num;
}
gst_buffer_unmap (frame->input_buffer, &map); gst_buffer_unmap (frame->input_buffer, &map);
frame->output_buffer = gst_buffer_new_wrapped (data, size); if (frame->output_buffer)
frame->pts = GST_BUFFER_PTS (frame->input_buffer); return gst_video_decoder_finish_frame (dec, frame);
frame->duration = GST_BUFFER_DURATION (frame->input_buffer); return GST_FLOW_OK;
return gst_video_decoder_finish_frame (dec, frame);
} }
static void static void
@ -125,6 +161,7 @@ gst_video_decoder_tester_class_init (GstVideoDecoderTesterClass * klass)
audiosink_class->start = gst_video_decoder_tester_start; audiosink_class->start = gst_video_decoder_tester_start;
audiosink_class->stop = gst_video_decoder_tester_stop; audiosink_class->stop = gst_video_decoder_tester_stop;
audiosink_class->flush = gst_video_decoder_tester_flush;
audiosink_class->handle_frame = gst_video_decoder_tester_handle_frame; audiosink_class->handle_frame = gst_video_decoder_tester_handle_frame;
audiosink_class->set_format = gst_video_decoder_tester_set_format; audiosink_class->set_format = gst_video_decoder_tester_set_format;
} }
@ -172,6 +209,26 @@ cleanup_videodecodertest (void)
gst_check_teardown_element (dec); gst_check_teardown_element (dec);
} }
static GstBuffer *
create_test_buffer (guint64 num)
{
GstBuffer *buffer;
guint64 *data = g_malloc (sizeof (guint64));
*data = num;
buffer = gst_buffer_new_wrapped (data, sizeof (guint64));
GST_BUFFER_PTS (buffer) =
gst_util_uint64_scale_round (num, GST_SECOND * TEST_VIDEO_FPS_D,
TEST_VIDEO_FPS_N);
GST_BUFFER_DURATION (buffer) =
gst_util_uint64_scale_round (GST_SECOND, TEST_VIDEO_FPS_D,
TEST_VIDEO_FPS_N);
return buffer;
}
static void static void
send_startup_events (void) send_startup_events (void)
{ {
@ -211,18 +268,7 @@ GST_START_TEST (videodecoder_playback)
/* push buffers, the data is actually a number so we can track them */ /* push buffers, the data is actually a number so we can track them */
for (i = 0; i < NUM_BUFFERS; i++) { for (i = 0; i < NUM_BUFFERS; i++) {
guint64 *data = g_malloc (sizeof (guint64)); buffer = create_test_buffer (i);
*data = i;
buffer = gst_buffer_new_wrapped (data, sizeof (guint64));
GST_BUFFER_PTS (buffer) =
gst_util_uint64_scale_round (i, GST_SECOND * TEST_VIDEO_FPS_D,
TEST_VIDEO_FPS_N);
GST_BUFFER_DURATION (buffer) =
gst_util_uint64_scale_round (GST_SECOND, TEST_VIDEO_FPS_D,
TEST_VIDEO_FPS_N);
fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK); fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
} }
@ -290,18 +336,7 @@ GST_START_TEST (videodecoder_playback_with_events)
tags = gst_tag_list_new (GST_TAG_TRACK_NUMBER, i, NULL); tags = gst_tag_list_new (GST_TAG_TRACK_NUMBER, i, NULL);
fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_tag (tags))); fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_tag (tags)));
} else { } else {
guint64 *data = g_malloc (sizeof (guint64)); buffer = create_test_buffer (i);
*data = i;
buffer = gst_buffer_new_wrapped (data, sizeof (guint64));
GST_BUFFER_PTS (buffer) =
gst_util_uint64_scale_round (i, GST_SECOND * TEST_VIDEO_FPS_D,
TEST_VIDEO_FPS_N);
GST_BUFFER_DURATION (buffer) =
gst_util_uint64_scale_round (GST_SECOND, TEST_VIDEO_FPS_D,
TEST_VIDEO_FPS_N);
fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK); fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
} }
@ -384,6 +419,88 @@ GST_START_TEST (videodecoder_playback_with_events)
GST_END_TEST; GST_END_TEST;
GST_START_TEST (videodecoder_backwards_playback)
{
GstSegment segment;
GstBuffer *buffer;
guint64 i;
GList *iter;
setup_videodecodertester ();
gst_pad_set_active (mysrcpad, TRUE);
gst_element_set_state (dec, GST_STATE_PLAYING);
gst_pad_set_active (mysinkpad, TRUE);
send_startup_events ();
/* push a new segment with -1 rate */
gst_segment_init (&segment, GST_FORMAT_TIME);
segment.rate = -1.0;
segment.stop = (NUM_BUFFERS + 1) * gst_util_uint64_scale_round (GST_SECOND,
TEST_VIDEO_FPS_D, TEST_VIDEO_FPS_N);
fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
/* push buffers, the data is actually a number so we can track them */
i = NUM_BUFFERS;
while (i > 0) {
gint target = i;
gint j;
/* push groups of 10 buffers
* every number that is divisible by 10 is set as a discont,
* if it is divisible by 20 it is also a keyframe
*
* The logic here is that hte current i is the target, and then
* it pushes buffers from 'target - 10' up to target.
*/
for (j = MAX (target - 10, 0); j < target; j++) {
GstBuffer *buffer = create_test_buffer (j);
if (j % 10 == 0)
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
if (j % 20 != 0)
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
i--;
}
}
fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
/* check that all buffers were received by our source pad */
fail_unless (g_list_length (buffers) == NUM_BUFFERS);
i = NUM_BUFFERS - 1;
for (iter = buffers; iter; iter = g_list_next (iter)) {
GstMapInfo map;
guint64 num;
buffer = iter->data;
gst_buffer_map (buffer, &map, GST_MAP_READ);
num = *(guint64 *) map.data;
fail_unless (i == num);
fail_unless (GST_BUFFER_PTS (buffer) == gst_util_uint64_scale_round (i,
GST_SECOND * TEST_VIDEO_FPS_D, TEST_VIDEO_FPS_N));
fail_unless (GST_BUFFER_DURATION (buffer) ==
gst_util_uint64_scale_round (GST_SECOND, TEST_VIDEO_FPS_D,
TEST_VIDEO_FPS_N));
gst_buffer_unmap (buffer, &map);
i--;
}
g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref);
buffers = NULL;
cleanup_videodecodertest ();
}
GST_END_TEST;
static Suite * static Suite *
gst_videodecoder_suite (void) gst_videodecoder_suite (void)
{ {
@ -394,6 +511,8 @@ gst_videodecoder_suite (void)
tcase_add_test (tc, videodecoder_playback); tcase_add_test (tc, videodecoder_playback);
tcase_add_test (tc, videodecoder_playback_with_events); tcase_add_test (tc, videodecoder_playback_with_events);
tcase_add_test (tc, videodecoder_backwards_playback);
return s; return s;
} }