diff --git a/tests/check/elements/camerabin.c b/tests/check/elements/camerabin.c index 8f3d19f88c..3458cac8d7 100644 --- a/tests/check/elements/camerabin.c +++ b/tests/check/elements/camerabin.c @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include #define IMAGE_FILENAME "image" @@ -42,6 +44,11 @@ #define VIDEO_PAD_SUPPORTED_CAPS "video/x-raw, format=RGB, width=600, height=480" #define IMAGE_PAD_SUPPORTED_CAPS "video/x-raw, format=RGB, width=800, height=600" +static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/x-raw, format=RGB")); + static GstStaticPadTemplate vfsrc_template = GST_STATIC_PAD_TEMPLATE (GST_BASE_CAMERA_SRC_VIEWFINDER_PAD_NAME, GST_PAD_SRC, @@ -89,7 +96,6 @@ struct _GstTestCameraSrcClass GType gst_test_camera_src_get_type (void); -#define gst_test_camera_src_parent_class parent_class G_DEFINE_TYPE (GstTestCameraSrc, gst_test_camera_src, GST_TYPE_BASE_CAMERA_SRC); static gboolean @@ -197,8 +203,244 @@ gst_test_camera_src_init (GstTestCameraSrc * self) /* end of custom test camera src element */ +/* custom video source element that implements GstPhotography iface */ + +#define GST_TYPE_TEST_VIDEO_SRC \ + (gst_test_video_src_get_type()) +#define GST_TEST_VIDEO_SRC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_TEST_VIDEO_SRC,GstTestVideoSrc)) +#define GST_TEST_VIDEO_SRC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_TEST_VIDEO_SRC,GstTestVideoSrcClass)) +#define GST_TEST_VIDEO_SRC_CAST(obj) ((GstTestVideoSrc *)obj) + +typedef struct _GstTestVideoSrc GstTestVideoSrc; +typedef struct _GstTestVideoSrcClass GstTestVideoSrcClass; +struct _GstTestVideoSrc +{ + GstPushSrc element; + + gint width, height; + GstCaps *caps; + + /* if TRUE, this element will only output resolutions with * + * same width and height (square frames). This allows us testing * + * extra cropping feature with GstPhotography interface captures */ + gboolean enable_resolution_restriction; +}; + +struct _GstTestVideoSrcClass +{ + GstPushSrcClass parent_class; +}; + +GType gst_test_video_src_get_type (void); + +enum +{ + PROP_0, + PROP_WB_MODE, + PROP_COLOR_TONE, + PROP_SCENE_MODE, + PROP_FLASH_MODE, + PROP_FLICKER_MODE, + PROP_FOCUS_MODE, + PROP_CAPABILITIES, + PROP_EV_COMP, + PROP_ISO_SPEED, + PROP_APERTURE, + PROP_EXPOSURE_TIME, + PROP_IMAGE_PREVIEW_SUPPORTED_CAPS, + PROP_IMAGE_CAPTURE_SUPPORTED_CAPS, + PROP_ZOOM, + PROP_COLOR_TEMPERATURE, + PROP_WHITE_POINT, + PROP_ANALOG_GAIN, + PROP_LENS_FOCUS, + PROP_MIN_EXPOSURE_TIME, + PROP_MAX_EXPORURE_TIME, + PROP_NOISE_REDUCTION +}; + +static gboolean +gst_test_video_src_prepare_for_capture (GstPhotography * photo, + GstPhotographyCapturePrepared func, GstCaps * capture_caps, + gpointer user_data) +{ + GstCaps *caps; + GstTestVideoSrc *testvideosrc = GST_TEST_VIDEO_SRC (photo); + + if (testvideosrc->enable_resolution_restriction) { + GstStructure *str = gst_caps_get_structure (capture_caps, 0); + gint width, height; + + gst_structure_get_int (str, "width", &width); + gst_structure_get_int (str, "height", &height); + + width = height = MAX (width, height); + str = gst_structure_copy (str); + gst_structure_set (str, "width", G_TYPE_INT, width, "height", G_TYPE_INT, + height, NULL); + caps = gst_caps_new_full (str, NULL); + caps = gst_caps_fixate (caps); + fail_unless (testvideosrc->caps == NULL); + testvideosrc->caps = gst_caps_ref (caps); + } else { + caps = gst_caps_ref (capture_caps); + } + + func (user_data, caps); + gst_caps_unref (caps); + return TRUE; +} + +static void +gst_test_video_src_photography_init (gpointer g_iface, gpointer iface_data) +{ + GstPhotographyInterface *iface = g_iface; + + iface->prepare_for_capture = gst_test_video_src_prepare_for_capture; +} + +G_DEFINE_TYPE_WITH_CODE (GstTestVideoSrc, gst_test_video_src, GST_TYPE_PUSH_SRC, + G_IMPLEMENT_INTERFACE (GST_TYPE_PHOTOGRAPHY, + gst_test_video_src_photography_init)); + +static void +gst_test_video_src_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec) +{ + /* don't care */ +} + +static void +gst_test_video_src_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec) +{ + /* don't care */ +} + +static gboolean +gst_test_video_src_set_caps (GstBaseSrc * src, GstCaps * caps) +{ + GstTestVideoSrc *self = GST_TEST_VIDEO_SRC (src); + GstStructure *structure = gst_caps_get_structure (caps, 0); + + + fail_unless (gst_structure_get_int (structure, "width", &self->width)); + fail_unless (gst_structure_get_int (structure, "height", &self->height)); + + return TRUE; +} + +static GstFlowReturn +gst_test_video_src_alloc (GstPushSrc * src, GstBuffer ** buf) +{ + GstTestVideoSrc *self = GST_TEST_VIDEO_SRC (src); + guint8 *data; + gsize data_size; + + if (self->caps) { + gst_base_src_set_caps (GST_BASE_SRC (self), self->caps); + gst_caps_unref (self->caps); + self->caps = NULL; + } + + data_size = self->width * self->height * 3; /* RGB size */ + data = g_malloc (data_size); + *buf = gst_buffer_new_wrapped (data, data_size); + + return GST_FLOW_OK; +} + +static GstFlowReturn +gst_test_video_src_fill (GstPushSrc * src, GstBuffer * buf) +{ + /* NOP */ + return GST_FLOW_OK; +} + +static void +gst_test_video_src_class_init (GstTestVideoSrcClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); + GstBaseSrcClass *gstbasesrc_class = GST_BASE_SRC_CLASS (klass); + GstPushSrcClass *gstpushsrc_class = GST_PUSH_SRC_CLASS (klass); + + gst_element_class_set_static_metadata (gstelement_class, + "Test Camera Video Src", + "Video/Src", + "Test camera video src", "Thiago Santos "); + + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&src_template)); + + gobject_class->get_property = gst_test_video_src_get_property; + gobject_class->set_property = gst_test_video_src_set_property; + + gstbasesrc_class->set_caps = gst_test_video_src_set_caps; + gstpushsrc_class->alloc = gst_test_video_src_alloc; + gstpushsrc_class->fill = gst_test_video_src_fill; + + /* photography interface properties */ + g_object_class_override_property (gobject_class, PROP_WB_MODE, + GST_PHOTOGRAPHY_PROP_WB_MODE); + g_object_class_override_property (gobject_class, PROP_COLOR_TONE, + GST_PHOTOGRAPHY_PROP_COLOR_TONE); + g_object_class_override_property (gobject_class, PROP_SCENE_MODE, + GST_PHOTOGRAPHY_PROP_SCENE_MODE); + g_object_class_override_property (gobject_class, PROP_FLASH_MODE, + GST_PHOTOGRAPHY_PROP_FLASH_MODE); + g_object_class_override_property (gobject_class, PROP_FLICKER_MODE, + GST_PHOTOGRAPHY_PROP_FLICKER_MODE); + g_object_class_override_property (gobject_class, PROP_FOCUS_MODE, + GST_PHOTOGRAPHY_PROP_FOCUS_MODE); + g_object_class_override_property (gobject_class, PROP_CAPABILITIES, + GST_PHOTOGRAPHY_PROP_CAPABILITIES); + g_object_class_override_property (gobject_class, PROP_EV_COMP, + GST_PHOTOGRAPHY_PROP_EV_COMP); + g_object_class_override_property (gobject_class, PROP_ISO_SPEED, + GST_PHOTOGRAPHY_PROP_ISO_SPEED); + g_object_class_override_property (gobject_class, PROP_APERTURE, + GST_PHOTOGRAPHY_PROP_APERTURE); + g_object_class_override_property (gobject_class, PROP_EXPOSURE_TIME, + GST_PHOTOGRAPHY_PROP_EXPOSURE_TIME); + g_object_class_override_property (gobject_class, + PROP_IMAGE_PREVIEW_SUPPORTED_CAPS, + GST_PHOTOGRAPHY_PROP_IMAGE_PREVIEW_SUPPORTED_CAPS); + g_object_class_override_property (gobject_class, + PROP_IMAGE_CAPTURE_SUPPORTED_CAPS, + GST_PHOTOGRAPHY_PROP_IMAGE_CAPTURE_SUPPORTED_CAPS); + g_object_class_override_property (gobject_class, PROP_ZOOM, + GST_PHOTOGRAPHY_PROP_ZOOM); + g_object_class_override_property (gobject_class, PROP_COLOR_TEMPERATURE, + GST_PHOTOGRAPHY_PROP_COLOR_TEMPERATURE); + g_object_class_override_property (gobject_class, PROP_WHITE_POINT, + GST_PHOTOGRAPHY_PROP_WHITE_POINT); + g_object_class_override_property (gobject_class, PROP_ANALOG_GAIN, + GST_PHOTOGRAPHY_PROP_ANALOG_GAIN); + g_object_class_override_property (gobject_class, PROP_LENS_FOCUS, + GST_PHOTOGRAPHY_PROP_LENS_FOCUS); + g_object_class_override_property (gobject_class, PROP_MIN_EXPOSURE_TIME, + GST_PHOTOGRAPHY_PROP_MIN_EXPOSURE_TIME); + g_object_class_override_property (gobject_class, PROP_MAX_EXPORURE_TIME, + GST_PHOTOGRAPHY_PROP_MAX_EXPOSURE_TIME); + g_object_class_override_property (gobject_class, PROP_NOISE_REDUCTION, + GST_PHOTOGRAPHY_PROP_NOISE_REDUCTION); +} + +static void +gst_test_video_src_init (GstTestVideoSrc * self) +{ + gst_base_src_set_format (GST_BASE_SRC (self), GST_FORMAT_TIME); +} + +/* end of custom test camera src element */ +/* end of custom video source element that implements GstPhotography iface */ + static GstElement *camera; +static GstElement *testsrc; static guint bus_source; static GMainLoop *main_loop; static gint capture_count = 0; @@ -395,9 +637,30 @@ extract_jpeg_tags (const gchar * filename, gint num) } static void -setup_wrappercamerabinsrc_videotestsrc (void) +setup_camerabin_common (void) { GstBus *bus; + test_id = g_random_int (); + bus_source = 0; + + main_loop = g_main_loop_new (NULL, TRUE); + + camera = gst_check_setup_element ("camerabin"); + fail_unless (camera != NULL, "failed to create camerabin element"); + + bus = gst_pipeline_get_bus (GST_PIPELINE (camera)); + bus_source = gst_bus_add_watch (bus, (GstBusFunc) capture_bus_cb, main_loop); + gst_object_unref (bus); + + tags_found = NULL; + capture_count = 0; + image_filename = make_test_file_name (IMAGE_FILENAME, -1); + video_filename = make_test_file_name (VIDEO_FILENAME, -1); +} + +static void +setup_wrappercamerabinsrc_videotestsrc (void) +{ GstElement *vfbin; GstElement *fakevideosink; GstElement *src; @@ -406,13 +669,8 @@ setup_wrappercamerabinsrc_videotestsrc (void) GST_INFO ("init"); - test_id = g_random_int (); - bus_source = 0; + setup_camerabin_common (); - main_loop = g_main_loop_new (NULL, TRUE); - - camera = gst_check_setup_element ("camerabin"); - fail_unless (camera != NULL, "failed to create camerabin element"); fakevideosink = gst_element_factory_make ("fakesink", NULL); fail_unless (fakevideosink != NULL, "failed to create fakesink element"); src = gst_element_factory_make ("wrappercamerabinsrc", NULL); @@ -439,14 +697,46 @@ setup_wrappercamerabinsrc_videotestsrc (void) gst_object_unref (vfbin); gst_object_unref (fakevideosink); - bus = gst_pipeline_get_bus (GST_PIPELINE (camera)); - bus_source = gst_bus_add_watch (bus, (GstBusFunc) capture_bus_cb, main_loop); - gst_object_unref (bus); + GST_INFO ("init finished"); +} - tags_found = NULL; - capture_count = 0; - image_filename = make_test_file_name (IMAGE_FILENAME, -1); - video_filename = make_test_file_name (VIDEO_FILENAME, -1); +static void +setup_test_camerasrc (void) +{ + GstElement *vfbin; + GstElement *fakevideosink; + GstElement *src; + GstElement *audiosrc; + + GST_INFO ("init"); + + setup_camerabin_common (); + + fakevideosink = gst_element_factory_make ("fakesink", NULL); + fail_unless (fakevideosink != NULL, "failed to create fakesink element"); + src = gst_element_factory_make ("wrappercamerabinsrc", NULL); + fail_unless (src != NULL, "failed to create wrappercamerabinsrc element"); + testsrc = g_object_new (GST_TYPE_TEST_VIDEO_SRC, NULL); + fail_unless (testsrc != NULL, "failed to create testvideosrc element"); + g_object_set (testsrc, "name", "testsrc", NULL); + audiosrc = gst_element_factory_make ("audiotestsrc", NULL); + fail_unless (audiosrc != NULL, "failed to create audiotestsrc element"); + + preview_caps = gst_caps_new_simple ("video/x-raw", "width", G_TYPE_INT, + 320, "height", G_TYPE_INT, 240, NULL); + + g_object_set (G_OBJECT (audiosrc), "is-live", TRUE, NULL); + g_object_set (G_OBJECT (src), "video-source", testsrc, NULL); + g_object_set (G_OBJECT (camera), "camera-source", src, "preview-caps", + preview_caps, "post-previews", TRUE, "audio-source", audiosrc, NULL); + gst_object_unref (src); + gst_object_unref (testsrc); + gst_object_unref (audiosrc); + + vfbin = gst_bin_get_by_name (GST_BIN (camera), "vf-bin"); + g_object_set (G_OBJECT (vfbin), "video-sink", fakevideosink, NULL); + gst_object_unref (vfbin); + gst_object_unref (fakevideosink); GST_INFO ("init finished"); } @@ -1589,6 +1879,39 @@ GST_START_TEST (test_image_location_switching) GST_END_TEST; +GST_START_TEST (test_photography_iface_image_capture) +{ + run_single_image_capture_test (NULL, NULL); +} + +GST_END_TEST; + + +GST_START_TEST (test_photography_iface_image_capture_with_caps) +{ + GstCaps *caps = gst_caps_from_string ("video/x-raw, width=800, height=600"); + + run_single_image_capture_test (NULL, caps); + gst_caps_unref (caps); +} + +GST_END_TEST; + + +GST_START_TEST (test_photography_iface_image_capture_with_caps_and_restriction) +{ + GstCaps *caps = gst_caps_from_string ("video/x-raw, width=800, height=600"); + + /* the source will actually provide an image with 800x800 resolution */ + GST_TEST_VIDEO_SRC (testsrc)->enable_resolution_restriction = TRUE; + + run_single_image_capture_test (NULL, caps); + gst_caps_unref (caps); +} + +GST_END_TEST; + + typedef struct _TestCaseDef { const gchar *name; @@ -1606,6 +1929,7 @@ camerabin_suite (void) Suite *s = suite_create ("camerabin"); gint i; TCase *tc_generic = tcase_create ("generic"); + TCase *tc_phography_iface = tcase_create ("photography-iface"); jpegenc_factory = gst_element_factory_find ("jpegenc"); if (jpegenc_factory == NULL) { @@ -1646,6 +1970,26 @@ camerabin_suite (void) tcase_add_test (tc_basic, test_image_location_switching); } + /* This is the GstPhotography interface test case. It was added in 0.10 + * to make it easy for integrating with hardware and providing lower + * delays from action to capture. + * There is also has a feature in wrappercamerabinsrc that allows + * captures with the interface to have a different(higher) resolution than + * requested and wrappercamerabinsrc will crop to the requested one. + * This doesn't make sense and seems to be very hardware specific but we + * can't simply remove it at this point. + * + * FIXME 2.0: revisit GstPhotography interface and its interaction with + * camerabin */ + suite_add_tcase (s, tc_phography_iface); + tcase_add_checked_fixture (tc_phography_iface, setup_test_camerasrc, + teardown); + tcase_add_test (tc_phography_iface, test_photography_iface_image_capture); + tcase_add_test (tc_phography_iface, + test_photography_iface_image_capture_with_caps); + tcase_add_test (tc_phography_iface, + test_photography_iface_image_capture_with_caps_and_restriction); + end: return s; }