Blame tests/check/pipelines/theoraenc.c

Packit 0652a1
/* GStreamer
Packit 0652a1
 *
Packit 0652a1
 * unit test for theoraenc
Packit 0652a1
 *
Packit 0652a1
 * Copyright (C) 2006 Andy Wingo <wingo at pobox.com>
Packit 0652a1
 *
Packit 0652a1
 * This library is free software; you can redistribute it and/or
Packit 0652a1
 * modify it under the terms of the GNU Library General Public
Packit 0652a1
 * License as published by the Free Software Foundation; either
Packit 0652a1
 * version 2 of the License, or (at your option) any later version.
Packit 0652a1
 *
Packit 0652a1
 * This library is distributed in the hope that it will be useful,
Packit 0652a1
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 0652a1
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 0652a1
 * Library General Public License for more details.
Packit 0652a1
 *
Packit 0652a1
 * You should have received a copy of the GNU Library General Public
Packit 0652a1
 * License along with this library; if not, write to the
Packit 0652a1
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
Packit 0652a1
 * Boston, MA 02110-1301, USA.
Packit 0652a1
 */
Packit 0652a1
#ifdef HAVE_CONFIG_H
Packit 0652a1
#include "config.h"
Packit 0652a1
#endif
Packit 0652a1
Packit 0652a1
#include <gst/check/gstcheck.h>
Packit 0652a1
#include <gst/check/gstbufferstraw.h>
Packit 0652a1
Packit 0652a1
#include <theora/theora.h>
Packit 0652a1
Packit 0652a1
#ifndef GST_DISABLE_PARSE
Packit 0652a1
Packit 0652a1
#define TIMESTAMP_OFFSET G_GINT64_CONSTANT(3249870963)
Packit 0652a1
#define FRAMERATE 10
Packit 0652a1
Packit 0652a1
/* I know all of these have a shift of 6 bits */
Packit 0652a1
#define GRANULEPOS_SHIFT 6
Packit 0652a1
Packit 0652a1
Packit 0652a1
#define check_buffer_is_header(buffer,is_header) \
Packit 0652a1
  fail_unless (GST_BUFFER_FLAG_IS_SET (buffer,   \
Packit 0652a1
          GST_BUFFER_FLAG_HEADER) == is_header, \
Packit 0652a1
      "GST_BUFFER_IN_CAPS is set to %d but expected %d", \
Packit 0652a1
      GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_HEADER), is_header)
Packit 0652a1
Packit 0652a1
#define check_buffer_timestamp(buffer,timestamp) \
Packit 0652a1
  fail_unless (GST_BUFFER_TIMESTAMP (buffer) == timestamp, \
Packit 0652a1
      "expected timestamp %" GST_TIME_FORMAT \
Packit 0652a1
      ", but got timestamp %" GST_TIME_FORMAT, \
Packit 0652a1
      GST_TIME_ARGS (timestamp), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)))
Packit 0652a1
Packit 0652a1
#define check_buffer_duration(buffer,duration) \
Packit 0652a1
  fail_unless (GST_BUFFER_DURATION (buffer) == duration, \
Packit 0652a1
      "expected duration %" GST_TIME_FORMAT \
Packit 0652a1
      ", but got duration %" GST_TIME_FORMAT, \
Packit 0652a1
      GST_TIME_ARGS (duration), GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)))
