ext/theora/: Added first attempt at cropping of the image as required by the theora spec. We need more properties in ...

Original commit message from CVS:
* ext/theora/theoradec.c: (theora_get_formats),
(theora_dec_src_convert), (theora_dec_sink_convert),
(theora_dec_src_query), (theora_dec_src_event), (theora_dec_event),
(theora_dec_chain):
* ext/theora/theoraenc.c: (theora_enc_sink_link):
Added first attempt at cropping of the image as required by the
theora spec. We need more properties in the caps (offset_x,
offset_y,stride) to implement this correctly.
Added some debug info in the encoder. Note :the encoder is not
updated with the offset code.
This commit is contained in:
Wim Taymans 2004-07-28 14:03:46 +00:00
parent 8aafec7515
commit 69934d5915
3 changed files with 97 additions and 16 deletions

View file

@ -1,3 +1,14 @@
2004-07-28 Wim Taymans <wim@fluendo.com>
* ext/theora/theoradec.c: (theora_get_formats),
(theora_dec_src_convert), (theora_dec_sink_convert),
(theora_dec_src_query), (theora_dec_src_event), (theora_dec_event),
(theora_dec_chain):
* ext/theora/theoraenc.c: (theora_enc_sink_link):
Added first attempt at cropping of the image as required by the
theora spec. We need more properties in the caps (offset_x,
offset_y,stride) to implement this correctly.
2004-07-28 Jan Schmidt <thaytan@mad.scientist.com> 2004-07-28 Jan Schmidt <thaytan@mad.scientist.com>
* ext/dvdnav/README: * ext/dvdnav/README:

View file

