1#!/bin/sh 2 3 4prefix=gst 5templatedir=element-templates 6 7while [ "$1" ] ; do 8 case $1 in 9 --help) 10 cat <<-EOF 11Usage: $(basename "$0") [OPTIONS] APP_NAME 12Create a GStreamer application from a template. 13Options: 14 --help Print this information 15 --prefix PREFIX Use PREFIX instead of "gst" 16Example: '$(basename "$0") my_app' will create the file gstmyapp.c. 17EOF 18 exit 0 19 ;; 20 --prefix) 21 shift 22 prefix=$1 23 ;; 24 -*) 25 echo Unknown option: $1 26 exit 1 27 ;; 28 *) 29 if [ "$name" = "" ]; then 30 name=$1 31 else 32 echo Ignored: $1 33 fi 34 esac 35 shift 36done 37 38if [ "$name" = "" ] ; then 39 echo "Usage: $(basename "$0") [OPTIONS] APP_NAME" 40 exit 1 41fi 42 43 44PREFIX=$(echo $prefix | sed -e 's/\(.*\)/\U\1/') 45NAME=$(echo $name | sed -e 's/\(.*\)/\U\1/') 46Prefix=$(echo $prefix | sed -e 's/_\(.\)/\U\1/g' -e 's/^\(.\)/\U\1/') 47Name=$(echo $name | sed -e 's/_\(.\)/\U\1/g' -e 's/^\(.\)/\U\1/') 48 49GST_IS_REPLACE=${PREFIX}_IS_${NAME} 50GST_REPLACE=${PREFIX}_${NAME} 51GST_TYPE_REPLACE=${PREFIX}_TYPE_${NAME} 52GstReplace=${Prefix}${Name} 53gst_replace=${prefix}_${name} 54gstreplace=${prefix}$(echo $name | sed -e 's/_//g') 55replace=$(echo $name | sed -e 's/_//g') 56 57if [ "$REAL_NAME" = "" ] ; then 58 REAL_NAME=FIXME 59fi 60if [ "$EMAIL_ADDRESS" = "" ] ; then 61 EMAIL_ADDRESS=fixme@example.com 62fi 63 64 65 66generate () 67{ 68 69cat <<-EOF 70/* GstReplace 71 * Copyright (C) $(date +%Y) $REAL_NAME <$EMAIL_ADDRESS> 72 * Copyright (C) 2010 Entropy Wave Inc 73 * 74 * Redistribution and use in source and binary forms, with or without 75 * modification, are permitted provided that the following conditions 76 * are met: 77 * 1. Redistributions of source code must retain the above copyright 78 * notice, this list of conditions and the following disclaimer. 79 * 2. Redistributions in binary form must reproduce the above copyright 80 * notice, this list of conditions and the following disclaimer in the 81 * documentation and/or other materials provided with the distribution. 82 * 83 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 84 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 85 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 86 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 87 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 88 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 89 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 90 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 91 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 92 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 93 * POSSIBILITY OF SUCH DAMAGE. 94 */ 95 96#ifdef HAVE_CONFIG_H 97#include "config.h" 98#endif 99 100#include <gst/gst.h> 101#include <stdlib.h> 102 103#define GETTEXT_PACKAGE "replace" 104 105 106typedef struct _GstReplace GstReplace; 107struct _GstReplace { 108 GstElement *pipeline; 109 GstBus *bus; 110 GMainLoop *main_loop; 111 112 GstElement *source_element; 113 GstElement *sink_element; 114 115 gboolean paused_for_buffering; 116 guint timer_id; 117}; 118 119GstReplace * gst_replace_new (void); 120void gst_replace_free (GstReplace *replace); 121void gst_replace_create_pipeline (GstReplace *replace); 122void gst_replace_create_pipeline_playbin (GstReplace *replace, const char *uri); 123void gst_replace_start (GstReplace *replace); 124void gst_replace_stop (GstReplace *replace); 125 126static gboolean gst_replace_handle_message (GstBus *bus, GstMessage *message, 127 gpointer data); 128static gboolean onesecond_timer (gpointer priv); 129 130 131gboolean verbose; 132 133static GOptionEntry entries[] = 134{ 135 { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Be verbose", NULL }, 136 137 { NULL } 138 139}; 140 141int 142main (int argc, char *argv[]) 143{ 144 GError *error = NULL; 145 GOptionContext *context; 146 GstReplace *replace; 147 GMainLoop *main_loop; 148 149 context = g_option_context_new ("- FIXME"); 150 g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); 151 g_option_context_add_group (context, gst_init_get_option_group ()); 152 if (!g_option_context_parse (context, &argc, &argv, &error)) { 153 g_print ("option parsing failed: %s\n", error->message); 154 g_clear_error (&error); 155 g_option_context_free (context); 156 exit (1); 157 } 158 g_option_context_free (context); 159 160 replace = gst_replace_new (); 161 162 if (argc > 1) { 163 gchar *uri; 164 if (gst_uri_is_valid (argv[1])) { 165 uri = g_strdup (argv[1]); 166 } else { 167 uri = g_filename_to_uri (argv[1], NULL, NULL); 168 } 169 gst_replace_create_pipeline_playbin (replace, uri); 170 g_free (uri); 171 } else { 172 gst_replace_create_pipeline (replace); 173 } 174 175 gst_replace_start (replace); 176 177 main_loop = g_main_loop_new (NULL, TRUE); 178 replace->main_loop = main_loop; 179 180 g_main_loop_run (main_loop); 181 182 exit (0); 183} 184 185 186GstReplace * 187gst_replace_new (void) 188{ 189 GstReplace *replace; 190 191 replace = g_new0 (GstReplace, 1); 192 193 return replace; 194} 195 196void 197gst_replace_free (GstReplace *replace) 198{ 199 if (replace->source_element) { 200 gst_object_unref (replace->source_element); 201 replace->source_element = NULL; 202 } 203 if (replace->sink_element) { 204 gst_object_unref (replace->sink_element); 205 replace->sink_element = NULL; 206 } 207 208 if (replace->pipeline) { 209 gst_element_set_state (replace->pipeline, GST_STATE_NULL); 210 gst_object_unref (replace->pipeline); 211 replace->pipeline = NULL; 212 } 213 g_free (replace); 214} 215 216void 217gst_replace_create_pipeline_playbin (GstReplace *replace, const char *uri) 218{ 219 GstElement *pipeline; 220 GError *error = NULL; 221 222 pipeline = gst_pipeline_new (NULL); 223 gst_bin_add (GST_BIN(pipeline), 224 gst_element_factory_make ("playbin", "source")); 225 226 if (error) { 227 g_print("pipeline parsing error: %s\n", error->message); 228 g_clear_error (&error); 229 gst_object_unref (pipeline); 230 return; 231 } 232 233 replace->pipeline = pipeline; 234 235 gst_pipeline_set_auto_flush_bus (GST_PIPELINE(pipeline), FALSE); 236 replace->bus = gst_pipeline_get_bus (GST_PIPELINE(pipeline)); 237 gst_bus_add_watch (replace->bus, gst_replace_handle_message, replace); 238 239 replace->source_element = gst_bin_get_by_name (GST_BIN(pipeline), "source"); 240 g_print("source_element is %p\n", replace->source_element); 241 242 g_print("setting uri to %s\n", uri); 243 g_object_set (replace->source_element, "uri", uri, NULL); 244} 245 246void 247gst_replace_create_pipeline (GstReplace *replace) 248{ 249 GString *pipe_desc; 250 GstElement *pipeline; 251 GError *error = NULL; 252 253 pipe_desc = g_string_new (""); 254 255 g_string_append (pipe_desc, "videotestsrc name=source num-buffers=100 ! "); 256 g_string_append (pipe_desc, "timeoverlay ! "); 257 g_string_append (pipe_desc, "xvimagesink name=sink "); 258 g_string_append (pipe_desc, "audiotestsrc samplesperbuffer=1600 num-buffers=100 ! "); 259 g_string_append (pipe_desc, "alsasink "); 260 261 if (verbose) g_print ("pipeline: %s\n", pipe_desc->str); 262 263 pipeline = (GstElement *) gst_parse_launch (pipe_desc->str, &error); 264 g_string_free (pipe_desc, FALSE); 265 266 if (error) { 267 g_print("pipeline parsing error: %s\n", error->message); 268 g_clear_error (&error); 269 gst_object_unref (pipeline); 270 return; 271 } 272 273 replace->pipeline = pipeline; 274 275 gst_pipeline_set_auto_flush_bus (GST_PIPELINE(pipeline), FALSE); 276 replace->bus = gst_pipeline_get_bus (GST_PIPELINE(pipeline)); 277 gst_bus_add_watch (replace->bus, gst_replace_handle_message, replace); 278 279 replace->source_element = gst_bin_get_by_name (GST_BIN(pipeline), "source"); 280 replace->sink_element = gst_bin_get_by_name (GST_BIN(pipeline), "sink"); 281} 282 283void 284gst_replace_start (GstReplace *replace) 285{ 286 gst_element_set_state (replace->pipeline, GST_STATE_READY); 287 288 replace->timer_id = g_timeout_add (1000, onesecond_timer, replace); 289} 290 291void 292gst_replace_stop (GstReplace *replace) 293{ 294 gst_element_set_state (replace->pipeline, GST_STATE_NULL); 295 296 g_source_remove (replace->timer_id); 297} 298 299static void 300gst_replace_handle_eos (GstReplace *replace) 301{ 302 gst_replace_stop (replace); 303} 304 305static void 306gst_replace_handle_error (GstReplace *replace, GError *error, 307 const char *debug) 308{ 309 g_print ("error: %s\n", error->message); 310 gst_replace_stop (replace); 311} 312 313static void 314gst_replace_handle_warning (GstReplace *replace, GError *error, 315 const char *debug) 316{ 317 g_print ("warning: %s\n", error->message); 318} 319 320static void 321gst_replace_handle_info (GstReplace *replace, GError *error, 322 const char *debug) 323{ 324 g_print ("info: %s\n", error->message); 325} 326 327static void 328gst_replace_handle_null_to_ready (GstReplace *replace) 329{ 330 gst_element_set_state (replace->pipeline, GST_STATE_PAUSED); 331 332} 333 334static void 335gst_replace_handle_ready_to_paused (GstReplace *replace) 336{ 337 if (!replace->paused_for_buffering) { 338 gst_element_set_state (replace->pipeline, GST_STATE_PLAYING); 339 } 340} 341 342static void 343gst_replace_handle_paused_to_playing (GstReplace *replace) 344{ 345 346} 347 348static void 349gst_replace_handle_playing_to_paused (GstReplace *replace) 350{ 351 352} 353 354static void 355gst_replace_handle_paused_to_ready (GstReplace *replace) 356{ 357 358} 359 360static void 361gst_replace_handle_ready_to_null (GstReplace *replace) 362{ 363 g_main_loop_quit (replace->main_loop); 364 365} 366 367 368static gboolean 369gst_replace_handle_message (GstBus *bus, GstMessage *message, 370 gpointer data) 371{ 372 GstReplace *replace = (GstReplace *) data; 373 374 switch (GST_MESSAGE_TYPE(message)) { 375 case GST_MESSAGE_EOS: 376 gst_replace_handle_eos (replace); 377 break; 378 case GST_MESSAGE_ERROR: 379 { 380 GError *error = NULL; 381 gchar *debug; 382 383 gst_message_parse_error (message, &error, &debug); 384 gst_replace_handle_error (replace, error, debug); 385 g_clear_error (&error); 386 } 387 break; 388 case GST_MESSAGE_WARNING: 389 { 390 GError *error = NULL; 391 gchar *debug; 392 393 gst_message_parse_warning (message, &error, &debug); 394 gst_replace_handle_warning (replace, error, debug); 395 g_clear_error (&error); 396 } 397 break; 398 case GST_MESSAGE_INFO: 399 { 400 GError *error = NULL; 401 gchar *debug; 402 403 gst_message_parse_info (message, &error, &debug); 404 gst_replace_handle_info (replace, error, debug); 405 g_clear_error (&error); 406 } 407 break; 408 case GST_MESSAGE_TAG: 409 { 410 GstTagList *tag_list; 411 412 gst_message_parse_tag (message, &tag_list); 413 if (verbose) g_print("tag\n"); 414 } 415 break; 416 case GST_MESSAGE_STATE_CHANGED: 417 { 418 GstState oldstate, newstate, pending; 419 420 gst_message_parse_state_changed (message, &oldstate, &newstate, 421 &pending); 422 if (GST_ELEMENT(message->src) == replace->pipeline) { 423 if (verbose) g_print("state change from %s to %s\n", 424 gst_element_state_get_name (oldstate), 425 gst_element_state_get_name (newstate)); 426 switch (GST_STATE_TRANSITION(oldstate, newstate)) { 427 case GST_STATE_CHANGE_NULL_TO_READY: 428 gst_replace_handle_null_to_ready (replace); 429 break; 430 case GST_STATE_CHANGE_READY_TO_PAUSED: 431 gst_replace_handle_ready_to_paused (replace); 432 break; 433 case GST_STATE_CHANGE_PAUSED_TO_PLAYING: 434 gst_replace_handle_paused_to_playing (replace); 435 break; 436 case GST_STATE_CHANGE_PLAYING_TO_PAUSED: 437 gst_replace_handle_playing_to_paused (replace); 438 break; 439 case GST_STATE_CHANGE_PAUSED_TO_READY: 440 gst_replace_handle_paused_to_ready (replace); 441 break; 442 case GST_STATE_CHANGE_READY_TO_NULL: 443 gst_replace_handle_ready_to_null (replace); 444 break; 445 default: 446 if (verbose) g_print("unknown state change from %s to %s\n", 447 gst_element_state_get_name (oldstate), 448 gst_element_state_get_name (newstate)); 449 } 450 } 451 } 452 break; 453 case GST_MESSAGE_BUFFERING: 454 { 455 int percent; 456 gst_message_parse_buffering (message, &percent); 457 //g_print("buffering %d\n", percent); 458 if (!replace->paused_for_buffering && percent < 100) { 459 g_print ("pausing for buffing\n"); 460 replace->paused_for_buffering = TRUE; 461 gst_element_set_state (replace->pipeline, GST_STATE_PAUSED); 462 } else if (replace->paused_for_buffering && percent == 100) { 463 g_print ("unpausing for buffing\n"); 464 replace->paused_for_buffering = FALSE; 465 gst_element_set_state (replace->pipeline, GST_STATE_PLAYING); 466 } 467 } 468 break; 469 case GST_MESSAGE_STATE_DIRTY: 470 case GST_MESSAGE_CLOCK_PROVIDE: 471 case GST_MESSAGE_CLOCK_LOST: 472 case GST_MESSAGE_NEW_CLOCK: 473 case GST_MESSAGE_STRUCTURE_CHANGE: 474 case GST_MESSAGE_STREAM_STATUS: 475 break; 476 case GST_MESSAGE_STEP_DONE: 477 case GST_MESSAGE_APPLICATION: 478 case GST_MESSAGE_ELEMENT: 479 case GST_MESSAGE_SEGMENT_START: 480 case GST_MESSAGE_SEGMENT_DONE: 481 case GST_MESSAGE_DURATION: 482 case GST_MESSAGE_LATENCY: 483 case GST_MESSAGE_ASYNC_START: 484 case GST_MESSAGE_ASYNC_DONE: 485 case GST_MESSAGE_REQUEST_STATE: 486 case GST_MESSAGE_STEP_START: 487 case GST_MESSAGE_QOS: 488 default: 489 if (verbose) { 490 g_print ("message: %s\n", GST_MESSAGE_TYPE_NAME (message)); 491 } 492 break; 493 } 494 495 return TRUE; 496} 497 498 499 500static gboolean 501onesecond_timer (gpointer priv) 502{ 503 //GstReplace *replace = (GstReplace *)priv; 504 505 g_print(".\n"); 506 507 return TRUE; 508} 509 510 511 512/* helper functions */ 513 514#if 0 515gboolean 516have_element (const gchar *element_name) 517{ 518 GstPluginFeature *feature; 519 520 feature = gst_default_registry_find_feature (element_name, 521 GST_TYPE_ELEMENT_FACTORY); 522 if (feature) { 523 g_object_unref (feature); 524 return TRUE; 525 } 526 return FALSE; 527} 528#endif 529 530EOF 531 532} 533 534generate | sed \ 535 -e "s/GST_BASE_REPLACE/$GST_BASE_REPLACE/g" \ 536 -e "s/GST_TYPE_BASE_REPLACE/$GST_TYPE_BASE_REPLACE/g" \ 537 -e "s/GstBaseReplace/$GstBaseReplace/g" \ 538 -e "s/GST_IS_REPLACE/$GST_IS_REPLACE/g" \ 539 -e "s/GST_REPLACE/$GST_REPLACE/g" \ 540 -e "s/GST_TYPE_REPLACE/$GST_TYPE_REPLACE/g" \ 541 -e "s/GstReplace/$GstReplace/g" \ 542 -e "s/gst_replace/$gst_replace/g" \ 543 -e "s/gstreplace/$gstreplace/g" \ 544 -e "s/replace/$replace/g" >$gstreplace.c 545 546gst-indent $gstreplace.c 547 548gcc -O2 -Wall $(pkg-config --cflags gstreamer-1.0) -c -o $gstreplace.o $gstreplace.c 549gcc -o $gstreplace $gstreplace.o $(pkg-config --libs gstreamer-1.0) 550 551 552