From 40a470c7853990d843718b2b3793bc38cdee34ce Mon Sep 17 00:00:00 2001 From: =?utf8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 29 Dec 2010 21:42:36 +0000 Subject: [PATCH] mpeg2dec: refactor cropping code to use libgstvideo functions https://bugzilla.gnome.org/show_bug.cgi?id=571146 --- ext/mpeg2dec/gstmpeg2dec.c | 205 +++++++++++++-------------------------------- 1 file changed, 56 insertions(+), 149 deletions(-) diff --git a/ext/mpeg2dec/gstmpeg2dec.c b/ext/mpeg2dec/gstmpeg2dec.c index 75f1010..bc58ba6 100644 --- a/ext/mpeg2dec/gstmpeg2dec.c +++ b/ext/mpeg2dec/gstmpeg2dec.c @@ -121,7 +121,7 @@ static const GstEventMask *gst_mpeg2dec_get_event_masks (GstPad * pad); static GstElementClass *parent_class = NULL; -static gboolean crop_buffer (GstMpeg2dec * mpeg2dec, GstBuffer ** buf); +static gboolean gst_mpeg2dec_crop_buffer (GstMpeg2dec * dec, GstBuffer ** buf); /*static guint gst_mpeg2dec_signals[LAST_SIGNAL] = { 0 };*/ @@ -319,137 +319,57 @@ gst_mpeg2dec_get_index (GstElement * element) } #endif -/* see gst-plugins/gst/games/gstvideoimage.c, paint_setup_I420() */ -#define I420_Y_ROWSTRIDE(width) (GST_ROUND_UP_4(width)) -#define I420_U_ROWSTRIDE(width) (GST_ROUND_UP_8(width)/2) -#define I420_V_ROWSTRIDE(width) ((GST_ROUND_UP_8(I420_Y_ROWSTRIDE(width)))/2) - -#define I420_Y_OFFSET(w,h) (0) -#define I420_U_OFFSET(w,h) (I420_Y_OFFSET(w,h)+(I420_Y_ROWSTRIDE(w)*GST_ROUND_UP_2(h))) -#define I420_V_OFFSET(w,h) (I420_U_OFFSET(w,h)+(I420_U_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2)) - -#define I420_SIZE(w,h) (I420_V_OFFSET(w,h)+(I420_V_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2)) - -static GstBuffer * -crop_copy_i420_buffer (GstMpeg2dec * mpeg2dec, GstBuffer * input) -{ - GstBuffer *outbuf; - guint8 *dest, *src; - guint outsize, line; - - outsize = I420_SIZE (mpeg2dec->width, mpeg2dec->height); - GST_LOG_OBJECT (mpeg2dec, "Copying input buffer %ux%u (%u) to output buffer " - "%ux%u (%u)", mpeg2dec->decoded_width, mpeg2dec->decoded_height, - GST_BUFFER_SIZE (input), mpeg2dec->width, mpeg2dec->height, outsize); - outbuf = gst_buffer_new_and_alloc (outsize); - - /* Copy Y first */ - src = GST_BUFFER_DATA (input); - dest = GST_BUFFER_DATA (outbuf); - for (line = 0; line < mpeg2dec->height; line++) { - memcpy (dest, src, mpeg2dec->width); - dest += I420_Y_ROWSTRIDE (mpeg2dec->width); - src += I420_Y_ROWSTRIDE (mpeg2dec->decoded_width); - } - - /* U */ - src = GST_BUFFER_DATA (input) - + I420_U_OFFSET (mpeg2dec->decoded_width, mpeg2dec->decoded_height); - dest = GST_BUFFER_DATA (outbuf) - + I420_U_OFFSET (mpeg2dec->width, mpeg2dec->height); - for (line = 0; line < mpeg2dec->height / 2; line++) { - memcpy (dest, src, mpeg2dec->width / 2); - dest += I420_U_ROWSTRIDE (mpeg2dec->width); - src += I420_U_ROWSTRIDE (mpeg2dec->decoded_width); - } - - /* V */ - src = GST_BUFFER_DATA (input) - + I420_V_OFFSET (mpeg2dec->decoded_width, mpeg2dec->decoded_height); - dest = GST_BUFFER_DATA (outbuf) - + I420_V_OFFSET (mpeg2dec->width, mpeg2dec->height); - for (line = 0; line < mpeg2dec->height / 2; line++) { - memcpy (dest, src, mpeg2dec->width / 2); - dest += I420_V_ROWSTRIDE (mpeg2dec->width); - src += I420_V_ROWSTRIDE (mpeg2dec->decoded_width); - } - - return outbuf; -} - - /* FIXME: this is unlikely to be right stride-wise and offset-wise */ -static GstBuffer * -crop_copy_i422_buffer (GstMpeg2dec * mpeg2dec, GstBuffer * input) -{ - GstBuffer *outbuf; - guint8 *in_data, *out_data; - guint line; - - outbuf = gst_buffer_new_and_alloc (mpeg2dec->width * mpeg2dec->height * 2); - - /* Copy Y first */ - in_data = GST_BUFFER_DATA (input); - out_data = GST_BUFFER_DATA (outbuf); - for (line = 0; line < mpeg2dec->height; line++) { - memcpy (out_data, in_data, mpeg2dec->width); - out_data += mpeg2dec->width; - in_data += mpeg2dec->decoded_width; - } - - /* Now copy U & V */ - in_data = GST_BUFFER_DATA (input) - + mpeg2dec->decoded_width * mpeg2dec->decoded_height; - for (line = 0; line < mpeg2dec->height; line++) { - memcpy (out_data, in_data, mpeg2dec->width / 2); - memcpy (out_data + mpeg2dec->width * mpeg2dec->height / 2, - in_data + mpeg2dec->decoded_width * mpeg2dec->decoded_height / 2, - mpeg2dec->width / 2); - out_data += mpeg2dec->width / 2; - in_data += mpeg2dec->decoded_width / 2; - } - - return outbuf; -} - static gboolean -crop_buffer (GstMpeg2dec * mpeg2dec, GstBuffer ** buf) +gst_mpeg2dec_crop_buffer (GstMpeg2dec * dec, GstBuffer ** buf) { - gboolean result = TRUE; - GstBuffer *input = *buf; + GstBuffer *inbuf = *buf; GstBuffer *outbuf; + guint outsize, c; - /*We crop only if the target region is smaller than the input one */ - if ((mpeg2dec->decoded_width > mpeg2dec->width) || - (mpeg2dec->decoded_height > mpeg2dec->height)) { - /* If we don't know about the format, we just return the original - * buffer. - */ - if (mpeg2dec->format == GST_VIDEO_FORMAT_Y42B || - mpeg2dec->format == GST_VIDEO_FORMAT_I420 || - mpeg2dec->format == GST_VIDEO_FORMAT_YV12) { - /*FIXME: I have tried to use gst_buffer_copy_on_write, but it - * still have some artifact, so I'me allocating new buffer - * for each frame decoded... - */ - if (mpeg2dec->format == GST_VIDEO_FORMAT_Y42B) { - outbuf = crop_copy_i422_buffer (mpeg2dec, input); - } else { - outbuf = crop_copy_i420_buffer (mpeg2dec, input); - } + outsize = gst_video_format_get_size (dec->format, dec->width, dec->height); - GST_DEBUG ("cropping buffer"); + GST_LOG_OBJECT (dec, "Copying input buffer %ux%u (%u) to output buffer " + "%ux%u (%u)", dec->decoded_width, dec->decoded_height, + GST_BUFFER_SIZE (inbuf), dec->width, dec->height, outsize); - gst_buffer_set_caps (outbuf, GST_PAD_CAPS (mpeg2dec->srcpad)); - gst_buffer_copy_metadata (outbuf, input, - GST_BUFFER_COPY_TIMESTAMPS | GST_BUFFER_COPY_FLAGS); - gst_buffer_unref (input); + outbuf = gst_buffer_new_and_alloc (outsize); - *buf = outbuf; - result = TRUE; + for (c = 0; c < 3; c++) { + const guint8 *src; + guint8 *dest; + guint stride_in, stride_out; + guint c_height, c_width, line; + + src = + GST_BUFFER_DATA (inbuf) + + gst_video_format_get_component_offset (dec->format, c, + dec->decoded_width, dec->decoded_height); + dest = + GST_BUFFER_DATA (outbuf) + + gst_video_format_get_component_offset (dec->format, c, dec->width, + dec->height); + stride_out = gst_video_format_get_row_stride (dec->format, c, dec->width); + stride_in = + gst_video_format_get_row_stride (dec->format, c, dec->decoded_width); + c_height = + gst_video_format_get_component_width (dec->format, c, dec->height); + c_width = gst_video_format_get_component_width (dec->format, c, dec->width); + + for (line = 0; line < c_height; line++) { + memcpy (dest, src, c_width); + dest += stride_out; + src += stride_in; } } - return result; + gst_buffer_set_caps (outbuf, GST_PAD_CAPS (dec->srcpad)); + gst_buffer_copy_metadata (outbuf, inbuf, + GST_BUFFER_COPY_TIMESTAMPS | GST_BUFFER_COPY_FLAGS); + + gst_buffer_unref (*buf); + *buf = outbuf; + + return TRUE; } static GstFlowReturn @@ -550,41 +470,24 @@ gst_mpeg2dec_negotiate_format (GstMpeg2dec * mpeg2dec) if (sequence->width != sequence->chroma_width && sequence->height != sequence->chroma_height) { - - fourcc = GST_STR_FOURCC ("I420"); mpeg2dec->format = GST_VIDEO_FORMAT_I420; - mpeg2dec->size = - I420_SIZE (mpeg2dec->decoded_width, mpeg2dec->decoded_height); - - mpeg2dec->u_offs = - I420_U_OFFSET (mpeg2dec->decoded_width, mpeg2dec->decoded_height); - mpeg2dec->v_offs = - I420_V_OFFSET (mpeg2dec->decoded_width, mpeg2dec->decoded_height); - } else if ((sequence->width == sequence->chroma_width && sequence->height != sequence->chroma_height) || (sequence->width != sequence->chroma_width && sequence->height == sequence->chroma_height)) { - gint halfsize; - - fourcc = GST_STR_FOURCC ("Y42B"); mpeg2dec->format = GST_VIDEO_FORMAT_Y42B; - halfsize = mpeg2dec->decoded_width * mpeg2dec->decoded_height; - mpeg2dec->size = halfsize * 2; - mpeg2dec->u_offs = halfsize; - mpeg2dec->v_offs = halfsize + (halfsize / 2); } else { - gint size; - - size = mpeg2dec->decoded_width * mpeg2dec->decoded_height; - - fourcc = GST_STR_FOURCC ("Y444"); mpeg2dec->format = GST_VIDEO_FORMAT_Y444; - mpeg2dec->size = size * 3; - mpeg2dec->u_offs = size; - mpeg2dec->v_offs = size * 2; } + fourcc = gst_video_format_to_fourcc (mpeg2dec->format); + mpeg2dec->size = gst_video_format_get_size (mpeg2dec->format, + mpeg2dec->decoded_width, mpeg2dec->decoded_height); + mpeg2dec->u_offs = gst_video_format_get_component_offset (mpeg2dec->format, 1, + mpeg2dec->decoded_width, mpeg2dec->decoded_height); + mpeg2dec->v_offs = gst_video_format_get_component_offset (mpeg2dec->format, 2, + mpeg2dec->decoded_width, mpeg2dec->decoded_height); + if (mpeg2dec->pixel_width == 0 || mpeg2dec->pixel_height == 0) { GValue par = { 0, } , dar = { @@ -1025,8 +928,12 @@ handle_slice (GstMpeg2dec * mpeg2dec, const mpeg2_info_t * info) * array of buffers */ gst_buffer_ref (outbuf); - /* do cropping if needed */ - crop_buffer (mpeg2dec, &outbuf); + /* do cropping if the target region is smaller than the input one */ + if (mpeg2dec->decoded_width != mpeg2dec->width || + mpeg2dec->decoded_height != mpeg2dec->height) { + GST_DEBUG_OBJECT (mpeg2dec, "cropping buffer"); + gst_mpeg2dec_crop_buffer (mpeg2dec, &outbuf); + } if (mpeg2dec->segment.rate >= 0.0) { /* forward: push right away */ -- 2.7.4