ext/mpeg2dec/gstmpeg2dec.c: When we need to crop the output buffer, make sure we create a buffer of the right size an...

Original commit message from CVS:
* ext/mpeg2dec/gstmpeg2dec.c: (crop_copy_i420_buffer),
(crop_copy_i422_buffer), (crop_buffer):
When we need to crop the output buffer, make sure we
create a buffer of the right size and respect the implicit
striding used for I420 elsewhere in GStreamer (#331301).
This commit is contained in:
Tim-Philipp Müller 2006-02-17 11:51:12 +00:00
parent 42f6df91db
commit c6ca130b97
2 changed files with 104 additions and 41 deletions

View file

@ -1,3 +1,11 @@
2006-02-17 Tim-Philipp Müller <tim at centricular dot net>
* ext/mpeg2dec/gstmpeg2dec.c: (crop_copy_i420_buffer),
(crop_copy_i422_buffer), (crop_buffer):
When we need to crop the output buffer, make sure we
create a buffer of the right size and respect the implicit
striding used for I420 elsewhere in GStreamer (#331301).
2006-02-17 Edward Hervey <edward@fluendo.com>
* gst/asfdemux/gstasfdemux.c: (gst_asf_demux_process_stream):

View file

@ -342,14 +342,101 @@ gst_mpeg2dec_get_index (GstElement * element)
return mpeg2dec->index;
}
/* 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)
{
unsigned char *in_data;
unsigned char *out_data;
unsigned int h_subsample;
unsigned int v_subsample;
unsigned int line;
gboolean result = FALSE;
GstBuffer *input = *buf;
GstBuffer *outbuf = input;
@ -368,45 +455,13 @@ crop_buffer (GstMpeg2dec * mpeg2dec, GstBuffer ** buf)
* for each frame decoded...
*/
if (mpeg2dec->format == MPEG2DEC_FORMAT_I422) {
outbuf =
gst_buffer_new_and_alloc (mpeg2dec->width * mpeg2dec->height * 2);
h_subsample = 2;
v_subsample = 1;
outbuf = crop_copy_i422_buffer (mpeg2dec, input);
} else {
outbuf =
gst_buffer_new_and_alloc (mpeg2dec->width * mpeg2dec->height * 1.5);
h_subsample = 2;
v_subsample = 2;
outbuf = crop_copy_i420_buffer (mpeg2dec, input);
}
gst_buffer_set_caps (outbuf, GST_PAD_CAPS (mpeg2dec->srcpad));
GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (input);
GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET (input);
GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (input);
/* 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 / v_subsample; line++) {
memcpy (out_data, in_data, mpeg2dec->width / h_subsample);
memcpy (out_data +
mpeg2dec->width * mpeg2dec->height / (v_subsample * h_subsample),
in_data +
mpeg2dec->decoded_width * mpeg2dec->decoded_height / (v_subsample *
h_subsample), mpeg2dec->width / h_subsample);
out_data += mpeg2dec->width / h_subsample;
in_data += mpeg2dec->decoded_width / h_subsample;
}
gst_buffer_stamp (outbuf, input);
*buf = outbuf;
result = TRUE;