#include #include gboolean bus_call(GstBus *bus, GstMessage *msg, void *data) { gchar *debug; GError *err; GMainLoop *loop = (GMainLoop*)data; switch (GST_MESSAGE_TYPE(msg)) { case GST_MESSAGE_EOS: g_print("EOS received on OBJ NAME %s\n",GST_OBJECT_NAME(msg->src)); g_main_loop_quit (loop); break; case GST_MESSAGE_ERROR: gst_message_parse_error(msg, &err, &debug); g_free(debug); g_print("BUS CALL %s\n", err->message); g_error_free(err); g_main_loop_quit (loop); break; default: break; } return TRUE; } /** * drop_eos_probe: * @pad: pad receiving the event * @event: received event * @u_data: main pipeline * * Event probe that drop all eos events. * * Returns: FALSE to drop the event, TRUE otherwise */ gboolean drop_eos_probe (GstPad * pad, GstEvent * event, gpointer data) { gboolean ret = TRUE; static int called = 0; switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: called++; g_print("PAD NAME %s: %s\n",gst_pad_get_name(pad),gst_element_get_name(gst_pad_get_parent_element(pad))); if(called == 1) // stop the recording { g_print("Removing recording bin: %d\n",__LINE__); GstElement *pipeline = (GstElement*)data; GstElement *rec_bin = gst_bin_get_by_name(GST_BIN(pipeline),"recording-bin"); GstElement *vtee = gst_bin_get_by_name(GST_BIN(pipeline), "viewing-tee"); #ifdef INCLUDE_AUDIO GstElement *atee = gst_bin_get_by_name(GST_BIN(pipeline), "viewing-audio-tee"); GstPad *vsrcpad = gst_element_get_pad(vtee,"src1"); GstPad *vsinkpad = gst_element_get_pad(rec_bin,"vsink"); GstPad *asrcpad = gst_element_get_pad(atee,"src1"); GstPad *asinkpad = gst_element_get_pad(rec_bin,"asink"); g_print("Removing recording bin: %d\n",__LINE__); gst_pad_set_blocked(vsrcpad,TRUE); gst_pad_set_blocked(asrcpad,TRUE); gst_pad_unlink(vsrcpad, vsinkpad); gst_pad_unlink(asrcpad, asinkpad); g_print("Removing recording bin: %d\n",__LINE__); gst_element_remove_pad(vtee, vsrcpad); gst_element_remove_pad(atee, asrcpad); gst_pad_set_blocked(asrcpad,FALSE); gst_pad_set_blocked(vsrcpad,FALSE); #else GstPad *vsrcpad = gst_element_get_pad(vtee,"src1"); GstPad *vsinkpad = gst_element_get_pad(rec_bin,"vsink"); g_print("Removing recording bin: %d\n",__LINE__); gst_pad_set_blocked(vsrcpad,TRUE); gst_pad_unlink(vsrcpad, vsinkpad); g_print("Removing recording bin: %d\n",__LINE__); gst_element_remove_pad(vtee, vsrcpad); gst_pad_set_blocked(vsrcpad,FALSE); #endif gst_bin_remove(GST_BIN(pipeline), rec_bin); gst_element_set_state(rec_bin, GST_STATE_NULL); g_print("Removing recording bin: %d\n",__LINE__); ret = FALSE; } else g_print("caught %d Not Dropping\n",called); break; default: break; } return ret; } /** * stop_encoding: * @data: main pipeline * * This is a glib function that gets called every 2 seconds, once called 3 times it will issue an EOS to the bin's sink pad * * Returns: FALSE to stop the event loop calling again, TRUE otherwise */ gboolean stop_encoding(gpointer *data) { static int called = 0; called++; g_print("CALLED!! %d times\n",called); if(called == 2) { GstElement *pipe = (GstElement*)data; GstElement *recording = gst_bin_get_by_name(GST_BIN(pipe),"recording-bin"); GstPad *sinkpad = gst_element_get_static_pad(recording,"vsink"); if(!sinkpad) { g_error("Unable to get vsink\n"); } else if(gst_pad_send_event(gst_element_get_static_pad(recording,"vsink"),gst_event_new_eos()) #ifdef INCLUDE_AUDIO && gst_pad_send_event(gst_element_get_static_pad(recording,"asink"),gst_event_new_eos()) #endif ) g_print("Sent EOS to stop recording!\n"); } return (called == 2)?FALSE:TRUE; } int main(int argc, char* argv[]) { GMainLoop *loop; gst_init(&argc,&argv); loop = g_main_loop_new (NULL, FALSE); GstElement *pipeline, *vsource, *vtee, *vqueue, *tover, *xvsink, *evqueue, *vencoder, *muxer, *filesink; #ifdef INCLUDE_AUDIO GstElement *asource, *atee, *aqueue, *aequeue, *aencoder, *asink; #endif GstBin *recording; GstBus *bus; GstPad *srcpad,*sinkpad; // Create gstreamer elements pipeline = gst_pipeline_new ("eos-test-player"); vsource = gst_element_factory_make ("videotestsrc", "viewing-file-source"); vtee = gst_element_factory_make ("tee", "viewing-tee"); vqueue = gst_element_factory_make ("queue2", "viewing-queue"); tover = gst_element_factory_make ("timeoverlay", "viewing-overlay"); xvsink = gst_element_factory_make ("xvimagesink", "viewing-xvsink"); #ifdef INCLUDE_AUDIO asource = gst_element_factory_make ("audiotestsrc", "viewing-audio-source"); atee = gst_element_factory_make ("tee", "viewing-audio-tee"); aqueue = gst_element_factory_make ("queue2", "viewing-audio-queue"); asink = gst_element_factory_make ("pulsesink", "viewing-audio-sink"); #endif recording = GST_BIN(gst_bin_new("recording-bin")); evqueue = gst_element_factory_make ("queue2", "encoding-queue"); vencoder = gst_element_factory_make ("ffenc_mpeg4", "encoding-encoder"); #ifdef INCLUDE_AUDIO aequeue = gst_element_factory_make ("queue2", "encoding-audio-queue"); aencoder = gst_element_factory_make ("lamemp3enc", "encoding-audio-encoder"); #endif muxer = gst_element_factory_make ("ffmux_mp4", "encoding-muxer"); filesink = gst_element_factory_make ("filesink", "encoding-filesink"); if(!pipeline || !vsource || !vtee || !vqueue || !xvsink || !tover ) { g_print("Unable to create all necessary elements\n"); return -1; } bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); gst_bus_add_watch (bus, bus_call, loop); gst_object_unref (bus); g_object_set(G_OBJECT(vsource),"num-buffers",400, NULL); g_object_set(G_OBJECT(filesink),"location","/tmp/output.mp4", NULL); g_object_set (G_OBJECT (tover), "halign", "right", NULL); g_object_set (G_OBJECT (tover), "valign", "top", NULL); g_object_set (G_OBJECT (tover), "shaded-background", TRUE, NULL); /* create the recording bin */ #ifdef INCLUDE_AUDIO gst_bin_add_many (recording, aequeue, aencoder, evqueue, vencoder, muxer, filesink, NULL); #else gst_bin_add_many (recording, evqueue, vencoder, muxer, filesink, NULL); #endif sinkpad = gst_element_get_static_pad(evqueue,"sink"); GstPad *ghost = gst_ghost_pad_new("vsink",sinkpad); if(ghost == NULL) g_error("Unable to create ghostpad!\n"); gst_element_add_pad(GST_ELEMENT(recording),ghost); gst_object_unref(GST_OBJECT(sinkpad)); gst_element_link_many(evqueue,vencoder,muxer,filesink,NULL); #ifdef INCLUDE_AUDIO sinkpad = gst_element_get_static_pad(aequeue,"sink"); gst_element_add_pad(GST_ELEMENT(recording),gst_ghost_pad_new("asink",sinkpad)); gst_object_unref(GST_OBJECT(sinkpad)); gst_element_link_many(aequeue,aencoder,muxer,NULL); #endif /* we add all elements into the pipeline */ #ifdef INCLUDE_AUDIO gst_bin_add_many (GST_BIN (pipeline), asource, atee, aqueue, asink, vsource, vtee, vqueue, tover, xvsink, recording, NULL); #else gst_bin_add_many (GST_BIN (pipeline), vsource, vtee, vqueue, tover, xvsink, recording, NULL); #endif /* link video elements */ gst_element_link_many(vsource,tover,vtee,NULL); srcpad = gst_element_get_request_pad(vtee,"src0"); sinkpad = gst_element_get_pad(vqueue,"sink"); gst_pad_link(srcpad,sinkpad); gst_element_link(vqueue,xvsink); /* link the viewing pipeline into the bin */ srcpad = gst_element_get_request_pad(vtee,"src1"); sinkpad = gst_element_get_pad(GST_ELEMENT(recording),"vsink"); gst_pad_link(srcpad,sinkpad); #ifdef INCLUDE_AUDIO /* link audio elements */ gst_element_link_many(asource,atee,NULL); srcpad = gst_element_get_request_pad(atee,"src0"); sinkpad = gst_element_get_pad(aqueue,"sink"); gst_pad_link(srcpad,sinkpad); gst_element_link(aqueue,asink); /* link the viewing pipeline into the bin */ srcpad = gst_element_get_request_pad(atee,"src1"); sinkpad = gst_element_get_pad(GST_ELEMENT(recording),"asink"); gst_pad_link(srcpad,sinkpad); #endif /* EOS probe */ gst_pad_add_event_probe (gst_element_get_static_pad(muxer,"src"), G_CALLBACK (drop_eos_probe), pipeline); /* Iterate */ g_print ("Running...\n"); g_timeout_add_seconds(2,(GSourceFunc)stop_encoding,pipeline); gst_element_set_state(pipeline,GST_STATE_PLAYING); g_main_loop_run (loop); /* Out of the main loop, clean up nicely */ g_print ("Returned, stopping playback\n"); gst_element_set_state (pipeline, GST_STATE_NULL); g_print ("Deleting pipeline\n"); gst_object_unref (GST_OBJECT (pipeline)); return 0; }