Packit 0652a1
Packit 0652a1
static gboolean old_libtheora;
Packit 0652a1
Packit 0652a1
static void
Packit 0652a1
check_libtheora (void)
Packit 0652a1
{
Packit 0652a1
  old_libtheora = (theora_version_number () <= 0x00030200);
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
static void
Packit 0652a1
check_buffer_granulepos (GstBuffer * buffer, gint64 granulepos)
Packit 0652a1
{
Packit 0652a1
  GstClockTime clocktime;
Packit 0652a1
  int framecount;
Packit 0652a1
Packit 0652a1
  /* With old versions of libtheora, the granulepos represented the
Packit 0652a1
   * start time, not end time. Adapt for that. */
Packit 0652a1
  if (old_libtheora) {
Packit 0652a1
    if (granulepos >> GRANULEPOS_SHIFT)
Packit 0652a1
      granulepos -= 1 << GRANULEPOS_SHIFT;
Packit 0652a1
    else if (granulepos)
Packit 0652a1
      granulepos -= 1;
Packit 0652a1
  }
Packit 0652a1
Packit 0652a1
  fail_unless (GST_BUFFER_OFFSET_END (buffer) == granulepos,
Packit 0652a1
      "expected granulepos %" G_GUINT64_FORMAT
Packit 0652a1
      ", but got granulepos %" G_GUINT64_FORMAT,
Packit 0652a1
      granulepos, GST_BUFFER_OFFSET_END (buffer));
Packit 0652a1
Packit 0652a1
  /* contrary to what we record as TIMESTAMP, we can use OFFSET to check
Packit 0652a1
   * the granulepos correctly here */
Packit 0652a1
  framecount = GST_BUFFER_OFFSET_END (buffer);
Packit 0652a1
  framecount = granulepos >> GRANULEPOS_SHIFT;
Packit 0652a1
  framecount += granulepos & ((1 << GRANULEPOS_SHIFT) - 1);
Packit 0652a1
  clocktime = gst_util_uint64_scale (framecount, GST_SECOND, FRAMERATE);
Packit 0652a1
Packit 0652a1
  fail_unless (clocktime == GST_BUFFER_OFFSET (buffer),
Packit 0652a1
      "expected OFFSET set to clocktime %" GST_TIME_FORMAT
Packit 0652a1
      ", but got %" GST_TIME_FORMAT,
Packit 0652a1
      GST_TIME_ARGS (clocktime), GST_TIME_ARGS (GST_BUFFER_OFFSET (buffer)));
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
/* this check is here to check that the granulepos we derive from the
Packit 0652a1
   timestamp is about correct. This is "about correct" because you can't
Packit 0652a1
   precisely go from timestamp to granulepos due to the downward-rounding
Packit 0652a1
   characteristics of gst_util_uint64_scale, so you check if granulepos is
Packit 0652a1
   equal to the number, or the number plus one. */
Packit 0652a1
/* should be from_endtime, but theora's granulepos mapping is "special" */
Packit 0652a1
static void
Packit 0652a1
check_buffer_granulepos_from_starttime (GstBuffer * buffer,
Packit 0652a1
    GstClockTime starttime)
Packit 0652a1
{
Packit 0652a1
  gint64 granulepos, expected, framecount;
Packit 0652a1
Packit 0652a1
  granulepos = GST_BUFFER_OFFSET_END (buffer);
Packit 0652a1
  /* Now convert to 'granulepos for start time', depending on libtheora 
Packit 0652a1
   * version */
Packit 0652a1
  if (!old_libtheora) {
Packit 0652a1
    if (granulepos & ((1 << GRANULEPOS_SHIFT) - 1))
Packit 0652a1
      granulepos -= 1;
Packit 0652a1
    else if (granulepos)
Packit 0652a1
      granulepos -= 1 << GRANULEPOS_SHIFT;
Packit 0652a1
  }
Packit 0652a1
Packit 0652a1
  framecount = granulepos >> GRANULEPOS_SHIFT;
Packit 0652a1
  framecount += granulepos & ((1 << GRANULEPOS_SHIFT) - 1);
Packit 0652a1
  expected = gst_util_uint64_scale (starttime, FRAMERATE, GST_SECOND);
Packit 0652a1
Packit 0652a1
  fail_unless (framecount == expected || framecount == expected + 1,
Packit 0652a1
      "expected frame count %" G_GUINT64_FORMAT
Packit 0652a1
      " or %" G_GUINT64_FORMAT
Packit 0652a1
      ", but got frame count %" G_GUINT64_FORMAT,
Packit 0652a1
      expected, expected + 1, framecount);
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
GST_START_TEST (test_granulepos_offset)
Packit 0652a1
{
Packit 0652a1
  GstElement *bin;
Packit 0652a1
  GstPad *pad;
Packit 0652a1
  gchar *pipe_str;
Packit 0652a1
  GstBuffer *buffer;
Packit 0652a1
  GError *error = NULL;
Packit 0652a1
Packit 0652a1
  pipe_str = g_strdup_printf ("videotestsrc timestamp-offset=%" G_GUINT64_FORMAT
Packit 0652a1
      " num-buffers=10 ! video/x-raw,format=(string)I420,framerate=10/1"
Packit 0652a1
      " ! theoraenc ! fakesink name=fs0", TIMESTAMP_OFFSET);
Packit 0652a1
Packit 0652a1
  bin = gst_parse_launch (pipe_str, &error);
Packit 0652a1
  fail_unless (bin != NULL, "Error parsing pipeline: %s",
Packit 0652a1
      error ? error->message : "(invalid error)");
Packit 0652a1
  g_free (pipe_str);
Packit 0652a1
Packit 0652a1
  /* get the pad */
Packit 0652a1
  {
Packit 0652a1
    GstElement *sink = gst_bin_get_by_name (GST_BIN (bin), "fs0");
Packit 0652a1
Packit 0652a1
    fail_unless (sink != NULL, "Could not get fakesink out of bin");
Packit 0652a1
    pad = gst_element_get_static_pad (sink, "sink");
Packit 0652a1
    fail_unless (pad != NULL, "Could not get pad out of fakesink");
Packit 0652a1
    gst_object_unref (sink);
Packit 0652a1
  }
Packit 0652a1
Packit 0652a1
  gst_buffer_straw_start_pipeline (bin, pad);
Packit 0652a1
Packit 0652a1
  /* header packets should have timestamp == NONE, granulepos 0, IN_CAPS */
Packit 0652a1
  buffer = gst_buffer_straw_get_buffer (bin, pad);
Packit 0652a1
  check_buffer_timestamp (buffer, GST_CLOCK_TIME_NONE);
Packit 0652a1
  check_buffer_duration (buffer, GST_CLOCK_TIME_NONE);
Packit 0652a1
  check_buffer_granulepos (buffer, 0);
Packit 0652a1
  check_buffer_is_header (buffer, TRUE);
Packit 0652a1
  gst_buffer_unref (buffer);
Packit 0652a1
Packit 0652a1
  buffer = gst_buffer_straw_get_buffer (bin, pad);
Packit 0652a1
  check_buffer_timestamp (buffer, GST_CLOCK_TIME_NONE);
Packit 0652a1
  check_buffer_duration (buffer, GST_CLOCK_TIME_NONE);
Packit 0652a1
  check_buffer_granulepos (buffer, 0);
Packit 0652a1
  check_buffer_is_header (buffer, TRUE);
Packit 0652a1
  gst_buffer_unref (buffer);
Packit 0652a1
Packit 0652a1
  buffer = gst_buffer_straw_get_buffer (bin, pad);
Packit 0652a1
  check_buffer_timestamp (buffer, GST_CLOCK_TIME_NONE);
Packit 0652a1
  check_buffer_duration (buffer, GST_CLOCK_TIME_NONE);
Packit 0652a1
  check_buffer_granulepos (buffer, 0);
Packit 0652a1
  check_buffer_is_header (buffer, TRUE);
Packit 0652a1
  gst_buffer_unref (buffer);
Packit 0652a1
Packit 0652a1
  {
Packit 0652a1
    GstClockTime next_timestamp;
Packit 0652a1
    gint64 last_granulepos;
Packit 0652a1
Packit 0652a1
    /* first buffer should have timestamp of TIMESTAMP_OFFSET, granulepos to
Packit 0652a1
     * match the timestamp of the end of the last sample in the output buffer.
Packit 0652a1
     * Note that one cannot go timestamp->granulepos->timestamp and get the
Packit 0652a1
     * same value due to loss of precision with granulepos. theoraenc does
Packit 0652a1
     * take care to timestamp correctly based on the offset of the input data
Packit 0652a1
     * however, so it does do sub-granulepos timestamping. */
Packit 0652a1
    buffer = gst_buffer_straw_get_buffer (bin, pad);
Packit 0652a1
    last_granulepos = GST_BUFFER_OFFSET_END (buffer);
Packit 0652a1
    check_buffer_timestamp (buffer, TIMESTAMP_OFFSET);
Packit 0652a1
    /* don't really have a good way of checking duration... */
Packit 0652a1
    check_buffer_granulepos_from_starttime (buffer, TIMESTAMP_OFFSET);
Packit 0652a1
    check_buffer_is_header (buffer, FALSE);
Packit 0652a1
Packit 0652a1
    next_timestamp = TIMESTAMP_OFFSET + GST_BUFFER_DURATION (buffer);
Packit 0652a1
Packit 0652a1
    gst_buffer_unref (buffer);
Packit 0652a1
Packit 0652a1
    /* check continuity with the next buffer */
Packit 0652a1
    buffer = gst_buffer_straw_get_buffer (bin, pad);
Packit 0652a1
    check_buffer_timestamp (buffer, next_timestamp);
Packit 0652a1
    check_buffer_duration (buffer,
Packit 0652a1
        gst_util_uint64_scale (GST_BUFFER_OFFSET_END (buffer), GST_SECOND,
Packit 0652a1
            FRAMERATE)
Packit 0652a1
        - gst_util_uint64_scale (last_granulepos, GST_SECOND, FRAMERATE));
Packit 0652a1
    check_buffer_granulepos_from_starttime (buffer, next_timestamp);
Packit 0652a1
    check_buffer_is_header (buffer, FALSE);
Packit 0652a1
Packit 0652a1
    gst_buffer_unref (buffer);
Packit 0652a1
  }
Packit 0652a1
Packit 0652a1
  gst_buffer_straw_stop_pipeline (bin, pad);
Packit 0652a1
Packit 0652a1
  gst_object_unref (pad);
Packit 0652a1
  gst_object_unref (bin);
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
GST_END_TEST;
Packit 0652a1
Packit 0652a1
GST_START_TEST (test_continuity)
Packit 0652a1
{
Packit 0652a1
  GstElement *bin;
Packit 0652a1
  GstPad *pad;
Packit 0652a1
  gchar *pipe_str;
Packit 0652a1
  GstBuffer *buffer;
Packit 0652a1
  GError *error = NULL;
Packit 0652a1
Packit 0652a1
  pipe_str = g_strdup_printf ("videotestsrc num-buffers=10"
Packit 0652a1
      " ! video/x-raw,format=(string)I420,framerate=10/1"
Packit 0652a1
      " ! theoraenc ! fakesink name=fs0");
Packit 0652a1
Packit 0652a1
  bin = gst_parse_launch (pipe_str, &error);
Packit 0652a1
  fail_unless (bin != NULL, "Error parsing pipeline: %s",
Packit 0652a1
      error ? error->message : "(invalid error)");
Packit 0652a1
  g_free (pipe_str);
Packit 0652a1
Packit 0652a1
  /* get the pad */
Packit 0652a1
  {
Packit 0652a1
    GstElement *sink = gst_bin_get_by_name (GST_BIN (bin), "fs0");
Packit 0652a1
Packit 0652a1
    fail_unless (sink != NULL, "Could not get fakesink out of bin");
Packit 0652a1
    pad = gst_element_get_static_pad (sink, "sink");
Packit 0652a1
    fail_unless (pad != NULL, "Could not get pad out of fakesink");
Packit 0652a1
    gst_object_unref (sink);
Packit 0652a1
  }
Packit 0652a1
Packit 0652a1
  gst_buffer_straw_start_pipeline (bin, pad);
Packit 0652a1
Packit 0652a1
  /* header packets should have timestamp == NONE, granulepos 0 */
Packit 0652a1
  buffer = gst_buffer_straw_get_buffer (bin, pad);
Packit 0652a1
  check_buffer_timestamp (buffer, GST_CLOCK_TIME_NONE);
Packit 0652a1
  check_buffer_duration (buffer, GST_CLOCK_TIME_NONE);
Packit 0652a1
  check_buffer_granulepos (buffer, 0);
Packit 0652a1
  check_buffer_is_header (buffer, TRUE);
Packit 0652a1
  gst_buffer_unref (buffer);
Packit 0652a1
Packit 0652a1
  buffer = gst_buffer_straw_get_buffer (bin, pad);
Packit 0652a1
  check_buffer_timestamp (buffer, GST_CLOCK_TIME_NONE);
Packit 0652a1
  check_buffer_duration (buffer, GST_CLOCK_TIME_NONE);
Packit 0652a1
  check_buffer_granulepos (buffer, 0);
Packit 0652a1
  check_buffer_is_header (buffer, TRUE);
Packit 0652a1
  gst_buffer_unref (buffer);
Packit 0652a1
Packit 0652a1
  buffer = gst_buffer_straw_get_buffer (bin, pad);
Packit 0652a1
  check_buffer_timestamp (buffer, GST_CLOCK_TIME_NONE);
Packit 0652a1
  check_buffer_duration (buffer, GST_CLOCK_TIME_NONE);
Packit 0652a1
  check_buffer_granulepos (buffer, 0);
Packit 0652a1
  check_buffer_is_header (buffer, TRUE);
Packit 0652a1
  gst_buffer_unref (buffer);
Packit 0652a1
Packit 0652a1
  {
Packit 0652a1
    GstClockTime next_timestamp;
Packit 0652a1
Packit 0652a1
    /* first buffer should have timestamp of TIMESTAMP_OFFSET, granulepos to
Packit 0652a1
     * match the timestamp of the end of the last sample in the output buffer.
Packit 0652a1
     * Note that one cannot go timestamp->granulepos->timestamp and get the
Packit 0652a1
     * same value due to loss of precision with granulepos. theoraenc does
Packit 0652a1
     * take care to timestamp correctly based on the offset of the input data
Packit 0652a1
     * however, so it does do sub-granulepos timestamping. */
Packit 0652a1
    buffer = gst_buffer_straw_get_buffer (bin, pad);
Packit 0652a1
    check_buffer_timestamp (buffer, 0);
Packit 0652a1
    /* plain division because I know the answer is exact */
Packit 0652a1
    check_buffer_duration (buffer, GST_SECOND / 10);
Packit 0652a1
    check_buffer_granulepos (buffer, 1 << GRANULEPOS_SHIFT);
Packit 0652a1
    check_buffer_is_header (buffer, FALSE);
Packit 0652a1
Packit 0652a1
    next_timestamp = GST_BUFFER_DURATION (buffer);
Packit 0652a1
Packit 0652a1
    gst_buffer_unref (buffer);
Packit 0652a1
Packit 0652a1
    /* check continuity with the next buffer */
Packit 0652a1
    buffer = gst_buffer_straw_get_buffer (bin, pad);
Packit 0652a1
    check_buffer_timestamp (buffer, next_timestamp);
Packit 0652a1
    check_buffer_duration (buffer, GST_SECOND / 10);
Packit 0652a1
    check_buffer_granulepos (buffer, (1 << GRANULEPOS_SHIFT) | 1);
Packit 0652a1
    check_buffer_is_header (buffer, FALSE);
Packit 0652a1
Packit 0652a1
    gst_buffer_unref (buffer);
Packit 0652a1
  }
Packit 0652a1
Packit 0652a1
  gst_buffer_straw_stop_pipeline (bin, pad);
Packit 0652a1
Packit 0652a1
  gst_object_unref (pad);
Packit 0652a1
  gst_object_unref (bin);
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
GST_END_TEST;
Packit 0652a1
Packit 0652a1
#endif /* #ifndef GST_DISABLE_PARSE */
Packit 0652a1
Packit 0652a1
static Suite *
Packit 0652a1
theoraenc_suite (void)
Packit 0652a1
{
Packit 0652a1
  Suite *s = suite_create ("theoraenc");
Packit 0652a1
  TCase *tc_chain = tcase_create ("general");
Packit 0652a1
Packit 0652a1
  suite_add_tcase (s, tc_chain);
Packit 0652a1
Packit 0652a1
  check_libtheora ();
Packit 0652a1
Packit 0652a1
#ifndef GST_DISABLE_PARSE
Packit 0652a1
  tcase_add_test (tc_chain, test_granulepos_offset);
Packit 0652a1
  tcase_add_test (tc_chain, test_continuity);
Packit 0652a1
#endif
Packit 0652a1
Packit 0652a1
  return s;
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
GST_CHECK_MAIN (theoraenc);