#include <stdio.h>
#include <gst/gst.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include<glib.h> 
#define FRAME_264  (1280*720)
#include <sys/time.h> 
/*
多路通道发出信号开始同时采集编码，发出命令结束编码，并以不同文件名保存 
 
*/ 
FILE *pFile[4];
unsigned int *dataPtr = NULL;

GstElement *pipeline[6];
GstBus *bus[6];
GstMessage *msg[6];

GstElement *src, *srcqueue, *video_queue, *video_convert, *q1, *video_enc, *parse, *q3, *mux, *video_sink;
GstElement *tee, *teequeue, *pic_queue, *pic_convert, *q2, *pic_enc, *pic_sink;
GstPad *tee_video_pad, *tee_picture_pad;
GstPad *queue_video_pad, *queue_picture_pad;

static int i=0;
static void new_sample (GstElement *sink) { 	
	GstSample *sample = NULL;
	GstBuffer *buffer = NULL;
  /* Retrieve the buffer */
  	g_signal_emit_by_name (pic_sink, "pull-sample", &sample);
  	buffer = gst_sample_get_buffer (sample);
  	int size = gst_buffer_get_size (buffer);
  	
	i++;
	g_print("i:%d\n",i);
	if (i>50)
	{
		i=0;
  		if (buffer) {
  			FILE *fp = NULL;
    			//fp = fopen("/opt/image/deviceid/tunnel_1/image.jpg","wb+");
    			fp = fopen("image.jpg","wb+");
    			gst_buffer_extract (buffer,0,dataPtr,size);
    			fwrite(dataPtr, sizeof(unsigned int), size, fp);
			gst_buffer_unref (buffer);
	 		fclose(fp); 
   			fp = NULL;
			g_print("have buffer!");
			//system("/opt/uploadoss/main image deviceid tunnel_1 image.jpg"); 
  		} 
	}
	else
	{
		gst_buffer_unref (buffer);
	} 
	//gst_sample_unref(sample);	
	sample = NULL;
	buffer = NULL;
}

static gboolean link_source_element_with_filter(GstElement *element1,
	GstElement *element2, int width, int height, int framerate)

{
	/* CAPS to be link:
	* 'video/x-raw, format=(string)YUY2, width=(int)800, height=(int)600, framerate=5/1'
	* */

	gboolean link_ok;
	GstCaps *caps;

	caps = gst_caps_new_simple("video/x-raw",
		"format", G_TYPE_STRING, "YUY2",
		"width", G_TYPE_INT, width,
		"height", G_TYPE_INT, height,
		"framerate", GST_TYPE_FRACTION, framerate, 1,
		NULL);

	link_ok = gst_element_link_filtered(element1, element2, caps);
	gst_caps_unref(caps);

	if (!link_ok) {
		g_warning("Failed to link element1 and element2!(v4l2src->convert)");
	}
	return link_ok;

}


void link_to_multiplexer(
	GstElement *tolink_element,
	GstElement *mux)
{
	GstCaps *pad_caps = NULL;
	GstPad *pad;
	GstPad *tolink_pad;
	GstPadLinkReturn ret;

	tolink_pad = gst_element_get_static_pad(tolink_element, "src");
	pad_caps = gst_pad_query_caps(tolink_pad, NULL);
	pad = gst_element_get_compatible_pad(mux, tolink_pad, pad_caps);
	gst_caps_unref(pad_caps);

	ret = gst_pad_link(tolink_pad, pad);
	if (ret==0)
		g_print("aaa\n");
	gst_object_unref(GST_OBJECT(pad));
	g_print("A new pad %s was created and linked to %s\n", gst_pad_get_name(tolink_pad), gst_pad_get_name(pad));
}


/* Main function does atual processing */

void record_start(int channel, char * filename)

