/*
 * uridecodebin_test.c
 *
 *  Created on: Aug 12, 2010
 *      Author: wl
 */

#include <stdio.h>
#include <stdlib.h>
#include <gst/gst.h>

GstElement 	*pipeline;
GstElement  *decodebin;
GstElement 	*acodec,*aconv,*vcodec,*muxer;
GstElement 	*filesink;
GstElement 	*mqueue;

GMainLoop 	*loop;

#define fragment_max 2

struct fragment{
	int start;
	int stop;
};

struct fragment fragments[fragment_max];

int fr_count;

static void pad_added (GstPadTemplate * templ G_GNUC_UNUSED, GstPad * newpad, gpointer data)
{GstPad *q_sinkpad,*q_srcpad,*c_sinkpad,*c_srcpad,*mpad;
 GstPadLinkReturn r;
 GstIterator *it;
 gchar *caps;

 	 q_sinkpad=gst_element_get_request_pad(mqueue,"sink%d");

 	 it=gst_pad_iterate_internal_links(q_sinkpad);
 	 if (!it || (gst_iterator_next (it,(gpointer)&q_srcpad))!=GST_ITERATOR_OK || q_srcpad==NULL) {
 	    g_print("Couldn't get srcpad from multiqueue for sinkpad %s:%s", GST_DEBUG_PAD_NAME(q_sinkpad));
	 	gst_iterator_free(it);
 	    return;
 	 }
 	 gst_iterator_free(it);

 	 caps=gst_caps_to_string(gst_pad_get_caps(newpad));
 	 g_print("pad_added, new pad caps: %s\n",caps);
 	 if(g_strrstr(caps,"video")){
 		 c_sinkpad=gst_element_get_compatible_pad(vcodec,newpad,gst_pad_get_caps(newpad));
 		 c_srcpad=gst_element_get_static_pad(vcodec,"src");
 	 }else{
 		 c_sinkpad=gst_element_get_compatible_pad(aconv,newpad,gst_pad_get_caps(newpad));
 		 c_srcpad=gst_element_get_static_pad(acodec,"src");
 	 }
 	 g_free(caps);

 	 mpad=gst_element_get_compatible_pad(muxer,c_srcpad,gst_pad_get_caps(c_srcpad));

 	 r=gst_pad_link(newpad,c_sinkpad);
 	 g_print("pad_added, linked %s:%s to %s:%s result=%d\n",GST_DEBUG_PAD_NAME(newpad),GST_DEBUG_PAD_NAME(c_sinkpad),r);
 	 r=gst_pad_link(c_srcpad,q_sinkpad);
 	 g_print("pad_added, linked %s:%s to %s:%s result=%d\n",GST_DEBUG_PAD_NAME(c_srcpad),GST_DEBUG_PAD_NAME(q_sinkpad),r);
 	 r=gst_pad_link(q_srcpad,mpad);
 	 g_print("pad_added, linked %s:%s to %s:%s result=%d\n",GST_DEBUG_PAD_NAME(q_srcpad),GST_DEBUG_PAD_NAME(mpad),r);

 	 gst_object_unref(q_srcpad);
 	 gst_object_unref(q_sinkpad);
 	 gst_object_unref(c_srcpad);
 	 gst_object_unref(c_sinkpad);
 	 gst_object_unref(mpad);

 	 if(data)
		GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(data),GST_DEBUG_GRAPH_SHOW_ALL,"decodebin");
}

gboolean bus_call(GstBus *bus, GstMessage *msg, gpointer data)
{
	gboolean ret=TRUE;
	switch(GST_MESSAGE_TYPE(msg)){
		case GST_MESSAGE_SEGMENT_DONE:
			g_print("segment done\n");
			if(fr_count < fragment_max){
				gboolean rs;
				rs=gst_element_seek(pipeline,
							1.0,
							GST_FORMAT_TIME,
							GST_SEEK_FLAG_FLUSH|GST_SEEK_FLAG_KEY_UNIT|GST_SEEK_FLAG_SEGMENT,
							GST_SEEK_TYPE_SET,
							fragments[fr_count].start*GST_SECOND,
							GST_SEEK_TYPE_SET,
							fragments[fr_count].stop*GST_SECOND
							);
				g_print("doing segment seek: result=%d\n",rs);
				fr_count++;
			}else{
				g_print("last segment played\n");
				ret=FALSE;
				g_main_loop_quit(loop);
			}
			break;
		case GST_MESSAGE_EOS:
			g_print("eos\n");
			g_main_loop_quit(loop);
			ret=FALSE;
			break;
		case GST_MESSAGE_ERROR:{
			GError *err;
			gchar *debug;

			gst_message_parse_error (msg, &err, &debug);
			g_print ("Error: %s\n", err->message);
			g_error_free (err);

			if (debug) {
				g_print ("Debug deails: %s\n", debug);
				g_free (debug);
			}
			g_main_loop_quit(loop);
			ret=FALSE;
			break;
		}
/*		case GST_MESSAGE_ASYNC_DONE:{
			GstState old,new,pend;

		}*/
		case GST_MESSAGE_STATE_CHANGED:{
			GstState old,new,pend;
			gst_message_parse_state_changed(msg,&old,&new,&pend);
			g_print("message state changed from %s: old:%d, new:%d, pending:%d\n",GST_MESSAGE_SRC_NAME(msg),
					old,new,pend);
			if(GST_MESSAGE_SRC(msg)==GST_OBJECT(pipeline)){
				if(fr_count==0 && new==GST_STATE_PAUSED /*&& pend==GST_STATE_PLAYING*/){
					gboolean rs;
					rs=gst_element_seek(pipeline,
								1.0,
								GST_FORMAT_TIME,
								GST_SEEK_FLAG_FLUSH|GST_SEEK_FLAG_KEY_UNIT|GST_SEEK_FLAG_SEGMENT,
								GST_SEEK_TYPE_SET,
								fragments[fr_count].start*GST_SECOND,
								GST_SEEK_TYPE_SET,
								fragments[fr_count].stop*GST_SECOND
								);
					g_print("doing segment seek from state changed: result=%d\n",rs);
					fr_count++;
					gst_element_set_state(pipeline,GST_STATE_PLAYING);
				}
			}
		}
		default:
			if(GST_MESSAGE_TYPE(msg)!=GST_MESSAGE_WARNING || g_strrstr(GST_MESSAGE_SRC_NAME(msg),"mpeg2dec")==NULL)
				g_print("message %s(%d) from %s\n",GST_MESSAGE_TYPE_NAME(msg),GST_MESSAGE_TYPE(msg),GST_MESSAGE_SRC_NAME(msg));
			break;
	}
	//gst_message_unref(msg);
	return ret;
}

