3ff12d637c1f0ce957e80fa628c736aa2c5ff064
[platform/upstream/gst-plugins-base.git] / ext / theora / theoraenc.c
1 /* GStreamer
2  * Copyright (C) 2004 Wim Taymans <wim@fluendo.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /**
21  * SECTION:element-theoraenc
22  * @see_also: theoradec, oggmux
23  *
24  * <refsect2>
25  * <para>
26  * This element encodes raw video into a Theora stream.
27  * <ulink url="http://www.theora.org/">Theora</ulink> is a royalty-free
28  * video codec maintained by the <ulink url="http://www.xiph.org/">Xiph.org
29  * Foundation</ulink>, based on the VP3 codec.
30  * </para>
31  * <title>Example pipeline</title>
32  * <programlisting>
33  * gst-launch -v videotestsrc num-buffers=1000 ! theoraenc ! oggmux ! filesink location=videotestsrc.ogg
34  * </programlisting>
35  * </refsect2>
36  */
37
38 #ifdef HAVE_CONFIG_H
39 #  include "config.h"
40 #endif
41
42 #include <gst/gst.h>
43 #include <theora/theora.h>
44 #include <string.h>
45 #include <gst/tag/tag.h>
46
47 GST_DEBUG_CATEGORY (theoraenc_debug);
48 #define GST_CAT_DEFAULT theoraenc_debug
49
50 #define GST_TYPE_THEORA_ENC \
51   (gst_theora_enc_get_type())
52 #define GST_THEORA_ENC(obj) \
53   (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_THEORA_ENC,GstTheoraEnc))
54 #define GST_THEORA_ENC_CLASS(klass) \
55   (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_THEORA_ENC,GstTheoraEnc))
56 #define GST_IS_THEORA_ENC(obj) \
57   (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_THEORA_ENC))
58 #define GST_IS_THEORA_ENC_CLASS(obj) \
59   (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_THEORA_ENC))
60
61 typedef struct _GstTheoraEnc GstTheoraEnc;
62 typedef struct _GstTheoraEncClass GstTheoraEncClass;
63
64 typedef enum
65 {
66   BORDER_NONE,
67   BORDER_BLACK,
68   BORDER_MIRROR
69 }
70 GstTheoraEncBorderMode;
71
72 #define GST_TYPE_BORDER_MODE (gst_border_mode_get_type())
73 static GType
74 gst_border_mode_get_type (void)
75 {
76   static GType border_mode_type = 0;
77   static GEnumValue border_mode[] = {
78     {BORDER_NONE, "BORDER_NONE", "No Border"},
79     {BORDER_BLACK, "BORDER_BLACK", "Black Border"},
80     {BORDER_MIRROR, "BORDER_MIRROR", "Mirror image in borders"},
81     {0, NULL, NULL},
82   };
83
84   if (!border_mode_type) {
85     border_mode_type =
86         g_enum_register_static ("GstTheoraEncBorderMode", border_mode);
87   }
88   return border_mode_type;
89 }
90
91 struct _GstTheoraEnc
92 {
93   GstElement element;
94
95   GstPad *sinkpad;
96   GstPad *srcpad;
97
98   ogg_stream_state to;
99
100   theora_state state;
101   theora_info info;
102   theora_comment comment;
103
104   gboolean center;
105   GstTheoraEncBorderMode border;
106
107   gint video_bitrate;           /* bitrate target for Theora video */
108   gint video_quality;           /* Theora quality selector 0 = low, 63 = high */
109   gboolean quick;
110   gboolean keyframe_auto;
111   gint keyframe_freq;
112   gint keyframe_force;
113   gint keyframe_threshold;
114   gint keyframe_mindistance;
115   gint noise_sensitivity;
116   gint sharpness;
117
118   gint info_width, info_height;
119   gint width, height;
120   gint offset_x, offset_y;
121   gdouble fps;
122
123   guint packetno;
124   guint64 bytes_out;
125   guint64 initial_delay;
126 };
127
128 struct _GstTheoraEncClass
129 {
130   GstElementClass parent_class;
131 };
132
133 #define ROUND_UP_2(x) (((x) + 1) & ~1)
134 #define ROUND_UP_4(x) (((x) + 3) & ~3)
135 #define ROUND_UP_8(x) (((x) + 7) & ~7)
136
137 #define THEORA_DEF_CENTER               TRUE
138 #define THEORA_DEF_BORDER               BORDER_BLACK
139 #define THEORA_DEF_BITRATE              0
140 #define THEORA_DEF_QUALITY              16
141 #define THEORA_DEF_QUICK                TRUE
142 #define THEORA_DEF_KEYFRAME_AUTO        TRUE
143 #define THEORA_DEF_KEYFRAME_FREQ        64
144 #define THEORA_DEF_KEYFRAME_FREQ_FORCE  64
145 #define THEORA_DEF_KEYFRAME_THRESHOLD   80
146 #define THEORA_DEF_KEYFRAME_MINDISTANCE 8
147 #define THEORA_DEF_NOISE_SENSITIVITY    1
148 #define THEORA_DEF_SHARPNESS            0
149
150 enum
151 {
152   ARG_0,
153   ARG_CENTER,
154   ARG_BORDER,
155   ARG_BITRATE,
156   ARG_QUALITY,
157   ARG_QUICK,
158   ARG_KEYFRAME_AUTO,
159   ARG_KEYFRAME_FREQ,
160   ARG_KEYFRAME_FREQ_FORCE,
161   ARG_KEYFRAME_THRESHOLD,
162   ARG_KEYFRAME_MINDISTANCE,
163   ARG_NOISE_SENSITIVITY,
164   ARG_SHARPNESS,
165   /* FILL ME */
166 };
167
168 static GstElementDetails theora_enc_details = {
169   "TheoraEnc",
170   "Codec/Encoder/Video",
171   "encode raw YUV video to a theora stream",
172   "Wim Taymans <wim@fluendo.com>",
173 };
174
175 static GstStaticPadTemplate theora_enc_sink_factory =
176 GST_STATIC_PAD_TEMPLATE ("sink",
177     GST_PAD_SINK,
178     GST_PAD_ALWAYS,
179     GST_STATIC_CAPS ("video/x-raw-yuv, "
180         "format = (fourcc) I420, "
181         "framerate = (double) [0, MAX], "
182         "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
183     );
184
185 static GstStaticPadTemplate theora_enc_src_factory =
186 GST_STATIC_PAD_TEMPLATE ("src",
187     GST_PAD_SRC,
188     GST_PAD_ALWAYS,
189     GST_STATIC_CAPS ("video/x-theora")
190     );
191
192 GST_BOILERPLATE (GstTheoraEnc, gst_theora_enc, GstElement, GST_TYPE_ELEMENT);
193
194 static gboolean theora_enc_sink_event (GstPad * pad, GstEvent * event);
195 static GstFlowReturn theora_enc_chain (GstPad * pad, GstBuffer * buffer);
196 static GstStateChangeReturn theora_enc_change_state (GstElement * element,
197     GstStateChange transition);
198 static gboolean theora_enc_sink_setcaps (GstPad * pad, GstCaps * caps);
199 static void theora_enc_get_property (GObject * object, guint prop_id,
200     GValue * value, GParamSpec * pspec);
201 static void theora_enc_set_property (GObject * object, guint prop_id,
202     const GValue * value, GParamSpec * pspec);
203
204 static void
205 gst_theora_enc_base_init (gpointer g_class)
206 {
207   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
208
209   gst_element_class_add_pad_template (element_class,
210       gst_static_pad_template_get (&theora_enc_src_factory));
211   gst_element_class_add_pad_template (element_class,
212       gst_static_pad_template_get (&theora_enc_sink_factory));
213   gst_element_class_set_details (element_class, &theora_enc_details);
214 }
215
216 static void
217 gst_theora_enc_class_init (GstTheoraEncClass * klass)
218 {
219   GObjectClass *gobject_class = (GObjectClass *) klass;
220   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
221
222   gobject_class->set_property = theora_enc_set_property;
223   gobject_class->get_property = theora_enc_get_property;
224
225   g_object_class_install_property (gobject_class, ARG_CENTER,
226       g_param_spec_boolean ("center", "Center",
227           "Center image when sizes not multiple of 16", THEORA_DEF_CENTER,
228           (GParamFlags) G_PARAM_READWRITE));
229   g_object_class_install_property (gobject_class, ARG_BORDER,
230       g_param_spec_enum ("border", "Border",
231           "Border color to add when sizes not multiple of 16",
232           GST_TYPE_BORDER_MODE, THEORA_DEF_BORDER,
233           (GParamFlags) G_PARAM_READWRITE));
234   /* general encoding stream options */
235   g_object_class_install_property (gobject_class, ARG_BITRATE,
236       g_param_spec_int ("bitrate", "Bitrate", "Compressed video bitrate (kbps)",
237           0, 2000, THEORA_DEF_BITRATE, (GParamFlags) G_PARAM_READWRITE));
238   g_object_class_install_property (gobject_class, ARG_QUALITY,
239       g_param_spec_int ("quality", "Quality", "Video quality",
240           0, 63, THEORA_DEF_QUALITY, (GParamFlags) G_PARAM_READWRITE));
241   g_object_class_install_property (gobject_class, ARG_QUICK,
242       g_param_spec_boolean ("quick", "Quick", "Quick encoding",
243           THEORA_DEF_QUICK, (GParamFlags) G_PARAM_READWRITE));
244   g_object_class_install_property (gobject_class, ARG_KEYFRAME_AUTO,
245       g_param_spec_boolean ("keyframe-auto", "Keyframe Auto",
246           "Automatic keyframe detection", THEORA_DEF_KEYFRAME_AUTO,
247           (GParamFlags) G_PARAM_READWRITE));
248   g_object_class_install_property (gobject_class, ARG_KEYFRAME_FREQ,
249       g_param_spec_int ("keyframe-freq", "Keyframe frequency",
250           "Keyframe frequency", 1, 32768, THEORA_DEF_KEYFRAME_FREQ,
251           (GParamFlags) G_PARAM_READWRITE));
252   g_object_class_install_property (gobject_class, ARG_KEYFRAME_FREQ_FORCE,
253       g_param_spec_int ("keyframe-force", "Keyframe force",
254           "Force keyframe every N frames", 1, 32768,
255           THEORA_DEF_KEYFRAME_FREQ_FORCE, (GParamFlags) G_PARAM_READWRITE));
256   g_object_class_install_property (gobject_class, ARG_KEYFRAME_THRESHOLD,
257       g_param_spec_int ("keyframe-threshold", "Keyframe threshold",
258           "Keyframe threshold", 0, 32768, THEORA_DEF_KEYFRAME_THRESHOLD,
259           (GParamFlags) G_PARAM_READWRITE));
260   g_object_class_install_property (gobject_class, ARG_KEYFRAME_MINDISTANCE,
261       g_param_spec_int ("keyframe-mindistance", "Keyframe mindistance",
262           "Keyframe mindistance", 1, 32768, THEORA_DEF_KEYFRAME_MINDISTANCE,
263           (GParamFlags) G_PARAM_READWRITE));
264   g_object_class_install_property (gobject_class, ARG_NOISE_SENSITIVITY,
265       g_param_spec_int ("noise-sensitivity", "Noise sensitivity",
266           "Noise sensitivity", 0, 32768, THEORA_DEF_NOISE_SENSITIVITY,
267           (GParamFlags) G_PARAM_READWRITE));
268   g_object_class_install_property (gobject_class, ARG_SHARPNESS,
269       g_param_spec_int ("sharpness", "Sharpness",
270           "Sharpness", 0, 2, THEORA_DEF_SHARPNESS,
271           (GParamFlags) G_PARAM_READWRITE));
272
273   gstelement_class->change_state = theora_enc_change_state;
274   GST_DEBUG_CATEGORY_INIT (theoraenc_debug, "theoraenc", 0, "Theora encoder");
275 }
276
277 static void
278 gst_theora_enc_init (GstTheoraEnc * enc, GstTheoraEncClass * g_class)
279 {
280   enc->sinkpad =
281       gst_pad_new_from_template (gst_static_pad_template_get
282       (&theora_enc_sink_factory), "sink");
283   gst_pad_set_chain_function (enc->sinkpad, theora_enc_chain);
284   gst_pad_set_event_function (enc->sinkpad, theora_enc_sink_event);
285   gst_pad_set_setcaps_function (enc->sinkpad, theora_enc_sink_setcaps);
286   gst_element_add_pad (GST_ELEMENT (enc), enc->sinkpad);
287
288   enc->srcpad =
289       gst_pad_new_from_template (gst_static_pad_template_get
290       (&theora_enc_src_factory), "src");
291   gst_element_add_pad (GST_ELEMENT (enc), enc->srcpad);
292
293   enc->center = THEORA_DEF_CENTER;
294   enc->border = THEORA_DEF_BORDER;
295
296   enc->video_bitrate = THEORA_DEF_BITRATE;
297   enc->video_quality = THEORA_DEF_QUALITY;
298   enc->quick = THEORA_DEF_QUICK;
299   enc->keyframe_auto = THEORA_DEF_KEYFRAME_AUTO;
300   enc->keyframe_freq = THEORA_DEF_KEYFRAME_FREQ;
301   enc->keyframe_force = THEORA_DEF_KEYFRAME_FREQ_FORCE;
302   enc->keyframe_threshold = THEORA_DEF_KEYFRAME_THRESHOLD;
303   enc->keyframe_mindistance = THEORA_DEF_KEYFRAME_MINDISTANCE;
304   enc->noise_sensitivity = THEORA_DEF_NOISE_SENSITIVITY;
305   enc->sharpness = THEORA_DEF_SHARPNESS;
306 }
307
308 static gboolean
309 theora_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
310 {
311   GstStructure *structure = gst_caps_get_structure (caps, 0);
312   GstTheoraEnc *enc = GST_THEORA_ENC (gst_pad_get_parent (pad));
313   const GValue *par;
314   GValue fps = { 0 };
315   GValue framerate = { 0 };
316
317   gst_structure_get_int (structure, "width", &enc->width);
318   gst_structure_get_int (structure, "height", &enc->height);
319   gst_structure_get_double (structure, "framerate", &enc->fps);
320   par = gst_structure_get_value (structure, "pixel-aspect-ratio");
321
322   theora_info_init (&enc->info);
323   /* Theora has a divisible-by-sixteen restriction for the encoded video size but
324    * we can define a visible area using the frame_width/frame_height */
325   enc->info_width = enc->info.width = (enc->width + 15) & ~15;
326   enc->info_height = enc->info.height = (enc->height + 15) & ~15;
327   enc->info.frame_width = enc->width;
328   enc->info.frame_height = enc->height;
329
330   /* center image if needed */
331   if (enc->center) {
332     /* make sure offset is even, for easier decoding */
333     enc->offset_x = ROUND_UP_2 ((enc->info_width - enc->width) / 2);
334     enc->offset_y = ROUND_UP_2 ((enc->info_height - enc->height) / 2);
335   } else {
336     enc->offset_x = 0;
337     enc->offset_y = 0;
338   }
339   enc->info.offset_x = enc->offset_x;
340   enc->info.offset_y = enc->offset_y;
341
342   /* convert double to fraction for the framerate */
343   g_value_init (&fps, G_TYPE_DOUBLE);
344   g_value_init (&framerate, GST_TYPE_FRACTION);
345   g_value_set_double (&fps, enc->fps);
346   g_value_transform (&fps, &framerate);
347
348   enc->info.fps_numerator = gst_value_get_fraction_numerator (&framerate);
349   enc->info.fps_denominator = gst_value_get_fraction_denominator (&framerate);
350
351   if (par) {
352     enc->info.aspect_numerator = gst_value_get_fraction_numerator (par);
353     enc->info.aspect_denominator = gst_value_get_fraction_denominator (par);
354   } else {
355     /* setting them to 0 indicates that the decoder can chose a good aspect
356      * ratio, defaulting to 1/1 */
357     enc->info.aspect_numerator = 0;
358     enc->info.aspect_denominator = 0;
359   }
360
361   enc->info.colorspace = OC_CS_UNSPECIFIED;
362   enc->info.target_bitrate = enc->video_bitrate;
363   enc->info.quality = enc->video_quality;
364
365   enc->info.dropframes_p = 0;
366   enc->info.quick_p = (enc->quick ? 1 : 0);
367   enc->info.keyframe_auto_p = (enc->keyframe_auto ? 1 : 0);
368   enc->info.keyframe_frequency = enc->keyframe_freq;
369   enc->info.keyframe_frequency_force = enc->keyframe_force;
370   enc->info.keyframe_data_target_bitrate = enc->video_bitrate * 1.5;
371   enc->info.keyframe_auto_threshold = enc->keyframe_threshold;
372   enc->info.keyframe_mindistance = enc->keyframe_mindistance;
373   enc->info.noise_sensitivity = enc->noise_sensitivity;
374   enc->info.sharpness = enc->sharpness;
375
376   theora_encode_init (&enc->state, &enc->info);
377
378   return TRUE;
379 }
380
381 /* prepare a buffer for transmission by passing data through libtheora */
382 static GstBuffer *
383 theora_buffer_from_packet (GstTheoraEnc * enc, ogg_packet * packet,
384     GstClockTime timestamp, GstClockTime duration)
385 {
386   GstBuffer *buf;
387   GstFlowReturn ret;
388
389   ret = gst_pad_alloc_buffer (enc->srcpad,
390       GST_BUFFER_OFFSET_NONE, packet->bytes, GST_PAD_CAPS (enc->srcpad), &buf);
391   if (ret != GST_FLOW_OK)
392     goto no_buffer;
393
394   memcpy (GST_BUFFER_DATA (buf), packet->packet, packet->bytes);
395   GST_BUFFER_OFFSET (buf) = enc->bytes_out;
396   GST_BUFFER_OFFSET_END (buf) = packet->granulepos;
397   GST_BUFFER_TIMESTAMP (buf) = timestamp;
398   GST_BUFFER_DURATION (buf) = duration;
399
400   /* the second most significant bit of the first data byte is cleared
401    * for keyframes */
402   if ((packet->packet[0] & 0x40) == 0) {
403     GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
404   } else {
405     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
406   }
407   enc->packetno++;
408
409   return buf;
410
411 no_buffer:
412   {
413     return NULL;
414   }
415 }
416
417 /* push out the buffer and do internal bookkeeping */
418 static GstFlowReturn
419 theora_push_buffer (GstTheoraEnc * enc, GstBuffer * buffer)
420 {
421   GstFlowReturn ret;
422
423   enc->bytes_out += GST_BUFFER_SIZE (buffer);
424
425   ret = gst_pad_push (enc->srcpad, buffer);
426
427   return ret;
428 }
429
430 static GstFlowReturn
431 theora_push_packet (GstTheoraEnc * enc, ogg_packet * packet,
432     GstClockTime timestamp, GstClockTime duration)
433 {
434   GstBuffer *buf;
435   GstFlowReturn ret;
436
437   buf = theora_buffer_from_packet (enc, packet, timestamp, duration);
438   ret = theora_push_buffer (enc, buf);
439
440   return ret;
441 }
442
443 static GstCaps *
444 theora_set_header_on_caps (GstCaps * caps, GstBuffer * buf1,
445     GstBuffer * buf2, GstBuffer * buf3)
446 {
447   GstStructure *structure;
448   GValue list = { 0 };
449   GValue value = { 0 };
450
451   caps = gst_caps_make_writable (caps);
452   structure = gst_caps_get_structure (caps, 0);
453
454   /* mark buffers */
455   GST_BUFFER_FLAG_SET (buf1, GST_BUFFER_FLAG_IN_CAPS);
456   GST_BUFFER_FLAG_SET (buf2, GST_BUFFER_FLAG_IN_CAPS);
457   GST_BUFFER_FLAG_SET (buf3, GST_BUFFER_FLAG_IN_CAPS);
458
459   /* put buffers in a fixed list */
460   g_value_init (&list, GST_TYPE_ARRAY);
461   g_value_init (&value, GST_TYPE_BUFFER);
462   gst_value_set_buffer (&value, buf1);
463   gst_value_list_append_value (&list, &value);
464   g_value_unset (&value);
465   g_value_init (&value, GST_TYPE_BUFFER);
466   gst_value_set_buffer (&value, buf2);
467   gst_value_list_append_value (&list, &value);
468   g_value_unset (&value);
469   g_value_init (&value, GST_TYPE_BUFFER);
470   gst_value_set_buffer (&value, buf3);
471   gst_value_list_append_value (&list, &value);
472   gst_structure_set_value (structure, "streamheader", &list);
473   g_value_unset (&value);
474   g_value_unset (&list);
475
476   return caps;
477 }
478
479 static gboolean
480 theora_enc_sink_event (GstPad * pad, GstEvent * event)
481 {
482   GstTheoraEnc *enc;
483   ogg_packet op;
484
485   enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
486
487   switch (GST_EVENT_TYPE (event)) {
488     case GST_EVENT_EOS:
489       /* push last packet with eos flag */
490       while (theora_encode_packetout (&enc->state, 1, &op)) {
491         GstClockTime out_time =
492             theora_granule_time (&enc->state, op.granulepos) * GST_SECOND;
493         theora_push_packet (enc, &op, out_time, GST_SECOND / enc->fps);
494       }
495     default:
496       return gst_pad_event_default (pad, event);
497   }
498 }
499
500 static GstFlowReturn
501 theora_enc_chain (GstPad * pad, GstBuffer * buffer)
502 {
503   GstTheoraEnc *enc;
504   ogg_packet op;
505   GstClockTime in_time;
506   GstFlowReturn ret;
507
508   enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
509
510   in_time = GST_BUFFER_TIMESTAMP (buffer);
511
512   /* no packets written yet, setup headers */
513   if (enc->packetno == 0) {
514     GstCaps *caps;
515     GstBuffer *buf1, *buf2, *buf3;
516
517     /* Theora streams begin with three headers; the initial header (with
518        most of the codec setup parameters) which is mandated by the Ogg
519        bitstream spec.  The second header holds any comment fields.  The
520        third header holds the bitstream codebook.  We merely need to
521        make the headers, then pass them to libtheora one at a time;
522        libtheora handles the additional Ogg bitstream constraints */
523
524     /* first packet will get its own page automatically */
525     theora_encode_header (&enc->state, &op);
526     buf1 = theora_buffer_from_packet (enc, &op, 0, 0);
527
528     /* create the remaining theora headers */
529     theora_comment_init (&enc->comment);
530     theora_encode_comment (&enc->comment, &op);
531     buf2 = theora_buffer_from_packet (enc, &op, 0, 0);
532     theora_encode_tables (&enc->state, &op);
533     buf3 = theora_buffer_from_packet (enc, &op, 0, 0);
534
535     /* mark buffers and put on caps */
536     caps = gst_pad_get_caps (enc->srcpad);
537     caps = theora_set_header_on_caps (caps, buf1, buf2, buf3);
538     GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
539     gst_pad_set_caps (enc->srcpad, caps);
540
541     gst_buffer_set_caps (buf1, caps);
542     gst_buffer_set_caps (buf2, caps);
543     gst_buffer_set_caps (buf3, caps);
544
545     /* push out the header buffers */
546     if ((ret = theora_push_buffer (enc, buf1)) != GST_FLOW_OK)
547       goto header_push;
548     if ((ret = theora_push_buffer (enc, buf2)) != GST_FLOW_OK)
549       goto header_push;
550     if ((ret = theora_push_buffer (enc, buf3)) != GST_FLOW_OK)
551       goto header_push;
552   }
553
554   {
555     yuv_buffer yuv;
556     gint res;
557     gint y_size;
558     guint8 *pixels;
559
560     yuv.y_width = enc->info_width;
561     yuv.y_height = enc->info_height;
562     yuv.y_stride = enc->info_width;
563
564     yuv.uv_width = enc->info_width / 2;
565     yuv.uv_height = enc->info_height / 2;
566     yuv.uv_stride = yuv.uv_width;
567
568     y_size = enc->info_width * enc->info_height;
569
570     if (enc->width == enc->info_width && enc->height == enc->info_height) {
571       /* easy case, no cropping/conversion needed */
572       pixels = GST_BUFFER_DATA (buffer);
573
574       yuv.y = pixels;
575       yuv.u = yuv.y + y_size;
576       yuv.v = yuv.u + y_size / 4;
577     } else {
578       GstBuffer *newbuf;
579       gint i;
580       guchar *dest_y, *src_y;
581       guchar *dest_u, *src_u;
582       guchar *dest_v, *src_v;
583       gint src_y_stride, src_uv_stride;
584       gint dst_y_stride, dst_uv_stride;
585       gint width, height;
586       gint cwidth, cheight;
587       gint offset_x, right_x, right_border;
588
589       /* source width/height */
590       width = enc->width;
591       height = enc->height;
592       /* soucre chroma width/height */
593       cwidth = width / 2;
594       cheight = height / 2;
595
596       /* source strides as defined in videotestsrc */
597       src_y_stride = ROUND_UP_4 (width);
598       src_uv_stride = ROUND_UP_8 (width) / 2;
599
600       /* destination strides from the real picture width */
601       dst_y_stride = enc->info_width;
602       dst_uv_stride = enc->info_width / 2;
603
604       ret = gst_pad_alloc_buffer (enc->srcpad,
605           GST_BUFFER_OFFSET_NONE, y_size * 3 / 2, GST_PAD_CAPS (enc->srcpad),
606           &newbuf);
607       if (ret != GST_FLOW_OK)
608         goto no_buffer;
609
610       dest_y = yuv.y = GST_BUFFER_DATA (newbuf);
611       dest_u = yuv.u = yuv.y + y_size;
612       dest_v = yuv.v = yuv.u + y_size / 4;
613
614       src_y = GST_BUFFER_DATA (buffer);
615       src_u = src_y + src_y_stride * ROUND_UP_2 (height);
616       src_v = src_u + src_uv_stride * ROUND_UP_2 (height) / 2;
617
618       if (enc->border != BORDER_NONE) {
619         /* fill top border */
620         for (i = 0; i < enc->offset_y; i++) {
621           memset (dest_y, 0, dst_y_stride);
622           dest_y += dst_y_stride;
623         }
624       } else {
625         dest_y += dst_y_stride * enc->offset_y;
626       }
627
628       offset_x = enc->offset_x;
629       right_x = width + enc->offset_x;
630       right_border = dst_y_stride - right_x;
631
632       /* copy Y plane */
633       for (i = 0; i < height; i++) {
634         memcpy (dest_y + offset_x, src_y, width);
635         if (enc->border != BORDER_NONE) {
636           memset (dest_y, 0, offset_x);
637           memset (dest_y + right_x, 0, right_border);
638         }
639
640         dest_y += dst_y_stride;
641         src_y += src_y_stride;
642       }
643
644       if (enc->border != BORDER_NONE) {
645         /* fill bottom border */
646         for (i = height + enc->offset_y; i < enc->info.height; i++) {
647           memset (dest_y, 0, dst_y_stride);
648           dest_y += dst_y_stride;
649         }
650
651         /* fill top border chroma */
652         for (i = 0; i < enc->offset_y / 2; i++) {
653           memset (dest_u, 128, dst_uv_stride);
654           memset (dest_v, 128, dst_uv_stride);
655           dest_u += dst_uv_stride;
656           dest_v += dst_uv_stride;
657         }
658       } else {
659         dest_u += dst_uv_stride * enc->offset_y / 2;
660         dest_v += dst_uv_stride * enc->offset_y / 2;
661       }
662
663       offset_x = enc->offset_x / 2;
664       right_x = cwidth + offset_x;
665       right_border = dst_uv_stride - right_x;
666
667       /* copy UV planes */
668       for (i = 0; i < cheight; i++) {
669         memcpy (dest_v + offset_x, src_v, cwidth);
670         memcpy (dest_u + offset_x, src_u, cwidth);
671
672         if (enc->border != BORDER_NONE) {
673           memset (dest_u, 128, offset_x);
674           memset (dest_u + right_x, 128, right_border);
675           memset (dest_v, 128, offset_x);
676           memset (dest_v + right_x, 128, right_border);
677         }
678
679         dest_u += dst_uv_stride;
680         dest_v += dst_uv_stride;
681         src_u += src_uv_stride;
682         src_v += src_uv_stride;
683       }
684
685       if (enc->border != BORDER_NONE) {
686         /* fill bottom border */
687         for (i = cheight + enc->offset_y / 2; i < enc->info_height / 2; i++) {
688           memset (dest_u, 128, dst_uv_stride);
689           memset (dest_v, 128, dst_uv_stride);
690           dest_u += dst_uv_stride;
691           dest_v += dst_uv_stride;
692         }
693       }
694
695       gst_buffer_unref (buffer);
696       buffer = newbuf;
697     }
698
699     res = theora_encode_YUVin (&enc->state, &yuv);
700
701     ret = GST_FLOW_OK;
702     while (theora_encode_packetout (&enc->state, 0, &op)) {
703       GstClockTime out_time;
704
705       out_time = theora_granule_time (&enc->state, op.granulepos) * GST_SECOND;
706       if ((ret = theora_push_packet (enc, &op, out_time, GST_SECOND / enc->fps))
707           != GST_FLOW_OK)
708         goto data_push;
709     }
710     gst_buffer_unref (buffer);
711   }
712
713   return ret;
714
715   /* ERRORS */
716 header_push:
717   {
718     gst_buffer_unref (buffer);
719     return ret;
720   }
721 no_buffer:
722   {
723     gst_buffer_unref (buffer);
724     return ret;
725   }
726 data_push:
727   {
728     gst_buffer_unref (buffer);
729     return ret;
730   }
731 }
732
733 static GstStateChangeReturn
734 theora_enc_change_state (GstElement * element, GstStateChange transition)
735 {
736   GstTheoraEnc *enc;
737   GstStateChangeReturn ret;
738
739   enc = GST_THEORA_ENC (element);
740
741   switch (transition) {
742     case GST_STATE_CHANGE_NULL_TO_READY:
743       break;
744     case GST_STATE_CHANGE_READY_TO_PAUSED:
745       theora_info_init (&enc->info);
746       theora_comment_init (&enc->comment);
747       enc->packetno = 0;
748       enc->initial_delay = 0;
749       break;
750     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
751       break;
752     default:
753       break;
754   }
755
756   ret = parent_class->change_state (element, transition);
757
758   switch (transition) {
759     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
760       break;
761     case GST_STATE_CHANGE_PAUSED_TO_READY:
762       GST_STREAM_LOCK (enc->sinkpad);
763       theora_clear (&enc->state);
764       theora_comment_clear (&enc->comment);
765       theora_info_clear (&enc->info);
766       GST_STREAM_UNLOCK (enc->sinkpad);
767       break;
768     case GST_STATE_CHANGE_READY_TO_NULL:
769       break;
770     default:
771       break;
772   }
773
774   return ret;
775 }
776
777 static void
778 theora_enc_set_property (GObject * object, guint prop_id,
779     const GValue * value, GParamSpec * pspec)
780 {
781   GstTheoraEnc *enc = GST_THEORA_ENC (object);
782
783   switch (prop_id) {
784     case ARG_CENTER:
785       enc->center = g_value_get_boolean (value);
786       break;
787     case ARG_BORDER:
788       enc->border = g_value_get_enum (value);
789       break;
790     case ARG_BITRATE:
791       enc->video_bitrate = g_value_get_int (value) * 1000;
792       enc->video_quality = 0;
793       break;
794     case ARG_QUALITY:
795       enc->video_quality = g_value_get_int (value);
796       enc->video_bitrate = 0;
797       break;
798     case ARG_QUICK:
799       enc->quick = g_value_get_boolean (value);
800       break;
801     case ARG_KEYFRAME_AUTO:
802       enc->keyframe_auto = g_value_get_boolean (value);
803       break;
804     case ARG_KEYFRAME_FREQ:
805       enc->keyframe_freq = g_value_get_int (value);
806       break;
807     case ARG_KEYFRAME_FREQ_FORCE:
808       enc->keyframe_force = g_value_get_int (value);
809       break;
810     case ARG_KEYFRAME_THRESHOLD:
811       enc->keyframe_threshold = g_value_get_int (value);
812       break;
813     case ARG_KEYFRAME_MINDISTANCE:
814       enc->keyframe_mindistance = g_value_get_int (value);
815       break;
816     case ARG_NOISE_SENSITIVITY:
817       enc->noise_sensitivity = g_value_get_int (value);
818       break;
819     case ARG_SHARPNESS:
820       enc->sharpness = g_value_get_int (value);
821       break;
822     default:
823       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
824       break;
825   }
826 }
827
828 static void
829 theora_enc_get_property (GObject * object, guint prop_id,
830     GValue * value, GParamSpec * pspec)
831 {
832   GstTheoraEnc *enc = GST_THEORA_ENC (object);
833
834   switch (prop_id) {
835     case ARG_CENTER:
836       g_value_set_boolean (value, enc->center);
837       break;
838     case ARG_BORDER:
839       g_value_set_enum (value, enc->border);
840       break;
841     case ARG_BITRATE:
842       g_value_set_int (value, enc->video_bitrate / 1000);
843       break;
844     case ARG_QUALITY:
845       g_value_set_int (value, enc->video_quality);
846       break;
847     case ARG_QUICK:
848       g_value_set_boolean (value, enc->quick);
849       break;
850     case ARG_KEYFRAME_AUTO:
851       g_value_set_boolean (value, enc->keyframe_auto);
852       break;
853     case ARG_KEYFRAME_FREQ:
854       g_value_set_int (value, enc->keyframe_freq);
855       break;
856     case ARG_KEYFRAME_FREQ_FORCE:
857       g_value_set_int (value, enc->keyframe_force);
858       break;
859     case ARG_KEYFRAME_THRESHOLD:
860       g_value_set_int (value, enc->keyframe_threshold);
861       break;
862     case ARG_KEYFRAME_MINDISTANCE:
863       g_value_set_int (value, enc->keyframe_mindistance);
864       break;
865     case ARG_NOISE_SENSITIVITY:
866       g_value_set_int (value, enc->noise_sensitivity);
867       break;
868     case ARG_SHARPNESS:
869       g_value_set_int (value, enc->sharpness);
870       break;
871     default:
872       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
873       break;
874   }
875 }