From 9ab7a0ef177bb5b494c0b7cdfe2b791b3bffec6b Mon Sep 17 00:00:00 2001 From: Thomas Vander Stichele Date: Fri, 28 Apr 2006 14:49:22 +0000 Subject: [PATCH] gst/videorate/gstvideorate.c: fix up docs fix a leak when no caps negotiated fix counting of input frames Original commit message from CVS: * gst/videorate/gstvideorate.c: (gst_video_rate_reset), (gst_video_rate_swap_prev), (gst_video_rate_chain): fix up docs fix a leak when no caps negotiated fix counting of input frames * tests/check/elements/.cvsignore: * tests/check/elements/videorate.c: (assert_videorate_stats), (GST_START_TEST), (videorate_suite): add tests for these --- ChangeLog | 12 +++ docs/libs/tmpl/gsttuner.sgml | 2 - gst/videorate/gstvideorate.c | 41 ++++--- tests/check/elements/.gitignore | 1 + tests/check/elements/videorate.c | 177 +++++++++++++++++++++++++++---- 5 files changed, 197 insertions(+), 36 deletions(-) diff --git a/ChangeLog b/ChangeLog index 69a0bfccdf..c74b6bd7c7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2006-04-28 Thomas Vander Stichele + + * gst/videorate/gstvideorate.c: (gst_video_rate_reset), + (gst_video_rate_swap_prev), (gst_video_rate_chain): + fix up docs + fix a leak when no caps negotiated + fix counting of input frames + * tests/check/elements/.cvsignore: + * tests/check/elements/videorate.c: (assert_videorate_stats), + (GST_START_TEST), (videorate_suite): + add tests for these + 2006-04-28 Wim Taymans * gst-libs/gst/audio/gstringbuffer.c: diff --git a/docs/libs/tmpl/gsttuner.sgml b/docs/libs/tmpl/gsttuner.sgml index 19d288556d..f01a16ec10 100644 --- a/docs/libs/tmpl/gsttuner.sgml +++ b/docs/libs/tmpl/gsttuner.sgml @@ -96,8 +96,6 @@ interface for elements that provide tuner operations @tuner: @norm: - -@channel: diff --git a/gst/videorate/gstvideorate.c b/gst/videorate/gstvideorate.c index f4186c93dc..bdea1369a4 100644 --- a/gst/videorate/gstvideorate.c +++ b/gst/videorate/gstvideorate.c @@ -28,29 +28,35 @@ * used to interpolate frames (yet). * * - * By default the element will simply negotiate the same framerate on its source and - * sink pad and will adjust timestamps/insert/drop frames in case the input stream - * is not respecting that framerate. + * By default the element will simply negotiate the same framerate on its + * source and sink pad and will adjust timestamps/insert/drop frames in case + * the input stream is not respecting that framerate. * * - * A conversion to another framerate can be forced by using filtered caps on the source - * pad. + * A conversion to another framerate can be forced by using filtered caps on + * the source pad. * * - * The properties "in", "out", "duplicate" and "drop" can be read to obtain - * information about respectively received frame, outputed frame, duplicated frames - * and dropped frames. - * When the "silent" property is set to FALSE, a GObject property notification will - * be emited whenever one of the "duplicate" or "drop" values changed. This can - * potentially cause performance degradation. Also note that property notification - * will happen in the streaming thread so applications should be prepared for this. + * The properties "in", "out", "duplicate" and "drop" can be read to obtain + * information about number of input frames, output frames, dropped frames + * (i.e. the number of unused input frames) and duplicated frames (i.e. the + * number of times an input frame was duplicated, beside being used normally). + * + * An input stream that needs no adjustments will thus never have dropped or + * duplicated frames. + * + * When the "silent" property is set to FALSE, a GObject property notification + * will be emitted whenever one of the "duplicate" or "drop" values changes. + * This can potentially cause performance degradation. + * Note that property notification will happen from the streaming thread, so + * applications should be prepared for this. * * Example pipelines * * * gst-launch -v filesrc location=videotestsrc.ogg ! oggdemux ! theoradec ! videorate ! video/x-raw-yuv,framerate=15/1 ! xvimagesink * - * Decode an Ogg/Theora and adjust the framerate to 15 fps. + * Decode an Ogg/Theora file and adjust the framerate to 15 fps before playing. * To create the test Ogg/Theora file refer to the documentation of theoraenc. * * @@ -358,7 +364,7 @@ no_transform: static void gst_video_rate_reset (GstVideoRate * videorate) { - GST_DEBUG ("resetting data"); + GST_DEBUG ("resetting internal variables"); videorate->in = 0; videorate->out = 0; @@ -450,6 +456,7 @@ static void gst_video_rate_swap_prev (GstVideoRate * videorate, GstBuffer * buffer, gint64 time) { + GST_LOG_OBJECT (videorate, "swap_prev: storing buffer %p in prev", buffer); if (videorate->prevbuf) gst_buffer_unref (videorate->prevbuf); videorate->prevbuf = buffer; @@ -530,7 +537,7 @@ gst_video_rate_chain (GstPad * pad, GstBuffer * buffer) videorate = GST_VIDEO_RATE (gst_pad_get_parent (pad)); - /* make sure the denominators have to be != 0 */ + /* make sure the denominators are not 0 */ if (videorate->from_rate_denominator == 0 || videorate->to_rate_denominator == 0) goto not_negotiated; @@ -543,9 +550,10 @@ gst_video_rate_chain (GstPad * pad, GstBuffer * buffer) intime = gst_segment_to_running_time (&videorate->segment, GST_FORMAT_TIME, in_ts); - /* pull in 2 buffers */ + /* we need to have two buffers to compare */ if (videorate->prevbuf == NULL) { gst_video_rate_swap_prev (videorate, buffer, intime); + videorate->in++; videorate->next_ts = 0; } else { GstClockTime prevtime; @@ -639,6 +647,7 @@ done: not_negotiated: { GST_WARNING_OBJECT (videorate, "no framerate negotiated"); + gst_buffer_unref (buffer); res = GST_FLOW_NOT_NEGOTIATED; goto done; } diff --git a/tests/check/elements/.gitignore b/tests/check/elements/.gitignore index 504ca6631c..437093582c 100644 --- a/tests/check/elements/.gitignore +++ b/tests/check/elements/.gitignore @@ -2,6 +2,7 @@ audioconvert audioresample audiotestsrc +videorate videotestsrc volume vorbisdec diff --git a/tests/check/elements/videorate.c b/tests/check/elements/videorate.c index 87997461a8..285f381270 100644 --- a/tests/check/elements/videorate.c +++ b/tests/check/elements/videorate.c @@ -146,6 +146,114 @@ GST_START_TEST (test_one) GST_END_TEST; +GST_START_TEST (test_more) +{ + GstElement *videorate; + GstBuffer *first, *second, *third, *outbuffer; + GList *l; + GstCaps *caps; + + videorate = setup_videorate (); + fail_unless (gst_element_set_state (videorate, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + assert_videorate_stats (videorate, "creation", 0, 0, 0, 0); + + /* first buffer */ + first = gst_buffer_new_and_alloc (4); + GST_BUFFER_TIMESTAMP (first) = 0; + memset (GST_BUFFER_DATA (first), 1, 4); + caps = gst_caps_from_string (VIDEO_CAPS_STRING); + gst_buffer_set_caps (first, caps); + gst_caps_unref (caps); + ASSERT_BUFFER_REFCOUNT (first, "first", 1); + gst_buffer_ref (first); + + /* pushing gives away my reference ... */ + fail_unless (gst_pad_push (mysrcpad, first) == GST_FLOW_OK); + /* ... and it is now stuck inside videorate */ + ASSERT_BUFFER_REFCOUNT (first, "first", 2); + fail_unless_equals_int (g_list_length (buffers), 0); + assert_videorate_stats (videorate, "first buffer", 1, 0, 0, 0); + + /* second buffer; inbetween second and third output frame's timestamp */ + second = gst_buffer_new_and_alloc (4); + GST_BUFFER_TIMESTAMP (second) = GST_SECOND * 3 / 50; + memset (GST_BUFFER_DATA (second), 2, 4); + caps = gst_caps_from_string (VIDEO_CAPS_STRING); + gst_buffer_set_caps (second, caps); + gst_caps_unref (caps); + ASSERT_BUFFER_REFCOUNT (second, "second", 1); + gst_buffer_ref (second); + + /* pushing gives away one of my references ... */ + fail_unless (gst_pad_push (mysrcpad, second) == GST_FLOW_OK); + /* ... and it is now stuck inside videorate */ + ASSERT_BUFFER_REFCOUNT (second, "second", 2); + + /* ... and the first one is pushed out, with timestamp 0 */ + fail_unless_equals_int (g_list_length (buffers), 1); + assert_videorate_stats (videorate, "second buffer", 2, 1, 0, 0); + ASSERT_BUFFER_REFCOUNT (first, "first", 2); + + outbuffer = buffers->data; + fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (outbuffer), 0); + + /* third buffer */ + third = gst_buffer_new_and_alloc (4); + GST_BUFFER_TIMESTAMP (third) = GST_SECOND * 12 / 50; + memset (GST_BUFFER_DATA (third), 3, 4); + caps = gst_caps_from_string (VIDEO_CAPS_STRING); + gst_buffer_set_caps (third, caps); + gst_caps_unref (caps); + ASSERT_BUFFER_REFCOUNT (third, "third", 1); + gst_buffer_ref (third); + + /* pushing gives away my reference ... */ + fail_unless (gst_pad_push (mysrcpad, third) == GST_FLOW_OK); + /* ... and it is now stuck inside videorate */ + ASSERT_BUFFER_REFCOUNT (third, "third", 2); + + /* submitting the third buffer has triggered flushing of three more frames */ + assert_videorate_stats (videorate, "third buffer", 3, 4, 0, 2); + + /* check timestamp and source correctness */ + l = buffers; + fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (l->data), 0); + fail_unless_equals_int (GST_BUFFER_DATA (l->data)[0], 1); + l = g_list_next (l); + fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (l->data), GST_SECOND / 25); + fail_unless_equals_int (GST_BUFFER_DATA (l->data)[0], 2); + l = g_list_next (l); + fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (l->data), + GST_SECOND * 2 / 25); + fail_unless_equals_int (GST_BUFFER_DATA (l->data)[0], 2); + l = g_list_next (l); + fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (l->data), + GST_SECOND * 3 / 25); + fail_unless_equals_int (GST_BUFFER_DATA (l->data)[0], 2); + + fail_unless_equals_int (g_list_length (buffers), 4); + /* one held by us, three held by each output frame taken from the second */ + ASSERT_BUFFER_REFCOUNT (second, "second", 4); + + /* now send EOS */ + fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ())); + + /* submitting eos should flush out two more frames for tick 8 and 10 */ + /* FIXME: right now it only flushes out one, so out is 5 instead of 6 ! */ + assert_videorate_stats (videorate, "eos", 3, 5, 0, 2); + fail_unless_equals_int (g_list_length (buffers), 5); + + /* cleanup */ + gst_buffer_unref (first); + gst_buffer_unref (second); + gst_buffer_unref (third); + cleanup_videorate (videorate); +} + +GST_END_TEST; + /* frames at 1, 0, 2 -> second one should be ignored */ GST_START_TEST (test_wrong_order_from_zero) { @@ -176,8 +284,7 @@ GST_START_TEST (test_wrong_order_from_zero) /* ... and it is now stuck inside videorate */ ASSERT_BUFFER_REFCOUNT (first, "first", 2); fail_unless_equals_int (g_list_length (buffers), 0); - /* FIXME: in is not counted properly, should be 1 */ - assert_videorate_stats (videorate, "first", 0, 0, 0, 0); + assert_videorate_stats (videorate, "first", 1, 0, 0, 0); /* second buffer */ second = gst_buffer_new_and_alloc (4); @@ -191,13 +298,12 @@ GST_START_TEST (test_wrong_order_from_zero) /* pushing gives away my reference ... */ fail_unless (gst_pad_push (mysrcpad, second) == GST_FLOW_OK); - /* ... and it got dropped because it was before the first */ + /* ... and it is now dropped because it is too old */ ASSERT_BUFFER_REFCOUNT (second, "second", 1); fail_unless_equals_int (g_list_length (buffers), 0); - /* ... and the first one is now dropped */ - /* FIXME: still a bug with in, needs to be 2 */ - assert_videorate_stats (videorate, "second", 1, 0, 1, 0); + /* ... and the first one is still there */ + assert_videorate_stats (videorate, "second", 2, 0, 1, 0); ASSERT_BUFFER_REFCOUNT (first, "first", 2); /* third buffer */ @@ -221,8 +327,7 @@ GST_START_TEST (test_wrong_order_from_zero) ASSERT_BUFFER_REFCOUNT (first, "first", 39); ASSERT_BUFFER_REFCOUNT (second, "second", 1); ASSERT_BUFFER_REFCOUNT (third, "third", 2); - /* FIXME: you guessed it ... */ - assert_videorate_stats (videorate, "third", 2, 38, 1, 37); + assert_videorate_stats (videorate, "third", 3, 38, 1, 37); /* verify last buffer */ outbuffer = g_list_last (buffers)->data; @@ -269,8 +374,7 @@ GST_START_TEST (test_wrong_order) /* ... and it is now stuck inside videorate */ ASSERT_BUFFER_REFCOUNT (first, "first", 2); fail_unless_equals_int (g_list_length (buffers), 0); - /* FIXME: in is not counted properly, should be 1 */ - assert_videorate_stats (videorate, "first", 0, 0, 0, 0); + assert_videorate_stats (videorate, "first", 1, 0, 0, 0); /* second buffer */ second = gst_buffer_new_and_alloc (4); @@ -288,8 +392,7 @@ GST_START_TEST (test_wrong_order) ASSERT_BUFFER_REFCOUNT (second, "second", 2); /* and it created 13 output buffers as copies of the first frame */ fail_unless_equals_int (g_list_length (buffers), 13); - /* FIXME: guess */ - assert_videorate_stats (videorate, "second", 1, 13, 0, 12); + assert_videorate_stats (videorate, "second", 2, 13, 0, 12); ASSERT_BUFFER_REFCOUNT (first, "first", 14); /* third buffer */ @@ -312,8 +415,7 @@ GST_START_TEST (test_wrong_order) ASSERT_BUFFER_REFCOUNT (first, "first", 14); ASSERT_BUFFER_REFCOUNT (second, "second", 26); /* three frames submitted; two of them output as is, and 36 duplicated */ - /* FIXME: guess */ - assert_videorate_stats (videorate, "third", 2, 38, 0, 36); + assert_videorate_stats (videorate, "third", 3, 38, 0, 36); /* fourth buffer */ fourth = gst_buffer_new_and_alloc (4); @@ -327,14 +429,13 @@ GST_START_TEST (test_wrong_order) /* pushing gives away my reference ... */ fail_unless (gst_pad_push (mysrcpad, fourth) == GST_FLOW_OK); - /* ... and it is dropped from videorate because 0 < 2 */ + /* ... and it is dropped */ ASSERT_BUFFER_REFCOUNT (fourth, "fourth", 1); fail_unless_equals_int (g_list_length (buffers), 38); - ASSERT_BUFFER_REFCOUNT (first, "first", 14); /* 13 frames pushed out */ + ASSERT_BUFFER_REFCOUNT (first, "first", 14); ASSERT_BUFFER_REFCOUNT (second, "second", 26); - /* FIXME: guess */ - assert_videorate_stats (videorate, "fourth", 3, 38, 1, 36); + assert_videorate_stats (videorate, "fourth", 4, 38, 1, 36); /* verify last buffer */ outbuffer = g_list_last (buffers)->data; @@ -342,6 +443,7 @@ GST_START_TEST (test_wrong_order) fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (outbuffer), GST_SECOND * 37 / 25); + /* cleanup */ gst_buffer_unref (first); gst_buffer_unref (second); @@ -352,6 +454,42 @@ GST_START_TEST (test_wrong_order) GST_END_TEST; + +/* if no framerate is negotiated, we should not be able to push a buffer */ +GST_START_TEST (test_no_framerate) +{ + GstElement *videorate; + GstBuffer *inbuffer, *outbuffer; + GstCaps *caps; + + videorate = setup_videorate (); + fail_unless (gst_element_set_state (videorate, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + inbuffer = gst_buffer_new_and_alloc (4); + memset (GST_BUFFER_DATA (inbuffer), 0, 4); + caps = gst_caps_from_string (VIDEO_CAPS_NO_FRAMERATE_STRING); + gst_buffer_set_caps (inbuffer, caps); + gst_caps_unref (caps); + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + + /* take a ref so we can later check refcount */ + gst_buffer_ref (inbuffer); + + /* no framerate is negotiated so pushing should fail */ + fail_if (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + gst_buffer_unref (inbuffer); + fail_unless_equals_int (g_list_length (buffers), 0); + + /* cleanup */ + cleanup_videorate (videorate); +} + +GST_END_TEST; + + Suite * videorate_suite (void) { @@ -359,8 +497,11 @@ videorate_suite (void) TCase *tc_chain = tcase_create ("general"); suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_one); + tcase_add_test (tc_chain, test_more); tcase_add_test (tc_chain, test_wrong_order_from_zero); tcase_add_test (tc_chain, test_wrong_order); + tcase_add_test (tc_chain, test_no_framerate); return s; }