mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-20 23:36:38 +00:00
videoflip: Add automatic flip mode driven by image-orientation tag
https://bugzilla.gnome.org/show_bug.cgi?id=709312
This commit is contained in:
parent
94f3d6fc07
commit
ed77b22f2b
2 changed files with 101 additions and 33 deletions
|
@ -97,6 +97,8 @@ static const GEnumValue video_flip_methods[] = {
|
||||||
"Flip across upper left/lower right diagonal", "upper-left-diagonal"},
|
"Flip across upper left/lower right diagonal", "upper-left-diagonal"},
|
||||||
{GST_VIDEO_FLIP_METHOD_OTHER,
|
{GST_VIDEO_FLIP_METHOD_OTHER,
|
||||||
"Flip across upper right/lower left diagonal", "upper-right-diagonal"},
|
"Flip across upper right/lower left diagonal", "upper-right-diagonal"},
|
||||||
|
{GST_VIDEO_FLIP_METHOD_AUTO,
|
||||||
|
"Select flip method based on image-orientation tag", "automatic"},
|
||||||
{0, NULL, NULL},
|
{0, NULL, NULL},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -132,7 +134,7 @@ gst_video_flip_transform_caps (GstBaseTransform * trans,
|
||||||
if (gst_structure_get_int (structure, "width", &width) &&
|
if (gst_structure_get_int (structure, "width", &width) &&
|
||||||
gst_structure_get_int (structure, "height", &height)) {
|
gst_structure_get_int (structure, "height", &height)) {
|
||||||
|
|
||||||
switch (videoflip->method) {
|
switch (videoflip->active_method) {
|
||||||
case GST_VIDEO_FLIP_METHOD_90R:
|
case GST_VIDEO_FLIP_METHOD_90R:
|
||||||
case GST_VIDEO_FLIP_METHOD_90L:
|
case GST_VIDEO_FLIP_METHOD_90L:
|
||||||
case GST_VIDEO_FLIP_METHOD_TRANS:
|
case GST_VIDEO_FLIP_METHOD_TRANS:
|
||||||
|
@ -220,7 +222,7 @@ gst_video_flip_planar_yuv (GstVideoFlip * videoflip, GstVideoFrame * dest,
|
||||||
dest_u_height = GST_VIDEO_FRAME_COMP_HEIGHT (dest, 1);
|
dest_u_height = GST_VIDEO_FRAME_COMP_HEIGHT (dest, 1);
|
||||||
dest_v_height = GST_VIDEO_FRAME_COMP_HEIGHT (dest, 2);
|
dest_v_height = GST_VIDEO_FRAME_COMP_HEIGHT (dest, 2);
|
||||||
|
|
||||||
switch (videoflip->method) {
|
switch (videoflip->active_method) {
|
||||||
case GST_VIDEO_FLIP_METHOD_90R:
|
case GST_VIDEO_FLIP_METHOD_90R:
|
||||||
/* Flip Y */
|
/* Flip Y */
|
||||||
s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
|
s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
|
||||||
|
@ -464,7 +466,7 @@ gst_video_flip_semi_planar_yuv (GstVideoFlip * videoflip, GstVideoFrame * dest,
|
||||||
dest_y_height = GST_VIDEO_FRAME_COMP_HEIGHT (dest, 0);
|
dest_y_height = GST_VIDEO_FRAME_COMP_HEIGHT (dest, 0);
|
||||||
dest_uv_height = GST_VIDEO_FRAME_COMP_HEIGHT (dest, 1);
|
dest_uv_height = GST_VIDEO_FRAME_COMP_HEIGHT (dest, 1);
|
||||||
|
|
||||||
switch (videoflip->method) {
|
switch (videoflip->active_method) {
|
||||||
case GST_VIDEO_FLIP_METHOD_90R:
|
case GST_VIDEO_FLIP_METHOD_90R:
|
||||||
/* Flip Y */
|
/* Flip Y */
|
||||||
s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
|
s = GST_VIDEO_FRAME_PLANE_DATA (src, 0);
|
||||||
|
@ -650,7 +652,7 @@ gst_video_flip_packed_simple (GstVideoFlip * videoflip, GstVideoFrame * dest,
|
||||||
/* This is only true for non-subsampled formats! */
|
/* This is only true for non-subsampled formats! */
|
||||||
bpp = GST_VIDEO_FRAME_COMP_PSTRIDE (src, 0);
|
bpp = GST_VIDEO_FRAME_COMP_PSTRIDE (src, 0);
|
||||||
|
|
||||||
switch (videoflip->method) {
|
switch (videoflip->active_method) {
|
||||||
case GST_VIDEO_FLIP_METHOD_90R:
|
case GST_VIDEO_FLIP_METHOD_90R:
|
||||||
for (y = 0; y < dh; y++) {
|
for (y = 0; y < dh; y++) {
|
||||||
for (x = 0; x < dw; x++) {
|
for (x = 0; x < dw; x++) {
|
||||||
|
@ -760,7 +762,7 @@ gst_video_flip_y422 (GstVideoFlip * videoflip, GstVideoFrame * dest,
|
||||||
y_stride = GST_VIDEO_FRAME_COMP_PSTRIDE (src, 0);
|
y_stride = GST_VIDEO_FRAME_COMP_PSTRIDE (src, 0);
|
||||||
bpp = y_stride;
|
bpp = y_stride;
|
||||||
|
|
||||||
switch (videoflip->method) {
|
switch (videoflip->active_method) {
|
||||||
case GST_VIDEO_FLIP_METHOD_90R:
|
case GST_VIDEO_FLIP_METHOD_90R:
|
||||||
for (y = 0; y < dh; y++) {
|
for (y = 0; y < dh; y++) {
|
||||||
for (x = 0; x < dw; x += 2) {
|
for (x = 0; x < dw; x += 2) {
|
||||||
|
@ -959,7 +961,7 @@ gst_video_flip_set_info (GstVideoFilter * vfilter, GstCaps * incaps,
|
||||||
goto invalid_caps;
|
goto invalid_caps;
|
||||||
|
|
||||||
/* Check that they are correct */
|
/* Check that they are correct */
|
||||||
switch (vf->method) {
|
switch (vf->active_method) {
|
||||||
case GST_VIDEO_FLIP_METHOD_90R:
|
case GST_VIDEO_FLIP_METHOD_90R:
|
||||||
case GST_VIDEO_FLIP_METHOD_90L:
|
case GST_VIDEO_FLIP_METHOD_90L:
|
||||||
case GST_VIDEO_FLIP_METHOD_TRANS:
|
case GST_VIDEO_FLIP_METHOD_TRANS:
|
||||||
|
@ -1037,6 +1039,43 @@ invalid_caps:
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_video_flip_set_method (GstVideoFlip * videoflip, GstVideoFlipMethod method,
|
||||||
|
gboolean from_tag)
|
||||||
|
{
|
||||||
|
GST_OBJECT_LOCK (videoflip);
|
||||||
|
|
||||||
|
/* Store updated method */
|
||||||
|
if (from_tag)
|
||||||
|
videoflip->tag_method = method;
|
||||||
|
else
|
||||||
|
videoflip->method = method;
|
||||||
|
|
||||||
|
/* Get the new method */
|
||||||
|
if (videoflip->method == GST_VIDEO_FLIP_METHOD_AUTO)
|
||||||
|
method = videoflip->tag_method;
|
||||||
|
else
|
||||||
|
method = videoflip->method;
|
||||||
|
|
||||||
|
if (method != videoflip->active_method) {
|
||||||
|
GstBaseTransform *btrans = GST_BASE_TRANSFORM (videoflip);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (videoflip, "Changing method from %s to %s",
|
||||||
|
video_flip_methods[videoflip->active_method].value_nick,
|
||||||
|
video_flip_methods[method].value_nick);
|
||||||
|
|
||||||
|
videoflip->active_method = method;
|
||||||
|
|
||||||
|
GST_OBJECT_UNLOCK (videoflip);
|
||||||
|
|
||||||
|
gst_base_transform_set_passthrough (btrans,
|
||||||
|
method == GST_VIDEO_FLIP_METHOD_IDENTITY);
|
||||||
|
gst_base_transform_reconfigure_src (btrans);
|
||||||
|
} else {
|
||||||
|
GST_OBJECT_UNLOCK (videoflip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_video_flip_before_transform (GstBaseTransform * trans, GstBuffer * in)
|
gst_video_flip_before_transform (GstBaseTransform * trans, GstBuffer * in)
|
||||||
{
|
{
|
||||||
|
@ -1064,7 +1103,7 @@ gst_video_flip_transform_frame (GstVideoFilter * vfilter,
|
||||||
goto not_negotiated;
|
goto not_negotiated;
|
||||||
|
|
||||||
GST_LOG_OBJECT (videoflip, "videoflip: flipping (%s)",
|
GST_LOG_OBJECT (videoflip, "videoflip: flipping (%s)",
|
||||||
video_flip_methods[videoflip->method].value_nick);
|
video_flip_methods[videoflip->active_method].value_nick);
|
||||||
|
|
||||||
GST_OBJECT_LOCK (videoflip);
|
GST_OBJECT_LOCK (videoflip);
|
||||||
videoflip->process (videoflip, out_frame, in_frame);
|
videoflip->process (videoflip, out_frame, in_frame);
|
||||||
|
@ -1099,7 +1138,7 @@ gst_video_flip_src_event (GstBaseTransform * trans, GstEvent * event)
|
||||||
if (gst_structure_get_double (structure, "pointer_x", &x) &&
|
if (gst_structure_get_double (structure, "pointer_x", &x) &&
|
||||||
gst_structure_get_double (structure, "pointer_y", &y)) {
|
gst_structure_get_double (structure, "pointer_y", &y)) {
|
||||||
GST_DEBUG_OBJECT (vf, "converting %fx%f", x, y);
|
GST_DEBUG_OBJECT (vf, "converting %fx%f", x, y);
|
||||||
switch (vf->method) {
|
switch (vf->active_method) {
|
||||||
case GST_VIDEO_FLIP_METHOD_90R:
|
case GST_VIDEO_FLIP_METHOD_90R:
|
||||||
new_x = y;
|
new_x = y;
|
||||||
new_y = out_info->width - x;
|
new_y = out_info->width - x;
|
||||||
|
@ -1147,6 +1186,50 @@ gst_video_flip_src_event (GstBaseTransform * trans, GstEvent * event)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_video_flip_sink_event (GstBaseTransform * trans, GstEvent * event)
|
||||||
|
{
|
||||||
|
GstVideoFlip *vf = GST_VIDEO_FLIP (trans);
|
||||||
|
GstTagList *taglist;
|
||||||
|
gchar *orientation;
|
||||||
|
gboolean ret;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (vf, "handling %s event", GST_EVENT_TYPE_NAME (event));
|
||||||
|
|
||||||
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
|
case GST_EVENT_TAG:
|
||||||
|
gst_event_parse_tag (event, &taglist);
|
||||||
|
|
||||||
|
if (gst_tag_list_get_string (taglist, "image-orientation", &orientation)) {
|
||||||
|
if (!g_strcmp0 ("rotate-0", orientation))
|
||||||
|
gst_video_flip_set_method (vf, GST_VIDEO_FLIP_METHOD_IDENTITY, TRUE);
|
||||||
|
else if (!g_strcmp0 ("rotate-90", orientation))
|
||||||
|
gst_video_flip_set_method (vf, GST_VIDEO_FLIP_METHOD_90R, TRUE);
|
||||||
|
else if (!g_strcmp0 ("rotate-180", orientation))
|
||||||
|
gst_video_flip_set_method (vf, GST_VIDEO_FLIP_METHOD_180, TRUE);
|
||||||
|
else if (!g_strcmp0 ("rotate-270", orientation))
|
||||||
|
gst_video_flip_set_method (vf, GST_VIDEO_FLIP_METHOD_90L, TRUE);
|
||||||
|
else if (!g_strcmp0 ("flip-rotate-0", orientation))
|
||||||
|
gst_video_flip_set_method (vf, GST_VIDEO_FLIP_METHOD_HORIZ, TRUE);
|
||||||
|
else if (!g_strcmp0 ("flip-rotate-90", orientation))
|
||||||
|
gst_video_flip_set_method (vf, GST_VIDEO_FLIP_METHOD_TRANS, TRUE);
|
||||||
|
else if (!g_strcmp0 ("flip-rotate-180", orientation))
|
||||||
|
gst_video_flip_set_method (vf, GST_VIDEO_FLIP_METHOD_VERT, TRUE);
|
||||||
|
else if (!g_strcmp0 ("flip-rotate-270", orientation))
|
||||||
|
gst_video_flip_set_method (vf, GST_VIDEO_FLIP_METHOD_OTHER, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (orientation);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = GST_BASE_TRANSFORM_CLASS (parent_class)->sink_event (trans, event);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_video_flip_set_property (GObject * object, guint prop_id,
|
gst_video_flip_set_property (GObject * object, guint prop_id,
|
||||||
const GValue * value, GParamSpec * pspec)
|
const GValue * value, GParamSpec * pspec)
|
||||||
|
@ -1155,28 +1238,7 @@ gst_video_flip_set_property (GObject * object, guint prop_id,
|
||||||
|
|
||||||
switch (prop_id) {
|
switch (prop_id) {
|
||||||
case PROP_METHOD:
|
case PROP_METHOD:
|
||||||
{
|
gst_video_flip_set_method (videoflip, g_value_get_enum (value), FALSE);
|
||||||
GstVideoFlipMethod method;
|
|
||||||
|
|
||||||
method = g_value_get_enum (value);
|
|
||||||
GST_OBJECT_LOCK (videoflip);
|
|
||||||
if (method != videoflip->method) {
|
|
||||||
GstBaseTransform *btrans = GST_BASE_TRANSFORM (videoflip);
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (videoflip, "Changing method from %s to %s",
|
|
||||||
video_flip_methods[videoflip->method].value_nick,
|
|
||||||
video_flip_methods[method].value_nick);
|
|
||||||
|
|
||||||
videoflip->method = method;
|
|
||||||
GST_OBJECT_UNLOCK (videoflip);
|
|
||||||
|
|
||||||
gst_base_transform_set_passthrough (btrans,
|
|
||||||
method == GST_VIDEO_FLIP_METHOD_IDENTITY);
|
|
||||||
gst_base_transform_reconfigure_src (btrans);
|
|
||||||
} else {
|
|
||||||
GST_OBJECT_UNLOCK (videoflip);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
@ -1232,6 +1294,7 @@ gst_video_flip_class_init (GstVideoFlipClass * klass)
|
||||||
trans_class->before_transform =
|
trans_class->before_transform =
|
||||||
GST_DEBUG_FUNCPTR (gst_video_flip_before_transform);
|
GST_DEBUG_FUNCPTR (gst_video_flip_before_transform);
|
||||||
trans_class->src_event = GST_DEBUG_FUNCPTR (gst_video_flip_src_event);
|
trans_class->src_event = GST_DEBUG_FUNCPTR (gst_video_flip_src_event);
|
||||||
|
trans_class->sink_event = GST_DEBUG_FUNCPTR (gst_video_flip_sink_event);
|
||||||
|
|
||||||
vfilter_class->set_info = GST_DEBUG_FUNCPTR (gst_video_flip_set_info);
|
vfilter_class->set_info = GST_DEBUG_FUNCPTR (gst_video_flip_set_info);
|
||||||
vfilter_class->transform_frame =
|
vfilter_class->transform_frame =
|
||||||
|
@ -1241,6 +1304,7 @@ gst_video_flip_class_init (GstVideoFlipClass * klass)
|
||||||
static void
|
static void
|
||||||
gst_video_flip_init (GstVideoFlip * videoflip)
|
gst_video_flip_init (GstVideoFlip * videoflip)
|
||||||
{
|
{
|
||||||
videoflip->method = PROP_METHOD_DEFAULT;
|
/* AUTO is not valid for active method, this is just to ensure we setup the
|
||||||
gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (videoflip), TRUE);
|
* method in gst_video_flip_set_method() */
|
||||||
|
videoflip->active_method = GST_VIDEO_FLIP_METHOD_AUTO;
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ G_BEGIN_DECLS
|
||||||
* @GST_VIDEO_FLIP_METHOD_VERT: Flip vertically
|
* @GST_VIDEO_FLIP_METHOD_VERT: Flip vertically
|
||||||
* @GST_VIDEO_FLIP_METHOD_TRANS: Flip across upper left/lower right diagonal
|
* @GST_VIDEO_FLIP_METHOD_TRANS: Flip across upper left/lower right diagonal
|
||||||
* @GST_VIDEO_FLIP_METHOD_OTHER: Flip across upper right/lower left diagonal
|
* @GST_VIDEO_FLIP_METHOD_OTHER: Flip across upper right/lower left diagonal
|
||||||
|
* @GST_VIDEO_FLIP_METHOD_AUTO: Select flip method based on image-orientation tag
|
||||||
*
|
*
|
||||||
* The different flip methods.
|
* The different flip methods.
|
||||||
*/
|
*/
|
||||||
|
@ -47,7 +48,8 @@ typedef enum {
|
||||||
GST_VIDEO_FLIP_METHOD_HORIZ,
|
GST_VIDEO_FLIP_METHOD_HORIZ,
|
||||||
GST_VIDEO_FLIP_METHOD_VERT,
|
GST_VIDEO_FLIP_METHOD_VERT,
|
||||||
GST_VIDEO_FLIP_METHOD_TRANS,
|
GST_VIDEO_FLIP_METHOD_TRANS,
|
||||||
GST_VIDEO_FLIP_METHOD_OTHER
|
GST_VIDEO_FLIP_METHOD_OTHER,
|
||||||
|
GST_VIDEO_FLIP_METHOD_AUTO
|
||||||
} GstVideoFlipMethod;
|
} GstVideoFlipMethod;
|
||||||
|
|
||||||
#define GST_TYPE_VIDEO_FLIP \
|
#define GST_TYPE_VIDEO_FLIP \
|
||||||
|
@ -74,6 +76,8 @@ struct _GstVideoFlip {
|
||||||
|
|
||||||
/* < private > */
|
/* < private > */
|
||||||
GstVideoFlipMethod method;
|
GstVideoFlipMethod method;
|
||||||
|
GstVideoFlipMethod tag_method;
|
||||||
|
GstVideoFlipMethod active_method;
|
||||||
void (*process) (GstVideoFlip *videoflip, GstVideoFrame *dest, const GstVideoFrame *src);
|
void (*process) (GstVideoFlip *videoflip, GstVideoFrame *dest, const GstVideoFrame *src);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue