smartencoder: Respect user `stream-format` when specified
[platform/upstream/gstreamer.git] / gst / encoding / gstsmartencoder.c
1 /* GStreamer Smart Video Encoder element
2  * Copyright (C) <2010> Edward Hervey <bilboed@gmail.com>
3  * Copyright (C) <2020> Thibault Saunier <tsaunier@igalia.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <string.h>
26 #include "gstsmartencoder.h"
27
28 GST_DEBUG_CATEGORY_STATIC (smart_encoder_debug);
29 #define GST_CAT_DEFAULT smart_encoder_debug
30
31 /* FIXME : Update this with new caps */
32 /* WARNING : We can only allow formats with closed-GOP */
33 #define ALLOWED_CAPS "video/x-h263;video/x-intel-h263;"\
34   "video/x-vp8;"\
35   "video/x-vp9;"\
36   "video/x-h264;"\
37   "video/x-h265;"\
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 G_DEFINE_TYPE (GstSmartEncoder, gst_smart_encoder, GST_TYPE_BIN);
54
55 static void
56 smart_encoder_reset (GstSmartEncoder * self)
57 {
58   gst_segment_init (&self->internal_segment, GST_FORMAT_UNDEFINED);
59   gst_segment_init (&self->input_segment, GST_FORMAT_UNDEFINED);
60   gst_segment_init (&self->output_segment, GST_FORMAT_UNDEFINED);
61
62   if (self->decoder) {
63     /* Clean up/remove internal encoding elements */
64     gst_element_set_state (self->encoder, GST_STATE_NULL);
65     gst_element_set_state (self->decoder, GST_STATE_NULL);
66     gst_clear_object (&self->internal_srcpad);
67     gst_element_remove_pad (GST_ELEMENT (self), self->internal_sinkpad);
68     gst_bin_remove (GST_BIN (self), gst_object_ref (self->encoder));
69     gst_bin_remove (GST_BIN (self), self->decoder);
70
71     self->decoder = NULL;
72     self->internal_sinkpad = NULL;
73   }
74   gst_clear_event (&self->segment_event);
75 }
76
77 static void
78 translate_timestamp_from_internal_to_src (GstSmartEncoder * self,
79     GstClockTime * ts)
80 {
81   GstClockTime running_time;
82
83   if (gst_segment_to_running_time_full (&self->internal_segment,
84           GST_FORMAT_TIME, *ts, &running_time) > 0)
85     *ts = running_time + self->output_segment.start;
86   else                          /* Negative timestamp */
87     *ts = self->output_segment.start - running_time;
88 }
89
90 static GstFlowReturn
91 gst_smart_encoder_finish_buffer (GstSmartEncoder * self, GstBuffer * buf)
92 {
93   translate_timestamp_from_internal_to_src (self, &GST_BUFFER_PTS (buf));
94   translate_timestamp_from_internal_to_src (self, &GST_BUFFER_DTS (buf));
95   GST_BUFFER_DTS (buf) = GST_BUFFER_DTS (buf);
96   if (self->last_dts > GST_BUFFER_DTS (buf)) {
97     /* Hack to always produces dts increasing DTS-s that are close to what the
98      * encoder produced. */
99     GST_BUFFER_DTS (buf) = self->last_dts + 1;
100   }
101   self->last_dts = GST_BUFFER_DTS (buf);
102
103   return gst_pad_push (self->srcpad, buf);
104 }
105
106 /*****************************************
107  *    Internal encoder/decoder pipeline  *
108  ******************************************/
109 static gboolean
110 internal_event_func (GstPad * pad, GstObject * parent, GstEvent * event)
111 {
112   GstSmartEncoder *self = GST_SMART_ENCODER (parent);
113
114   switch (GST_EVENT_TYPE (event)) {
115     case GST_EVENT_EOS:
116       g_mutex_lock (&self->internal_flow_lock);
117       if (self->internal_flow == GST_FLOW_CUSTOM_SUCCESS)
118         self->internal_flow = GST_FLOW_OK;
119       g_cond_signal (&self->internal_flow_cond);
120       g_mutex_unlock (&self->internal_flow_lock);
121       break;
122     case GST_EVENT_SEGMENT:
123       gst_event_copy_segment (event, &self->internal_segment);
124
125       if (self->output_segment.format == GST_FORMAT_UNDEFINED) {
126         gst_segment_init (&self->output_segment, GST_FORMAT_TIME);
127
128         /* Ensure that we can represent negative DTS in our 'single' segment */
129         self->output_segment.start = 60 * 60 * GST_SECOND * 1000;
130         if (!gst_pad_push_event (self->srcpad,
131                 gst_event_new_segment (&self->output_segment))) {
132           GST_ERROR_OBJECT (self, "Could not push segment!");
133
134           GST_ELEMENT_FLOW_ERROR (self, GST_FLOW_ERROR);
135
136           return FALSE;
137         }
138       }
139
140       break;
141     case GST_EVENT_CAPS:
142     {
143       return gst_pad_push_event (self->srcpad, event);
144     }
145     default:
146       break;
147   }
148
149   return gst_pad_event_default (pad, parent, event);
150 }
151
152 static GstFlowReturn
153 internal_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
154 {
155   return gst_smart_encoder_finish_buffer (GST_SMART_ENCODER (parent), buf);
156 }
157
158 static void
159 decodebin_src_pad_added_cb (GstElement * decodebin, GstPad * srcpad,
160     GstSmartEncoder * self)
161 {
162   GstPadLinkReturn ret = gst_pad_link (srcpad, self->encoder->sinkpads->data);
163
164   if (ret != GST_PAD_LINK_OK) {
165     GST_ERROR_OBJECT (self, "Could not link decoder with encoder! %s",
166         gst_pad_link_get_name (ret));
167     g_mutex_lock (&self->internal_flow_lock);
168     self->internal_flow = GST_FLOW_NOT_LINKED;
169     g_mutex_unlock (&self->internal_flow_lock);
170   }
171 }
172
173 static gboolean
174 setup_recoder_pipeline (GstSmartEncoder * self)
175 {
176   GstPad *tmppad;
177   GstElement *capsfilter;
178   GstPadLinkReturn lret;
179
180   /* Fast path */
181   if (G_UNLIKELY (self->decoder))
182     return TRUE;
183
184   g_assert (self->encoder);
185   GST_DEBUG ("Creating internal decoder and encoder");
186
187   /* Create decoder/encoder */
188   self->decoder = gst_element_factory_make ("decodebin", NULL);
189   if (G_UNLIKELY (self->decoder == NULL))
190     goto no_decoder;
191   g_signal_connect (self->decoder, "pad-added",
192       G_CALLBACK (decodebin_src_pad_added_cb), self);
193   gst_element_set_locked_state (self->decoder, TRUE);
194   gst_bin_add (GST_BIN (self), self->decoder);
195   gst_bin_add (GST_BIN (self), gst_object_ref (self->encoder));
196
197   GST_DEBUG_OBJECT (self, "Creating internal pads");
198
199   /* Create internal pads */
200
201   /* Source pad which we'll use to feed data to decoders */
202   self->internal_srcpad = gst_pad_new ("internal_src", GST_PAD_SRC);
203   self->internal_sinkpad = gst_pad_new ("internal_sink", GST_PAD_SINK);
204   gst_pad_set_iterate_internal_links_function (self->internal_sinkpad, NULL);
205   if (!gst_element_add_pad (GST_ELEMENT (self), self->internal_sinkpad)) {
206     GST_ERROR_OBJECT (self, "Could not add internal sinkpad %" GST_PTR_FORMAT,
207         self->internal_sinkpad);
208     return FALSE;
209   }
210
211   gst_pad_set_chain_function (self->internal_sinkpad,
212       GST_DEBUG_FUNCPTR (internal_chain));
213   gst_pad_set_event_function (self->internal_sinkpad,
214       GST_DEBUG_FUNCPTR (internal_event_func));
215   gst_pad_set_active (self->internal_sinkpad, TRUE);
216   gst_pad_set_active (self->internal_srcpad, TRUE);
217
218   GST_DEBUG_OBJECT (self, "Linking pads to elements");
219
220   /* Link everything */
221   capsfilter = gst_element_factory_make ("capsfilter", NULL);
222   if (!gst_bin_add (GST_BIN (self), capsfilter)) {
223     GST_ERROR_OBJECT (self, "Could not add capsfilter!");
224     return FALSE;
225   }
226
227   gst_element_sync_state_with_parent (capsfilter);
228   if (!gst_element_link (self->encoder, capsfilter))
229     goto encoder_capsfilter_link_fail;
230   tmppad = gst_element_get_static_pad (capsfilter, "src");
231   if ((lret =
232           gst_pad_link_full (tmppad, self->internal_sinkpad,
233               GST_PAD_LINK_CHECK_NOTHING)) < GST_PAD_LINK_OK)
234     goto sinkpad_link_fail;
235   gst_object_unref (tmppad);
236
237   tmppad = gst_element_get_static_pad (self->decoder, "sink");
238   if (GST_PAD_LINK_FAILED (gst_pad_link_full (self->internal_srcpad,
239               tmppad, GST_PAD_LINK_CHECK_NOTHING)))
240     goto srcpad_link_fail;
241   gst_object_unref (tmppad);
242
243   GST_DEBUG ("Done creating internal elements/pads");
244
245   return TRUE;
246
247 no_decoder:
248   {
249     GST_WARNING ("Couldn't find a decodebin?!");
250     return FALSE;
251   }
252
253 srcpad_link_fail:
254   {
255     gst_object_unref (tmppad);
256     GST_WARNING ("Couldn't link internal srcpad to decoder");
257     return FALSE;
258   }
259
260 sinkpad_link_fail:
261   {
262     gst_object_unref (tmppad);
263     GST_WARNING ("Couldn't link encoder to internal sinkpad: %s",
264         gst_pad_link_get_name (lret));
265     return FALSE;
266   }
267
268 encoder_capsfilter_link_fail:
269   {
270     GST_WARNING ("Couldn't link encoder to capsfilter");
271     return FALSE;
272   }
273 }
274
275 static GstFlowReturn
276 gst_smart_encoder_reencode_gop (GstSmartEncoder * self)
277 {
278   GstFlowReturn res = GST_FLOW_OK;
279   GstCaps *caps = NULL;
280
281   GST_DEBUG_OBJECT (self, "Reencoding GOP!");
282   if (self->decoder == NULL) {
283     if (!setup_recoder_pipeline (self)) {
284       GST_ERROR_OBJECT (self, "Could not setup reencoder pipeline");
285       return GST_FLOW_ERROR;
286     }
287   }
288
289   /* Activate elements */
290   /* Set elements to PAUSED */
291   gst_element_set_state (self->encoder, GST_STATE_PLAYING);
292   gst_element_set_state (self->decoder, GST_STATE_PLAYING);
293
294   GST_INFO ("Pushing Flush start/stop to clean decoder/encoder");
295   gst_pad_push_event (self->internal_srcpad, gst_event_new_flush_start ());
296   gst_pad_push_event (self->internal_srcpad, gst_event_new_flush_stop (TRUE));
297
298   /* push segment_event */
299   GST_INFO ("Pushing segment_event %" GST_PTR_FORMAT, self->segment_event);
300   gst_pad_push_event (self->internal_srcpad,
301       gst_event_ref (self->stream_start_event));
302   caps = gst_pad_get_current_caps (self->sinkpad);
303   gst_pad_push_event (self->internal_srcpad, gst_event_new_caps (caps));
304   gst_caps_unref (caps);
305
306   gst_pad_push_event (self->internal_srcpad,
307       gst_event_ref (self->segment_event));
308
309   /* Push buffers through our pads */
310   GST_DEBUG ("Pushing %d pending buffers", g_list_length (self->pending_gop));
311
312   g_mutex_lock (&self->internal_flow_lock);
313   self->internal_flow = GST_FLOW_CUSTOM_SUCCESS;
314   g_mutex_unlock (&self->internal_flow_lock);
315   while (self->pending_gop) {
316     GstBuffer *buf = (GstBuffer *) self->pending_gop->data;
317
318     self->pending_gop =
319         g_list_remove_link (self->pending_gop, self->pending_gop);
320     res = gst_pad_push (self->internal_srcpad, buf);
321     if (res == GST_FLOW_EOS) {
322       GST_INFO_OBJECT (self, "Got eos... waiting for the event"
323           " waiting for encoding to be done");
324       break;
325     }
326
327     if (res != GST_FLOW_OK) {
328       GST_WARNING ("Error pushing pending buffers : %s",
329           gst_flow_get_name (res));
330       goto done;
331     }
332   }
333
334   GST_DEBUG_OBJECT (self, "-> Drain encoder.");
335   gst_pad_push_event (self->internal_srcpad, gst_event_new_eos ());
336
337   g_mutex_lock (&self->internal_flow_lock);
338   while (self->internal_flow == GST_FLOW_CUSTOM_SUCCESS) {
339     g_cond_wait (&self->internal_flow_cond, &self->internal_flow_lock);
340   }
341   g_mutex_unlock (&self->internal_flow_lock);
342
343   res = self->internal_flow;
344
345   GST_DEBUG_OBJECT (self, "Done reencoding GOP.");
346   gst_element_set_state (self->encoder, GST_STATE_NULL);
347   gst_element_set_state (self->decoder, GST_STATE_NULL);
348   GST_OBJECT_FLAG_UNSET (self->internal_sinkpad, GST_PAD_FLAG_EOS);
349   GST_OBJECT_FLAG_UNSET (self->internal_srcpad, GST_PAD_FLAG_EOS);
350
351 done:
352   g_list_free_full (self->pending_gop, (GDestroyNotify) gst_buffer_unref);
353   self->pending_gop = NULL;
354
355   return res;
356 }
357
358 static GstFlowReturn
359 gst_smart_encoder_push_pending_gop (GstSmartEncoder * self)
360 {
361   guint64 cstart, cstop;
362   GList *tmp;
363   GstFlowReturn res = GST_FLOW_OK;
364
365   GST_DEBUG ("Pushing pending GOP (%" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT
366       ")", GST_TIME_ARGS (self->gop_start), GST_TIME_ARGS (self->gop_stop));
367
368   if (!self->pending_gop) {
369     /* This might happen on EOS */
370     GST_INFO_OBJECT (self, "Empty gop!");
371     goto done;
372   }
373
374   if (!gst_segment_clip (&self->input_segment, GST_FORMAT_TIME, self->gop_start,
375           self->gop_stop, &cstart, &cstop)) {
376     /* The whole GOP is outside the segment, there's most likely
377      * a bug somewhere. */
378     GST_DEBUG_OBJECT (self,
379         "GOP is entirely outside of the segment, upstream gave us too much data: (%"
380         GST_TIME_FORMAT " -- %" GST_TIME_FORMAT ")",
381         GST_TIME_ARGS (self->gop_start), GST_TIME_ARGS (self->gop_stop));
382     for (tmp = self->pending_gop; tmp; tmp = tmp->next)
383       gst_buffer_unref ((GstBuffer *) tmp->data);
384
385     goto done;
386   }
387
388   if ((cstart != self->gop_start)
389       || (cstop != self->gop_stop)) {
390     GST_INFO_OBJECT (self,
391         "GOP needs to be re-encoded from %" GST_TIME_FORMAT " to %"
392         GST_TIME_FORMAT " - %" GST_SEGMENT_FORMAT, GST_TIME_ARGS (cstart),
393         GST_TIME_ARGS (cstop), &self->input_segment);
394     res = gst_smart_encoder_reencode_gop (self);
395
396     /* Make sure we push the original caps when resuming the original stream */
397     self->push_original_caps = TRUE;
398   } else {
399     if (self->push_original_caps) {
400       gst_pad_push_event (self->srcpad,
401           gst_event_new_caps (self->original_caps));
402       self->push_original_caps = FALSE;
403     }
404
405     if (self->output_segment.format == GST_FORMAT_UNDEFINED) {
406       gst_segment_init (&self->output_segment, GST_FORMAT_TIME);
407
408       /* Ensure that we can represent negative DTS in our 'single' segment */
409       self->output_segment.start = 60 * 60 * GST_SECOND * 1000;
410       if (!gst_pad_push_event (self->srcpad,
411               gst_event_new_segment (&self->output_segment))) {
412         GST_ERROR_OBJECT (self, "Could not push segment!");
413
414         GST_ELEMENT_FLOW_ERROR (self, GST_FLOW_ERROR);
415
416         return GST_FLOW_ERROR;
417       }
418     }
419
420     /* The whole GOP is within the segment, push all pending buffers downstream */
421     GST_INFO_OBJECT (self,
422         "GOP doesn't need to be modified, pushing downstream: %" GST_TIME_FORMAT
423         " to %" GST_TIME_FORMAT, GST_TIME_ARGS (cstart), GST_TIME_ARGS (cstop));
424
425     self->internal_segment = self->input_segment;
426     for (tmp = self->pending_gop; tmp; tmp = tmp->next) {
427       GstBuffer *buf = (GstBuffer *) tmp->data;
428
429       res = gst_smart_encoder_finish_buffer (self, buf);
430       if (G_UNLIKELY (res != GST_FLOW_OK))
431         break;
432     }
433   }
434
435 done:
436   g_list_free (self->pending_gop);
437   self->pending_gop = NULL;
438   self->gop_start = GST_CLOCK_TIME_NONE;
439   self->gop_stop = 0;
440
441   return res;
442 }
443
444 static GstFlowReturn
445 gst_smart_encoder_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
446 {
447   GstSmartEncoder *self;
448   GstFlowReturn res = GST_FLOW_OK;
449   gboolean discont, keyframe;
450   GstClockTime end_time;
451
452   self = GST_SMART_ENCODER (parent->parent);
453
454   discont = GST_BUFFER_IS_DISCONT (buf);
455   keyframe = !GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
456   end_time = GST_BUFFER_PTS (buf);
457   if (GST_CLOCK_TIME_IS_VALID (end_time))
458     end_time += (GST_BUFFER_DURATION_IS_VALID (buf) ? buf->duration : 0);
459
460   GST_DEBUG_OBJECT (pad,
461       "New buffer %s %s %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
462       discont ? "discont" : "", keyframe ? "keyframe" : "",
463       GST_TIME_ARGS (GST_BUFFER_PTS (buf)), GST_TIME_ARGS (end_time));
464
465   if (keyframe) {
466     /* If there's a pending GOP, flush it out */
467     if (self->pending_gop) {
468       /* Mark stop of previous gop */
469       if (GST_BUFFER_PTS_IS_VALID (buf)) {
470         if (self->gop_stop > buf->pts)
471           GST_WARNING_OBJECT (self, "Next gop start < current gop" " end");
472         self->gop_stop = buf->pts;
473       }
474
475       /* flush pending */
476       res = gst_smart_encoder_push_pending_gop (self);
477       if (G_UNLIKELY (res != GST_FLOW_OK))
478         goto beach;
479     }
480
481     /* Mark gop_start for new gop */
482     self->gop_start = GST_BUFFER_TIMESTAMP (buf);
483   }
484
485   /* Store buffer */
486   self->pending_gop = g_list_append (self->pending_gop, buf);
487
488   /* Update GOP stop position */
489   if (GST_CLOCK_TIME_IS_VALID (end_time))
490     self->gop_stop = MAX (self->gop_stop, end_time);
491
492   GST_DEBUG_OBJECT (self, "Buffer stored , Current GOP : %"
493       GST_TIME_FORMAT " -- %" GST_TIME_FORMAT,
494       GST_TIME_ARGS (self->gop_start), GST_TIME_ARGS (self->gop_stop));
495
496 beach:
497   return res;
498 }
499
500 static gboolean
501 smart_encoder_sink_event (GstPad * pad, GstObject * ghostpad, GstEvent * event)
502 {
503   gboolean res = TRUE;
504   GstSmartEncoder *self = GST_SMART_ENCODER (ghostpad->parent);
505
506   switch (GST_EVENT_TYPE (event)) {
507     case GST_EVENT_FLUSH_STOP:
508       smart_encoder_reset (self);
509       break;
510     case GST_EVENT_CAPS:
511     {
512       GstCaps *caps;
513
514       gst_event_parse_caps (event, &caps);
515       if (self->original_caps)
516         gst_caps_unref (self->original_caps);
517
518       self->original_caps = gst_caps_ref (caps);
519       self->push_original_caps = TRUE;
520       gst_clear_event (&event);
521       break;
522     }
523     case GST_EVENT_STREAM_START:
524       gst_event_replace (&self->stream_start_event, gst_event_ref (event));
525       break;
526     case GST_EVENT_SEGMENT:
527     {
528       GST_INFO_OBJECT (self, "Pushing pending GOP on new segment");
529       gst_smart_encoder_push_pending_gop (self);
530
531       gst_event_copy_segment (event, &self->input_segment);
532
533       GST_DEBUG_OBJECT (self, "input_segment: %" GST_SEGMENT_FORMAT,
534           &self->input_segment);
535       if (self->input_segment.format != GST_FORMAT_TIME) {
536         GST_ERROR_OBJECT (self, "Can't handle streams %s format",
537             gst_format_get_name (self->input_segment.format));
538         gst_event_unref (event);
539
540         return FALSE;
541       }
542       self->segment_event = event;
543       event = NULL;
544       GST_INFO_OBJECT (self, "Eating segment");
545       break;
546     }
547     case GST_EVENT_EOS:
548       if (self->input_segment.format == GST_FORMAT_TIME)
549         gst_smart_encoder_push_pending_gop (self);
550       break;
551     default:
552       break;
553   }
554
555   if (event)
556     res = gst_pad_push_event (self->srcpad, event);
557
558   return res;
559 }
560
561 static GstCaps *
562 smart_encoder_sink_getcaps (GstSmartEncoder * self, GstPad * pad,
563     GstCaps * filter)
564 {
565   GstCaps *peer, *tmpl, *res;
566
567   tmpl = gst_static_pad_template_get_caps (&src_template);
568
569   /* Try getting it from downstream */
570   peer = gst_pad_peer_query_caps (self->srcpad, tmpl);
571   if (peer == NULL) {
572     res = tmpl;
573   } else {
574     res = peer;
575     gst_caps_unref (tmpl);
576   }
577
578   if (filter) {
579     GstCaps *filtered_res = gst_caps_intersect (res, filter);
580
581     gst_caps_unref (res);
582     if (!filtered_res || gst_caps_is_empty (filtered_res)) {
583       res = NULL;
584     } else {
585       res = filtered_res;
586     }
587   }
588
589   return res;
590 }
591
592 static gboolean
593 _pad_sink_acceptcaps (GstPad * pad, GstSmartEncoder * self, GstCaps * caps)
594 {
595   gboolean ret;
596   GstCaps *modified_caps;
597   GstCaps *accepted_caps;
598   gint i, n;
599   GstStructure *s;
600
601   GST_DEBUG_OBJECT (pad, "%" GST_PTR_FORMAT, caps);
602
603   accepted_caps = gst_pad_get_current_caps (GST_PAD (self->srcpad));
604   if (accepted_caps == NULL)
605     accepted_caps = gst_pad_get_pad_template_caps (GST_PAD (self->srcpad));
606   accepted_caps = gst_caps_make_writable (accepted_caps);
607
608   GST_LOG_OBJECT (pad, "src caps %" GST_PTR_FORMAT, accepted_caps);
609
610   n = gst_caps_get_size (accepted_caps);
611   for (i = 0; i < n; i++) {
612     s = gst_caps_get_structure (accepted_caps, i);
613
614     if (gst_structure_has_name (s, "video/x-h264") ||
615         gst_structure_has_name (s, "video/x-h265")) {
616       gst_structure_remove_fields (s, "codec_data", "tier", "profile", "level",
617           NULL);
618     } else if (gst_structure_has_name (s, "video/x-vp8")
619         || gst_structure_has_name (s, "video/x-vp9")) {
620       gst_structure_remove_field (s, "streamheader");
621     }
622   }
623
624   modified_caps = gst_caps_copy (caps);
625   n = gst_caps_get_size (modified_caps);
626   for (i = 0; i < n; i++) {
627     s = gst_caps_get_structure (modified_caps, i);
628
629     if (gst_structure_has_name (s, "video/x-h264") ||
630         gst_structure_has_name (s, "video/x-h265")) {
631       gst_structure_remove_fields (s, "codec_data", "tier", "profile", "level",
632           NULL);
633     } else if (gst_structure_has_name (s, "video/x-vp8")
634         || gst_structure_has_name (s, "video/x-vp9")) {
635       gst_structure_remove_field (s, "streamheader");
636     }
637   }
638
639   ret = gst_caps_can_intersect (modified_caps, accepted_caps);
640   GST_DEBUG_OBJECT (pad, "%saccepted caps %" GST_PTR_FORMAT,
641       (ret ? "" : "Doesn't "), caps);
642   return ret;
643 }
644
645 static gboolean
646 smart_encoder_sink_query (GstPad * pad, GstObject * ghostpad, GstQuery * query)
647 {
648   gboolean res;
649   GstSmartEncoder *self = GST_SMART_ENCODER (ghostpad->parent);
650
651   switch (GST_QUERY_TYPE (query)) {
652     case GST_QUERY_CAPS:
653     {
654       GstCaps *filter, *caps;
655
656       gst_query_parse_caps (query, &filter);
657       caps = smart_encoder_sink_getcaps (self, pad, filter);
658       GST_DEBUG_OBJECT (self, "Got caps: %" GST_PTR_FORMAT, caps);
659       gst_query_set_caps_result (query, caps);
660       gst_caps_unref (caps);
661       res = TRUE;
662       break;
663     }
664     case GST_QUERY_ACCEPT_CAPS:
665     {
666       GstCaps *caps;
667
668       gst_query_parse_accept_caps (query, &caps);
669       res = _pad_sink_acceptcaps (GST_PAD (pad), self, caps);
670       gst_query_set_accept_caps_result (query, res);
671       res = TRUE;
672       break;
673     }
674     default:
675       res = gst_pad_query_default (pad, ghostpad, query);
676       break;
677   }
678   return res;
679 }
680
681 static gboolean
682 gst_smart_encoder_add_parser (GstSmartEncoder * self, GstCaps * format)
683 {
684   const gchar *stream_format;
685   GstPad *chainpad, *internal_chainpad, *sinkpad;
686   GstStructure *structure = gst_caps_get_structure (format, 0);
687   GstElement *capsfilter = gst_element_factory_make ("capsfilter", NULL);
688
689   gst_bin_add (GST_BIN (self), capsfilter);
690   g_object_set (capsfilter, "caps", format, NULL);
691   if (gst_structure_has_name (structure, "video/x-h264")) {
692     GstElement *parser = gst_element_factory_make ("h264parse", NULL);
693     if (!parser) {
694       GST_ERROR_OBJECT (self, "`h264parse` is missing, can't encode smartly");
695
696       goto failed;
697     }
698
699     stream_format = gst_structure_get_string (structure, "stream-format");
700     if (g_strcmp0 (stream_format, "avc1"))
701       g_object_set (parser, "config-interval", -1, NULL);
702
703     if (!gst_bin_add (GST_BIN (self), parser)) {
704       GST_ERROR_OBJECT (self, "Could not add parser.");
705
706       goto failed;
707     }
708
709     if (!gst_element_link (parser, capsfilter)) {
710       GST_ERROR_OBJECT (self, "Could not link capfilter and parser.");
711
712       goto failed;
713     }
714
715     sinkpad = gst_element_get_static_pad (parser, "sink");
716   } else if (gst_structure_has_name (gst_caps_get_structure (format, 0),
717           "video/x-h265")) {
718     GstElement *parser = gst_element_factory_make ("h265parse", NULL);
719     if (!parser) {
720       GST_ERROR_OBJECT (self, "`h265parse` is missing, can't encode smartly");
721
722       goto failed;
723     }
724
725     stream_format = gst_structure_get_string (structure, "stream-format");
726     if (g_strcmp0 (stream_format, "hvc1"))
727       g_object_set (parser, "config-interval", -1, NULL);
728
729     if (!gst_bin_add (GST_BIN (self), parser)) {
730       GST_ERROR_OBJECT (self, "Could not add parser.");
731
732       goto failed;
733     }
734
735     if (!gst_element_link (parser, capsfilter)) {
736       GST_ERROR_OBJECT (self, "Could not link capfilter and parser.");
737
738       goto failed;
739     }
740
741     sinkpad = gst_element_get_static_pad (parser, "sink");
742   } else {
743     sinkpad = gst_element_get_static_pad (capsfilter, "sink");
744   }
745
746   g_assert (sinkpad);
747
748   /* The chainpad is the pad that is linked to the srcpad of the chain
749    * of element that is linked to our public sinkpad, this is the pad where
750    * we chain the buffers either directly to our srcpad or through the
751    * reencoding sub chain. */
752   chainpad =
753       GST_PAD (gst_ghost_pad_new ("chainpad", capsfilter->srcpads->data));
754   gst_element_add_pad (GST_ELEMENT (self), chainpad);
755   internal_chainpad =
756       GST_PAD (gst_proxy_pad_get_internal (GST_PROXY_PAD (chainpad)));
757   gst_pad_set_chain_function (internal_chainpad, gst_smart_encoder_chain);
758   gst_pad_set_event_function (internal_chainpad, smart_encoder_sink_event);
759   gst_pad_set_query_function (internal_chainpad, smart_encoder_sink_query);
760
761   gst_ghost_pad_set_target (GST_GHOST_PAD (self->sinkpad), sinkpad);
762   gst_object_unref (sinkpad);
763
764   return TRUE;
765
766 failed:
767   return FALSE;
768 }
769
770 gboolean
771 gst_smart_encoder_set_encoder (GstSmartEncoder * self, GstCaps * format,
772     GstElement * encoder)
773 {
774   self->encoder = g_object_ref_sink (encoder);
775   gst_element_set_locked_state (self->encoder, TRUE);
776
777   return gst_smart_encoder_add_parser (self, format);
778 }
779
780 /******************************************
781  *    GstElement vmethod implementations  *
782  ******************************************/
783
784 static GstStateChangeReturn
785 gst_smart_encoder_change_state (GstElement * element, GstStateChange transition)
786 {
787   GstSmartEncoder *self;
788   GstStateChangeReturn ret;
789
790   g_return_val_if_fail (GST_IS_SMART_ENCODER (element),
791       GST_STATE_CHANGE_FAILURE);
792
793   self = GST_SMART_ENCODER (element);
794
795   ret =
796       GST_ELEMENT_CLASS (gst_smart_encoder_parent_class)->change_state (element,
797       transition);
798
799   switch (transition) {
800     case GST_STATE_CHANGE_PAUSED_TO_READY:
801       smart_encoder_reset (self);
802       break;
803     default:
804       break;
805   }
806
807   return ret;
808 }
809
810 /******************************************
811  *          GObject vmethods              *
812  ******************************************/
813 static void
814 gst_smart_encoder_finalize (GObject * object)
815 {
816   GstSmartEncoder *self = (GstSmartEncoder *) object;
817   g_mutex_clear (&self->internal_flow_lock);
818   g_cond_clear (&self->internal_flow_cond);
819
820   G_OBJECT_CLASS (gst_smart_encoder_parent_class)->finalize (object);
821 }
822
823 static void
824 gst_smart_encoder_dispose (GObject * object)
825 {
826   GstSmartEncoder *self = (GstSmartEncoder *) object;
827
828   gst_clear_object (&self->encoder);
829
830   if (self->original_caps) {
831     gst_caps_unref (self->original_caps);
832     self->original_caps = NULL;
833   }
834
835   G_OBJECT_CLASS (gst_smart_encoder_parent_class)->dispose (object);
836 }
837
838
839 static void
840 gst_smart_encoder_class_init (GstSmartEncoderClass * klass)
841 {
842   GObjectClass *gobject_class;
843   GstElementClass *element_class;
844
845   element_class = (GstElementClass *) klass;
846   gobject_class = G_OBJECT_CLASS (klass);
847
848   gst_smart_encoder_parent_class = g_type_class_peek_parent (klass);
849
850   gst_element_class_add_static_pad_template (element_class, &src_template);
851   gst_element_class_add_static_pad_template (element_class, &sink_template);
852
853   gst_element_class_set_static_metadata (element_class, "Smart Video Encoder",
854       "Codec/Recoder/Video",
855       "Re-encodes portions of Video that lay on segment boundaries",
856       "Edward Hervey <bilboed@gmail.com>");
857
858   gobject_class->dispose = (GObjectFinalizeFunc) gst_smart_encoder_dispose;
859   gobject_class->finalize = (GObjectFinalizeFunc) gst_smart_encoder_finalize;
860   element_class->change_state = gst_smart_encoder_change_state;
861
862   GST_DEBUG_CATEGORY_INIT (smart_encoder_debug, "smartencoder", 0,
863       "Smart Encoder");
864 }
865
866 static void
867 gst_smart_encoder_init (GstSmartEncoder * self)
868 {
869   GstPadTemplate *template = gst_static_pad_template_get (&sink_template);
870
871   self->sinkpad = gst_ghost_pad_new_no_target_from_template ("sink", template);
872   gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
873   gst_object_unref (template);
874
875   self->srcpad = gst_pad_new_from_static_template (&src_template, "src");
876   gst_pad_use_fixed_caps (self->srcpad);
877   gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
878
879   g_mutex_init (&self->internal_flow_lock);
880   g_cond_init (&self->internal_flow_cond);
881   smart_encoder_reset (self);
882 }