目标
亮度,对比度,色度和饱和度都是常见的视频调节参数,也是GStreamer里面设置色彩平衡的参数。本教程将展示:
如何发现可用的色彩平衡通道
如何改变它们
介绍
《GStreamer基础教程05——集成GUI工具》里面已经解释了GObject接口:应用通过它们来获得特定功能,而不用去管具体的element的实现。
playbin2实现了色彩平衡的接口(gstcolorbalance),这就可以设置色彩平衡了。如果playbin2里面的任何一个element支持了这个接口,playbin2就仅仅简单地把应用的设置传给element,否则就会在pipeline中增加一个色彩平衡的element。
这个接口允许查询可用的色彩平衡通道(gstcolorbalancechannel),包括它们的名字和值得有效区间,然后调整当前的值。
色彩平衡例子
#include <string.h> #include <gst/gst.h> #include <gst/interfaces/colorbalance.h> typedef struct _CustomData { GstElement *pipeline; GMainLoop *loop; } CustomData; /* Process a color balance command */ static void update_color_channel (const gchar *channel_name, gboolean increase, GstColorBalance *cb) { gdouble step; gint value; GstColorBalanceChannel *channel = NULL; const GList *channels, *l; /* Retrieve the list of channels and locate the requested one */ channels = gst_color_balance_list_channels (cb); for (l = channels; l != NULL; l = l->next) { GstColorBalanceChannel *tmp = (GstColorBalanceChannel *)l->data; if (g_strrstr (tmp->label, channel_name)) { channel = tmp; break; } } if (!channel) return; /* Change the channel's value */ step = 0.1 * (channel->max_value - channel->min_value); value = gst_color_balance_get_value (cb, channel); if (increase) { value = (gint)(value + step); if (value > channel->max_value) value = channel->max_value; } else { value = (gint)(value - step); if (value < channel->min_value) value = channel->min_value; } gst_color_balance_set_value (cb, channel, value); } /* Output the current values of all Color Balance channels */ static void print_current_values (GstElement *pipeline) { const GList *channels, *l; /* Output Color Balance values */ channels = gst_color_balance_list_channels (GST_COLOR_BALANCE (pipeline)); for (l = channels; l != NULL; l = l->next) { GstColorBalanceChannel *channel = (GstColorBalanceChannel *)l->data; gint value = gst_color_balance_get_value (GST_COLOR_BALANCE (pipeline), channel); g_print ("%s: %3d%% ", channel->label, 100 * (value - channel->min_value) / (channel->max_value - channel->min_value)); } g_print ("\n"); } /* Process keyboard input */ static gboolean handle_keyboard (GIOChannel *source, GIOCondition cond, CustomData *data) { gchar *str = NULL; if (g_io_channel_read_line (source, &str, NULL, NULL, NULL) != G_IO_STATUS_NORMAL) { return TRUE; } switch (g_ascii_tolower (str[0])) { case 'c': update_color_channel ("CONTRAST", g_ascii_isupper (str[0]), GST_COLOR_BALANCE (data->pipeline)); break; case 'b': update_color_channel ("BRIGHTNESS", g_ascii_isupper (str[0]), GST_COLOR_BALANCE (data->pipeline)); break; case 'h': update_color_channel ("HUE", g_ascii_isupper (str[0]), GST_COLOR_BALANCE (data->pipeline)); break; case 's': update_color_channel ("SATURATION", g_ascii_isupper (str[0]), GST_COLOR_BALANCE (data->pipeline)); break; case 'q': g_main_loop_quit (data->loop); break; default: break; } g_free (str); print_current_values (data->pipeline); return TRUE; } int main(int argc, char *argv[]) { CustomData data; GstStateChangeReturn ret; GIOChannel *io_stdin; /* Initialize GStreamer */ gst_init (&argc, &argv); /* Initialize our data structure */ memset (&data, 0, sizeof (data)); /* Print usage map */ g_print ( "USAGE: Choose one of the following options, then press enter:\n" " 'C' to increase contrast, 'c' to decrease contrast\n" " 'B' to increase brightness, 'b' to decrease brightness\n" " 'H' to increase hue, 'h' to decrease hue\n" " 'S' to increase saturation, 's' to decrease saturation\n" " 'Q' to quit\n"); /* Build the pipeline */ data.pipeline = gst_parse_launch ("playbin2 uri=http://docs.gstreamer.com/media/sintel_trailer-480p.webm", NULL); /* Add a keyboard watch so we get notified of keystrokes */ #ifdef _WIN32 io_stdin = g_io_channel_win32_new_fd (fileno (stdin)); #else io_stdin = g_io_channel_unix_new (fileno (stdin)); #endif g_io_add_watch (io_stdin, G_IO_IN, (GIOFunc)handle_keyboard, &data); /* Start playing */ ret = gst_element_set_state (data.pipeline, GST_STATE_PLAYING); if (ret == GST_STATE_CHANGE_FAILURE) { g_printerr ("Unable to set the pipeline to the playing state.\n"); gst_object_unref (data.pipeline); return -1; } print_current_values (data.pipeline); /* Create a GLib Main Loop and set it to run */ data.loop = g_main_loop_new (NULL, FALSE); g_main_loop_run (data.loop); /* Free resources */ g_main_loop_unref (data.loop); g_io_channel_unref (io_stdin); gst_element_set_state (data.pipeline, GST_STATE_NULL); gst_object_unref (data.pipeline); return 0; }
工作流程
main()函数非常的简单。用一个playbin2的建立pipeline,注册一个键盘处理函数来监控按键。
/* Output the current values of all Color Balance channels */ static void print_current_values (GstElement *pipeline) { const GList *channels, *l; /* Output Color Balance values */ channels = gst_color_balance_list_channels (GST_COLOR_BALANCE (pipeline)); for (l = channels; l != NULL; l = l->next) { GstColorBalanceChannel *channel = (GstColorBalanceChannel *)l->data; gint value = gst_color_balance_get_value (GST_COLOR_BALANCE (pipeline), channel); g_print ("%s: %3d%% ", channel->label, 100 * (value - channel->min_value) / (channel->max_value - channel->min_value)); } g_print ("\n"); }
这个方法展示了如何获得通道的列表并打印所有通道当前的值。这是通过gst_color_balance_list_channels()方法来实现的,它会返回一个GList结构,我们遍历这个结构即可。
在这个列表里面的每一个element都是GstColorBalanceChannel结构,包括通道名,最小值和最大值。然后就可以在每个通道调用gst_color_balance_get_value()方法来获得当前值。
在这个例子中,当前值常常用占最大值的百分比来显示。
/* Process a color balance command */ static void update_color_channel (const gchar *channel_name, gboolean increase, GstColorBalance *cb) { gdouble step; gint value; GstColorBalanceChannel *channel = NULL; const GList *channels, *l; /* Retrieve the list of channels and locate the requested one */ channels = gst_color_balance_list_channels (cb); for (l = channels; l != NULL; l = l->next) { GstColorBalanceChannel *tmp = (GstColorBalanceChannel *)l->data; if (g_strrstr (tmp->label, channel_name)) { channel = tmp; break; } } if (!channel) return;
这个方法通过指定通道名来确定通道,然后根据操作增加或者减少值。另外,通道列表的获得后是根据指定的名字来解析获得通道的。很显然,这个列表只应该解析一次,指向通道的指针需要保持在比一个字符串更高效的数据结构中。
/* Change the channel's value */ step = 0.1 * (channel->max_value - channel->min_value); value = gst_color_balance_get_value (cb, channel); if (increase) { value = (gint)(value + step); if (value > channel->max_value) value = channel->max_value; } else { value = (gint)(value - step); if (value < channel->min_value) value = channel->min_value; } gst_color_balance_set_value (cb, channel, value); }
然后就获得当前通道的值,修改它但确保它的值有效,使用gst_color_balance_set_value()来设置。
其它没有什么了。运行一下这个程序实际看一下效果。