ret = gst_caps_copy (caps);
+ GST_OBJECT_LOCK (videoflip);
+
+ if (videoflip->change_configuring_method) {
+ GEnumValue *configuring_method_enum, *method_enum;
+ GEnumClass *enum_class =
+ g_type_class_ref (GST_TYPE_VIDEO_ORIENTATION_METHOD);
+
+ configuring_method_enum =
+ g_enum_get_value (enum_class, videoflip->configuring_method);
+ method_enum = g_enum_get_value (enum_class, videoflip->proposed_method);
+ GST_LOG_OBJECT (videoflip,
+ "Changing configuring method from %s to proposed %s",
+ configuring_method_enum ? configuring_method_enum->value_nick : "(nil)",
+ method_enum ? method_enum->value_nick : "(nil)");
+ g_type_class_unref (enum_class);
+
+ videoflip->configuring_method = videoflip->proposed_method;
+ }
+ videoflip->change_configuring_method = FALSE;
+
for (i = 0; i < gst_caps_get_size (ret); i++) {
GstStructure *structure = gst_caps_get_structure (ret, i);
gint par_n, par_d;
if (gst_structure_get_int (structure, "width", &width) &&
gst_structure_get_int (structure, "height", &height)) {
- switch (videoflip->active_method) {
+ switch (videoflip->configuring_method) {
case GST_VIDEO_ORIENTATION_90R:
case GST_VIDEO_ORIENTATION_90L:
case GST_VIDEO_ORIENTATION_UL_LR:
}
}
}
+ GST_OBJECT_UNLOCK (videoflip);
GST_DEBUG_OBJECT (videoflip, "transformed %" GST_PTR_FORMAT " to %"
GST_PTR_FORMAT, caps, ret);
}
break;
case GST_VIDEO_ORIENTATION_IDENTITY:
- g_assert_not_reached ();
+ gst_video_frame_copy (dest, src);
break;
default:
g_assert_not_reached ();
}
break;
case GST_VIDEO_ORIENTATION_IDENTITY:
- g_assert_not_reached ();
+ gst_video_frame_copy (dest, src);
break;
default:
g_assert_not_reached ();
}
break;
case GST_VIDEO_ORIENTATION_IDENTITY:
- g_assert_not_reached ();
+ gst_video_frame_copy (dest, src);
break;
default:
g_assert_not_reached ();
}
break;
case GST_VIDEO_ORIENTATION_IDENTITY:
- g_assert_not_reached ();
+ gst_video_frame_copy (dest, src);
break;
default:
g_assert_not_reached ();
}
}
+static void
+gst_video_flip_configure_process (GstVideoFlip * vf)
+{
+ switch (vf->v_format) {
+ case GST_VIDEO_FORMAT_I420:
+ case GST_VIDEO_FORMAT_YV12:
+ case GST_VIDEO_FORMAT_Y444:
+ vf->process = gst_video_flip_planar_yuv;
+ break;
+ case GST_VIDEO_FORMAT_YUY2:
+ case GST_VIDEO_FORMAT_UYVY:
+ case GST_VIDEO_FORMAT_YVYU:
+ vf->process = gst_video_flip_y422;
+ break;
+ case GST_VIDEO_FORMAT_AYUV:
+ case GST_VIDEO_FORMAT_ARGB:
+ case GST_VIDEO_FORMAT_ABGR:
+ case GST_VIDEO_FORMAT_RGBA:
+ case GST_VIDEO_FORMAT_BGRA:
+ case GST_VIDEO_FORMAT_xRGB:
+ case GST_VIDEO_FORMAT_xBGR:
+ case GST_VIDEO_FORMAT_RGBx:
+ case GST_VIDEO_FORMAT_BGRx:
+ case GST_VIDEO_FORMAT_RGB:
+ case GST_VIDEO_FORMAT_BGR:
+ case GST_VIDEO_FORMAT_GRAY8:
+ case GST_VIDEO_FORMAT_GRAY16_BE:
+ case GST_VIDEO_FORMAT_GRAY16_LE:
+ vf->process = gst_video_flip_packed_simple;
+ break;
+ case GST_VIDEO_FORMAT_NV12:
+ case GST_VIDEO_FORMAT_NV21:
+ vf->process = gst_video_flip_semi_planar_yuv;
+ break;
+ default:
+ break;
+ }
+}
static gboolean
gst_video_flip_set_info (GstVideoFilter * vfilter, GstCaps * incaps,
GstVideoInfo * in_info, GstCaps * outcaps, GstVideoInfo * out_info)
{
GstVideoFlip *vf = GST_VIDEO_FLIP (vfilter);
- gboolean ret = FALSE;
+ gboolean ret = FALSE, need_reconfigure = FALSE;
vf->process = NULL;
goto invalid_caps;
/* Check that they are correct */
- switch (vf->active_method) {
+ GST_OBJECT_LOCK (vf);
+ switch (vf->configuring_method) {
case GST_VIDEO_ORIENTATION_90R:
case GST_VIDEO_ORIENTATION_90L:
case GST_VIDEO_ORIENTATION_UL_LR:
}
break;
case GST_VIDEO_ORIENTATION_IDENTITY:
-
- break;
case GST_VIDEO_ORIENTATION_180:
case GST_VIDEO_ORIENTATION_HORIZ:
case GST_VIDEO_ORIENTATION_VERT:
ret = TRUE;
- switch (GST_VIDEO_INFO_FORMAT (in_info)) {
- case GST_VIDEO_FORMAT_I420:
- case GST_VIDEO_FORMAT_YV12:
- case GST_VIDEO_FORMAT_Y444:
- vf->process = gst_video_flip_planar_yuv;
- break;
- case GST_VIDEO_FORMAT_YUY2:
- case GST_VIDEO_FORMAT_UYVY:
- case GST_VIDEO_FORMAT_YVYU:
- vf->process = gst_video_flip_y422;
- break;
- case GST_VIDEO_FORMAT_AYUV:
- case GST_VIDEO_FORMAT_ARGB:
- case GST_VIDEO_FORMAT_ABGR:
- case GST_VIDEO_FORMAT_RGBA:
- case GST_VIDEO_FORMAT_BGRA:
- case GST_VIDEO_FORMAT_xRGB:
- case GST_VIDEO_FORMAT_xBGR:
- case GST_VIDEO_FORMAT_RGBx:
- case GST_VIDEO_FORMAT_BGRx:
- case GST_VIDEO_FORMAT_RGB:
- case GST_VIDEO_FORMAT_BGR:
- case GST_VIDEO_FORMAT_GRAY8:
- case GST_VIDEO_FORMAT_GRAY16_BE:
- case GST_VIDEO_FORMAT_GRAY16_LE:
- vf->process = gst_video_flip_packed_simple;
- break;
- case GST_VIDEO_FORMAT_NV12:
- case GST_VIDEO_FORMAT_NV21:
- vf->process = gst_video_flip_semi_planar_yuv;
- break;
- default:
- break;
+ {
+ GEnumValue *active_method_enum, *method_enum;
+ GEnumClass *enum_class =
+ g_type_class_ref (GST_TYPE_VIDEO_ORIENTATION_METHOD);
+
+ active_method_enum = g_enum_get_value (enum_class, vf->active_method);
+ method_enum = g_enum_get_value (enum_class, vf->configuring_method);
+ GST_LOG_OBJECT (vf, "Changing active method from %s to configuring %s",
+ active_method_enum ? active_method_enum->value_nick : "(nil)",
+ method_enum ? method_enum->value_nick : "(nil)");
+ g_type_class_unref (enum_class);
}
+ vf->active_method = vf->configuring_method;
+ vf->change_configuring_method = TRUE;
+ if (vf->active_method != vf->proposed_method)
+ need_reconfigure = TRUE;
+
+ vf->v_format = GST_VIDEO_INFO_FORMAT (in_info);
+ gst_video_flip_configure_process (vf);
beach:
+ GST_OBJECT_UNLOCK (vf);
+ if (need_reconfigure) {
+ gst_base_transform_reconfigure_src (GST_BASE_TRANSFORM (vf));
+ }
+
return ret && (vf->process != NULL);
invalid_caps:
else
method = videoflip->method;
- if (method != videoflip->active_method) {
+ if (method != videoflip->proposed_method) {
GEnumValue *active_method_enum, *method_enum;
GstBaseTransform *btrans = GST_BASE_TRANSFORM (videoflip);
GEnumClass *enum_class =
active_method_enum =
g_enum_get_value (enum_class, videoflip->active_method);
method_enum = g_enum_get_value (enum_class, method);
- GST_DEBUG_OBJECT (videoflip, "Changing method from %s to %s",
+ GST_LOG_OBJECT (videoflip, "Changing method from %s to %s",
active_method_enum ? active_method_enum->value_nick : "(nil)",
method_enum ? method_enum->value_nick : "(nil)");
g_type_class_unref (enum_class);
- videoflip->active_method = method;
+ videoflip->proposed_method = method;
GST_OBJECT_UNLOCK (videoflip);
GstVideoFrame * in_frame, GstVideoFrame * out_frame)
{
GEnumClass *enum_class;
+ GstVideoOrientationMethod active, proposed;
GEnumValue *active_method_enum;
GstVideoFlip *videoflip = GST_VIDEO_FLIP (vfilter);
+ GST_OBJECT_LOCK (videoflip);
if (G_UNLIKELY (videoflip->process == NULL))
goto not_negotiated;
+ if (videoflip->configuring_method != videoflip->active_method) {
+ videoflip->active_method = videoflip->configuring_method;
+ gst_video_flip_configure_process (videoflip);
+ }
+
enum_class = g_type_class_ref (GST_TYPE_VIDEO_ORIENTATION_METHOD);
active_method_enum = g_enum_get_value (enum_class, videoflip->active_method);
- GST_LOG_OBJECT (videoflip, "videoflip: flipping (%s)",
- active_method_enum ? active_method_enum->value_nick : "(nil)");
+ GST_LOG_OBJECT (videoflip,
+ "videoflip: flipping (%s), input %ux%u output %ux%u",
+ active_method_enum ? active_method_enum->value_nick : "(nil)",
+ GST_VIDEO_FRAME_WIDTH (in_frame), GST_VIDEO_FRAME_HEIGHT (in_frame),
+ GST_VIDEO_FRAME_WIDTH (out_frame), GST_VIDEO_FRAME_HEIGHT (out_frame));
g_type_class_unref (enum_class);
- GST_OBJECT_LOCK (videoflip);
videoflip->process (videoflip, out_frame, in_frame);
+
+ proposed = videoflip->proposed_method;
+ active = videoflip->active_method;
+ videoflip->change_configuring_method = TRUE;
GST_OBJECT_UNLOCK (videoflip);
+ if (proposed != active) {
+ gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (videoflip),
+ proposed == GST_VIDEO_ORIENTATION_IDENTITY);
+ gst_base_transform_reconfigure_src (GST_BASE_TRANSFORM (videoflip));
+ }
+
return GST_FLOW_OK;
not_negotiated:
{
+ GST_OBJECT_UNLOCK (videoflip);
GST_ERROR_OBJECT (videoflip, "Not negotiated yet");
return GST_FLOW_NOT_NEGOTIATED;
}
if (gst_structure_get_double (structure, "pointer_x", &x) &&
gst_structure_get_double (structure, "pointer_y", &y)) {
GST_DEBUG_OBJECT (vf, "converting %fx%f", x, y);
+ GST_OBJECT_LOCK (vf);
switch (vf->active_method) {
case GST_VIDEO_ORIENTATION_90R:
new_x = y;
new_y = y;
break;
}
+ GST_OBJECT_UNLOCK (vf);
GST_DEBUG_OBJECT (vf, "to %fx%f", new_x, new_y);
gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE, new_x,
"pointer_y", G_TYPE_DOUBLE, new_y, NULL);
GstElementClass *gstelement_class = (GstElementClass *) klass;
GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
GstVideoFilterClass *vfilter_class = (GstVideoFilterClass *) klass;
+ GParamSpec *pspec;
GST_DEBUG_CATEGORY_INIT (video_flip_debug, "videoflip", 0, "videoflip");
g_param_spec_enum ("method", "method",
"method (deprecated, use video-direction instead)",
GST_TYPE_VIDEO_FLIP_METHOD, PROP_METHOD_DEFAULT,
- GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
- G_PARAM_STATIC_STRINGS));
+ GST_PARAM_CONTROLLABLE | GST_PARAM_MUTABLE_PLAYING |
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
g_object_class_override_property (gobject_class, PROP_VIDEO_DIRECTION,
"video-direction");
+ /* override the overriden property's flags to include the mutable in playing
+ * flag */
+ pspec = g_object_class_find_property (gobject_class, "video-direction");
+ pspec->flags |= GST_PARAM_MUTABLE_PLAYING;
gst_element_class_set_static_metadata (gstelement_class, "Video flipper",
"Filter/Effect/Video",
/* AUTO is not valid for active method, this is just to ensure we setup the
* method in gst_video_flip_set_method() */
videoflip->active_method = GST_VIDEO_ORIENTATION_AUTO;
+ videoflip->proposed_method = GST_VIDEO_ORIENTATION_IDENTITY;
+ videoflip->configuring_method = GST_VIDEO_ORIENTATION_IDENTITY;
}
GST_END_TEST;
+GST_START_TEST (test_change_method_twice_same_caps_different_method)
+{
+ GstHarness *flip = gst_harness_new ("videoflip");
+ GstVideoInfo in_info, out_info;
+ GstCaps *in_caps, *out_caps;
+ GstEvent *e;
+ GstBuffer *input, *output, *buf;
+ GstMapInfo in_map_info, out_map_info;
+
+ gst_video_info_set_format (&in_info, GST_VIDEO_FORMAT_RGBA, 4, 9);
+ in_caps = gst_video_info_to_caps (&in_info);
+
+ gst_harness_set_src_caps (flip, in_caps);
+
+ e = gst_harness_pull_event (flip);
+ fail_unless_equals_int (GST_EVENT_TYPE (e), GST_EVENT_STREAM_START);
+ gst_event_unref (e);
+ e = gst_harness_pull_event (flip);
+ fail_unless_equals_int (GST_EVENT_TYPE (e), GST_EVENT_CAPS);
+ gst_event_parse_caps (e, &out_caps);
+ fail_unless (gst_video_info_from_caps (&out_info, out_caps));
+ fail_unless_equals_int (GST_VIDEO_INFO_WIDTH (&in_info),
+ GST_VIDEO_INFO_WIDTH (&out_info));
+ fail_unless_equals_int (GST_VIDEO_INFO_HEIGHT (&in_info),
+ GST_VIDEO_INFO_HEIGHT (&out_info));
+ gst_event_unref (e);
+
+ e = gst_harness_pull_event (flip);
+ fail_unless_equals_int (GST_EVENT_TYPE (e), GST_EVENT_SEGMENT);
+ gst_event_unref (e);
+
+ buf = create_test_video_buffer_rgba8 (&in_info);
+ buf = gst_harness_push_and_pull (flip, buf);
+ fail_unless (buf != NULL);
+ gst_buffer_unref (buf);
+
+ g_object_set (flip->element, "video-direction", 1 /* 90r */ , NULL);
+ g_object_set (flip->element, "video-direction", 2 /* 180 */ , NULL);
+
+ input = create_test_video_buffer_rgba8 (&in_info);
+ fail_unless_equals_int (gst_harness_push (flip, gst_buffer_ref (input)),
+ GST_FLOW_OK);
+ /* caps will not change and basetransform won't send updated ones so we
+ * can't check for them */
+ output = gst_harness_pull (flip);
+ fail_unless (output != NULL);
+
+ fail_unless (gst_buffer_map (input, &in_map_info, GST_MAP_READ));
+ fail_unless (gst_buffer_map (output, &out_map_info, GST_MAP_READ));
+
+ {
+ gsize top_right = (GST_VIDEO_INFO_WIDTH (&in_info) - 1) * 4;
+ gsize bottom_left =
+ (GST_VIDEO_INFO_HEIGHT (&out_info) -
+ 1) * GST_VIDEO_INFO_PLANE_STRIDE (&out_info, 0);
+
+ fail_unless_equals_int (in_map_info.data[top_right + 0],
+ out_map_info.data[bottom_left + 0]);
+ fail_unless_equals_int (in_map_info.data[top_right + 1],
+ out_map_info.data[bottom_left + 1]);
+ fail_unless_equals_int (in_map_info.data[top_right + 2],
+ out_map_info.data[bottom_left + 2]);
+ fail_unless_equals_int (in_map_info.data[top_right + 3],
+ out_map_info.data[bottom_left + 3]);
+ }
+
+ gst_buffer_unmap (input, &in_map_info);
+ gst_buffer_unmap (output, &out_map_info);
+
+ gst_buffer_unref (input);
+ gst_buffer_unref (output);
+
+ gst_harness_teardown (flip);
+}
+
+GST_END_TEST;
GST_START_TEST (test_stress_change_method)
{
GstHarness *flip = gst_harness_new ("videoflip");
suite_add_tcase (s, tc_chain);
tcase_add_test (tc_chain, test_passthrough);
tcase_add_test (tc_chain, test_change_method);
+ tcase_add_test (tc_chain,
+ test_change_method_twice_same_caps_different_method);
tcase_add_test (tc_chain, test_stress_change_method);
return s;