/* GStreamer * Copyright (C) 2005 Jan Schmidt * 2009 Wim Taymans * * gstsegment.c: Unit test for segments * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #define check_times(segment, position, stream_time, running_time) G_STMT_START { \ guint64 st, rt, pos; \ \ st = gst_segment_to_stream_time ((segment), (segment)->format, (position)); \ rt = gst_segment_to_running_time ((segment), (segment)->format, (position)); \ GST_DEBUG ("position %" G_GUINT64_FORMAT ", st %" G_GUINT64_FORMAT ", rt %" \ G_GUINT64_FORMAT, (guint64) (position), (guint64) (stream_time), (guint64) (running_time)); \ \ fail_unless_equals_int64 (st, (stream_time)); \ fail_unless_equals_int64 (rt, (running_time)); \ if ((stream_time) != -1) { \ pos = gst_segment_position_from_stream_time ((segment), (segment)->format, st); \ fail_unless_equals_int64 (pos, (position)); \ } \ \ if ((running_time) != -1) { \ pos = gst_segment_position_from_running_time ((segment), (segment)->format, rt); \ fail_unless_equals_int64 (pos, (position)); \ } \ } G_STMT_END; /* mess with the segment structure in the bytes format */ GST_START_TEST (segment_seek_nosize) { GstSegment segment; gboolean res; guint64 cstart, cstop; gboolean update; gst_segment_init (&segment, GST_FORMAT_BYTES); /* configure segment to start 100 */ gst_segment_do_seek (&segment, 1.0, GST_FORMAT_BYTES, GST_SEEK_FLAG_NONE, GST_SEEK_TYPE_SET, 100, GST_SEEK_TYPE_NONE, -1, &update); fail_unless_equals_uint64 (segment.start, 100); fail_unless_equals_uint64 (segment.position, 100); fail_unless_equals_uint64 (segment.stop, -1); fail_unless (update == TRUE); /* appended after current position 0 */ check_times (&segment, 100, 100, 0); /* do some clipping on the open range */ /* completely outside */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 0, 50, &cstart, &cstop); fail_unless (res == FALSE); /* touching lower bound, still outside of the segment */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 50, 100, &cstart, &cstop); fail_unless (res == FALSE); /* partially inside */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 50, 150, &cstart, &cstop); fail_unless (res == TRUE); fail_unless_equals_uint64 (cstart, 100); fail_unless_equals_uint64 (cstop, 150); /* inside, touching lower bound */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 100, 150, &cstart, &cstop); fail_unless (res == TRUE); fail_unless_equals_uint64 (cstart, 100); fail_unless_equals_uint64 (cstop, 150); /* special case, 0 duration and outside segment */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 90, 90, &cstart, &cstop); fail_unless (res == FALSE); /* special case, 0 duration and touching lower bound, i.e. inside segment */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 100, 100, &cstart, &cstop); fail_unless (res == TRUE); fail_unless_equals_uint64 (cstart, 100); fail_unless_equals_uint64 (cstop, 100); /* special case, 0 duration and inside the segment */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 120, 120, &cstart, &cstop); fail_unless (res == TRUE); fail_unless_equals_uint64 (cstart, 120); fail_unless_equals_uint64 (cstop, 120); /* completely inside */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 150, 200, &cstart, &cstop); fail_unless (res == TRUE); fail_unless_equals_uint64 (cstart, 150); fail_unless_equals_uint64 (cstop, 200); /* invalid start */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, -1, 100, &cstart, &cstop); fail_unless (res == FALSE); /* start outside, we don't know the stop */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 50, -1, &cstart, &cstop); fail_unless (res == TRUE); fail_unless_equals_uint64 (cstart, 100); fail_unless_equals_int64 (cstop, -1); /* start on lower bound */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 100, -1, &cstart, &cstop); fail_unless (res == TRUE); fail_unless_equals_uint64 (cstart, 100); fail_unless_equals_int64 (cstop, -1); /* start inside */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 150, -1, &cstart, &cstop); fail_unless (res == TRUE); fail_unless_equals_uint64 (cstart, 150); fail_unless_equals_int64 (cstop, -1); /* move to 150, this is a running_time of 50 */ segment.position = 150; check_times (&segment, 150, 150, 50); /* add 100 to start, set stop to 300 */ gst_segment_do_seek (&segment, 1.0, GST_FORMAT_BYTES, GST_SEEK_FLAG_NONE, GST_SEEK_TYPE_SET, 100 + 100, GST_SEEK_TYPE_SET, 300, &update); fail_unless_equals_uint64 (segment.start, 200); fail_unless_equals_uint64 (segment.position, 200); fail_unless_equals_uint64 (segment.stop, 300); fail_unless_equals_uint64 (segment.base, 50); fail_unless (update == TRUE); check_times (&segment, 200, 200, 50); check_times (&segment, 250, 250, 100); update = FALSE; /* add 100 to start (to 300), set stop to 200, this is not allowed. * nothing should be updated in the segment. A g_warning is * emitted. */ ASSERT_CRITICAL (gst_segment_do_seek (&segment, 1.0, GST_FORMAT_BYTES, GST_SEEK_FLAG_NONE, GST_SEEK_TYPE_SET, 200 + 100, GST_SEEK_TYPE_SET, 200, &update)); fail_unless_equals_uint64 (segment.start, 200); fail_unless_equals_uint64 (segment.position, 200); fail_unless_equals_uint64 (segment.stop, 300); fail_unless_equals_uint64 (segment.base, 50); /* update didn't change */ fail_unless (update == FALSE); check_times (&segment, 200, 200, 50); check_times (&segment, 250, 250, 100); update = TRUE; /* seek relative to end, should not do anything since size is * unknown. */ gst_segment_do_seek (&segment, 1.0, GST_FORMAT_BYTES, GST_SEEK_FLAG_NONE, GST_SEEK_TYPE_END, -300, GST_SEEK_TYPE_END, -100, &update); fail_unless_equals_uint64 (segment.start, 200); fail_unless_equals_uint64 (segment.position, 200); fail_unless_equals_uint64 (segment.stop, 300); fail_unless_equals_uint64 (segment.base, 50); fail_unless (update == FALSE); check_times (&segment, 250, 250, 100); /* completely outside */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 0, 50, &cstart, &cstop); fail_unless (res == FALSE); /* touching lower bound */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 50, 200, &cstart, &cstop); fail_unless (res == FALSE); /* partially inside */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 50, 250, &cstart, &cstop); fail_unless (res == TRUE); fail_unless_equals_uint64 (cstart, 200); fail_unless_equals_uint64 (cstop, 250); /* inside, touching lower bound */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 200, 250, &cstart, &cstop); fail_unless (res == TRUE); fail_unless_equals_uint64 (cstart, 200); fail_unless_equals_uint64 (cstop, 250); /* completely inside */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 250, 290, &cstart, &cstop); fail_unless (res == TRUE); fail_unless_equals_uint64 (cstart, 250); fail_unless_equals_uint64 (cstop, 290); /* partially inside */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 250, 350, &cstart, &cstop); fail_unless (res == TRUE); fail_unless_equals_uint64 (cstart, 250); fail_unless_equals_uint64 (cstop, 300); /* invalid start */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, -1, 100, &cstart, &cstop); fail_unless (res == FALSE); /* start outside */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 50, -1, &cstart, &cstop); fail_unless (res == TRUE); fail_unless_equals_uint64 (cstart, 200); fail_unless_equals_uint64 (cstop, 300); /* start on lower bound */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 200, -1, &cstart, &cstop); fail_unless (res == TRUE); fail_unless_equals_uint64 (cstart, 200); fail_unless_equals_uint64 (cstop, 300); /* start inside */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 250, -1, &cstart, &cstop); fail_unless (res == TRUE); fail_unless_equals_uint64 (cstart, 250); fail_unless_equals_uint64 (cstop, 300); /* start outside on boundary */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 300, -1, &cstart, &cstop); fail_unless (res == FALSE); /* start completely outside */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 350, -1, &cstart, &cstop); fail_unless (res == FALSE); } GST_END_TEST; /* mess with the segment structure in the bytes format */ GST_START_TEST (segment_seek_size) { GstSegment segment; gboolean res; guint64 cstart, cstop; gboolean update; gst_segment_init (&segment, GST_FORMAT_BYTES); segment.duration = 200; /* configure segment to start 100 */ gst_segment_do_seek (&segment, 1.0, GST_FORMAT_BYTES, GST_SEEK_FLAG_NONE, GST_SEEK_TYPE_SET, 100, GST_SEEK_TYPE_NONE, -1, &update); fail_unless_equals_uint64 (segment.start, 100); fail_unless_equals_uint64 (segment.position, 100); fail_unless_equals_int64 (segment.stop, -1); fail_unless (update == TRUE); check_times (&segment, 100, 100, 0); /* do some clipping on the open range */ /* completely outside */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 0, 50, &cstart, &cstop); fail_unless (res == FALSE); /* touching lower bound */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 50, 100, &cstart, &cstop); fail_unless (res == FALSE); /* partially inside */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 50, 150, &cstart, &cstop); fail_unless (res == TRUE); fail_unless_equals_uint64 (cstart, 100); fail_unless_equals_uint64 (cstop, 150); /* inside, touching lower bound */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 100, 150, &cstart, &cstop); fail_unless (res == TRUE); fail_unless_equals_uint64 (cstart, 100); fail_unless_equals_uint64 (cstop, 150); /* completely inside */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 150, 200, &cstart, &cstop); fail_unless (res == TRUE); fail_unless_equals_uint64 (cstart, 150); fail_unless_equals_uint64 (cstop, 200); /* invalid start */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, -1, 100, &cstart, &cstop); fail_unless (res == FALSE); /* start outside */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 50, -1, &cstart, &cstop); fail_unless (res == TRUE); fail_unless_equals_uint64 (cstart, 100); fail_unless_equals_int64 (cstop, -1); /* start on lower bound */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 100, -1, &cstart, &cstop); fail_unless (res == TRUE); fail_unless_equals_uint64 (cstart, 100); fail_unless_equals_uint64 (cstop, -1); /* start inside */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 150, -1, &cstart, &cstop); fail_unless (res == TRUE); fail_unless_equals_uint64 (cstart, 150); fail_unless_equals_uint64 (cstop, -1); /* add 100 to start, set stop to 300, stop clips to 200 */ gst_segment_do_seek (&segment, 1.0, GST_FORMAT_BYTES, GST_SEEK_FLAG_NONE, GST_SEEK_TYPE_SET, 100 + 100, GST_SEEK_TYPE_SET, 300, &update); fail_unless_equals_uint64 (segment.start, 200); fail_unless_equals_uint64 (segment.position, 200); fail_unless_equals_uint64 (segment.stop, 200); check_times (&segment, 200, 200, 0); /* add 100 to start (to 300), set stop to 200, this clips start * to duration */ gst_segment_do_seek (&segment, 1.0, GST_FORMAT_BYTES, GST_SEEK_FLAG_NONE, GST_SEEK_TYPE_SET, 200 + 100, GST_SEEK_TYPE_SET, 200, &update); fail_unless_equals_uint64 (segment.start, 200); fail_unless_equals_uint64 (segment.position, 200); fail_unless_equals_uint64 (segment.stop, 200); fail_unless (update == FALSE); check_times (&segment, 200, 200, 0); /* special case, segment's start and stop are identical */ /* completely outside */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 50, 100, &cstart, &cstop); fail_unless (res == FALSE); /* completely outside also */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 250, 300, &cstart, &cstop); fail_unless (res == FALSE); /* stop at boundary point. it's outside because stop is exclusive */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 100, 200, &cstart, &cstop); fail_unless (res == FALSE); /* touching boundary point. it's inside because start at segment start */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 200, 300, &cstart, &cstop); fail_unless (res == TRUE); fail_unless_equals_uint64 (cstart, 200); fail_unless_equals_uint64 (cstop, 200); /* completely inside */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 200, 200, &cstart, &cstop); fail_unless (res == TRUE); fail_unless_equals_uint64 (cstart, 200); fail_unless_equals_uint64 (cstop, 200); /* exclusively cover boundary point */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 150, 250, &cstart, &cstop); fail_unless (res == TRUE); fail_unless_equals_uint64 (cstart, 200); fail_unless_equals_uint64 (cstop, 200); /* invalid start */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, -1, 200, &cstart, &cstop); fail_unless (res == FALSE); /* start outside */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 50, -1, &cstart, &cstop); fail_unless (res == TRUE); fail_unless_equals_uint64 (cstart, 200); fail_unless_equals_uint64 (cstop, 200); /* start on boundary point */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 200, -1, &cstart, &cstop); fail_unless (res == TRUE); fail_unless_equals_uint64 (cstart, 200); fail_unless_equals_uint64 (cstop, 200); /* start completely outside */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 250, -1, &cstart, &cstop); fail_unless (res == FALSE); /* seek relative to end */ gst_segment_do_seek (&segment, 1.0, GST_FORMAT_BYTES, GST_SEEK_FLAG_NONE, GST_SEEK_TYPE_END, -100, GST_SEEK_TYPE_END, -20, &update); fail_unless_equals_uint64 (segment.start, 100); fail_unless_equals_uint64 (segment.position, 100); fail_unless_equals_uint64 (segment.stop, 180); fail_unless (update == TRUE); check_times (&segment, 150, 150, 50); /* completely outside */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 0, 50, &cstart, &cstop); fail_unless (res == FALSE); /* touching lower bound */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 50, 100, &cstart, &cstop); fail_unless (res == FALSE); /* partially inside */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 50, 150, &cstart, &cstop); fail_unless (res == TRUE); fail_unless_equals_uint64 (cstart, 100); fail_unless_equals_uint64 (cstop, 150); /* inside, touching lower bound */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 100, 150, &cstart, &cstop); fail_unless (res == TRUE); fail_unless_equals_uint64 (cstart, 100); fail_unless_equals_uint64 (cstop, 150); /* completely inside */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 150, 170, &cstart, &cstop); fail_unless (res == TRUE); fail_unless_equals_uint64 (cstart, 150); fail_unless_equals_uint64 (cstop, 170); /* partially inside */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 150, 250, &cstart, &cstop); fail_unless (res == TRUE); fail_unless_equals_uint64 (cstart, 150); fail_unless_equals_uint64 (cstop, 180); /* invalid start */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, -1, 100, &cstart, &cstop); fail_unless (res == FALSE); /* start outside */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 50, -1, &cstart, &cstop); fail_unless (res == TRUE); fail_unless_equals_uint64 (cstart, 100); fail_unless_equals_uint64 (cstop, 180); /* start on lower bound */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 100, -1, &cstart, &cstop); fail_unless (res == TRUE); fail_unless_equals_uint64 (cstart, 100); fail_unless_equals_uint64 (cstop, 180); /* start inside */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 150, -1, &cstart, &cstop); fail_unless (res == TRUE); fail_unless_equals_uint64 (cstart, 150); fail_unless_equals_uint64 (cstop, 180); /* start outside on boundary */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 180, -1, &cstart, &cstop); fail_unless (res == FALSE); /* start completely outside */ res = gst_segment_clip (&segment, GST_FORMAT_BYTES, 250, -1, &cstart, &cstop); fail_unless (res == FALSE); } GST_END_TEST; GST_START_TEST (segment_seek_reverse) { GstSegment segment; gboolean update; gst_segment_init (&segment, GST_FORMAT_BYTES); segment.duration = 200; /* configure segment to stop 100 */ gst_segment_do_seek (&segment, -1.0, GST_FORMAT_BYTES, GST_SEEK_FLAG_NONE, GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_SET, 100, &update); fail_unless_equals_uint64 (segment.start, 0); fail_unless_equals_uint64 (segment.stop, 100); fail_unless_equals_uint64 (segment.time, 0); fail_unless_equals_uint64 (segment.position, 100); fail_unless (update == TRUE); check_times (&segment, 100, 100, 0); check_times (&segment, 50, 50, 50); check_times (&segment, 0, 0, 100); /* update */ gst_segment_do_seek (&segment, -1.0, GST_FORMAT_BYTES, GST_SEEK_FLAG_NONE, GST_SEEK_TYPE_SET, 10, GST_SEEK_TYPE_SET, 100 - 20, &update); fail_unless_equals_uint64 (segment.start, 10); fail_unless_equals_uint64 (segment.stop, 80); fail_unless_equals_uint64 (segment.time, 10); fail_unless_equals_uint64 (segment.position, 80); fail_unless (update == TRUE); check_times (&segment, 80, 80, 0); check_times (&segment, 40, 40, 40); check_times (&segment, 10, 10, 70); gst_segment_do_seek (&segment, -1.0, GST_FORMAT_BYTES, GST_SEEK_FLAG_NONE, GST_SEEK_TYPE_SET, 20, GST_SEEK_TYPE_NONE, 0, &update); fail_unless_equals_uint64 (segment.start, 20); fail_unless_equals_uint64 (segment.stop, 80); fail_unless_equals_uint64 (segment.time, 20); fail_unless_equals_uint64 (segment.position, 80); fail_unless (update == FALSE); check_times (&segment, 80, 80, 0); check_times (&segment, 20, 20, 60); } GST_END_TEST; /* mess with the segment structure in the bytes format */ GST_START_TEST (segment_seek_rate) { GstSegment segment; gboolean update; gst_segment_init (&segment, GST_FORMAT_BYTES); /* configure segment to rate 2.0 */ gst_segment_do_seek (&segment, 2.0, GST_FORMAT_BYTES, GST_SEEK_FLAG_NONE, GST_SEEK_TYPE_NONE, -1, GST_SEEK_TYPE_NONE, -1, &update); fail_unless (segment.format == GST_FORMAT_BYTES); fail_unless_equals_uint64 (segment.start, 0); fail_unless_equals_uint64 (segment.position, 0); fail_unless_equals_int64 (segment.stop, -1); fail_unless_equals_float (segment.rate, 2.0); fail_unless (update == FALSE); check_times (&segment, 50, 50, 25); /* set a real stop position, this must happen in bytes */ gst_segment_do_seek (&segment, 3.0, GST_FORMAT_BYTES, GST_SEEK_FLAG_NONE, GST_SEEK_TYPE_NONE, -1, GST_SEEK_TYPE_SET, 100, &update); fail_unless (segment.format == GST_FORMAT_BYTES); fail_unless_equals_uint64 (segment.start, 0); fail_unless_equals_uint64 (segment.stop, 100); fail_unless_equals_float (segment.rate, 3.0); /* no seek should happen, we just updated the stop position in forward * playback mode.*/ fail_unless (update == FALSE); check_times (&segment, 60, 60, 20); /* set some duration, stop -1 END seeks will now work with the * duration, if the formats match */ segment.duration = 200; /* seek to end with 0 should set the stop to the duration */ gst_segment_do_seek (&segment, 2.0, GST_FORMAT_BYTES, GST_SEEK_FLAG_NONE, GST_SEEK_TYPE_NONE, -1, GST_SEEK_TYPE_END, 0, &update); fail_unless_equals_uint64 (segment.stop, 200); fail_unless_equals_uint64 (segment.duration, 200); /* subtract 100 from the end */ gst_segment_do_seek (&segment, 2.0, GST_FORMAT_BYTES, GST_SEEK_FLAG_NONE, GST_SEEK_TYPE_NONE, -1, GST_SEEK_TYPE_END, -100, &update); fail_unless_equals_uint64 (segment.stop, 100); fail_unless_equals_uint64 (segment.duration, 200); /* add 100 to the duration, this should be clamped to the duration */ gst_segment_do_seek (&segment, 2.0, GST_FORMAT_BYTES, GST_SEEK_FLAG_NONE, GST_SEEK_TYPE_NONE, -1, GST_SEEK_TYPE_END, 100, &update); fail_unless_equals_uint64 (segment.stop, 200); fail_unless_equals_uint64 (segment.duration, 200); } GST_END_TEST; GST_START_TEST (segment_copy) { GstSegment *copy; GstSegment segment = { 0.0, }; /* this is a boxed type copy function, we support copying NULL */ fail_unless (gst_segment_copy (NULL) == NULL); gst_segment_init (&segment, GST_FORMAT_TIME); segment.rate = -1.0; segment.applied_rate = 1.0; segment.start = 0; segment.stop = 200; segment.time = 0; copy = gst_segment_copy (&segment); fail_unless (copy != NULL); /* we inited the struct on the stack to zeroes, so direct comparison should * be ok here despite the padding field and regardless of implementation */ fail_unless (memcmp (copy, &segment, sizeof (GstSegment)) == 0); gst_segment_free (copy); } GST_END_TEST; /* mess with the segment structure in the bytes format */ GST_START_TEST (segment_seek_noupdate) { GstSegment segment; gboolean update; gst_segment_init (&segment, GST_FORMAT_TIME); segment.start = 0; segment.position = 50; segment.stop = 200; segment.time = 0; /* doesn't change anything */ gst_segment_do_seek (&segment, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_NONE, GST_SEEK_TYPE_NONE, 0, GST_SEEK_TYPE_NONE, 0, &update); fail_unless (update == FALSE); fail_unless (segment.format == GST_FORMAT_TIME); fail_unless_equals_uint64 (segment.start, 0); fail_unless_equals_uint64 (segment.stop, 200); fail_unless_equals_uint64 (segment.time, 0); fail_unless_equals_uint64 (segment.position, 50); fail_unless_equals_uint64 (segment.base, 50); fail_unless_equals_uint64 (segment.offset, 50); gst_segment_do_seek (&segment, 2.0, GST_FORMAT_TIME, GST_SEEK_FLAG_NONE, GST_SEEK_TYPE_NONE, 0, GST_SEEK_TYPE_NONE, 0, &update); fail_unless (update == FALSE); fail_unless (segment.format == GST_FORMAT_TIME); fail_unless_equals_uint64 (segment.start, 0); fail_unless_equals_uint64 (segment.stop, 200); fail_unless_equals_uint64 (segment.time, 0); fail_unless_equals_uint64 (segment.position, 50); fail_unless_equals_uint64 (segment.base, 50); fail_unless_equals_uint64 (segment.offset, 50); gst_segment_do_seek (&segment, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_NONE, 0, GST_SEEK_TYPE_NONE, 0, &update); fail_unless (update == FALSE); fail_unless (segment.format == GST_FORMAT_TIME); fail_unless_equals_uint64 (segment.start, 0); fail_unless_equals_uint64 (segment.stop, 200); fail_unless_equals_uint64 (segment.time, 0); fail_unless_equals_uint64 (segment.position, 50); fail_unless_equals_uint64 (segment.base, 0); fail_unless_equals_uint64 (segment.offset, 50); /* FALSE should be returned when GST_SEEK_FLAG_INSTANT_RATE_CHANGE */ fail_unless (gst_segment_do_seek (&segment, 1.5, GST_FORMAT_TIME, GST_SEEK_FLAG_INSTANT_RATE_CHANGE, GST_SEEK_TYPE_NONE, 0, GST_SEEK_TYPE_NONE, 0, NULL) == FALSE); fail_unless (segment.format == GST_FORMAT_TIME); fail_unless_equals_uint64 (segment.start, 0); fail_unless_equals_uint64 (segment.stop, 200); fail_unless_equals_uint64 (segment.time, 0); fail_unless_equals_uint64 (segment.position, 50); fail_unless_equals_uint64 (segment.base, 0); fail_unless_equals_uint64 (segment.offset, 50); } GST_END_TEST; GST_START_TEST (segment_offset) { GstSegment segment; gst_segment_init (&segment, GST_FORMAT_TIME); segment.start = 0; segment.position = 50; segment.stop = 200; segment.time = 0; check_times (&segment, 20, 20, 20); check_times (&segment, 220, -1, -1); fail_unless (gst_segment_offset_running_time (&segment, GST_FORMAT_TIME, 0) == TRUE); fail_unless_equals_uint64 (segment.start, 0); fail_unless_equals_uint64 (segment.stop, 200); fail_unless_equals_uint64 (segment.time, 0); fail_unless_equals_uint64 (segment.position, 50); fail_unless_equals_uint64 (segment.base, 0); fail_unless_equals_uint64 (segment.offset, 0); check_times (&segment, 20, 20, 20); fail_unless (gst_segment_offset_running_time (&segment, GST_FORMAT_TIME, 100) == TRUE); fail_unless_equals_uint64 (segment.start, 0); fail_unless_equals_uint64 (segment.stop, 200); fail_unless_equals_uint64 (segment.time, 0); fail_unless_equals_uint64 (segment.position, 50); fail_unless_equals_uint64 (segment.base, 100); fail_unless_equals_uint64 (segment.offset, 0); check_times (&segment, 20, 20, 120); fail_unless (gst_segment_offset_running_time (&segment, GST_FORMAT_TIME, -50) == TRUE); fail_unless_equals_uint64 (segment.start, 0); fail_unless_equals_uint64 (segment.stop, 200); fail_unless_equals_uint64 (segment.time, 0); fail_unless_equals_uint64 (segment.position, 50); fail_unless_equals_uint64 (segment.base, 50); fail_unless_equals_uint64 (segment.offset, 0); check_times (&segment, 20, 20, 70); fail_unless (gst_segment_offset_running_time (&segment, GST_FORMAT_TIME, -100) == TRUE); fail_unless_equals_uint64 (segment.start, 0); fail_unless_equals_uint64 (segment.stop, 200); fail_unless_equals_uint64 (segment.time, 0); fail_unless_equals_uint64 (segment.position, 50); fail_unless_equals_uint64 (segment.base, 0); fail_unless_equals_uint64 (segment.offset, 50); check_times (&segment, 20, 20, -1); check_times (&segment, 200, 200, 150); /* can go negative */ fail_unless (gst_segment_offset_running_time (&segment, GST_FORMAT_TIME, -151) == FALSE); fail_unless_equals_uint64 (segment.start, 0); fail_unless_equals_uint64 (segment.stop, 200); fail_unless_equals_uint64 (segment.time, 0); fail_unless_equals_uint64 (segment.position, 50); fail_unless_equals_uint64 (segment.base, 0); fail_unless_equals_uint64 (segment.offset, 50); check_times (&segment, 100, 100, 50); check_times (&segment, 200, 200, 150); fail_unless (gst_segment_offset_running_time (&segment, GST_FORMAT_TIME, -150) == TRUE); fail_unless_equals_uint64 (segment.start, 0); fail_unless_equals_uint64 (segment.stop, 200); fail_unless_equals_uint64 (segment.time, 0); fail_unless_equals_uint64 (segment.position, 50); fail_unless_equals_uint64 (segment.base, 0); fail_unless_equals_uint64 (segment.offset, 200); check_times (&segment, 200, 200, 0); gst_segment_init (&segment, GST_FORMAT_TIME); segment.start = 20; segment.position = 50; segment.stop = 220; segment.time = 0; check_times (&segment, 40, 20, 20); check_times (&segment, 240, -1, -1); fail_unless (gst_segment_offset_running_time (&segment, GST_FORMAT_TIME, 0) == TRUE); fail_unless_equals_uint64 (segment.start, 20); fail_unless_equals_uint64 (segment.stop, 220); fail_unless_equals_uint64 (segment.time, 0); fail_unless_equals_uint64 (segment.position, 50); fail_unless_equals_uint64 (segment.base, 0); fail_unless_equals_uint64 (segment.offset, 0); check_times (&segment, 40, 20, 20); fail_unless (gst_segment_offset_running_time (&segment, GST_FORMAT_TIME, 100) == TRUE); fail_unless_equals_uint64 (segment.start, 20); fail_unless_equals_uint64 (segment.stop, 220); fail_unless_equals_uint64 (segment.time, 0); fail_unless_equals_uint64 (segment.position, 50); fail_unless_equals_uint64 (segment.base, 100); fail_unless_equals_uint64 (segment.offset, 0); check_times (&segment, 40, 20, 120); fail_unless (gst_segment_offset_running_time (&segment, GST_FORMAT_TIME, -50) == TRUE); fail_unless_equals_uint64 (segment.start, 20); fail_unless_equals_uint64 (segment.stop, 220); fail_unless_equals_uint64 (segment.time, 0); fail_unless_equals_uint64 (segment.position, 50); fail_unless_equals_uint64 (segment.base, 50); fail_unless_equals_uint64 (segment.offset, 0); check_times (&segment, 40, 20, 70); fail_unless (gst_segment_offset_running_time (&segment, GST_FORMAT_TIME, -100) == TRUE); fail_unless_equals_uint64 (segment.start, 20); fail_unless_equals_uint64 (segment.stop, 220); fail_unless_equals_uint64 (segment.time, 0); fail_unless_equals_uint64 (segment.position, 50); fail_unless_equals_uint64 (segment.base, 0); fail_unless_equals_uint64 (segment.offset, 50); check_times (&segment, 40, 20, -1); check_times (&segment, 220, 200, 150); } GST_END_TEST; GST_START_TEST (segment_full) { GstSegment segment; guint64 rt, pos; gst_segment_init (&segment, GST_FORMAT_TIME); segment.start = 50; segment.position = 150; segment.stop = 200; segment.time = 0; check_times (&segment, 100, 50, 50); check_times (&segment, 220, -1, -1); fail_unless (gst_segment_to_running_time_full (&segment, GST_FORMAT_TIME, 50, &rt) == 1); fail_unless (rt == 0); fail_unless (gst_segment_position_from_running_time_full (&segment, GST_FORMAT_TIME, rt, &pos) == 1); fail_unless (pos == 50); fail_unless (gst_segment_to_running_time_full (&segment, GST_FORMAT_TIME, 200, &rt) == 1); fail_unless (rt == 150); fail_unless (gst_segment_position_from_running_time_full (&segment, GST_FORMAT_TIME, rt, &pos) == 1); fail_unless (pos == 200); fail_unless (!gst_segment_clip (&segment, GST_FORMAT_TIME, 40, 40, NULL, NULL)); fail_unless (gst_segment_to_running_time_full (&segment, GST_FORMAT_TIME, 40, &rt) == -1); fail_unless (!gst_segment_clip (&segment, GST_FORMAT_TIME, 49, 49, NULL, NULL)); fail_unless (gst_segment_to_running_time_full (&segment, GST_FORMAT_TIME, 49, &rt) == -1); fail_unless (!gst_segment_clip (&segment, GST_FORMAT_TIME, 201, 201, NULL, NULL)); fail_unless (gst_segment_to_running_time_full (&segment, GST_FORMAT_TIME, 201, &rt) == 1); fail_unless (gst_segment_position_from_running_time_full (&segment, GST_FORMAT_TIME, rt, &pos) == 1); fail_unless (pos == 201); fail_unless (gst_segment_offset_running_time (&segment, GST_FORMAT_TIME, -50) == TRUE); fail_unless (segment.offset == 50); fail_unless (gst_segment_to_running_time_full (&segment, GST_FORMAT_TIME, 50, &rt) == -1); GST_DEBUG ("%" G_GUINT64_FORMAT, rt); fail_unless (rt == 50); /* Forward jump will be applied directly to the base field */ fail_unless (gst_segment_offset_running_time (&segment, GST_FORMAT_TIME, 50) == TRUE); fail_unless (segment.base == 50); /* Now there's enough base, a negative offset should come from there */ fail_unless (gst_segment_offset_running_time (&segment, GST_FORMAT_TIME, -50) == TRUE); fail_unless (segment.base == 0); segment.start = 50; segment.stop = 300; segment.position = 150; segment.time = 0; segment.offset = 0; gst_segment_set_running_time (&segment, GST_FORMAT_TIME, 100); fail_unless_equals_int (segment.base, 100); fail_unless (gst_segment_position_from_running_time_full (&segment, GST_FORMAT_TIME, 70, &pos) == 1); fail_unless_equals_int (pos, 120); fail_unless (gst_segment_position_from_running_time_full (&segment, GST_FORMAT_TIME, 140, &pos) == 1); fail_unless_equals_int (pos, 190); /* Test a non-1.0 rate that lands right before the segment, but still +ve */ segment.rate = 2.0; segment.start = 100; segment.offset = 0; segment.stop = 500; segment.position = 40; segment.base = 150; segment.time = 10000; fail_unless (gst_segment_position_from_running_time_full (&segment, GST_FORMAT_TIME, 140, &pos) == 1); fail_unless (pos == 80); /* And now one that should give a position < 0 */ fail_unless (gst_segment_position_from_running_time_full (&segment, GST_FORMAT_TIME, 0, &pos) == -1); fail_unless (pos == 200); /* Test a non-1.0 negative rate that lands right after the (reversed) segment, but still +ve position */ segment.rate = -2.0; segment.start = 100; segment.offset = 0; segment.stop = 500; segment.position = 150; segment.base = 133; segment.time = 10000; fail_unless (gst_segment_position_from_running_time_full (&segment, GST_FORMAT_TIME, 200 + 133 + 20, &pos) == 1); fail_unless (pos == 60); /* And now one that should give a position < 0, reported as a negated value */ fail_unless (gst_segment_position_from_running_time_full (&segment, GST_FORMAT_TIME, 200 + 133 + 70, &pos) == -1); fail_unless (pos == 40); /* Test gst_segment_position_from_running_time_full() with offsets */ segment.rate = 2.0; segment.start = 100; segment.offset = 100; segment.stop = 500; segment.position = 150; segment.base = 175; segment.time = 10000; /* Position before the segment but >= 0 */ fail_unless (gst_segment_position_from_running_time_full (&segment, GST_FORMAT_TIME, 75, &pos) == 1); fail_unless (pos == 0); fail_unless (gst_segment_position_from_running_time (&segment, GST_FORMAT_TIME, 75) == -1); /* Position before the segment and < 0 */ fail_unless (gst_segment_position_from_running_time_full (&segment, GST_FORMAT_TIME, 65, &pos) == -1); fail_unless (pos == 20); /* Actually -20 */ fail_unless (gst_segment_position_from_running_time (&segment, GST_FORMAT_TIME, 65) == -1); /* After the segment */ fail_unless (gst_segment_position_from_running_time_full (&segment, GST_FORMAT_TIME, 175 + 150 + 10, &pos) == 1); fail_unless (pos == 520); fail_unless (gst_segment_position_from_running_time (&segment, GST_FORMAT_TIME, 175 + 150 + 10) == -1); /* And with negative rate, so the segment is reversed */ segment.rate = -2.0; /* Before the segment */ fail_unless (gst_segment_position_from_running_time_full (&segment, GST_FORMAT_TIME, 75, &pos) == 1); fail_unless (pos == 600); fail_unless (gst_segment_position_from_running_time (&segment, GST_FORMAT_TIME, 75) == -1); /* Position after the segment and < 0 */ fail_unless (gst_segment_position_from_running_time_full (&segment, GST_FORMAT_TIME, 400, &pos) == -1); fail_unless (pos == 50); /* Actually -50 */ fail_unless (gst_segment_position_from_running_time (&segment, GST_FORMAT_TIME, 400) == -1); /* Position after the segment and >= 0 */ fail_unless (gst_segment_position_from_running_time_full (&segment, GST_FORMAT_TIME, 325 + 10, &pos) == 1); fail_unless (pos == 80); fail_unless (gst_segment_position_from_running_time (&segment, GST_FORMAT_TIME, 325 + 10) == -1); /* Big offset can clip away an entire reversed segment and produce a negative position anyway */ segment.offset = 1000; fail_unless (gst_segment_position_from_running_time_full (&segment, GST_FORMAT_TIME, 75, &pos) == -1); fail_unless (pos == 300); /* Actually -300 */ /* Test for running time conversion with stop == -1, where * calculations should use the duration instead */ segment.rate = -2.0; segment.start = 100; segment.offset = 0; segment.stop = -1; segment.duration = 200; segment.position = 40; segment.base = 100; segment.time = 10000; fail_unless (gst_segment_to_running_time_full (&segment, GST_FORMAT_TIME, 150, &rt) == 1); fail_unless (rt == 175); } GST_END_TEST; GST_START_TEST (segment_stream_time_full) { GstSegment segment; guint64 st, pos; gst_segment_init (&segment, GST_FORMAT_TIME); segment.start = 50; segment.stop = 200; segment.time = 30; segment.position = 0; fail_unless (gst_segment_to_stream_time_full (&segment, GST_FORMAT_TIME, 0, &st) == -1); fail_unless_equals_int (st, 20); fail_unless (gst_segment_to_stream_time_full (&segment, GST_FORMAT_TIME, 20, &st) == 1); fail_unless_equals_int (st, 0); fail_unless (gst_segment_position_from_stream_time_full (&segment, GST_FORMAT_TIME, 0, &pos) == 1); fail_unless_equals_int (pos, 20); fail_unless (gst_segment_to_stream_time_full (&segment, GST_FORMAT_TIME, 10, &st) == -1); fail_unless_equals_int (st, 10); fail_unless (gst_segment_to_stream_time_full (&segment, GST_FORMAT_TIME, 40, &st) == 1); fail_unless_equals_int (st, 20); fail_unless (gst_segment_position_from_stream_time_full (&segment, GST_FORMAT_TIME, st, &pos) == 1); fail_unless_equals_int (pos, 40); segment.time = 100; fail_unless (gst_segment_position_from_stream_time_full (&segment, GST_FORMAT_TIME, 40, &pos) == -1); fail_unless_equals_int (pos, 10); fail_unless (gst_segment_position_from_stream_time_full (&segment, GST_FORMAT_TIME, 60, &pos) == 1); fail_unless_equals_int (pos, 10); segment.start = 50; segment.position = 150; segment.stop = 200; segment.time = 0; segment.applied_rate = -1; segment.rate = -1; fail_unless (gst_segment_to_stream_time_full (&segment, GST_FORMAT_TIME, 0, &st) == 1); fail_unless_equals_int (st, 200); fail_unless (gst_segment_position_from_stream_time_full (&segment, GST_FORMAT_TIME, 200, &pos) == 1); fail_unless_equals_int (pos, 0); fail_unless (gst_segment_to_stream_time_full (&segment, GST_FORMAT_TIME, 250, &st) == -1); fail_unless_equals_int (st, 50); fail_unless (gst_segment_position_from_stream_time_full (&segment, GST_FORMAT_TIME, 200, &pos) == 1); fail_unless_equals_int (pos, 0); fail_unless (gst_segment_position_from_stream_time_full (&segment, GST_FORMAT_TIME, 250, &pos) == -1); fail_unless_equals_int (pos, 50); segment.time = 70; fail_unless (gst_segment_to_stream_time_full (&segment, GST_FORMAT_TIME, 250, &st) == 1); fail_unless_equals_int (st, 20); fail_unless (gst_segment_position_from_stream_time_full (&segment, GST_FORMAT_TIME, 50, &pos) == 1); fail_unless_equals_int (pos, 220); fail_unless (gst_segment_position_from_stream_time_full (&segment, GST_FORMAT_TIME, 90, &pos) == 1); fail_unless_equals_int (pos, 180); segment.stop = 60; fail_unless (gst_segment_position_from_stream_time_full (&segment, GST_FORMAT_TIME, 5, &pos) == 1); fail_unless_equals_int (pos, 125); } GST_END_TEST; GST_START_TEST (segment_negative_rate) { GstSegment segment; gst_segment_init (&segment, GST_FORMAT_TIME); segment.start = 50; segment.position = 150; segment.stop = 200; segment.time = 0; segment.applied_rate = -1; segment.rate = -1; /* somewhere in the middle */ check_times (&segment, 100, 100, 100); /* after stop */ check_times (&segment, 220, -1, -1); /* before start */ check_times (&segment, 10, -1, -1); /* at segment start */ check_times (&segment, 50, 150, 150); /* another place in the middle */ check_times (&segment, 150, 50, 50); /* at segment stop */ check_times (&segment, 200, 0, 0); segment.time = 100; segment.base = 100; /* somewhere in the middle */ check_times (&segment, 100, 200, 200); /* at segment start */ check_times (&segment, 50, 250, 250); /* another place in the middle */ check_times (&segment, 150, 150, 150); /* at segment stop */ check_times (&segment, 200, 100, 100); } GST_END_TEST; GST_START_TEST (segment_negative_applied_rate) { GstSegment segment; gst_segment_init (&segment, GST_FORMAT_TIME); segment.start = 50; segment.position = 150; segment.stop = 200; segment.time = 0; segment.applied_rate = -1; segment.rate = 1; /* somewhere in the middle */ check_times (&segment, 100, 100, 50); /* after stop */ check_times (&segment, 220, -1, -1); /* before start */ check_times (&segment, 10, -1, -1); /* at segment start */ check_times (&segment, 50, 150, 0); /* another place in the middle */ check_times (&segment, 150, 50, 100); /* at segment stop */ check_times (&segment, 200, 0, 150); segment.time = 100; segment.base = 100; /* somewhere in the middle */ check_times (&segment, 100, 200, 150); /* at segment start */ check_times (&segment, 50, 250, 100); /* another place in the middle */ check_times (&segment, 150, 150, 200); /* at segment stop */ check_times (&segment, 200, 100, 250); } GST_END_TEST; static Suite * gst_segment_suite (void) { Suite *s = suite_create ("GstSegment"); TCase *tc_chain = tcase_create ("segments"); tcase_set_timeout (tc_chain, 20); suite_add_tcase (s, tc_chain); tcase_add_test (tc_chain, segment_seek_nosize); tcase_add_test (tc_chain, segment_seek_size); tcase_add_test (tc_chain, segment_seek_reverse); tcase_add_test (tc_chain, segment_seek_rate); tcase_add_test (tc_chain, segment_copy); tcase_add_test (tc_chain, segment_seek_noupdate); tcase_add_test (tc_chain, segment_offset); tcase_add_test (tc_chain, segment_full); tcase_add_test (tc_chain, segment_negative_rate); tcase_add_test (tc_chain, segment_negative_applied_rate); tcase_add_test (tc_chain, segment_stream_time_full); return s; } GST_CHECK_MAIN (gst_segment);