gst_plugins_good/ext/jpeg/gstsmokedec.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 /*#define DEBUG_ENABLED*/
       
    27 #include "gstsmokedec.h"
       
    28 #include <gst/video/video.h>
       
    29 
       
    30 /* elementfactory information */
       
    31 static const GstElementDetails gst_smokedec_details =
       
    32 GST_ELEMENT_DETAILS ("Smoke video decoder",
       
    33     "Codec/Decoder/Video",
       
    34     "Decode video from Smoke format",
       
    35     "Wim Taymans <wim@fluendo.com>");
       
    36 
       
    37 GST_DEBUG_CATEGORY (smokedec_debug);
       
    38 #define GST_CAT_DEFAULT smokedec_debug
       
    39 
       
    40 /* SmokeDec signals and args */
       
    41 enum
       
    42 {
       
    43   LAST_SIGNAL
       
    44 };
       
    45 
       
    46 enum
       
    47 {
       
    48   PROP_0
       
    49 };
       
    50 
       
    51 static void gst_smokedec_base_init (gpointer g_class);
       
    52 static void gst_smokedec_class_init (GstSmokeDec * klass);
       
    53 static void gst_smokedec_init (GstSmokeDec * smokedec);
       
    54 
       
    55 static GstFlowReturn gst_smokedec_chain (GstPad * pad, GstBuffer * buf);
       
    56 
       
    57 static GstElementClass *parent_class = NULL;
       
    58 
       
    59 /*static guint gst_smokedec_signals[LAST_SIGNAL] = { 0 }; */
       
    60 
       
    61 GType
       
    62 gst_smokedec_get_type (void)
       
    63 {
       
    64   static GType smokedec_type = 0;
       
    65 
       
    66   if (!smokedec_type) {
       
    67     static const GTypeInfo smokedec_info = {
       
    68       sizeof (GstSmokeDecClass),
       
    69       gst_smokedec_base_init,
       
    70       NULL,
       
    71       (GClassInitFunc) gst_smokedec_class_init,
       
    72       NULL,
       
    73       NULL,
       
    74       sizeof (GstSmokeDec),
       
    75       0,
       
    76       (GInstanceInitFunc) gst_smokedec_init,
       
    77     };
       
    78 
       
    79     smokedec_type =
       
    80         g_type_register_static (GST_TYPE_ELEMENT, "GstSmokeDec", &smokedec_info,
       
    81         0);
       
    82   }
       
    83   return smokedec_type;
       
    84 }
       
    85 
       
    86 static GstStaticPadTemplate gst_smokedec_src_pad_template =
       
    87 GST_STATIC_PAD_TEMPLATE ("src",
       
    88     GST_PAD_SRC,
       
    89     GST_PAD_ALWAYS,
       
    90     GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420"))
       
    91     );
       
    92 
       
    93 static GstStaticPadTemplate gst_smokedec_sink_pad_template =
       
    94 GST_STATIC_PAD_TEMPLATE ("sink",
       
    95     GST_PAD_SINK,
       
    96     GST_PAD_ALWAYS,
       
    97     GST_STATIC_CAPS ("video/x-smoke, "
       
    98         "width = (int) [ 16, 4096 ], "
       
    99         "height = (int) [ 16, 4096 ], " "framerate = (fraction) [ 0/1, MAX ]")
       
   100     );
       
   101 
       
   102 static void
       
   103 gst_smokedec_base_init (gpointer g_class)
       
   104 {
       
   105   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
       
   106 
       
   107   gst_element_class_add_pad_template (element_class,
       
   108       gst_static_pad_template_get (&gst_smokedec_src_pad_template));
       
   109   gst_element_class_add_pad_template (element_class,
       
   110       gst_static_pad_template_get (&gst_smokedec_sink_pad_template));
       
   111   gst_element_class_set_details (element_class, &gst_smokedec_details);
       
   112 }
       
   113 
       
   114 static void
       
   115 gst_smokedec_class_init (GstSmokeDec * klass)
       
   116 {
       
   117   GstElementClass *gstelement_class;
       
   118 
       
   119   gstelement_class = (GstElementClass *) klass;
       
   120 
       
   121   parent_class = g_type_class_peek_parent (klass);
       
   122 
       
   123   GST_DEBUG_CATEGORY_INIT (smokedec_debug, "smokedec", 0, "Smoke decoder");
       
   124 }
       
   125 
       
   126 static void
       
   127 gst_smokedec_init (GstSmokeDec * smokedec)
       
   128 {
       
   129   GST_DEBUG_OBJECT (smokedec, "gst_smokedec_init: initializing");
       
   130   /* create the sink and src pads */
       
   131 
       
   132   smokedec->sinkpad =
       
   133       gst_pad_new_from_static_template (&gst_smokedec_sink_pad_template,
       
   134       "sink");
       
   135   gst_pad_set_chain_function (smokedec->sinkpad, gst_smokedec_chain);
       
   136   gst_element_add_pad (GST_ELEMENT (smokedec), smokedec->sinkpad);
       
   137 
       
   138   smokedec->srcpad =
       
   139       gst_pad_new_from_static_template (&gst_smokedec_src_pad_template, "src");
       
   140   gst_pad_use_fixed_caps (smokedec->srcpad);
       
   141   gst_element_add_pad (GST_ELEMENT (smokedec), smokedec->srcpad);
       
   142 
       
   143   /* reset the initial video state */
       
   144   smokedec->format = -1;
       
   145   smokedec->width = -1;
       
   146   smokedec->height = -1;
       
   147   smokedec->fps_num = -1;
       
   148   smokedec->fps_denom = -1;
       
   149   smokedec->next_time = 0;
       
   150 
       
   151   smokecodec_decode_new (&smokedec->info);
       
   152 }
       
   153 
       
   154 static GstFlowReturn
       
   155 gst_smokedec_chain (GstPad * pad, GstBuffer * buf)
       
   156 {
       
   157   GstSmokeDec *smokedec;
       
   158   guint8 *data, *outdata;
       
   159   gulong size, outsize;
       
   160   GstBuffer *outbuf;
       
   161   SmokeCodecFlags flags;
       
   162   GstClockTime time;
       
   163   guint width, height;
       
   164   guint fps_num, fps_denom;
       
   165   gint smokeret;
       
   166   GstFlowReturn ret;
       
   167 
       
   168   smokedec = GST_SMOKEDEC (gst_pad_get_parent (pad));
       
   169 
       
   170   data = GST_BUFFER_DATA (buf);
       
   171   size = GST_BUFFER_SIZE (buf);
       
   172   time = GST_BUFFER_TIMESTAMP (buf);
       
   173 
       
   174   GST_DEBUG_OBJECT (smokedec,
       
   175       "gst_smokedec_chain: got buffer of %ld bytes in '%s'", size,
       
   176       GST_OBJECT_NAME (smokedec));
       
   177 
       
   178   /* have the ID packet. */
       
   179   if (data[0] == SMOKECODEC_TYPE_ID) {
       
   180     smokeret = smokecodec_parse_id (smokedec->info, data, size);
       
   181     if (smokeret != SMOKECODEC_OK)
       
   182       goto header_error;
       
   183 
       
   184     ret = GST_FLOW_OK;
       
   185     goto done;
       
   186   }
       
   187 
       
   188   /* now handle data packets */
       
   189   GST_DEBUG_OBJECT (smokedec, "gst_smokedec_chain: reading header %08lx",
       
   190       *(gulong *) data);
       
   191   smokecodec_parse_header (smokedec->info, data, size, &flags, &width, &height,
       
   192       &fps_num, &fps_denom);
       
   193 
       
   194   if (smokedec->height != height || smokedec->width != width ||
       
   195       smokedec->fps_num != fps_num || smokedec->fps_denom != fps_denom) {
       
   196     GstCaps *caps;
       
   197 
       
   198     smokedec->height = height;
       
   199     smokedec->width = width;
       
   200 
       
   201     caps = gst_caps_new_simple ("video/x-raw-yuv",
       
   202         "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'),
       
   203         "width", G_TYPE_INT, width,
       
   204         "height", G_TYPE_INT, height,
       
   205         "framerate", GST_TYPE_FRACTION, fps_num, fps_denom, NULL);
       
   206 
       
   207     gst_pad_set_caps (smokedec->srcpad, caps);
       
   208     gst_caps_unref (caps);
       
   209   }
       
   210 
       
   211 
       
   212   if (smokedec->need_keyframe) {
       
   213     if (!(flags & SMOKECODEC_KEYFRAME))
       
   214       goto keyframe_skip;
       
   215 
       
   216     smokedec->need_keyframe = FALSE;
       
   217   }
       
   218 
       
   219   outbuf = gst_buffer_new ();
       
   220   outsize = GST_BUFFER_SIZE (outbuf) = width * height + width * height / 2;
       
   221   outdata = g_malloc (outsize);
       
   222   GST_BUFFER_DATA (outbuf) = outdata;
       
   223   GST_BUFFER_MALLOCDATA (outbuf) = outdata;
       
   224 
       
   225   GST_BUFFER_DURATION (outbuf) = GST_SECOND * fps_denom / fps_num;
       
   226   GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET (buf);
       
   227   gst_buffer_set_caps (outbuf, GST_PAD_CAPS (smokedec->srcpad));
       
   228 
       
   229   if (time == GST_CLOCK_TIME_NONE) {
       
   230     if (GST_BUFFER_OFFSET (buf) == -1) {
       
   231       time = smokedec->next_time;
       
   232     } else {
       
   233       time = GST_BUFFER_OFFSET (buf) * GST_BUFFER_DURATION (outbuf);
       
   234     }
       
   235   }
       
   236   GST_BUFFER_TIMESTAMP (outbuf) = time;
       
   237   smokedec->next_time = time + GST_BUFFER_DURATION (outbuf);
       
   238 
       
   239   smokeret = smokecodec_decode (smokedec->info, data, size, outdata);
       
   240   if (smokeret != SMOKECODEC_OK)
       
   241     goto decode_error;
       
   242 
       
   243   GST_DEBUG_OBJECT (smokedec, "gst_smokedec_chain: sending buffer");
       
   244   ret = gst_pad_push (smokedec->srcpad, outbuf);
       
   245 
       
   246 done:
       
   247   gst_buffer_unref (buf);
       
   248   gst_object_unref (smokedec);
       
   249 
       
   250   return ret;
       
   251 
       
   252   /* ERRORS */
       
   253 header_error:
       
   254   {
       
   255     GST_ELEMENT_ERROR (smokedec, STREAM, DECODE,
       
   256         (NULL), ("Could not parse smoke header, reason: %d", smokeret));
       
   257     ret = GST_FLOW_ERROR;
       
   258     goto done;
       
   259   }
       
   260 keyframe_skip:
       
   261   {
       
   262     GST_DEBUG_OBJECT (smokedec, "dropping buffer while waiting for keyframe");
       
   263     ret = GST_FLOW_OK;
       
   264     goto done;
       
   265   }
       
   266 decode_error:
       
   267   {
       
   268     GST_ELEMENT_ERROR (smokedec, STREAM, DECODE,
       
   269         (NULL), ("Could not decode smoke frame, reason: %d", smokeret));
       
   270     ret = GST_FLOW_ERROR;
       
   271     goto done;
       
   272   }
       
   273 }