/* GStreamer * * Copyright (C) 2006 Edgard Lima <edgard dot lima at indt dot org dot br> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include <string.h> #include <stdio.h> #include <stdlib.h> #include <getopt.h> #include <gst/gst.h> #include <gst/interfaces/tuner.h> #include <gst/interfaces/colorbalance.h> #include <gst/interfaces/videoorientation.h> GstElement *pipeline, *source, *sink; GMainLoop *loop; volatile int exit_read = 0; static void print_options (void) { printf ("\nf - to change the fequency\n"); printf ("i - to change the input\n"); printf ("n - to change the norm\n"); printf ("c - list color balance\n"); printf ("v - change video orientarion\n"); printf ("e - to exit\n"); } static void run_options (char opt) { int res; switch (opt) { case 'f': { GstTuner *tuner = GST_TUNER (source); GstTunerChannel *channel; guint freq; channel = gst_tuner_get_channel (tuner); freq = gst_tuner_get_frequency (tuner, channel); printf ("\ntype the new frequency (current = %u) (-1 to cancel): ", freq); res = scanf ("%u", &freq); if (res != 1 || freq != -1) gst_tuner_set_frequency (tuner, channel, freq); } break; case 'n': { GstTuner *tuner = GST_TUNER (source); const GList *item, *list; const GstTunerNorm *current_norm; GstTunerNorm *norm = NULL; gint index, next_norm; list = gst_tuner_list_norms (tuner); current_norm = gst_tuner_get_norm (tuner); printf ("\nlist of norms:\n"); for (item = list, index = 0; item != NULL; item = item->next, ++index) { norm = item->data; if (current_norm == norm) { printf (" * %u - %s\n", index, norm->label); } else { printf (" %u - %s\n", index, norm->label); } } printf ("\ntype the number of norm you want (-1 to cancel): "); res = scanf ("%d", &next_norm); if (res != 1 || next_norm < 0) { break; } if (index <= next_norm) { printf ("Norm %d not available\n", next_norm); break; } for (item = list, index = 0; item != NULL && index <= next_norm; item = item->next, ++index) { norm = item->data; } if (norm) gst_tuner_set_norm (tuner, norm); } break; case 'i': { GstTuner *tuner = GST_TUNER (source); const GList *item, *list; const GstTunerChannel *current_channel; GstTunerChannel *channel = NULL; gint index, next_channel; list = gst_tuner_list_channels (tuner); current_channel = gst_tuner_get_channel (tuner); printf ("\nlist of inputs:\n"); for (item = list, index = 0; item != NULL; item = item->next, ++index) { channel = item->data; if (current_channel == channel) { printf (" * %u - %s\n", index, channel->label); } else { printf (" %u - %s\n", index, channel->label); } } printf ("\ntype the number of input you want (-1 to cancel): "); res = scanf ("%d", &next_channel); if (res != 1 || next_channel < 0) { break; } if (index <= next_channel) { printf ("Input %d not available\n", next_channel); break; } for (item = list, index = 0; item != NULL && index <= next_channel; item = item->next, ++index) { channel = item->data; } if (channel) gst_tuner_set_channel (tuner, channel); } break; case 'e': gst_element_set_state (pipeline, GST_STATE_NULL); g_main_loop_quit (loop); printf ("Bye\n"); g_thread_exit (0); break; case 'c': { GstColorBalance *balance = GST_COLOR_BALANCE (source); const GList *controls; GstColorBalanceChannel *channel; const GList *item; gint index, new_value; controls = gst_color_balance_list_channels (balance); printf ("\n"); if (controls == NULL) { printf ("There is no list of colorbalance controls\n"); goto done; } if (controls) { printf ("list of controls:\n"); for (item = controls, index = 0; item != NULL; item = item->next, ++index) { channel = item->data; printf (" %u - %s (%d - %d) = %d\n", index, channel->label, channel->min_value, channel->max_value, gst_color_balance_get_value (balance, channel)); } printf ("\ntype the number of color control you want (-1 to cancel): "); res = scanf ("%d", &new_value); if (res != 1 || new_value == -1) break; for (item = controls, index = 0; item != NULL && index <= new_value; item = item->next, ++index) { channel = item->data; } printf (" %u - %s (%d - %d) = %d, type the new value: ", index - 1, channel->label, channel->min_value, channel->max_value, gst_color_balance_get_value (balance, channel)); res = scanf ("%d", &new_value); if (res != 1 || new_value == -1) break; gst_color_balance_set_value (balance, channel, new_value); } } case 'v': { GstVideoOrientation *vidorient = GST_VIDEO_ORIENTATION (source); gboolean flip = FALSE; gint center = 0; printf ("\n"); if (gst_video_orientation_get_hflip (vidorient, &flip)) { gint new_value; printf ("Horizontal flip is %s\n", flip ? "on" : "off"); printf ("\ntype 1 to toggle (-1 to cancel): "); res = scanf ("%d", &new_value); if (res != 1 || new_value == 1) { flip = !flip; if (gst_video_orientation_set_hflip (vidorient, flip)) { gst_video_orientation_get_hflip (vidorient, &flip); printf ("Now horizontal flip is %s\n", flip ? "on" : "off"); } else { printf ("Error toggling horizontal flip\n"); } } else { } } else { printf ("Horizontal flip control not available\n"); } if (gst_video_orientation_get_vflip (vidorient, &flip)) { gint new_value; printf ("\nVertical flip is %s\n", flip ? "on" : "off"); printf ("\ntype 1 to toggle (-1 to cancel): "); res = scanf ("%d", &new_value); if (res != 1 || new_value == 1) { flip = !flip; if (gst_video_orientation_set_vflip (vidorient, flip)) { gst_video_orientation_get_vflip (vidorient, &flip); printf ("Now vertical flip is %s\n", flip ? "on" : "off"); } else { printf ("Error toggling vertical flip\n"); } } else { } } else { printf ("Vertical flip control not available\n"); } if (gst_video_orientation_get_hcenter (vidorient, ¢er)) { printf ("Horizontal center is %d\n", center); printf ("\ntype the new horizontal center value (-1 to cancel): "); res = scanf ("%d", ¢er); if (res != 1 || center != -1) { if (gst_video_orientation_set_hcenter (vidorient, center)) { gst_video_orientation_get_hcenter (vidorient, ¢er); printf ("Now horizontal center is %d\n", center); } else { printf ("Error setting horizontal center\n"); } } else { } } else { printf ("Horizontal center control not available\n"); } if (gst_video_orientation_get_vcenter (vidorient, ¢er)) { printf ("Vertical center is %d\n", center); printf ("\ntype the new vertical center value (-1 to cancel): "); res = scanf ("%d", ¢er); if (res != 1 || center != -1) { if (gst_video_orientation_set_vcenter (vidorient, center)) { gst_video_orientation_get_vcenter (vidorient, ¢er); printf ("Now vertical center is %d\n", center); } else { printf ("Error setting vertical center\n"); } } else { } } else { printf ("Vertical center control not available\n"); } } break; break; default: if (opt != 10) printf ("error: invalid option %c", opt); break; } done: return; } static gpointer read_user (gpointer data) { char opt; while (!exit_read) { print_options (); do { opt = getchar (); if (exit_read) { break; } } while (opt == '\n'); run_options (opt); } return NULL; } static gboolean my_bus_callback (GstBus * bus, GstMessage * message, gpointer data) { switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_ERROR:{ GError *err; gchar *debug; gchar *str; gst_message_parse_error (message, &err, &debug); str = gst_element_get_name (message->src); g_print ("%s error: %s\n", str, err->message); g_free (str); g_print ("Debug: %s\n", debug); g_error_free (err); g_free (debug); printf ("presse <ENTER> key to exit\n"); exit_read = 1; g_main_loop_quit (loop); break; case GST_MESSAGE_EOS: /* end-of-stream */ printf ("presse any key to exit\n"); exit_read = 1; g_main_loop_quit (loop); break; default: break; } } return TRUE; } int main (int argc, char *argv[]) { GThread *input_thread; gint numbuffers = -1; gchar device[128] = { '\0' }; gchar input[128] = { '\0' }; gulong frequency = 0; GstBus *bus; /* see for input option */ int c; while (1) { static char long_options_desc[][64] = { {"Number of buffers to output before sending EOS"}, {"Device location. Common in /dev/video0"}, {"input/output (channel) to switch to"}, {"frequency to tune to (in Hz)"}, {0, 0, 0, 0} }; static struct option long_options[] = { {"numbuffers", 1, 0, 'n'}, {"device", 1, 0, 'd'}, {"input", 1, 0, 'i'}, {"frequency", 1, 0, 'f'}, {0, 0, 0, 0} }; /* getopt_long stores the option index here. */ int option_index = 0; c = getopt_long (argc, argv, "n:d:i:f:h", long_options, &option_index); /* Detect the end of the options. */ if (c == -1) { printf ("tip: use -h to see help message.\n"); break; } switch (c) { case 0: /* If this option set a flag, do nothing else now. */ if (long_options[option_index].flag != 0) break; printf ("option %s", long_options[option_index].name); if (optarg) printf (" with arg %s", optarg); printf ("\n"); break; case 'n': numbuffers = atoi (optarg); break; case 'd': strncpy (device, optarg, sizeof (device) / sizeof (device[0])); break; case 'i': strncpy (input, optarg, sizeof (input) / sizeof (input[0])); break; case 'f': frequency = atol (optarg); break; case 'h': printf ("Usage: v4l2src-test [OPTION]...\n"); for (c = 0; long_options[c].name; ++c) { printf ("-%c, --%s\r\t\t\t\t%s\n", long_options[c].val, long_options[c].name, long_options_desc[c]); } exit (0); break; case '?': /* getopt_long already printed an error message. */ printf ("Use -h to see help message.\n"); break; default: abort (); } } /* Print any remaining command line arguments (not options). */ if (optind < argc) { printf ("Use -h to see help message.\n" "non-option ARGV-elements: "); while (optind < argc) printf ("%s ", argv[optind++]); putchar ('\n'); } /* init */ gst_init (&argc, &argv); /* create elements */ if (!(pipeline = gst_pipeline_new ("my_pipeline"))) { fprintf (stderr, "error: gst_pipeline_new return NULL"); return -1; } if (!(source = gst_element_factory_make ("v4l2src", NULL))) { fprintf (stderr, "error: gst_element_factory_make (\"v4l2src\", NULL) return NULL"); return -1; } if (!(sink = gst_element_factory_make ("xvimagesink", NULL))) { fprintf (stderr, "error: gst_element_factory_make (\"xvimagesink\", NULL) return NULL"); return -1; } if (numbuffers > -1) { g_object_set (source, "num-buffers", numbuffers, NULL); } if (device[0]) { g_object_set (source, "device", device, NULL); } if (input[0]) { g_object_set (source, "input", input, NULL); } if (frequency) { g_object_set (source, "frequency", frequency, NULL); } /* you would normally check that the elements were created properly */ bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); gst_bus_add_watch (bus, my_bus_callback, NULL); /* put together a pipeline */ gst_bin_add_many (GST_BIN (pipeline), source, sink, NULL); gst_element_link_pads (source, "src", sink, "sink"); /* start the pipeline */ gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING); loop = g_main_loop_new (NULL, FALSE); if (!(input_thread = g_thread_create (read_user, source, TRUE, NULL))) { fprintf (stderr, "error: g_thread_create return NULL"); return -1; } g_main_loop_run (loop); g_thread_join (input_thread); gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL); gst_object_unref (bus); gst_object_unref (pipeline); gst_deinit (); return 0; }