mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 04:01:08 +00:00
camerabin2: Implement tagsetter interface
This commit is contained in:
parent
a90f8210bb
commit
a715b46c7f
3 changed files with 261 additions and 0 deletions
|
@ -103,6 +103,11 @@ GType
|
||||||
gst_camera_bin_get_type (void)
|
gst_camera_bin_get_type (void)
|
||||||
{
|
{
|
||||||
static GType gst_camera_bin_type = 0;
|
static GType gst_camera_bin_type = 0;
|
||||||
|
static const GInterfaceInfo camerabin_tagsetter_info = {
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
if (!gst_camera_bin_type) {
|
if (!gst_camera_bin_type) {
|
||||||
static const GTypeInfo gst_camera_bin_info = {
|
static const GTypeInfo gst_camera_bin_info = {
|
||||||
|
@ -121,6 +126,9 @@ gst_camera_bin_get_type (void)
|
||||||
gst_camera_bin_type =
|
gst_camera_bin_type =
|
||||||
g_type_register_static (GST_TYPE_PIPELINE, "GstCameraBin2",
|
g_type_register_static (GST_TYPE_PIPELINE, "GstCameraBin2",
|
||||||
&gst_camera_bin_info, 0);
|
&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;
|
return gst_camera_bin_type;
|
||||||
|
@ -149,7 +157,30 @@ gst_camera_bin_new_event_renegotiate (void)
|
||||||
static void
|
static void
|
||||||
gst_camera_bin_start_capture (GstCameraBin * camerabin)
|
gst_camera_bin_start_capture (GstCameraBin * camerabin)
|
||||||
{
|
{
|
||||||
|
const GstTagList *taglist;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (camerabin, "Received start-capture");
|
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);
|
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) {
|
switch (trans) {
|
||||||
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
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);
|
gst_element_set_state (camera->videosink, GST_STATE_READY);
|
||||||
break;
|
break;
|
||||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||||
|
|
|
@ -201,6 +201,7 @@ elements_camerabin2_CFLAGS = \
|
||||||
elements_camerabin2_LDADD = \
|
elements_camerabin2_LDADD = \
|
||||||
$(top_builddir)/gst-libs/gst/interfaces/libgstphotography-@GST_MAJORMINOR@.la \
|
$(top_builddir)/gst-libs/gst/interfaces/libgstphotography-@GST_MAJORMINOR@.la \
|
||||||
$(top_builddir)/gst-libs/gst/basecamerabinsrc/libgstbasecamerabinsrc-@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)
|
$(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) $(GST_LIBS) $(LDADD)
|
||||||
elements_camerabin2_SOURCES = elements/camerabin2.c
|
elements_camerabin2_SOURCES = elements/camerabin2.c
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include <gst/video/video.h>
|
#include <gst/video/video.h>
|
||||||
#include <gst/check/gstcheck.h>
|
#include <gst/check/gstcheck.h>
|
||||||
#include <gst/basecamerabinsrc/gstbasecamerasrc.h>
|
#include <gst/basecamerabinsrc/gstbasecamerasrc.h>
|
||||||
|
#include <gst/pbutils/encoding-profile.h>
|
||||||
|
|
||||||
#define IMAGE_FILENAME "image"
|
#define IMAGE_FILENAME "image"
|
||||||
#define VIDEO_FILENAME "video"
|
#define VIDEO_FILENAME "video"
|
||||||
|
@ -171,6 +172,26 @@ guint32 test_id = 0;
|
||||||
|
|
||||||
static GstBuffer *preview_buffer;
|
static GstBuffer *preview_buffer;
|
||||||
static GstCaps *preview_caps;
|
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 */
|
/* helper function for filenames */
|
||||||
static const gchar *
|
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
|
static void
|
||||||
setup_wrappercamerabinsrc_videotestsrc (void)
|
setup_wrappercamerabinsrc_videotestsrc (void)
|
||||||
{
|
{
|
||||||
|
@ -334,6 +380,10 @@ teardown (void)
|
||||||
gst_buffer_unref (preview_buffer);
|
gst_buffer_unref (preview_buffer);
|
||||||
preview_buffer = NULL;
|
preview_buffer = NULL;
|
||||||
|
|
||||||
|
if (tags_found)
|
||||||
|
gst_tag_list_free (tags_found);
|
||||||
|
tags_found = NULL;
|
||||||
|
|
||||||
GST_INFO ("done");
|
GST_INFO ("done");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -360,12 +410,32 @@ validity_bus_cb (GstBus * bus, GstMessage * message, gpointer data)
|
||||||
g_main_loop_quit (loop);
|
g_main_loop_quit (loop);
|
||||||
GST_DEBUG ("eos");
|
GST_DEBUG ("eos");
|
||||||
break;
|
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:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return TRUE;
|
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
|
/* Validate captured files by playing them with playbin
|
||||||
* and checking that no errors occur. */
|
* and checking that no errors occur. */
|
||||||
static gboolean
|
static gboolean
|
||||||
|
@ -417,6 +487,17 @@ check_file_validity (const gchar * filename, gint num, GstTagList * taglist,
|
||||||
g_main_loop_run (loop);
|
g_main_loop_run (loop);
|
||||||
gst_element_set_state (playbin, GST_STATE_NULL);
|
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);
|
g_free (uri);
|
||||||
gst_object_unref (bus);
|
gst_object_unref (bus);
|
||||||
gst_object_unref (playbin);
|
gst_object_unref (playbin);
|
||||||
|
@ -703,6 +784,150 @@ GST_START_TEST (test_image_capture_previews)
|
||||||
GST_END_TEST;
|
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)
|
GST_START_TEST (test_supported_caps)
|
||||||
{
|
{
|
||||||
GstCaps *padcaps = NULL;
|
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_multiple_video_recordings);
|
||||||
|
|
||||||
tcase_add_test (tc_basic, test_image_capture_previews);
|
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:
|
end:
|
||||||
|
|
Loading…
Reference in a new issue