/* gcc -g -Wall -lm `pkg-config --cflags --libs gstreamer-0.8` -o main main.c */

#include <math.h>

#include <gst/gst.h>

static GstElement *pipeline;
static GstElement *filesrc;
static GstElement *decodebin;
static GstElement *sink;

gdouble framerate;
gint    width;
gint    height;


void
cb_new_pad (GstElement *decodebin,
	    GstPad     *pad,
	    gboolean    last,
	    gpointer    data)
{
  GstCaps *caps;
  GstStructure *str;
  const gchar *mimetype;

  caps = gst_pad_get_caps (pad);
  str = gst_caps_get_structure (caps, 0);
  mimetype = gst_structure_get_name (str);

  printf ("\nNew Pad : %s\n", gst_structure_to_string (str));

  if (g_str_has_prefix (mimetype, "video/"))
    {
      GstPad       *videopad;
      GstStructure *str;
      
      videopad = gst_element_get_pad (sink, "sink");
      gst_pad_link (pad, videopad);
      gst_bin_sync_children_state (GST_BIN (pipeline));
      
      videopad = gst_element_get_pad (gst_pad_get_real_parent (pad),
				      "sink");
      str = gst_caps_get_structure (GST_PAD_CAPS (videopad), 0);
      if (str)
	{
	  gst_structure_get_int (str, "width", &width);
	  gst_structure_get_int (str, "height", &height);
	  
	  gst_structure_get_double (str, "framerate", &framerate);
	  
	  g_print ("Width......: %d\n", width);
	  g_print ("Height.....: %d\n", height);
	  g_print ("Framerate..: %f\n", framerate);
	}
    }
}  

void
cb_no_more_pad (GstElement *decodebin,
		gpointer    data)
{
  gst_element_set_state (pipeline, GST_STATE_PAUSED);
}

void
cb_handoff(GObject * obj, GstBuffer *buffer, GstPad * pad, void * data)
{
  FILE *file;
  gint i, j;
  unsigned char *Y;
  unsigned char *U;
  unsigned char *V;
  gint offset_Y, offset_U;
  gint r, g, b;

  g_print ("handoff\n");
  gst_element_set_state (pipeline, GST_STATE_PAUSED);


  /* Open the ppm file */
  file = fopen ("test.ppm", "w+b");
  if (file == NULL)
    {
      printf ("The file can't be opened for writing\n");
      return;
    }

  /* Header */
  fprintf (file, "P3\n# colorbars.ppm\n%d %d\n256\n", width, height);
  
  
  /* the video is in I420 */
  Y = buffer->data;
  V = Y + width * height;
  U = V + ((width * height) >> 2);

  for (j = 0 ; j < height ; j++)
    for (i = 0 ; i < width ; i++)
      {
	offset_Y = j*width + i;
	offset_U = ((j*width) >> 2) + (i >> 1);

	r = 1.164 * (Y[offset_Y] - 16) + 1.596 * (V[offset_U] - 128);
	g = 1.164 * (Y[offset_Y] - 16) - 0.813 * (V[offset_U] - 128) - 0.391 * (U[offset_U] - 128);
	b = 1.164 * (Y[offset_Y] - 16) + 2.018 * (U[offset_U] - 128);
	
	fprintf (file, "%d %d %d\n", r, g, b);
      }
  fclose (file);
}

int
main (int argc, char *argv[])
{
  gint frame_number = 175;
  char *filename = "/mnt/win_d/provi/blood_small.ogm";
  gint i;
  gint id_new;
  gint id_nomore;
  long long int time;
  GstSeekType type = (GstSeekType)(GST_FORMAT_TIME     |
				   GST_SEEK_METHOD_SET |
				   GST_SEEK_FLAG_FLUSH);

  gst_init (&argc, &argv);

  pipeline = gst_pipeline_new ("pipeline");

  filesrc = gst_element_factory_make ("filesrc", NULL);
  g_object_set (G_OBJECT (filesrc), "location", filename, NULL);
  decodebin = gst_element_factory_make ("decodebin", NULL);
  sink = gst_element_factory_make ("fakesink", NULL);
  gst_bin_add_many (GST_BIN (pipeline), filesrc, decodebin, sink, NULL);
  gst_element_link (filesrc, decodebin);

  g_object_set (G_OBJECT (sink), "signal-handoffs", TRUE, NULL);

  id_new = g_signal_connect (G_OBJECT (decodebin),
			     "new-decoded-pad",
			     G_CALLBACK (cb_new_pad), NULL);
  id_nomore = g_signal_connect (G_OBJECT (decodebin),
				"no-more-pads",
				G_CALLBACK (cb_no_more_pad), NULL);
  
  gst_element_set_state (pipeline, GST_STATE_PLAYING);

  i = 0;
  while (gst_bin_iterate (GST_BIN (pipeline)) && (i<=40))
    {
      g_print ("I: %d\n", i);
      i++;
    }

  if (g_signal_handler_is_connected (G_OBJECT (decodebin), id_new))
    g_signal_handler_disconnect (G_OBJECT (decodebin), id_new);
  if (g_signal_handler_is_connected (G_OBJECT (decodebin), id_nomore))
    g_signal_handler_disconnect (G_OBJECT (decodebin), id_nomore);
  
  /* seek */
  time = floor (1000000000*frame_number*framerate);
  if (!gst_element_seek(sink, type, frame_number))
    {
      g_print ("not good...\n");
      exit (0);
    }

  g_signal_connect (G_OBJECT (sink),
		    "handoff",
		    G_CALLBACK (cb_handoff), NULL);
  
  gst_element_set_state (pipeline, GST_STATE_PLAYING);
  while (gst_bin_iterate (GST_BIN (pipeline))) { }

  gst_element_set_state (pipeline, GST_STATE_NULL);
  gst_object_unref (GST_OBJECT (pipeline));

  return 1;
}