gboolean tick(gpointer pipeline_pointer)
{guint64 position, duration;
 GstFormat format=GST_FORMAT_TIME;
 GstState state;
 GTimeVal timeval;
 gchar *tv;

 	gst_element_query_position(GST_ELEMENT(pipeline_pointer),&format,&position);

 	format=GST_FORMAT_TIME;
 	gst_element_query_duration(GST_ELEMENT(pipeline_pointer),&format,&duration);

 	gst_element_get_state(GST_ELEMENT(pipeline_pointer),&state,NULL,GST_CLOCK_TIME_NONE);

 	g_get_current_time(&timeval);
 	tv=g_time_val_to_iso8601(&timeval);
 	g_print("%s: position [%"GST_TIME_FORMAT"/%"GST_TIME_FORMAT"]\n",tv,GST_TIME_ARGS(position),GST_TIME_ARGS(duration));
 	g_free(tv);

 	return state==GST_STATE_NULL?FALSE:TRUE;
}

int main(int argc,char *argv[])
{
	GstBus *bus;
	GTimeVal timeval;
	gboolean wait_result;
	GstFormat format;
	gint64 position, duration;
	gchar *location="file:///home/wl/AVIK/video/198640.mpg";
	GstStateChangeReturn rs;

	g_thread_init(NULL);
	gst_init(&argc,&argv);

	loop=g_main_loop_new(NULL,FALSE);

	pipeline = gst_pipeline_new("pipeline");
	bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
	gst_bus_add_watch(bus,bus_call,NULL);

	GstPluginFeature *feature=gst_default_registry_find_feature("flump3dec",GST_TYPE_ELEMENT_FACTORY);
	if(feature)
		gst_plugin_feature_set_rank(feature,GST_RANK_NONE);

	decodebin = gst_element_factory_make("uridecodebin","ubin");
	g_object_set(decodebin,"uri",location,NULL);
	g_signal_connect(G_OBJECT(decodebin),"pad-added",G_CALLBACK(pad_added),pipeline);

	mqueue = gst_element_factory_make("multiqueue","mqueue");

	aconv = gst_element_factory_make("audioconvert","aconv");

	acodec = gst_element_factory_make(//"lamemp3enc"
									  "twolame"
								,"acodec");
	vcodec = gst_element_factory_make(//"mpeg2enc",
								"ffenc_mpeg2video"
								,"vcodec");

	muxer = gst_element_factory_make("mpegpsmux","mux");
	filesink = gst_element_factory_make("filesink","sink");
	g_object_set(filesink,"location","/home/wl/AVIK/video/dectsaved.mpg",
			"sync",FALSE,
			NULL);

	gst_bin_add_many(GST_BIN(pipeline),decodebin,mqueue,aconv,acodec,vcodec,muxer,filesink,NULL);

	gst_element_link(aconv,acodec);
	gst_element_link(muxer,filesink);

	fragments[0].start=5; fragments[0].stop=25;
	fragments[1].start=90; fragments[1].stop=125;

	fr_count=0;
	rs=gst_element_set_state(pipeline,GST_STATE_PAUSED);
	g_print("gst_element_set_state(pipeline,GST_STATE_PAUSED); rs=%d\n",rs);

	g_timeout_add(500,tick,pipeline);

	g_main_loop_run(loop);

	gst_element_set_state(pipeline,GST_STATE_NULL);

	g_print("Return from main app\n");
	return EXIT_SUCCESS;
}
