1 # Playback tutorial 5: Color Balance
5 Brightness, Contrast, Hue and Saturation are common video adjustments,
6 which are collectively known as Color Balance settings in GStreamer.
9 - How to find out the available color balance channels
13 [](sdk-basic-tutorial-toolkit-integration.md) has
14 already explained the concept of GObject interfaces: applications use
15 them to find out if certain functionality is available, regardless of
16 the actual element which implements it.
18 `playbin` implements the Color Balance interface (`GstColorBalance`),
19 which allows access to the color balance settings. If any of the
20 elements in the `playbin` pipeline support this interface,
21 `playbin` simply forwards it to the application, otherwise, a
22 colorbalance element is inserted in the pipeline.
24 This interface allows querying for the available color balance channels
25 (`GstColorBalanceChannel`), along with their name and valid range of
26 values, and then modify the current value of any of them.
28 ## Color balance example
30 Copy this code into a text file named `playback-tutorial-5.c`.
32 **playback-tutorial-5.c**
38 #include <gst/video/colorbalance.h>
40 typedef struct _CustomData {
45 /* Process a color balance command */
46 static void update_color_channel (const gchar *channel_name, gboolean increase, GstColorBalance *cb) {
49 GstColorBalanceChannel *channel = NULL;
50 const GList *channels, *l;
52 /* Retrieve the list of channels and locate the requested one */
53 channels = gst_color_balance_list_channels (cb);
54 for (l = channels; l != NULL; l = l->next) {
55 GstColorBalanceChannel *tmp = (GstColorBalanceChannel *)l->data;
57 if (g_strrstr (tmp->label, channel_name)) {
65 /* Change the channel's value */
66 step = 0.1 * (channel->max_value - channel->min_value);
67 value = gst_color_balance_get_value (cb, channel);
69 value = (gint)(value + step);
70 if (value > channel->max_value)
71 value = channel->max_value;
73 value = (gint)(value - step);
74 if (value < channel->min_value)
75 value = channel->min_value;
77 gst_color_balance_set_value (cb, channel, value);
80 /* Output the current values of all Color Balance channels */
81 static void print_current_values (GstElement *pipeline) {
82 const GList *channels, *l;
84 /* Output Color Balance values */
85 channels = gst_color_balance_list_channels (GST_COLOR_BALANCE (pipeline));
86 for (l = channels; l != NULL; l = l->next) {
87 GstColorBalanceChannel *channel = (GstColorBalanceChannel *)l->data;
88 gint value = gst_color_balance_get_value (GST_COLOR_BALANCE (pipeline), channel);
89 g_print ("%s: %3d%% ", channel->label,
90 100 * (value - channel->min_value) / (channel->max_value - channel->min_value));
95 /* Process keyboard input */
96 static gboolean handle_keyboard (GIOChannel *source, GIOCondition cond, CustomData *data) {
99 if (g_io_channel_read_line (source, &str, NULL, NULL, NULL) != G_IO_STATUS_NORMAL) {
103 switch (g_ascii_tolower (str[0])) {
105 update_color_channel ("CONTRAST", g_ascii_isupper (str[0]), GST_COLOR_BALANCE (data->pipeline));
108 update_color_channel ("BRIGHTNESS", g_ascii_isupper (str[0]), GST_COLOR_BALANCE (data->pipeline));
111 update_color_channel ("HUE", g_ascii_isupper (str[0]), GST_COLOR_BALANCE (data->pipeline));
114 update_color_channel ("SATURATION", g_ascii_isupper (str[0]), GST_COLOR_BALANCE (data->pipeline));
117 g_main_loop_quit (data->loop);
125 print_current_values (data->pipeline);
130 int main(int argc, char *argv[]) {
132 GstStateChangeReturn ret;
133 GIOChannel *io_stdin;
135 /* Initialize GStreamer */
136 gst_init (&argc, &argv);
138 /* Initialize our data structure */
139 memset (&data, 0, sizeof (data));
141 /* Print usage map */
143 "USAGE: Choose one of the following options, then press enter:\n"
144 " 'C' to increase contrast, 'c' to decrease contrast\n"
145 " 'B' to increase brightness, 'b' to decrease brightness\n"
146 " 'H' to increase hue, 'h' to decrease hue\n"
147 " 'S' to increase saturation, 's' to decrease saturation\n"
150 /* Build the pipeline */
151 data.pipeline = gst_parse_launch ("playbin uri=https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.webm", NULL);
153 /* Add a keyboard watch so we get notified of keystrokes */
155 io_stdin = g_io_channel_win32_new_fd (fileno (stdin));
157 io_stdin = g_io_channel_unix_new (fileno (stdin));
159 g_io_add_watch (io_stdin, G_IO_IN, (GIOFunc)handle_keyboard, &data);
162 ret = gst_element_set_state (data.pipeline, GST_STATE_PLAYING);
163 if (ret == GST_STATE_CHANGE_FAILURE) {
164 g_printerr ("Unable to set the pipeline to the playing state.\n");
165 gst_object_unref (data.pipeline);
168 print_current_values (data.pipeline);
170 /* Create a GLib Main Loop and set it to run */
171 data.loop = g_main_loop_new (NULL, FALSE);
172 g_main_loop_run (data.loop);
175 g_main_loop_unref (data.loop);
176 g_io_channel_unref (io_stdin);
177 gst_element_set_state (data.pipeline, GST_STATE_NULL);
178 gst_object_unref (data.pipeline);
183 > ![information] If you need help to compile this code, refer to the
184 > **Building the tutorials** section for your platform: [Mac] or
185 > [Windows] or use this specific command on Linux:
187 > `` gcc playback-tutorial-5.c -o playback-tutorial-5 `pkg-config --cflags --libs gstreamer-1.0 gstreamer-video-1.0` ``
189 > If you need help to run this code, refer to the **Running the
190 > tutorials** section for your platform: [Mac OS X], [Windows][1], for
191 > [iOS] or for [android].
193 > This tutorial opens a window and displays a movie, with accompanying audio. The media is fetched from the Internet, so the window might take a few seconds to appear, depending on your connection speed.
195 >The console should print all commands (Each command is a single upper-case or lower-case letter) and list all available Color Balance channels, typically, CONTRAST, BRIGHTNESS, HUE and SATURATION. Type each command (letter) followed by the Enter key.
197 > Required libraries: `gstreamer-1.0 gstreamer-video-1.0`
201 The `main()` function is fairly simple. A `playbin` pipeline is
202 instantiated and set to run, and a keyboard watch is installed so
203 keystrokes can be monitored.
206 /* Output the current values of all Color Balance channels */
207 static void print_current_values (GstElement *pipeline) {
208 const GList *channels, *l;
210 /* Output Color Balance values */
211 channels = gst_color_balance_list_channels (GST_COLOR_BALANCE (pipeline));
212 for (l = channels; l != NULL; l = l->next) {
213 GstColorBalanceChannel *channel = (GstColorBalanceChannel *)l->data;
214 gint value = gst_color_balance_get_value (GST_COLOR_BALANCE (pipeline), channel);
215 g_print ("%s: %3d%% ", channel->label,
216 100 * (value - channel->min_value) / (channel->max_value - channel->min_value));
222 This method prints the current value for all channels, and exemplifies
223 how to retrieve the list of channels. This is accomplished through the
224 `gst_color_balance_list_channels()` method. It returns a `GList` which
225 needs to be traversed.
227 Each element in the list is a `GstColorBalanceChannel` structure,
228 informing of the channel’s name, minimum value and maximum value.
229 `gst_color_balance_get_value()` can then be called on each channel to
230 retrieve the current value.
232 In this example, the minimum and maximum values are used to output the
233 current value as a percentage.
236 /* Process a color balance command */
237 static void update_color_channel (const gchar *channel_name, gboolean increase, GstColorBalance *cb) {
240 GstColorBalanceChannel *channel = NULL;
241 const GList *channels, *l;
243 /* Retrieve the list of channels and locate the requested one */
244 channels = gst_color_balance_list_channels (cb);
245 for (l = channels; l != NULL; l = l->next) {
246 GstColorBalanceChannel *tmp = (GstColorBalanceChannel *)l->data;
248 if (g_strrstr (tmp->label, channel_name)) {
257 This method locates the specified channel by name and increases or
258 decreases it as requested. Again, the list of channels is retrieved and
259 parsed looking for the channel with the specified name. Obviously, this
260 list could be parsed only once and the pointers to the channels be
261 stored and indexed by something more efficient than a string.
264 /* Change the channel's value */
265 step = 0.1 * (channel->max_value - channel->min_value);
266 value = gst_color_balance_get_value (cb, channel);
268 value = (gint)(value + step);
269 if (value > channel->max_value)
270 value = channel->max_value;
272 value = (gint)(value - step);
273 if (value < channel->min_value)
274 value = channel->min_value;
276 gst_color_balance_set_value (cb, channel, value);
280 The current value for the channel is then retrieved, changed (the
281 increment is proportional to its dynamic range), clamped (to avoid
282 out-of-range values) and set using `gst_color_balance_set_value()`.
284 And there is not much more to it. Run the program and observe the effect
285 of changing each of the channels in real time.
289 This tutorial has shown how to use the color balance interface.
290 Particularly, it has shown:
292 - How to retrieve the list of color available balance channels
293 with `gst_color_balance_list_channels()`
294 - How to manipulate the current value of each channel using
295 `gst_color_balance_get_value()` and `gst_color_balance_set_value()`
297 It has been a pleasure having you here, and see you soon\!
300 [information]: images/icons/emoticons/information.png
301 [Mac]: sdk-installing-on-mac-osx.md
302 [Windows]: sdk-installing-on-windows.md
303 [Mac OS X]: sdk-installing-on-mac-osx.md#building-the-tutorials
304 [1]: sdk-installing-on-windows.md#running-the-tutorials
305 [iOS]: sdk-installing-for-ios-development.md#building-the-tutorials
306 [android]: sdk-installing-for-android-development.md#building-the-tutorials
307 [warning]: images/icons/emoticons/warning.png