From 0ee56888a8a9286caaae22e72fb559ebfdcb8bea Mon Sep 17 00:00:00 2001 From: Erik Walthinsen Date: Sun, 31 Dec 2000 10:46:16 +0000 Subject: [PATCH] Complete rewrite of the launcher. Now supports pretty arbitrary pipelines. Original commit message from CVS: Complete rewrite of the launcher. Now supports pretty arbitrary pipelines. Try '((fakesrc) ! identity ! (fakesink))' out. Doesn't seem to recognize pad names yet for some reason, so it goes with the first sink/src pad it finds in a given element. Other problems still remain, but the hard part is done with. --- tools/gstreamer-launch.c | 319 +++++++++++++++++++++++++++++++-------- 1 file changed, 255 insertions(+), 64 deletions(-) diff --git a/tools/gstreamer-launch.c b/tools/gstreamer-launch.c index 932c5e7e64..02d2fa4030 100644 --- a/tools/gstreamer-launch.c +++ b/tools/gstreamer-launch.c @@ -19,75 +19,268 @@ void launch_newpad(GstElement *element,GstPad *pad,launch_delayed_pad *peer) { } } -void parse(int argc,char *argv[],GstElement *parent,gint offset,gchar endchar) { - gint i = offset; - gchar *plugin; - GstElement *element = NULL, *prevelement; - GstPad *prevpad = NULL,*nextpad; - gchar *prevpadname = NULL,*nextpadname = NULL; - gchar *ptr; +// element ! [ element ! (element ! element )] ! element +// 0 1 2 3 4 5 6 7 8 9 10 11 +// 0 1 2 3 4 5 8 +// 0 1 2 3 6 + +guint bincount = 0; +guint threadcount = 0; +GHashTable *elementcounts; + +gchar *unique_name(gchar *type) { + gint count; + + count = GPOINTER_TO_INT(g_hash_table_lookup(elementcounts,type)); + count++; + g_hash_table_insert(elementcounts,type,GINT_TO_POINTER(count)); + + return g_strdup_printf("%s%d",type,count-1); +} + +gint parse_cmdline(int argc,char *argv[],GstBin *parent) { + gint i = 0; + gchar *arg; + GstElement *element = NULL, *prevelement = NULL, *prevprevelement = NULL; + gchar closingchar; gint len; - launch_delayed_pad *delayed; + gchar *ptr; + gchar *sinkpadname = NULL, *srcpadname = NULL; + GstPad *sinkpad = NULL, *srcpad = NULL; + GList *pads; + gint elementcount = 0; + gint retval = 0; - gst_info("at offset %d, argc is %d\n",i,argc); + if (GST_IS_PIPELINE(parent)) closingchar = '\0',fprintf(stderr,"in pipeline "); + else if (GST_IS_THREAD(parent)) closingchar = '}',fprintf(stderr,"in thread "); + else closingchar = ')',fprintf(stderr,"in bin "); + fprintf(stderr,"%s\n",gst_element_get_name (GST_ELEMENT (parent))); - // loop through all the arguments while (i < argc) { - // first is the plugin name - plugin = argv[i++]; - gst_info("plugin is \"%s\"\n",plugin); - // record previous element - prevelement = element; - // create the element and add it to the parent - element = gst_elementfactory_make(plugin,plugin); - gst_bin_add(GST_BIN(parent),element); - // connect it to the previous if there is one - if (nextpadname != NULL) { - // grab the pad of this element - nextpad = gst_element_get_pad(element,nextpadname); - g_return_if_fail(nextpad != NULL); - // check to see if the pad exists yet, connect it if it does - if (prevpad != NULL) { - gst_pad_connect(prevpad,nextpad); - gst_info("wired '%s' to '%s'\n", - gst_pad_get_name(prevpad),gst_pad_get_name(nextpad)); + arg = argv[i]; + len = strlen(arg); + element = NULL; + fprintf(stderr,"** ARGUMENT is '%s'\n",arg); + + // a null that slipped through the reconstruction + if (len == 0) { + fprintf(stderr,"random arg, FIXME\n"); + i++; + continue; + + // end of the container + } else if (arg[0] == closingchar) { + // time to finish off this bin + fprintf(stderr,"exiting container %s\n",gst_element_get_name (GST_ELEMENT (parent))); + retval = i+1; + break; + + // a pad connection + } else if ((ptr = strchr(arg,'!'))) { + fprintf(stderr,"attempting to connect pads together....\n"); + + // if it starts with the ! + if (arg[0] == '!') { + srcpadname = NULL; + // if there's a sinkpad... + if (len > 1) + sinkpadname = &arg[1]; + else + sinkpadname = NULL; + } else { + srcpadname = g_strndup(arg,(ptr-arg)); + // if there's a sinkpad + if (len > (ptr-arg)+1) + sinkpadname = &ptr[1]; + else + sinkpadname = NULL; } - // otherwise we have to attach and wait for it to show - else { - delayed = g_new0(launch_delayed_pad,1); - delayed->name = prevpadname; - delayed->peer = nextpad; - gtk_signal_connect(GTK_OBJECT(prevelement),"new_pad", - launch_newpad,delayed); + + fprintf(stderr,"have sinkpad %s, srcpad %s\n",sinkpadname,srcpadname); + + srcpad = NULL; + + // if the srcpadname doesn't have any commas in it, find an actual pad + if (!srcpadname || !strchr(srcpadname,',')) { + if (srcpadname != NULL) + srcpad = gst_element_get_pad(prevelement,srcpadname); + + if (!srcpad) { + // check through the list to find the first sink pad + pads = gst_element_get_pad_list(prevelement); + while (pads) { + srcpad = GST_PAD(pads->data); + pads = g_list_next (pads); + if (gst_pad_get_direction (srcpad) == GST_PAD_SRC) break; + srcpad = NULL; + } + } + + if (!srcpad) fprintf(stderr,"error, can't find a src pad!!!\n"); + else fprintf(stderr,"have src pad %s:%s\n",GST_DEBUG_PAD_NAME(srcpad)); + } + + // element, or beginning of bin or thread + } else { + fprintf(stderr,"have element or bin/thread\n"); + // if we have a bin or thread starting + if (strchr("({",arg[0])) { + if (arg[0] == '(') + // create a bin and add it to the current parent + element = gst_bin_new(g_strdup_printf("bin%d",bincount++)); + else if (arg[0] == '{') + // create a thread and add it to the current parent + element = gst_thread_new(g_strdup_printf("thread%d",threadcount++)); + + i += parse_cmdline(argc - i, argv + i + 1, GST_BIN (element)); + + // else we have an element + } else { + fprintf(stderr,"attempting to create element '%s'\n",arg); + element = gst_elementfactory_make(arg,unique_name(arg)); + fprintf(stderr,"created element %s\n",gst_element_get_name(element)); + } + + gst_bin_add (GST_BIN (parent), element); + elementcount++; + + if (srcpad != NULL) { + fprintf(stderr,"need to connect to sinkpad %s:%s\n",GST_DEBUG_PAD_NAME(srcpad)); + + sinkpad = NULL; + + if (sinkpadname != NULL) + sinkpad = gst_element_get_pad(prevelement,sinkpadname); + + if (!sinkpad) { + // check through the list to find the first sink pad + pads = gst_element_get_pad_list(element); + while (pads) { + sinkpad = GST_PAD(pads->data); + pads = g_list_next (pads); + if (gst_pad_get_direction (sinkpad) == GST_PAD_SINK) break; + sinkpad = NULL; + } + } + + if (!sinkpad) fprintf(stderr,"error, can't find a sink pad!!!\n"); + else fprintf(stderr,"have sink pad %s:%s\n",GST_DEBUG_PAD_NAME(sinkpad)); + + fprintf(stderr,"CONNECTING %s:%s and %s:%s\n",GST_DEBUG_PAD_NAME(srcpad),GST_DEBUG_PAD_NAME(sinkpad)); + gst_pad_connect(srcpad,sinkpad); + + sinkpad = NULL; + srcpad = NULL; + } + + // if we're the first element, ghost all the sinkpads + if (elementcount == 1) { + fprintf(stderr,"first element, ghosting all of %s's sink pads to parent %s\n", + gst_element_get_name(element),gst_element_get_name(GST_ELEMENT(parent))); + pads = gst_element_get_pad_list (element); + while (pads) { + sinkpad = GST_PAD (pads->data); + pads = g_list_next (pads); + if (!sinkpad) fprintf(stderr,"much oddness, pad doesn't seem to exist\n"); + else if (gst_pad_get_direction (sinkpad) == GST_PAD_SINK) { + gst_element_add_ghost_pad (GST_ELEMENT (parent), sinkpad); + fprintf(stderr,"ghosted %s:%s\n",GST_DEBUG_PAD_NAME(sinkpad)); + } + } } } - // then come all the other things - while (i < argc) { - // snag the length in advance; - len = strlen(argv[i]); - // if it's just a connection, pick the 'src' pad and move on - if ((ptr = strchr(argv[i],'!')) != 0) { - // if there's a previous pad name - if (ptr != argv[i]) { - ptr[0] = '\0'; - prevpadname = argv[i]; - prevpad = gst_element_get_pad(element,prevpadname); - } else - prevpad = gst_element_get_pad(element,"src"); - // if there's a next pad name - if (((ptr - argv[i]) + 1) < len) { - nextpadname = ptr + 1; - } else - nextpadname = "sink"; - i++; - break; - } else { - gst_info("have unknown argument '%s'\n",argv[i]); - gtk_object_set(GTK_OBJECT(element),"location",argv[i],NULL); - i++; + + i++; + prevelement = element; + } + + // ghost all the src pads of the bin + if (prevelement != NULL) { + fprintf(stderr,"last element, ghosting all of %s's src pads to parent %s\n", + gst_element_get_name(prevelement),gst_element_get_name(GST_ELEMENT(parent))); + pads = gst_element_get_pad_list (prevelement); + while (pads) { + srcpad = GST_PAD (pads->data); + pads = g_list_next (pads); + if (!srcpad) fprintf(stderr,"much oddness, pad doesn't seem to exist\n"); + else if (gst_pad_get_direction (srcpad) == GST_PAD_SRC) { + gst_element_add_ghost_pad (GST_ELEMENT (parent), srcpad); + fprintf(stderr,"ghosted %s:%s\n",GST_DEBUG_PAD_NAME(srcpad)); } } } + + if (retval) return retval; + + if (closingchar != '\0') + fprintf(stderr,"returning IN THE WRONG PLACE\n"); + else fprintf(stderr,"ending pipeline\n"); + return i+1; +} + +gint parse(int argc,char *argv[],GstBin *parent) { + char **argvn; + gchar *cmdline; + gint newargc; + gint len; + int i,j,k; + + // make a null-terminated version of argv + argvn = g_new0(char *,argc+1); + memcpy(argvn,argv,sizeof(char*)*argc); + // join the argvs together + cmdline = g_strjoinv(" ",argvn); + // free the null-terminated argv + g_free(argvn); + + // first walk through quickly and see how many more slots we need + len = strlen(cmdline); + newargc = 1; + for (i=0;i 0) { + if (cmdline[k] == ' ') k++; + argvn[j] = g_new0(char,(i-k)+1); + memcpy(argvn[j],&cmdline[k],i-k); + j++; + } + k = i; + + // if this is a bracket, construct a word + if ((cmdline[i] != ' ') && (cmdline[i] != '\0')) { + argvn[j++] = g_strdup_printf("%c",cmdline[i]); + k++; + } + } + } + + // print them out + for (i=0;i