1 /* GStreamer H265 encoder plugin
2  * Copyright (C) 2005 Michal Benes <michal.benes@itonis.tv>
3  * Copyright (C) 2005 Josef Zlomek <josef.zlomek@itonis.tv>
4  * Copyright (C) 2008 Mark Nauwelaerts <mnauw@users.sf.net>
5  * Copyright (C) 2014 Thijs Vermeir <thijs.vermeir@barco.com>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22 
23 /**
24  * SECTION:element-x265enc
25  * @title: x265enc
26  *
27  * This element encodes raw video into H265 compressed data.
28  *
29  **/
30 
31 #ifdef HAVE_CONFIG_H
32 #  include "config.h"
33 #endif
34 
35 #include "gstx265enc.h"
36 
37 #include <gst/pbutils/pbutils.h>
38 #include <gst/video/video.h>
39 #include <gst/video/gstvideometa.h>
40 #include <gst/video/gstvideopool.h>
41 
42 #include <string.h>
43 #include <stdlib.h>
44 
45 GST_DEBUG_CATEGORY_STATIC (x265_enc_debug);
46 #define GST_CAT_DEFAULT x265_enc_debug
47 
48 enum
49 {
50   PROP_0,
51   PROP_BITRATE,
52   PROP_QP,
53   PROP_OPTION_STRING,
54   PROP_X265_LOG_LEVEL,
55   PROP_SPEED_PRESET,
56   PROP_TUNE,
57   PROP_KEY_INT_MAX
58 };
59 
60 #define PROP_BITRATE_DEFAULT            (2 * 1024)
61 #define PROP_QP_DEFAULT                 -1
62 #define PROP_OPTION_STRING_DEFAULT      ""
63 #define PROP_LOG_LEVEL_DEFAULT           -1     /* None   */
64 #define PROP_SPEED_PRESET_DEFAULT        6      /* Medium */
65 #define PROP_TUNE_DEFAULT                2      /* SSIM   */
66 #define PROP_KEY_INT_MAX_DEFAULT         0      /* x265 lib default */
67 
68 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
69 #define FORMATS "I420, Y444, I420_10LE, Y444_10LE"
70 #else
71 #define FORMATS "I420, Y444, I420_10BE, Y444_10BE"
72 #endif
73 
74 #define GST_X265_ENC_LOG_LEVEL_TYPE (gst_x265_enc_log_level_get_type())
75 static GType
gst_x265_enc_log_level_get_type(void)76 gst_x265_enc_log_level_get_type (void)
77 {
78   static GType log_level = 0;
79 
80   static const GEnumValue log_levels[] = {
81     {X265_LOG_NONE, "No logging", "none"},
82     {X265_LOG_ERROR, "Error", "error"},
83     {X265_LOG_WARNING, "Warning", "warning"},
84     {X265_LOG_INFO, "Info", "info"},
85     {X265_LOG_DEBUG, "Debug", "debug"},
86     {X265_LOG_FULL, "Full", "full"},
87     {0, NULL, NULL}
88   };
89 
90   if (!log_level) {
91     log_level = g_enum_register_static ("GstX265LogLevel", log_levels);
92   }
93   return log_level;
94 }
95 
96 #define GST_X265_ENC_SPEED_PRESET_TYPE (gst_x265_enc_speed_preset_get_type())
97 static GType
gst_x265_enc_speed_preset_get_type(void)98 gst_x265_enc_speed_preset_get_type (void)
99 {
100   static GType speed_preset = 0;
101   static GEnumValue *speed_presets;
102   int n, i;
103 
104   if (speed_preset != 0)
105     return speed_preset;
106 
107   n = 0;
108   while (x265_preset_names[n] != NULL)
109     n++;
110 
111   speed_presets = g_new0 (GEnumValue, n + 2);
112 
113   speed_presets[0].value = 0;
114   speed_presets[0].value_name = "No preset";
115   speed_presets[0].value_nick = "No preset";
116 
117   for (i = 0; i < n; i++) {
118     speed_presets[i + 1].value = i + 1;
119     speed_presets[i + 1].value_name = x265_preset_names[i];
120     speed_presets[i + 1].value_nick = x265_preset_names[i];
121   }
122 
123   speed_preset = g_enum_register_static ("GstX265SpeedPreset", speed_presets);
124 
125   return speed_preset;
126 }
127 
128 #define GST_X265_ENC_TUNE_TYPE (gst_x265_enc_tune_get_type())
129 static GType
gst_x265_enc_tune_get_type(void)130 gst_x265_enc_tune_get_type (void)
131 {
132   static GType tune = 0;
133   static GEnumValue *tune_values;
134   int n, i;
135 
136   if (tune != 0)
137     return tune;
138 
139   n = 0;
140   while (x265_tune_names[n] != NULL)
141     n++;
142 
143   tune_values = g_new0 (GEnumValue, n + 2);
144 
145   tune_values[0].value = 0;
146   tune_values[0].value_name = "No tunning";
147   tune_values[0].value_nick = "No tunning";
148 
149   for (i = 0; i < n; i++) {
150     tune_values[i + 1].value = i + 1;
151     tune_values[i + 1].value_name = x265_tune_names[i];
152     tune_values[i + 1].value_nick = x265_tune_names[i];
153   }
154 
155   tune = g_enum_register_static ("GstX265Tune", tune_values);
156 
157   return tune;
158 }
159 
160 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
161     GST_PAD_SINK,
162     GST_PAD_ALWAYS,
163     GST_STATIC_CAPS ("video/x-raw, "
164         "format = (string) { " FORMATS " }, "
165         "framerate = (fraction) [0, MAX], "
166         "width = (int) [ 4, MAX ], " "height = (int) [ 4, MAX ]")
167     );
168 
169 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
170     GST_PAD_SRC,
171     GST_PAD_ALWAYS,
172     GST_STATIC_CAPS ("video/x-h265, "
173         "framerate = (fraction) [0/1, MAX], "
174         "width = (int) [ 4, MAX ], " "height = (int) [ 4, MAX ], "
175         "stream-format = (string) byte-stream, "
176         "alignment = (string) au, " "profile = (string) { main }")
177     );
178 
179 static void gst_x265_enc_finalize (GObject * object);
180 static gboolean gst_x265_enc_start (GstVideoEncoder * encoder);
181 static gboolean gst_x265_enc_stop (GstVideoEncoder * encoder);
182 static gboolean gst_x265_enc_flush (GstVideoEncoder * encoder);
183 
184 static gboolean gst_x265_enc_init_encoder (GstX265Enc * encoder);
185 static void gst_x265_enc_close_encoder (GstX265Enc * encoder);
186 
187 static GstFlowReturn gst_x265_enc_finish (GstVideoEncoder * encoder);
188 static GstFlowReturn gst_x265_enc_handle_frame (GstVideoEncoder * encoder,
189     GstVideoCodecFrame * frame);
190 static void gst_x265_enc_flush_frames (GstX265Enc * encoder, gboolean send);
191 static GstFlowReturn gst_x265_enc_encode_frame (GstX265Enc * encoder,
192     x265_picture * pic_in, GstVideoCodecFrame * input_frame, guint32 * i_nal,
193     gboolean send);
194 static gboolean gst_x265_enc_set_format (GstVideoEncoder * video_enc,
195     GstVideoCodecState * state);
196 static gboolean gst_x265_enc_propose_allocation (GstVideoEncoder * encoder,
197     GstQuery * query);
198 
199 static void gst_x265_enc_set_property (GObject * object, guint prop_id,
200     const GValue * value, GParamSpec * pspec);
201 static void gst_x265_enc_get_property (GObject * object, guint prop_id,
202     GValue * value, GParamSpec * pspec);
203 
204 #define gst_x265_enc_parent_class parent_class
205 G_DEFINE_TYPE_WITH_CODE (GstX265Enc, gst_x265_enc, GST_TYPE_VIDEO_ENCODER,
206     G_IMPLEMENT_INTERFACE (GST_TYPE_PRESET, NULL));
207 
208 static void
set_value(GValue * val,gint count,...)209 set_value (GValue * val, gint count, ...)
210 {
211   const gchar *fmt = NULL;
212   GValue sval = G_VALUE_INIT;
213   va_list ap;
214   gint i;
215 
216   g_value_init (&sval, G_TYPE_STRING);
217 
218   if (count > 1)
219     g_value_init (val, GST_TYPE_LIST);
220 
221   va_start (ap, count);
222   for (i = 0; i < count; i++) {
223     fmt = va_arg (ap, const gchar *);
224     g_value_set_string (&sval, fmt);
225     if (count > 1) {
226       gst_value_list_append_value (val, &sval);
227     }
228   }
229   va_end (ap);
230 
231   if (count == 1)
232     *val = sval;
233   else
234     g_value_unset (&sval);
235 }
236 
237 static void
gst_x265_enc_add_x265_chroma_format(GstStructure * s,int x265_chroma_format_local)238 gst_x265_enc_add_x265_chroma_format (GstStructure * s,
239     int x265_chroma_format_local)
240 {
241   GValue fmt = G_VALUE_INIT;
242 
243   if (x265_max_bit_depth >= 10) {
244     GST_INFO ("This x265 build supports %d-bit depth", x265_max_bit_depth);
245     if (x265_chroma_format_local == 0) {
246 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
247       set_value (&fmt, 4, "I420", "Y444", "I420_10LE", "Y444_10LE");
248 #else
249       set_value (&fmt, 4, "I420", "Y444", "I420_10BE", "Y444_10BE");
250 #endif
251     } else if (x265_chroma_format_local == X265_CSP_I444) {
252 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
253       set_value (&fmt, 2, "Y444", "Y444_10LE");
254 #else
255       set_value (&fmt, 2, "Y444", "Y444_10BE");
256 #endif
257     } else if (x265_chroma_format_local == X265_CSP_I420) {
258 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
259       set_value (&fmt, 2, "I420", "I420_10LE");
260 #else
261       set_value (&fmt, 2, "I420", "I420_10BE");
262 #endif
263     } else {
264       GST_ERROR ("Unsupported chroma format %d", x265_chroma_format_local);
265     }
266   } else if (x265_max_bit_depth == 8) {
267     GST_INFO ("This x265 build supports 8-bit depth");
268     if (x265_chroma_format_local == 0) {
269       set_value (&fmt, 2, "I420", "Y444");
270     } else if (x265_chroma_format_local == X265_CSP_I444) {
271       set_value (&fmt, 1, "Y444");
272     } else if (x265_chroma_format_local == X265_CSP_I420) {
273       set_value (&fmt, 1, "I420");
274     } else {
275       GST_ERROR ("Unsupported chroma format %d", x265_chroma_format_local);
276     }
277   }
278 
279   if (G_VALUE_TYPE (&fmt) != G_TYPE_INVALID)
280     gst_structure_take_value (s, "format", &fmt);
281 }
282 
283 static GstCaps *
gst_x265_enc_get_supported_input_caps(void)284 gst_x265_enc_get_supported_input_caps (void)
285 {
286   GstCaps *caps;
287   int x265_chroma_format = 0;
288 
289   caps = gst_caps_new_simple ("video/x-raw",
290       "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1,
291       "width", GST_TYPE_INT_RANGE, 4, G_MAXINT,
292       "height", GST_TYPE_INT_RANGE, 4, G_MAXINT, NULL);
293 
294   gst_x265_enc_add_x265_chroma_format (gst_caps_get_structure (caps, 0),
295       x265_chroma_format);
296 
297   GST_DEBUG ("returning %" GST_PTR_FORMAT, caps);
298   return caps;
299 }
300 
301 static gboolean
gst_x265_enc_sink_query(GstVideoEncoder * enc,GstQuery * query)302 gst_x265_enc_sink_query (GstVideoEncoder * enc, GstQuery * query)
303 {
304   gboolean res;
305 
306   switch (GST_QUERY_TYPE (query)) {
307     case GST_QUERY_ACCEPT_CAPS:{
308       GstCaps *acceptable, *caps;
309 
310       acceptable = gst_x265_enc_get_supported_input_caps ();
311       gst_query_parse_accept_caps (query, &caps);
312 
313       gst_query_set_accept_caps_result (query,
314           gst_caps_is_subset (caps, acceptable));
315       gst_caps_unref (acceptable);
316       res = TRUE;
317     }
318       break;
319     default:
320       res = GST_VIDEO_ENCODER_CLASS (parent_class)->sink_query (enc, query);
321       break;
322   }
323 
324   return res;
325 }
326 
327 static GstCaps *
gst_x265_enc_sink_getcaps(GstVideoEncoder * enc,GstCaps * filter)328 gst_x265_enc_sink_getcaps (GstVideoEncoder * enc, GstCaps * filter)
329 {
330   GstCaps *supported_incaps;
331   GstCaps *ret;
332 
333   supported_incaps = gst_x265_enc_get_supported_input_caps ();
334 
335   ret = gst_video_encoder_proxy_getcaps (enc, supported_incaps, filter);
336   if (supported_incaps)
337     gst_caps_unref (supported_incaps);
338   return ret;
339 }
340 
341 static void
gst_x265_enc_class_init(GstX265EncClass * klass)342 gst_x265_enc_class_init (GstX265EncClass * klass)
343 {
344   GObjectClass *gobject_class;
345   GstElementClass *element_class;
346   GstVideoEncoderClass *gstencoder_class;
347 
348   gobject_class = G_OBJECT_CLASS (klass);
349   element_class = GST_ELEMENT_CLASS (klass);
350   gstencoder_class = GST_VIDEO_ENCODER_CLASS (klass);
351 
352   gobject_class->set_property = gst_x265_enc_set_property;
353   gobject_class->get_property = gst_x265_enc_get_property;
354   gobject_class->finalize = gst_x265_enc_finalize;
355 
356   gstencoder_class->set_format = GST_DEBUG_FUNCPTR (gst_x265_enc_set_format);
357   gstencoder_class->handle_frame =
358       GST_DEBUG_FUNCPTR (gst_x265_enc_handle_frame);
359   gstencoder_class->start = GST_DEBUG_FUNCPTR (gst_x265_enc_start);
360   gstencoder_class->stop = GST_DEBUG_FUNCPTR (gst_x265_enc_stop);
361   gstencoder_class->flush = GST_DEBUG_FUNCPTR (gst_x265_enc_flush);
362   gstencoder_class->finish = GST_DEBUG_FUNCPTR (gst_x265_enc_finish);
363   gstencoder_class->getcaps = GST_DEBUG_FUNCPTR (gst_x265_enc_sink_getcaps);
364   gstencoder_class->sink_query = GST_DEBUG_FUNCPTR (gst_x265_enc_sink_query);
365   gstencoder_class->propose_allocation =
366       GST_DEBUG_FUNCPTR (gst_x265_enc_propose_allocation);
367 
368   g_object_class_install_property (gobject_class, PROP_BITRATE,
369       g_param_spec_uint ("bitrate", "Bitrate", "Bitrate in kbit/sec", 1,
370           100 * 1024, PROP_BITRATE_DEFAULT,
371           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
372           GST_PARAM_MUTABLE_PLAYING));
373 
374   g_object_class_install_property (gobject_class, PROP_QP,
375       g_param_spec_int ("qp", "Quantization parameter",
376           "QP for P slices in (implied) CQP mode (-1 = disabled)", -1,
377           51, PROP_QP_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
378 
379   g_object_class_install_property (gobject_class, PROP_OPTION_STRING,
380       g_param_spec_string ("option-string", "Option string",
381           "String of x265 options (overridden by element properties)"
382           " in the format \"key1=value1:key2=value2\".",
383           PROP_OPTION_STRING_DEFAULT,
384           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
385 
386   g_object_class_install_property (gobject_class, PROP_X265_LOG_LEVEL,
387       g_param_spec_enum ("log-level", "(internal) x265 log level",
388           "x265 log level", GST_X265_ENC_LOG_LEVEL_TYPE,
389           PROP_LOG_LEVEL_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
390 
391   g_object_class_install_property (gobject_class, PROP_SPEED_PRESET,
392       g_param_spec_enum ("speed-preset", "Speed preset",
393           "Preset name for speed/quality tradeoff options",
394           GST_X265_ENC_SPEED_PRESET_TYPE, PROP_SPEED_PRESET_DEFAULT,
395           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
396 
397   g_object_class_install_property (gobject_class, PROP_TUNE,
398       g_param_spec_enum ("tune", "Tune options",
399           "Preset name for tuning options", GST_X265_ENC_TUNE_TYPE,
400           PROP_TUNE_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
401   /**
402    * GstX265Enc::key-int-max:
403    *
404    * Controls maximum number of frames since the last keyframe
405    *
406    * Since: 1.16
407    */
408   g_object_class_install_property (gobject_class, PROP_KEY_INT_MAX,
409       g_param_spec_int ("key-int-max", "Max key frame",
410           "Maximal distance between two key-frames (0 = x265 default / 250)",
411           0, G_MAXINT32, PROP_KEY_INT_MAX_DEFAULT, G_PARAM_READWRITE));
412 
413   gst_element_class_set_static_metadata (element_class,
414       "x265enc", "Codec/Encoder/Video", "H265 Encoder",
415       "Thijs Vermeir <thijs.vermeir@barco.com>");
416 
417   gst_element_class_add_static_pad_template (element_class, &sink_factory);
418   gst_element_class_add_static_pad_template (element_class, &src_factory);
419 }
420 
421 /* initialize the new element
422  * instantiate pads and add them to element
423  * set functions
424  * initialize structure
425  */
426 static void
gst_x265_enc_init(GstX265Enc * encoder)427 gst_x265_enc_init (GstX265Enc * encoder)
428 {
429   x265_param_default (&encoder->x265param);
430 
431   encoder->push_header = TRUE;
432 
433   encoder->bitrate = PROP_BITRATE_DEFAULT;
434   encoder->qp = PROP_QP_DEFAULT;
435   encoder->option_string_prop = g_string_new (PROP_OPTION_STRING_DEFAULT);
436   encoder->log_level = PROP_LOG_LEVEL_DEFAULT;
437   encoder->speed_preset = PROP_SPEED_PRESET_DEFAULT;
438   encoder->tune = PROP_TUNE_DEFAULT;
439   encoder->keyintmax = PROP_KEY_INT_MAX_DEFAULT;
440 }
441 
442 typedef struct
443 {
444   GstVideoCodecFrame *frame;
445   GstVideoFrame vframe;
446 } FrameData;
447 
448 static FrameData *
gst_x265_enc_queue_frame(GstX265Enc * enc,GstVideoCodecFrame * frame,GstVideoInfo * info)449 gst_x265_enc_queue_frame (GstX265Enc * enc, GstVideoCodecFrame * frame,
450     GstVideoInfo * info)
451 {
452   GstVideoFrame vframe;
453   FrameData *fdata;
454 
455   if (!gst_video_frame_map (&vframe, info, frame->input_buffer, GST_MAP_READ))
456     return NULL;
457 
458   fdata = g_slice_new (FrameData);
459   fdata->frame = gst_video_codec_frame_ref (frame);
460   fdata->vframe = vframe;
461 
462   enc->pending_frames = g_list_prepend (enc->pending_frames, fdata);
463 
464   return fdata;
465 }
466 
467 static void
gst_x265_enc_dequeue_frame(GstX265Enc * enc,GstVideoCodecFrame * frame)468 gst_x265_enc_dequeue_frame (GstX265Enc * enc, GstVideoCodecFrame * frame)
469 {
470   GList *l;
471 
472   for (l = enc->pending_frames; l; l = l->next) {
473     FrameData *fdata = l->data;
474 
475     if (fdata->frame != frame)
476       continue;
477 
478     gst_video_frame_unmap (&fdata->vframe);
479     gst_video_codec_frame_unref (fdata->frame);
480     g_slice_free (FrameData, fdata);
481 
482     enc->pending_frames = g_list_delete_link (enc->pending_frames, l);
483     return;
484   }
485 }
486 
487 static void
gst_x265_enc_dequeue_all_frames(GstX265Enc * enc)488 gst_x265_enc_dequeue_all_frames (GstX265Enc * enc)
489 {
490   GList *l;
491 
492   for (l = enc->pending_frames; l; l = l->next) {
493     FrameData *fdata = l->data;
494 
495     gst_video_frame_unmap (&fdata->vframe);
496     gst_video_codec_frame_unref (fdata->frame);
497     g_slice_free (FrameData, fdata);
498   }
499   g_list_free (enc->pending_frames);
500   enc->pending_frames = NULL;
501 }
502 
503 static gboolean
gst_x265_enc_start(GstVideoEncoder * encoder)504 gst_x265_enc_start (GstVideoEncoder * encoder)
505 {
506   return TRUE;
507 }
508 
509 static gboolean
gst_x265_enc_stop(GstVideoEncoder * encoder)510 gst_x265_enc_stop (GstVideoEncoder * encoder)
511 {
512   GstX265Enc *x265enc = GST_X265_ENC (encoder);
513 
514   GST_DEBUG_OBJECT (encoder, "stop encoder");
515 
516   gst_x265_enc_flush_frames (x265enc, FALSE);
517   gst_x265_enc_close_encoder (x265enc);
518   gst_x265_enc_dequeue_all_frames (x265enc);
519 
520   if (x265enc->input_state)
521     gst_video_codec_state_unref (x265enc->input_state);
522   x265enc->input_state = NULL;
523 
524   return TRUE;
525 }
526 
527 
528 static gboolean
gst_x265_enc_flush(GstVideoEncoder * encoder)529 gst_x265_enc_flush (GstVideoEncoder * encoder)
530 {
531   GstX265Enc *x265enc = GST_X265_ENC (encoder);
532 
533   GST_DEBUG_OBJECT (encoder, "flushing encoder");
534 
535   gst_x265_enc_flush_frames (x265enc, FALSE);
536   gst_x265_enc_close_encoder (x265enc);
537   gst_x265_enc_dequeue_all_frames (x265enc);
538 
539   gst_x265_enc_init_encoder (x265enc);
540 
541   return TRUE;
542 }
543 
544 static void
gst_x265_enc_finalize(GObject * object)545 gst_x265_enc_finalize (GObject * object)
546 {
547   GstX265Enc *encoder = GST_X265_ENC (object);
548 
549   if (encoder->input_state)
550     gst_video_codec_state_unref (encoder->input_state);
551   encoder->input_state = NULL;
552 
553   gst_x265_enc_close_encoder (encoder);
554 
555   g_string_free (encoder->option_string_prop, TRUE);
556 
557   G_OBJECT_CLASS (parent_class)->finalize (object);
558 }
559 
560 static gint
gst_x265_enc_gst_to_x265_video_format(GstVideoFormat format,gint * nplanes)561 gst_x265_enc_gst_to_x265_video_format (GstVideoFormat format, gint * nplanes)
562 {
563   switch (format) {
564     case GST_VIDEO_FORMAT_I420:
565     case GST_VIDEO_FORMAT_YV12:
566     case GST_VIDEO_FORMAT_I420_10LE:
567     case GST_VIDEO_FORMAT_I420_10BE:
568       if (nplanes)
569         *nplanes = 3;
570       return X265_CSP_I420;
571     case GST_VIDEO_FORMAT_Y444:
572     case GST_VIDEO_FORMAT_Y444_10LE:
573     case GST_VIDEO_FORMAT_Y444_10BE:
574       if (nplanes)
575         *nplanes = 3;
576       return X265_CSP_I444;
577     default:
578       g_return_val_if_reached (GST_VIDEO_FORMAT_UNKNOWN);
579   }
580 }
581 
582 /*
583  * gst_x265_enc_parse_options
584  * @encoder: Encoder to which options are assigned
585  * @str: Option string
586  *
587  * Parse option string and assign to x265 parameters
588  *
589  */
590 static gboolean
gst_x265_enc_parse_options(GstX265Enc * encoder,const gchar * str)591 gst_x265_enc_parse_options (GstX265Enc * encoder, const gchar * str)
592 {
593   GStrv kvpairs;
594   guint npairs, i;
595   gint parse_result = 0, ret = 0;
596   gchar *options = (gchar *) str;
597 
598   while (*options == ':')
599     options++;
600 
601   kvpairs = g_strsplit (options, ":", 0);
602   npairs = g_strv_length (kvpairs);
603 
604   for (i = 0; i < npairs; i++) {
605     GStrv key_val = g_strsplit (kvpairs[i], "=", 2);
606 
607     parse_result =
608         x265_param_parse (&encoder->x265param, key_val[0], key_val[1]);
609 
610     if (parse_result == X265_PARAM_BAD_NAME) {
611       GST_ERROR_OBJECT (encoder, "Bad name for option %s=%s",
612           key_val[0] ? key_val[0] : "", key_val[1] ? key_val[1] : "");
613     }
614     if (parse_result == X265_PARAM_BAD_VALUE) {
615       GST_ERROR_OBJECT (encoder,
616           "Bad value for option %s=%s (Note: a NULL value for a non-boolean triggers this)",
617           key_val[0] ? key_val[0] : "", key_val[1] ? key_val[1] : "");
618     }
619 
620     g_strfreev (key_val);
621 
622     if (parse_result)
623       ret++;
624   }
625 
626   g_strfreev (kvpairs);
627   return !ret;
628 }
629 
630 /*
631  * gst_x265_enc_init_encoder
632  * @encoder:  Encoder which should be initialized.
633  *
634  * Initialize x265 encoder.
635  *
636  */
637 static gboolean
gst_x265_enc_init_encoder(GstX265Enc * encoder)638 gst_x265_enc_init_encoder (GstX265Enc * encoder)
639 {
640   GstVideoInfo *info;
641 
642   if (!encoder->input_state) {
643     GST_DEBUG_OBJECT (encoder, "Have no input state yet");
644     return FALSE;
645   }
646 
647   info = &encoder->input_state->info;
648 
649   /* make sure that the encoder is closed */
650   gst_x265_enc_close_encoder (encoder);
651 
652   GST_OBJECT_LOCK (encoder);
653 
654   if (x265_param_default_preset (&encoder->x265param,
655           x265_preset_names[encoder->speed_preset - 1],
656           x265_tune_names[encoder->tune - 1]) < 0) {
657     GST_DEBUG_OBJECT (encoder, "preset or tune unrecognized");
658     GST_OBJECT_UNLOCK (encoder);
659     return FALSE;
660   }
661 
662   /* set up encoder parameters */
663   encoder->x265param.logLevel = encoder->log_level;
664   encoder->x265param.internalCsp =
665       gst_x265_enc_gst_to_x265_video_format (info->finfo->format, NULL);
666   if (info->fps_d == 0 || info->fps_n == 0) {
667   } else {
668     encoder->x265param.fpsNum = info->fps_n;
669     encoder->x265param.fpsDenom = info->fps_d;
670   }
671   encoder->x265param.sourceWidth = info->width;
672   encoder->x265param.sourceHeight = info->height;
673   if (info->par_d > 0) {
674     encoder->x265param.vui.aspectRatioIdc = X265_EXTENDED_SAR;
675     encoder->x265param.vui.sarWidth = info->par_n;
676     encoder->x265param.vui.sarHeight = info->par_d;
677   }
678 
679   if (encoder->qp != -1) {
680     /* CQP */
681     encoder->x265param.rc.qp = encoder->qp;
682     encoder->x265param.rc.rateControlMode = X265_RC_CQP;
683   } else {
684     /* ABR */
685     encoder->x265param.rc.bitrate = encoder->bitrate;
686     encoder->x265param.rc.rateControlMode = X265_RC_ABR;
687   }
688 
689   if (encoder->keyintmax > 0) {
690     encoder->x265param.keyframeMax = encoder->keyintmax;
691   }
692 
693   /* apply option-string property */
694   if (encoder->option_string_prop && encoder->option_string_prop->len) {
695     GST_DEBUG_OBJECT (encoder, "Applying option-string: %s",
696         encoder->option_string_prop->str);
697     if (gst_x265_enc_parse_options (encoder,
698             encoder->option_string_prop->str) == FALSE) {
699       GST_DEBUG_OBJECT (encoder, "Your option-string contains errors.");
700       GST_OBJECT_UNLOCK (encoder);
701       return FALSE;
702     }
703   }
704 
705   encoder->reconfig = FALSE;
706 
707   /* good start, will be corrected if needed */
708   encoder->dts_offset = 0;
709 
710   GST_OBJECT_UNLOCK (encoder);
711 
712   encoder->x265enc = x265_encoder_open (&encoder->x265param);
713   if (!encoder->x265enc) {
714     GST_ELEMENT_ERROR (encoder, STREAM, ENCODE,
715         ("Can not initialize x265 encoder."), (NULL));
716     return FALSE;
717   }
718 
719   encoder->push_header = TRUE;
720 
721   return TRUE;
722 }
723 
724 /* gst_x265_enc_close_encoder
725  * @encoder:  Encoder which should close.
726  *
727  * Close x265 encoder.
728  */
729 static void
gst_x265_enc_close_encoder(GstX265Enc * encoder)730 gst_x265_enc_close_encoder (GstX265Enc * encoder)
731 {
732   if (encoder->x265enc != NULL) {
733     x265_encoder_close (encoder->x265enc);
734     encoder->x265enc = NULL;
735   }
736 }
737 
738 static x265_nal *
gst_x265_enc_bytestream_to_nal(x265_nal * input)739 gst_x265_enc_bytestream_to_nal (x265_nal * input)
740 {
741   x265_nal *output;
742   int i, j, zeros;
743 
744   output = g_malloc (sizeof (x265_nal));
745   output->payload = g_malloc (input->sizeBytes - 4);
746   output->sizeBytes = input->sizeBytes - 4;
747   output->type = input->type;
748 
749   zeros = 0;
750   for (i = 4, j = 0; i < input->sizeBytes; (i++, j++)) {
751     if (input->payload[i] == 0x00) {
752       zeros++;
753     } else if (input->payload[i] == 0x03 && zeros == 2) {
754       zeros = 0;
755       j--;
756       output->sizeBytes--;
757       continue;
758     } else {
759       zeros = 0;
760     }
761     output->payload[j] = input->payload[i];
762   }
763 
764   return output;
765 }
766 
767 static void
x265_nal_free(x265_nal * nal)768 x265_nal_free (x265_nal * nal)
769 {
770   g_free (nal->payload);
771   g_free (nal);
772 }
773 
774 static gboolean
gst_x265_enc_set_level_tier_and_profile(GstX265Enc * encoder,GstCaps * caps)775 gst_x265_enc_set_level_tier_and_profile (GstX265Enc * encoder, GstCaps * caps)
776 {
777   x265_nal *nal, *vps_nal;
778   guint32 i_nal;
779   int header_return;
780   gboolean ret = TRUE;
781 
782   GST_DEBUG_OBJECT (encoder, "set profile, level and tier");
783 
784   header_return = x265_encoder_headers (encoder->x265enc, &nal, &i_nal);
785   if (header_return < 0) {
786     GST_ELEMENT_ERROR (encoder, STREAM, ENCODE, ("Encode x265 header failed."),
787         ("x265_encoder_headers return code=%d", header_return));
788     return FALSE;
789   }
790 
791   GST_DEBUG_OBJECT (encoder, "%d nal units in header", i_nal);
792 
793   g_assert (nal[0].type == NAL_UNIT_VPS);
794   vps_nal = gst_x265_enc_bytestream_to_nal (&nal[0]);
795 
796   GST_MEMDUMP ("VPS", vps_nal->payload, vps_nal->sizeBytes);
797 
798   if (!gst_codec_utils_h265_caps_set_level_tier_and_profile (caps,
799           vps_nal->payload + 6, vps_nal->sizeBytes - 6)) {
800     GST_ELEMENT_ERROR (encoder, STREAM, ENCODE, ("Encode x265 failed."),
801         ("Failed to find correct level, tier or profile in VPS"));
802     ret = FALSE;
803   }
804 
805   x265_nal_free (vps_nal);
806 
807   return ret;
808 }
809 
810 static GstBuffer *
gst_x265_enc_get_header_buffer(GstX265Enc * encoder)811 gst_x265_enc_get_header_buffer (GstX265Enc * encoder)
812 {
813   x265_nal *nal;
814   guint32 i_nal, i, offset;
815   gint32 vps_idx, sps_idx, pps_idx;
816   int header_return;
817   GstBuffer *buf;
818 
819   header_return = x265_encoder_headers (encoder->x265enc, &nal, &i_nal);
820   if (header_return < 0) {
821     GST_ELEMENT_ERROR (encoder, STREAM, ENCODE, ("Encode x265 header failed."),
822         ("x265_encoder_headers return code=%d", header_return));
823     return FALSE;
824   }
825 
826   GST_DEBUG_OBJECT (encoder, "%d nal units in header", i_nal);
827 
828   /* x265 returns also non header nal units with the call x265_encoder_headers.
829    * The usefull headers are sequential (VPS, SPS and PPS), so we look for this
830    * nal units and only copy these tree nal units as the header */
831 
832   vps_idx = sps_idx = pps_idx = -1;
833   for (i = 0; i < i_nal; i++) {
834     if (nal[i].type == 32) {
835       vps_idx = i;
836     } else if (nal[i].type == 33) {
837       sps_idx = i;
838     } else if (nal[i].type == 34) {
839       pps_idx = i;
840     }
841   }
842 
843   if (vps_idx == -1 || sps_idx == -1 || pps_idx == -1) {
844     GST_ELEMENT_ERROR (encoder, STREAM, ENCODE, ("Encode x265 header failed."),
845         ("x265_encoder_headers did not return VPS, SPS and PPS"));
846     return FALSE;
847   }
848 
849   offset = 0;
850   buf =
851       gst_buffer_new_allocate (NULL,
852       nal[vps_idx].sizeBytes + nal[sps_idx].sizeBytes + nal[pps_idx].sizeBytes,
853       NULL);
854   gst_buffer_fill (buf, offset, nal[vps_idx].payload, nal[vps_idx].sizeBytes);
855   offset += nal[vps_idx].sizeBytes;
856   gst_buffer_fill (buf, offset, nal[sps_idx].payload, nal[sps_idx].sizeBytes);
857   offset += nal[sps_idx].sizeBytes;
858   gst_buffer_fill (buf, offset, nal[pps_idx].payload, nal[pps_idx].sizeBytes);
859 
860   return buf;
861 }
862 
863 /* gst_x265_enc_set_src_caps
864  * Returns: TRUE on success.
865  */
866 static gboolean
gst_x265_enc_set_src_caps(GstX265Enc * encoder,GstCaps * caps)867 gst_x265_enc_set_src_caps (GstX265Enc * encoder, GstCaps * caps)
868 {
869   GstCaps *outcaps;
870   GstStructure *structure;
871   GstVideoCodecState *state;
872   GstTagList *tags;
873 
874   outcaps = gst_caps_new_empty_simple ("video/x-h265");
875   structure = gst_caps_get_structure (outcaps, 0);
876 
877   gst_structure_set (structure, "stream-format", G_TYPE_STRING, "byte-stream",
878       NULL);
879   gst_structure_set (structure, "alignment", G_TYPE_STRING, "au", NULL);
880 
881   if (!gst_x265_enc_set_level_tier_and_profile (encoder, outcaps)) {
882     gst_caps_unref (outcaps);
883     return FALSE;
884   }
885 
886   state = gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (encoder),
887       outcaps, encoder->input_state);
888   GST_DEBUG_OBJECT (encoder, "output caps: %" GST_PTR_FORMAT, state->caps);
889   gst_video_codec_state_unref (state);
890 
891   tags = gst_tag_list_new_empty ();
892   gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER, "x265",
893       GST_TAG_ENCODER_VERSION, x265_version_str, NULL);
894   gst_video_encoder_merge_tags (GST_VIDEO_ENCODER (encoder), tags,
895       GST_TAG_MERGE_REPLACE);
896   gst_tag_list_unref (tags);
897 
898   return TRUE;
899 }
900 
901 static void
gst_x265_enc_set_latency(GstX265Enc * encoder)902 gst_x265_enc_set_latency (GstX265Enc * encoder)
903 {
904   GstVideoInfo *info = &encoder->input_state->info;
905   gint max_delayed_frames;
906   GstClockTime latency;
907 
908   /* FIXME get a real value from the encoder, this is currently not exposed */
909   if (encoder->tune > 0 && encoder->tune <= G_N_ELEMENTS (x265_tune_names) &&
910       strcmp (x265_tune_names[encoder->tune - 1], "zerolatency") == 0)
911     max_delayed_frames = 0;
912   else
913     max_delayed_frames = 5;
914 
915   if (info->fps_n) {
916     latency = gst_util_uint64_scale_ceil (GST_SECOND * info->fps_d,
917         max_delayed_frames, info->fps_n);
918   } else {
919     /* FIXME: Assume 25fps. This is better than reporting no latency at
920      * all and then later failing in live pipelines
921      */
922     latency = gst_util_uint64_scale_ceil (GST_SECOND * 1,
923         max_delayed_frames, 25);
924   }
925 
926   GST_INFO_OBJECT (encoder,
927       "Updating latency to %" GST_TIME_FORMAT " (%d frames)",
928       GST_TIME_ARGS (latency), max_delayed_frames);
929 
930   gst_video_encoder_set_latency (GST_VIDEO_ENCODER (encoder), latency, latency);
931 }
932 
933 static gboolean
gst_x265_enc_set_format(GstVideoEncoder * video_enc,GstVideoCodecState * state)934 gst_x265_enc_set_format (GstVideoEncoder * video_enc,
935     GstVideoCodecState * state)
936 {
937   GstX265Enc *encoder = GST_X265_ENC (video_enc);
938   GstVideoInfo *info = &state->info;
939 
940   /* If the encoder is initialized, do not reinitialize it again if not
941    * necessary */
942   if (encoder->x265enc) {
943     GstVideoInfo *old = &encoder->input_state->info;
944 
945     if (info->finfo->format == old->finfo->format
946         && info->width == old->width && info->height == old->height
947         && info->fps_n == old->fps_n && info->fps_d == old->fps_d
948         && info->par_n == old->par_n && info->par_d == old->par_d) {
949       gst_video_codec_state_unref (encoder->input_state);
950       encoder->input_state = gst_video_codec_state_ref (state);
951       return TRUE;
952     }
953 
954     /* clear out pending frames */
955     gst_x265_enc_flush_frames (encoder, TRUE);
956   }
957 
958   if (encoder->input_state)
959     gst_video_codec_state_unref (encoder->input_state);
960   encoder->input_state = gst_video_codec_state_ref (state);
961 
962   if (!gst_x265_enc_init_encoder (encoder))
963     return FALSE;
964 
965   if (!gst_x265_enc_set_src_caps (encoder, state->caps)) {
966     gst_x265_enc_close_encoder (encoder);
967     return FALSE;
968   }
969 
970   gst_x265_enc_set_latency (encoder);
971 
972   return TRUE;
973 }
974 
975 static GstFlowReturn
gst_x265_enc_finish(GstVideoEncoder * encoder)976 gst_x265_enc_finish (GstVideoEncoder * encoder)
977 {
978   GST_DEBUG_OBJECT (encoder, "finish encoder");
979 
980   gst_x265_enc_flush_frames (GST_X265_ENC (encoder), TRUE);
981   gst_x265_enc_flush_frames (GST_X265_ENC (encoder), TRUE);
982   return GST_FLOW_OK;
983 }
984 
985 static gboolean
gst_x265_enc_propose_allocation(GstVideoEncoder * encoder,GstQuery * query)986 gst_x265_enc_propose_allocation (GstVideoEncoder * encoder, GstQuery * query)
987 {
988   gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
989 
990   return GST_VIDEO_ENCODER_CLASS (parent_class)->propose_allocation (encoder,
991       query);
992 }
993 
994 /* chain function
995  * this function does the actual processing
996  */
997 static GstFlowReturn
gst_x265_enc_handle_frame(GstVideoEncoder * video_enc,GstVideoCodecFrame * frame)998 gst_x265_enc_handle_frame (GstVideoEncoder * video_enc,
999     GstVideoCodecFrame * frame)
1000 {
1001   GstX265Enc *encoder = GST_X265_ENC (video_enc);
1002   GstVideoInfo *info = &encoder->input_state->info;
1003   GstFlowReturn ret;
1004   x265_picture pic_in;
1005   guint32 i_nal, i;
1006   FrameData *fdata;
1007   gint nplanes = 0;
1008 
1009   if (G_UNLIKELY (encoder->x265enc == NULL))
1010     goto not_inited;
1011 
1012   /* set up input picture */
1013   x265_picture_init (&encoder->x265param, &pic_in);
1014 
1015   fdata = gst_x265_enc_queue_frame (encoder, frame, info);
1016   if (!fdata)
1017     goto invalid_frame;
1018 
1019   pic_in.colorSpace =
1020       gst_x265_enc_gst_to_x265_video_format (info->finfo->format, &nplanes);
1021   for (i = 0; i < nplanes; i++) {
1022     pic_in.planes[i] = GST_VIDEO_FRAME_PLANE_DATA (&fdata->vframe, i);
1023     pic_in.stride[i] = GST_VIDEO_FRAME_COMP_STRIDE (&fdata->vframe, i);
1024   }
1025 
1026   pic_in.sliceType = X265_TYPE_AUTO;
1027   pic_in.pts = frame->pts;
1028   pic_in.dts = frame->dts;
1029   pic_in.bitDepth = info->finfo->depth[0];
1030   pic_in.userData = GINT_TO_POINTER (frame->system_frame_number);
1031 
1032   ret = gst_x265_enc_encode_frame (encoder, &pic_in, frame, &i_nal, TRUE);
1033 
1034   /* input buffer is released later on */
1035   return ret;
1036 
1037 /* ERRORS */
1038 not_inited:
1039   {
1040     GST_WARNING_OBJECT (encoder, "Got buffer before set_caps was called");
1041     return GST_FLOW_NOT_NEGOTIATED;
1042   }
1043 invalid_frame:
1044   {
1045     GST_ERROR_OBJECT (encoder, "Failed to map frame");
1046     return GST_FLOW_ERROR;
1047   }
1048 }
1049 
1050 static GstFlowReturn
gst_x265_enc_encode_frame(GstX265Enc * encoder,x265_picture * pic_in,GstVideoCodecFrame * input_frame,guint32 * i_nal,gboolean send)1051 gst_x265_enc_encode_frame (GstX265Enc * encoder, x265_picture * pic_in,
1052     GstVideoCodecFrame * input_frame, guint32 * i_nal, gboolean send)
1053 {
1054   GstVideoCodecFrame *frame = NULL;
1055   GstBuffer *out_buf = NULL;
1056   x265_picture pic_out;
1057   x265_nal *nal;
1058   int i_size, i, offset;
1059   int encoder_return;
1060   GstFlowReturn ret = GST_FLOW_OK;
1061   gboolean update_latency = FALSE;
1062 
1063   if (G_UNLIKELY (encoder->x265enc == NULL)) {
1064     if (input_frame)
1065       gst_video_codec_frame_unref (input_frame);
1066     return GST_FLOW_NOT_NEGOTIATED;
1067   }
1068 
1069   GST_OBJECT_LOCK (encoder);
1070   if (encoder->reconfig) {
1071     /* x265_encoder_reconfig is not yet implemented thus we shut down and re-create encoder */
1072     gst_x265_enc_init_encoder (encoder);
1073     update_latency = TRUE;
1074   }
1075 
1076   if (pic_in && input_frame) {
1077     if (GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (input_frame)) {
1078       GST_INFO_OBJECT (encoder, "Forcing key frame");
1079       pic_in->sliceType = X265_TYPE_IDR;
1080     }
1081   }
1082   GST_OBJECT_UNLOCK (encoder);
1083 
1084   if (G_UNLIKELY (update_latency))
1085     gst_x265_enc_set_latency (encoder);
1086 
1087   encoder_return = x265_encoder_encode (encoder->x265enc,
1088       &nal, i_nal, pic_in, &pic_out);
1089 
1090   GST_DEBUG_OBJECT (encoder, "encoder result (%d) with %u nal units",
1091       encoder_return, *i_nal);
1092 
1093   if (encoder_return < 0) {
1094     GST_ELEMENT_ERROR (encoder, STREAM, ENCODE, ("Encode x265 frame failed."),
1095         ("x265_encoder_encode return code=%d", encoder_return));
1096     ret = GST_FLOW_ERROR;
1097     /* Make sure we finish this frame */
1098     frame = input_frame;
1099     goto out;
1100   }
1101 
1102   /* Input frame is now queued */
1103   if (input_frame)
1104     gst_video_codec_frame_unref (input_frame);
1105 
1106   if (!*i_nal) {
1107     ret = GST_FLOW_OK;
1108     GST_LOG_OBJECT (encoder, "no output yet");
1109     goto out;
1110   }
1111 
1112   frame = gst_video_encoder_get_frame (GST_VIDEO_ENCODER (encoder),
1113       GPOINTER_TO_INT (pic_out.userData));
1114   g_assert (frame || !send);
1115 
1116   GST_DEBUG_OBJECT (encoder,
1117       "output picture ready POC=%d system=%d frame found %d", pic_out.poc,
1118       GPOINTER_TO_INT (pic_out.userData), frame != NULL);
1119 
1120   if (!send || !frame) {
1121     GST_LOG_OBJECT (encoder, "not sending (%d) or frame not found (%d)", send,
1122         frame != NULL);
1123     ret = GST_FLOW_OK;
1124     goto out;
1125   }
1126 
1127   i_size = 0;
1128   offset = 0;
1129   for (i = 0; i < *i_nal; i++)
1130     i_size += nal[i].sizeBytes;
1131   out_buf = gst_buffer_new_allocate (NULL, i_size, NULL);
1132   for (i = 0; i < *i_nal; i++) {
1133     gst_buffer_fill (out_buf, offset, nal[i].payload, nal[i].sizeBytes);
1134     offset += nal[i].sizeBytes;
1135   }
1136 
1137   if (pic_out.sliceType == X265_TYPE_IDR || pic_out.sliceType == X265_TYPE_I) {
1138     GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
1139   }
1140 
1141   frame->output_buffer = out_buf;
1142 
1143   if (encoder->push_header) {
1144     GstBuffer *header;
1145 
1146     header = gst_x265_enc_get_header_buffer (encoder);
1147     frame->output_buffer = gst_buffer_append (header, frame->output_buffer);
1148     encoder->push_header = FALSE;
1149   }
1150 
1151   GST_LOG_OBJECT (encoder,
1152       "output: dts %" G_GINT64_FORMAT " pts %" G_GINT64_FORMAT,
1153       (gint64) pic_out.dts, (gint64) pic_out.pts);
1154 
1155   frame->dts = pic_out.dts + encoder->dts_offset;
1156 
1157 out:
1158   if (frame) {
1159     gst_x265_enc_dequeue_frame (encoder, frame);
1160     ret = gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (encoder), frame);
1161   }
1162 
1163   return ret;
1164 }
1165 
1166 static void
gst_x265_enc_flush_frames(GstX265Enc * encoder,gboolean send)1167 gst_x265_enc_flush_frames (GstX265Enc * encoder, gboolean send)
1168 {
1169   GstFlowReturn flow_ret;
1170   guint32 i_nal;
1171 
1172   /* first send the remaining frames */
1173   if (encoder->x265enc)
1174     do {
1175       flow_ret = gst_x265_enc_encode_frame (encoder, NULL, NULL, &i_nal, send);
1176     } while (flow_ret == GST_FLOW_OK && i_nal > 0);
1177 }
1178 
1179 static void
gst_x265_enc_reconfig(GstX265Enc * encoder)1180 gst_x265_enc_reconfig (GstX265Enc * encoder)
1181 {
1182   encoder->x265param.rc.bitrate = encoder->bitrate;
1183   encoder->reconfig = TRUE;
1184 }
1185 
1186 static void
gst_x265_enc_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)1187 gst_x265_enc_set_property (GObject * object, guint prop_id,
1188     const GValue * value, GParamSpec * pspec)
1189 {
1190   GstX265Enc *encoder;
1191   GstState state;
1192 
1193   encoder = GST_X265_ENC (object);
1194 
1195   GST_OBJECT_LOCK (encoder);
1196 
1197   state = GST_STATE (encoder);
1198   if ((state != GST_STATE_READY && state != GST_STATE_NULL) &&
1199       !(pspec->flags & GST_PARAM_MUTABLE_PLAYING))
1200     goto wrong_state;
1201 
1202   switch (prop_id) {
1203     case PROP_BITRATE:
1204       encoder->bitrate = g_value_get_uint (value);
1205       break;
1206     case PROP_QP:
1207       encoder->qp = g_value_get_int (value);
1208       break;
1209     case PROP_OPTION_STRING:
1210       g_string_assign (encoder->option_string_prop, g_value_get_string (value));
1211       break;
1212     case PROP_X265_LOG_LEVEL:
1213       encoder->log_level = g_value_get_enum (value);
1214       break;
1215     case PROP_SPEED_PRESET:
1216       encoder->speed_preset = g_value_get_enum (value);
1217       break;
1218     case PROP_TUNE:
1219       encoder->tune = g_value_get_enum (value);
1220       break;
1221     case PROP_KEY_INT_MAX:
1222       encoder->keyintmax = g_value_get_int (value);
1223       break;
1224     default:
1225       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1226       break;
1227   }
1228 
1229   gst_x265_enc_reconfig (encoder);
1230   GST_OBJECT_UNLOCK (encoder);
1231   return;
1232 
1233 wrong_state:
1234   {
1235     GST_WARNING_OBJECT (encoder, "setting property in wrong state");
1236     GST_OBJECT_UNLOCK (encoder);
1237   }
1238 }
1239 
1240 static void
gst_x265_enc_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)1241 gst_x265_enc_get_property (GObject * object, guint prop_id,
1242     GValue * value, GParamSpec * pspec)
1243 {
1244   GstX265Enc *encoder;
1245 
1246   encoder = GST_X265_ENC (object);
1247 
1248   GST_OBJECT_LOCK (encoder);
1249   switch (prop_id) {
1250     case PROP_BITRATE:
1251       g_value_set_uint (value, encoder->bitrate);
1252       break;
1253     case PROP_QP:
1254       g_value_set_int (value, encoder->qp);
1255       break;
1256     case PROP_OPTION_STRING:
1257       g_value_set_string (value, encoder->option_string_prop->str);
1258       break;
1259     case PROP_X265_LOG_LEVEL:
1260       g_value_set_enum (value, encoder->log_level);
1261       break;
1262     case PROP_SPEED_PRESET:
1263       g_value_set_enum (value, encoder->speed_preset);
1264       break;
1265     case PROP_TUNE:
1266       g_value_set_enum (value, encoder->tune);
1267       break;
1268     case PROP_KEY_INT_MAX:
1269       g_value_set_int (value, encoder->keyintmax);
1270       break;
1271     default:
1272       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1273       break;
1274   }
1275   GST_OBJECT_UNLOCK (encoder);
1276 }
1277 
1278 static gboolean
plugin_init(GstPlugin * plugin)1279 plugin_init (GstPlugin * plugin)
1280 {
1281   GST_DEBUG_CATEGORY_INIT (x265_enc_debug, "x265enc", 0,
1282       "h265 encoding element");
1283 
1284   GST_INFO ("x265 build: %u", X265_BUILD);
1285 
1286   return gst_element_register (plugin, "x265enc",
1287       GST_RANK_PRIMARY, GST_TYPE_X265_ENC);
1288 }
1289 
1290 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1291     GST_VERSION_MINOR,
1292     x265,
1293     "x265-based H265 plugins",
1294     plugin_init, VERSION, "GPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
1295