/*
* Clutter-GStreamer.
*
* GStreamer integration library for Clutter.
*
* camera-player.c - A simple camera player.
*
* Copyright (C) 2007,2008 OpenedHand
* Copyright (C) 2012 Collabora Ltd.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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
#include
#include
typedef struct _CameraApp
{
ClutterActor *stage;
ClutterActor *camera_actor;
ClutterGstCamera *camera_player;
const GPtrArray *camera_devices;
guint selected_camera_device;
gboolean decrease_selected;
} CameraApp;
static gboolean opt_fullscreen = FALSE;
static GOptionEntry options[] =
{
{ "fullscreen",
'f', 0,
G_OPTION_ARG_NONE,
&opt_fullscreen,
"Start the player in fullscreen",
NULL },
{ NULL }
};
static void
update_gamma (CameraApp *app)
{
gdouble min, max, cur;
if (!clutter_gst_camera_supports_gamma_correction (app->camera_player))
{
g_print ("Cannot update gamma, not supported\n");
return;
}
if (!clutter_gst_camera_get_gamma_range (app->camera_player,
&min, &max, NULL))
{
g_print ("Cannot update gamma, unable to get allowed range\n");
return;
}
if (!clutter_gst_camera_get_gamma (app->camera_player, &cur))
{
g_print ("Cannot update gamma, unable to get current value\n");
return;
}
g_print ("Updating gamma:\n");
g_print ("\tmin value: %0.2f\n", min);
g_print ("\tmax value: %0.2f\n", max);
g_print ("\tcur value: %0.2f\n", cur);
if (app->decrease_selected)
{
cur -= 0.1;
if (cur < min)
cur = min;
}
else
{
cur += 0.1;
if (cur > max)
cur = max;
}
g_print ("\tnew value: %0.2f\n", cur);
clutter_gst_camera_set_gamma (app->camera_player, cur);
}
static void
update_color_balance (CameraApp *app,
const gchar *property)
{
gdouble min, max, cur;
if (!clutter_gst_camera_supports_color_balance (app->camera_player))
{
g_print ("Cannot update color balance property %s, "
"not supported\n",
property);
return;
}
if (!clutter_gst_camera_get_color_balance_property_range (app->camera_player,
property, &min, &max, NULL))
{
g_print ("Cannot update color balance property %s, "
"unable to get allowed range\n",
property);
return;
}
if (!clutter_gst_camera_get_color_balance_property (app->camera_player,
property, &cur))
{
g_print ("Cannot update color balance property %s, "
"unable to get current value\n",
property);
return;
}
g_print ("Updating color balance property %s:\n", property);
g_print ("\tmin value: %0.2f\n", min);
g_print ("\tmax value: %0.2f\n", max);
g_print ("\tcur value: %0.2f\n", cur);
if (app->decrease_selected)
{
cur -= 0.1;
if (cur < min)
cur = min;
}
else
{
cur += 0.1;
if (cur > max)
cur = max;
}
g_print ("\tnew value: %0.2f\n", cur);
clutter_gst_camera_set_color_balance_property (app->camera_player,
property, cur);
}
static gboolean
input_cb (ClutterStage *stage,
ClutterEvent *event,
gpointer user_data)
{
CameraApp *app = (CameraApp*)user_data;
gboolean handled = FALSE;
switch (event->type)
{
case CLUTTER_KEY_PRESS:
{
switch (clutter_event_get_key_symbol (event))
{
case CLUTTER_minus:
app->decrease_selected = TRUE;
break;
case CLUTTER_plus:
app->decrease_selected = FALSE;
break;
case CLUTTER_b:
update_color_balance (app, "brightness");
break;
case CLUTTER_c:
update_color_balance (app, "contrast");
break;
case CLUTTER_s:
update_color_balance (app, "saturation");
break;
case CLUTTER_h:
update_color_balance (app, "hue");
break;
case CLUTTER_g:
update_gamma (app);
break;
case CLUTTER_d:
{
ClutterGstCameraDevice *device;
if (app->camera_devices->len == 1)
break;
app->selected_camera_device++;
if (app->selected_camera_device >= app->camera_devices->len)
app->selected_camera_device = 0;
device = g_ptr_array_index (app->camera_devices, app->selected_camera_device);
g_print ("Selecting device %s (node=%s)\n",
clutter_gst_camera_device_get_name (device),
clutter_gst_camera_device_get_node (device));
clutter_gst_camera_set_camera_device (app->camera_player, device);
break;
}
case CLUTTER_q:
case CLUTTER_Escape:
clutter_main_quit ();
break;
case CLUTTER_v:
{
gchar *filename;
static guint photos_cnt = 0;
if (clutter_gst_camera_is_recording_video (app->camera_player))
{
g_print ("Stopping video recording\n");
clutter_gst_camera_stop_video_recording (app->camera_player);
}
else if (!clutter_gst_camera_is_ready_for_capture (app->camera_player))
g_print ("Unable to record video as the camera is not ready for capture\n");
else
{
g_print ("Recording video!\n");
filename = g_strdup_printf ("camera-video-%d.ogv", photos_cnt++);
clutter_gst_camera_start_video_recording (app->camera_player,
filename);
g_free (filename);
}
break;
}
case CLUTTER_p:
{
gchar *filename;
static guint photos_cnt = 0;
if (clutter_gst_camera_is_recording_video (app->camera_player))
g_print ("Unable to take photo as the camera is recording video\n");
else if (!clutter_gst_camera_is_ready_for_capture (app->camera_player))
g_print ("Unable to take photo as the camera is not ready for capture\n");
else
{
g_print ("Taking picture!\n");
filename = g_strdup_printf ("camera-photo-%d.jpg", photos_cnt++);
clutter_gst_camera_take_photo (app->camera_player,
filename);
g_free (filename);
}
break;
}
case CLUTTER_e:
{
GstElement *filter;
gboolean ret;
filter = gst_element_factory_make ("dicetv", NULL);
if (!filter)
{
g_print ("ERROR: Unable to create 'dicetv' element, cannot set filter\n");
}
ret = clutter_gst_camera_set_filter (app->camera_player, filter);
if (ret)
g_print ("Filter set successfully\n");
else
g_print ("ERROR: Unable to set filter\n");
break;
}
case CLUTTER_r:
clutter_gst_camera_remove_filter (app->camera_player);
break;
default:
break;
}
}
default:
break;
}
return handled;
}
static void
ready_for_capture (ClutterGstCamera *camera_player,
gboolean ready)
{
if (ready)
g_print ("Ready for capture!\n");
}
static void
photo_saved (ClutterGstCamera *camera_player)
{
g_print ("Photo saved!\n");
}
static void
video_saved (ClutterGstCamera *camera_player)
{
g_print ("Video saved!\n");
}
static void
size_change (ClutterGstPlayer *player,
gint base_width,
gint base_height,
CameraApp *app)
{
ClutterActor *stage = app->stage;
gfloat new_x, new_y, new_width, new_height;
gfloat stage_width, stage_height;
clutter_actor_get_size (stage, &stage_width, &stage_height);
new_height = (base_height * stage_width) / base_width;
if (new_height <= stage_height)
{
new_width = stage_width;
new_x = 0;
new_y = (stage_height - new_height) / 2;
}
else
{
new_width = (base_width * stage_height) / base_height;
new_height = stage_height;
new_x = (stage_width - new_width) / 2;
new_y = 0;
}
clutter_actor_set_position (app->camera_actor, new_x, new_y);
clutter_actor_set_size (app->camera_actor, new_width, new_height);
}
int
main (int argc, char *argv[])
{
CameraApp *app = NULL;
ClutterActor *stage;
ClutterColor stage_color = { 0x00, 0x00, 0x00, 0x00 };
GError *error = NULL;
guint i;
clutter_gst_init_with_args (&argc,
&argv,
" - A simple camera player",
options,
NULL,
&error);
if (error)
{
g_print ("%s\n", error->message);
g_error_free (error);
return EXIT_FAILURE;
}
stage = clutter_stage_new ();
clutter_actor_set_background_color (stage, &stage_color);
clutter_actor_set_size (stage, 768, 576);
clutter_stage_set_minimum_size (CLUTTER_STAGE (stage), 640, 480);
if (opt_fullscreen)
clutter_stage_set_fullscreen (CLUTTER_STAGE (stage), TRUE);
app = g_new0(CameraApp, 1);
app->stage = stage;
app->camera_player = clutter_gst_camera_new ();
if (app->camera_player == NULL)
{
g_error ("failed to create camera player");
return EXIT_FAILURE;
}
app->camera_actor = g_object_new (CLUTTER_TYPE_ACTOR,
"content", g_object_new (CLUTTER_GST_TYPE_ASPECTRATIO,
"player", app->camera_player,
NULL),
NULL);
app->camera_devices = clutter_gst_camera_manager_get_camera_devices (clutter_gst_camera_manager_get_default ());
if (!app->camera_devices)
{
g_error ("no suitable camera device available");
return EXIT_FAILURE;
}
g_print ("Available camera devices:\n");
for (i = 0; i < app->camera_devices->len; ++i)
{
ClutterGstCameraDevice *device;
device = g_ptr_array_index (app->camera_devices, i);
g_print ("\tdevice %s (node=%s)\n",
clutter_gst_camera_device_get_name (device),
clutter_gst_camera_device_get_node (device));
clutter_gst_camera_device_set_capture_resolution (device, 800, 600);
}
app->selected_camera_device = 0;
g_signal_connect (app->camera_player, "ready-for-capture",
G_CALLBACK (ready_for_capture),
app);
g_signal_connect (app->camera_player, "photo-saved",
G_CALLBACK (photo_saved),
app);
g_signal_connect (app->camera_player, "video-saved",
G_CALLBACK (video_saved),
app);
/* Handle it ourselves so can scale up for fullscreen better */
g_signal_connect_after (app->camera_player,
"size-change",
G_CALLBACK (size_change), app);
/* Add control UI to stage */
clutter_actor_add_child (stage, app->camera_actor);
clutter_stage_hide_cursor (CLUTTER_STAGE (stage));
/* Hook up other events */
g_signal_connect (stage, "event", G_CALLBACK (input_cb), app);
clutter_gst_player_set_playing (CLUTTER_GST_PLAYER (app->camera_player), TRUE);
clutter_actor_show (stage);
clutter_main ();
return EXIT_SUCCESS;
}