camerabin2: Implement tagsetter interface

This commit is contained in:
Thiago Santos 2011-01-11 14:50:48 -03:00
parent a90f8210bb
commit a715b46c7f
3 changed files with 261 additions and 0 deletions

View file

@ -103,6 +103,11 @@ GType
gst_camera_bin_get_type (void)
{
static GType gst_camera_bin_type = 0;
static const GInterfaceInfo camerabin_tagsetter_info = {
NULL,
NULL,
NULL,
};
if (!gst_camera_bin_type) {
static const GTypeInfo gst_camera_bin_info = {
@ -121,6 +126,9 @@ gst_camera_bin_get_type (void)
gst_camera_bin_type =
g_type_register_static (GST_TYPE_PIPELINE, "GstCameraBin2",
&gst_camera_bin_info, 0);
g_type_add_interface_static (gst_camera_bin_type, GST_TYPE_TAG_SETTER,
&camerabin_tagsetter_info);
}
return gst_camera_bin_type;
@ -149,7 +157,30 @@ gst_camera_bin_new_event_renegotiate (void)
static void
gst_camera_bin_start_capture (GstCameraBin * camerabin)
{
const GstTagList *taglist;
GST_DEBUG_OBJECT (camerabin, "Received start-capture");
taglist = gst_tag_setter_get_tag_list (GST_TAG_SETTER (camerabin));
if (taglist) {
GstPad *active_pad;
GST_DEBUG_OBJECT (camerabin, "Pushing tags from application: %"
GST_PTR_FORMAT, taglist);
if (camerabin->mode == MODE_IMAGE) {
active_pad = gst_element_get_static_pad (camerabin->src,
GST_BASE_CAMERA_SRC_IMAGE_PAD_NAME);
} else {
active_pad = gst_element_get_static_pad (camerabin->src,
GST_BASE_CAMERA_SRC_VIDEO_PAD_NAME);
}
gst_pad_push_event (active_pad,
gst_event_new_tag (gst_tag_list_copy (taglist)));
gst_object_unref (active_pad);
}
g_signal_emit_by_name (camerabin->src, "start-capture", NULL);
}
@ -559,6 +590,7 @@ gst_camera_bin_change_state (GstElement * element, GstStateChange trans)
switch (trans) {
case GST_STATE_CHANGE_PAUSED_TO_READY:
gst_tag_setter_reset_tags (GST_TAG_SETTER (camera));
gst_element_set_state (camera->videosink, GST_STATE_READY);
break;
case GST_STATE_CHANGE_READY_TO_NULL:

View file

@ -201,6 +201,7 @@ elements_camerabin2_CFLAGS = \
elements_camerabin2_LDADD = \
$(top_builddir)/gst-libs/gst/interfaces/libgstphotography-@GST_MAJORMINOR@.la \
$(top_builddir)/gst-libs/gst/basecamerabinsrc/libgstbasecamerabinsrc-@GST_MAJORMINOR@.la \
-lgstpbutils-$(GST_MAJORMINOR) \
$(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) $(GST_LIBS) $(LDADD)
elements_camerabin2_SOURCES = elements/camerabin2.c

View file

@ -31,6 +31,7 @@
#include <gst/video/video.h>
#include <gst/check/gstcheck.h>
#include <gst/basecamerabinsrc/gstbasecamerasrc.h>
#include <gst/pbutils/encoding-profile.h>
#define IMAGE_FILENAME "image"
#define VIDEO_FILENAME "video"
@ -171,6 +172,26 @@ guint32 test_id = 0;
static GstBuffer *preview_buffer;
static GstCaps *preview_caps;
static GstTagList *tags_found;
static gboolean
validity_bus_cb (GstBus * bus, GstMessage * message, gpointer data);
static void
validate_taglist_foreach (const GstTagList * list, const gchar * tag,
gpointer user_data)
{
GstTagList *other = GST_TAG_LIST (user_data);
const GValue *val1 = gst_tag_list_get_value_index (list, tag, 0);
const GValue *val2 = gst_tag_list_get_value_index (other, tag, 0);
fail_if (val1 == NULL);
fail_if (val2 == NULL);
fail_unless (gst_value_can_intersect (val1, val2));
}
/* helper function for filenames */
static const gchar *
@ -271,6 +292,31 @@ check_preview_image (void)
}
}
static void
extract_jpeg_tags (const gchar * filename, gint num)
{
GstBus *bus;
GMainLoop *loop = g_main_loop_new (NULL, FALSE);
const gchar *filepath = make_test_file_name (filename, num);
gchar *pipeline_str = g_strdup_printf ("filesrc location=%s ! "
"jpegparse ! fakesink", filepath);
GstElement *pipeline;
pipeline = gst_parse_launch (pipeline_str, NULL);
fail_unless (pipeline != NULL);
g_free (pipeline_str);
bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
gst_bus_add_watch (bus, (GstBusFunc) validity_bus_cb, loop);
gst_element_set_state (pipeline, GST_STATE_PLAYING);
g_main_loop_run (loop);
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_object_unref (bus);
gst_object_unref (pipeline);
}
static void
setup_wrappercamerabinsrc_videotestsrc (void)
{
@ -334,6 +380,10 @@ teardown (void)
gst_buffer_unref (preview_buffer);
preview_buffer = NULL;
if (tags_found)
gst_tag_list_free (tags_found);
tags_found = NULL;
GST_INFO ("done");
}
@ -360,12 +410,32 @@ validity_bus_cb (GstBus * bus, GstMessage * message, gpointer data)
g_main_loop_quit (loop);
GST_DEBUG ("eos");
break;
case GST_MESSAGE_TAG:{
GstTagList *taglist = NULL;
gst_message_parse_tag (message, &taglist);
if (tags_found) {
gst_tag_list_insert (tags_found, taglist, GST_TAG_MERGE_REPLACE);
gst_tag_list_free (taglist);
} else {
tags_found = taglist;
}
}
break;
default:
break;
}
return TRUE;
}
/* checks that tags in @tags_a are in @tags_b */
static gboolean
taglist_is_subset (GstTagList * tags_a, GstTagList * tags_b)
{
gst_tag_list_foreach (tags_a, validate_taglist_foreach, tags_b);
return TRUE;
}
/* Validate captured files by playing them with playbin
* and checking that no errors occur. */
static gboolean
@ -417,6 +487,17 @@ check_file_validity (const gchar * filename, gint num, GstTagList * taglist,
g_main_loop_run (loop);
gst_element_set_state (playbin, GST_STATE_NULL);
/* special handling for images (jpg) as jpegparse isn't plugged by
* default due to its current low rank */
if (taglist && strstr (filename, "image")) {
extract_jpeg_tags (filename, num);
}
if (taglist) {
fail_unless (tags_found != NULL);
fail_unless (taglist_is_subset (taglist, tags_found));
}
g_free (uri);
gst_object_unref (bus);
gst_object_unref (playbin);
@ -703,6 +784,150 @@ GST_START_TEST (test_image_capture_previews)
GST_END_TEST;
GST_START_TEST (test_image_capture_with_tags)
{
gint i;
GstTagList *taglists[3];
if (!camera)
return;
taglists[0] = gst_tag_list_new_full (GST_TAG_COMMENT, "test1",
GST_TAG_GEO_LOCATION_LATITUDE, 36.6, GST_TAG_GEO_LOCATION_LONGITUDE,
-12.5,
GST_TAG_COPYRIGHT, "My copyright notice",
GST_TAG_DEVICE_MANUFACTURER, "MyFavoriteBrand",
GST_TAG_DEVICE_MODEL, "123v42.1",
GST_TAG_DESCRIPTION, "some description",
GST_TAG_APPLICATION_NAME, "camerabin2 test",
GST_TAG_GEO_LOCATION_ELEVATION, 300.85, NULL);
taglists[1] = gst_tag_list_new_full (GST_TAG_COMMENT, "test2",
GST_TAG_GEO_LOCATION_LATITUDE, 1.6, GST_TAG_GEO_LOCATION_LONGITUDE,
0.0,
GST_TAG_COPYRIGHT, "some cp",
GST_TAG_DEVICE_MANUFACTURER, "ABRAND",
GST_TAG_DEVICE_MODEL, "abcd",
GST_TAG_DESCRIPTION, "desc",
GST_TAG_APPLICATION_NAME, "another cam test",
GST_TAG_GEO_LOCATION_ELEVATION, 10.0, NULL);
taglists[2] = gst_tag_list_new_full (GST_TAG_COMMENT, "test3",
GST_TAG_GEO_LOCATION_LATITUDE, 1.3, GST_TAG_GEO_LOCATION_LONGITUDE,
-5.0,
GST_TAG_COPYRIGHT, "CC",
GST_TAG_DEVICE_MANUFACTURER, "Homemade",
GST_TAG_DEVICE_MODEL, "xpto",
GST_TAG_DESCRIPTION, "another description",
GST_TAG_APPLICATION_NAME, "cam2 test",
GST_TAG_GEO_LOCATION_ELEVATION, 0.0, NULL);
/* set still image mode */
g_object_set (camera, "mode", 1,
"location", make_test_file_name (IMAGE_FILENAME, -1), NULL);
if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) ==
GST_STATE_CHANGE_FAILURE) {
GST_WARNING ("setting camerabin to PLAYING failed");
gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
gst_object_unref (camera);
camera = NULL;
}
fail_unless (camera != NULL);
GST_INFO ("starting capture");
for (i = 0; i < 3; i++) {
gst_tag_setter_merge_tags (GST_TAG_SETTER (camera), taglists[i],
GST_TAG_MERGE_REPLACE);
g_signal_emit_by_name (camera, "start-capture", NULL);
g_timeout_add_seconds (3, (GSourceFunc) g_main_loop_quit, main_loop);
g_main_loop_run (main_loop);
}
gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
for (i = 0; i < 2; i++) {
check_file_validity (IMAGE_FILENAME, i, taglists[i], 0, 0);
gst_tag_list_free (taglists[i]);
}
}
GST_END_TEST;
GST_START_TEST (test_video_capture_with_tags)
{
gint i;
GstTagList *taglists[3];
if (!camera)
return;
taglists[0] = gst_tag_list_new_full (GST_TAG_COMMENT, "test1", NULL);
taglists[1] = gst_tag_list_new_full (GST_TAG_COMMENT, "test2", NULL);
taglists[2] = gst_tag_list_new_full (GST_TAG_COMMENT, "test3", NULL);
/* set video mode */
g_object_set (camera, "mode", 2,
"location", make_test_file_name (VIDEO_FILENAME, -1), NULL);
/* set a profile that has xmp support for more tags being saved */
{
GstEncodingContainerProfile *profile;
GstCaps *caps;
caps =
gst_caps_new_simple ("video/quicktime", "variant", G_TYPE_STRING,
"apple", NULL);
profile = gst_encoding_container_profile_new ("qt", "jpeg+qt", caps, NULL);
gst_caps_unref (caps);
caps = gst_caps_new_simple ("image/jpeg", NULL);
if (!gst_encoding_container_profile_add_profile (profile,
(GstEncodingProfile *) gst_encoding_video_profile_new (caps,
NULL, NULL, 1))) {
GST_WARNING_OBJECT (camera, "Failed to create encoding profiles");
}
gst_caps_unref (caps);
g_object_set (camera, "video-profile", profile, NULL);
gst_encoding_profile_unref (profile);
}
if (gst_element_set_state (GST_ELEMENT (camera), GST_STATE_PLAYING) ==
GST_STATE_CHANGE_FAILURE) {
GST_WARNING ("setting camerabin to PLAYING failed");
gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
gst_object_unref (camera);
camera = NULL;
}
fail_unless (camera != NULL);
GST_INFO ("starting capture");
for (i = 0; i < 3; i++) {
gst_tag_setter_merge_tags (GST_TAG_SETTER (camera), taglists[i],
GST_TAG_MERGE_REPLACE);
g_signal_emit_by_name (camera, "start-capture", NULL);
g_timeout_add_seconds (3, (GSourceFunc) g_main_loop_quit, main_loop);
g_main_loop_run (main_loop);
g_signal_emit_by_name (camera, "stop-capture", NULL);
g_usleep (G_USEC_PER_SEC * 3);
}
gst_element_set_state (GST_ELEMENT (camera), GST_STATE_NULL);
for (i = 0; i < 2; i++) {
check_file_validity (VIDEO_FILENAME, i, taglists[i], 0, 0);
gst_tag_list_free (taglists[i]);
}
}
GST_END_TEST;
GST_START_TEST (test_supported_caps)
{
GstCaps *padcaps = NULL;
@ -798,6 +1023,9 @@ camerabin_suite (void)
tcase_add_test (tc_basic, test_multiple_video_recordings);
tcase_add_test (tc_basic, test_image_capture_previews);
tcase_add_test (tc_basic, test_image_capture_with_tags);
tcase_add_test (tc_basic, test_video_capture_with_tags);
}
end: