theora: Port to 0.11 again with the new base classes

This commit is contained in:
Sebastian Dröge 2012-04-24 21:32:28 +02:00
parent a8c40a658c
commit e120979f17
4 changed files with 122 additions and 254 deletions

View file

@ -47,11 +47,13 @@
#include "gsttheoradec.h" #include "gsttheoradec.h"
#include <gst/tag/tag.h> #include <gst/tag/tag.h>
#include <gst/video/video.h> #include <gst/video/video.h>
#include <gst/video/gstvideometa.h>
#include <gst/video/gstvideopool.h>
#define GST_CAT_DEFAULT theoradec_debug #define GST_CAT_DEFAULT theoradec_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
GST_DEBUG_CATEGORY_EXTERN (GST_CAT_PERFORMANCE);
#define THEORA_DEF_CROP TRUE
#define THEORA_DEF_TELEMETRY_MV 0 #define THEORA_DEF_TELEMETRY_MV 0
#define THEORA_DEF_TELEMETRY_MBMODE 0 #define THEORA_DEF_TELEMETRY_MBMODE 0
#define THEORA_DEF_TELEMETRY_QI 0 #define THEORA_DEF_TELEMETRY_QI 0
@ -60,7 +62,6 @@ GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
enum enum
{ {
PROP_0, PROP_0,
PROP_CROP,
PROP_TELEMETRY_MV, PROP_TELEMETRY_MV,
PROP_TELEMETRY_MBMODE, PROP_TELEMETRY_MBMODE,
PROP_TELEMETRY_QI, PROP_TELEMETRY_QI,
@ -71,8 +72,8 @@ static GstStaticPadTemplate theora_dec_src_factory =
GST_STATIC_PAD_TEMPLATE ("src", GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC, GST_PAD_SRC,
GST_PAD_ALWAYS, GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-raw-yuv, " GST_STATIC_CAPS ("video/x-raw, "
"format = (fourcc) { I420, Y42B, Y444 }, " "format = (string) { I420, Y42B, Y444 }, "
"framerate = (fraction) [0/1, MAX], " "framerate = (fraction) [0/1, MAX], "
"width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]") "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
); );
@ -84,8 +85,8 @@ GST_STATIC_PAD_TEMPLATE ("sink",
GST_STATIC_CAPS ("video/x-theora") GST_STATIC_CAPS ("video/x-theora")
); );
GST_BOILERPLATE (GstTheoraDec, gst_theora_dec, GstVideoDecoder, #define gst_theora_dec_parent_class parent_class
GST_TYPE_VIDEO_DECODER); G_DEFINE_TYPE (GstTheoraDec, gst_theora_dec, GST_TYPE_VIDEO_DECODER);
static void theora_dec_get_property (GObject * object, guint prop_id, static void theora_dec_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec); GValue * value, GParamSpec * pspec);
@ -105,22 +106,6 @@ static GstFlowReturn theora_dec_handle_frame (GstVideoDecoder * decoder,
static GstFlowReturn theora_dec_decode_buffer (GstTheoraDec * dec, static GstFlowReturn theora_dec_decode_buffer (GstTheoraDec * dec,
GstBuffer * buf, GstVideoCodecFrame * frame); GstBuffer * buf, GstVideoCodecFrame * frame);
static void
gst_theora_dec_base_init (gpointer g_class)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&theora_dec_src_factory));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&theora_dec_sink_factory));
gst_element_class_set_details_simple (element_class,
"Theora video decoder", "Codec/Decoder/Video",
"decode raw theora streams to raw YUV video",
"Benjamin Otte <otte@gnome.org>, Wim Taymans <wim@fluendo.com>");
}
static gboolean static gboolean
gst_theora_dec_ctl_is_supported (int req) gst_theora_dec_ctl_is_supported (int req)
{ {
@ -132,16 +117,12 @@ static void
gst_theora_dec_class_init (GstTheoraDecClass * klass) gst_theora_dec_class_init (GstTheoraDecClass * klass)
{ {
GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
GstVideoDecoderClass *video_decoder_class = GST_VIDEO_DECODER_CLASS (klass); GstVideoDecoderClass *video_decoder_class = GST_VIDEO_DECODER_CLASS (klass);
gobject_class->set_property = theora_dec_set_property; gobject_class->set_property = theora_dec_set_property;
gobject_class->get_property = theora_dec_get_property; gobject_class->get_property = theora_dec_get_property;
g_object_class_install_property (gobject_class, PROP_CROP,
g_param_spec_boolean ("crop", "Crop",
"Crop the image to the visible region", THEORA_DEF_CROP,
(GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
if (gst_theora_dec_ctl_is_supported (TH_DECCTL_SET_TELEMETRY_MV)) { if (gst_theora_dec_ctl_is_supported (TH_DECCTL_SET_TELEMETRY_MV)) {
g_object_class_install_property (gobject_class, PROP_TELEMETRY_MV, g_object_class_install_property (gobject_class, PROP_TELEMETRY_MV,
g_param_spec_int ("visualize-motion-vectors", g_param_spec_int ("visualize-motion-vectors",
@ -186,6 +167,15 @@ gst_theora_dec_class_init (GstTheoraDecClass * klass)
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
} }
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&theora_dec_src_factory));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&theora_dec_sink_factory));
gst_element_class_set_details_simple (element_class,
"Theora video decoder", "Codec/Decoder/Video",
"decode raw theora streams to raw YUV video",
"Benjamin Otte <otte@gnome.org>, Wim Taymans <wim@fluendo.com>");
video_decoder_class->start = GST_DEBUG_FUNCPTR (theora_dec_start); video_decoder_class->start = GST_DEBUG_FUNCPTR (theora_dec_start);
video_decoder_class->stop = GST_DEBUG_FUNCPTR (theora_dec_stop); video_decoder_class->stop = GST_DEBUG_FUNCPTR (theora_dec_stop);
video_decoder_class->reset = GST_DEBUG_FUNCPTR (theora_dec_reset); video_decoder_class->reset = GST_DEBUG_FUNCPTR (theora_dec_reset);
@ -198,9 +188,8 @@ gst_theora_dec_class_init (GstTheoraDecClass * klass)
} }
static void static void
gst_theora_dec_init (GstTheoraDec * dec, GstTheoraDecClass * g_class) gst_theora_dec_init (GstTheoraDec * dec)
{ {
dec->crop = THEORA_DEF_CROP;
dec->telemetry_mv = THEORA_DEF_TELEMETRY_MV; dec->telemetry_mv = THEORA_DEF_TELEMETRY_MV;
dec->telemetry_mbmode = THEORA_DEF_TELEMETRY_MBMODE; dec->telemetry_mbmode = THEORA_DEF_TELEMETRY_MBMODE;
dec->telemetry_qi = THEORA_DEF_TELEMETRY_QI; dec->telemetry_qi = THEORA_DEF_TELEMETRY_QI;
@ -269,10 +258,11 @@ theora_dec_parse (GstVideoDecoder * decoder,
av = gst_adapter_available (adapter); av = gst_adapter_available (adapter);
data = gst_adapter_peek (adapter, 1); data = gst_adapter_map (adapter, 1);
/* check for keyframe; must not be header packet */ /* check for keyframe; must not be header packet */
if (!(data[0] & 0x80) && (data[0] & 0x40) == 0) if (!(data[0] & 0x80) && (data[0] & 0x40) == 0)
GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame); GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
gst_adapter_unmap (adapter);
/* and pass along all */ /* and pass along all */
gst_video_decoder_add_to_frame (decoder, av); gst_video_decoder_add_to_frame (decoder, av);
@ -295,15 +285,17 @@ theora_dec_set_format (GstVideoDecoder * bdec, GstVideoCodecState * state)
/* FIXME : Interesting, we always accept any kind of caps ? */ /* FIXME : Interesting, we always accept any kind of caps ? */
if (state->codec_data) { if (state->codec_data) {
GstBuffer *buffer; GstBuffer *buffer;
GstMapInfo minfo;
guint8 *data; guint8 *data;
guint size; guint size;
guint offset; guint offset;
buffer = state->codec_data; buffer = state->codec_data;
gst_buffer_map (buffer, &minfo, GST_MAP_READ);
offset = 0; offset = 0;
size = GST_BUFFER_SIZE (buffer); size = minfo.size;
data = GST_BUFFER_DATA (buffer); data = (guint8 *) minfo.data;
while (size > 2) { while (size > 2) {
guint psize; guint psize;
@ -318,7 +310,7 @@ theora_dec_set_format (GstVideoDecoder * bdec, GstVideoCodecState * state)
/* make sure we don't read too much */ /* make sure we don't read too much */
psize = MIN (psize, size); psize = MIN (psize, size);
buf = gst_buffer_create_sub (buffer, offset, psize); buf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, offset, psize);
/* first buffer is a discont buffer */ /* first buffer is a discont buffer */
if (offset == 2) if (offset == 2)
@ -333,6 +325,8 @@ theora_dec_set_format (GstVideoDecoder * bdec, GstVideoCodecState * state)
data += psize; data += psize;
offset += psize; offset += psize;
} }
gst_buffer_unmap (buffer, &minfo);
} }
GST_DEBUG_OBJECT (dec, "Done"); GST_DEBUG_OBJECT (dec, "Done");
@ -344,24 +338,17 @@ static GstFlowReturn
theora_handle_comment_packet (GstTheoraDec * dec, ogg_packet * packet) theora_handle_comment_packet (GstTheoraDec * dec, ogg_packet * packet)
{ {
gchar *encoder = NULL; gchar *encoder = NULL;
GstBuffer *buf;
GstTagList *list; GstTagList *list;
GST_DEBUG_OBJECT (dec, "parsing comment packet"); GST_DEBUG_OBJECT (dec, "parsing comment packet");
buf = gst_buffer_new ();
GST_BUFFER_SIZE (buf) = packet->bytes;
GST_BUFFER_DATA (buf) = packet->packet;
list = list =
gst_tag_list_from_vorbiscomment_buffer (buf, (guint8 *) "\201theora", 7, gst_tag_list_from_vorbiscomment (packet->packet, packet->bytes,
&encoder); (guint8 *) "\201theora", 7, &encoder);
gst_buffer_unref (buf);
if (!list) { if (!list) {
GST_ERROR_OBJECT (dec, "couldn't decode comments"); GST_ERROR_OBJECT (dec, "couldn't decode comments");
list = gst_tag_list_new (); list = gst_tag_list_new_empty ();
} }
if (encoder) { if (encoder) {
gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
@ -437,29 +424,13 @@ theora_handle_type_packet (GstTheoraDec * dec, ogg_packet * packet)
goto unsupported_format; goto unsupported_format;
} }
if (dec->crop) { /* FIXME: Use crop metadata */
GST_VIDEO_INFO_WIDTH (info) = dec->info.pic_width;
GST_VIDEO_INFO_HEIGHT (info) = dec->info.pic_height; /* no cropping, use the encoded dimensions */
dec->offset_x = dec->info.pic_x; GST_VIDEO_INFO_WIDTH (info) = dec->info.frame_width;
dec->offset_y = dec->info.pic_y; GST_VIDEO_INFO_HEIGHT (info) = dec->info.frame_height;
/* Ensure correct offsets in chroma for formats that need it dec->offset_x = 0;
* by rounding the offset. libtheora will add proper pixels, dec->offset_y = 0;
* so no need to handle them ourselves. */
if (dec->offset_x & 1 && dec->info.pixel_fmt != TH_PF_444) {
dec->offset_x--;
GST_VIDEO_INFO_WIDTH (info)++;
}
if (dec->offset_y & 1 && dec->info.pixel_fmt == TH_PF_420) {
dec->offset_y--;
GST_VIDEO_INFO_HEIGHT (info)++;
}
} else {
/* no cropping, use the encoded dimensions */
GST_VIDEO_INFO_WIDTH (info) = dec->info.frame_width;
GST_VIDEO_INFO_HEIGHT (info) = dec->info.frame_height;
dec->offset_x = 0;
dec->offset_y = 0;
}
GST_DEBUG_OBJECT (dec, "after fixup frame dimension %dx%d, offset %d:%d", GST_DEBUG_OBJECT (dec, "after fixup frame dimension %dx%d, offset %d:%d",
info->width, info->height, dec->offset_x, dec->offset_y); info->width, info->height, dec->offset_x, dec->offset_y);
@ -504,8 +475,8 @@ theora_handle_type_packet (GstTheoraDec * dec, ogg_packet * packet)
/* FIXME : Put this on the next outgoing frame */ /* FIXME : Put this on the next outgoing frame */
/* FIXME : */ /* FIXME : */
if (dec->tags) { if (dec->tags) {
gst_element_found_tags_for_pad (GST_ELEMENT_CAST (dec), gst_pad_push_event (GST_VIDEO_DECODER (dec)->srcpad,
GST_VIDEO_DECODER_SRC_PAD (dec), dec->tags); gst_event_new_tag (dec->tags));
dec->tags = NULL; dec->tags = NULL;
} }
@ -569,6 +540,7 @@ theora_handle_image (GstTheoraDec * dec, th_ycbcr_buffer buf,
int i, plane; int i, plane;
guint8 *dest, *src; guint8 *dest, *src;
GstBuffer *out; GstBuffer *out;
GstMapInfo minfo;
result = gst_video_decoder_alloc_output_frame (decoder, frame); result = gst_video_decoder_alloc_output_frame (decoder, frame);
@ -581,13 +553,15 @@ theora_handle_image (GstTheoraDec * dec, th_ycbcr_buffer buf,
out = frame->output_buffer; out = frame->output_buffer;
info = &dec->output_state->info; info = &dec->output_state->info;
/* FIXME : Use GstVideoInfo */ gst_buffer_map (out, &minfo, GST_MAP_WRITE);
/* FIXME : Use crop metadata */
for (plane = 0; plane < 3; plane++) { for (plane = 0; plane < 3; plane++) {
width = GST_VIDEO_INFO_COMP_WIDTH (info, plane); width = GST_VIDEO_INFO_COMP_WIDTH (info, plane);
height = GST_VIDEO_INFO_COMP_HEIGHT (info, plane); height = GST_VIDEO_INFO_COMP_HEIGHT (info, plane);
stride = GST_VIDEO_INFO_COMP_STRIDE (info, plane); stride = GST_VIDEO_INFO_COMP_STRIDE (info, plane);
dest = GST_BUFFER_DATA (out) + GST_VIDEO_INFO_COMP_OFFSET (info, plane); dest = minfo.data + GST_VIDEO_INFO_COMP_OFFSET (info, plane);
src = buf[plane].data; src = buf[plane].data;
src += src +=
((height == ((height ==
@ -605,6 +579,8 @@ theora_handle_image (GstTheoraDec * dec, th_ycbcr_buffer buf,
} }
} }
gst_buffer_unmap (out, &minfo);
return GST_FLOW_OK; return GST_FLOW_OK;
} }
@ -700,10 +676,12 @@ theora_dec_decode_buffer (GstTheoraDec * dec, GstBuffer * buf,
{ {
ogg_packet packet; ogg_packet packet;
GstFlowReturn result = GST_FLOW_OK; GstFlowReturn result = GST_FLOW_OK;
GstMapInfo minfo;
/* make ogg_packet out of the buffer */ /* make ogg_packet out of the buffer */
packet.packet = GST_BUFFER_DATA (buf); gst_buffer_map (buf, &minfo, GST_MAP_READ);
packet.bytes = GST_BUFFER_SIZE (buf); packet.packet = minfo.data;
packet.bytes = minfo.size;
packet.granulepos = -1; packet.granulepos = -1;
packet.packetno = 0; /* we don't really care */ packet.packetno = 0; /* we don't really care */
packet.b_o_s = dec->have_header ? 0 : 1; packet.b_o_s = dec->have_header ? 0 : 1;
@ -732,6 +710,8 @@ theora_dec_decode_buffer (GstTheoraDec * dec, GstBuffer * buf,
} }
done: done:
gst_buffer_unmap (buf, &minfo);
return result; return result;
} }
@ -757,9 +737,6 @@ theora_dec_set_property (GObject * object, guint prop_id,
GstTheoraDec *dec = GST_THEORA_DEC (object); GstTheoraDec *dec = GST_THEORA_DEC (object);
switch (prop_id) { switch (prop_id) {
case PROP_CROP:
dec->crop = g_value_get_boolean (value);
break;
case PROP_TELEMETRY_MV: case PROP_TELEMETRY_MV:
dec->telemetry_mv = g_value_get_int (value); dec->telemetry_mv = g_value_get_int (value);
break; break;
@ -785,9 +762,6 @@ theora_dec_get_property (GObject * object, guint prop_id,
GstTheoraDec *dec = GST_THEORA_DEC (object); GstTheoraDec *dec = GST_THEORA_DEC (object);
switch (prop_id) { switch (prop_id) {
case PROP_CROP:
g_value_set_boolean (value, dec->crop);
break;
case PROP_TELEMETRY_MV: case PROP_TELEMETRY_MV:
g_value_set_int (value, dec->telemetry_mv); g_value_set_int (value, dec->telemetry_mv);
break; break;

View file

@ -77,10 +77,7 @@ struct _GstTheoraDec
gint telemetry_qi; gint telemetry_qi;
gint telemetry_bits; gint telemetry_bits;
gboolean crop;
GstTagList *tags; GstTagList *tags;
}; };
struct _GstTheoraDecClass struct _GstTheoraDecClass

View file

@ -69,25 +69,6 @@
#define GST_CAT_DEFAULT theoraenc_debug #define GST_CAT_DEFAULT theoraenc_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
#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 const GEnumValue border_mode[] = {
{BORDER_NONE, "No Border", "none"},
{BORDER_BLACK, "Black Border", "black"},
{BORDER_MIRROR, "Mirror image in borders", "mirror"},
{0, NULL, NULL},
};
if (!border_mode_type) {
border_mode_type =
g_enum_register_static ("GstTheoraEncBorderMode", border_mode);
}
return border_mode_type;
}
#define GST_TYPE_MULTIPASS_MODE (gst_multipass_mode_get_type()) #define GST_TYPE_MULTIPASS_MODE (gst_multipass_mode_get_type())
static GType static GType
gst_multipass_mode_get_type (void) gst_multipass_mode_get_type (void)
@ -136,18 +117,11 @@ _ilog (unsigned int v)
enum enum
{ {
PROP_0, PROP_0,
PROP_CENTER,
PROP_BORDER,
PROP_BITRATE, PROP_BITRATE,
PROP_QUALITY, PROP_QUALITY,
PROP_QUICK,
PROP_KEYFRAME_AUTO, PROP_KEYFRAME_AUTO,
PROP_KEYFRAME_FREQ, PROP_KEYFRAME_FREQ,
PROP_KEYFRAME_FREQ_FORCE, PROP_KEYFRAME_FREQ_FORCE,
PROP_KEYFRAME_THRESHOLD,
PROP_KEYFRAME_MINDISTANCE,
PROP_NOISE_SENSITIVITY,
PROP_SHARPNESS,
PROP_SPEEDLEVEL, PROP_SPEEDLEVEL,
PROP_VP3_COMPATIBLE, PROP_VP3_COMPATIBLE,
PROP_DROP_FRAMES, PROP_DROP_FRAMES,
@ -182,8 +156,8 @@ static GstStaticPadTemplate theora_enc_sink_factory =
GST_STATIC_PAD_TEMPLATE ("sink", GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK, GST_PAD_SINK,
GST_PAD_ALWAYS, GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-raw-yuv, " GST_STATIC_CAPS ("video/x-raw, "
"format = (fourcc) { I420, Y42B, Y444 }, " "format = (string) { I420, Y42B, Y444 }, "
"framerate = (fraction) [1/MAX, MAX], " "framerate = (fraction) [1/MAX, MAX], "
"width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]") "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
); );
@ -192,11 +166,13 @@ static GstStaticPadTemplate theora_enc_src_factory =
GST_STATIC_PAD_TEMPLATE ("src", GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC, GST_PAD_SRC,
GST_PAD_ALWAYS, GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-theora") GST_STATIC_CAPS ("video/x-theora, "
"framerate = (fraction) [1/MAX, MAX], "
"width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
); );
GST_BOILERPLATE (GstTheoraEnc, gst_theora_enc, GstVideoEncoder, #define gst_theora_enc_parent_class parent_class
GST_TYPE_VIDEO_ENCODER); G_DEFINE_TYPE (GstTheoraEnc, gst_theora_enc, GST_TYPE_VIDEO_ENCODER);
static gboolean theora_enc_start (GstVideoEncoder * enc); static gboolean theora_enc_start (GstVideoEncoder * enc);
static gboolean theora_enc_stop (GstVideoEncoder * enc); static gboolean theora_enc_stop (GstVideoEncoder * enc);
@ -208,7 +184,8 @@ static GstFlowReturn theora_enc_pre_push (GstVideoEncoder * benc,
GstVideoCodecFrame * frame); GstVideoCodecFrame * frame);
static GstFlowReturn theora_enc_finish (GstVideoEncoder * enc); static GstFlowReturn theora_enc_finish (GstVideoEncoder * enc);
static GstCaps *theora_enc_sink_getcaps (GstPad * pad); static GstCaps *theora_enc_getcaps (GstVideoEncoder * encoder,
GstCaps * filter);
static void theora_enc_get_property (GObject * object, guint prop_id, static void theora_enc_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec); GValue * value, GParamSpec * pspec);
static void theora_enc_set_property (GObject * object, guint prop_id, static void theora_enc_set_property (GObject * object, guint prop_id,
@ -219,9 +196,16 @@ static gboolean theora_enc_write_multipass_cache (GstTheoraEnc * enc,
gboolean begin, gboolean eos); gboolean begin, gboolean eos);
static void static void
gst_theora_enc_base_init (gpointer g_class) gst_theora_enc_class_init (GstTheoraEncClass * klass)
{ {
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); GObjectClass *gobject_class = (GObjectClass *) klass;
GstElementClass *element_class = (GstElementClass *) klass;
GstVideoEncoderClass *gstvideo_encoder_class =
GST_VIDEO_ENCODER_CLASS (klass);
gobject_class->set_property = theora_enc_set_property;
gobject_class->get_property = theora_enc_get_property;
gobject_class->finalize = theora_enc_finalize;
gst_element_class_add_pad_template (element_class, gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&theora_enc_src_factory)); gst_static_pad_template_get (&theora_enc_src_factory));
@ -231,18 +215,6 @@ gst_theora_enc_base_init (gpointer g_class)
"Theora video encoder", "Codec/Encoder/Video", "Theora video encoder", "Codec/Encoder/Video",
"encode raw YUV video to a theora stream", "encode raw YUV video to a theora stream",
"Wim Taymans <wim@fluendo.com>"); "Wim Taymans <wim@fluendo.com>");
}
static void
gst_theora_enc_class_init (GstTheoraEncClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
GstVideoEncoderClass *gstvideo_encoder_class =
GST_VIDEO_ENCODER_CLASS (klass);
gobject_class->set_property = theora_enc_set_property;
gobject_class->get_property = theora_enc_get_property;
gobject_class->finalize = theora_enc_finalize;
gstvideo_encoder_class->start = GST_DEBUG_FUNCPTR (theora_enc_start); gstvideo_encoder_class->start = GST_DEBUG_FUNCPTR (theora_enc_start);
gstvideo_encoder_class->stop = GST_DEBUG_FUNCPTR (theora_enc_stop); gstvideo_encoder_class->stop = GST_DEBUG_FUNCPTR (theora_enc_stop);
@ -252,16 +224,8 @@ gst_theora_enc_class_init (GstTheoraEncClass * klass)
GST_DEBUG_FUNCPTR (theora_enc_handle_frame); GST_DEBUG_FUNCPTR (theora_enc_handle_frame);
gstvideo_encoder_class->pre_push = GST_DEBUG_FUNCPTR (theora_enc_pre_push); gstvideo_encoder_class->pre_push = GST_DEBUG_FUNCPTR (theora_enc_pre_push);
gstvideo_encoder_class->finish = GST_DEBUG_FUNCPTR (theora_enc_finish); gstvideo_encoder_class->finish = GST_DEBUG_FUNCPTR (theora_enc_finish);
gstvideo_encoder_class->getcaps = GST_DEBUG_FUNCPTR (theora_enc_getcaps);
g_object_class_install_property (gobject_class, PROP_CENTER,
g_param_spec_boolean ("center", "Center",
"ignored and kept for API compat only", TRUE,
(GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_BORDER,
g_param_spec_enum ("border", "Border",
"ignored and kept for API compat only",
GST_TYPE_BORDER_MODE, BORDER_BLACK,
(GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/* general encoding stream options */ /* general encoding stream options */
g_object_class_install_property (gobject_class, PROP_BITRATE, g_object_class_install_property (gobject_class, PROP_BITRATE,
g_param_spec_int ("bitrate", "Bitrate", "Compressed video bitrate (kbps)", g_param_spec_int ("bitrate", "Bitrate", "Compressed video bitrate (kbps)",
@ -273,10 +237,6 @@ gst_theora_enc_class_init (GstTheoraEncClass * klass)
THEORA_DEF_QUALITY, THEORA_DEF_QUALITY,
(GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_PLAYING)); GST_PARAM_MUTABLE_PLAYING));
g_object_class_install_property (gobject_class, PROP_QUICK,
g_param_spec_boolean ("quick", "Quick",
"ignored and kept for API compat only", TRUE,
(GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_KEYFRAME_AUTO, g_object_class_install_property (gobject_class, PROP_KEYFRAME_AUTO,
g_param_spec_boolean ("keyframe-auto", "Keyframe Auto", g_param_spec_boolean ("keyframe-auto", "Keyframe Auto",
"Automatic keyframe detection", THEORA_DEF_KEYFRAME_AUTO, "Automatic keyframe detection", THEORA_DEF_KEYFRAME_AUTO,
@ -290,22 +250,6 @@ gst_theora_enc_class_init (GstTheoraEncClass * klass)
"Force keyframe every N frames", 1, 32768, "Force keyframe every N frames", 1, 32768,
THEORA_DEF_KEYFRAME_FREQ_FORCE, THEORA_DEF_KEYFRAME_FREQ_FORCE,
(GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_KEYFRAME_THRESHOLD,
g_param_spec_int ("keyframe-threshold", "Keyframe threshold",
"ignored and kept for API compat only", 0, 32768, 80,
(GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_KEYFRAME_MINDISTANCE,
g_param_spec_int ("keyframe-mindistance", "Keyframe mindistance",
"ignored and kept for API compat only", 1, 32768, 8,
(GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_NOISE_SENSITIVITY,
g_param_spec_int ("noise-sensitivity", "Noise sensitivity",
"ignored and kept for API compat only", 0, 32768, 1,
(GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_SHARPNESS,
g_param_spec_int ("sharpness", "Sharpness",
"ignored and kept for API compat only", 0, 2, 0,
(GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_SPEEDLEVEL, g_object_class_install_property (gobject_class, PROP_SPEEDLEVEL,
g_param_spec_int ("speed-level", "Speed level", g_param_spec_int ("speed-level", "Speed level",
"Controls the amount of motion vector searching done while " "Controls the amount of motion vector searching done while "
@ -358,11 +302,8 @@ gst_theora_enc_class_init (GstTheoraEncClass * klass)
} }
static void static void
gst_theora_enc_init (GstTheoraEnc * enc, GstTheoraEncClass * g_class) gst_theora_enc_init (GstTheoraEnc * enc)
{ {
gst_pad_set_getcaps_function (GST_VIDEO_ENCODER_SINK_PAD (enc),
GST_DEBUG_FUNCPTR (theora_enc_sink_getcaps));
enc->video_bitrate = THEORA_DEF_BITRATE; enc->video_bitrate = THEORA_DEF_BITRATE;
enc->video_quality = THEORA_DEF_QUALITY; enc->video_quality = THEORA_DEF_QUALITY;
enc->keyframe_auto = THEORA_DEF_KEYFRAME_AUTO; enc->keyframe_auto = THEORA_DEF_KEYFRAME_AUTO;
@ -571,9 +512,9 @@ theora_enc_get_supported_formats (void)
} }
static GstCaps * static GstCaps *
theora_enc_sink_getcaps (GstPad * pad) theora_enc_getcaps (GstVideoEncoder * encoder, GstCaps * filter)
{ {
GstCaps *caps; GstCaps *caps, *ret;
char *supported_formats, *caps_string; char *supported_formats, *caps_string;
supported_formats = theora_enc_get_supported_formats (); supported_formats = theora_enc_get_supported_formats ();
@ -582,8 +523,8 @@ theora_enc_sink_getcaps (GstPad * pad)
return gst_caps_new_empty (); return gst_caps_new_empty ();
} }
caps_string = g_strdup_printf ("video/x-raw-yuv, " caps_string = g_strdup_printf ("video/x-raw, "
"format = (fourcc) { %s }, " "format = (string) { %s }, "
"framerate = (fraction) [1/MAX, MAX], " "framerate = (fraction) [1/MAX, MAX], "
"width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]", "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]",
supported_formats); supported_formats);
@ -592,7 +533,10 @@ theora_enc_sink_getcaps (GstPad * pad)
g_free (supported_formats); g_free (supported_formats);
GST_DEBUG ("Supported caps: %" GST_PTR_FORMAT, caps); GST_DEBUG ("Supported caps: %" GST_PTR_FORMAT, caps);
return caps; ret = gst_video_encoder_proxy_getcaps (encoder, caps, filter);
gst_caps_unref (caps);
return ret;
} }
static gboolean static gboolean
@ -682,14 +626,14 @@ theora_push_packet (GstTheoraEnc * enc, ogg_packet * packet)
benc = GST_VIDEO_ENCODER (enc); benc = GST_VIDEO_ENCODER (enc);
buf = gst_buffer_new_and_alloc (packet->bytes); buf = gst_buffer_new_allocate (NULL, packet->bytes, NULL);
if (!buf) { if (!buf) {
GST_WARNING_OBJECT (enc, "Could not allocate buffer"); GST_WARNING_OBJECT (enc, "Could not allocate buffer");
ret = GST_FLOW_ERROR; ret = GST_FLOW_ERROR;
goto done; goto done;
} }
memcpy (GST_BUFFER_DATA (buf), packet->packet, packet->bytes); gst_buffer_fill (buf, 0, packet->packet, packet->bytes);
frame = gst_video_encoder_get_oldest_frame (benc); frame = gst_video_encoder_get_oldest_frame (benc);
frame->output_buffer = buf; frame->output_buffer = buf;
@ -728,7 +672,7 @@ theora_set_header_on_caps (GstCaps * caps, GList * buffers)
buffer = walk->data; buffer = walk->data;
/* mark buffer */ /* mark buffer */
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_IN_CAPS); GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_HEADER);
/* Copy buffer, because we can't use the original - /* Copy buffer, because we can't use the original -
* it creates a circular refcount with the caps<->buffers */ * it creates a circular refcount with the caps<->buffers */
@ -750,25 +694,11 @@ theora_set_header_on_caps (GstCaps * caps, GList * buffers)
} }
static void static void
theora_enc_init_buffer (th_ycbcr_buffer buf, th_info * info, guint8 * data) theora_enc_init_buffer (th_ycbcr_buffer buf, GstVideoFrame * frame)
{ {
GstVideoFormat format; GstVideoInfo vinfo;
guint i; guint i;
switch (info->pixel_fmt) {
case TH_PF_444:
format = GST_VIDEO_FORMAT_Y444;
break;
case TH_PF_420:
format = GST_VIDEO_FORMAT_I420;
break;
case TH_PF_422:
format = GST_VIDEO_FORMAT_Y42B;
break;
default:
g_assert_not_reached ();
}
/* According to Theora developer Timothy Terriberry, the Theora /* According to Theora developer Timothy Terriberry, the Theora
* encoder will not use memory outside of pic_width/height, even when * encoder will not use memory outside of pic_width/height, even when
* the frame size is bigger. The values outside this region will be encoded * the frame size is bigger. The values outside this region will be encoded
@ -776,17 +706,17 @@ theora_enc_init_buffer (th_ycbcr_buffer buf, th_info * info, guint8 * data)
* Due to this, setting the frame's width/height as the buffer width/height * Due to this, setting the frame's width/height as the buffer width/height
* is perfectly ok, even though it does not strictly look ok. * is perfectly ok, even though it does not strictly look ok.
*/ */
for (i = 0; i < 3; i++) {
buf[i].width =
gst_video_format_get_component_width (format, i, info->frame_width);
buf[i].height =
gst_video_format_get_component_height (format, i, info->frame_height);
buf[i].data = gst_video_info_init (&vinfo);
data + gst_video_format_get_component_offset (format, i, gst_video_info_set_format (&vinfo, GST_VIDEO_FRAME_FORMAT (frame),
info->pic_width, info->pic_height); GST_ROUND_UP_16 (GST_VIDEO_FRAME_WIDTH (frame)),
buf[i].stride = GST_ROUND_UP_16 (GST_VIDEO_FRAME_HEIGHT (frame)));
gst_video_format_get_row_stride (format, i, info->pic_width);
for (i = 0; i < 3; i++) {
buf[i].width = GST_VIDEO_INFO_COMP_WIDTH (&vinfo, i);
buf[i].height = GST_VIDEO_INFO_COMP_HEIGHT (&vinfo, i);
buf[i].data = GST_VIDEO_FRAME_COMP_DATA (frame, i);
buf[i].stride = GST_VIDEO_FRAME_COMP_STRIDE (frame, i);
} }
} }
@ -795,22 +725,29 @@ theora_enc_read_multipass_cache (GstTheoraEnc * enc)
{ {
GstBuffer *cache_buf; GstBuffer *cache_buf;
const guint8 *cache_data; const guint8 *cache_data;
gsize bytes_read = 0, bytes_consumed = 0; gsize bytes_read = 0;
gssize bytes_consumed = 0;
GIOStatus stat = G_IO_STATUS_NORMAL; GIOStatus stat = G_IO_STATUS_NORMAL;
gboolean done = FALSE; gboolean done = FALSE;
while (!done) { while (!done) {
if (gst_adapter_available (enc->multipass_cache_adapter) == 0) { if (gst_adapter_available (enc->multipass_cache_adapter) == 0) {
cache_buf = gst_buffer_new_and_alloc (512); GstMapInfo minfo;
cache_buf = gst_buffer_new_allocate (NULL, 512, NULL);
gst_buffer_map (cache_buf, &minfo, GST_MAP_WRITE);
stat = g_io_channel_read_chars (enc->multipass_cache_fd, stat = g_io_channel_read_chars (enc->multipass_cache_fd,
(gchar *) GST_BUFFER_DATA (cache_buf), GST_BUFFER_SIZE (cache_buf), (gchar *) minfo.data, minfo.size, &bytes_read, NULL);
&bytes_read, NULL);
if (bytes_read <= 0) { if (bytes_read <= 0) {
gst_buffer_unmap (cache_buf, &minfo);
gst_buffer_unref (cache_buf); gst_buffer_unref (cache_buf);
break; break;
} else { } else {
GST_BUFFER_SIZE (cache_buf) = bytes_read; gst_buffer_unmap (cache_buf, &minfo);
gst_buffer_resize (cache_buf, 0, bytes_read);
gst_adapter_push (enc->multipass_cache_adapter, cache_buf); gst_adapter_push (enc->multipass_cache_adapter, cache_buf);
} }
@ -821,11 +758,13 @@ theora_enc_read_multipass_cache (GstTheoraEnc * enc)
bytes_read = bytes_read =
MIN (gst_adapter_available (enc->multipass_cache_adapter), 512); MIN (gst_adapter_available (enc->multipass_cache_adapter), 512);
cache_data = gst_adapter_peek (enc->multipass_cache_adapter, bytes_read); cache_data = gst_adapter_map (enc->multipass_cache_adapter, bytes_read);
bytes_consumed = bytes_consumed =
th_encode_ctl (enc->encoder, TH_ENCCTL_2PASS_IN, (guint8 *) cache_data, th_encode_ctl (enc->encoder, TH_ENCCTL_2PASS_IN, (guint8 *) cache_data,
bytes_read); bytes_read);
gst_adapter_unmap (enc->multipass_cache_adapter);
done = bytes_consumed <= 0; done = bytes_consumed <= 0;
if (bytes_consumed > 0) if (bytes_consumed > 0)
gst_adapter_flush (enc->multipass_cache_adapter, bytes_consumed); gst_adapter_flush (enc->multipass_cache_adapter, bytes_consumed);
@ -864,7 +803,7 @@ theora_enc_write_multipass_cache (GstTheoraEnc * enc, gboolean begin,
} }
if (stat == G_IO_STATUS_ERROR || bytes_read < 0 || bytes_written < 0) { if (stat == G_IO_STATUS_ERROR || bytes_read < 0) {
if (begin) { if (begin) {
if (eos) if (eos)
GST_ELEMENT_WARNING (enc, RESOURCE, WRITE, (NULL), GST_ELEMENT_WARNING (enc, RESOURCE, WRITE, (NULL),
@ -900,15 +839,15 @@ theora_enc_buffer_from_header_packet (GstTheoraEnc * enc, ogg_packet * packet)
{ {
GstBuffer *outbuf; GstBuffer *outbuf;
outbuf = gst_buffer_new_and_alloc (packet->bytes); outbuf = gst_buffer_new_allocate (NULL, packet->bytes, NULL);
memcpy (GST_BUFFER_DATA (outbuf), packet->packet, packet->bytes); gst_buffer_fill (outbuf, 0, packet->packet, packet->bytes);
GST_BUFFER_OFFSET (outbuf) = 0; GST_BUFFER_OFFSET (outbuf) = 0;
GST_BUFFER_OFFSET_END (outbuf) = 0; GST_BUFFER_OFFSET_END (outbuf) = 0;
GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE; GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE;
GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE; GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
GST_DEBUG ("created header packet buffer, %d bytes", GST_DEBUG ("created header packet buffer, %d bytes",
GST_BUFFER_SIZE (outbuf)); gst_buffer_get_size (outbuf));
return outbuf; return outbuf;
} }
@ -996,7 +935,7 @@ theora_enc_handle_frame (GstVideoEncoder * benc, GstVideoCodecFrame * frame)
buffers = g_list_reverse (buffers); buffers = g_list_reverse (buffers);
/* mark buffers and put on caps */ /* mark buffers and put on caps */
caps = gst_caps_new_simple ("video/x-theora", NULL); caps = gst_caps_new_empty_simple ("video/x-theora");
caps = theora_set_header_on_caps (caps, buffers); caps = theora_set_header_on_caps (caps, buffers);
state = gst_video_encoder_set_output_state (benc, caps, enc->input_state); state = gst_video_encoder_set_output_state (benc, caps, enc->input_state);
@ -1012,9 +951,7 @@ theora_enc_handle_frame (GstVideoEncoder * benc, GstVideoCodecFrame * frame)
{ {
th_ycbcr_buffer ycbcr; th_ycbcr_buffer ycbcr;
gint res; gint res;
GstVideoFrame vframe;
theora_enc_init_buffer (ycbcr, &enc->info,
GST_BUFFER_DATA (frame->input_buffer));
if (force_keyframe) { if (force_keyframe) {
theora_enc_reset (enc); theora_enc_reset (enc);
@ -1029,7 +966,13 @@ theora_enc_handle_frame (GstVideoEncoder * benc, GstVideoCodecFrame * frame)
} }
} }
gst_video_frame_map (&vframe, &enc->input_state->info, frame->input_buffer,
GST_MAP_READ);
theora_enc_init_buffer (ycbcr, &vframe);
res = th_encode_ycbcr_in (enc->encoder, ycbcr); res = th_encode_ycbcr_in (enc->encoder, ycbcr);
gst_video_frame_unmap (&vframe);
/* none of the failure cases can happen here */ /* none of the failure cases can happen here */
g_assert (res == 0); g_assert (res == 0);
@ -1102,15 +1045,6 @@ theora_enc_set_property (GObject * object, guint prop_id,
GstTheoraEnc *enc = GST_THEORA_ENC (object); GstTheoraEnc *enc = GST_THEORA_ENC (object);
switch (prop_id) { switch (prop_id) {
case PROP_CENTER:
case PROP_BORDER:
case PROP_QUICK:
case PROP_KEYFRAME_THRESHOLD:
case PROP_KEYFRAME_MINDISTANCE:
case PROP_NOISE_SENSITIVITY:
case PROP_SHARPNESS:
/* kept for API compat, but ignored */
break;
case PROP_BITRATE: case PROP_BITRATE:
GST_OBJECT_LOCK (enc); GST_OBJECT_LOCK (enc);
enc->video_bitrate = g_value_get_int (value) * 1000; enc->video_bitrate = g_value_get_int (value) * 1000;
@ -1176,12 +1110,6 @@ theora_enc_get_property (GObject * object, guint prop_id,
GstTheoraEnc *enc = GST_THEORA_ENC (object); GstTheoraEnc *enc = GST_THEORA_ENC (object);
switch (prop_id) { switch (prop_id) {
case PROP_CENTER:
g_value_set_boolean (value, TRUE);
break;
case PROP_BORDER:
g_value_set_enum (value, BORDER_BLACK);
break;
case PROP_BITRATE: case PROP_BITRATE:
GST_OBJECT_LOCK (enc); GST_OBJECT_LOCK (enc);
g_value_set_int (value, enc->video_bitrate / 1000); g_value_set_int (value, enc->video_bitrate / 1000);
@ -1192,9 +1120,6 @@ theora_enc_get_property (GObject * object, guint prop_id,
g_value_set_int (value, enc->video_quality); g_value_set_int (value, enc->video_quality);
GST_OBJECT_UNLOCK (enc); GST_OBJECT_UNLOCK (enc);
break; break;
case PROP_QUICK:
g_value_set_boolean (value, TRUE);
break;
case PROP_KEYFRAME_AUTO: case PROP_KEYFRAME_AUTO:
g_value_set_boolean (value, enc->keyframe_auto); g_value_set_boolean (value, enc->keyframe_auto);
break; break;
@ -1204,18 +1129,6 @@ theora_enc_get_property (GObject * object, guint prop_id,
case PROP_KEYFRAME_FREQ_FORCE: case PROP_KEYFRAME_FREQ_FORCE:
g_value_set_int (value, enc->keyframe_force); g_value_set_int (value, enc->keyframe_force);
break; break;
case PROP_KEYFRAME_THRESHOLD:
g_value_set_int (value, 80);
break;
case PROP_KEYFRAME_MINDISTANCE:
g_value_set_int (value, 8);
break;
case PROP_NOISE_SENSITIVITY:
g_value_set_int (value, 1);
break;
case PROP_SHARPNESS:
g_value_set_int (value, 0);
break;
case PROP_SPEEDLEVEL: case PROP_SPEEDLEVEL:
g_value_set_int (value, enc->speed_level); g_value_set_int (value, enc->speed_level);
break; break;

View file

@ -44,22 +44,6 @@ G_BEGIN_DECLS
typedef struct _GstTheoraEnc GstTheoraEnc; typedef struct _GstTheoraEnc GstTheoraEnc;
typedef struct _GstTheoraEncClass GstTheoraEncClass; typedef struct _GstTheoraEncClass GstTheoraEncClass;
/**
* GstTheoraEncBorderMode:
* @BORDER_NONE: no border
* @BORDER_BLACK: black border
* @BORDER_MIRROR: Mirror image in border
*
* Border color to add when sizes not multiple of 16.
*/
typedef enum
{
BORDER_NONE,
BORDER_BLACK,
BORDER_MIRROR
}
GstTheoraEncBorderMode;
/** /**
* GstTheoraEncMultipassMode: * GstTheoraEncMultipassMode:
* @MULTIPASS_MODE_SINGLE_PASS: Single pass encoding * @MULTIPASS_MODE_SINGLE_PASS: Single pass encoding