| /* 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., 51 Franklin St, Fifth Floor, |
| * Boston, MA 02110-1301, USA. |
| */ |
| |
| #include <string.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <getopt.h> |
| |
| #include <gst/gst.h> |
| #include <gst/video/colorbalance.h> |
| #include <gst/video/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) { |
| #if 0 |
| 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; |
| #endif |
| 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); |
| |
| input_thread = g_thread_try_new ("v4l2src-test", read_user, source, NULL); |
| |
| if (input_thread == NULL) { |
| fprintf (stderr, "error: g_thread_try_new() failed"); |
| 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; |
| |
| } |