Tizen 2.1 base
[profile/ivi/gst-plugins-bad0.10.git] / sys / applemedia / vth264decbin.c
1 /*
2  * Copyright (C) 2010 Ole André Vadla Ravnås <oravnas@cisco.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 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 #include "vth264decbin.h"
25
26 #include <string.h>
27 #include <gst/video/video.h>
28
29 #define VT_H264_DEC_BIN_ERROR_STATE_DEFAULT FALSE
30
31 GST_DEBUG_CATEGORY_STATIC (gst_vt_h264_dec_bin_debug);
32 #define GST_CAT_DEFAULT gst_vt_h264_dec_bin_debug
33
34 enum
35 {
36   PROP_0,
37   PROP_ERROR_STATE,
38   PROP_HAPPY
39 };
40
41 enum
42 {
43   H264PARSE_OUTPUT_FORMAT_AVC_SAMPLE = 0,
44   H264PARSE_OUTPUT_FORMAT_BYTE_STREAM = 1,
45   H264PARSE_OUTPUT_FORMAT_INPUT = 2
46 };
47
48 static GstStaticPadTemplate vth264decbin_sink_template =
49 GST_STATIC_PAD_TEMPLATE ("sink",
50     GST_PAD_SINK,
51     GST_PAD_ALWAYS,
52     GST_STATIC_CAPS ("video/x-h264, "
53         "stream-format = (string) { byte-stream, avc }")
54     );
55
56 static GstStaticPadTemplate vth264decbin_src_template =
57 GST_STATIC_PAD_TEMPLATE ("src",
58     GST_PAD_SRC,
59     GST_PAD_ALWAYS,
60     GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("NV12"))
61     );
62
63 #define TAA_VT_H264_DEC_BIN_GET_PRIVATE(obj)  \
64    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_VT_H264_DEC_BIN, \
65                                  GstVTH264DecBinPrivate))
66
67 struct _GstVTH264DecBinPrivate
68 {
69   GstElement *parser;
70   GstPad *parser_sinkpad;
71
72   GstElement *decoder;
73   GstPad *decoder_srcpad;
74
75   gboolean error_state;
76
77   gboolean seen_output;
78   GstClockTime prev_input_ts;
79
80   gulong output_probe;
81 };
82
83 GST_BOILERPLATE (GstVTH264DecBin, gst_vt_h264_dec_bin, GstBin, GST_TYPE_BIN);
84
85 static gboolean gst_vt_h264_dec_bin_on_output (GstPad * pad,
86     GstMiniObject * mini_obj, gpointer user_data);
87
88 static void
89 gst_vt_h264_dec_bin_update_error_state (GstVTH264DecBin * self,
90     gboolean error_state)
91 {
92   GstVTH264DecBinPrivate *priv = self->priv;
93   GObject *obj = (GObject *) self;
94
95   GST_OBJECT_LOCK (self);
96   priv->error_state = error_state;
97   GST_OBJECT_UNLOCK (self);
98
99   if (priv->output_probe == 0 && (error_state || !priv->seen_output)) {
100     GST_DEBUG_OBJECT (self, "attaching buffer probe");
101     priv->output_probe = gst_pad_add_buffer_probe (priv->decoder_srcpad,
102         G_CALLBACK (gst_vt_h264_dec_bin_on_output), self);
103   } else if (priv->output_probe != 0 && (!error_state && priv->seen_output)) {
104     GST_DEBUG_OBJECT (self, "detaching buffer probe");
105     gst_pad_remove_buffer_probe (priv->decoder_srcpad, priv->output_probe);
106     priv->output_probe = 0;
107   }
108
109   g_object_notify (obj, "error-state");
110   g_object_notify (obj, "happy");
111 }
112
113 static gboolean
114 gst_vt_h264_dec_bin_sink_setcaps (GstPad * pad, GstCaps * caps)
115 {
116   GstVTH264DecBin *self = GST_VT_H264_DEC_BIN_CAST (GST_PAD_PARENT (pad));
117   const gchar *format;
118   gint output_format;
119   gboolean access_unit;
120
121   format = gst_structure_get_string (gst_caps_get_structure (caps, 0),
122       "stream-format");
123   if (format == NULL)
124     goto no_stream_format;
125
126   if (strcmp (format, "byte-stream") == 0) {
127     output_format = H264PARSE_OUTPUT_FORMAT_AVC_SAMPLE;
128     access_unit = TRUE;
129   } else {
130     output_format = H264PARSE_OUTPUT_FORMAT_INPUT;
131     access_unit = FALSE;
132   }
133
134   g_object_set (self->priv->parser, "output-format", output_format,
135       "access-unit", access_unit, NULL);
136
137   return gst_pad_set_caps (GST_PAD_PEER (self->priv->parser_sinkpad), caps);
138
139 no_stream_format:
140   return FALSE;
141 }
142
143 static gboolean
144 gst_vt_h264_dec_bin_sink_event (GstPad * pad, GstEvent * event)
145 {
146   GstVTH264DecBin *self = GST_VT_H264_DEC_BIN_CAST (GST_PAD_PARENT (pad));
147   GstVTH264DecBinPrivate *priv = self->priv;
148
149   switch (GST_EVENT_TYPE (event)) {
150     case GST_EVENT_NEWSEGMENT:
151       if (priv->seen_output) {
152         GST_DEBUG_OBJECT (self, "error state ON because of packetloss");
153         gst_vt_h264_dec_bin_update_error_state (self, TRUE);
154       }
155       break;
156     case GST_EVENT_FLUSH_STOP:
157       priv->seen_output = FALSE;
158       priv->prev_input_ts = GST_CLOCK_TIME_NONE;
159       GST_DEBUG_OBJECT (self, "error state OFF because of FLUSH_STOP");
160       gst_vt_h264_dec_bin_update_error_state (self, FALSE);
161       break;
162     default:
163       break;
164   }
165
166   return gst_pad_push_event (GST_PAD_PEER (priv->parser_sinkpad), event);
167 }
168
169 static GstFlowReturn
170 gst_vt_h264_dec_bin_sink_chain (GstPad * pad, GstBuffer * buffer)
171 {
172   GstVTH264DecBin *self = GST_VT_H264_DEC_BIN_CAST (GST_PAD_PARENT (pad));
173   GstVTH264DecBinPrivate *priv = self->priv;
174   GstClockTime cur_ts;
175   GstFlowReturn flow_ret;
176
177   cur_ts = GST_BUFFER_TIMESTAMP (buffer);
178
179   gst_vt_h264_dec_bin_update_error_state (self, priv->error_state);
180
181   flow_ret = gst_pad_push (GST_PAD_PEER (priv->parser_sinkpad), buffer);
182
183   if (!priv->seen_output && !priv->error_state &&
184       GST_CLOCK_TIME_IS_VALID (priv->prev_input_ts)) {
185     if (cur_ts != priv->prev_input_ts) {
186       GST_DEBUG_OBJECT (self,
187           "error state ON because of no output and detected timestamp gap");
188       gst_vt_h264_dec_bin_update_error_state (self, TRUE);
189     }
190   }
191   priv->prev_input_ts = cur_ts;
192
193   return flow_ret;
194 }
195
196 static gboolean
197 gst_vt_h264_dec_bin_on_output (GstPad * pad, GstMiniObject * mini_obj,
198     gpointer user_data)
199 {
200   GstVTH264DecBin *self = GST_VT_H264_DEC_BIN_CAST (user_data);
201
202   self->priv->seen_output = TRUE;
203
204   GST_DEBUG_OBJECT (self, "error state OFF because we saw output");
205   gst_vt_h264_dec_bin_update_error_state (self, FALSE);
206
207   return TRUE;
208 }
209
210 static void
211 gst_vt_h264_dec_bin_base_init (gpointer gclass)
212 {
213   GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
214
215   gst_element_class_set_details_simple (element_class,
216       "VTH264DecBin",
217       "Decoder/Video",
218       "VideoToolbox H.264 decoder bin",
219       "Ole André Vadla Ravnås <oravnas@cisco.com>");
220
221   gst_element_class_add_static_pad_template (element_class,
222       &vth264decbin_sink_template);
223   gst_element_class_add_static_pad_template (element_class,
224       &vth264decbin_src_template);
225 }
226
227 static void
228 gst_vt_h264_dec_bin_init (GstVTH264DecBin * self, GstVTH264DecBinClass * gclass)
229 {
230   GstVTH264DecBinPrivate *priv;
231   GstPad *ghost_pad;
232
233   self->priv = priv = TAA_VT_H264_DEC_BIN_GET_PRIVATE (self);
234
235   priv->parser = gst_element_factory_make ("h264parse", "parser");
236   priv->decoder = gst_element_factory_make ("vtdec_h264", "decoder");
237   gst_bin_add_many (GST_BIN_CAST (self), priv->parser, priv->decoder, NULL);
238   gst_element_link (priv->parser, priv->decoder);
239
240   priv->parser_sinkpad = gst_element_get_static_pad (priv->parser, "sink");
241   ghost_pad = gst_ghost_pad_new_from_template ("sink", priv->parser_sinkpad,
242       gst_static_pad_template_get (&vth264decbin_sink_template));
243   gst_pad_set_setcaps_function (ghost_pad, gst_vt_h264_dec_bin_sink_setcaps);
244   gst_pad_set_event_function (ghost_pad, gst_vt_h264_dec_bin_sink_event);
245   gst_pad_set_chain_function (ghost_pad, gst_vt_h264_dec_bin_sink_chain);
246   gst_element_add_pad (GST_ELEMENT_CAST (self), ghost_pad);
247
248   priv->decoder_srcpad = gst_element_get_static_pad (priv->decoder, "src");
249   ghost_pad = gst_ghost_pad_new_from_template ("src", priv->decoder_srcpad,
250       gst_static_pad_template_get (&vth264decbin_src_template));
251   gst_element_add_pad (GST_ELEMENT_CAST (self), ghost_pad);
252
253   priv->seen_output = FALSE;
254   priv->prev_input_ts = GST_CLOCK_TIME_NONE;
255 }
256
257 static void
258 gst_vt_h264_dec_bin_dispose (GObject * obj)
259 {
260   GstVTH264DecBin *self = GST_VT_H264_DEC_BIN_CAST (obj);
261   GstVTH264DecBinPrivate *priv = self->priv;
262
263   if (priv->parser_sinkpad != NULL) {
264     gst_object_unref (priv->parser_sinkpad);
265     priv->parser_sinkpad = NULL;
266   }
267
268   if (priv->decoder_srcpad != NULL) {
269     gst_object_unref (priv->decoder_srcpad);
270     priv->decoder_srcpad = NULL;
271   }
272
273   G_OBJECT_CLASS (parent_class)->dispose (obj);
274 }
275
276 static void
277 gst_vt_h264_dec_bin_get_property (GObject * obj, guint prop_id,
278     GValue * value, GParamSpec * pspec)
279 {
280   GstVTH264DecBin *self = GST_VT_H264_DEC_BIN_CAST (obj);
281
282   switch (prop_id) {
283     case PROP_ERROR_STATE:
284       GST_OBJECT_LOCK (self);
285       g_value_set_boolean (value, self->priv->error_state);
286       GST_OBJECT_UNLOCK (self);
287       break;
288     case PROP_HAPPY:
289       GST_OBJECT_LOCK (self);
290       g_value_set_boolean (value, !self->priv->error_state);
291       GST_OBJECT_UNLOCK (self);
292       break;
293     default:
294       G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
295       break;
296   }
297 }
298
299 static void
300 gst_vt_h264_dec_bin_class_init (GstVTH264DecBinClass * klass)
301 {
302   GObjectClass *gobject_class = (GObjectClass *) klass;
303
304   gobject_class->dispose = gst_vt_h264_dec_bin_dispose;
305   gobject_class->get_property = gst_vt_h264_dec_bin_get_property;
306
307   g_type_class_add_private (klass, sizeof (GstVTH264DecBinPrivate));
308
309   g_object_class_install_property (gobject_class, PROP_ERROR_STATE,
310       g_param_spec_boolean ("error-state", "Error State",
311           "Whether the decoder is currently in an error state",
312           VT_H264_DEC_BIN_ERROR_STATE_DEFAULT,
313           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
314   g_object_class_install_property (gobject_class, PROP_HAPPY,
315       g_param_spec_boolean ("happy", "Happy",
316           "Whether the decoder is currently not in an error state",
317           !VT_H264_DEC_BIN_ERROR_STATE_DEFAULT,
318           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
319
320   GST_DEBUG_CATEGORY_INIT (gst_vt_h264_dec_bin_debug,
321       "vth264decbin", 0, "VideoToolbox H.264 decoder bin");
322 }