diff --git a/src/gst-controller.c b/src/gst-controller.c
index 2188a372d8657c3dc862085922c7408180a28765..37d63714b59ccda50c3d0973506abdfb24b621be 100644 (file)
--- a/src/gst-controller.c
+++ b/src/gst-controller.c
/*
- * Copyright (c) 2010-2011, Texas Instruments Incorporated
+ * 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
/**
* @file gst-controller.c
*
- * @brief
+ * @brief Imeplements GStreamer related functions
*/
#include <stdint.h>
#include <string.h>
#include <gst/gst.h>
-#include <gtk/gtk.h>
-#include <gdk/gdkx.h>
-#include <gst/interfaces/xoverlay.h>
#include "gst-controller.h"
-/*GMainLoop *loop;
-int processDecode (gchar ** files)
-{
- gint i;
- gint fileCount = 0;
- gint retVal = 1;
- g_print("In process decode\n");
- if (NULL == files) {
- g_print ("Input files not specified\n");
- exit(1);
- }
- for(i = 0; files[i] != NULL; i++){
- g_print("In init decode %s\n", files[i]);
- }*/
-
- /*Count files*/
- /*for (i = 0; NULL != files[i++]; fileCount++);
-
- switch (fileCount) {
- case 1:
- g_print ("Single Decode\n");
- setupGst (files, SINGLE);
- g_main_loop_run(loop);
- break;
- case 2:
- g_print ("Dual Decode\n");
- setupGst (files, DUAL);
- g_main_loop_run(loop);
- break;
- }
- return retVal;
-
-}
+gchar * fsinkArr [] = {"fsink0", "fsink1"};
+static gint fsinkCounter = 0;
+static void getTime (gint64 arr[], gint64 time);
+/******************************************************************************
+
+ Static Functions
-int initGstController ()
-{
- gint retVal = 1;
- gst_init(NULL,NULL);
- loop = g_main_loop_new(NULL,FALSE);
- return retVal;
-}
-
-GstElement *createPipe()
-{
- GstElement *pipeline = NULL; */
-
- /*create the pipeline. This will be returned to the caller function*/
- /*pipeline = gst_element_factory_make("playbin2","pipeline");
- if(!pipeline){
- g_print("Playbin Element Creation Failed.\n");
- }
-
- return pipeline;
-}
-
-int setupGst (gchar **files, int decode)
-{
- gint i = 0;
- gint retVal = 1;
- GstElement *bin = NULL;
- GstElement *tee = NULL;
- GstElement *queue0 = NULL;
- GstElement *queue1 = NULL;
- GstElement *sink0 = NULL;
- GstElement *sink1 = NULL;
- GstPad *pad = NULL;
-
- for ( i = 0; i < decode; i++)
- {
- pipelines[i] = createPipe(); */
- /**
- * Create a message handler to the bus of the pipeline.
- * messages will be emitted to the application from the bus when there is an
- * error or warning, or when the stream is complete. The application can then
- * be clo
-
-
-
-sed if the message is handled.
- */
- /*g_object_set(G_OBJECT(pipelines[i]),"uri", *files,NULL);
-
-
- if (SINGLE == decode) { */
- /*The two xvimagesinks are put inside a bin. They are connected to a */
- /*tee via two queues. The tee is connected to a ghost sink pad which */
- /*makes the bin a sink element. The bin can then serve as a video-sink */
- /*element for the pipeline */
-
- /*bin = gst_bin_new ("vsinkbin");
- sink0 = gst_element_factory_make ("xvimagesink","disp0");
- sink1 = gst_element_factory_make ("xvimagesink","disp1");
- tee = gst_element_factory_make ("tee","splitter");
- queue0 = gst_element_factory_make ("queue","q0");
- queue1 = gst_element_factory_make ("queue","q1");
- gst_bin_add_many (GST_BIN (bin), tee, sink0, sink1, queue0, queue1,NULL);
- */
- /*connecting the tee through queues is necessary to sync the two displays*/
- /*gst_element_link(tee,queue0);
- gst_element_link(tee,queue1);
- gst_element_link(queue0,sink0);
- gst_element_link(queue1,sink1);
-
- 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(pipelines[i]), "video-sink", bin, NULL);
- }
- else if (DUAL == decode) {
- *files++;
- }
- gst_element_set_state (pipelines[i], GST_STATE_PLAYING);
-
-
- bus = gst_pipeline_get_bus (GST_PIPELINE(pipelines[i]));
- gst_bus_add_watch (bus,busCallback,loop);
- gst_object_unref (bus);
- }
- return retVal;
-} */
-GstElement * createImageSinkFromWindow(GtkWidget *window,gchar *name)
-{
- GstElement *sink = NULL;
- XID xid = 0;
- GdkDrawable *drawable = NULL;
-
- /*make an xvimagesink element from factory*/
- /*TODO : hard coded strings. will change*/
- sink = gst_element_factory_make("xvimagesink",name);
- if(NULL == sink){
- goto return_pos;
- }
-
- /*get the XID of the display window's drawable*/
- drawable = gtk_widget_get_window (GTK_WIDGET (window));
- if(FALSE == GDK_IS_DRAWABLE(drawable)){
- /*TODO: A BUG HERE?*/
- g_object_unref(G_OBJECT(sink));
- sink=NULL;
- goto return_pos;
- }
- xid = gdk_x11_drawable_get_xid(drawable);
-
- /*link the gst sink element to the XID*/
- gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (sink),xid);
-
-return_pos:
- return sink;
-}
-
-gboolean attachPipeElements (Pipeline *pipePtr, GtkWidget *drawArea1,
- GtkWidget *drawArea2)
+******************************************************************************/
+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;
- GstElement *sink0 = NULL;
- GstElement *sink1 = NULL;
GstPad *pad = NULL;
-
- if (NULL != drawArea2) {
- bin = gst_bin_new ("vsinkbin");
- tee = gst_element_factory_make ("tee","splitter");
- sink0 = createImageSinkFromWindow (drawArea1, "sink0");
- queue0 = gst_element_factory_make ("queue","q0");
- sink1 = createImageSinkFromWindow (drawArea2, "sink1");
- queue1 = gst_element_factory_make ("queue","q1");
-
- if ( !bin || !tee || !sink0 || !sink1 || !queue0 || !queue1) {
- ret = FALSE;
- goto exit;
- }
-
- gst_bin_add_many (GST_BIN (bin), tee, sink0, sink1, queue0, queue1,NULL);
-
- /*Connecting the tee through queues is necessary to sync the two displays*/
- gst_element_link(tee,queue0);
- gst_element_link(tee,queue1);
- gst_element_link(queue0,sink0);
- gst_element_link(queue1,sink1);
-
- 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), "video-sink", bin, NULL);
- }
- else {
-
- sink0 = createImageSinkFromWindow (drawArea1, "sink0");
- if (!sink0){
- ret = FALSE;
- goto exit;
+ bin = gst_bin_new ("vsinkbin");
+ tee = gst_element_factory_make ("tee","splitter");
+ 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;
}
- g_object_set (G_OBJECT (pipePtr), "video-sink", sink0, NULL);
+ 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)
+
+static gboolean busCallback (GstBus *bus, GstMessage *msg, gpointer data)
{
gchar *name = (gchar *)data;
gchar *debugMsg = NULL;
GError *err = NULL;
- static int count = 0;
+ static int count = 0;
- switch(GST_MESSAGE_TYPE(msg)){
+ switch (GST_MESSAGE_TYPE(msg)) {
- case GST_MESSAGE_EOS:
- g_printerr("%s -> Message (EOS) : End of stream.\n",name);
- count++;
- break;
+ 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",
+ 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;
+ g_free(debugMsg);
+ g_error_free(err);
+ break;
}
default:
}
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
+
+******************************************************************************/
+
+
+/*****************************************************************************
+* see gst-controller.h
+******************************************************************************/
Pipeline * DualDecode_createPipeline()
{
Pipeline *pipelinePtr = (Pipeline *) malloc (sizeof(Pipeline));
GstBus *bus = NULL;
- pipelinePtr->pipe = gst_element_factory_make("playbin2",NULL);
- bus = gst_pipeline_get_bus (GST_PIPELINE(pipelinePtr));
+ 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->func = NULL;
+ pipelinePtr->logFunc = NULL;
return pipelinePtr;
}
-gboolean DualDecode_playMedia (Pipeline *pipePtr, gchar *filename, gint position,
- GtkWidget *drawArea1, GtkWidget *drawArea2)
+gboolean DualDecode_setSinksForPipes (Pipeline **pipes, GstElement *sink0,
+ GstElement *sink1)
{
gboolean ret = TRUE;
-
- g_object_set(G_OBJECT(pipePtr),"uri", filename,NULL);
- if (!(attachPipeElements (pipePtr, drawArea1, drawArea2))) {
- ret = FALSE;
- goto exit;
- }
- gst_element_set_state (pipePtr->pipe, GST_STATE_PLAYING);
-
-
-exit: return ret;
+ 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;
- if(!gst_element_set_state (pipePtr->pipe, GST_STATE_PAUSED))
- ret = FALSE;
+ 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))
+ 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))
+ 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 ("%" G_GINT64_FORMAT ":\
+ %" G_GINT64_FORMAT ":%" G_GINT64_FORMAT "/\
+ %" G_GINT64_FORMAT ":%" G_GINT64_FORMAT ":%" G_GINT64_FORMAT "",
+ 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 = GST_STATE_NULL;
+ GstFormat format = GST_FORMAT_TIME;
+ gint64 position = 0;
+
+
+ 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);
+
+
+ /* Get position of the media */
+ gst_element_query_position (otherWindowSink, &format, &position);
+
+ /* 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, position);
+ 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;
+}