From e22281e0458c48f1d38b7a2abf20121378a811f8 Mon Sep 17 00:00:00 2001 From: Kazunori Kobayashi Date: Thu, 18 Oct 2012 18:27:03 +0900 Subject: [PATCH 22/31] videocrop: move output buffer size calculation to transform_size() transform_size() is the optional method that can be overridden to calculate buffer sizes. The default implementation uses get_unit_size(), but when performing zero-copy cropping, transform_size() should be used because the buffer size calculation is different from the default. The buffer size calculation should be performed using the tranform_size() override, rather than being inlined in prepare_output_buffer(). --- gst/videocrop/gstvideocrop.c | 120 +++++++++++++++++++++++++++++++++--------- 1 file changed, 95 insertions(+), 25 deletions(-) diff --git a/gst/videocrop/gstvideocrop.c b/gst/videocrop/gstvideocrop.c index 4d2a027..4887137 100644 --- a/gst/videocrop/gstvideocrop.c +++ b/gst/videocrop/gstvideocrop.c @@ -140,6 +140,9 @@ static gboolean gst_video_crop_src_event (GstBaseTransform * trans, static GstFlowReturn gst_video_crop_prepare_output_buffer (GstBaseTransform * trans, GstBuffer * input, gint size, GstCaps * caps, GstBuffer ** buf); static gboolean gst_video_crop_query_stride_supported (GstVideoCrop * vcrop); +static gboolean gst_videocrop_transform_size (GstBaseTransform * trans, + GstPadDirection direction, GstCaps * caps, guint size, GstCaps * othercaps, + guint * othersize); static void gst_video_crop_base_init (gpointer g_class) @@ -234,6 +237,8 @@ gst_video_crop_class_init (GstVideoCropClass * klass) GST_DEBUG_FUNCPTR (gst_video_crop_get_unit_size); basetransform_class->prepare_output_buffer = GST_DEBUG_FUNCPTR (gst_video_crop_prepare_output_buffer); + basetransform_class->transform_size = + GST_DEBUG_FUNCPTR (gst_videocrop_transform_size); basetransform_class->passthrough_on_same_caps = FALSE; basetransform_class->src_event = GST_DEBUG_FUNCPTR (gst_video_crop_src_event); @@ -838,7 +843,6 @@ gst_video_crop_prepare_output_buffer (GstBaseTransform * trans, GstBuffer * input, gint size, GstCaps * caps, GstBuffer ** buf) { GstVideoCrop *vcrop = GST_VIDEO_CROP (trans); - guint sub_offset, sub_size; if (!gst_video_crop_query_stride_supported (vcrop)) { GST_LOG_OBJECT @@ -847,30 +851,7 @@ gst_video_crop_prepare_output_buffer (GstBaseTransform * trans, return GST_FLOW_OK; } - if (vcrop->in.packing == VIDEO_CROP_PIXEL_FORMAT_PACKED_SIMPLE) { - sub_offset = (vcrop->crop_top * vcrop->in.stride) + - (vcrop->crop_left * vcrop->in.bytes_per_pixel); - } else if (vcrop->in.packing == VIDEO_CROP_PIXEL_FORMAT_PACKED_COMPLEX) { - sub_offset = (vcrop->crop_top * vcrop->in.stride) + - (ROUND_DOWN_2 (vcrop->crop_left) * vcrop->in.bytes_per_pixel); - } else if (vcrop->in.packing == VIDEO_CROP_PIXEL_FORMAT_SEMI_PLANAR) { - GstStructure *structure; - - structure = gst_caps_get_structure (caps, 0); - if (vcrop->interlaced) - sub_offset = (vcrop->crop_top / 2 * vcrop->in.stride) + - ROUND_DOWN_2 (vcrop->crop_left); - else - sub_offset = (vcrop->crop_top * vcrop->in.stride) + - ROUND_DOWN_2 (vcrop->crop_left); - } else { - GST_LOG_OBJECT (vcrop, - "can't do zero-copy cropping except for packed format"); - return GST_FLOW_OK; - } - - sub_size = vcrop->in.size - sub_offset; - *buf = gst_buffer_create_sub (input, sub_offset, sub_size); + *buf = gst_buffer_create_sub (input, vcrop->in.size - size, size); if (*buf == NULL) { GST_ERROR_OBJECT (vcrop, "failed to create subbuffer"); return GST_FLOW_ERROR; @@ -880,6 +861,95 @@ gst_video_crop_prepare_output_buffer (GstBaseTransform * trans, return GST_FLOW_OK; } +static gboolean +gst_videocrop_transform_size (GstBaseTransform * trans, + GstPadDirection direction, GstCaps * caps, guint size, GstCaps * othercaps, + guint * othersize) +{ + GstVideoCrop *vcrop = GST_VIDEO_CROP (trans); + guint inunitsize; + + if (!gst_video_crop_query_stride_supported (vcrop) || + direction == GST_PAD_SRC) { + guint outunitsize, units; + + if (!gst_video_crop_get_unit_size (trans, caps, &inunitsize)) + goto no_in_size; + + GST_DEBUG_OBJECT (vcrop, "input size %d, input unit size %d", size, + inunitsize); + + /* input size must be a multiple of the unit_size of the input caps */ + if (inunitsize == 0 || (size % inunitsize != 0)) + goto no_multiple; + + /* get the amount of units */ + units = size / inunitsize; + + /* now get the unit size of the output */ + if (!gst_video_crop_get_unit_size (trans, othercaps, &outunitsize)) + goto no_out_size; + + /* the output size is the unit_size times the amount of units on the + * input */ + *othersize = units * outunitsize; + } else { + guint sub_offset; + + /* Calculate a subbufer size for zero-copy cropping. The subbuffer is + created in prepare_output_buffer (). */ + if (vcrop->in.packing == VIDEO_CROP_PIXEL_FORMAT_PACKED_SIMPLE) { + sub_offset = (vcrop->crop_top * vcrop->in.stride) + + (vcrop->crop_left * vcrop->in.bytes_per_pixel); + } else if (vcrop->in.packing == VIDEO_CROP_PIXEL_FORMAT_PACKED_COMPLEX) { + sub_offset = (vcrop->crop_top * vcrop->in.stride) + + (ROUND_DOWN_2 (vcrop->crop_left) * vcrop->in.bytes_per_pixel); + } else if (vcrop->in.packing == VIDEO_CROP_PIXEL_FORMAT_SEMI_PLANAR) { + GstStructure *structure; + + structure = gst_caps_get_structure (caps, 0); + if (vcrop->interlaced) + sub_offset = (vcrop->crop_top / 2 * vcrop->in.stride) + + ROUND_DOWN_2 (vcrop->crop_left); + else + sub_offset = (vcrop->crop_top * vcrop->in.stride) + + ROUND_DOWN_2 (vcrop->crop_left); + } else { + GST_LOG_OBJECT (vcrop, + "can't do zero-copy cropping except for packed format"); + return FALSE; + } + + *othersize = vcrop->in.size - sub_offset; + } + + GST_DEBUG_OBJECT (vcrop, "transformed size to %d", *othersize); + + return TRUE; + + /* ERRORS */ +no_in_size: + { + GST_DEBUG_OBJECT (vcrop, "could not get in_size"); + g_warning ("%s: could not get in_size", GST_ELEMENT_NAME (trans)); + return FALSE; + } +no_multiple: + { + GST_DEBUG_OBJECT (vcrop, "Size %u is not a multiple of unit size %u", size, + inunitsize); + g_warning ("%s: size %u is not a multiple of unit size %u", + GST_ELEMENT_NAME (trans), size, inunitsize); + return FALSE; + } +no_out_size: + { + GST_DEBUG_OBJECT (vcrop, "could not get out_size"); + g_warning ("%s: could not get out_size", GST_ELEMENT_NAME (trans)); + return FALSE; + } +} + static void gst_video_crop_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) -- 1.7.9.5