gst_plugins_base/ext/theora/theoraenc.c
changeset 0 0e761a78d257
equal deleted inserted replaced
-1:000000000000 0:0e761a78d257
       
     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  * <para>
       
    32  * The theora codec internally only supports encoding of images that are a
       
    33  * multiple of 16 pixels in both X and Y direction. It is however perfectly
       
    34  * possible to encode images with other dimensions because an arbitrary
       
    35  * rectangular cropping region can be set up. This element will automatically
       
    36  * set up a correct cropping region if the dimensions are not multiples of 16
       
    37  * pixels. The "border" and "center" properties control how this cropping
       
    38  * region will be set up.
       
    39  * </para>
       
    40  * <para>
       
    41  * To control the quality of the encoding, the "bitrate" and "quality"
       
    42  * properties can be used. These two properties are mutualy exclusive. Setting
       
    43  * the bitrate property will produce a constant bitrate (CBR) stream while
       
    44  * setting the quality property will produce a variable bitrate (VBR) stream.
       
    45  * </para>
       
    46  * <title>Example pipeline</title>
       
    47  * <programlisting>
       
    48  * gst-launch -v videotestsrc num-buffers=1000 ! theoraenc ! oggmux ! filesink location=videotestsrc.ogg
       
    49  * </programlisting>
       
    50  * This example pipeline will encode a test video source to theora muxed in an
       
    51  * ogg container. Refer to the theoradec documentation to decode the create
       
    52  * stream.
       
    53  * </refsect2>
       
    54  *
       
    55  * Last reviewed on 2006-03-01 (0.10.4)
       
    56  */
       
    57 
       
    58 #ifdef HAVE_CONFIG_H
       
    59 #  include "config.h"
       
    60 #endif
       
    61 
       
    62 #include "gsttheoraenc.h"
       
    63 
       
    64 #include <string.h>
       
    65 #include <stdlib.h>             /* free */
       
    66 
       
    67 #include <gst/tag/tag.h>
       
    68 
       
    69 #define GST_CAT_DEFAULT theoraenc_debug
       
    70 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
       
    71 
       
    72 /* With libtheora-1.0beta1 the granulepos scheme was changed:
       
    73  * where earlier the granulepos refered to the index/beginning
       
    74  * of a frame, it now refers to the end, which matches the use
       
    75  * in vorbis/speex. There don't seem to be defines for the
       
    76  * theora version we're compiling against, so we'll just use
       
    77  * a run-time check for now. See theora_enc_get_ogg_packet_end_time().
       
    78  */
       
    79 static gboolean use_old_granulepos;
       
    80 
       
    81 #define GST_TYPE_BORDER_MODE (gst_border_mode_get_type())
       
    82 static GType
       
    83 gst_border_mode_get_type (void)
       
    84 {
       
    85   static GType border_mode_type = 0;
       
    86   static const GEnumValue border_mode[] = {
       
    87     {BORDER_NONE, "No Border", "none"},
       
    88     {BORDER_BLACK, "Black Border", "black"},
       
    89     {BORDER_MIRROR, "Mirror image in borders", "mirror"},
       
    90     {0, NULL, NULL},
       
    91   };
       
    92 
       
    93   if (!border_mode_type) {
       
    94     border_mode_type =
       
    95         g_enum_register_static ("GstTheoraEncBorderMode", border_mode);
       
    96   }
       
    97   return border_mode_type;
       
    98 }
       
    99 
       
   100 /* taken from theora/lib/toplevel.c */
       
   101 static int
       
   102 _ilog (unsigned int v)
       
   103 {
       
   104   int ret = 0;
       
   105 
       
   106   while (v) {
       
   107     ret++;
       
   108     v >>= 1;
       
   109   }
       
   110   return (ret);
       
   111 }
       
   112 
       
   113 #define THEORA_DEF_CENTER               TRUE
       
   114 #define THEORA_DEF_BORDER               BORDER_BLACK
       
   115 #define THEORA_DEF_BITRATE              0
       
   116 #define THEORA_DEF_QUALITY              16
       
   117 #define THEORA_DEF_QUICK                TRUE
       
   118 #define THEORA_DEF_KEYFRAME_AUTO        TRUE
       
   119 #define THEORA_DEF_KEYFRAME_FREQ        64
       
   120 #define THEORA_DEF_KEYFRAME_FREQ_FORCE  64
       
   121 #define THEORA_DEF_KEYFRAME_THRESHOLD   80
       
   122 #define THEORA_DEF_KEYFRAME_MINDISTANCE 8
       
   123 #define THEORA_DEF_NOISE_SENSITIVITY    1
       
   124 #define THEORA_DEF_SHARPNESS            0
       
   125 enum
       
   126 {
       
   127   ARG_0,
       
   128   ARG_CENTER,
       
   129   ARG_BORDER,
       
   130   ARG_BITRATE,
       
   131   ARG_QUALITY,
       
   132   ARG_QUICK,
       
   133   ARG_KEYFRAME_AUTO,
       
   134   ARG_KEYFRAME_FREQ,
       
   135   ARG_KEYFRAME_FREQ_FORCE,
       
   136   ARG_KEYFRAME_THRESHOLD,
       
   137   ARG_KEYFRAME_MINDISTANCE,
       
   138   ARG_NOISE_SENSITIVITY,
       
   139   ARG_SHARPNESS,
       
   140   /* FILL ME */
       
   141 };
       
   142 
       
   143 /* this function does a straight granulepos -> timestamp conversion */
       
   144 static GstClockTime
       
   145 granulepos_to_timestamp (GstTheoraEnc * theoraenc, ogg_int64_t granulepos)
       
   146 {
       
   147   guint64 iframe, pframe;
       
   148   int shift = theoraenc->granule_shift;
       
   149 
       
   150   if (granulepos < 0)
       
   151     return GST_CLOCK_TIME_NONE;
       
   152 
       
   153   iframe = granulepos >> shift;
       
   154   pframe = granulepos - (iframe << shift);
       
   155 
       
   156   /* num and den are 32 bit, so we can safely multiply with GST_SECOND */
       
   157   return gst_util_uint64_scale ((guint64) (iframe + pframe),
       
   158       GST_SECOND * theoraenc->info.fps_denominator,
       
   159       theoraenc->info.fps_numerator);
       
   160 }
       
   161 
       
   162 static const GstElementDetails theora_enc_details =
       
   163 GST_ELEMENT_DETAILS ("Theora video encoder",
       
   164     "Codec/Encoder/Video",
       
   165     "encode raw YUV video to a theora stream",
       
   166     "Wim Taymans <wim@fluendo.com>");
       
   167 
       
   168 static GstStaticPadTemplate theora_enc_sink_factory =
       
   169 GST_STATIC_PAD_TEMPLATE ("sink",
       
   170     GST_PAD_SINK,
       
   171     GST_PAD_ALWAYS,
       
   172     GST_STATIC_CAPS ("video/x-raw-yuv, "
       
   173         "format = (fourcc) I420, "
       
   174         "framerate = (fraction) [0/1, MAX], "
       
   175         "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
       
   176     );
       
   177 
       
   178 static GstStaticPadTemplate theora_enc_src_factory =
       
   179 GST_STATIC_PAD_TEMPLATE ("src",
       
   180     GST_PAD_SRC,
       
   181     GST_PAD_ALWAYS,
       
   182     GST_STATIC_CAPS ("video/x-theora")
       
   183     );
       
   184 
       
   185 GST_BOILERPLATE (GstTheoraEnc, gst_theora_enc, GstElement, GST_TYPE_ELEMENT);
       
   186 
       
   187 static gboolean theora_enc_sink_event (GstPad * pad, GstEvent * event);
       
   188 static GstFlowReturn theora_enc_chain (GstPad * pad, GstBuffer * buffer);
       
   189 static GstStateChangeReturn theora_enc_change_state (GstElement * element,
       
   190     GstStateChange transition);
       
   191 static gboolean theora_enc_sink_setcaps (GstPad * pad, GstCaps * caps);
       
   192 static void theora_enc_get_property (GObject * object, guint prop_id,
       
   193     GValue * value, GParamSpec * pspec);
       
   194 static void theora_enc_set_property (GObject * object, guint prop_id,
       
   195     const GValue * value, GParamSpec * pspec);
       
   196 static void theora_enc_finalize (GObject * object);
       
   197 
       
   198 static void
       
   199 gst_theora_enc_base_init (gpointer g_class)
       
   200 {
       
   201   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
       
   202 
       
   203   gst_element_class_add_pad_template (element_class,
       
   204       gst_static_pad_template_get (&theora_enc_src_factory));
       
   205   gst_element_class_add_pad_template (element_class,
       
   206       gst_static_pad_template_get (&theora_enc_sink_factory));
       
   207   gst_element_class_set_details (element_class, &theora_enc_details);
       
   208 }
       
   209 
       
   210 static void
       
   211 gst_theora_enc_class_init (GstTheoraEncClass * klass)
       
   212 {
       
   213   GObjectClass *gobject_class = (GObjectClass *) klass;
       
   214   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
       
   215 
       
   216   gobject_class->set_property = theora_enc_set_property;
       
   217   gobject_class->get_property = theora_enc_get_property;
       
   218   gobject_class->finalize = theora_enc_finalize;
       
   219 
       
   220   g_object_class_install_property (gobject_class, ARG_CENTER,
       
   221       g_param_spec_boolean ("center", "Center",
       
   222           "Center image when sizes not multiple of 16", THEORA_DEF_CENTER,
       
   223           (GParamFlags) G_PARAM_READWRITE));
       
   224   g_object_class_install_property (gobject_class, ARG_BORDER,
       
   225       g_param_spec_enum ("border", "Border",
       
   226           "Border color to add when sizes not multiple of 16",
       
   227           GST_TYPE_BORDER_MODE, THEORA_DEF_BORDER,
       
   228           (GParamFlags) G_PARAM_READWRITE));
       
   229   /* general encoding stream options */
       
   230   g_object_class_install_property (gobject_class, ARG_BITRATE,
       
   231       g_param_spec_int ("bitrate", "Bitrate", "Compressed video bitrate (kbps)",
       
   232           0, 2000, THEORA_DEF_BITRATE, (GParamFlags) G_PARAM_READWRITE));
       
   233   g_object_class_install_property (gobject_class, ARG_QUALITY,
       
   234       g_param_spec_int ("quality", "Quality", "Video quality",
       
   235           0, 63, THEORA_DEF_QUALITY, (GParamFlags) G_PARAM_READWRITE));
       
   236   g_object_class_install_property (gobject_class, ARG_QUICK,
       
   237       g_param_spec_boolean ("quick", "Quick", "Quick encoding",
       
   238           THEORA_DEF_QUICK, (GParamFlags) G_PARAM_READWRITE));
       
   239   g_object_class_install_property (gobject_class, ARG_KEYFRAME_AUTO,
       
   240       g_param_spec_boolean ("keyframe-auto", "Keyframe Auto",
       
   241           "Automatic keyframe detection", THEORA_DEF_KEYFRAME_AUTO,
       
   242           (GParamFlags) G_PARAM_READWRITE));
       
   243   g_object_class_install_property (gobject_class, ARG_KEYFRAME_FREQ,
       
   244       g_param_spec_int ("keyframe-freq", "Keyframe frequency",
       
   245           "Keyframe frequency", 1, 32768, THEORA_DEF_KEYFRAME_FREQ,
       
   246           (GParamFlags) G_PARAM_READWRITE));
       
   247   g_object_class_install_property (gobject_class, ARG_KEYFRAME_FREQ_FORCE,
       
   248       g_param_spec_int ("keyframe-force", "Keyframe force",
       
   249           "Force keyframe every N frames", 1, 32768,
       
   250           THEORA_DEF_KEYFRAME_FREQ_FORCE, (GParamFlags) G_PARAM_READWRITE));
       
   251   g_object_class_install_property (gobject_class, ARG_KEYFRAME_THRESHOLD,
       
   252       g_param_spec_int ("keyframe-threshold", "Keyframe threshold",
       
   253           "Keyframe threshold", 0, 32768, THEORA_DEF_KEYFRAME_THRESHOLD,
       
   254           (GParamFlags) G_PARAM_READWRITE));
       
   255   g_object_class_install_property (gobject_class, ARG_KEYFRAME_MINDISTANCE,
       
   256       g_param_spec_int ("keyframe-mindistance", "Keyframe mindistance",
       
   257           "Keyframe mindistance", 1, 32768, THEORA_DEF_KEYFRAME_MINDISTANCE,
       
   258           (GParamFlags) G_PARAM_READWRITE));
       
   259   g_object_class_install_property (gobject_class, ARG_NOISE_SENSITIVITY,
       
   260       g_param_spec_int ("noise-sensitivity", "Noise sensitivity",
       
   261           "Noise sensitivity", 0, 32768, THEORA_DEF_NOISE_SENSITIVITY,
       
   262           (GParamFlags) G_PARAM_READWRITE));
       
   263   g_object_class_install_property (gobject_class, ARG_SHARPNESS,
       
   264       g_param_spec_int ("sharpness", "Sharpness",
       
   265           "Sharpness", 0, 2, THEORA_DEF_SHARPNESS,
       
   266           (GParamFlags) G_PARAM_READWRITE));
       
   267 
       
   268   gstelement_class->change_state = theora_enc_change_state;
       
   269   GST_DEBUG_CATEGORY_INIT (theoraenc_debug, "theoraenc", 0, "Theora encoder");
       
   270 
       
   271   use_old_granulepos = (theora_version_number () <= 0x00030200);
       
   272 }
       
   273 
       
   274 static void
       
   275 gst_theora_enc_init (GstTheoraEnc * enc, GstTheoraEncClass * g_class)
       
   276 {
       
   277   enc->sinkpad =
       
   278       gst_pad_new_from_static_template (&theora_enc_sink_factory, "sink");
       
   279   gst_pad_set_chain_function (enc->sinkpad, theora_enc_chain);
       
   280   gst_pad_set_event_function (enc->sinkpad, theora_enc_sink_event);
       
   281   gst_pad_set_setcaps_function (enc->sinkpad, theora_enc_sink_setcaps);
       
   282   gst_element_add_pad (GST_ELEMENT (enc), enc->sinkpad);
       
   283 
       
   284   enc->srcpad =
       
   285       gst_pad_new_from_static_template (&theora_enc_src_factory, "src");
       
   286   gst_element_add_pad (GST_ELEMENT (enc), enc->srcpad);
       
   287 
       
   288   enc->center = THEORA_DEF_CENTER;
       
   289   enc->border = THEORA_DEF_BORDER;
       
   290 
       
   291   enc->video_bitrate = THEORA_DEF_BITRATE;
       
   292   enc->video_quality = THEORA_DEF_QUALITY;
       
   293   enc->quick = THEORA_DEF_QUICK;
       
   294   enc->keyframe_auto = THEORA_DEF_KEYFRAME_AUTO;
       
   295   enc->keyframe_freq = THEORA_DEF_KEYFRAME_FREQ;
       
   296   enc->keyframe_force = THEORA_DEF_KEYFRAME_FREQ_FORCE;
       
   297   enc->keyframe_threshold = THEORA_DEF_KEYFRAME_THRESHOLD;
       
   298   enc->keyframe_mindistance = THEORA_DEF_KEYFRAME_MINDISTANCE;
       
   299   enc->noise_sensitivity = THEORA_DEF_NOISE_SENSITIVITY;
       
   300   enc->sharpness = THEORA_DEF_SHARPNESS;
       
   301 
       
   302   enc->granule_shift = _ilog (enc->info.keyframe_frequency_force - 1);
       
   303   GST_DEBUG_OBJECT (enc,
       
   304       "keyframe_frequency_force is %d, granule shift is %d",
       
   305       enc->info.keyframe_frequency_force, enc->granule_shift);
       
   306   enc->expected_ts = GST_CLOCK_TIME_NONE;
       
   307 }
       
   308 
       
   309 static void
       
   310 theora_enc_finalize (GObject * object)
       
   311 {
       
   312   GstTheoraEnc *enc = GST_THEORA_ENC (object);
       
   313 
       
   314   GST_DEBUG_OBJECT (enc, "Finalizing");
       
   315   theora_clear (&enc->state);
       
   316   theora_comment_clear (&enc->comment);
       
   317   theora_info_clear (&enc->info);
       
   318 
       
   319   G_OBJECT_CLASS (parent_class)->finalize (object);
       
   320 }
       
   321 
       
   322 static void
       
   323 theora_enc_reset (GstTheoraEnc * enc)
       
   324 {
       
   325   theora_clear (&enc->state);
       
   326   theora_encode_init (&enc->state, &enc->info);
       
   327 }
       
   328 
       
   329 static void
       
   330 theora_enc_clear (GstTheoraEnc * enc)
       
   331 {
       
   332   enc->packetno = 0;
       
   333   enc->bytes_out = 0;
       
   334   enc->granulepos_offset = 0;
       
   335   enc->timestamp_offset = 0;
       
   336 
       
   337   enc->next_ts = GST_CLOCK_TIME_NONE;
       
   338   enc->next_discont = FALSE;
       
   339   enc->expected_ts = GST_CLOCK_TIME_NONE;
       
   340 }
       
   341 
       
   342 static gboolean
       
   343 theora_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
       
   344 {
       
   345   GstStructure *structure = gst_caps_get_structure (caps, 0);
       
   346   GstTheoraEnc *enc = GST_THEORA_ENC (gst_pad_get_parent (pad));
       
   347   const GValue *par;
       
   348   gint fps_n, fps_d;
       
   349 
       
   350   gst_structure_get_int (structure, "width", &enc->width);
       
   351   gst_structure_get_int (structure, "height", &enc->height);
       
   352   gst_structure_get_fraction (structure, "framerate", &fps_n, &fps_d);
       
   353   par = gst_structure_get_value (structure, "pixel-aspect-ratio");
       
   354 
       
   355   theora_info_clear (&enc->info);
       
   356   theora_info_init (&enc->info);
       
   357   /* Theora has a divisible-by-sixteen restriction for the encoded video size but
       
   358    * we can define a visible area using the frame_width/frame_height */
       
   359   enc->info_width = enc->info.width = (enc->width + 15) & ~15;
       
   360   enc->info_height = enc->info.height = (enc->height + 15) & ~15;
       
   361   enc->info.frame_width = enc->width;
       
   362   enc->info.frame_height = enc->height;
       
   363 
       
   364   /* center image if needed */
       
   365   if (enc->center) {
       
   366     /* make sure offset is even, for easier decoding */
       
   367     enc->offset_x = GST_ROUND_UP_2 ((enc->info_width - enc->width) / 2);
       
   368     enc->offset_y = GST_ROUND_UP_2 ((enc->info_height - enc->height) / 2);
       
   369   } else {
       
   370     enc->offset_x = 0;
       
   371     enc->offset_y = 0;
       
   372   }
       
   373   enc->info.offset_x = enc->offset_x;
       
   374   enc->info.offset_y = enc->offset_y;
       
   375 
       
   376   enc->info.fps_numerator = enc->fps_n = fps_n;
       
   377   enc->info.fps_denominator = enc->fps_d = fps_d;
       
   378   if (par) {
       
   379     enc->info.aspect_numerator = gst_value_get_fraction_numerator (par);
       
   380     enc->info.aspect_denominator = gst_value_get_fraction_denominator (par);
       
   381   } else {
       
   382     /* setting them to 0 indicates that the decoder can chose a good aspect
       
   383      * ratio, defaulting to 1/1 */
       
   384     enc->info.aspect_numerator = 0;
       
   385     enc->info.aspect_denominator = 0;
       
   386   }
       
   387 
       
   388   enc->info.colorspace = OC_CS_UNSPECIFIED;
       
   389   enc->info.target_bitrate = enc->video_bitrate;
       
   390   enc->info.quality = enc->video_quality;
       
   391 
       
   392   enc->info.dropframes_p = 0;
       
   393   enc->info.quick_p = (enc->quick ? 1 : 0);
       
   394   enc->info.keyframe_auto_p = (enc->keyframe_auto ? 1 : 0);
       
   395   enc->info.keyframe_frequency = enc->keyframe_freq;
       
   396   enc->info.keyframe_frequency_force = enc->keyframe_force;
       
   397   enc->info.keyframe_data_target_bitrate = enc->video_bitrate * 1.5;
       
   398   enc->info.keyframe_auto_threshold = enc->keyframe_threshold;
       
   399   enc->info.keyframe_mindistance = enc->keyframe_mindistance;
       
   400   enc->info.noise_sensitivity = enc->noise_sensitivity;
       
   401   enc->info.sharpness = enc->sharpness;
       
   402 
       
   403   /* as done in theora */
       
   404   enc->granule_shift = _ilog (enc->info.keyframe_frequency_force - 1);
       
   405   GST_DEBUG_OBJECT (enc,
       
   406       "keyframe_frequency_force is %d, granule shift is %d",
       
   407       enc->info.keyframe_frequency_force, enc->granule_shift);
       
   408 
       
   409   theora_enc_reset (enc);
       
   410   enc->initialised = TRUE;
       
   411 
       
   412   gst_object_unref (enc);
       
   413 
       
   414   return TRUE;
       
   415 }
       
   416 
       
   417 static guint64
       
   418 granulepos_add (guint64 granulepos, guint64 addend, gint shift)
       
   419 {
       
   420   guint64 iframe, pframe;
       
   421 
       
   422   iframe = granulepos >> shift;
       
   423   pframe = granulepos - (iframe << shift);
       
   424   iframe += addend;
       
   425 
       
   426   return (iframe << shift) + pframe;
       
   427 }
       
   428 
       
   429 /* prepare a buffer for transmission by passing data through libtheora */
       
   430 static GstFlowReturn
       
   431 theora_buffer_from_packet (GstTheoraEnc * enc, ogg_packet * packet,
       
   432     GstClockTime timestamp, GstClockTime duration, GstBuffer ** buffer)
       
   433 {
       
   434   GstBuffer *buf;
       
   435   GstFlowReturn ret = GST_FLOW_OK;
       
   436 
       
   437   buf = gst_buffer_new_and_alloc (packet->bytes);
       
   438   if (!buf) {
       
   439     GST_WARNING_OBJECT (enc, "Could not allocate buffer");
       
   440     ret = GST_FLOW_ERROR;
       
   441     goto done;
       
   442   }
       
   443 
       
   444   memcpy (GST_BUFFER_DATA (buf), packet->packet, packet->bytes);
       
   445   gst_buffer_set_caps (buf, GST_PAD_CAPS (enc->srcpad));
       
   446   /* see ext/ogg/README; OFFSET_END takes "our" granulepos, OFFSET its
       
   447    * time representation */
       
   448   GST_BUFFER_OFFSET_END (buf) =
       
   449       granulepos_add (packet->granulepos, enc->granulepos_offset,
       
   450       enc->granule_shift);
       
   451   GST_BUFFER_OFFSET (buf) = granulepos_to_timestamp (enc,
       
   452       GST_BUFFER_OFFSET_END (buf));
       
   453 
       
   454   GST_BUFFER_TIMESTAMP (buf) = timestamp + enc->timestamp_offset;
       
   455   GST_BUFFER_DURATION (buf) = duration;
       
   456 
       
   457   if (enc->next_discont) {
       
   458     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
       
   459     enc->next_discont = FALSE;
       
   460   }
       
   461 
       
   462   /* the second most significant bit of the first data byte is cleared
       
   463    * for keyframes */
       
   464   if ((packet->packet[0] & 0x40) == 0) {
       
   465     GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
       
   466   } else {
       
   467     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
       
   468   }
       
   469   enc->packetno++;
       
   470 
       
   471 done:
       
   472   *buffer = buf;
       
   473   return ret;
       
   474 }
       
   475 
       
   476 /* push out the buffer and do internal bookkeeping */
       
   477 static GstFlowReturn
       
   478 theora_push_buffer (GstTheoraEnc * enc, GstBuffer * buffer)
       
   479 {
       
   480   GstFlowReturn ret;
       
   481 
       
   482   enc->bytes_out += GST_BUFFER_SIZE (buffer);
       
   483 
       
   484   ret = gst_pad_push (enc->srcpad, buffer);
       
   485 
       
   486   return ret;
       
   487 }
       
   488 
       
   489 static GstFlowReturn
       
   490 theora_push_packet (GstTheoraEnc * enc, ogg_packet * packet,
       
   491     GstClockTime timestamp, GstClockTime duration)
       
   492 {
       
   493   GstBuffer *buf;
       
   494   GstFlowReturn ret;
       
   495 
       
   496   ret = theora_buffer_from_packet (enc, packet, timestamp, duration, &buf);
       
   497   if (ret == GST_FLOW_OK)
       
   498     ret = theora_push_buffer (enc, buf);
       
   499 
       
   500   return ret;
       
   501 }
       
   502 
       
   503 static GstCaps *
       
   504 theora_set_header_on_caps (GstCaps * caps, GstBuffer * buf1,
       
   505     GstBuffer * buf2, GstBuffer * buf3)
       
   506 {
       
   507   GstStructure *structure;
       
   508   GValue array = { 0 };
       
   509   GValue value = { 0 };
       
   510 
       
   511   caps = gst_caps_make_writable (caps);
       
   512   structure = gst_caps_get_structure (caps, 0);
       
   513 
       
   514   /* mark buffers */
       
   515   GST_BUFFER_FLAG_SET (buf1, GST_BUFFER_FLAG_IN_CAPS);
       
   516   GST_BUFFER_FLAG_SET (buf2, GST_BUFFER_FLAG_IN_CAPS);
       
   517   GST_BUFFER_FLAG_SET (buf3, GST_BUFFER_FLAG_IN_CAPS);
       
   518 
       
   519   /* Copy buffers, because we can't use the originals -
       
   520    * it creates a circular refcount with the caps<->buffers */
       
   521   buf1 = gst_buffer_copy (buf1);
       
   522   buf2 = gst_buffer_copy (buf2);
       
   523   buf3 = gst_buffer_copy (buf3);
       
   524 
       
   525   /* put copies of the buffers in a fixed list */
       
   526   g_value_init (&array, GST_TYPE_ARRAY);
       
   527 
       
   528   g_value_init (&value, GST_TYPE_BUFFER);
       
   529   gst_value_set_buffer (&value, buf1);
       
   530   gst_value_array_append_value (&array, &value);
       
   531   g_value_unset (&value);
       
   532 
       
   533   g_value_init (&value, GST_TYPE_BUFFER);
       
   534   gst_value_set_buffer (&value, buf2);
       
   535   gst_value_array_append_value (&array, &value);
       
   536   g_value_unset (&value);
       
   537 
       
   538   g_value_init (&value, GST_TYPE_BUFFER);
       
   539   gst_value_set_buffer (&value, buf3);
       
   540   gst_value_array_append_value (&array, &value);
       
   541   g_value_unset (&value);
       
   542 
       
   543   gst_structure_set_value (structure, "streamheader", &array);
       
   544   g_value_unset (&array);
       
   545 
       
   546   /* Unref our copies */
       
   547   gst_buffer_unref (buf1);
       
   548   gst_buffer_unref (buf2);
       
   549   gst_buffer_unref (buf3);
       
   550 
       
   551   return caps;
       
   552 }
       
   553 
       
   554 static GstClockTime
       
   555 theora_enc_get_ogg_packet_end_time (GstTheoraEnc * enc, ogg_packet * op)
       
   556 {
       
   557   ogg_int64_t end_granule;
       
   558 
       
   559   /* FIXME: remove this hack once we depend on libtheora >= 1.0beta1 */
       
   560   if (G_UNLIKELY (use_old_granulepos)) {
       
   561     /* This is where we hack around theora's broken idea of what granulepos
       
   562      * is -- normally we wouldn't need to add the 1, because granulepos
       
   563      * should be the presentation time of the last sample in the packet, but
       
   564      * theora starts with 0 instead of 1... (update: this only applies to old
       
   565      * bitstream/theora versions, this is fixed with bitstream version 3.2.1) */
       
   566     end_granule = granulepos_add (op->granulepos, 1, enc->granule_shift);
       
   567   } else {
       
   568     end_granule = op->granulepos;
       
   569   }
       
   570   return theora_granule_time (&enc->state, end_granule) * GST_SECOND;
       
   571 }
       
   572 
       
   573 static gboolean
       
   574 theora_enc_sink_event (GstPad * pad, GstEvent * event)
       
   575 {
       
   576   GstTheoraEnc *enc;
       
   577   ogg_packet op;
       
   578   gboolean res;
       
   579 
       
   580   enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
       
   581 
       
   582   switch (GST_EVENT_TYPE (event)) {
       
   583     case GST_EVENT_EOS:
       
   584       if (enc->initialised) {
       
   585         /* push last packet with eos flag */
       
   586         while (theora_encode_packetout (&enc->state, 1, &op)) {
       
   587           GstClockTime next_time =
       
   588               theora_enc_get_ogg_packet_end_time (enc, &op);
       
   589 
       
   590           theora_push_packet (enc, &op, enc->next_ts, next_time - enc->next_ts);
       
   591           enc->next_ts = next_time;
       
   592         }
       
   593       }
       
   594       res = gst_pad_push_event (enc->srcpad, event);
       
   595       break;
       
   596     case GST_EVENT_CUSTOM_DOWNSTREAM:
       
   597     {
       
   598       const GstStructure *s;
       
   599 
       
   600       s = gst_event_get_structure (event);
       
   601 
       
   602       if (gst_structure_has_name (s, "GstForceKeyUnit")) {
       
   603         GstClockTime next_ts;
       
   604 
       
   605         /* make sure timestamps increment after resetting the decoder */
       
   606         next_ts = enc->next_ts + enc->timestamp_offset;
       
   607 
       
   608         theora_enc_reset (enc);
       
   609         enc->granulepos_offset =
       
   610             gst_util_uint64_scale (next_ts, enc->fps_n,
       
   611             GST_SECOND * enc->fps_d);
       
   612         enc->timestamp_offset = next_ts;
       
   613         enc->next_ts = 0;
       
   614       }
       
   615       res = gst_pad_push_event (enc->srcpad, event);
       
   616       break;
       
   617     }
       
   618     default:
       
   619       res = gst_pad_push_event (enc->srcpad, event);
       
   620       break;
       
   621   }
       
   622   return res;
       
   623 }
       
   624 
       
   625 static gboolean
       
   626 theora_enc_is_discontinuous (GstTheoraEnc * enc, GstBuffer * buffer)
       
   627 {
       
   628   GstClockTime ts = GST_BUFFER_TIMESTAMP (buffer);
       
   629   GstClockTimeDiff max_diff;
       
   630   gboolean ret = FALSE;
       
   631 
       
   632   /* Allow 3/4 a frame off */
       
   633   max_diff = (enc->info.fps_denominator * GST_SECOND * 3) /
       
   634       (enc->info.fps_numerator * 4);
       
   635 
       
   636   if (ts != GST_CLOCK_TIME_NONE && enc->expected_ts != GST_CLOCK_TIME_NONE) {
       
   637     if ((GstClockTimeDiff) (ts - enc->expected_ts) > max_diff) {
       
   638       GST_DEBUG_OBJECT (enc, "Incoming TS %" GST_TIME_FORMAT
       
   639           " exceeds expected value %" GST_TIME_FORMAT
       
   640           " by too much, marking discontinuity",
       
   641           GST_TIME_ARGS (ts), GST_TIME_ARGS (enc->expected_ts));
       
   642       ret = TRUE;
       
   643     }
       
   644   }
       
   645 
       
   646   if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer)))
       
   647     enc->expected_ts = ts + GST_BUFFER_DURATION (buffer);
       
   648   else
       
   649     enc->expected_ts = GST_CLOCK_TIME_NONE;
       
   650 
       
   651   return ret;
       
   652 }
       
   653 
       
   654 static GstFlowReturn
       
   655 theora_enc_chain (GstPad * pad, GstBuffer * buffer)
       
   656 {
       
   657   GstTheoraEnc *enc;
       
   658   ogg_packet op;
       
   659   GstClockTime in_time;
       
   660   GstFlowReturn ret;
       
   661 
       
   662   enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
       
   663 
       
   664   in_time = GST_BUFFER_TIMESTAMP (buffer);
       
   665 
       
   666   if (enc->packetno == 0) {
       
   667     /* no packets written yet, setup headers */
       
   668     GstCaps *caps;
       
   669     GstBuffer *buf1, *buf2, *buf3;
       
   670 
       
   671     enc->granulepos_offset = 0;
       
   672     enc->timestamp_offset = 0;
       
   673 
       
   674     GST_DEBUG_OBJECT (enc, "output headers");
       
   675     /* Theora streams begin with three headers; the initial header (with
       
   676        most of the codec setup parameters) which is mandated by the Ogg
       
   677        bitstream spec.  The second header holds any comment fields.  The
       
   678        third header holds the bitstream codebook.  We merely need to
       
   679        make the headers, then pass them to libtheora one at a time;
       
   680        libtheora handles the additional Ogg bitstream constraints */
       
   681 
       
   682     /* first packet will get its own page automatically */
       
   683     if (theora_encode_header (&enc->state, &op) != 0)
       
   684       goto encoder_disabled;
       
   685 
       
   686     ret = theora_buffer_from_packet (enc, &op, GST_CLOCK_TIME_NONE,
       
   687         GST_CLOCK_TIME_NONE, &buf1);
       
   688     if (ret != GST_FLOW_OK) {
       
   689       goto header_buffer_alloc;
       
   690     }
       
   691 
       
   692     /* create the remaining theora headers */
       
   693     theora_comment_clear (&enc->comment);
       
   694     theora_comment_init (&enc->comment);
       
   695 
       
   696     if (theora_encode_comment (&enc->comment, &op) != 0)
       
   697       goto encoder_disabled;
       
   698 
       
   699     ret = theora_buffer_from_packet (enc, &op, GST_CLOCK_TIME_NONE,
       
   700         GST_CLOCK_TIME_NONE, &buf2);
       
   701     /* Theora expects us to put this packet buffer into an ogg page,
       
   702      * in which case it becomes the ogg library's responsibility to
       
   703      * free it. Since we're copying and outputting a gst_buffer,
       
   704      * we need to free it ourselves. */
       
   705     if (op.packet)
       
   706       free (op.packet);
       
   707 
       
   708     if (ret != GST_FLOW_OK) {
       
   709       gst_buffer_unref (buf1);
       
   710       goto header_buffer_alloc;
       
   711     }
       
   712 
       
   713     if (theora_encode_tables (&enc->state, &op) != 0)
       
   714       goto encoder_disabled;
       
   715 
       
   716     ret = theora_buffer_from_packet (enc, &op, GST_CLOCK_TIME_NONE,
       
   717         GST_CLOCK_TIME_NONE, &buf3);
       
   718     if (ret != GST_FLOW_OK) {
       
   719       gst_buffer_unref (buf1);
       
   720       gst_buffer_unref (buf2);
       
   721       goto header_buffer_alloc;
       
   722     }
       
   723 
       
   724     /* mark buffers and put on caps */
       
   725     caps = gst_pad_get_caps (enc->srcpad);
       
   726     caps = theora_set_header_on_caps (caps, buf1, buf2, buf3);
       
   727     GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
       
   728     gst_pad_set_caps (enc->srcpad, caps);
       
   729 
       
   730     gst_buffer_set_caps (buf1, caps);
       
   731     gst_buffer_set_caps (buf2, caps);
       
   732     gst_buffer_set_caps (buf3, caps);
       
   733 
       
   734     gst_caps_unref (caps);
       
   735 
       
   736     /* push out the header buffers */
       
   737     if ((ret = theora_push_buffer (enc, buf1)) != GST_FLOW_OK) {
       
   738       gst_buffer_unref (buf2);
       
   739       gst_buffer_unref (buf3);
       
   740       goto header_push;
       
   741     }
       
   742     if ((ret = theora_push_buffer (enc, buf2)) != GST_FLOW_OK) {
       
   743       gst_buffer_unref (buf3);
       
   744       goto header_push;
       
   745     }
       
   746     if ((ret = theora_push_buffer (enc, buf3)) != GST_FLOW_OK) {
       
   747       goto header_push;
       
   748     }
       
   749 
       
   750     enc->granulepos_offset =
       
   751         gst_util_uint64_scale (in_time, enc->fps_n, GST_SECOND * enc->fps_d);
       
   752     enc->timestamp_offset = in_time;
       
   753     enc->next_ts = 0;
       
   754   }
       
   755 
       
   756   {
       
   757     yuv_buffer yuv;
       
   758     gint res;
       
   759     gint y_size;
       
   760     guint8 *pixels;
       
   761 
       
   762     yuv.y_width = enc->info_width;
       
   763     yuv.y_height = enc->info_height;
       
   764     yuv.y_stride = enc->info_width;
       
   765 
       
   766     yuv.uv_width = enc->info_width / 2;
       
   767     yuv.uv_height = enc->info_height / 2;
       
   768     yuv.uv_stride = yuv.uv_width;
       
   769 
       
   770     y_size = enc->info_width * enc->info_height;
       
   771 
       
   772     if (enc->width == enc->info_width && enc->height == enc->info_height) {
       
   773       GST_LOG_OBJECT (enc, "no cropping/conversion needed");
       
   774       /* easy case, no cropping/conversion needed */
       
   775       pixels = GST_BUFFER_DATA (buffer);
       
   776 
       
   777       yuv.y = pixels;
       
   778       yuv.u = yuv.y + y_size;
       
   779       yuv.v = yuv.u + y_size / 4;
       
   780     } else {
       
   781       GstBuffer *newbuf;
       
   782       gint i;
       
   783       guchar *dest_y, *src_y;
       
   784       guchar *dest_u, *src_u;
       
   785       guchar *dest_v, *src_v;
       
   786       gint src_y_stride, src_uv_stride;
       
   787       gint dst_y_stride, dst_uv_stride;
       
   788       gint width, height;
       
   789       gint cwidth, cheight;
       
   790       gint offset_x, right_x, right_border;
       
   791 
       
   792       GST_LOG_OBJECT (enc, "cropping/conversion needed for strides");
       
   793       /* source width/height */
       
   794       width = enc->width;
       
   795       height = enc->height;
       
   796       /* soucre chroma width/height */
       
   797       cwidth = width / 2;
       
   798       cheight = height / 2;
       
   799 
       
   800       /* source strides as defined in videotestsrc */
       
   801       src_y_stride = GST_ROUND_UP_4 (width);
       
   802       src_uv_stride = GST_ROUND_UP_8 (width) / 2;
       
   803 
       
   804       /* destination strides from the real picture width */
       
   805       dst_y_stride = enc->info_width;
       
   806       dst_uv_stride = enc->info_width / 2;
       
   807 
       
   808       newbuf = gst_buffer_new_and_alloc (y_size * 3 / 2);
       
   809       if (!newbuf) {
       
   810         ret = GST_FLOW_ERROR;
       
   811         goto no_buffer;
       
   812       }
       
   813       GST_BUFFER_OFFSET (newbuf) = GST_BUFFER_OFFSET_NONE;
       
   814       gst_buffer_set_caps (newbuf, GST_PAD_CAPS (enc->srcpad));
       
   815 
       
   816       dest_y = yuv.y = GST_BUFFER_DATA (newbuf);
       
   817       dest_u = yuv.u = yuv.y + y_size;
       
   818       dest_v = yuv.v = yuv.u + y_size / 4;
       
   819 
       
   820       src_y = GST_BUFFER_DATA (buffer);
       
   821       src_u = src_y + src_y_stride * GST_ROUND_UP_2 (height);
       
   822       src_v = src_u + src_uv_stride * GST_ROUND_UP_2 (height) / 2;
       
   823 
       
   824       if (enc->border != BORDER_NONE) {
       
   825         /* fill top border */
       
   826         for (i = 0; i < enc->offset_y; i++) {
       
   827           memset (dest_y, 0, dst_y_stride);
       
   828           dest_y += dst_y_stride;
       
   829         }
       
   830       } else {
       
   831         dest_y += dst_y_stride * enc->offset_y;
       
   832       }
       
   833 
       
   834       offset_x = enc->offset_x;
       
   835       right_x = width + enc->offset_x;
       
   836       right_border = dst_y_stride - right_x;
       
   837 
       
   838       /* copy Y plane */
       
   839       for (i = 0; i < height; i++) {
       
   840         memcpy (dest_y + offset_x, src_y, width);
       
   841         if (enc->border != BORDER_NONE) {
       
   842           memset (dest_y, 0, offset_x);
       
   843           memset (dest_y + right_x, 0, right_border);
       
   844         }
       
   845 
       
   846         dest_y += dst_y_stride;
       
   847         src_y += src_y_stride;
       
   848       }
       
   849 
       
   850       if (enc->border != BORDER_NONE) {
       
   851         /* fill bottom border */
       
   852         for (i = height + enc->offset_y; i < enc->info.height; i++) {
       
   853           memset (dest_y, 0, dst_y_stride);
       
   854           dest_y += dst_y_stride;
       
   855         }
       
   856 
       
   857         /* fill top border chroma */
       
   858         for (i = 0; i < enc->offset_y / 2; i++) {
       
   859           memset (dest_u, 128, dst_uv_stride);
       
   860           memset (dest_v, 128, dst_uv_stride);
       
   861           dest_u += dst_uv_stride;
       
   862           dest_v += dst_uv_stride;
       
   863         }
       
   864       } else {
       
   865         dest_u += dst_uv_stride * enc->offset_y / 2;
       
   866         dest_v += dst_uv_stride * enc->offset_y / 2;
       
   867       }
       
   868 
       
   869       offset_x = enc->offset_x / 2;
       
   870       right_x = cwidth + offset_x;
       
   871       right_border = dst_uv_stride - right_x;
       
   872 
       
   873       /* copy UV planes */
       
   874       for (i = 0; i < cheight; i++) {
       
   875         memcpy (dest_v + offset_x, src_v, cwidth);
       
   876         memcpy (dest_u + offset_x, src_u, cwidth);
       
   877 
       
   878         if (enc->border != BORDER_NONE) {
       
   879           memset (dest_u, 128, offset_x);
       
   880           memset (dest_u + right_x, 128, right_border);
       
   881           memset (dest_v, 128, offset_x);
       
   882           memset (dest_v + right_x, 128, right_border);
       
   883         }
       
   884 
       
   885         dest_u += dst_uv_stride;
       
   886         dest_v += dst_uv_stride;
       
   887         src_u += src_uv_stride;
       
   888         src_v += src_uv_stride;
       
   889       }
       
   890 
       
   891       if (enc->border != BORDER_NONE) {
       
   892         /* fill bottom border */
       
   893         for (i = cheight + enc->offset_y / 2; i < enc->info_height / 2; i++) {
       
   894           memset (dest_u, 128, dst_uv_stride);
       
   895           memset (dest_v, 128, dst_uv_stride);
       
   896           dest_u += dst_uv_stride;
       
   897           dest_v += dst_uv_stride;
       
   898         }
       
   899       }
       
   900 
       
   901       gst_buffer_unref (buffer);
       
   902       buffer = newbuf;
       
   903     }
       
   904 
       
   905     if (theora_enc_is_discontinuous (enc, buffer)) {
       
   906       theora_enc_reset (enc);
       
   907       enc->granulepos_offset =
       
   908           gst_util_uint64_scale (in_time, enc->fps_n, GST_SECOND * enc->fps_d);
       
   909       enc->timestamp_offset = in_time;
       
   910       enc->next_ts = 0;
       
   911       enc->next_discont = TRUE;
       
   912     }
       
   913 
       
   914     res = theora_encode_YUVin (&enc->state, &yuv);
       
   915 
       
   916     ret = GST_FLOW_OK;
       
   917     while (theora_encode_packetout (&enc->state, 0, &op)) {
       
   918       GstClockTime next_time = theora_enc_get_ogg_packet_end_time (enc, &op);
       
   919 
       
   920       ret =
       
   921           theora_push_packet (enc, &op, enc->next_ts, next_time - enc->next_ts);
       
   922       enc->next_ts = next_time;
       
   923       if (ret != GST_FLOW_OK)
       
   924         goto data_push;
       
   925     }
       
   926     gst_buffer_unref (buffer);
       
   927   }
       
   928 
       
   929   return ret;
       
   930 
       
   931   /* ERRORS */
       
   932 header_buffer_alloc:
       
   933   {
       
   934     gst_buffer_unref (buffer);
       
   935     return ret;
       
   936   }
       
   937 header_push:
       
   938   {
       
   939     gst_buffer_unref (buffer);
       
   940     return ret;
       
   941   }
       
   942 no_buffer:
       
   943   {
       
   944     return ret;
       
   945   }
       
   946 data_push:
       
   947   {
       
   948     gst_buffer_unref (buffer);
       
   949     return ret;
       
   950   }
       
   951 encoder_disabled:
       
   952   {
       
   953     GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL),
       
   954         ("libtheora has been compiled with the encoder disabled"));
       
   955     gst_buffer_unref (buffer);
       
   956     return GST_FLOW_ERROR;
       
   957   }
       
   958 }
       
   959 
       
   960 static GstStateChangeReturn
       
   961 theora_enc_change_state (GstElement * element, GstStateChange transition)
       
   962 {
       
   963   GstTheoraEnc *enc;
       
   964   GstStateChangeReturn ret;
       
   965 
       
   966   enc = GST_THEORA_ENC (element);
       
   967 
       
   968   switch (transition) {
       
   969     case GST_STATE_CHANGE_NULL_TO_READY:
       
   970       break;
       
   971     case GST_STATE_CHANGE_READY_TO_PAUSED:
       
   972       GST_DEBUG_OBJECT (enc, "READY->PAUSED Initing theora state");
       
   973       theora_info_init (&enc->info);
       
   974       theora_comment_init (&enc->comment);
       
   975       enc->packetno = 0;
       
   976       break;
       
   977     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
       
   978       break;
       
   979     default:
       
   980       break;
       
   981   }
       
   982 
       
   983   ret = parent_class->change_state (element, transition);
       
   984 
       
   985   switch (transition) {
       
   986     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
       
   987       break;
       
   988     case GST_STATE_CHANGE_PAUSED_TO_READY:
       
   989       GST_DEBUG_OBJECT (enc, "PAUSED->READY Clearing theora state");
       
   990       theora_clear (&enc->state);
       
   991       theora_comment_clear (&enc->comment);
       
   992       theora_info_clear (&enc->info);
       
   993 
       
   994       theora_enc_clear (enc);
       
   995       enc->initialised = FALSE;
       
   996       break;
       
   997     case GST_STATE_CHANGE_READY_TO_NULL:
       
   998       break;
       
   999     default:
       
  1000       break;
       
  1001   }
       
  1002 
       
  1003   return ret;
       
  1004 }
       
  1005 
       
  1006 static void
       
  1007 theora_enc_set_property (GObject * object, guint prop_id,
       
  1008     const GValue * value, GParamSpec * pspec)
       
  1009 {
       
  1010   GstTheoraEnc *enc = GST_THEORA_ENC (object);
       
  1011 
       
  1012   switch (prop_id) {
       
  1013     case ARG_CENTER:
       
  1014       enc->center = g_value_get_boolean (value);
       
  1015       break;
       
  1016     case ARG_BORDER:
       
  1017       enc->border = g_value_get_enum (value);
       
  1018       break;
       
  1019     case ARG_BITRATE:
       
  1020       enc->video_bitrate = g_value_get_int (value) * 1000;
       
  1021       enc->video_quality = 0;
       
  1022       break;
       
  1023     case ARG_QUALITY:
       
  1024       enc->video_quality = g_value_get_int (value);
       
  1025       enc->video_bitrate = 0;
       
  1026       break;
       
  1027     case ARG_QUICK:
       
  1028       enc->quick = g_value_get_boolean (value);
       
  1029       break;
       
  1030     case ARG_KEYFRAME_AUTO:
       
  1031       enc->keyframe_auto = g_value_get_boolean (value);
       
  1032       break;
       
  1033     case ARG_KEYFRAME_FREQ:
       
  1034       enc->keyframe_freq = g_value_get_int (value);
       
  1035       break;
       
  1036     case ARG_KEYFRAME_FREQ_FORCE:
       
  1037       enc->keyframe_force = g_value_get_int (value);
       
  1038       break;
       
  1039     case ARG_KEYFRAME_THRESHOLD:
       
  1040       enc->keyframe_threshold = g_value_get_int (value);
       
  1041       break;
       
  1042     case ARG_KEYFRAME_MINDISTANCE:
       
  1043       enc->keyframe_mindistance = g_value_get_int (value);
       
  1044       break;
       
  1045     case ARG_NOISE_SENSITIVITY:
       
  1046       enc->noise_sensitivity = g_value_get_int (value);
       
  1047       break;
       
  1048     case ARG_SHARPNESS:
       
  1049       enc->sharpness = g_value_get_int (value);
       
  1050       break;
       
  1051     default:
       
  1052       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       
  1053       break;
       
  1054   }
       
  1055 }
       
  1056 
       
  1057 static void
       
  1058 theora_enc_get_property (GObject * object, guint prop_id,
       
  1059     GValue * value, GParamSpec * pspec)
       
  1060 {
       
  1061   GstTheoraEnc *enc = GST_THEORA_ENC (object);
       
  1062 
       
  1063   switch (prop_id) {
       
  1064     case ARG_CENTER:
       
  1065       g_value_set_boolean (value, enc->center);
       
  1066       break;
       
  1067     case ARG_BORDER:
       
  1068       g_value_set_enum (value, enc->border);
       
  1069       break;
       
  1070     case ARG_BITRATE:
       
  1071       g_value_set_int (value, enc->video_bitrate / 1000);
       
  1072       break;
       
  1073     case ARG_QUALITY:
       
  1074       g_value_set_int (value, enc->video_quality);
       
  1075       break;
       
  1076     case ARG_QUICK:
       
  1077       g_value_set_boolean (value, enc->quick);
       
  1078       break;
       
  1079     case ARG_KEYFRAME_AUTO:
       
  1080       g_value_set_boolean (value, enc->keyframe_auto);
       
  1081       break;
       
  1082     case ARG_KEYFRAME_FREQ:
       
  1083       g_value_set_int (value, enc->keyframe_freq);
       
  1084       break;
       
  1085     case ARG_KEYFRAME_FREQ_FORCE:
       
  1086       g_value_set_int (value, enc->keyframe_force);
       
  1087       break;
       
  1088     case ARG_KEYFRAME_THRESHOLD:
       
  1089       g_value_set_int (value, enc->keyframe_threshold);
       
  1090       break;
       
  1091     case ARG_KEYFRAME_MINDISTANCE:
       
  1092       g_value_set_int (value, enc->keyframe_mindistance);
       
  1093       break;
       
  1094     case ARG_NOISE_SENSITIVITY:
       
  1095       g_value_set_int (value, enc->noise_sensitivity);
       
  1096       break;
       
  1097     case ARG_SHARPNESS:
       
  1098       g_value_set_int (value, enc->sharpness);
       
  1099       break;
       
  1100     default:
       
  1101       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       
  1102       break;
       
  1103   }
       
  1104 }