/* * Copyright (c) 2012-2013, Texas Instruments Incorporated * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of Texas Instruments Incorporated nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Contact information for paper mail: * Texas Instruments * Post Office Box 655303 * Dallas, Texas 75265 * Contact information: * http://www-k.ext.ti.com/sc/technical-support/product-information-centers.htm? * DCMP=TIHomeTracking&HQS=Other+OT+home_d_contact * ============================================================================ * */ /** * @file gst-controller.c * * @brief Imeplements GStreamer related functions */ #include #include #include #include "gst-controller.h" gchar * fsinkArr [] = {"fsink0", "fsink1"}; static gint fsinkCounter = 0; static void getTime (gint64 arr[], gint64 time); /****************************************************************************** Static Functions ******************************************************************************/ static gboolean attachPipeElements (Pipeline *pipePtr, GstElement *sink0, GstElement *sink1) { gboolean ret = TRUE; GstElement *fsink0 = NULL; GstElement *fsink1 = NULL; GstElement *bin = NULL; GstElement *tee = NULL; GstElement *queue0 = NULL; GstElement *queue1 = NULL; GstPad *pad = NULL; bin = gst_bin_new ("vsinkbin"); tee = gst_element_factory_make ("tee","splitter"); //sink0 = createImageSinkFromWindow (drawArea1, "sink0"); queue0 = gst_element_factory_make ("queue","q0"); queue1 = gst_element_factory_make ("queue","q1"); if (NULL == sink0) fsink0 = gst_element_factory_make ("fakesink", fsinkArr[fsinkCounter++]); if (NULL == sink1) fsink1 = gst_element_factory_make ("fakesink", fsinkArr[fsinkCounter++]); if ( !bin || !tee || !queue0 || !queue1) { ret = FALSE; goto exit; } if (NULL == sink0 && NULL == sink1) { gst_bin_add_many (GST_BIN (bin), tee, fsink0, fsink1, queue0, queue1,NULL); gst_element_link (queue0, fsink0); gst_element_link(queue1,fsink1); } else if (NULL != sink0 && NULL == sink1){ gst_bin_add_many (GST_BIN (bin), tee, sink0, fsink1, queue0, queue1,NULL); gst_element_link (queue0, sink0); gst_element_link(queue1,fsink1); } else if (NULL!= sink0 && NULL!=sink1) { gst_bin_add_many (GST_BIN (bin), tee, sink0, sink1, queue0, queue1,NULL); gst_element_link (queue0, sink0); gst_element_link(queue1,sink1); } else { ret = FALSE; goto exit; } /*Connecting the tee through queues is necessary to sync the two displays*/ gst_element_link(tee,queue0); gst_element_link(tee,queue1); pad = gst_element_get_static_pad (tee, "sink"); gst_element_add_pad (bin, gst_ghost_pad_new ("sink", pad)); gst_object_unref (GST_OBJECT (pad)); g_object_set (G_OBJECT (pipePtr->pipe), "video-sink", bin, NULL); exit: return ret; } gboolean busCallback(GstBus *bus, GstMessage *msg, gpointer data) { gchar *name = (gchar *)data; gchar *debugMsg = NULL; GError *err = NULL; static int count = 0; switch(GST_MESSAGE_TYPE(msg)){ case GST_MESSAGE_EOS: g_printerr("%s -> Message (EOS) : End of stream.\n",name); count++; break; case GST_MESSAGE_ERROR: { gst_message_parse_error(msg,&err,&debugMsg); g_printerr("%s -> Message (ERROR) : %s : debug ( %s )\n", name,err->message,debugMsg); g_free(debugMsg); g_error_free(err); count++; break; } case GST_MESSAGE_WARNING: { gst_message_parse_warning(msg,&err,&debugMsg); g_printerr("%s -> Message (WARNING) : %s : debug ( %s )\n", name,err->message,debugMsg); g_free(debugMsg); g_error_free(err); break; } default: break; } return TRUE; } static void getTime (gint64 arr[], gint64 time) { gint8 i = 0; time = time / (gint64) NANOSEC; for (i = 0; i < 3; i++){ arr[i] = time % 60; time = time / 60; } } /***************************************************************************** Public Functions ******************************************************************************/ Pipeline * DualDecode_createPipeline() { Pipeline *pipelinePtr = (Pipeline *) malloc (sizeof(Pipeline)); pipelinePtr->pipe = NULL; GstBus *bus = NULL; pipelinePtr->pipe = gst_element_factory_make("playbin2",NULL); bus = gst_pipeline_get_bus (GST_PIPELINE(pipelinePtr->pipe)); pipelinePtr->busSignal = gst_bus_add_watch (bus,busCallback, NULL); gst_object_unref (bus); pipelinePtr->logFunc = NULL; return pipelinePtr; } gboolean DualDecode_setSinksForPipes (Pipeline **pipes,GstElement *sink0, GstElement *sink1) { gboolean ret = TRUE; attachPipeElements (pipes[0], sink0, NULL); attachPipeElements (pipes[1], sink1, NULL); return ret; } gboolean DualDecode_seekMedia(Pipeline *pipePtr, gint64 position) { if(position < 0){ return FALSE; } return gst_element_seek_simple(pipePtr->pipe, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT, position); } gboolean DualDecode_pauseMedia (Pipeline *pipePtr) { gboolean ret = TRUE; GstStateChangeReturn stateReturn; if (GST_STATE_CHANGE_ASYNC == gst_element_set_state (pipePtr->pipe, GST_STATE_PAUSED)){ g_print ("STATE CHANGE RETURNED ASYNC \n"); stateReturn = gst_element_get_state (pipePtr->pipe, NULL, NULL, TIMEOUT); g_print ("GET STATE RETURNED %s\n", gst_element_state_change_return_get_name (stateReturn)); } return ret; } gboolean DualDecode_resumeMedia (Pipeline *pipePtr) { gboolean ret = TRUE; if(!gst_element_set_state (pipePtr->pipe, GST_STATE_PLAYING)) ret = FALSE; g_print ("IN RESUME MEDIA\n"); return ret; } gboolean DualDecode_stopMedia (Pipeline *pipePtr) { gboolean ret = TRUE; if(!gst_element_set_state (pipePtr->pipe, GST_STATE_NULL)) ret = FALSE; return ret; } gboolean DualDecode_setLogFunction (Pipeline *pipePtr, LogFunc func, gpointer data) { gboolean ret = TRUE; return ret; } GstState DualDecode_getMediaState(Pipeline *pipePtr) { GstState state, pending; g_print ("IN GET MEDIA STATE ENTRY\n"); if(GST_STATE_CHANGE_SUCCESS != gst_element_get_state( pipePtr->pipe, &state, &pending, GST_CLOCK_TIME_NONE)){ /*TODO : a bug here*/ g_printerr("No state in GstElement\n"); } g_print("EXITING FROM GET MEDIA STATE\n"); return state; } gboolean DualDecode_getMediaPosition (Pipeline *pipePtr, gdouble *seekScaleValue, gchar **timeLabelText) { gboolean ret = TRUE; gint64 position = 0, duration = 0; gint64 pos[3], dur[3]; GstFormat format = GST_FORMAT_TIME; if (TRUE == gst_element_query_position (pipePtr->pipe, &format, &position) && (TRUE == gst_element_query_duration (pipePtr->pipe, &format, &duration))) { getTime (pos, position); getTime (dur, duration); *timeLabelText = g_strdup_printf ("%ld:%ld:%ld/%ld:%ld:%ld", pos[HH], pos[MM], pos[SS], dur[HH], dur[MM], dur[SS]); if (duration) *seekScaleValue = (gdouble)position/ (gdouble)duration * 100; } else ret = FALSE; return ret; } void DualDecode_setPipelineSink (Pipeline *pipePtr, GstElement *sink0, GstElement *sink1) { g_print ("IN SET PIPE IN SINGLE MODE"); attachPipeElements (pipePtr, sink0, sink1); } gboolean DualDecode_playMedia (Pipeline *pipePtr, gchar *filename, gint64 position) { gboolean ret = TRUE; g_print ("IN PLAYMEDIA2"); g_object_set(G_OBJECT(pipePtr->pipe),"uri", filename,NULL); gst_element_set_state (pipePtr->pipe, GST_STATE_NULL); gst_element_set_state (pipePtr->pipe, GST_STATE_PLAYING); DualDecode_getMediaState(pipePtr); DualDecode_seekMedia(pipePtr, position); return ret; } gboolean DualDecode_singleToDual (Pipeline **pipes,GstElement * otherWindowSink, gint thisWindow, gint otherWindow, gchar *filename) { gboolean ret = TRUE; GstElement *thisbin = NULL; GstElement *otherbin = NULL; GstElement *fsink = NULL; GstElement *queue0 = NULL; GstElement *queue1 = NULL; GstState state0 = NULL; gst_element_get_state( pipes[thisWindow]->pipe, &state0, NULL, GST_CLOCK_TIME_NONE); /*Remove otherWindowsink from this pipeline*/ g_object_get (G_OBJECT (pipes[thisWindow]->pipe),"video-sink", &thisbin,NULL); queue1 = gst_bin_get_by_name (GST_BIN (thisbin), "q1"); gst_element_unlink (queue1, otherWindowSink); gst_object_ref (otherWindowSink); gst_bin_remove (GST_BIN (thisbin), otherWindowSink); /*Remove a fake sink from the other pipeline*/ g_object_get (G_OBJECT (pipes[otherWindow]->pipe), "video-sink", &otherbin, NULL); queue0 = gst_bin_get_by_name (GST_BIN (otherbin), "q0"); fsink = gst_bin_get_by_name (GST_BIN (otherbin), "fsink0"); gst_element_unlink (queue0, fsink); gst_object_ref (fsink); gst_bin_remove (GST_BIN (otherbin), fsink); /*Add fakesink to this pipeline*/ gst_bin_add (GST_BIN (thisbin), fsink); gst_element_sync_state_with_parent (fsink); gst_element_link (queue1, fsink); /* Add otherWindowSink to other pipeline */ gst_element_set_state (otherWindowSink, GST_STATE_READY); gst_bin_add (GST_BIN (otherbin), otherWindowSink); gst_element_link (queue0, otherWindowSink); DualDecode_playMedia (pipes[otherWindow], filename, 0); gst_element_set_state (pipes[thisWindow]->pipe, state0); return ret; } gboolean DualDecode_dualToSingle (Pipeline **pipes,GstElement * otherWindowSink, gint thisWindow, gint otherWindow) { gboolean ret = TRUE; GstElement *bin = NULL; GstElement *bin2 = NULL; GstElement *fsink = NULL; GstElement *fsink0 = NULL; GstElement *queue0 = NULL; GstElement *queue1 = NULL; gchar *name = NULL; /*Remove otherWindow sink from other pipeline*/ gst_element_set_state (pipes[otherWindow]->pipe, GST_STATE_PAUSED); g_object_get (G_OBJECT (pipes[otherWindow]->pipe), "video-sink", &bin2, NULL); queue0 = gst_bin_get_by_name (GST_BIN (bin2), "q0"); gst_element_unlink (queue0, otherWindowSink); gst_object_ref (otherWindowSink); gst_bin_remove (GST_BIN (bin2), otherWindowSink); /*Remove fake sink from this pipeline*/ g_object_get (G_OBJECT (pipes[thisWindow]->pipe), "video-sink", &bin, NULL); queue1 = gst_bin_get_by_name (GST_BIN (bin), "q1"); fsink = gst_bin_get_by_name (GST_BIN (bin), "fsink0"); if (NULL == fsink) fsink = gst_bin_get_by_name (GST_BIN (bin), "fsink1"); name = gst_element_get_name(fsink); gst_element_unlink (queue1, fsink); gst_object_ref (fsink); gst_bin_remove (GST_BIN (bin),fsink); gst_element_set_state (otherWindowSink, GST_STATE_READY); /*Add fake sink to other pipeline */ gst_bin_add (GST_BIN (bin2), fsink); gst_element_sync_state_with_parent (fsink); if (!g_strcmp0 (name, "fsink0")){ g_print ("NAME IS fsink0\n"); gst_element_link (queue0, fsink); } else if (!g_strcmp0 (name, "fsink1")){ g_print ("NAME IS fsink1\n"); fsink0 = gst_bin_get_by_name (GST_BIN (bin2), "fsink0"); queue1 = gst_bin_get_by_name (GST_BIN (bin2), "q1"); gst_element_unlink (queue1, fsink0); gst_element_link (queue1, fsink); gst_element_link (queue0, fsink0); } g_free (name); /*Add otherWindowSink to this pipeline*/ gst_bin_add (GST_BIN (bin), otherWindowSink); gst_element_sync_state_with_parent (otherWindowSink); gst_element_link (queue1, otherWindowSink); return ret; }