tizen 2.0 init
[framework/multimedia/gst-plugins-base0.10.git] / gst / encoding / gstsmartencoder.c
1 /* GStreamer Smart Video Encoder element
2  * Copyright (C) <2010> Edward Hervey <bilboed@gmail.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 /* TODO:
21  * * Implement get_caps/set_caps (store/forward caps)
22  * * Adjust template caps to the formats we can support
23  **/
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include <string.h>
30 #include "gstsmartencoder.h"
31
32 GST_DEBUG_CATEGORY_STATIC (smart_encoder_debug);
33 #define GST_CAT_DEFAULT smart_encoder_debug
34
35 /* FIXME : Update this with new caps */
36 /* WARNING : We can only allow formats with closed-GOP */
37 #define ALLOWED_CAPS "video/x-h263;video/x-intel-h263;"\
38   "video/mpeg,mpegversion=(int)1,systemstream=(boolean)false;"\
39   "video/mpeg,mpegversion=(int)2,systemstream=(boolean)false;"
40
41 static GstStaticPadTemplate src_template =
42 GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC,
43     GST_PAD_ALWAYS,
44     GST_STATIC_CAPS (ALLOWED_CAPS)
45     );
46
47 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
48     GST_PAD_SINK,
49     GST_PAD_ALWAYS,
50     GST_STATIC_CAPS (ALLOWED_CAPS)
51     );
52
53 static GQuark INTERNAL_ELEMENT;
54
55 /* GstSmartEncoder signals and args */
56 enum
57 {
58   /* FILL ME */
59   LAST_SIGNAL
60 };
61
62 enum
63 {
64   ARG_0
65       /* FILL ME */
66 };
67
68 static void
69 _do_init (void)
70 {
71   INTERNAL_ELEMENT = g_quark_from_string ("internal-element");
72 };
73
74 G_DEFINE_TYPE_EXTENDED (GstSmartEncoder, gst_smart_encoder, GST_TYPE_ELEMENT, 0,
75     _do_init ());
76
77 static void gst_smart_encoder_dispose (GObject * object);
78
79 static gboolean setup_recoder_pipeline (GstSmartEncoder * smart_encoder);
80
81 static GstFlowReturn gst_smart_encoder_chain (GstPad * pad, GstBuffer * buf);
82 static gboolean smart_encoder_sink_event (GstPad * pad, GstEvent * event);
83 static GstCaps *smart_encoder_sink_getcaps (GstPad * pad);
84 static GstStateChangeReturn
85 gst_smart_encoder_change_state (GstElement * element,
86     GstStateChange transition);
87
88 static void
89 gst_smart_encoder_class_init (GstSmartEncoderClass * klass)
90 {
91   GObjectClass *gobject_class;
92   GstElementClass *element_class;
93
94   element_class = (GstElementClass *) klass;
95   gobject_class = G_OBJECT_CLASS (klass);
96
97   gst_smart_encoder_parent_class = g_type_class_peek_parent (klass);
98
99   gst_element_class_add_static_pad_template (element_class, &src_template);
100   gst_element_class_add_static_pad_template (element_class,
101       &sink_template);
102
103   gst_element_class_set_details_simple (element_class, "Smart Video Encoder",
104       "Codec/Recoder/Video",
105       "Re-encodes portions of Video that lay on segment boundaries",
106       "Edward Hervey <bilboed@gmail.com>");
107
108   gobject_class->dispose = (GObjectFinalizeFunc) (gst_smart_encoder_dispose);
109   element_class->change_state = gst_smart_encoder_change_state;
110
111   GST_DEBUG_CATEGORY_INIT (smart_encoder_debug, "smartencoder", 0,
112       "Smart Encoder");
113 }
114
115 static void
116 smart_encoder_reset (GstSmartEncoder * smart_encoder)
117 {
118   gst_segment_init (smart_encoder->segment, GST_FORMAT_UNDEFINED);
119
120   if (smart_encoder->encoder) {
121     /* Clean up/remove elements */
122     gst_element_set_state (smart_encoder->encoder, GST_STATE_NULL);
123     gst_element_set_state (smart_encoder->decoder, GST_STATE_NULL);
124     gst_element_set_bus (smart_encoder->encoder, NULL);
125     gst_element_set_bus (smart_encoder->decoder, NULL);
126     gst_pad_set_active (smart_encoder->internal_srcpad, FALSE);
127     gst_pad_set_active (smart_encoder->internal_sinkpad, FALSE);
128     gst_object_unref (smart_encoder->encoder);
129     gst_object_unref (smart_encoder->decoder);
130     gst_object_unref (smart_encoder->internal_srcpad);
131     gst_object_unref (smart_encoder->internal_sinkpad);
132
133     smart_encoder->encoder = NULL;
134     smart_encoder->decoder = NULL;
135     smart_encoder->internal_sinkpad = NULL;
136     smart_encoder->internal_srcpad = NULL;
137   }
138
139   if (smart_encoder->newsegment) {
140     gst_event_unref (smart_encoder->newsegment);
141     smart_encoder->newsegment = NULL;
142   }
143 }
144
145
146 static void
147 gst_smart_encoder_init (GstSmartEncoder * smart_encoder)
148 {
149   smart_encoder->sinkpad =
150       gst_pad_new_from_static_template (&sink_template, "sink");
151   gst_pad_set_chain_function (smart_encoder->sinkpad, gst_smart_encoder_chain);
152   gst_pad_set_event_function (smart_encoder->sinkpad, smart_encoder_sink_event);
153   gst_pad_set_getcaps_function (smart_encoder->sinkpad,
154       smart_encoder_sink_getcaps);
155   gst_element_add_pad (GST_ELEMENT (smart_encoder), smart_encoder->sinkpad);
156
157   smart_encoder->srcpad =
158       gst_pad_new_from_static_template (&src_template, "src");
159   gst_pad_use_fixed_caps (smart_encoder->srcpad);
160   gst_element_add_pad (GST_ELEMENT (smart_encoder), smart_encoder->srcpad);
161
162   smart_encoder->segment = gst_segment_new ();
163
164   smart_encoder_reset (smart_encoder);
165 }
166
167 void
168 gst_smart_encoder_dispose (GObject * object)
169 {
170   GstSmartEncoder *smart_encoder = (GstSmartEncoder *) object;
171
172   if (smart_encoder->segment)
173     gst_segment_free (smart_encoder->segment);
174   smart_encoder->segment = NULL;
175   if (smart_encoder->available_caps)
176     gst_caps_unref (smart_encoder->available_caps);
177   smart_encoder->available_caps = NULL;
178   G_OBJECT_CLASS (gst_smart_encoder_parent_class)->dispose (object);
179 }
180
181 static GstFlowReturn
182 gst_smart_encoder_reencode_gop (GstSmartEncoder * smart_encoder)
183 {
184   GstFlowReturn res = GST_FLOW_OK;
185   GList *tmp;
186
187   if (smart_encoder->encoder == NULL) {
188     if (!setup_recoder_pipeline (smart_encoder))
189       return GST_FLOW_ERROR;
190   }
191
192   /* Activate elements */
193   /* Set elements to PAUSED */
194   gst_element_set_state (smart_encoder->encoder, GST_STATE_PAUSED);
195   gst_element_set_state (smart_encoder->decoder, GST_STATE_PAUSED);
196
197   GST_INFO ("Pushing Flush start/stop to clean decoder/encoder");
198   gst_pad_push_event (smart_encoder->internal_srcpad,
199       gst_event_new_flush_start ());
200   gst_pad_push_event (smart_encoder->internal_srcpad,
201       gst_event_new_flush_stop ());
202
203   /* push newsegment */
204   GST_INFO ("Pushing newsegment %" GST_PTR_FORMAT, smart_encoder->newsegment);
205   gst_pad_push_event (smart_encoder->internal_srcpad,
206       gst_event_ref (smart_encoder->newsegment));
207
208   /* Push buffers through our pads */
209   GST_DEBUG ("Pushing pending buffers");
210
211   for (tmp = smart_encoder->pending_gop; tmp; tmp = tmp->next) {
212     GstBuffer *buf = (GstBuffer *) tmp->data;
213
214     res = gst_pad_push (smart_encoder->internal_srcpad, buf);
215     if (G_UNLIKELY (res != GST_FLOW_OK))
216       break;
217   }
218
219   if (G_UNLIKELY (res != GST_FLOW_OK)) {
220     GST_WARNING ("Error pushing pending buffers : %s", gst_flow_get_name (res));
221     /* Remove pending bfufers */
222     for (tmp = smart_encoder->pending_gop; tmp; tmp = tmp->next) {
223       gst_buffer_unref ((GstBuffer *) tmp->data);
224     }
225   } else {
226     GST_INFO ("Pushing out EOS to flush out decoder/encoder");
227     gst_pad_push_event (smart_encoder->internal_srcpad, gst_event_new_eos ());
228   }
229
230   /* Activate elements */
231   /* Set elements to PAUSED */
232   gst_element_set_state (smart_encoder->encoder, GST_STATE_NULL);
233   gst_element_set_state (smart_encoder->decoder, GST_STATE_NULL);
234
235   g_list_free (smart_encoder->pending_gop);
236   smart_encoder->pending_gop = NULL;
237
238   return res;
239 }
240
241 static GstFlowReturn
242 gst_smart_encoder_push_pending_gop (GstSmartEncoder * smart_encoder)
243 {
244   gint64 cstart, cstop;
245   GList *tmp;
246   GstFlowReturn res = GST_FLOW_OK;
247
248   GST_DEBUG ("Pushing pending GOP (%" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT
249       ")", GST_TIME_ARGS (smart_encoder->gop_start),
250       GST_TIME_ARGS (smart_encoder->gop_stop));
251
252   /* If GOP is entirely within segment, just push downstream */
253   if (gst_segment_clip (smart_encoder->segment, GST_FORMAT_TIME,
254           smart_encoder->gop_start, smart_encoder->gop_stop, &cstart, &cstop)) {
255     if ((cstart != smart_encoder->gop_start)
256         || (cstop != smart_encoder->gop_stop)) {
257       GST_DEBUG ("GOP needs to be re-encoded from %" GST_TIME_FORMAT " to %"
258           GST_TIME_FORMAT, GST_TIME_ARGS (cstart), GST_TIME_ARGS (cstop));
259       res = gst_smart_encoder_reencode_gop (smart_encoder);
260     } else {
261       /* The whole GOP is within the segment, push all pending buffers downstream */
262       GST_DEBUG ("GOP doesn't need to be modified, pushing downstream");
263       for (tmp = smart_encoder->pending_gop; tmp; tmp = tmp->next) {
264         GstBuffer *buf = (GstBuffer *) tmp->data;
265         res = gst_pad_push (smart_encoder->srcpad, buf);
266         if (G_UNLIKELY (res != GST_FLOW_OK))
267           break;
268       }
269     }
270   } else {
271     /* The whole GOP is outside the segment, there's most likely
272      * a bug somewhere. */
273     GST_WARNING
274         ("GOP is entirely outside of the segment, upstream gave us too much data");
275     for (tmp = smart_encoder->pending_gop; tmp; tmp = tmp->next) {
276       gst_buffer_unref ((GstBuffer *) tmp->data);
277     }
278   }
279
280   if (smart_encoder->pending_gop) {
281     g_list_free (smart_encoder->pending_gop);
282     smart_encoder->pending_gop = NULL;
283   }
284   smart_encoder->gop_start = GST_CLOCK_TIME_NONE;
285   smart_encoder->gop_stop = GST_CLOCK_TIME_NONE;
286
287   return res;
288 }
289
290 static GstFlowReturn
291 gst_smart_encoder_chain (GstPad * pad, GstBuffer * buf)
292 {
293   GstSmartEncoder *smart_encoder;
294   GstFlowReturn res = GST_FLOW_OK;
295   gboolean discont, keyframe;
296
297   smart_encoder = GST_SMART_ENCODER (gst_object_get_parent (GST_OBJECT (pad)));
298
299   discont = GST_BUFFER_IS_DISCONT (buf);
300   keyframe = !GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
301
302   GST_DEBUG ("New buffer %s %s %" GST_TIME_FORMAT,
303       discont ? "discont" : "",
304       keyframe ? "keyframe" : "", GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
305
306   if (keyframe) {
307     GST_DEBUG ("Got a keyframe");
308
309     /* If there's a pending GOP, flush it out */
310     if (smart_encoder->pending_gop) {
311       /* Mark gop_stop */
312       smart_encoder->gop_stop = GST_BUFFER_TIMESTAMP (buf);
313
314       /* flush pending */
315       res = gst_smart_encoder_push_pending_gop (smart_encoder);
316       if (G_UNLIKELY (res != GST_FLOW_OK))
317         goto beach;
318     }
319
320     /* Mark gop_start for new gop */
321     smart_encoder->gop_start = GST_BUFFER_TIMESTAMP (buf);
322   }
323
324   /* Store buffer */
325   smart_encoder->pending_gop = g_list_append (smart_encoder->pending_gop, buf);
326   /* Update GOP stop position */
327   if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
328     smart_encoder->gop_stop = GST_BUFFER_TIMESTAMP (buf);
329     if (GST_BUFFER_DURATION_IS_VALID (buf))
330       smart_encoder->gop_stop += GST_BUFFER_DURATION (buf);
331   }
332
333   GST_DEBUG ("Buffer stored , Current GOP : %" GST_TIME_FORMAT " -- %"
334       GST_TIME_FORMAT, GST_TIME_ARGS (smart_encoder->gop_start),
335       GST_TIME_ARGS (smart_encoder->gop_stop));
336
337 beach:
338   gst_object_unref (smart_encoder);
339   return res;
340 }
341
342 static gboolean
343 smart_encoder_sink_event (GstPad * pad, GstEvent * event)
344 {
345   gboolean res = TRUE;
346   GstSmartEncoder *smart_encoder = GST_SMART_ENCODER (gst_pad_get_parent (pad));
347
348   switch (GST_EVENT_TYPE (event)) {
349     case GST_EVENT_FLUSH_STOP:
350       smart_encoder_reset (smart_encoder);
351       break;
352     case GST_EVENT_NEWSEGMENT:
353     {
354       GstFormat format;
355       gdouble rate, arate;
356       gint64 start, stop, time;
357       gboolean update;
358
359       gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
360           &start, &stop, &time);
361       GST_DEBUG_OBJECT (smart_encoder,
362           "newsegment: update %d, rate %g, arate %g, start %" GST_TIME_FORMAT
363           ", stop %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT,
364           update, rate, arate, GST_TIME_ARGS (start), GST_TIME_ARGS (stop),
365           GST_TIME_ARGS (time));
366       if (format != GST_FORMAT_TIME)
367         GST_ERROR
368             ("smart_encoder can not handle streams not specified in GST_FORMAT_TIME");
369
370       /* now configure the values */
371       gst_segment_set_newsegment_full (smart_encoder->segment, update,
372           rate, arate, format, start, stop, time);
373
374       /* And keep a copy for further usage */
375       if (smart_encoder->newsegment)
376         gst_event_unref (smart_encoder->newsegment);
377       smart_encoder->newsegment = gst_event_ref (event);
378     }
379       break;
380     case GST_EVENT_EOS:
381       GST_DEBUG ("Eos, flushing remaining data");
382       gst_smart_encoder_push_pending_gop (smart_encoder);
383       break;
384     default:
385       break;
386   }
387
388   res = gst_pad_push_event (smart_encoder->srcpad, event);
389
390   gst_object_unref (smart_encoder);
391   return res;
392 }
393
394 static GstCaps *
395 smart_encoder_sink_getcaps (GstPad * pad)
396 {
397   GstCaps *peer, *tmpl, *res;
398   GstSmartEncoder *smart_encoder = GST_SMART_ENCODER (gst_pad_get_parent (pad));
399
400   /* Try getting it from downstream */
401   peer = gst_pad_peer_get_caps_reffed (smart_encoder->srcpad);
402
403   /* Use computed caps */
404   if (smart_encoder->available_caps)
405     tmpl = gst_caps_ref (smart_encoder->available_caps);
406   else
407     tmpl = gst_static_pad_template_get_caps (&src_template);
408
409   if (peer == NULL) {
410     res = tmpl;
411   } else {
412     res = gst_caps_intersect (peer, tmpl);
413     gst_caps_unref (peer);
414     gst_caps_unref (tmpl);
415   }
416
417   gst_object_unref (smart_encoder);
418   return res;
419 }
420
421 /*****************************************
422  *    Internal encoder/decoder pipeline  *
423  ******************************************/
424
425 static GstElementFactory *
426 get_decoder_factory (GstCaps * caps)
427 {
428   GstElementFactory *fact = NULL;
429   GList *decoders, *tmp;
430
431   tmp =
432       gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_DECODER,
433       GST_RANK_MARGINAL);
434   decoders = gst_element_factory_list_filter (tmp, caps, GST_PAD_SINK, FALSE);
435   gst_plugin_feature_list_free (tmp);
436
437   for (tmp = decoders; tmp; tmp = tmp->next) {
438     /* We just pick the first one */
439     fact = (GstElementFactory *) tmp->data;
440     gst_object_ref (fact);
441     break;
442   }
443
444   gst_plugin_feature_list_free (decoders);
445
446   return fact;
447 }
448
449 static GstElementFactory *
450 get_encoder_factory (GstCaps * caps)
451 {
452   GstElementFactory *fact = NULL;
453   GList *encoders, *tmp;
454
455   tmp =
456       gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_ENCODER,
457       GST_RANK_MARGINAL);
458   encoders = gst_element_factory_list_filter (tmp, caps, GST_PAD_SRC, FALSE);
459   gst_plugin_feature_list_free (tmp);
460
461   for (tmp = encoders; tmp; tmp = tmp->next) {
462     /* We just pick the first one */
463     fact = (GstElementFactory *) tmp->data;
464     gst_object_ref (fact);
465     break;
466   }
467
468   gst_plugin_feature_list_free (encoders);
469
470   return fact;
471 }
472
473 static GstElement *
474 get_decoder (GstCaps * caps)
475 {
476   GstElementFactory *fact = get_decoder_factory (caps);
477   GstElement *res = NULL;
478
479   if (fact) {
480     res = gst_element_factory_create (fact, "internal-decoder");
481     gst_object_unref (fact);
482   }
483   return res;
484 }
485
486 static GstElement *
487 get_encoder (GstCaps * caps)
488 {
489   GstElementFactory *fact = get_encoder_factory (caps);
490   GstElement *res = NULL;
491
492   if (fact) {
493     res = gst_element_factory_create (fact, "internal-encoder");
494     gst_object_unref (fact);
495   }
496   return res;
497 }
498
499 static GstFlowReturn
500 internal_chain (GstPad * pad, GstBuffer * buf)
501 {
502   GstSmartEncoder *smart_encoder =
503       g_object_get_qdata ((GObject *) pad, INTERNAL_ELEMENT);
504
505   return gst_pad_push (smart_encoder->srcpad, buf);
506 }
507
508 static gboolean
509 setup_recoder_pipeline (GstSmartEncoder * smart_encoder)
510 {
511   GstPad *tmppad;
512
513   /* Fast path */
514   if (G_UNLIKELY (smart_encoder->encoder))
515     return TRUE;
516
517   GST_DEBUG ("Creating internal decoder and encoder");
518
519   /* Create decoder/encoder */
520   smart_encoder->decoder = get_decoder (GST_PAD_CAPS (smart_encoder->sinkpad));
521   if (G_UNLIKELY (smart_encoder->decoder == NULL))
522     goto no_decoder;
523   gst_element_set_bus (smart_encoder->decoder, GST_ELEMENT_BUS (smart_encoder));
524
525   smart_encoder->encoder = get_encoder (GST_PAD_CAPS (smart_encoder->sinkpad));
526   if (G_UNLIKELY (smart_encoder->encoder == NULL))
527     goto no_encoder;
528   gst_element_set_bus (smart_encoder->encoder, GST_ELEMENT_BUS (smart_encoder));
529
530   GST_DEBUG ("Creating internal pads");
531
532   /* Create internal pads */
533
534   /* Source pad which we'll use to feed data to decoders */
535   smart_encoder->internal_srcpad = gst_pad_new ("internal_src", GST_PAD_SRC);
536   g_object_set_qdata ((GObject *) smart_encoder->internal_srcpad,
537       INTERNAL_ELEMENT, smart_encoder);
538   gst_pad_set_caps (smart_encoder->internal_srcpad,
539       GST_PAD_CAPS (smart_encoder->sinkpad));
540   gst_pad_set_active (smart_encoder->internal_srcpad, TRUE);
541
542   /* Sink pad which will get the buffers from the encoder.
543    * Note: We don't need an event function since we'll be discarding all
544    * of them. */
545   smart_encoder->internal_sinkpad = gst_pad_new ("internal_sink", GST_PAD_SINK);
546   g_object_set_qdata ((GObject *) smart_encoder->internal_sinkpad,
547       INTERNAL_ELEMENT, smart_encoder);
548   gst_pad_set_caps (smart_encoder->internal_sinkpad,
549       GST_PAD_CAPS (smart_encoder->sinkpad));
550   gst_pad_set_chain_function (smart_encoder->internal_sinkpad, internal_chain);
551   gst_pad_set_active (smart_encoder->internal_sinkpad, TRUE);
552
553   GST_DEBUG ("Linking pads to elements");
554
555   /* Link everything */
556   tmppad = gst_element_get_static_pad (smart_encoder->encoder, "src");
557   if (GST_PAD_LINK_FAILED (gst_pad_link (tmppad,
558               smart_encoder->internal_sinkpad)))
559     goto sinkpad_link_fail;
560   gst_object_unref (tmppad);
561
562   if (!gst_element_link (smart_encoder->decoder, smart_encoder->encoder))
563     goto encoder_decoder_link_fail;
564
565   tmppad = gst_element_get_static_pad (smart_encoder->decoder, "sink");
566   if (GST_PAD_LINK_FAILED (gst_pad_link (smart_encoder->internal_srcpad,
567               tmppad)))
568     goto srcpad_link_fail;
569   gst_object_unref (tmppad);
570
571   GST_DEBUG ("Done creating internal elements/pads");
572
573   return TRUE;
574
575 no_decoder:
576   {
577     GST_WARNING ("Couldn't find a decoder for %" GST_PTR_FORMAT,
578         GST_PAD_CAPS (smart_encoder->sinkpad));
579     return FALSE;
580   }
581
582 no_encoder:
583   {
584     GST_WARNING ("Couldn't find an encoder for %" GST_PTR_FORMAT,
585         GST_PAD_CAPS (smart_encoder->sinkpad));
586     return FALSE;
587   }
588
589 srcpad_link_fail:
590   {
591     gst_object_unref (tmppad);
592     GST_WARNING ("Couldn't link internal srcpad to decoder");
593     return FALSE;
594   }
595
596 sinkpad_link_fail:
597   {
598     gst_object_unref (tmppad);
599     GST_WARNING ("Couldn't link encoder to internal sinkpad");
600     return FALSE;
601   }
602
603 encoder_decoder_link_fail:
604   {
605     GST_WARNING ("Couldn't link decoder to encoder");
606     return FALSE;
607   }
608 }
609
610 static GstStateChangeReturn
611 gst_smart_encoder_find_elements (GstSmartEncoder * smart_encoder)
612 {
613   guint i, n;
614   GstCaps *tmpl, *st, *res;
615   GstElementFactory *dec, *enc;
616   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
617
618   if (G_UNLIKELY (smart_encoder->available_caps))
619     goto beach;
620
621   /* Iterate over all pad template caps and see if we have both an
622    * encoder and a decoder for those media types */
623   tmpl = gst_static_pad_template_get_caps (&src_template);
624   res = gst_caps_new_empty ();
625   n = gst_caps_get_size (tmpl);
626
627   for (i = 0; i < n; i++) {
628     st = gst_caps_copy_nth (tmpl, i);
629     GST_DEBUG_OBJECT (smart_encoder,
630         "Checking for available decoder and encoder for %" GST_PTR_FORMAT, st);
631     if (!(dec = get_decoder_factory (st))) {
632       gst_caps_unref (st);
633       continue;
634     }
635     gst_object_unref (dec);
636     if (!(enc = get_encoder_factory (st))) {
637       gst_caps_unref (st);
638       continue;
639     }
640     gst_object_unref (enc);
641     GST_DEBUG_OBJECT (smart_encoder, "OK");
642     gst_caps_append (res, st);
643   }
644
645   gst_caps_unref (tmpl);
646
647   if (gst_caps_is_empty (res)) {
648     gst_caps_unref (res);
649     ret = GST_STATE_CHANGE_FAILURE;
650   } else
651     smart_encoder->available_caps = res;
652
653   GST_DEBUG_OBJECT (smart_encoder, "Done, available_caps:%" GST_PTR_FORMAT,
654       smart_encoder->available_caps);
655
656 beach:
657   return ret;
658 }
659
660 /******************************************
661  *    GstElement vmethod implementations  *
662  ******************************************/
663
664 static GstStateChangeReturn
665 gst_smart_encoder_change_state (GstElement * element, GstStateChange transition)
666 {
667   GstSmartEncoder *smart_encoder;
668   GstStateChangeReturn ret;
669
670   g_return_val_if_fail (GST_IS_SMART_ENCODER (element),
671       GST_STATE_CHANGE_FAILURE);
672
673   smart_encoder = GST_SMART_ENCODER (element);
674
675   switch (transition) {
676     case GST_STATE_CHANGE_NULL_TO_READY:
677       /* Figure out which elements are available  */
678       if ((ret =
679               gst_smart_encoder_find_elements (smart_encoder)) ==
680           GST_STATE_CHANGE_FAILURE)
681         goto beach;
682       break;
683     default:
684       break;
685   }
686
687   ret =
688       GST_ELEMENT_CLASS (gst_smart_encoder_parent_class)->change_state (element,
689       transition);
690
691   switch (transition) {
692     case GST_STATE_CHANGE_PAUSED_TO_READY:
693       smart_encoder_reset (smart_encoder);
694       break;
695     default:
696       break;
697   }
698
699 beach:
700   return ret;
701 }