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