/*
 * Reproducing rate-bug (based on Simple GStreamer application template)
 *
 * Copyright (c) 2014 Sebastian Dröge <sebastian@centricular.com>
 * Copyright (c) 2016 Heinrich Fink <hfink@toolsonair.com>
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 */

#include <gst/gst.h>

static GMainLoop *loop;
static GstElement *pipeline;

static gboolean
message_cb (GstBus * bus, GstMessage * message, gpointer user_data)
{
  switch (GST_MESSAGE_TYPE (message)) {
    case GST_MESSAGE_ERROR:{
      GError *err = NULL;
      gchar *name, *debug = NULL;

      name = gst_object_get_path_string (message->src);
      gst_message_parse_error (message, &err, &debug);

      g_printerr ("ERROR: from element %s: %s\n", name, err->message);
      if (debug != NULL)
        g_printerr ("Additional debug info:\n%s\n", debug);

      g_error_free (err);
      g_free (debug);
      g_free (name);

      g_main_loop_quit (loop);
      break;
    }
    case GST_MESSAGE_WARNING:{
      GError *err = NULL;
      gchar *name, *debug = NULL;

      name = gst_object_get_path_string (message->src);
      gst_message_parse_warning (message, &err, &debug);

      g_printerr ("ERROR: from element %s: %s\n", name, err->message);
      if (debug != NULL)
        g_printerr ("Additional debug info:\n%s\n", debug);

      g_error_free (err);
      g_free (debug);
      g_free (name);
      break;
    }
    case GST_MESSAGE_EOS:
      g_print ("Got EOS\n");
      g_main_loop_quit (loop);
      break;
    default:
      break;
  }

  return TRUE;
}

static gboolean
change_rate (GstClock * clock, GstClockTime time, GstClockID id,
    gpointer user_data)
{
  GstBin *pipeline = GST_BIN_CAST (user_data);
  static gint nominator = 10;

  GstCaps *caps = NULL;
  g_assert_nonnull (user_data);
  GstElement *capsfilter = gst_bin_get_by_name (pipeline, "ratecaps");
  g_assert_nonnull (capsfilter);

  g_object_get (capsfilter, "caps", &caps, NULL);
  caps = gst_caps_make_writable (caps);
  g_assert_nonnull (caps);

  gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION, nominator, 1,
      NULL);
  g_object_set (capsfilter, "caps", caps, NULL);
  gst_caps_unref (caps);

  gst_object_unref (capsfilter);
  capsfilter = NULL;

  g_print ("changed frame rate to %d/1\n", nominator);

  if (nominator == 10)
    nominator = 25;
  else
    nominator = 10;

  return FALSE;
}

int
main (int argc, char **argv)
{
  GstBus *bus;
  GError *err = NULL;
  GstClock *clk = NULL;
  GstClockTime now_t;

  gst_init (&argc, &argv);
  pipeline = gst_parse_launch ("\
      videotestsrc pattern=18 is-live=TRUE ! \
      capsfilter caps=\"video/x-raw,format=UYVY,width=640,height=360,framerate=50/1,interlace-mode=progressive\" ! \
      interlace top-field-first=TRUE field-pattern=0 ! \
      capsfilter caps=\"video/x-raw,interlace-mode=interleaved\" ! \
      deinterlace fields=1 tff=1 ! \
      queue max-size-buffers=0 max-size-bytes=0 max-size-time=200000000 min-threshold-time=100000000 ! \
      videorate skip-to-first=TRUE ! \
      videoscale ! \
      videoconvert ! \
      capsfilter caps-change-mode=1 name=ratecaps caps=\"video/x-raw,width=640,width=360,interlace-mode=progressive,framerate=25/1\" ! \
      videoconvert ! autovideosink", &err);

  if (!pipeline) {
    g_error ("failed to create pipeline. err: %s",
        err != NULL ? err->message : "?");
  }

  loop = g_main_loop_new (NULL, FALSE);

  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
  gst_bus_add_signal_watch (bus);
  g_signal_connect (G_OBJECT (bus), "message", G_CALLBACK (message_cb), NULL);
  gst_object_unref (GST_OBJECT (bus));

  if (gst_element_set_state (pipeline,
          GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
    g_error ("Failed to go into PLAYING state");
    return -3;
  }

  /* every 3 seconds, change the frame rate between
   * 10/1 and 25/1*/
  clk = gst_system_clock_obtain ();
  now_t = gst_clock_get_time (clk);

  GstClockID change_rate_id =
      gst_clock_new_periodic_id (clk, now_t, 3 * GST_SECOND);
  gst_clock_id_wait_async (change_rate_id, change_rate, pipeline, NULL);

  g_main_loop_run (loop);

  gst_element_set_state (pipeline, GST_STATE_NULL);

  g_main_loop_unref (loop);
  gst_object_unref (pipeline);
  gst_object_unref (clk);
  gst_clock_id_unref (change_rate_id);

  return 0;
}
