• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static x265_api default_vtable;
49 
50 static const x265_api *vtable_8bit = NULL;
51 static const x265_api *vtable_10bit = NULL;
52 static const x265_api *vtable_12bit = NULL;
53 
54 enum
55 {
56   PROP_0,
57   PROP_BITRATE,
58   PROP_QP,
59   PROP_OPTION_STRING,
60   PROP_X265_LOG_LEVEL,
61   PROP_SPEED_PRESET,
62   PROP_TUNE,
63   PROP_KEY_INT_MAX
64 };
65 
66 #define PROP_BITRATE_DEFAULT            (2 * 1024)
67 #define PROP_QP_DEFAULT                 -1
68 #define PROP_OPTION_STRING_DEFAULT      ""
69 #define PROP_LOG_LEVEL_DEFAULT           -1     /* None   */
70 #define PROP_SPEED_PRESET_DEFAULT        6      /* Medium */
71 #define PROP_TUNE_DEFAULT                2      /* SSIM   */
72 #define PROP_KEY_INT_MAX_DEFAULT         0      /* x265 lib default */
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 src_factory = GST_STATIC_PAD_TEMPLATE ("src",
161     GST_PAD_SRC,
162     GST_PAD_ALWAYS,
163     GST_STATIC_CAPS ("video/x-h265, "
164         "framerate = (fraction) [0/1, MAX], "
165         "width = (int) [ 16, MAX ], " "height = (int) [ 16, MAX ], "
166         "stream-format = (string) byte-stream, "
167         "alignment = (string) au, "
168         "profile = (string) { main, main-still-picture, main-intra, main-444,"
169         " main-444-intra, main-444-still-picture,"
170         " main-10, main-10-intra, main-422-10, main-422-10-intra,"
171         " main-444-10, main-444-10-intra,"
172         " main-12, main-12-intra, main-422-12, main-422-12-intra,"
173         " main-444-12, main-444-12-intra }")
174     );
175 
176 static void gst_x265_enc_finalize (GObject * object);
177 static gboolean gst_x265_enc_start (GstVideoEncoder * encoder);
178 static gboolean gst_x265_enc_stop (GstVideoEncoder * encoder);
179 static gboolean gst_x265_enc_flush (GstVideoEncoder * encoder);
180 
181 static gboolean gst_x265_enc_init_encoder (GstX265Enc * encoder);
182 static void gst_x265_enc_close_encoder (GstX265Enc * encoder);
183 
184 static GstFlowReturn gst_x265_enc_finish (GstVideoEncoder * encoder);
185 static GstFlowReturn gst_x265_enc_handle_frame (GstVideoEncoder * encoder,
186     GstVideoCodecFrame * frame);
187 static void gst_x265_enc_flush_frames (GstX265Enc * encoder, gboolean send);
188 static GstFlowReturn gst_x265_enc_encode_frame (GstX265Enc * encoder,
189     x265_picture * pic_in, GstVideoCodecFrame * input_frame, guint32 * i_nal,
190     gboolean send);
191 static gboolean gst_x265_enc_set_format (GstVideoEncoder * video_enc,
192     GstVideoCodecState * state);
193 static gboolean gst_x265_enc_propose_allocation (GstVideoEncoder * encoder,
194     GstQuery * query);
195 
196 static void gst_x265_enc_set_property (GObject * object, guint prop_id,
197     const GValue * value, GParamSpec * pspec);
198 static void gst_x265_enc_get_property (GObject * object, guint prop_id,
199     GValue * value, GParamSpec * pspec);
200 static gboolean x265enc_element_init (GstPlugin * plugin);
201 
202 #define gst_x265_enc_parent_class parent_class
203 G_DEFINE_TYPE_WITH_CODE (GstX265Enc, gst_x265_enc, GST_TYPE_VIDEO_ENCODER,
204     G_IMPLEMENT_INTERFACE (GST_TYPE_PRESET, NULL));
205 GST_ELEMENT_REGISTER_DEFINE_CUSTOM (x265enc, x265enc_element_init);
206 
207 static gboolean
gst_x265_enc_add_x265_chroma_format(GstStructure * s,gboolean allow_420,gboolean allow_422,gboolean allow_444,gboolean allow_8bit,gboolean allow_10bit,gboolean allow_12bit)208 gst_x265_enc_add_x265_chroma_format (GstStructure * s,
209     gboolean allow_420, gboolean allow_422, gboolean allow_444,
210     gboolean allow_8bit, gboolean allow_10bit, gboolean allow_12bit)
211 {
212   GValue fmts = G_VALUE_INIT;
213   GValue fmt = G_VALUE_INIT;
214   gboolean ret = FALSE;
215 
216   g_value_init (&fmts, GST_TYPE_LIST);
217   g_value_init (&fmt, G_TYPE_STRING);
218 
219   if (allow_8bit) {
220     if (allow_444) {
221       g_value_set_string (&fmt, "Y444");
222       gst_value_list_append_value (&fmts, &fmt);
223     }
224 
225     if (allow_422) {
226       g_value_set_string (&fmt, "Y42B");
227       gst_value_list_append_value (&fmts, &fmt);
228     }
229 
230     if (allow_420) {
231       g_value_set_string (&fmt, "I420");
232       gst_value_list_append_value (&fmts, &fmt);
233     }
234   }
235 
236   if (allow_10bit) {
237     if (allow_444) {
238       if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
239         g_value_set_string (&fmt, "Y444_10LE");
240       else
241         g_value_set_string (&fmt, "Y444_10BE");
242 
243       gst_value_list_append_value (&fmts, &fmt);
244     }
245 
246     if (allow_422) {
247       if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
248         g_value_set_string (&fmt, "I422_10LE");
249       else
250         g_value_set_string (&fmt, "I422_10BE");
251 
252       gst_value_list_append_value (&fmts, &fmt);
253     }
254 
255     if (allow_420) {
256       if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
257         g_value_set_string (&fmt, "I420_10LE");
258       else
259         g_value_set_string (&fmt, "I420_10BE");
260 
261       gst_value_list_append_value (&fmts, &fmt);
262     }
263   }
264 
265   if (allow_12bit) {
266     if (allow_444) {
267       if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
268         g_value_set_string (&fmt, "Y444_12LE");
269       else
270         g_value_set_string (&fmt, "Y444_12BE");
271 
272       gst_value_list_append_value (&fmts, &fmt);
273     }
274 
275     if (allow_422) {
276       if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
277         g_value_set_string (&fmt, "I422_12LE");
278       else
279         g_value_set_string (&fmt, "I422_12BE");
280 
281       gst_value_list_append_value (&fmts, &fmt);
282     }
283 
284     if (allow_420) {
285       if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
286         g_value_set_string (&fmt, "I420_12LE");
287       else
288         g_value_set_string (&fmt, "I420_12BE");
289 
290       gst_value_list_append_value (&fmts, &fmt);
291     }
292   }
293 
294   if (gst_value_list_get_size (&fmts) != 0) {
295     gst_structure_take_value (s, "format", &fmts);
296     ret = TRUE;
297   } else {
298     g_value_unset (&fmts);
299   }
300 
301   g_value_unset (&fmt);
302 
303   return ret;
304 }
305 
306 static gboolean
gst_x265_enc_sink_query(GstVideoEncoder * enc,GstQuery * query)307 gst_x265_enc_sink_query (GstVideoEncoder * enc, GstQuery * query)
308 {
309   GstPad *pad = GST_VIDEO_ENCODER_SINK_PAD (enc);
310   gboolean res;
311 
312   switch (GST_QUERY_TYPE (query)) {
313     case GST_QUERY_ACCEPT_CAPS:{
314       GstCaps *acceptable, *caps;
315 
316       acceptable = gst_pad_get_pad_template_caps (pad);
317 
318       gst_query_parse_accept_caps (query, &caps);
319 
320       gst_query_set_accept_caps_result (query,
321           gst_caps_is_subset (caps, acceptable));
322       gst_caps_unref (acceptable);
323       res = TRUE;
324     }
325       break;
326     default:
327       res = GST_VIDEO_ENCODER_CLASS (parent_class)->sink_query (enc, query);
328       break;
329   }
330 
331   return res;
332 }
333 
334 static void
check_formats(const gchar * str,guint * max_chroma,guint * max_bit_minus_8)335 check_formats (const gchar * str, guint * max_chroma, guint * max_bit_minus_8)
336 {
337   if (!str)
338     return;
339 
340   if (g_strrstr (str, "-444"))
341     *max_chroma = 2;
342   else if (g_strrstr (str, "-422") && *max_chroma < 1)
343     *max_chroma = 1;
344 
345   if (g_strrstr (str, "-12"))
346     *max_bit_minus_8 = 4;
347   else if (g_strrstr (str, "-10") && *max_bit_minus_8 < 2)
348     *max_bit_minus_8 = 2;
349 }
350 
351 static GstCaps *
gst_x265_enc_sink_getcaps(GstVideoEncoder * enc,GstCaps * filter)352 gst_x265_enc_sink_getcaps (GstVideoEncoder * enc, GstCaps * filter)
353 {
354   GstCaps *templ_caps, *supported_incaps;
355   GstCaps *allowed;
356   GstCaps *fcaps;
357   gint i, j;
358   gboolean has_profile = FALSE;
359   guint max_chroma_index = 0;
360   guint max_bit_minus_8 = 0;
361 
362   templ_caps = gst_pad_get_pad_template_caps (GST_VIDEO_ENCODER_SINK_PAD (enc));
363   allowed = gst_pad_get_allowed_caps (enc->srcpad);
364 
365   GST_LOG_OBJECT (enc, "template caps %" GST_PTR_FORMAT, templ_caps);
366   GST_LOG_OBJECT (enc, "allowed caps %" GST_PTR_FORMAT, allowed);
367 
368   if (!allowed) {
369     /* no peer */
370     supported_incaps = templ_caps;
371     goto done;
372   } else if (gst_caps_is_empty (allowed)) {
373     /* cannot negotiate, return empty caps */
374     gst_caps_unref (templ_caps);
375     return allowed;
376   }
377 
378   /* fill format based on requested profile */
379   for (i = 0; i < gst_caps_get_size (allowed); i++) {
380     const GstStructure *allowed_s = gst_caps_get_structure (allowed, i);
381     const GValue *val;
382 
383     if ((val = gst_structure_get_value (allowed_s, "profile"))) {
384       if (G_VALUE_HOLDS_STRING (val)) {
385         check_formats (g_value_get_string (val), &max_chroma_index,
386             &max_bit_minus_8);
387         has_profile = TRUE;
388       } else if (GST_VALUE_HOLDS_LIST (val)) {
389         for (j = 0; j < gst_value_list_get_size (val); j++) {
390           const GValue *vlist = gst_value_list_get_value (val, j);
391 
392           if (G_VALUE_HOLDS_STRING (vlist)) {
393             check_formats (g_value_get_string (vlist), &max_chroma_index,
394                 &max_bit_minus_8);
395             has_profile = TRUE;
396           }
397         }
398       }
399     }
400   }
401 
402   if (!has_profile) {
403     /* downstream did not request profile */
404     supported_incaps = templ_caps;
405   } else {
406     GstStructure *s;
407     gboolean has_12bit = FALSE;
408     gboolean has_10bit = FALSE;
409     gboolean has_8bit = TRUE;
410     gboolean has_444 = FALSE;
411     gboolean has_422 = FALSE;
412     gboolean has_420 = TRUE;
413 
414     supported_incaps = gst_caps_new_simple ("video/x-raw",
415         "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1,
416         "width", GST_TYPE_INT_RANGE, 16, G_MAXINT,
417         "height", GST_TYPE_INT_RANGE, 16, G_MAXINT, NULL);
418 
419     /* NOTE: 12bits profiles can accept 8bits and 10bits format */
420     if (max_bit_minus_8 >= 4)
421       has_12bit = TRUE;
422     if (max_bit_minus_8 >= 2)
423       has_10bit = TRUE;
424 
425     has_8bit &= ! !vtable_8bit;
426     has_10bit &= ! !vtable_10bit;
427     has_12bit &= ! !vtable_12bit;
428 
429     /* 4:4:4 profiles can handle 4:2:2 and 4:2:0 */
430     if (max_chroma_index >= 2)
431       has_444 = TRUE;
432     if (max_chroma_index >= 1)
433       has_422 = TRUE;
434 
435     s = gst_caps_get_structure (supported_incaps, 0);
436     gst_x265_enc_add_x265_chroma_format (s, has_420, has_422, has_444,
437         has_8bit, has_10bit, has_12bit);
438 
439     gst_caps_unref (templ_caps);
440   }
441 
442 done:
443   GST_LOG_OBJECT (enc, "supported caps %" GST_PTR_FORMAT, supported_incaps);
444   fcaps = gst_video_encoder_proxy_getcaps (enc, supported_incaps, filter);
445   gst_clear_caps (&supported_incaps);
446   gst_clear_caps (&allowed);
447 
448   GST_LOG_OBJECT (enc, "proxy caps %" GST_PTR_FORMAT, fcaps);
449 
450   return fcaps;
451 }
452 
453 static void
gst_x265_enc_class_init(GstX265EncClass * klass)454 gst_x265_enc_class_init (GstX265EncClass * klass)
455 {
456   GObjectClass *gobject_class;
457   GstElementClass *element_class;
458   GstVideoEncoderClass *gstencoder_class;
459   GstPadTemplate *sink_templ;
460   GstCaps *supported_sinkcaps;
461 
462   gobject_class = G_OBJECT_CLASS (klass);
463   element_class = GST_ELEMENT_CLASS (klass);
464   gstencoder_class = GST_VIDEO_ENCODER_CLASS (klass);
465 
466   gobject_class->set_property = gst_x265_enc_set_property;
467   gobject_class->get_property = gst_x265_enc_get_property;
468   gobject_class->finalize = gst_x265_enc_finalize;
469 
470   gstencoder_class->set_format = GST_DEBUG_FUNCPTR (gst_x265_enc_set_format);
471   gstencoder_class->handle_frame =
472       GST_DEBUG_FUNCPTR (gst_x265_enc_handle_frame);
473   gstencoder_class->start = GST_DEBUG_FUNCPTR (gst_x265_enc_start);
474   gstencoder_class->stop = GST_DEBUG_FUNCPTR (gst_x265_enc_stop);
475   gstencoder_class->flush = GST_DEBUG_FUNCPTR (gst_x265_enc_flush);
476   gstencoder_class->finish = GST_DEBUG_FUNCPTR (gst_x265_enc_finish);
477   gstencoder_class->getcaps = GST_DEBUG_FUNCPTR (gst_x265_enc_sink_getcaps);
478   gstencoder_class->sink_query = GST_DEBUG_FUNCPTR (gst_x265_enc_sink_query);
479   gstencoder_class->propose_allocation =
480       GST_DEBUG_FUNCPTR (gst_x265_enc_propose_allocation);
481 
482   g_object_class_install_property (gobject_class, PROP_BITRATE,
483       g_param_spec_uint ("bitrate", "Bitrate", "Bitrate in kbit/sec", 1,
484           100 * 1024, PROP_BITRATE_DEFAULT,
485           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
486           GST_PARAM_MUTABLE_PLAYING));
487 
488   g_object_class_install_property (gobject_class, PROP_QP,
489       g_param_spec_int ("qp", "Quantization parameter",
490           "QP for P slices in (implied) CQP mode (-1 = disabled)", -1,
491           51, PROP_QP_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
492 
493   g_object_class_install_property (gobject_class, PROP_OPTION_STRING,
494       g_param_spec_string ("option-string", "Option string",
495           "String of x265 options (overridden by element properties)"
496           " in the format \"key1=value1:key2=value2\".",
497           PROP_OPTION_STRING_DEFAULT,
498           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
499 
500   g_object_class_install_property (gobject_class, PROP_X265_LOG_LEVEL,
501       g_param_spec_enum ("log-level", "(internal) x265 log level",
502           "x265 log level", GST_X265_ENC_LOG_LEVEL_TYPE,
503           PROP_LOG_LEVEL_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
504 
505   g_object_class_install_property (gobject_class, PROP_SPEED_PRESET,
506       g_param_spec_enum ("speed-preset", "Speed preset",
507           "Preset name for speed/quality tradeoff options",
508           GST_X265_ENC_SPEED_PRESET_TYPE, PROP_SPEED_PRESET_DEFAULT,
509           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
510 
511   g_object_class_install_property (gobject_class, PROP_TUNE,
512       g_param_spec_enum ("tune", "Tune options",
513           "Preset name for tuning options", GST_X265_ENC_TUNE_TYPE,
514           PROP_TUNE_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
515   /**
516    * GstX265Enc::key-int-max:
517    *
518    * Controls maximum number of frames since the last keyframe
519    *
520    * Since: 1.16
521    */
522   g_object_class_install_property (gobject_class, PROP_KEY_INT_MAX,
523       g_param_spec_int ("key-int-max", "Max key frame",
524           "Maximal distance between two key-frames (0 = x265 default / 250)",
525           0, G_MAXINT32, PROP_KEY_INT_MAX_DEFAULT, G_PARAM_READWRITE));
526 
527   gst_element_class_set_static_metadata (element_class,
528       "x265enc", "Codec/Encoder/Video", "H265 Encoder",
529       "Thijs Vermeir <thijs.vermeir@barco.com>");
530 
531   supported_sinkcaps = gst_caps_new_simple ("video/x-raw",
532       "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1,
533       "width", GST_TYPE_INT_RANGE, 16, G_MAXINT,
534       "height", GST_TYPE_INT_RANGE, 16, G_MAXINT, NULL);
535 
536   gst_x265_enc_add_x265_chroma_format (gst_caps_get_structure
537       (supported_sinkcaps, 0), TRUE, TRUE, TRUE, ! !vtable_8bit,
538       ! !vtable_10bit, ! !vtable_12bit);
539 
540   sink_templ = gst_pad_template_new ("sink",
541       GST_PAD_SINK, GST_PAD_ALWAYS, supported_sinkcaps);
542 
543   gst_caps_unref (supported_sinkcaps);
544 
545   gst_element_class_add_pad_template (element_class, sink_templ);
546   gst_element_class_add_static_pad_template (element_class, &src_factory);
547 
548   gst_type_mark_as_plugin_api (GST_X265_ENC_LOG_LEVEL_TYPE, 0);
549   gst_type_mark_as_plugin_api (GST_X265_ENC_SPEED_PRESET_TYPE, 0);
550   gst_type_mark_as_plugin_api (GST_X265_ENC_TUNE_TYPE,
551       GST_PLUGIN_API_FLAG_IGNORE_ENUM_MEMBERS);
552 }
553 
554 /* initialize the new element
555  * instantiate pads and add them to element
556  * set functions
557  * initialize structure
558  */
559 static void
gst_x265_enc_init(GstX265Enc * encoder)560 gst_x265_enc_init (GstX265Enc * encoder)
561 {
562   encoder->push_header = TRUE;
563 
564   encoder->bitrate = PROP_BITRATE_DEFAULT;
565   encoder->qp = PROP_QP_DEFAULT;
566   encoder->option_string_prop = g_string_new (PROP_OPTION_STRING_DEFAULT);
567   encoder->log_level = PROP_LOG_LEVEL_DEFAULT;
568   encoder->speed_preset = PROP_SPEED_PRESET_DEFAULT;
569   encoder->tune = PROP_TUNE_DEFAULT;
570   encoder->keyintmax = PROP_KEY_INT_MAX_DEFAULT;
571   encoder->api = &default_vtable;
572 
573   encoder->api->param_default (&encoder->x265param);
574 
575   encoder->peer_profiles = g_ptr_array_new ();
576 }
577 
578 typedef struct
579 {
580   GstVideoCodecFrame *frame;
581   GstVideoFrame vframe;
582 } FrameData;
583 
584 static FrameData *
gst_x265_enc_queue_frame(GstX265Enc * enc,GstVideoCodecFrame * frame,GstVideoInfo * info)585 gst_x265_enc_queue_frame (GstX265Enc * enc, GstVideoCodecFrame * frame,
586     GstVideoInfo * info)
587 {
588   GstVideoFrame vframe;
589   FrameData *fdata;
590 
591   if (!gst_video_frame_map (&vframe, info, frame->input_buffer, GST_MAP_READ))
592     return NULL;
593 
594   fdata = g_slice_new (FrameData);
595   fdata->frame = gst_video_codec_frame_ref (frame);
596   fdata->vframe = vframe;
597 
598   enc->pending_frames = g_list_prepend (enc->pending_frames, fdata);
599 
600   return fdata;
601 }
602 
603 static void
gst_x265_enc_dequeue_frame(GstX265Enc * enc,GstVideoCodecFrame * frame)604 gst_x265_enc_dequeue_frame (GstX265Enc * enc, GstVideoCodecFrame * frame)
605 {
606   GList *l;
607 
608   for (l = enc->pending_frames; l; l = l->next) {
609     FrameData *fdata = l->data;
610 
611     if (fdata->frame != frame)
612       continue;
613 
614     gst_video_frame_unmap (&fdata->vframe);
615     gst_video_codec_frame_unref (fdata->frame);
616     g_slice_free (FrameData, fdata);
617 
618     enc->pending_frames = g_list_delete_link (enc->pending_frames, l);
619     return;
620   }
621 }
622 
623 static void
gst_x265_enc_dequeue_all_frames(GstX265Enc * enc)624 gst_x265_enc_dequeue_all_frames (GstX265Enc * enc)
625 {
626   GList *l;
627 
628   for (l = enc->pending_frames; l; l = l->next) {
629     FrameData *fdata = l->data;
630 
631     gst_video_frame_unmap (&fdata->vframe);
632     gst_video_codec_frame_unref (fdata->frame);
633     g_slice_free (FrameData, fdata);
634   }
635   g_list_free (enc->pending_frames);
636   enc->pending_frames = NULL;
637 }
638 
639 static gboolean
gst_x265_enc_start(GstVideoEncoder * encoder)640 gst_x265_enc_start (GstVideoEncoder * encoder)
641 {
642   GstX265Enc *x265enc = GST_X265_ENC (encoder);
643 
644   g_ptr_array_set_size (x265enc->peer_profiles, 0);
645 
646   /* make sure that we have enough time for first DTS,
647      this is probably overkill for most streams */
648   gst_video_encoder_set_min_pts (encoder, GST_SECOND * 60 * 60 * 1000);
649 
650   return TRUE;
651 }
652 
653 static gboolean
gst_x265_enc_stop(GstVideoEncoder * encoder)654 gst_x265_enc_stop (GstVideoEncoder * encoder)
655 {
656   GstX265Enc *x265enc = GST_X265_ENC (encoder);
657 
658   GST_DEBUG_OBJECT (encoder, "stop encoder");
659 
660   gst_x265_enc_flush_frames (x265enc, FALSE);
661   gst_x265_enc_close_encoder (x265enc);
662   gst_x265_enc_dequeue_all_frames (x265enc);
663 
664   if (x265enc->input_state)
665     gst_video_codec_state_unref (x265enc->input_state);
666   x265enc->input_state = NULL;
667 
668   g_ptr_array_set_size (x265enc->peer_profiles, 0);
669 
670   return TRUE;
671 }
672 
673 
674 static gboolean
gst_x265_enc_flush(GstVideoEncoder * encoder)675 gst_x265_enc_flush (GstVideoEncoder * encoder)
676 {
677   GstX265Enc *x265enc = GST_X265_ENC (encoder);
678 
679   GST_DEBUG_OBJECT (encoder, "flushing encoder");
680 
681   gst_x265_enc_flush_frames (x265enc, FALSE);
682   gst_x265_enc_close_encoder (x265enc);
683   gst_x265_enc_dequeue_all_frames (x265enc);
684 
685   gst_x265_enc_init_encoder (x265enc);
686 
687   return TRUE;
688 }
689 
690 static void
gst_x265_enc_finalize(GObject * object)691 gst_x265_enc_finalize (GObject * object)
692 {
693   GstX265Enc *encoder = GST_X265_ENC (object);
694 
695   if (encoder->input_state)
696     gst_video_codec_state_unref (encoder->input_state);
697   encoder->input_state = NULL;
698 
699   gst_x265_enc_close_encoder (encoder);
700 
701   g_string_free (encoder->option_string_prop, TRUE);
702 
703   if (encoder->peer_profiles)
704     g_ptr_array_free (encoder->peer_profiles, FALSE);
705 
706   G_OBJECT_CLASS (parent_class)->finalize (object);
707 }
708 
709 static gint
gst_x265_enc_gst_to_x265_video_format(GstVideoFormat format,gint * nplanes)710 gst_x265_enc_gst_to_x265_video_format (GstVideoFormat format, gint * nplanes)
711 {
712   switch (format) {
713     case GST_VIDEO_FORMAT_I420:
714     case GST_VIDEO_FORMAT_YV12:
715     case GST_VIDEO_FORMAT_I420_10LE:
716     case GST_VIDEO_FORMAT_I420_10BE:
717     case GST_VIDEO_FORMAT_I420_12LE:
718     case GST_VIDEO_FORMAT_I420_12BE:
719       if (nplanes)
720         *nplanes = 3;
721       return X265_CSP_I420;
722     case GST_VIDEO_FORMAT_Y444:
723     case GST_VIDEO_FORMAT_Y444_10LE:
724     case GST_VIDEO_FORMAT_Y444_10BE:
725     case GST_VIDEO_FORMAT_Y444_12LE:
726     case GST_VIDEO_FORMAT_Y444_12BE:
727       if (nplanes)
728         *nplanes = 3;
729       return X265_CSP_I444;
730     case GST_VIDEO_FORMAT_Y42B:
731     case GST_VIDEO_FORMAT_I422_10LE:
732     case GST_VIDEO_FORMAT_I422_10BE:
733     case GST_VIDEO_FORMAT_I422_12LE:
734     case GST_VIDEO_FORMAT_I422_12BE:
735       if (nplanes)
736         *nplanes = 3;
737       return X265_CSP_I422;
738     default:
739       g_return_val_if_reached (GST_VIDEO_FORMAT_UNKNOWN);
740   }
741 }
742 
743 /*
744  * gst_x265_enc_parse_options
745  * @encoder: Encoder to which options are assigned
746  * @str: Option string
747  *
748  * Parse option string and assign to x265 parameters
749  *
750  */
751 static gboolean
gst_x265_enc_parse_options(GstX265Enc * encoder,const gchar * str)752 gst_x265_enc_parse_options (GstX265Enc * encoder, const gchar * str)
753 {
754   GStrv kvpairs;
755   guint npairs, i;
756   gint parse_result = 0, ret = 0;
757   gchar *options = (gchar *) str;
758   const x265_api *api = encoder->api;
759 
760   g_assert (api != NULL);
761 
762   while (*options == ':')
763     options++;
764 
765   kvpairs = g_strsplit (options, ":", 0);
766   npairs = g_strv_length (kvpairs);
767 
768   for (i = 0; i < npairs; i++) {
769     GStrv key_val = g_strsplit (kvpairs[i], "=", 2);
770 
771     parse_result =
772         api->param_parse (&encoder->x265param, key_val[0], key_val[1]);
773 
774     if (parse_result == X265_PARAM_BAD_NAME) {
775       GST_ERROR_OBJECT (encoder, "Bad name for option %s=%s",
776           key_val[0] ? key_val[0] : "", key_val[1] ? key_val[1] : "");
777     }
778     if (parse_result == X265_PARAM_BAD_VALUE) {
779       GST_ERROR_OBJECT (encoder,
780           "Bad value for option %s=%s (Note: a NULL value for a non-boolean triggers this)",
781           key_val[0] ? key_val[0] : "", key_val[1] ? key_val[1] : "");
782     }
783 
784     g_strfreev (key_val);
785 
786     if (parse_result)
787       ret++;
788   }
789 
790   g_strfreev (kvpairs);
791   return !ret;
792 }
793 
794 static gboolean
gst_x265_enc_init_encoder_locked(GstX265Enc * encoder)795 gst_x265_enc_init_encoder_locked (GstX265Enc * encoder)
796 {
797   GstVideoInfo *info;
798   guint bitdepth;
799   gboolean peer_intra = FALSE;
800 
801   if (!encoder->input_state) {
802     GST_DEBUG_OBJECT (encoder, "Have no input state yet");
803     return FALSE;
804   }
805 
806   info = &encoder->input_state->info;
807 
808   /* make sure that the encoder is closed */
809   gst_x265_enc_close_encoder (encoder);
810 
811   bitdepth = GST_VIDEO_INFO_COMP_DEPTH (info, 0);
812   encoder->api = NULL;
813 
814   switch (bitdepth) {
815     case 8:
816       if (vtable_8bit)
817         encoder->api = vtable_8bit;
818       else if (vtable_10bit)
819         encoder->api = vtable_10bit;
820       else
821         encoder->api = vtable_12bit;
822       break;
823     case 10:
824       if (vtable_10bit)
825         encoder->api = vtable_10bit;
826       else
827         encoder->api = vtable_12bit;
828       break;
829     case 12:
830       encoder->api = vtable_12bit;
831       break;
832     default:
833       break;
834   }
835 
836   if (!encoder->api) {
837     GST_ERROR_OBJECT (encoder, "no %d bitdepth vtable available", bitdepth);
838     return FALSE;
839   }
840 
841   if (encoder->api->param_default_preset (&encoder->x265param,
842           x265_preset_names[encoder->speed_preset - 1],
843           x265_tune_names[encoder->tune - 1]) < 0) {
844     GST_DEBUG_OBJECT (encoder, "preset or tune unrecognized");
845     return FALSE;
846   }
847 
848   /* set up encoder parameters */
849   encoder->x265param.logLevel = encoder->log_level;
850   encoder->x265param.internalCsp =
851       gst_x265_enc_gst_to_x265_video_format (info->finfo->format, NULL);
852   if (info->fps_d == 0 || info->fps_n == 0) {
853   } else {
854     encoder->x265param.fpsNum = info->fps_n;
855     encoder->x265param.fpsDenom = info->fps_d;
856   }
857   encoder->x265param.sourceWidth = info->width;
858   encoder->x265param.sourceHeight = info->height;
859 
860   /* x265 does not allow user to configure a picture size smaller than
861    * at least one CU size, and maxCUSize must be 16, 32, or 64.
862    * Therefore, we should be set the CU size according to the input resolution.
863    */
864   if (encoder->x265param.sourceWidth < 64
865       || encoder->x265param.sourceHeight < 64)
866     encoder->x265param.maxCUSize = 32;
867   if (encoder->x265param.sourceWidth < 32
868       || encoder->x265param.sourceHeight < 32)
869     encoder->x265param.maxCUSize = 16;
870 
871   if (info->par_d > 0) {
872     encoder->x265param.vui.aspectRatioIdc = X265_EXTENDED_SAR;
873     encoder->x265param.vui.sarWidth = info->par_n;
874     encoder->x265param.vui.sarHeight = info->par_d;
875   }
876 
877   encoder->x265param.vui.bEnableVideoSignalTypePresentFlag = 1;
878   /* Unspecified video format (5) */
879   encoder->x265param.vui.videoFormat = 5;
880   if (info->colorimetry.range == GST_VIDEO_COLOR_RANGE_0_255) {
881     encoder->x265param.vui.bEnableVideoFullRangeFlag = 1;
882   } else {
883     encoder->x265param.vui.bEnableVideoFullRangeFlag = 0;
884   }
885 
886   encoder->x265param.vui.bEnableColorDescriptionPresentFlag = 1;
887   encoder->x265param.vui.matrixCoeffs =
888       gst_video_color_matrix_to_iso (info->colorimetry.matrix);
889   encoder->x265param.vui.colorPrimaries =
890       gst_video_color_primaries_to_iso (info->colorimetry.primaries);
891   encoder->x265param.vui.transferCharacteristics =
892       gst_video_transfer_function_to_iso (info->colorimetry.transfer);
893 
894   if (encoder->qp != -1) {
895     /* CQP */
896     encoder->x265param.rc.qp = encoder->qp;
897     encoder->x265param.rc.rateControlMode = X265_RC_CQP;
898   } else {
899     /* ABR */
900     encoder->x265param.rc.bitrate = encoder->bitrate;
901     encoder->x265param.rc.rateControlMode = X265_RC_ABR;
902   }
903 
904   if (encoder->peer_profiles->len > 0) {
905     gint i;
906 
907     for (i = 0; i < encoder->peer_profiles->len; i++) {
908       const gchar *profile = g_ptr_array_index (encoder->peer_profiles, i);
909 
910       GST_DEBUG_OBJECT (encoder, "Apply peer profile %s", profile);
911       if (encoder->api->param_apply_profile (&encoder->x265param, profile) < 0) {
912         GST_WARNING_OBJECT (encoder, "Failed to apply profile %s", profile);
913       } else {
914         /* libx265 chooses still-picture profile only if x265_param::totalFrames
915          * equals to one (otherwise, -intra profile will be chosen) */
916         if (g_strrstr (profile, "stillpicture"))
917           encoder->x265param.totalFrames = 1;
918 
919         if (g_str_has_suffix (profile, "-intra"))
920           peer_intra = TRUE;
921 
922         break;
923       }
924     }
925 
926     if (i == encoder->peer_profiles->len) {
927       GST_ERROR_OBJECT (encoder, "Couldn't apply peer profile");
928 
929       return FALSE;
930     }
931   }
932 
933   if (peer_intra) {
934     encoder->x265param.keyframeMax = 1;
935   } else if (encoder->keyintmax > 0) {
936     encoder->x265param.keyframeMax = encoder->keyintmax;
937   }
938 #if (X265_BUILD >= 79)
939   {
940     GstVideoMasteringDisplayInfo minfo;
941     GstVideoContentLightLevel cll;
942 
943     if (gst_video_mastering_display_info_from_caps (&minfo,
944             encoder->input_state->caps)) {
945       GST_DEBUG_OBJECT (encoder, "Apply mastering display info");
946 
947       /* GstVideoMasteringDisplayInfo::display_primaries is rgb order but
948        * HEVC uses gbr order
949        * See spec D.3.28 display_primaries_x and display_primaries_y
950        */
951       encoder->x265param.masteringDisplayColorVolume =
952           g_strdup_printf ("G(%hu,%hu)B(%hu,%hu)R(%hu,%hu)WP(%hu,%hu)L(%u,%u)",
953           minfo.display_primaries[1].x, minfo.display_primaries[1].y,
954           minfo.display_primaries[2].x, minfo.display_primaries[2].y,
955           minfo.display_primaries[0].x, minfo.display_primaries[0].y,
956           minfo.white_point.x, minfo.white_point.y,
957           minfo.max_display_mastering_luminance,
958           minfo.min_display_mastering_luminance);
959     }
960 
961     if (gst_video_content_light_level_from_caps (&cll,
962             encoder->input_state->caps)) {
963       GST_DEBUG_OBJECT (encoder, "Apply content light level");
964 
965       encoder->x265param.maxCLL = cll.max_content_light_level;
966       encoder->x265param.maxFALL = cll.max_frame_average_light_level;
967     }
968   }
969 #endif
970 
971   /* apply option-string property */
972   if (encoder->option_string_prop && encoder->option_string_prop->len) {
973     GST_DEBUG_OBJECT (encoder, "Applying option-string: %s",
974         encoder->option_string_prop->str);
975     if (gst_x265_enc_parse_options (encoder,
976             encoder->option_string_prop->str) == FALSE) {
977       GST_DEBUG_OBJECT (encoder, "Your option-string contains errors.");
978       return FALSE;
979     }
980   }
981 
982   encoder->reconfig = FALSE;
983 
984   /* good start, will be corrected if needed */
985   encoder->dts_offset = 0;
986 
987   encoder->x265enc = encoder->api->encoder_open (&encoder->x265param);
988   if (!encoder->x265enc) {
989     GST_ERROR_OBJECT (encoder, "Can not open x265 encoder.");
990     return FALSE;
991   }
992 
993   encoder->push_header = TRUE;
994 
995   return TRUE;
996 }
997 
998 /*
999  * gst_x265_enc_init_encoder
1000  * @encoder:  Encoder which should be initialized.
1001  *
1002  * Initialize x265 encoder.
1003  *
1004  */
1005 static gboolean
gst_x265_enc_init_encoder(GstX265Enc * encoder)1006 gst_x265_enc_init_encoder (GstX265Enc * encoder)
1007 {
1008   gboolean result;
1009 
1010   GST_OBJECT_LOCK (encoder);
1011   result = gst_x265_enc_init_encoder_locked (encoder);
1012   GST_OBJECT_UNLOCK (encoder);
1013 
1014   if (!result)
1015     GST_ELEMENT_ERROR (encoder, STREAM, ENCODE,
1016         ("Can not initialize x265 encoder."), (NULL));
1017 
1018   return result;
1019 }
1020 
1021 /* gst_x265_enc_close_encoder
1022  * @encoder:  Encoder which should close.
1023  *
1024  * Close x265 encoder.
1025  */
1026 static void
gst_x265_enc_close_encoder(GstX265Enc * encoder)1027 gst_x265_enc_close_encoder (GstX265Enc * encoder)
1028 {
1029   if (encoder->x265enc != NULL) {
1030     g_assert (encoder->api != NULL);
1031 
1032     encoder->api->encoder_close (encoder->x265enc);
1033     encoder->x265enc = NULL;
1034   }
1035 }
1036 
1037 static x265_nal *
gst_x265_enc_bytestream_to_nal(x265_nal * input)1038 gst_x265_enc_bytestream_to_nal (x265_nal * input)
1039 {
1040   x265_nal *output;
1041   int i, j, zeros;
1042 
1043   output = g_malloc (sizeof (x265_nal));
1044   output->payload = g_malloc (input->sizeBytes - 4);
1045   output->sizeBytes = input->sizeBytes - 4;
1046   output->type = input->type;
1047 
1048   zeros = 0;
1049   for (i = 4, j = 0; i < input->sizeBytes; (i++, j++)) {
1050     if (input->payload[i] == 0x00) {
1051       zeros++;
1052     } else if (input->payload[i] == 0x03 && zeros == 2) {
1053       zeros = 0;
1054       j--;
1055       output->sizeBytes--;
1056       continue;
1057     } else {
1058       zeros = 0;
1059     }
1060     output->payload[j] = input->payload[i];
1061   }
1062 
1063   return output;
1064 }
1065 
1066 static void
x265_nal_free(x265_nal * nal)1067 x265_nal_free (x265_nal * nal)
1068 {
1069   g_free (nal->payload);
1070   g_free (nal);
1071 }
1072 
1073 static gboolean
gst_x265_enc_set_level_tier_and_profile(GstX265Enc * encoder,GstCaps * caps)1074 gst_x265_enc_set_level_tier_and_profile (GstX265Enc * encoder, GstCaps * caps)
1075 {
1076   x265_nal *nal, *vps_nal;
1077   guint32 i_nal;
1078   int header_return;
1079   const x265_api *api = encoder->api;
1080   GstStructure *s;
1081   const gchar *profile;
1082   GstCaps *allowed_caps;
1083   GstStructure *s2;
1084   const gchar *allowed_profile;
1085 
1086   GST_DEBUG_OBJECT (encoder, "set profile, level and tier");
1087 
1088   g_assert (api != NULL);
1089 
1090   header_return = api->encoder_headers (encoder->x265enc, &nal, &i_nal);
1091   if (header_return < 0) {
1092     GST_ELEMENT_ERROR (encoder, STREAM, ENCODE, ("Encode x265 header failed."),
1093         ("x265_encoder_headers return code=%d", header_return));
1094     return FALSE;
1095   }
1096 
1097   GST_DEBUG_OBJECT (encoder, "%d nal units in header", i_nal);
1098 
1099   g_assert (nal[0].type == NAL_UNIT_VPS);
1100   vps_nal = gst_x265_enc_bytestream_to_nal (&nal[0]);
1101 
1102   GST_MEMDUMP ("VPS", vps_nal->payload, vps_nal->sizeBytes);
1103 
1104   gst_codec_utils_h265_caps_set_level_tier_and_profile (caps,
1105       vps_nal->payload + 6, vps_nal->sizeBytes - 6);
1106   x265_nal_free (vps_nal);
1107 
1108   /* relaxing the profile condition since libx265 can select lower profile than
1109    * requested one via param_apply_profile()
1110    */
1111   s = gst_caps_get_structure (caps, 0);
1112   profile = gst_structure_get_string (s, "profile");
1113 
1114   allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (encoder));
1115 
1116   if (allowed_caps == NULL)
1117     goto no_peer;
1118 
1119   if (!gst_caps_can_intersect (allowed_caps, caps)) {
1120     guint peer_bitdepth = 0;
1121     guint peer_chroma_format = 0;
1122     guint bitdepth = 0;
1123     guint chroma_format = 0;
1124 
1125     allowed_caps = gst_caps_make_writable (allowed_caps);
1126     allowed_caps = gst_caps_truncate (allowed_caps);
1127     s2 = gst_caps_get_structure (allowed_caps, 0);
1128     gst_structure_fixate_field_string (s2, "profile", profile);
1129     allowed_profile = gst_structure_get_string (s2, "profile");
1130 
1131     check_formats (allowed_profile, &peer_chroma_format, &peer_bitdepth);
1132     check_formats (profile, &chroma_format, &bitdepth);
1133 
1134     if (chroma_format <= peer_chroma_format && bitdepth <= peer_bitdepth) {
1135       GST_INFO_OBJECT (encoder, "downstream requested %s profile, but "
1136           "encoder will now output %s profile (which is a subset), due "
1137           "to how it's been configured", allowed_profile, profile);
1138       gst_structure_set (s, "profile", G_TYPE_STRING, allowed_profile, NULL);
1139     }
1140   }
1141   gst_caps_unref (allowed_caps);
1142 
1143 no_peer:
1144 
1145   return TRUE;
1146 }
1147 
1148 static GstBuffer *
gst_x265_enc_get_header_buffer(GstX265Enc * encoder)1149 gst_x265_enc_get_header_buffer (GstX265Enc * encoder)
1150 {
1151   x265_nal *nal;
1152   guint32 i_nal, i, offset;
1153   gint32 vps_idx, sps_idx, pps_idx;
1154   int header_return;
1155   GstBuffer *buf;
1156   gsize header_size = 0;
1157   const x265_api *api = encoder->api;
1158 
1159   g_assert (api != NULL);
1160 
1161   header_return = api->encoder_headers (encoder->x265enc, &nal, &i_nal);
1162   if (header_return < 0) {
1163     GST_ELEMENT_ERROR (encoder, STREAM, ENCODE, ("Encode x265 header failed."),
1164         ("x265_encoder_headers return code=%d", header_return));
1165     return FALSE;
1166   }
1167 
1168   GST_DEBUG_OBJECT (encoder, "%d nal units in header", i_nal);
1169 
1170   /* x265 returns also non header nal units with the call x265_encoder_headers.
1171    * The useful headers are sequential (VPS, SPS and PPS), so we look for this
1172    * nal units and only copy these tree nal units as the header */
1173 
1174   vps_idx = sps_idx = pps_idx = -1;
1175   for (i = 0; i < i_nal; i++) {
1176     if (nal[i].type == NAL_UNIT_VPS) {
1177       vps_idx = i;
1178       header_size += nal[i].sizeBytes;
1179     } else if (nal[i].type == NAL_UNIT_SPS) {
1180       sps_idx = i;
1181       header_size += nal[i].sizeBytes;
1182     } else if (nal[i].type == NAL_UNIT_PPS) {
1183       pps_idx = i;
1184       header_size += nal[i].sizeBytes;
1185     } else if (nal[i].type == NAL_UNIT_PREFIX_SEI) {
1186       header_size += nal[i].sizeBytes;
1187     }
1188   }
1189 
1190   if (vps_idx == -1 || sps_idx == -1 || pps_idx == -1) {
1191     GST_ELEMENT_ERROR (encoder, STREAM, ENCODE, ("Encode x265 header failed."),
1192         ("x265_encoder_headers did not return VPS, SPS and PPS"));
1193     return FALSE;
1194   }
1195 
1196   offset = 0;
1197   buf = gst_buffer_new_allocate (NULL, header_size, NULL);
1198   gst_buffer_fill (buf, offset, nal[vps_idx].payload, nal[vps_idx].sizeBytes);
1199   offset += nal[vps_idx].sizeBytes;
1200   gst_buffer_fill (buf, offset, nal[sps_idx].payload, nal[sps_idx].sizeBytes);
1201   offset += nal[sps_idx].sizeBytes;
1202   gst_buffer_fill (buf, offset, nal[pps_idx].payload, nal[pps_idx].sizeBytes);
1203   offset += nal[pps_idx].sizeBytes;
1204 
1205   for (i = 0; i < i_nal; i++) {
1206     if (nal[i].type == NAL_UNIT_PREFIX_SEI) {
1207       gst_buffer_fill (buf, offset, nal[i].payload, nal[i].sizeBytes);
1208       offset += nal[i].sizeBytes;
1209     }
1210   }
1211 
1212   return buf;
1213 }
1214 
1215 /* gst_x265_enc_set_src_caps
1216  * Returns: TRUE on success.
1217  */
1218 static gboolean
gst_x265_enc_set_src_caps(GstX265Enc * encoder,GstCaps * caps)1219 gst_x265_enc_set_src_caps (GstX265Enc * encoder, GstCaps * caps)
1220 {
1221   GstCaps *outcaps;
1222   GstStructure *structure;
1223   GstVideoCodecState *state;
1224   GstTagList *tags;
1225 
1226   outcaps = gst_caps_new_empty_simple ("video/x-h265");
1227   structure = gst_caps_get_structure (outcaps, 0);
1228 
1229   gst_structure_set (structure, "stream-format", G_TYPE_STRING, "byte-stream",
1230       NULL);
1231   gst_structure_set (structure, "alignment", G_TYPE_STRING, "au", NULL);
1232 
1233   if (!gst_x265_enc_set_level_tier_and_profile (encoder, outcaps)) {
1234     gst_caps_unref (outcaps);
1235     return FALSE;
1236   }
1237 
1238   state = gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (encoder),
1239       outcaps, encoder->input_state);
1240   GST_DEBUG_OBJECT (encoder, "output caps: %" GST_PTR_FORMAT, state->caps);
1241   gst_video_codec_state_unref (state);
1242 
1243   tags = gst_tag_list_new_empty ();
1244   gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER, "x265",
1245       GST_TAG_ENCODER_VERSION, x265_version_str, NULL);
1246   gst_video_encoder_merge_tags (GST_VIDEO_ENCODER (encoder), tags,
1247       GST_TAG_MERGE_REPLACE);
1248   gst_tag_list_unref (tags);
1249 
1250   return TRUE;
1251 }
1252 
1253 static void
gst_x265_enc_set_latency(GstX265Enc * encoder)1254 gst_x265_enc_set_latency (GstX265Enc * encoder)
1255 {
1256   GstVideoInfo *info = &encoder->input_state->info;
1257   gint max_delayed_frames;
1258   GstClockTime latency;
1259 
1260   /* FIXME get a real value from the encoder, this is currently not exposed */
1261   if (encoder->tune > 0 && encoder->tune <= G_N_ELEMENTS (x265_tune_names) &&
1262       strcmp (x265_tune_names[encoder->tune - 1], "zerolatency") == 0)
1263     max_delayed_frames = 0;
1264   else
1265     max_delayed_frames = 5;
1266 
1267   if (info->fps_n) {
1268     latency = gst_util_uint64_scale_ceil (GST_SECOND * info->fps_d,
1269         max_delayed_frames, info->fps_n);
1270   } else {
1271     /* FIXME: Assume 25fps. This is better than reporting no latency at
1272      * all and then later failing in live pipelines
1273      */
1274     latency = gst_util_uint64_scale_ceil (GST_SECOND * 1,
1275         max_delayed_frames, 25);
1276   }
1277 
1278   GST_INFO_OBJECT (encoder,
1279       "Updating latency to %" GST_TIME_FORMAT " (%d frames)",
1280       GST_TIME_ARGS (latency), max_delayed_frames);
1281 
1282   gst_video_encoder_set_latency (GST_VIDEO_ENCODER (encoder), latency, latency);
1283 }
1284 
1285 typedef struct
1286 {
1287   const gchar *gst_profile;
1288   const gchar *x265_profile;
1289 } GstX265EncProfileTable;
1290 
1291 static const gchar *
gst_x265_enc_profile_from_gst(const gchar * profile)1292 gst_x265_enc_profile_from_gst (const gchar * profile)
1293 {
1294   gint i;
1295   static const GstX265EncProfileTable profile_table[] = {
1296     /* 8 bits */
1297     {"main", "main"},
1298     {"main-still-picture", "mainstillpicture"},
1299     {"main-intra", "main-intra"},
1300     {"main-444", "main444-8"},
1301     {"main-444-intra", "main444-intra"},
1302     {"main-444-still-picture", "main444-stillpicture"},
1303     /* 10 bits */
1304     {"main-10", "main10"},
1305     {"main-10-intra", "main10-intra"},
1306     {"main-422-10", "main422-10"},
1307     {"main-422-10-intra", "main422-10-intra"},
1308     {"main-444-10", "main444-10"},
1309     {"main-444-10-intra", "main444-10-intra"},
1310     /* 12 bits */
1311     {"main-12", "main12"},
1312     {"main-12-intra", "main12-intra"},
1313     {"main-422-12", "main422-12"},
1314     {"main-422-12-intra", "main422-12-intra"},
1315     {"main-444-12", "main444-12"},
1316     {"main-444-12-intra", "main444-12-intra"},
1317   };
1318 
1319   if (!profile)
1320     return NULL;
1321 
1322   for (i = 0; i < G_N_ELEMENTS (profile_table); i++) {
1323     if (!strcmp (profile, profile_table[i].gst_profile))
1324       return profile_table[i].x265_profile;
1325   }
1326 
1327   return NULL;
1328 }
1329 
1330 static gboolean
gst_x265_enc_set_format(GstVideoEncoder * video_enc,GstVideoCodecState * state)1331 gst_x265_enc_set_format (GstVideoEncoder * video_enc,
1332     GstVideoCodecState * state)
1333 {
1334   GstX265Enc *encoder = GST_X265_ENC (video_enc);
1335   GstVideoInfo *info = &state->info;
1336   GstCaps *template_caps;
1337   GstCaps *allowed_caps = NULL;
1338 
1339   /* If the encoder is initialized, do not reinitialize it again if not
1340    * necessary */
1341   if (encoder->x265enc) {
1342     GstVideoInfo *old = &encoder->input_state->info;
1343 
1344     if (info->finfo->format == old->finfo->format
1345         && info->width == old->width && info->height == old->height
1346         && info->fps_n == old->fps_n && info->fps_d == old->fps_d
1347         && info->par_n == old->par_n && info->par_d == old->par_d) {
1348       gst_video_codec_state_unref (encoder->input_state);
1349       encoder->input_state = gst_video_codec_state_ref (state);
1350       return TRUE;
1351     }
1352 
1353     /* clear out pending frames */
1354     gst_x265_enc_flush_frames (encoder, TRUE);
1355   }
1356 
1357   if (encoder->input_state)
1358     gst_video_codec_state_unref (encoder->input_state);
1359   encoder->input_state = gst_video_codec_state_ref (state);
1360 
1361   g_ptr_array_set_size (encoder->peer_profiles, 0);
1362 
1363   template_caps = gst_static_pad_template_get_caps (&src_factory);
1364   allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (encoder));
1365 
1366   GST_DEBUG_OBJECT (encoder, "allowed caps %" GST_PTR_FORMAT, allowed_caps);
1367 
1368   /* allowed != template is meaning that downstream has some restriction
1369    * so we need check whether there is requested profile or not */
1370   if (allowed_caps && !gst_caps_is_equal (allowed_caps, template_caps)) {
1371     gint i, j;
1372 
1373     if (gst_caps_is_empty (allowed_caps)) {
1374       gst_caps_unref (allowed_caps);
1375       gst_caps_unref (template_caps);
1376       return FALSE;
1377     }
1378 
1379     for (i = 0; i < gst_caps_get_size (allowed_caps); i++) {
1380       GstStructure *s;
1381       const GValue *val;
1382       const gchar *profile;
1383       const gchar *x265_profile;
1384 
1385       s = gst_caps_get_structure (allowed_caps, i);
1386 
1387       if ((val = gst_structure_get_value (s, "profile"))) {
1388         if (G_VALUE_HOLDS_STRING (val)) {
1389           profile = g_value_get_string (val);
1390           x265_profile = gst_x265_enc_profile_from_gst (profile);
1391 
1392           if (x265_profile) {
1393             GST_DEBUG_OBJECT (encoder,
1394                 "Add profile %s to peer profile list", x265_profile);
1395 
1396             g_ptr_array_add (encoder->peer_profiles, (gpointer) x265_profile);
1397           }
1398         } else if (GST_VALUE_HOLDS_LIST (val)) {
1399           for (j = 0; j < gst_value_list_get_size (val); j++) {
1400             const GValue *vlist = gst_value_list_get_value (val, j);
1401             profile = g_value_get_string (vlist);
1402             x265_profile = gst_x265_enc_profile_from_gst (profile);
1403 
1404             if (x265_profile) {
1405               GST_DEBUG_OBJECT (encoder,
1406                   "Add profile %s to peer profile list", x265_profile);
1407 
1408               g_ptr_array_add (encoder->peer_profiles, (gpointer) x265_profile);
1409             }
1410           }
1411         }
1412       }
1413     }
1414   }
1415 
1416   gst_clear_caps (&allowed_caps);
1417   gst_caps_unref (template_caps);
1418 
1419 
1420   if (!gst_x265_enc_init_encoder (encoder))
1421     return FALSE;
1422 
1423   if (!gst_x265_enc_set_src_caps (encoder, state->caps)) {
1424     gst_x265_enc_close_encoder (encoder);
1425     return FALSE;
1426   }
1427 
1428   gst_x265_enc_set_latency (encoder);
1429 
1430   return TRUE;
1431 }
1432 
1433 static GstFlowReturn
gst_x265_enc_finish(GstVideoEncoder * encoder)1434 gst_x265_enc_finish (GstVideoEncoder * encoder)
1435 {
1436   GST_DEBUG_OBJECT (encoder, "finish encoder");
1437 
1438   gst_x265_enc_flush_frames (GST_X265_ENC (encoder), TRUE);
1439   gst_x265_enc_flush_frames (GST_X265_ENC (encoder), TRUE);
1440   return GST_FLOW_OK;
1441 }
1442 
1443 static gboolean
gst_x265_enc_propose_allocation(GstVideoEncoder * encoder,GstQuery * query)1444 gst_x265_enc_propose_allocation (GstVideoEncoder * encoder, GstQuery * query)
1445 {
1446   gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
1447 
1448   return GST_VIDEO_ENCODER_CLASS (parent_class)->propose_allocation (encoder,
1449       query);
1450 }
1451 
1452 /* chain function
1453  * this function does the actual processing
1454  */
1455 static GstFlowReturn
gst_x265_enc_handle_frame(GstVideoEncoder * video_enc,GstVideoCodecFrame * frame)1456 gst_x265_enc_handle_frame (GstVideoEncoder * video_enc,
1457     GstVideoCodecFrame * frame)
1458 {
1459   GstX265Enc *encoder = GST_X265_ENC (video_enc);
1460   GstVideoInfo *info = &encoder->input_state->info;
1461   GstFlowReturn ret;
1462   x265_picture pic_in;
1463   guint32 i_nal, i;
1464   FrameData *fdata;
1465   gint nplanes = 0;
1466   const x265_api *api = encoder->api;
1467 
1468   g_assert (api != NULL);
1469 
1470   if (G_UNLIKELY (encoder->x265enc == NULL))
1471     goto not_inited;
1472 
1473   /* set up input picture */
1474   api->picture_init (&encoder->x265param, &pic_in);
1475 
1476   fdata = gst_x265_enc_queue_frame (encoder, frame, info);
1477   if (!fdata)
1478     goto invalid_frame;
1479 
1480   pic_in.colorSpace =
1481       gst_x265_enc_gst_to_x265_video_format (info->finfo->format, &nplanes);
1482   for (i = 0; i < nplanes; i++) {
1483     pic_in.planes[i] = GST_VIDEO_FRAME_PLANE_DATA (&fdata->vframe, i);
1484     pic_in.stride[i] = GST_VIDEO_FRAME_COMP_STRIDE (&fdata->vframe, i);
1485   }
1486 
1487   pic_in.sliceType = X265_TYPE_AUTO;
1488   pic_in.pts = frame->pts;
1489   pic_in.dts = frame->dts;
1490   pic_in.bitDepth = info->finfo->depth[0];
1491   pic_in.userData = GINT_TO_POINTER (frame->system_frame_number);
1492 
1493   ret = gst_x265_enc_encode_frame (encoder, &pic_in, frame, &i_nal, TRUE);
1494 
1495   /* input buffer is released later on */
1496   return ret;
1497 
1498 /* ERRORS */
1499 not_inited:
1500   {
1501     GST_WARNING_OBJECT (encoder, "Got buffer before set_caps was called");
1502     return GST_FLOW_NOT_NEGOTIATED;
1503   }
1504 invalid_frame:
1505   {
1506     GST_ERROR_OBJECT (encoder, "Failed to map frame");
1507     return GST_FLOW_ERROR;
1508   }
1509 }
1510 
1511 static GstFlowReturn
gst_x265_enc_encode_frame(GstX265Enc * encoder,x265_picture * pic_in,GstVideoCodecFrame * input_frame,guint32 * i_nal,gboolean send)1512 gst_x265_enc_encode_frame (GstX265Enc * encoder, x265_picture * pic_in,
1513     GstVideoCodecFrame * input_frame, guint32 * i_nal, gboolean send)
1514 {
1515   GstVideoCodecFrame *frame = NULL;
1516   GstBuffer *out_buf = NULL;
1517   x265_picture pic_out;
1518   x265_nal *nal;
1519   int i_size, i, offset;
1520   int encoder_return;
1521   GstFlowReturn ret = GST_FLOW_OK;
1522   gboolean update_latency = FALSE;
1523   const x265_api *api;
1524 
1525   if (G_UNLIKELY (encoder->x265enc == NULL)) {
1526     if (input_frame)
1527       gst_video_codec_frame_unref (input_frame);
1528     return GST_FLOW_NOT_NEGOTIATED;
1529   }
1530 
1531   api = encoder->api;
1532   g_assert (api != NULL);
1533 
1534   GST_OBJECT_LOCK (encoder);
1535   if (encoder->reconfig) {
1536     /* x265_encoder_reconfig is not yet implemented thus we shut down and re-create encoder */
1537     gst_x265_enc_init_encoder_locked (encoder);
1538     update_latency = TRUE;
1539   }
1540 
1541   if (pic_in && input_frame) {
1542     if (GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (input_frame)) {
1543       GST_INFO_OBJECT (encoder, "Forcing key frame");
1544       pic_in->sliceType = X265_TYPE_IDR;
1545     }
1546   }
1547   GST_OBJECT_UNLOCK (encoder);
1548 
1549   if (G_UNLIKELY (update_latency))
1550     gst_x265_enc_set_latency (encoder);
1551 
1552   encoder_return = api->encoder_encode (encoder->x265enc,
1553       &nal, i_nal, pic_in, &pic_out);
1554 
1555   GST_DEBUG_OBJECT (encoder, "encoder result (%d) with %u nal units",
1556       encoder_return, *i_nal);
1557 
1558   if (encoder_return < 0) {
1559     GST_ELEMENT_ERROR (encoder, STREAM, ENCODE, ("Encode x265 frame failed."),
1560         ("x265_encoder_encode return code=%d", encoder_return));
1561     ret = GST_FLOW_ERROR;
1562     /* Make sure we finish this frame */
1563     frame = input_frame;
1564     goto out;
1565   }
1566 
1567   /* Input frame is now queued */
1568   if (input_frame)
1569     gst_video_codec_frame_unref (input_frame);
1570 
1571   if (!*i_nal) {
1572     ret = GST_FLOW_OK;
1573     GST_LOG_OBJECT (encoder, "no output yet");
1574     goto out;
1575   }
1576 
1577   frame = gst_video_encoder_get_frame (GST_VIDEO_ENCODER (encoder),
1578       GPOINTER_TO_INT (pic_out.userData));
1579   g_assert (frame || !send);
1580 
1581   GST_DEBUG_OBJECT (encoder,
1582       "output picture ready POC=%d system=%d frame found %d", pic_out.poc,
1583       GPOINTER_TO_INT (pic_out.userData), frame != NULL);
1584 
1585   if (!send || !frame) {
1586     GST_LOG_OBJECT (encoder, "not sending (%d) or frame not found (%d)", send,
1587         frame != NULL);
1588     ret = GST_FLOW_OK;
1589     goto out;
1590   }
1591 
1592   i_size = 0;
1593   offset = 0;
1594   for (i = 0; i < *i_nal; i++)
1595     i_size += nal[i].sizeBytes;
1596   out_buf = gst_buffer_new_allocate (NULL, i_size, NULL);
1597   for (i = 0; i < *i_nal; i++) {
1598     gst_buffer_fill (out_buf, offset, nal[i].payload, nal[i].sizeBytes);
1599     offset += nal[i].sizeBytes;
1600   }
1601 
1602   if (pic_out.sliceType == X265_TYPE_IDR || pic_out.sliceType == X265_TYPE_I) {
1603     GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
1604   }
1605 
1606   frame->output_buffer = out_buf;
1607 
1608   if (encoder->push_header) {
1609     GstBuffer *header;
1610 
1611     header = gst_x265_enc_get_header_buffer (encoder);
1612     frame->output_buffer = gst_buffer_append (header, frame->output_buffer);
1613     encoder->push_header = FALSE;
1614   }
1615 
1616   GST_LOG_OBJECT (encoder,
1617       "output: dts %" G_GINT64_FORMAT " pts %" G_GINT64_FORMAT,
1618       (gint64) pic_out.dts, (gint64) pic_out.pts);
1619 
1620   frame->dts = pic_out.dts + encoder->dts_offset;
1621 
1622 out:
1623   if (frame) {
1624     gst_x265_enc_dequeue_frame (encoder, frame);
1625     ret = gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (encoder), frame);
1626   }
1627 
1628   return ret;
1629 }
1630 
1631 static void
gst_x265_enc_flush_frames(GstX265Enc * encoder,gboolean send)1632 gst_x265_enc_flush_frames (GstX265Enc * encoder, gboolean send)
1633 {
1634   GstFlowReturn flow_ret;
1635   guint32 i_nal;
1636 
1637   /* first send the remaining frames */
1638   if (encoder->x265enc)
1639     do {
1640       flow_ret = gst_x265_enc_encode_frame (encoder, NULL, NULL, &i_nal, send);
1641     } while (flow_ret == GST_FLOW_OK && i_nal > 0);
1642 }
1643 
1644 static void
gst_x265_enc_reconfig(GstX265Enc * encoder)1645 gst_x265_enc_reconfig (GstX265Enc * encoder)
1646 {
1647   encoder->x265param.rc.bitrate = encoder->bitrate;
1648   encoder->reconfig = TRUE;
1649 }
1650 
1651 static void
gst_x265_enc_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)1652 gst_x265_enc_set_property (GObject * object, guint prop_id,
1653     const GValue * value, GParamSpec * pspec)
1654 {
1655   GstX265Enc *encoder;
1656   GstState state;
1657 
1658   encoder = GST_X265_ENC (object);
1659 
1660   GST_OBJECT_LOCK (encoder);
1661 
1662   state = GST_STATE (encoder);
1663   if ((state != GST_STATE_READY && state != GST_STATE_NULL) &&
1664       !(pspec->flags & GST_PARAM_MUTABLE_PLAYING))
1665     goto wrong_state;
1666 
1667   switch (prop_id) {
1668     case PROP_BITRATE:
1669       encoder->bitrate = g_value_get_uint (value);
1670       break;
1671     case PROP_QP:
1672       encoder->qp = g_value_get_int (value);
1673       break;
1674     case PROP_OPTION_STRING:
1675       g_string_assign (encoder->option_string_prop, g_value_get_string (value));
1676       break;
1677     case PROP_X265_LOG_LEVEL:
1678       encoder->log_level = g_value_get_enum (value);
1679       break;
1680     case PROP_SPEED_PRESET:
1681       encoder->speed_preset = g_value_get_enum (value);
1682       break;
1683     case PROP_TUNE:
1684       encoder->tune = g_value_get_enum (value);
1685       break;
1686     case PROP_KEY_INT_MAX:
1687       encoder->keyintmax = g_value_get_int (value);
1688       break;
1689     default:
1690       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1691       break;
1692   }
1693 
1694   gst_x265_enc_reconfig (encoder);
1695   GST_OBJECT_UNLOCK (encoder);
1696   return;
1697 
1698 wrong_state:
1699   {
1700     GST_WARNING_OBJECT (encoder, "setting property in wrong state");
1701     GST_OBJECT_UNLOCK (encoder);
1702   }
1703 }
1704 
1705 static void
gst_x265_enc_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)1706 gst_x265_enc_get_property (GObject * object, guint prop_id,
1707     GValue * value, GParamSpec * pspec)
1708 {
1709   GstX265Enc *encoder;
1710 
1711   encoder = GST_X265_ENC (object);
1712 
1713   GST_OBJECT_LOCK (encoder);
1714   switch (prop_id) {
1715     case PROP_BITRATE:
1716       g_value_set_uint (value, encoder->bitrate);
1717       break;
1718     case PROP_QP:
1719       g_value_set_int (value, encoder->qp);
1720       break;
1721     case PROP_OPTION_STRING:
1722       g_value_set_string (value, encoder->option_string_prop->str);
1723       break;
1724     case PROP_X265_LOG_LEVEL:
1725       g_value_set_enum (value, encoder->log_level);
1726       break;
1727     case PROP_SPEED_PRESET:
1728       g_value_set_enum (value, encoder->speed_preset);
1729       break;
1730     case PROP_TUNE:
1731       g_value_set_enum (value, encoder->tune);
1732       break;
1733     case PROP_KEY_INT_MAX:
1734       g_value_set_int (value, encoder->keyintmax);
1735       break;
1736     default:
1737       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1738       break;
1739   }
1740   GST_OBJECT_UNLOCK (encoder);
1741 }
1742 
1743 static gboolean
x265enc_element_init(GstPlugin * plugin)1744 x265enc_element_init (GstPlugin * plugin)
1745 {
1746   GST_DEBUG_CATEGORY_INIT (x265_enc_debug, "x265enc", 0,
1747       "h265 encoding element");
1748 
1749   GST_INFO ("x265 build: %u", X265_BUILD);
1750 
1751   default_vtable = *x265_api_get (0);
1752 
1753   GST_INFO ("x265 default bitdepth: %u", default_vtable.bit_depth);
1754 
1755   switch (default_vtable.bit_depth) {
1756     case 8:
1757       vtable_8bit = &default_vtable;
1758       break;
1759     case 10:
1760       vtable_10bit = &default_vtable;
1761       break;
1762     case 12:
1763       vtable_12bit = &default_vtable;
1764       break;
1765     default:
1766       GST_WARNING ("Unknown default bitdepth %d", default_vtable.bit_depth);
1767       break;
1768   }
1769 
1770   if (!vtable_8bit && (vtable_8bit = x265_api_get (8)))
1771     GST_INFO ("x265 8bit api available");
1772 
1773   if (!vtable_10bit && (vtable_10bit = x265_api_get (10)))
1774     GST_INFO ("x265 10bit api available");
1775 
1776 #if (X265_BUILD >= 68)
1777   if (!vtable_12bit && (vtable_12bit = x265_api_get (12)))
1778     GST_INFO ("x265 12bit api available");
1779 #endif
1780 
1781   return gst_element_register (plugin, "x265enc",
1782       GST_RANK_PRIMARY, GST_TYPE_X265_ENC);
1783 }
1784 
1785 static gboolean
plugin_init(GstPlugin * plugin)1786 plugin_init (GstPlugin * plugin)
1787 {
1788   return GST_ELEMENT_REGISTER (x265enc, plugin);
1789 }
1790 
1791 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1792     GST_VERSION_MINOR,
1793     x265,
1794     "x265-based H265 plugins",
1795     plugin_init, VERSION, "GPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
1796