gst_plugins_good/ext/jpeg/gstjpegenc.c
changeset 27 d43ce56a1534
parent 23 29ecd5cb86b3
child 31 aec498aab1d3
equal deleted inserted replaced
23:29ecd5cb86b3 27:d43ce56a1534
     1 /* GStreamer
       
     2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
       
     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 #ifdef HAVE_CONFIG_H
       
    22 #include "config.h"
       
    23 #endif
       
    24 #include <string.h>
       
    25 
       
    26 #include "gstjpegenc.h"
       
    27 #include <gst/video/video.h>
       
    28 
       
    29 /* elementfactory information */
       
    30 static const GstElementDetails gst_jpegenc_details =
       
    31 GST_ELEMENT_DETAILS ("JPEG image encoder",
       
    32     "Codec/Encoder/Image",
       
    33     "Encode images in JPEG format",
       
    34     "Wim Taymans <wim.taymans@tvd.be>");
       
    35 
       
    36 GST_DEBUG_CATEGORY (jpegenc_debug);
       
    37 #define GST_CAT_DEFAULT jpegenc_debug
       
    38 
       
    39 #define JPEG_DEFAULT_QUALITY 85
       
    40 
       
    41 /* These macros are adapted from videotestsrc.c 
       
    42  *  and/or gst-plugins/gst/games/gstvideoimage.c */
       
    43 
       
    44 /* I420 */
       
    45 #define I420_Y_ROWSTRIDE(width) (GST_ROUND_UP_4(width))
       
    46 #define I420_U_ROWSTRIDE(width) (GST_ROUND_UP_8(width)/2)
       
    47 #define I420_V_ROWSTRIDE(width) ((GST_ROUND_UP_8(I420_Y_ROWSTRIDE(width)))/2)
       
    48 
       
    49 #define I420_Y_OFFSET(w,h) (0)
       
    50 #define I420_U_OFFSET(w,h) (I420_Y_OFFSET(w,h)+(I420_Y_ROWSTRIDE(w)*GST_ROUND_UP_2(h)))
       
    51 #define I420_V_OFFSET(w,h) (I420_U_OFFSET(w,h)+(I420_U_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2))
       
    52 
       
    53 #define I420_SIZE(w,h)     (I420_V_OFFSET(w,h)+(I420_V_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2))
       
    54 
       
    55 /* JpegEnc signals and args */
       
    56 enum
       
    57 {
       
    58   FRAME_ENCODED,
       
    59   /* FILL ME */
       
    60   LAST_SIGNAL
       
    61 };
       
    62 
       
    63 enum
       
    64 {
       
    65   ARG_0,
       
    66   ARG_QUALITY,
       
    67   ARG_SMOOTHING
       
    68       /* FILL ME */
       
    69 };
       
    70 
       
    71 static void gst_jpegenc_base_init (gpointer g_class);
       
    72 static void gst_jpegenc_class_init (GstJpegEnc * klass);
       
    73 static void gst_jpegenc_init (GstJpegEnc * jpegenc);
       
    74 static void gst_jpegenc_finalize (GObject * object);
       
    75 
       
    76 static GstFlowReturn gst_jpegenc_chain (GstPad * pad, GstBuffer * buf);
       
    77 static gboolean gst_jpegenc_setcaps (GstPad * pad, GstCaps * caps);
       
    78 static GstCaps *gst_jpegenc_getcaps (GstPad * pad);
       
    79 
       
    80 static void gst_jpegenc_resync (GstJpegEnc * jpegenc);
       
    81 static void gst_jpegenc_set_property (GObject * object, guint prop_id,
       
    82     const GValue * value, GParamSpec * pspec);
       
    83 static void gst_jpegenc_get_property (GObject * object, guint prop_id,
       
    84     GValue * value, GParamSpec * pspec);
       
    85 static GstStateChangeReturn gst_jpegenc_change_state (GstElement * element,
       
    86     GstStateChange transition);
       
    87 
       
    88 
       
    89 static GstElementClass *parent_class = NULL;
       
    90 static guint gst_jpegenc_signals[LAST_SIGNAL] = { 0 };
       
    91 
       
    92 GType
       
    93 gst_jpegenc_get_type (void)
       
    94 {
       
    95   static GType jpegenc_type = 0;
       
    96 
       
    97   if (!jpegenc_type) {
       
    98     static const GTypeInfo jpegenc_info = {
       
    99       sizeof (GstJpegEnc),
       
   100       (GBaseInitFunc) gst_jpegenc_base_init,
       
   101       NULL,
       
   102       (GClassInitFunc) gst_jpegenc_class_init,
       
   103       NULL,
       
   104       NULL,
       
   105       sizeof (GstJpegEnc),
       
   106       0,
       
   107       (GInstanceInitFunc) gst_jpegenc_init,
       
   108     };
       
   109 
       
   110     jpegenc_type =
       
   111         g_type_register_static (GST_TYPE_ELEMENT, "GstJpegEnc", &jpegenc_info,
       
   112         0);
       
   113   }
       
   114   return jpegenc_type;
       
   115 }
       
   116 
       
   117 static GstStaticPadTemplate gst_jpegenc_sink_pad_template =
       
   118 GST_STATIC_PAD_TEMPLATE ("sink",
       
   119     GST_PAD_SINK,
       
   120     GST_PAD_ALWAYS,
       
   121     GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420"))
       
   122     );
       
   123 
       
   124 static GstStaticPadTemplate gst_jpegenc_src_pad_template =
       
   125 GST_STATIC_PAD_TEMPLATE ("src",
       
   126     GST_PAD_SRC,
       
   127     GST_PAD_ALWAYS,
       
   128     GST_STATIC_CAPS ("image/jpeg, "
       
   129         "width = (int) [ 16, 4096 ], "
       
   130         "height = (int) [ 16, 4096 ], " "framerate = (fraction) [ 0/1, MAX ]")
       
   131     );
       
   132 
       
   133 static void
       
   134 gst_jpegenc_base_init (gpointer g_class)
       
   135 {
       
   136   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
       
   137 
       
   138   gst_element_class_add_pad_template (element_class,
       
   139       gst_static_pad_template_get (&gst_jpegenc_sink_pad_template));
       
   140   gst_element_class_add_pad_template (element_class,
       
   141       gst_static_pad_template_get (&gst_jpegenc_src_pad_template));
       
   142   gst_element_class_set_details (element_class, &gst_jpegenc_details);
       
   143 }
       
   144 
       
   145 static void
       
   146 gst_jpegenc_class_init (GstJpegEnc * klass)
       
   147 {
       
   148   GObjectClass *gobject_class;
       
   149   GstElementClass *gstelement_class;
       
   150 
       
   151   gobject_class = (GObjectClass *) klass;
       
   152   gstelement_class = (GstElementClass *) klass;
       
   153 
       
   154   parent_class = g_type_class_peek_parent (klass);
       
   155 
       
   156   gst_jpegenc_signals[FRAME_ENCODED] =
       
   157       g_signal_new ("frame-encoded", G_TYPE_FROM_CLASS (klass),
       
   158       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstJpegEncClass, frame_encoded), NULL,
       
   159       NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
       
   160 
       
   161   gobject_class->set_property = gst_jpegenc_set_property;
       
   162   gobject_class->get_property = gst_jpegenc_get_property;
       
   163 
       
   164 
       
   165   g_object_class_install_property (gobject_class, ARG_QUALITY,
       
   166       g_param_spec_int ("quality", "Quality", "Quality of encoding",
       
   167           0, 100, JPEG_DEFAULT_QUALITY, G_PARAM_READWRITE));
       
   168 #if 0
       
   169   /* disabled, since it doesn't seem to work */
       
   170   g_object_class_install_property (gobject_class, ARG_SMOOTHING,
       
   171       g_param_spec_int ("smoothing", "Smoothing", "Smoothing factor",
       
   172           0, 100, 0, G_PARAM_READWRITE));
       
   173 #endif
       
   174 
       
   175   gstelement_class->change_state = gst_jpegenc_change_state;
       
   176 
       
   177   gobject_class->finalize = gst_jpegenc_finalize;
       
   178 
       
   179   GST_DEBUG_CATEGORY_INIT (jpegenc_debug, "jpegenc", 0,
       
   180       "JPEG encoding element");
       
   181 }
       
   182 
       
   183 static void
       
   184 gst_jpegenc_init_destination (j_compress_ptr cinfo)
       
   185 {
       
   186   GST_DEBUG ("gst_jpegenc_chain: init_destination");
       
   187 }
       
   188 
       
   189 static gboolean
       
   190 gst_jpegenc_flush_destination (j_compress_ptr cinfo)
       
   191 {
       
   192   GST_DEBUG ("gst_jpegenc_chain: flush_destination: buffer too small !!!");
       
   193   return TRUE;
       
   194 }
       
   195 
       
   196 static void
       
   197 gst_jpegenc_term_destination (j_compress_ptr cinfo)
       
   198 {
       
   199   GST_DEBUG ("gst_jpegenc_chain: term_source");
       
   200 }
       
   201 
       
   202 static void
       
   203 gst_jpegenc_init (GstJpegEnc * jpegenc)
       
   204 {
       
   205   /* create the sink and src pads */
       
   206   jpegenc->sinkpad =
       
   207       gst_pad_new_from_static_template (&gst_jpegenc_sink_pad_template, "sink");
       
   208   gst_pad_set_chain_function (jpegenc->sinkpad,
       
   209       GST_DEBUG_FUNCPTR (gst_jpegenc_chain));
       
   210   gst_pad_set_getcaps_function (jpegenc->sinkpad,
       
   211       GST_DEBUG_FUNCPTR (gst_jpegenc_getcaps));
       
   212   gst_pad_set_setcaps_function (jpegenc->sinkpad,
       
   213       GST_DEBUG_FUNCPTR (gst_jpegenc_setcaps));
       
   214   gst_element_add_pad (GST_ELEMENT (jpegenc), jpegenc->sinkpad);
       
   215 
       
   216   jpegenc->srcpad =
       
   217       gst_pad_new_from_static_template (&gst_jpegenc_src_pad_template, "src");
       
   218   gst_pad_set_getcaps_function (jpegenc->sinkpad,
       
   219       GST_DEBUG_FUNCPTR (gst_jpegenc_getcaps));
       
   220   /*gst_pad_set_setcaps_function (jpegenc->sinkpad, gst_jpegenc_setcaps); */
       
   221   gst_pad_use_fixed_caps (jpegenc->sinkpad);
       
   222   gst_element_add_pad (GST_ELEMENT (jpegenc), jpegenc->srcpad);
       
   223 
       
   224   /* reset the initial video state */
       
   225   jpegenc->width = -1;
       
   226   jpegenc->height = -1;
       
   227 
       
   228   /* setup jpeglib */
       
   229   memset (&jpegenc->cinfo, 0, sizeof (jpegenc->cinfo));
       
   230   memset (&jpegenc->jerr, 0, sizeof (jpegenc->jerr));
       
   231   jpegenc->cinfo.err = jpeg_std_error (&jpegenc->jerr);
       
   232   jpeg_create_compress (&jpegenc->cinfo);
       
   233 
       
   234   jpegenc->jdest.init_destination = gst_jpegenc_init_destination;
       
   235   jpegenc->jdest.empty_output_buffer = gst_jpegenc_flush_destination;
       
   236   jpegenc->jdest.term_destination = gst_jpegenc_term_destination;
       
   237   jpegenc->cinfo.dest = &jpegenc->jdest;
       
   238 
       
   239   jpegenc->quality = JPEG_DEFAULT_QUALITY;
       
   240   jpegenc->smoothing = 0;
       
   241 }
       
   242 
       
   243 static void
       
   244 gst_jpegenc_finalize (GObject * object)
       
   245 {
       
   246 
       
   247   GstJpegEnc *filter = GST_JPEGENC (object);
       
   248 
       
   249   jpeg_destroy_compress (&filter->cinfo);
       
   250 
       
   251   G_OBJECT_CLASS (parent_class)->finalize (object);
       
   252 }
       
   253 
       
   254 static GstCaps *
       
   255 gst_jpegenc_getcaps (GstPad * pad)
       
   256 {
       
   257   GstJpegEnc *jpegenc = GST_JPEGENC (gst_pad_get_parent (pad));
       
   258   GstPad *otherpad;
       
   259   GstCaps *caps;
       
   260   const char *name;
       
   261   int i;
       
   262   GstStructure *structure = NULL;
       
   263 
       
   264   /* we want to proxy properties like width, height and framerate from the
       
   265      other end of the element */
       
   266   otherpad = (pad == jpegenc->srcpad) ? jpegenc->sinkpad : jpegenc->srcpad;
       
   267   caps = gst_pad_get_allowed_caps (otherpad);
       
   268   if (pad == jpegenc->srcpad) {
       
   269     name = "image/jpeg";
       
   270   } else {
       
   271     name = "video/x-raw-yuv";
       
   272   }
       
   273   for (i = 0; i < gst_caps_get_size (caps); i++) {
       
   274     structure = gst_caps_get_structure (caps, i);
       
   275 
       
   276     gst_structure_set_name (structure, name);
       
   277     gst_structure_remove_field (structure, "format");
       
   278     /* ... but for the sink pad, we only do I420 anyway, so add that */
       
   279     if (pad == jpegenc->sinkpad) {
       
   280       gst_structure_set (structure, "format", GST_TYPE_FOURCC,
       
   281           GST_STR_FOURCC ("I420"), NULL);
       
   282     }
       
   283   }
       
   284   gst_object_unref (jpegenc);
       
   285 
       
   286   return caps;
       
   287 }
       
   288 
       
   289 static gboolean
       
   290 gst_jpegenc_setcaps (GstPad * pad, GstCaps * caps)
       
   291 {
       
   292   GstJpegEnc *jpegenc = GST_JPEGENC (gst_pad_get_parent (pad));
       
   293   GstStructure *structure;
       
   294   GstCaps *othercaps;
       
   295   GstPad *otherpad;
       
   296   gboolean ret;
       
   297   const GValue *framerate;
       
   298 
       
   299   otherpad = (pad == jpegenc->srcpad) ? jpegenc->sinkpad : jpegenc->srcpad;
       
   300 
       
   301   structure = gst_caps_get_structure (caps, 0);
       
   302   framerate = gst_structure_get_value (structure, "framerate");
       
   303   gst_structure_get_int (structure, "width", &jpegenc->width);
       
   304   gst_structure_get_int (structure, "height", &jpegenc->height);
       
   305 
       
   306   othercaps = gst_caps_copy (gst_pad_get_pad_template_caps (otherpad));
       
   307   if (framerate) {
       
   308     gst_caps_set_simple (othercaps,
       
   309         "width", G_TYPE_INT, jpegenc->width,
       
   310         "height", G_TYPE_INT, jpegenc->height,
       
   311         "framerate", GST_TYPE_FRACTION,
       
   312         gst_value_get_fraction_numerator (framerate),
       
   313         gst_value_get_fraction_denominator (framerate), NULL);
       
   314   } else {
       
   315     gst_caps_set_simple (othercaps,
       
   316         "width", G_TYPE_INT, jpegenc->width,
       
   317         "height", G_TYPE_INT, jpegenc->height, NULL);
       
   318   }
       
   319 
       
   320   ret = gst_pad_set_caps (jpegenc->srcpad, othercaps);
       
   321   gst_caps_unref (othercaps);
       
   322 
       
   323   if (GST_PAD_LINK_SUCCESSFUL (ret)) {
       
   324     gst_jpegenc_resync (jpegenc);
       
   325   }
       
   326 
       
   327   gst_object_unref (jpegenc);
       
   328 
       
   329   return ret;
       
   330 }
       
   331 
       
   332 static void
       
   333 gst_jpegenc_resync (GstJpegEnc * jpegenc)
       
   334 {
       
   335   gint width, height;
       
   336 
       
   337   GST_DEBUG_OBJECT (jpegenc, "resync");
       
   338 
       
   339   jpegenc->cinfo.image_width = width = jpegenc->width;
       
   340   jpegenc->cinfo.image_height = height = jpegenc->height;
       
   341   jpegenc->cinfo.input_components = 3;
       
   342 
       
   343   GST_DEBUG_OBJECT (jpegenc, "width %d, height %d", width, height);
       
   344 
       
   345   jpeg_set_defaults (&jpegenc->cinfo);
       
   346   jpegenc->cinfo.dct_method = JDCT_FASTEST;
       
   347   /*jpegenc->cinfo.dct_method = JDCT_DEFAULT; */
       
   348   /*jpegenc->cinfo.smoothing_factor = jpegenc->smoothing; */
       
   349   jpeg_set_quality (&jpegenc->cinfo, jpegenc->quality, TRUE);
       
   350 
       
   351 #if 0
       
   352   switch (jpegenc->format) {
       
   353     case GST_COLORSPACE_RGB24:
       
   354       jpegenc->bufsize = jpegenc->width * jpegenc->height * 3;
       
   355       GST_DEBUG ("gst_jpegenc_resync: setting format to RGB24");
       
   356       jpegenc->cinfo.in_color_space = JCS_RGB;
       
   357       jpegenc->cinfo.raw_data_in = FALSE;
       
   358       break;
       
   359     case GST_COLORSPACE_YUV420P:
       
   360 #endif
       
   361       jpegenc->bufsize = I420_SIZE (jpegenc->width, jpegenc->height);
       
   362       jpegenc->cinfo.raw_data_in = TRUE;
       
   363       jpegenc->cinfo.in_color_space = JCS_YCbCr;
       
   364       GST_DEBUG_OBJECT (jpegenc, "setting format to YUV420P");
       
   365       jpegenc->cinfo.comp_info[0].h_samp_factor = 2;
       
   366       jpegenc->cinfo.comp_info[0].v_samp_factor = 2;
       
   367       jpegenc->cinfo.comp_info[1].h_samp_factor = 1;
       
   368       jpegenc->cinfo.comp_info[1].v_samp_factor = 1;
       
   369       jpegenc->cinfo.comp_info[2].h_samp_factor = 1;
       
   370       jpegenc->cinfo.comp_info[2].v_samp_factor = 1;
       
   371 
       
   372       if (height != -1) {
       
   373         jpegenc->line[0] =
       
   374             g_realloc (jpegenc->line[0], height * sizeof (char *));
       
   375         jpegenc->line[1] =
       
   376             g_realloc (jpegenc->line[1], height * sizeof (char *) / 2);
       
   377         jpegenc->line[2] =
       
   378             g_realloc (jpegenc->line[2], height * sizeof (char *) / 2);
       
   379       }
       
   380 
       
   381       GST_DEBUG_OBJECT (jpegenc, "setting format done");
       
   382 #if 0
       
   383       break;
       
   384     default:
       
   385       printf ("gst_jpegenc_resync: unsupported colorspace, using RGB\n");
       
   386       jpegenc->bufsize = jpegenc->width * jpegenc->height * 3;
       
   387       jpegenc->cinfo.in_color_space = JCS_RGB;
       
   388       break;
       
   389   }
       
   390 #endif
       
   391 
       
   392   jpeg_suppress_tables (&jpegenc->cinfo, TRUE);
       
   393   //jpeg_suppress_tables(&jpegenc->cinfo, FALSE);
       
   394 
       
   395   jpegenc->buffer = NULL;
       
   396   GST_DEBUG_OBJECT (jpegenc, "resync done");
       
   397 }
       
   398 
       
   399 static GstFlowReturn
       
   400 gst_jpegenc_chain (GstPad * pad, GstBuffer * buf)
       
   401 {
       
   402   GstFlowReturn ret;
       
   403   GstJpegEnc *jpegenc;
       
   404   guchar *data;
       
   405   gulong size;
       
   406   GstBuffer *outbuf;
       
   407   guint height, width;
       
   408   guchar *base[3], *end[3];
       
   409   gint i, j, k;
       
   410 
       
   411   jpegenc = GST_JPEGENC (GST_OBJECT_PARENT (pad));
       
   412 
       
   413   data = GST_BUFFER_DATA (buf);
       
   414   size = GST_BUFFER_SIZE (buf);
       
   415 
       
   416   GST_DEBUG_OBJECT (jpegenc, "got buffer of %u bytes", size);
       
   417 
       
   418   ret =
       
   419       gst_pad_alloc_buffer_and_set_caps (jpegenc->srcpad,
       
   420       GST_BUFFER_OFFSET_NONE, jpegenc->bufsize, GST_PAD_CAPS (jpegenc->srcpad),
       
   421       &outbuf);
       
   422 
       
   423   if (ret != GST_FLOW_OK)
       
   424     goto done;
       
   425 
       
   426   gst_buffer_stamp (outbuf, buf);
       
   427 
       
   428   width = jpegenc->width;
       
   429   height = jpegenc->height;
       
   430 
       
   431   base[0] = data + I420_Y_OFFSET (width, height);
       
   432   base[1] = data + I420_U_OFFSET (width, height);
       
   433   base[2] = data + I420_V_OFFSET (width, height);
       
   434 
       
   435   end[0] = base[0] + height * I420_Y_ROWSTRIDE (width);
       
   436   end[1] = base[1] + (height / 2) * I420_U_ROWSTRIDE (width);
       
   437   end[2] = base[2] + (height / 2) * I420_V_ROWSTRIDE (width);
       
   438 
       
   439   jpegenc->jdest.next_output_byte = GST_BUFFER_DATA (outbuf);
       
   440   jpegenc->jdest.free_in_buffer = GST_BUFFER_SIZE (outbuf);
       
   441 
       
   442   jpegenc->cinfo.smoothing_factor = jpegenc->smoothing;
       
   443   jpeg_set_quality (&jpegenc->cinfo, jpegenc->quality, TRUE);
       
   444   jpeg_start_compress (&jpegenc->cinfo, TRUE);
       
   445 
       
   446   GST_DEBUG_OBJECT (jpegenc, "compressing");
       
   447 
       
   448   for (i = 0; i < height; i += 2 * DCTSIZE) {
       
   449     /*g_print ("next scanline: %d\n", jpegenc->cinfo.next_scanline); */
       
   450     for (j = 0, k = 0; j < (2 * DCTSIZE); j += 2, k++) {
       
   451       jpegenc->line[0][j] = base[0];
       
   452       if (base[0] + I420_Y_ROWSTRIDE (width) < end[0])
       
   453         base[0] += I420_Y_ROWSTRIDE (width);
       
   454       jpegenc->line[0][j + 1] = base[0];
       
   455       if (base[0] + I420_Y_ROWSTRIDE (width) < end[0])
       
   456         base[0] += I420_Y_ROWSTRIDE (width);
       
   457       jpegenc->line[1][k] = base[1];
       
   458       if (base[1] + I420_U_ROWSTRIDE (width) < end[1])
       
   459         base[1] += I420_U_ROWSTRIDE (width);
       
   460       jpegenc->line[2][k] = base[2];
       
   461       if (base[2] + I420_V_ROWSTRIDE (width) < end[2])
       
   462         base[2] += I420_V_ROWSTRIDE (width);
       
   463     }
       
   464     jpeg_write_raw_data (&jpegenc->cinfo, jpegenc->line, 2 * DCTSIZE);
       
   465   }
       
   466 
       
   467   jpeg_finish_compress (&jpegenc->cinfo);
       
   468   GST_DEBUG_OBJECT (jpegenc, "compressing done");
       
   469 
       
   470   GST_BUFFER_SIZE (outbuf) =
       
   471       GST_ROUND_UP_4 (jpegenc->bufsize - jpegenc->jdest.free_in_buffer);
       
   472 
       
   473   g_signal_emit (G_OBJECT (jpegenc), gst_jpegenc_signals[FRAME_ENCODED], 0);
       
   474 
       
   475   ret = gst_pad_push (jpegenc->srcpad, outbuf);
       
   476 
       
   477 done:
       
   478   gst_buffer_unref (buf);
       
   479 
       
   480   return ret;
       
   481 }
       
   482 
       
   483 static void
       
   484 gst_jpegenc_set_property (GObject * object, guint prop_id,
       
   485     const GValue * value, GParamSpec * pspec)
       
   486 {
       
   487   GstJpegEnc *jpegenc = GST_JPEGENC (object);
       
   488 
       
   489   GST_OBJECT_LOCK (jpegenc);
       
   490 
       
   491   switch (prop_id) {
       
   492     case ARG_QUALITY:
       
   493       jpegenc->quality = g_value_get_int (value);
       
   494       break;
       
   495     case ARG_SMOOTHING:
       
   496       jpegenc->smoothing = g_value_get_int (value);
       
   497       break;
       
   498     default:
       
   499       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       
   500       break;
       
   501   }
       
   502 
       
   503   GST_OBJECT_UNLOCK (jpegenc);
       
   504 }
       
   505 
       
   506 static void
       
   507 gst_jpegenc_get_property (GObject * object, guint prop_id, GValue * value,
       
   508     GParamSpec * pspec)
       
   509 {
       
   510   GstJpegEnc *jpegenc = GST_JPEGENC (object);
       
   511 
       
   512   GST_OBJECT_LOCK (jpegenc);
       
   513 
       
   514   switch (prop_id) {
       
   515     case ARG_QUALITY:
       
   516       g_value_set_int (value, jpegenc->quality);
       
   517       break;
       
   518     case ARG_SMOOTHING:
       
   519       g_value_set_int (value, jpegenc->smoothing);
       
   520       break;
       
   521     default:
       
   522       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       
   523       break;
       
   524   }
       
   525 
       
   526   GST_OBJECT_UNLOCK (jpegenc);
       
   527 }
       
   528 
       
   529 static GstStateChangeReturn
       
   530 gst_jpegenc_change_state (GstElement * element, GstStateChange transition)
       
   531 {
       
   532   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
       
   533   GstJpegEnc *filter = GST_JPEGENC (element);
       
   534 
       
   535   switch (transition) {
       
   536     case GST_STATE_CHANGE_NULL_TO_READY:
       
   537       GST_DEBUG_OBJECT (element, "setting line buffers");
       
   538       filter->line[0] = NULL;
       
   539       filter->line[1] = NULL;
       
   540       filter->line[2] = NULL;
       
   541       gst_jpegenc_resync (filter);
       
   542       break;
       
   543     default:
       
   544       break;
       
   545   }
       
   546 
       
   547   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
       
   548   if (ret == GST_STATE_CHANGE_FAILURE)
       
   549     return ret;
       
   550 
       
   551   switch (transition) {
       
   552     case GST_STATE_CHANGE_READY_TO_NULL:
       
   553       g_free (filter->line[0]);
       
   554       g_free (filter->line[1]);
       
   555       g_free (filter->line[2]);
       
   556       filter->line[0] = NULL;
       
   557       filter->line[1] = NULL;
       
   558       filter->line[2] = NULL;
       
   559       break;
       
   560     default:
       
   561       break;
       
   562   }
       
   563 
       
   564   return ret;
       
   565 }