//gst-launch-1.0 -e videotestsrc ! 'video/x-raw, format=(string)NV12, width=(int)1280, height=(int)720, framerate=(fraction)30/1' ! vpe num-input-buffers=8 ! queue ! ducatih264enc bitrate=4000 ! queue ! h264parse ! qtmux ! filesink location=x.mov
{
//	GstElement *src, *video_queue, *video_convert, *q1, *video_enc, *parse, *q3, *mux, *video_sink;
//	GstElement *tee, *pic_queue, *pic_convert, *pic_enc, *pic_sink; 
  	
	gst_init(NULL, NULL);

	/* Create the empty pipeline */
	pipeline[channel] = gst_pipeline_new("test-pipeline");

	/* Create the elements */
	src = gst_element_factory_make("v4l2src", "video_source");
	g_object_set(G_OBJECT(src), "device", "/dev/video1", NULL);
	g_object_set(G_OBJECT(src), "io-mode", 4, NULL);
	g_object_set(G_OBJECT(src), "num-buffers", -1, NULL);
	/*
	src = gst_element_factory_make("videotestsrc", "video_source");
	g_object_set(G_OBJECT(src), "num-buffers", -1, NULL);
        */
	video_convert = gst_element_factory_make("vpe", "video_convert");
	g_object_set(G_OBJECT(video_convert), "num-input-buffers", 8, NULL);
	q1 = gst_element_factory_make("queue", "q1");
	srcqueue = gst_element_factory_make("queue", "srcqueue");
	teequeue = gst_element_factory_make("queue", "teequeue");
	video_enc = gst_element_factory_make("ducatih264enc", "video_enc");
	//g_object_set(G_OBJECT(video_enc), "profile", 100, NULL);//10000会出现问题？？ 
	//g_object_set(G_OBJECT(video_enc), "level", 41, NULL);//10000会出现问题？？ 
	g_object_set(G_OBJECT(video_enc), "bitrate", 10000, NULL);//10000会出现问题？？ 
	
	parse = gst_element_factory_make("h264parse", "parser");
	q3 = gst_element_factory_make("queue", "q3");
	mux = gst_element_factory_make("avimux", "mux");
	video_sink = gst_element_factory_make("filesink", "video_sink");
	g_object_set(G_OBJECT(video_sink), "location", filename, NULL);
	q2 = gst_element_factory_make("queue", "q2");
	tee = gst_element_factory_make ("tee", "tee");
	video_queue =gst_element_factory_make("queue","video_queue"); 
	pic_queue = gst_element_factory_make("queue","pic_queue"); 
	pic_convert = gst_element_factory_make("vpe", "pic_convert");
	//g_object_set(G_OBJECT(pic_convert), "num-input-buffers", 8, NULL);
	
	pic_enc = gst_element_factory_make("ducatijpegenc", "pic_enc");
	//g_object_set (pic_enc, "intra-interval", 100, NULL);
	pic_sink = gst_element_factory_make("appsink", "pic_sink");
	g_object_set (pic_sink, "emit-signals", TRUE, NULL);
  	g_signal_connect (pic_sink, "new-sample", G_CALLBACK (new_sample), NULL); 
	

	gst_bin_add_many(GST_BIN(pipeline[channel]), src, tee, video_convert, q1, video_enc, parse, q3, mux, video_sink, pic_convert, q2,pic_enc, pic_sink, NULL);
  	
	tee_video_pad = gst_element_get_request_pad (tee, "src_%u");
  	g_print ("Obtained request pad %s for video branch.\n", gst_pad_get_name (tee_video_pad));
  	queue_video_pad = gst_element_get_static_pad (video_convert, "sink");
  	tee_picture_pad = gst_element_get_request_pad (tee, "src_%u");
  	g_print ("Obtained request pad %s for picture branch.\n", gst_pad_get_name (tee_picture_pad));
  	queue_picture_pad = gst_element_get_static_pad (pic_convert, "sink");
  	
  	if (gst_pad_link (tee_picture_pad, queue_picture_pad) != GST_PAD_LINK_OK ||
      gst_pad_link (tee_video_pad, queue_video_pad) != GST_PAD_LINK_OK) {
    g_printerr ("Tee could not be linked.\n");
    gst_object_unref (pipeline);
  	}
	  
	/*if (gst_element_link_pads(src, "src", srcqueue, "sink") != TRUE)
	{
		g_print("11\n");
	}
	
	if (gst_element_link_pads(srcqueue, "src", teequeue, "sink") != TRUE)
	{
		g_print("111\n");
	}//有没有 queue都一样 
	*/
	
	link_source_element_with_filter(src, tee, 1280, 720, 30);
	
  		if (gst_element_link_pads(video_convert, "src", q1, "sink") != TRUE)
	{
		g_print("1\n");
	}
	if (gst_element_link_pads(q1, "src", video_enc, "sink") != TRUE)
	{
		g_print("2\n");
	}
	if (gst_element_link_pads(video_enc, "src", parse, "sink") != TRUE)
	{
		g_print("3\n");
	}
	if (gst_element_link_pads(parse, "src", q3, "sink") != TRUE)
	{     
		g_print("4\n");
	}
	link_to_multiplexer(q3, mux);
	if (gst_element_link_pads(mux, "src", video_sink, "sink") != TRUE)
	{
		g_print("5\n");
	}
  	
  	//link_source_element_with_filter(pic_queue, pic_convert, 1280, 720, 30);
	
	if(gst_element_link_pads(pic_convert, "src", q2, "sink")!= TRUE)
	{
		g_print("6\n");
	}
	if(gst_element_link_pads(q2, "src", pic_enc, "sink")!= TRUE)
	{
		g_print("66\n");
	}
	if(gst_element_link_pads(pic_enc, "src", pic_sink, "sink")!= TRUE)
	{
		g_print("7\n");
	}
  
	gst_object_unref (queue_picture_pad);
  	gst_object_unref (queue_video_pad);
	
	gst_element_set_state(pipeline[channel], GST_STATE_PLAYING);	
}

void record_stop(int channel)
{

 	gst_element_send_event(pipeline[channel],gst_event_new_eos()); 	
	/* Wait until error or EOS */
	bus[channel] = gst_element_get_bus(pipeline[channel]);
	msg[channel] = gst_bus_timed_pop_filtered(bus[channel], GST_CLOCK_TIME_NONE , GST_MESSAGE_ERROR | GST_MESSAGE_EOS);//GST_CLOCK_TIME_NONE
	
 	gst_element_release_request_pad (tee, tee_picture_pad);
  	gst_element_release_request_pad (tee, tee_video_pad);
  	gst_object_unref (tee_picture_pad);
  	gst_object_unref (tee_video_pad);
  
	if (msg[channel] != NULL)
	{
		gst_message_unref(msg[channel]);
	}


	gst_object_unref(bus[channel]);
	
	gst_element_set_state(pipeline[channel], GST_STATE_PAUSED);
	gst_element_set_state(pipeline[channel], GST_STATE_READY);
	gst_element_set_state(pipeline[channel], GST_STATE_NULL);
	gst_object_unref(pipeline[channel]);
}

void main()
{
    dataPtr=(unsigned int*)malloc(sizeof(unsigned int) * FRAME_264);
    memset(dataPtr,0,FRAME_264);
    
	record_start(0, "ch0.avi");
	sleep(500);
	record_stop(0);
	free(dataPtr);
	dataPtr = NULL;
}