@ -460,6 +460,10 @@ theora_dec_event (GstTheoraDec * dec, GstEvent * event)
gst_pad_event_default (dec->sinkpad, event); gst_pad_event_default (dec->sinkpad, event);
} }
#define ROUND_UP_2(x) (((x) + 1) & ~1)
#define ROUND_UP_4(x) (((x) + 3) & ~3)
#define ROUND_UP_8(x) (((x) + 7) & ~7)
static void static void
theora_dec_chain (GstPad * pad, GstData * data) theora_dec_chain (GstPad * pad, GstData * data)
{ {
@ -545,9 +549,19 @@ theora_dec_chain (GstPad * pad, GstData * data)
par_den = dec->info.aspect_denominator; par_den = dec->info.aspect_denominator;
if (par_num == 0 && par_den == 0) { if (par_num == 0 && par_den == 0) {
par_num = par_den = 1; par_num = par_den = 1;
} }
GST_DEBUG_OBJECT (dec, "video %dx%d, PAR %d/%d", dec->info.width, /* theora has:
*
* width/height : dimension of the encoded frame
* frame_width/frame_height : dimension of the visible part
* offset_x/offset_y : offset in encoded frame where visible part starts
*/
GST_DEBUG_OBJECT (dec, "dimension %dx%d, PAR %d/%d", dec->info.width,
dec->info.height, par_num, par_den); dec->info.height, par_num, par_den);
GST_DEBUG_OBJECT (dec, "frame dimension %dx%d, offset %d:%d",
dec->info.frame_width, dec->info.frame_height,
dec->info.offset_x, dec->info.offset_y);
/* done */ /* done */
theora_decode_init (&dec->state, &dec->info); theora_decode_init (&dec->state, &dec->info);
@ -556,8 +570,8 @@ theora_dec_chain (GstPad * pad, GstData * data)
"framerate", G_TYPE_DOUBLE, "framerate", G_TYPE_DOUBLE,
((gdouble) dec->info.fps_numerator) / dec->info.fps_denominator, ((gdouble) dec->info.fps_numerator) / dec->info.fps_denominator,
"pixel-aspect-ratio", GST_TYPE_FRACTION, par_num, par_den, "pixel-aspect-ratio", GST_TYPE_FRACTION, par_num, par_den,
"width", G_TYPE_INT, dec->info.width, "height", G_TYPE_INT, "width", G_TYPE_INT, dec->info.frame_width, "height", G_TYPE_INT,
dec->info.height, NULL); dec->info.frame_height, NULL);
gst_pad_set_explicit_caps (dec->srcpad, caps); gst_pad_set_explicit_caps (dec->srcpad, caps);
gst_caps_free (caps); gst_caps_free (caps);
} }
@ -565,9 +579,12 @@ theora_dec_chain (GstPad * pad, GstData * data)
/* normal data packet */ /* normal data packet */
yuv_buffer yuv; yuv_buffer yuv;
GstBuffer *out; GstBuffer *out;
guint8 *y, *v, *u;
guint i; guint i;
gboolean keyframe; gboolean keyframe;
gint out_size;
gint stride_y, stride_uv;
gint width, height;
gint cwidth, cheight;
/* the second most significant bit of the first data byte is cleared /* the second most significant bit of the first data byte is cleared
* for keyframes */ * for keyframes */
@ -591,20 +608,70 @@ theora_dec_chain (GstPad * pad, GstData * data)
gst_data_unref (data); gst_data_unref (data);
return; return;
} }
g_return_if_fail (yuv.y_width == dec->info.width); g_return_if_fail (yuv.y_width == dec->info.width);
g_return_if_fail (yuv.y_height == dec->info.height); g_return_if_fail (yuv.y_height == dec->info.height);
out = gst_pad_alloc_buffer (dec->srcpad, GST_BUFFER_OFFSET_NONE,
yuv.y_width * yuv.y_height * 3 / 2); width = dec->info.frame_width;
y = GST_BUFFER_DATA (out); height = dec->info.frame_height;
u = y + yuv.y_width * yuv.y_height;
v = u + yuv.y_width * yuv.y_height / 4; /* should get the stride from the caps, for now we round up to the nearest
for (i = 0; i < yuv.y_height; i++) { * multiple of 4 because some element needs it. chroma needs special
memcpy (y + i * yuv.y_width, yuv.y + i * yuv.y_stride, yuv.y_width); * treatment, see videotestsrc. */
stride_y = ROUND_UP_4 (width);
stride_uv = ROUND_UP_8 (width) / 2;
/* for odd offsets we need to copy one extra line/column of chroma samples */
cwidth = width / 2 + (dec->info.offset_x & 1);
cheight = height / 2 + (dec->info.offset_y & 1);
out_size = stride_y * height + stride_uv * cheight * 2;
/* now copy over the area contained in offset_x,offset_y,
* frame_width, frame_height */
out = gst_pad_alloc_buffer (dec->srcpad, GST_BUFFER_OFFSET_NONE, out_size);
/* copy the visible region to the destination. This is actually pretty
* complicated and gstreamer doesn't support all the needed caps to do this
* correctly. For example, when we have an odd offset, we should only combine
* 1 row/column of luma samples with on chroma sample in colorspace conversion.
*/
{
guint8 *dest_y, *src_y;
guint8 *dest_u, *src_u;
guint8 *dest_v, *src_v;
dest_y = GST_BUFFER_DATA (out);
dest_u = dest_y + stride_y * height;
dest_v = dest_u + stride_uv * height / 2;
src_y = yuv.y + dec->info.offset_x + dec->info.offset_y * yuv.y_stride;
for (i = 0; i < height; i++) {
memcpy (dest_y, src_y, width);
dest_y += stride_y;
src_y += yuv.y_stride;
} }
for (i = 0; i < yuv.y_height / 2; i++) {
memcpy (u + i * yuv.uv_width, yuv.u + i * yuv.uv_stride, yuv.uv_width); src_u =
memcpy (v + i * yuv.uv_width, yuv.v + i * yuv.uv_stride, yuv.uv_width); yuv.u + dec->info.offset_x / 2 +
dec->info.offset_y / 2 * yuv.uv_stride;
src_v =
yuv.v + dec->info.offset_x / 2 +
dec->info.offset_y / 2 * yuv.uv_stride;
for (i = 0; i < cheight; i++) {
memcpy (dest_u, src_u, cwidth);
memcpy (dest_v, src_v, cwidth);
dest_u += stride_uv;
src_u += yuv.uv_stride;
dest_v += stride_uv;
src_v += yuv.uv_stride;
} }
}
GST_BUFFER_OFFSET (out) = dec->packetno - 4; GST_BUFFER_OFFSET (out) = dec->packetno - 4;
GST_BUFFER_OFFSET_END (out) = dec->packetno - 3; GST_BUFFER_OFFSET_END (out) = dec->packetno - 3;
GST_BUFFER_DURATION (out) = GST_BUFFER_DURATION (out) =

View file

@ -245,8 +245,11 @@ theora_enc_sink_link (GstPad * pad, const GstCaps * caps)
par = gst_structure_get_value (structure, "pixel-aspect-ratio"); par = gst_structure_get_value (structure, "pixel-aspect-ratio");
/* Theora has a divisible-by-sixteen restriction for the encoded video size */ /* Theora has a divisible-by-sixteen restriction for the encoded video size */
if ((enc->width & 0x0f) != 0 || (enc->height & 0x0f) != 0) if ((enc->width & 0x0f) != 0 || (enc->height & 0x0f) != 0) {
GST_DEBUG ("width and height not a multiple of 16 in caps %" GST_PTR_FORMAT,
caps);
return GST_PAD_LINK_REFUSED; return GST_PAD_LINK_REFUSED;
}
theora_info_init (&enc->info); theora_info_init (&enc->info);
enc->info.width = enc->width; enc->info.width = enc->width;