1 /* GStreamer Smart Video Encoder element
2 * Copyright (C) <2010> Edward Hervey <bilboed@gmail.com>
3 * Copyright (C) <2020> Thibault Saunier <tsaunier@igalia.com>
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.
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.
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.
26 #include "gstsmartencoder.h"
28 GST_DEBUG_CATEGORY_STATIC (smart_encoder_debug);
29 #define GST_CAT_DEFAULT smart_encoder_debug
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;"\
38 "video/mpeg,mpegversion=(int)1,systemstream=(boolean)false;"\
39 "video/mpeg,mpegversion=(int)2,systemstream=(boolean)false;"
41 static GstStaticPadTemplate src_template =
42 GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC,
44 GST_STATIC_CAPS (ALLOWED_CAPS)
47 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
50 GST_STATIC_CAPS (ALLOWED_CAPS)
53 G_DEFINE_TYPE (GstSmartEncoder, gst_smart_encoder, GST_TYPE_BIN);
56 smart_encoder_reset (GstSmartEncoder * self)
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);
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);
72 self->internal_sinkpad = NULL;
74 gst_clear_event (&self->segment_event);
78 translate_timestamp_from_internal_to_src (GstSmartEncoder * self,
81 GstClockTime running_time;
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;
91 gst_smart_encoder_finish_buffer (GstSmartEncoder * self, GstBuffer * buf)
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;
101 self->last_dts = GST_BUFFER_DTS (buf);
103 return gst_pad_push (self->srcpad, buf);
106 /*****************************************
107 * Internal encoder/decoder pipeline *
108 ******************************************/
110 internal_event_func (GstPad * pad, GstObject * parent, GstEvent * event)
112 GstSmartEncoder *self = GST_SMART_ENCODER (parent);
114 switch (GST_EVENT_TYPE (event)) {
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);
122 case GST_EVENT_SEGMENT:
123 gst_event_copy_segment (event, &self->internal_segment);
125 if (self->output_segment.format == GST_FORMAT_UNDEFINED) {
126 gst_segment_init (&self->output_segment, GST_FORMAT_TIME);
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!");
134 GST_ELEMENT_FLOW_ERROR (self, GST_FLOW_ERROR);
143 return gst_pad_push_event (self->srcpad, event);
149 return gst_pad_event_default (pad, parent, event);
153 internal_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
155 return gst_smart_encoder_finish_buffer (GST_SMART_ENCODER (parent), buf);
159 decodebin_src_pad_added_cb (GstElement * decodebin, GstPad * srcpad,
160 GstSmartEncoder * self)
162 GstPadLinkReturn ret = gst_pad_link (srcpad, self->encoder->sinkpads->data);
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);
174 setup_recoder_pipeline (GstSmartEncoder * self)
177 GstElement *capsfilter;
178 GstPadLinkReturn lret;
181 if (G_UNLIKELY (self->decoder))
184 g_assert (self->encoder);
185 GST_DEBUG ("Creating internal decoder and encoder");
187 /* Create decoder/encoder */
188 self->decoder = gst_element_factory_make ("decodebin", NULL);
189 if (G_UNLIKELY (self->decoder == NULL))
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));
197 GST_DEBUG_OBJECT (self, "Creating internal pads");
199 /* Create internal pads */
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);
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);
218 GST_DEBUG_OBJECT (self, "Linking pads to elements");
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!");
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");
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);
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);
243 GST_DEBUG ("Done creating internal elements/pads");
249 GST_WARNING ("Couldn't find a decodebin?!");
255 gst_object_unref (tmppad);
256 GST_WARNING ("Couldn't link internal srcpad to decoder");
262 gst_object_unref (tmppad);
263 GST_WARNING ("Couldn't link encoder to internal sinkpad: %s",
264 gst_pad_link_get_name (lret));
268 encoder_capsfilter_link_fail:
270 GST_WARNING ("Couldn't link encoder to capsfilter");
276 gst_smart_encoder_reencode_gop (GstSmartEncoder * self)
278 GstFlowReturn res = GST_FLOW_OK;
279 GstCaps *caps = NULL;
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;
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);
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));
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);
306 gst_pad_push_event (self->internal_srcpad,
307 gst_event_ref (self->segment_event));
309 /* Push buffers through our pads */
310 GST_DEBUG ("Pushing %d pending buffers", g_list_length (self->pending_gop));
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;
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");
327 if (res != GST_FLOW_OK) {
328 GST_WARNING ("Error pushing pending buffers : %s",
329 gst_flow_get_name (res));
334 GST_DEBUG_OBJECT (self, "-> Drain encoder.");
335 gst_pad_push_event (self->internal_srcpad, gst_event_new_eos ());
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);
341 g_mutex_unlock (&self->internal_flow_lock);
343 res = self->internal_flow;
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);
352 g_list_free_full (self->pending_gop, (GDestroyNotify) gst_buffer_unref);
353 self->pending_gop = NULL;
359 gst_smart_encoder_push_pending_gop (GstSmartEncoder * self)
361 guint64 cstart, cstop;
363 GstFlowReturn res = GST_FLOW_OK;
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));
368 if (!self->pending_gop) {
369 /* This might happen on EOS */
370 GST_INFO_OBJECT (self, "Empty gop!");
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);
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);
396 /* Make sure we push the original caps when resuming the original stream */
397 self->push_original_caps = TRUE;
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;
405 if (self->output_segment.format == GST_FORMAT_UNDEFINED) {
406 gst_segment_init (&self->output_segment, GST_FORMAT_TIME);
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!");
414 GST_ELEMENT_FLOW_ERROR (self, GST_FLOW_ERROR);
416 return GST_FLOW_ERROR;
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));
425 self->internal_segment = self->input_segment;
426 for (tmp = self->pending_gop; tmp; tmp = tmp->next) {
427 GstBuffer *buf = (GstBuffer *) tmp->data;
429 res = gst_smart_encoder_finish_buffer (self, buf);
430 if (G_UNLIKELY (res != GST_FLOW_OK))
436 g_list_free (self->pending_gop);
437 self->pending_gop = NULL;
438 self->gop_start = GST_CLOCK_TIME_NONE;
445 gst_smart_encoder_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
447 GstSmartEncoder *self;
448 GstFlowReturn res = GST_FLOW_OK;
449 gboolean discont, keyframe;
450 GstClockTime end_time;
452 self = GST_SMART_ENCODER (parent->parent);
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);
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));
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;
476 res = gst_smart_encoder_push_pending_gop (self);
477 if (G_UNLIKELY (res != GST_FLOW_OK))
481 /* Mark gop_start for new gop */
482 self->gop_start = GST_BUFFER_TIMESTAMP (buf);
486 self->pending_gop = g_list_append (self->pending_gop, buf);
488 /* Update GOP stop position */
489 if (GST_CLOCK_TIME_IS_VALID (end_time))
490 self->gop_stop = MAX (self->gop_stop, end_time);
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));
501 smart_encoder_sink_event (GstPad * pad, GstObject * ghostpad, GstEvent * event)
504 GstSmartEncoder *self = GST_SMART_ENCODER (ghostpad->parent);
506 switch (GST_EVENT_TYPE (event)) {
507 case GST_EVENT_FLUSH_STOP:
508 smart_encoder_reset (self);
514 gst_event_parse_caps (event, &caps);
515 if (self->original_caps)
516 gst_caps_unref (self->original_caps);
518 self->original_caps = gst_caps_ref (caps);
519 self->push_original_caps = TRUE;
520 gst_clear_event (&event);
523 case GST_EVENT_STREAM_START:
524 gst_event_replace (&self->stream_start_event, gst_event_ref (event));
526 case GST_EVENT_SEGMENT:
528 GST_INFO_OBJECT (self, "Pushing pending GOP on new segment");
529 gst_smart_encoder_push_pending_gop (self);
531 gst_event_copy_segment (event, &self->input_segment);
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);
542 self->segment_event = event;
544 GST_INFO_OBJECT (self, "Eating segment");
548 if (self->input_segment.format == GST_FORMAT_TIME)
549 gst_smart_encoder_push_pending_gop (self);
556 res = gst_pad_push_event (self->srcpad, event);
562 smart_encoder_sink_getcaps (GstSmartEncoder * self, GstPad * pad,
565 GstCaps *peer, *tmpl, *res;
567 tmpl = gst_static_pad_template_get_caps (&src_template);
569 /* Try getting it from downstream */
570 peer = gst_pad_peer_query_caps (self->srcpad, tmpl);
575 gst_caps_unref (tmpl);
579 GstCaps *filtered_res = gst_caps_intersect (res, filter);
581 gst_caps_unref (res);
582 if (!filtered_res || gst_caps_is_empty (filtered_res)) {
593 _pad_sink_acceptcaps (GstPad * pad, GstSmartEncoder * self, GstCaps * caps)
596 GstCaps *modified_caps;
597 GstCaps *accepted_caps;
601 GST_DEBUG_OBJECT (pad, "%" GST_PTR_FORMAT, caps);
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);
608 GST_LOG_OBJECT (pad, "src caps %" GST_PTR_FORMAT, accepted_caps);
610 n = gst_caps_get_size (accepted_caps);
611 for (i = 0; i < n; i++) {
612 s = gst_caps_get_structure (accepted_caps, i);
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",
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");
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);
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",
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");
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);
646 smart_encoder_sink_query (GstPad * pad, GstObject * ghostpad, GstQuery * query)
649 GstSmartEncoder *self = GST_SMART_ENCODER (ghostpad->parent);
651 switch (GST_QUERY_TYPE (query)) {
654 GstCaps *filter, *caps;
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);
664 case GST_QUERY_ACCEPT_CAPS:
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);
675 res = gst_pad_query_default (pad, ghostpad, query);
682 gst_smart_encoder_add_parser (GstSmartEncoder * self, GstCaps * format)
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);
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);
694 GST_ERROR_OBJECT (self, "`h264parse` is missing, can't encode smartly");
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);
703 if (!gst_bin_add (GST_BIN (self), parser)) {
704 GST_ERROR_OBJECT (self, "Could not add parser.");
709 if (!gst_element_link (parser, capsfilter)) {
710 GST_ERROR_OBJECT (self, "Could not link capfilter and parser.");
715 sinkpad = gst_element_get_static_pad (parser, "sink");
716 } else if (gst_structure_has_name (gst_caps_get_structure (format, 0),
718 GstElement *parser = gst_element_factory_make ("h265parse", NULL);
720 GST_ERROR_OBJECT (self, "`h265parse` is missing, can't encode smartly");
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);
729 if (!gst_bin_add (GST_BIN (self), parser)) {
730 GST_ERROR_OBJECT (self, "Could not add parser.");
735 if (!gst_element_link (parser, capsfilter)) {
736 GST_ERROR_OBJECT (self, "Could not link capfilter and parser.");
741 sinkpad = gst_element_get_static_pad (parser, "sink");
743 sinkpad = gst_element_get_static_pad (capsfilter, "sink");
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. */
753 GST_PAD (gst_ghost_pad_new ("chainpad", capsfilter->srcpads->data));
754 gst_element_add_pad (GST_ELEMENT (self), 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);
761 gst_ghost_pad_set_target (GST_GHOST_PAD (self->sinkpad), sinkpad);
762 gst_object_unref (sinkpad);
771 gst_smart_encoder_set_encoder (GstSmartEncoder * self, GstCaps * format,
772 GstElement * encoder)
774 self->encoder = g_object_ref_sink (encoder);
775 gst_element_set_locked_state (self->encoder, TRUE);
777 return gst_smart_encoder_add_parser (self, format);
780 /******************************************
781 * GstElement vmethod implementations *
782 ******************************************/
784 static GstStateChangeReturn
785 gst_smart_encoder_change_state (GstElement * element, GstStateChange transition)
787 GstSmartEncoder *self;
788 GstStateChangeReturn ret;
790 g_return_val_if_fail (GST_IS_SMART_ENCODER (element),
791 GST_STATE_CHANGE_FAILURE);
793 self = GST_SMART_ENCODER (element);
796 GST_ELEMENT_CLASS (gst_smart_encoder_parent_class)->change_state (element,
799 switch (transition) {
800 case GST_STATE_CHANGE_PAUSED_TO_READY:
801 smart_encoder_reset (self);
810 /******************************************
812 ******************************************/
814 gst_smart_encoder_finalize (GObject * object)
816 GstSmartEncoder *self = (GstSmartEncoder *) object;
817 g_mutex_clear (&self->internal_flow_lock);
818 g_cond_clear (&self->internal_flow_cond);
820 G_OBJECT_CLASS (gst_smart_encoder_parent_class)->finalize (object);
824 gst_smart_encoder_dispose (GObject * object)
826 GstSmartEncoder *self = (GstSmartEncoder *) object;
828 gst_clear_object (&self->encoder);
830 if (self->original_caps) {
831 gst_caps_unref (self->original_caps);
832 self->original_caps = NULL;
835 G_OBJECT_CLASS (gst_smart_encoder_parent_class)->dispose (object);
840 gst_smart_encoder_class_init (GstSmartEncoderClass * klass)
842 GObjectClass *gobject_class;
843 GstElementClass *element_class;
845 element_class = (GstElementClass *) klass;
846 gobject_class = G_OBJECT_CLASS (klass);
848 gst_smart_encoder_parent_class = g_type_class_peek_parent (klass);
850 gst_element_class_add_static_pad_template (element_class, &src_template);
851 gst_element_class_add_static_pad_template (element_class, &sink_template);
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>");
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;
862 GST_DEBUG_CATEGORY_INIT (smart_encoder_debug, "smartencoder", 0,
867 gst_smart_encoder_init (GstSmartEncoder * self)
869 GstPadTemplate *template = gst_static_pad_template_get (&sink_template);
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);
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);
879 g_mutex_init (&self->internal_flow_lock);
880 g_cond_init (&self->internal_flow_cond);
881 smart_encoder_reset (self);