Commit fe21b563 authored by Wim Taymans's avatar Wim Taymans

ext/theora/: Added cropping option to theora decoder.

Original commit message from CVS:
* ext/theora/theoradec.c: (gst_theora_dec_class_init),
(gst_theora_dec_init), (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), (theora_dec_set_property),
(theora_dec_get_property):
* ext/theora/theoraenc.c: (gst_border_mode_get_type),
(gst_theora_enc_class_init), (gst_theora_enc_init),
(theora_enc_sink_link), (theora_enc_chain),
(theora_enc_set_property), (theora_enc_get_property):
Added cropping option to theora decoder.
Added border option to theora encoder.
parent 05584c6b
2004-07-30 Wim Taymans <wim@fluendo.com>
* ext/theora/theoradec.c: (gst_theora_dec_class_init),
(gst_theora_dec_init), (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), (theora_dec_set_property),
(theora_dec_get_property):
* ext/theora/theoraenc.c: (gst_border_mode_get_type),
(gst_theora_enc_class_init), (gst_theora_enc_init),
(theora_enc_sink_link), (theora_enc_chain),
(theora_enc_set_property), (theora_enc_get_property):
Added cropping option to theora decoder.
Added border option to theora encoder.
2004-07-30 Zaheer Abbas Merali <zaheerabbas at merali dot org>
* ext/libpng/gstpngenc.c: (gst_pngenc_class_init),
......
......@@ -60,6 +60,8 @@ struct _GstTheoraDec
gboolean need_keyframe;
gint width, height;
gint offset_x, offset_y;
gboolean crop;
};
struct _GstTheoraDecClass
......@@ -67,6 +69,13 @@ struct _GstTheoraDecClass
GstElementClass parent_class;
};
#define THEORA_DEF_CROP TRUE
enum
{
ARG_0,
ARG_CROP
};
static GstElementDetails theora_dec_details = {
"TheoraDec",
"Codec/Decoder/Video",
......@@ -94,6 +103,11 @@ GST_STATIC_PAD_TEMPLATE ("sink",
GST_BOILERPLATE (GstTheoraDec, gst_theora_dec, GstElement, GST_TYPE_ELEMENT);
static void theora_dec_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void theora_dec_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void theora_dec_chain (GstPad * pad, GstData * data);
static GstElementStateReturn theora_dec_change_state (GstElement * element);
static gboolean theora_dec_src_event (GstPad * pad, GstEvent * event);
......@@ -125,8 +139,17 @@ gst_theora_dec_base_init (gpointer g_class)
static void
gst_theora_dec_class_init (GstTheoraDecClass * klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
gobject_class->set_property = theora_dec_set_property;
gobject_class->get_property = theora_dec_get_property;
g_object_class_install_property (gobject_class, ARG_CROP,
g_param_spec_boolean ("crop", "Crop",
"Crop the image to the visible region", THEORA_DEF_CROP,
(GParamFlags) G_PARAM_READWRITE));
gstelement_class->change_state = theora_dec_change_state;
GST_DEBUG_CATEGORY_INIT (theoradec_debug, "theoradec", 0, "Theora decoder");
......@@ -157,6 +180,8 @@ gst_theora_dec_init (GstTheoraDec * dec)
gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);
GST_FLAG_SET (dec, GST_ELEMENT_EVENT_AWARE);
dec->crop = THEORA_DEF_CROP;
}
/* FIXME: copy from libtheora, theora should somehow make this available for seeking */
......@@ -565,14 +590,22 @@ theora_dec_chain (GstPad * pad, GstData * data)
dec->info.frame_width, dec->info.frame_height,
dec->info.offset_x, dec->info.offset_y);
/* add black borders to make width/height/offsets even. we need this because
* we cannot express an offset to the peer plugin. */
dec->width =
ROUND_UP_2 (dec->info.frame_width + (dec->info.offset_x & 1));
dec->height =
ROUND_UP_2 (dec->info.frame_height + (dec->info.offset_y & 1));
dec->offset_x = dec->info.offset_x & ~1;
dec->offset_y = dec->info.offset_y & ~1;
if (dec->crop) {
/* add black borders to make width/height/offsets even. we need this because
* we cannot express an offset to the peer plugin. */
dec->width =
ROUND_UP_2 (dec->info.frame_width + (dec->info.offset_x & 1));
dec->height =
ROUND_UP_2 (dec->info.frame_height + (dec->info.offset_y & 1));
dec->offset_x = dec->info.offset_x & ~1;
dec->offset_y = dec->info.offset_y & ~1;
} else {
/* no cropping, use the encoded dimensions */
dec->width = dec->info.width;
dec->height = dec->info.height;
dec->offset_x = 0;
dec->offset_y = 0;
}
GST_DEBUG_OBJECT (dec, "after fixup frame dimension %dx%d, offset %d:%d",
dec->width, dec->height, dec->offset_x, dec->offset_y);
......@@ -726,3 +759,35 @@ theora_dec_change_state (GstElement * element)
return parent_class->change_state (element);
}
static void
theora_dec_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstTheoraDec *dec = GST_THEORA_DEC (object);
switch (prop_id) {
case ARG_CROP:
dec->crop = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
theora_dec_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstTheoraDec *dec = GST_THEORA_DEC (object);
switch (prop_id) {
case ARG_CROP:
g_value_set_boolean (value, dec->crop);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
......@@ -43,6 +43,33 @@ GST_DEBUG_CATEGORY (theoraenc_debug);
typedef struct _GstTheoraEnc GstTheoraEnc;
typedef struct _GstTheoraEncClass GstTheoraEncClass;
typedef enum
{
BORDER_NONE,
BORDER_BLACK,
BORDER_MIRROR
}
GstTheoraEncBorderMode;
#define GST_TYPE_BORDER_MODE (gst_border_mode_get_type())
static GType
gst_border_mode_get_type (void)
{
static GType border_mode_type = 0;
static GEnumValue border_mode[] = {
{BORDER_NONE, "BORDER_NONE", "No Border"},
{BORDER_BLACK, "BORDER_BLACK", "Black Border"},
{BORDER_MIRROR, "BORDER_MIRROR", "Mirror image in borders"},
{0, NULL, NULL},
};
if (!border_mode_type) {
border_mode_type =
g_enum_register_static ("GstTheoraEncBorderMode", border_mode);
}
return border_mode_type;
}
struct _GstTheoraEnc
{
GstElement element;
......@@ -57,6 +84,7 @@ struct _GstTheoraEnc
theora_comment comment;
gboolean center;
GstTheoraEncBorderMode border;
gint video_bitrate; /* bitrate target for Theora video */
gint video_quality; /* Theora quality selector 0 = low, 63 = high */
......@@ -88,6 +116,7 @@ struct _GstTheoraEncClass
#define ROUND_UP_8(x) (((x) + 7) & ~7)
#define THEORA_DEF_CENTER TRUE
#define THEORA_DEF_BORDER BORDER_BLACK
#define THEORA_DEF_BITRATE 0
#define THEORA_DEF_QUALITY 16
#define THEORA_DEF_QUICK TRUE
......@@ -102,6 +131,7 @@ enum
{
ARG_0,
ARG_CENTER,
ARG_BORDER,
ARG_BITRATE,
ARG_QUALITY,
ARG_QUICK,
......@@ -174,6 +204,11 @@ gst_theora_enc_class_init (GstTheoraEncClass * klass)
g_param_spec_boolean ("center", "Center",
"Center image when sizes not multiple of 16", THEORA_DEF_CENTER,
(GParamFlags) G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, ARG_BORDER,
g_param_spec_enum ("border", "Border",
"Border color to add when sizes not multiple of 16",
GST_TYPE_BORDER_MODE, THEORA_DEF_BORDER,
(GParamFlags) G_PARAM_READWRITE));
/* general encoding stream options */
g_object_class_install_property (gobject_class, ARG_BITRATE,
g_param_spec_int ("bitrate", "Bitrate", "Compressed video bitrate (kbps)",
......@@ -229,6 +264,9 @@ gst_theora_enc_init (GstTheoraEnc * enc)
gst_pad_use_explicit_caps (enc->srcpad);
gst_element_add_pad (GST_ELEMENT (enc), enc->srcpad);
enc->center = THEORA_DEF_CENTER;
enc->border = THEORA_DEF_BORDER;
enc->video_bitrate = THEORA_DEF_BITRATE;
enc->video_quality = THEORA_DEF_QUALITY;
enc->quick = THEORA_DEF_QUICK;
......@@ -494,6 +532,7 @@ theora_enc_chain (GstPad * pad, GstData * data)
gint dst_y_stride, dst_uv_stride;
gint width, height;
gint cwidth, cheight;
gint offset_x, right_x, right_border;
/* source width/height */
width = enc->width;
......@@ -513,33 +552,74 @@ theora_enc_chain (GstPad * pad, GstData * data)
newbuf = gst_pad_alloc_buffer (enc->srcpad,
GST_BUFFER_OFFSET_NONE, y_size * 3 / 2);
yuv.y = GST_BUFFER_DATA (newbuf);
yuv.u = yuv.y + y_size;
yuv.v = yuv.u + y_size / 4;
/* center if needed */
dest_y = yuv.y + enc->offset_x + enc->offset_y * dst_y_stride;
dest_u =
yuv.u + (enc->offset_x / 2) + (enc->offset_y / 2) * dst_uv_stride;
dest_v =
yuv.v + (enc->offset_x / 2) + (enc->offset_y / 2) * dst_uv_stride;
dest_y = yuv.y = GST_BUFFER_DATA (newbuf);
dest_u = yuv.u = yuv.y + y_size;
dest_v = yuv.v = yuv.u + y_size / 4;
src_y = GST_BUFFER_DATA (buf);
src_u = src_y + src_y_stride * ROUND_UP_2 (height);
src_v = src_u + src_uv_stride * ROUND_UP_2 (height) / 2;
if (enc->border != BORDER_NONE) {
/* fill top border */
for (i = 0; i < enc->offset_y; i++) {
memset (dest_y, 0, dst_y_stride);
dest_y += dst_y_stride;
}
} else {
dest_y += dst_y_stride * enc->offset_y;
}
offset_x = enc->offset_x;
right_x = width + enc->offset_x;
right_border = dst_y_stride - right_x;
/* copy Y plane */
for (i = 0; i < height; i++) {
memcpy (dest_y, src_y, width);
memcpy (dest_y + offset_x, src_y, width);
if (enc->border != BORDER_NONE) {
memset (dest_y, 0, offset_x);
memset (dest_y + right_x, 0, right_border);
}
dest_y += dst_y_stride;
src_y += src_y_stride;
}
if (enc->border != BORDER_NONE) {
/* fill bottom border */
for (i = height + enc->offset_y; i < enc->info.height; i++) {
memset (dest_y, 0, dst_y_stride);
dest_y += dst_y_stride;
}
/* fill top border chroma */
for (i = 0; i < enc->offset_y / 2; i++) {
memset (dest_u, 128, dst_uv_stride);
memset (dest_v, 128, dst_uv_stride);
dest_u += dst_uv_stride;
dest_v += dst_uv_stride;
}
} else {
dest_u += dst_uv_stride * enc->offset_y / 2;
dest_v += dst_uv_stride * enc->offset_y / 2;
}
offset_x = enc->offset_x / 2;
right_x = cwidth + offset_x;
right_border = dst_uv_stride - right_x;
/* copy UV planes */
for (i = 0; i < cheight; i++) {
memcpy (dest_u, src_u, cwidth);
memcpy (dest_v, src_v, cwidth);
memcpy (dest_v + offset_x, src_v, cwidth);
memcpy (dest_u + offset_x, src_u, cwidth);
if (enc->border != BORDER_NONE) {
memset (dest_u, 128, offset_x);
memset (dest_u + right_x, 128, right_border);
memset (dest_v, 128, offset_x);
memset (dest_v + right_x, 128, right_border);
}
dest_u += dst_uv_stride;
dest_v += dst_uv_stride;
......@@ -547,6 +627,16 @@ theora_enc_chain (GstPad * pad, GstData * data)
src_v += src_uv_stride;
}
if (enc->border != BORDER_NONE) {
/* fill bottom border */
for (i = cheight + enc->offset_y / 2; i < enc->info_height / 2; i++) {
memset (dest_u, 128, dst_uv_stride);
memset (dest_v, 128, dst_uv_stride);
dest_u += dst_uv_stride;
dest_v += dst_uv_stride;
}
}
gst_buffer_unref (buf);
buf = newbuf;
}
......@@ -604,6 +694,9 @@ theora_enc_set_property (GObject * object, guint prop_id,
case ARG_CENTER:
enc->center = g_value_get_boolean (value);
break;
case ARG_BORDER:
enc->border = g_value_get_enum (value);
break;
case ARG_BITRATE:
enc->video_bitrate = g_value_get_int (value) * 1000;
enc->video_quality = 0;
......@@ -649,6 +742,9 @@ theora_enc_get_property (GObject * object, guint prop_id,
case ARG_CENTER:
g_value_set_boolean (value, enc->center);
break;
case ARG_BORDER:
g_value_set_enum (value, enc->border);
break;
case ARG_BITRATE:
g_value_set_int (value, enc->video_bitrate / 1000);
break;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment