blob: e805a5bcbbc1cc337131aded737601f737c17c16 [file] [log] [blame]
Matthew Watersb1d13e12015-07-30 16:42:38 +10001/* GStreamer NVENC plugin
2 * Copyright (C) 2015 Centricular Ltd
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20#ifdef HAVE_CONFIG_H
21#include "config.h"
22#endif
23
24#include "gstnvbaseenc.h"
25
26#include <gst/pbutils/codec-utils.h>
27
28#include <string.h>
29
30#if HAVE_NVENC_GST_GL
31#include <cuda.h>
32#include <cuda_runtime_api.h>
33#include <cuda_gl_interop.h>
34#include <gst/gl/gl.h>
35#endif
36
37/* TODO:
38 * - reset last_flow on FLUSH_STOP (seeking)
39 */
40
Matthew Watersd6f7ea82016-03-31 01:21:42 +110041/* This currently supports both 5.x and 6.x versions of the NvEncodeAPI.h
42 * header which are mostly API compatible. */
43
Matthew Watersb1d13e12015-07-30 16:42:38 +100044#define N_BUFFERS_PER_FRAME 1
45#define SUPPORTED_GL_APIS GST_GL_API_OPENGL3
46
47/* magic pointer value we can put in the async queue to signal shut down */
48#define SHUTDOWN_COOKIE ((gpointer)GINT_TO_POINTER (1))
49
50#define parent_class gst_nv_base_enc_parent_class
51G_DEFINE_ABSTRACT_TYPE (GstNvBaseEnc, gst_nv_base_enc, GST_TYPE_VIDEO_ENCODER);
52
Matthew Watersc45fc2e2016-04-07 22:46:08 +100053#define GST_TYPE_NV_PRESET (gst_nv_preset_get_type())
54static GType
55gst_nv_preset_get_type (void)
56{
57 static GType nv_preset_type = 0;
58
59 static const GEnumValue presets[] = {
60 {GST_NV_PRESET_DEFAULT, "Default", "default"},
61 {GST_NV_PRESET_HP, "High Performance", "hp"},
62 {GST_NV_PRESET_HQ, "High Quality", "hq"},
63/* {GST_NV_PRESET_BD, "BD", "bd"}, */
64 {GST_NV_PRESET_LOW_LATENCY_DEFAULT, "Low Latency", "low-latency"},
65 {GST_NV_PRESET_LOW_LATENCY_HQ, "Low Latency, High Quality",
66 "low-latency-hq"},
67 {GST_NV_PRESET_LOW_LATENCY_HP, "Low Latency, High Performance",
68 "low-latency-hp"},
69 {GST_NV_PRESET_LOSSLESS_DEFAULT, "Lossless", "lossless"},
70 {GST_NV_PRESET_LOSSLESS_HP, "Lossless, High Performance", "lossless-hp"},
71 {0, NULL, NULL},
72 };
73
74 if (!nv_preset_type) {
75 nv_preset_type = g_enum_register_static ("GstNvPreset", presets);
76 }
77 return nv_preset_type;
78}
79
80static GUID
81_nv_preset_to_guid (GstNvPreset preset)
82{
83 GUID null = { 0, };
84
85 switch (preset) {
86#define CASE(gst,nv) case G_PASTE(GST_NV_PRESET_,gst): return G_PASTE(G_PASTE(NV_ENC_PRESET_,nv),_GUID)
87 CASE (DEFAULT, DEFAULT);
88 CASE (HP, HP);
89 CASE (HQ, HQ);
90/* CASE (BD, BD);*/
91 CASE (LOW_LATENCY_DEFAULT, LOW_LATENCY_DEFAULT);
92 CASE (LOW_LATENCY_HQ, LOW_LATENCY_HQ);
93 CASE (LOW_LATENCY_HP, LOW_LATENCY_HQ);
94 CASE (LOSSLESS_DEFAULT, LOSSLESS_DEFAULT);
95 CASE (LOSSLESS_HP, LOSSLESS_HP);
96#undef CASE
97 default:
98 return null;
99 }
100}
101
Matthew Watersdc1a3262016-04-08 14:51:44 +1000102#define GST_TYPE_NV_RC_MODE (gst_nv_rc_mode_get_type())
103static GType
104gst_nv_rc_mode_get_type (void)
105{
106 static GType nv_rc_mode_type = 0;
107
108 static const GEnumValue modes[] = {
109 {GST_NV_RC_MODE_DEFAULT, "Default (from NVENC preset)", "default"},
110 {GST_NV_RC_MODE_CONSTQP, "Constant Quantization", "constqp"},
111 {GST_NV_RC_MODE_CBR, "Constant Bit Rate", "cbr"},
112 {GST_NV_RC_MODE_VBR, "Variable Bit Rate", "vbr"},
113 {GST_NV_RC_MODE_VBR_MINQP,
114 "Variable Bit Rate (with minimum quantization parameter)",
115 "vbr-minqp"},
116 {0, NULL, NULL},
117 };
118
119 if (!nv_rc_mode_type) {
120 nv_rc_mode_type = g_enum_register_static ("GstNvRCMode", modes);
121 }
122 return nv_rc_mode_type;
123}
124
125static NV_ENC_PARAMS_RC_MODE
126_rc_mode_to_nv (GstNvRCMode mode)
127{
128 switch (mode) {
129 case GST_NV_RC_MODE_DEFAULT:
130 return -1;
131#define CASE(gst,nv) case G_PASTE(GST_NV_RC_MODE_,gst): return G_PASTE(NV_ENC_PARAMS_RC_,nv)
132 CASE (CONSTQP, CONSTQP);
133 CASE (CBR, CBR);
134 CASE (VBR, VBR);
135 CASE (VBR_MINQP, VBR_MINQP);
136#undef CASE
137 default:
138 return -1;
139 }
140}
141
Matthew Watersb1d13e12015-07-30 16:42:38 +1000142static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
143 GST_PAD_SINK,
144 GST_PAD_ALWAYS,
Ole André Vadla Ravnåsbc92b102017-04-14 15:30:44 +0200145 GST_STATIC_CAPS ("video/x-raw, " "format = (string) { NV12, I420 }, " // TODO: YV12, Y444 support
Matthew Watersb1d13e12015-07-30 16:42:38 +1000146 "width = (int) [ 16, 4096 ], height = (int) [ 16, 2160 ], "
147 "framerate = (fraction) [0, MAX],"
148 "interlace-mode = { progressive, mixed, interleaved } "
149#if HAVE_NVENC_GST_GL
150 ";"
151 "video/x-raw(memory:GLMemory), "
152 "format = (string) { NV12, Y444 }, "
153 "width = (int) [ 16, 4096 ], height = (int) [ 16, 2160 ], "
154 "framerate = (fraction) [0, MAX],"
155 "interlace-mode = { progressive, mixed, interleaved } "
156#endif
157 ));
158
159enum
160{
161 PROP_0,
162 PROP_DEVICE_ID,
Matthew Watersc45fc2e2016-04-07 22:46:08 +1000163 PROP_PRESET,
Matthew Watersdc1a3262016-04-08 14:51:44 +1000164 PROP_BITRATE,
165 PROP_RC_MODE,
166 PROP_QP_MIN,
167 PROP_QP_MAX,
168 PROP_QP_CONST,
Tim-Philipp Müller07c84172017-04-16 16:08:27 +0200169 PROP_GOP_SIZE,
Matthew Watersb1d13e12015-07-30 16:42:38 +1000170};
171
Matthew Watersc45fc2e2016-04-07 22:46:08 +1000172#define DEFAULT_PRESET GST_NV_PRESET_DEFAULT
Matthew Watersdc1a3262016-04-08 14:51:44 +1000173#define DEFAULT_BITRATE 0
174#define DEFAULT_RC_MODE GST_NV_RC_MODE_DEFAULT
175#define DEFAULT_QP_MIN -1
176#define DEFAULT_QP_MAX -1
177#define DEFAULT_QP_CONST -1
Tim-Philipp Müller07c84172017-04-16 16:08:27 +0200178#define DEFAULT_GOP_SIZE 75
Matthew Watersc45fc2e2016-04-07 22:46:08 +1000179
Matthew Marsh0e34c022015-12-22 11:10:31 +0200180/* This lock is needed to prevent the situation where multiple encoders are
181 * initialised at the same time which appears to cause excessive CPU usage over
182 * some period of time. */
183G_LOCK_DEFINE_STATIC (initialization_lock);
184
Matthew Watersb1d13e12015-07-30 16:42:38 +1000185#if HAVE_NVENC_GST_GL
186struct gl_input_resource
187{
188 GstGLMemory *gl_mem[GST_VIDEO_MAX_PLANES];
189 struct cudaGraphicsResource *cuda_texture;
190 gpointer cuda_plane_pointers[GST_VIDEO_MAX_PLANES];
191 gpointer cuda_pointer;
192 gsize cuda_stride;
193 gsize cuda_num_bytes;
194 NV_ENC_REGISTER_RESOURCE nv_resource;
195 NV_ENC_MAP_INPUT_RESOURCE nv_mapped_resource;
196};
197#endif
198
199struct frame_state
200{
201 gint n_buffers;
202 gpointer in_bufs[N_BUFFERS_PER_FRAME];
203 gpointer out_bufs[N_BUFFERS_PER_FRAME];
204};
205
206static gboolean gst_nv_base_enc_open (GstVideoEncoder * enc);
207static gboolean gst_nv_base_enc_close (GstVideoEncoder * enc);
208static gboolean gst_nv_base_enc_start (GstVideoEncoder * enc);
209static gboolean gst_nv_base_enc_stop (GstVideoEncoder * enc);
210static void gst_nv_base_enc_set_context (GstElement * element,
211 GstContext * context);
212static gboolean gst_nv_base_enc_sink_query (GstVideoEncoder * enc,
213 GstQuery * query);
214static gboolean gst_nv_base_enc_set_format (GstVideoEncoder * enc,
215 GstVideoCodecState * state);
216static GstFlowReturn gst_nv_base_enc_handle_frame (GstVideoEncoder * enc,
217 GstVideoCodecFrame * frame);
218static void gst_nv_base_enc_free_buffers (GstNvBaseEnc * nvenc);
219static GstFlowReturn gst_nv_base_enc_finish (GstVideoEncoder * enc);
220static void gst_nv_base_enc_set_property (GObject * object, guint prop_id,
221 const GValue * value, GParamSpec * pspec);
222static void gst_nv_base_enc_get_property (GObject * object, guint prop_id,
223 GValue * value, GParamSpec * pspec);
224static void gst_nv_base_enc_finalize (GObject * obj);
225static GstCaps *gst_nv_base_enc_getcaps (GstVideoEncoder * enc,
226 GstCaps * filter);
Ole André Vadla Ravnåscb283142017-04-17 19:25:49 +0200227static gboolean gst_nv_base_enc_stop_bitstream_thread (GstNvBaseEnc * nvenc);
Matthew Watersb1d13e12015-07-30 16:42:38 +1000228
229static void
230gst_nv_base_enc_class_init (GstNvBaseEncClass * klass)
231{
232 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
233 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
234 GstVideoEncoderClass *videoenc_class = GST_VIDEO_ENCODER_CLASS (klass);
235
236 gobject_class->set_property = gst_nv_base_enc_set_property;
237 gobject_class->get_property = gst_nv_base_enc_get_property;
238 gobject_class->finalize = gst_nv_base_enc_finalize;
239
240 element_class->set_context = GST_DEBUG_FUNCPTR (gst_nv_base_enc_set_context);
241
242 videoenc_class->open = GST_DEBUG_FUNCPTR (gst_nv_base_enc_open);
243 videoenc_class->close = GST_DEBUG_FUNCPTR (gst_nv_base_enc_close);
244
245 videoenc_class->start = GST_DEBUG_FUNCPTR (gst_nv_base_enc_start);
246 videoenc_class->stop = GST_DEBUG_FUNCPTR (gst_nv_base_enc_stop);
247
248 videoenc_class->set_format = GST_DEBUG_FUNCPTR (gst_nv_base_enc_set_format);
249 videoenc_class->getcaps = GST_DEBUG_FUNCPTR (gst_nv_base_enc_getcaps);
250 videoenc_class->handle_frame =
251 GST_DEBUG_FUNCPTR (gst_nv_base_enc_handle_frame);
252 videoenc_class->finish = GST_DEBUG_FUNCPTR (gst_nv_base_enc_finish);
253 videoenc_class->sink_query = GST_DEBUG_FUNCPTR (gst_nv_base_enc_sink_query);
254
Vineeth TM8cdfb132016-03-04 15:50:26 +0900255 gst_element_class_add_static_pad_template (element_class, &sink_factory);
Matthew Watersb1d13e12015-07-30 16:42:38 +1000256
257 g_object_class_install_property (gobject_class, PROP_DEVICE_ID,
258 g_param_spec_uint ("cuda-device-id",
259 "Cuda Device ID",
260 "Set the GPU device to use for operations",
261 0, G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Matthew Watersc45fc2e2016-04-07 22:46:08 +1000262 g_object_class_install_property (gobject_class, PROP_PRESET,
263 g_param_spec_enum ("preset", "Encoding Preset",
264 "Encoding Preset",
Tim-Philipp Müllerbea0ea62018-01-24 10:21:48 +0000265 GST_TYPE_NV_PRESET, DEFAULT_PRESET,
266 G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING |
267 G_PARAM_STATIC_STRINGS));
Matthew Watersdc1a3262016-04-08 14:51:44 +1000268 g_object_class_install_property (gobject_class, PROP_RC_MODE,
Tim-Philipp Müllerbea0ea62018-01-24 10:21:48 +0000269 g_param_spec_enum ("rc-mode", "RC Mode", "Rate Control Mode",
270 GST_TYPE_NV_RC_MODE, DEFAULT_RC_MODE,
271 G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING |
272 G_PARAM_STATIC_STRINGS));
Matthew Watersdc1a3262016-04-08 14:51:44 +1000273 g_object_class_install_property (gobject_class, PROP_QP_MIN,
274 g_param_spec_int ("qp-min", "Minimum Quantizer",
275 "Minimum quantizer (-1 = from NVENC preset)", -1, 51, DEFAULT_QP_MIN,
Tim-Philipp Müllerbea0ea62018-01-24 10:21:48 +0000276 G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING |
277 G_PARAM_STATIC_STRINGS));
Matthew Watersdc1a3262016-04-08 14:51:44 +1000278 g_object_class_install_property (gobject_class, PROP_QP_MAX,
279 g_param_spec_int ("qp-max", "Maximum Quantizer",
280 "Maximum quantizer (-1 = from NVENC preset)", -1, 51, DEFAULT_QP_MAX,
Tim-Philipp Müllerbea0ea62018-01-24 10:21:48 +0000281 G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING |
282 G_PARAM_STATIC_STRINGS));
Matthew Watersdc1a3262016-04-08 14:51:44 +1000283 g_object_class_install_property (gobject_class, PROP_QP_CONST,
284 g_param_spec_int ("qp-const", "Constant Quantizer",
Tim-Philipp Müllerbea0ea62018-01-24 10:21:48 +0000285 "Constant quantizer (-1 = from NVENC preset)", -1, 51,
286 DEFAULT_QP_CONST,
287 G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING |
288 G_PARAM_STATIC_STRINGS));
Tim-Philipp Müller07c84172017-04-16 16:08:27 +0200289 g_object_class_install_property (gobject_class, PROP_GOP_SIZE,
290 g_param_spec_int ("gop-size", "GOP size",
291 "Number of frames between intra frames (-1 = infinite)",
292 -1, G_MAXINT, DEFAULT_GOP_SIZE,
293 (GParamFlags) (G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING |
294 G_PARAM_STATIC_STRINGS)));
Matthew Watersdc1a3262016-04-08 14:51:44 +1000295 g_object_class_install_property (gobject_class, PROP_BITRATE,
296 g_param_spec_uint ("bitrate", "Bitrate",
297 "Bitrate in kbit/sec (0 = from NVENC preset)", 0, 2000 * 1024,
Tim-Philipp Müllerbea0ea62018-01-24 10:21:48 +0000298 DEFAULT_BITRATE,
299 G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING |
300 G_PARAM_STATIC_STRINGS));
Matthew Watersb1d13e12015-07-30 16:42:38 +1000301}
302
303static gboolean
304_get_supported_input_formats (GstNvBaseEnc * nvenc)
305{
306 GstNvBaseEncClass *nvenc_class = GST_NV_BASE_ENC_GET_CLASS (nvenc);
307 guint64 format_mask = 0;
308 uint32_t i, num = 0;
309 NV_ENC_BUFFER_FORMAT formats[64];
310 GValue list = G_VALUE_INIT;
311 GValue val = G_VALUE_INIT;
312
313 NvEncGetInputFormats (nvenc->encoder, nvenc_class->codec_id, formats,
314 G_N_ELEMENTS (formats), &num);
315
316 for (i = 0; i < num; ++i) {
317 GST_INFO_OBJECT (nvenc, "input format: 0x%08x", formats[i]);
318 /* Apparently we can just ignore the tiled formats and can feed
319 * it the respective untiled planar format instead ?! */
320 switch (formats[i]) {
321 case NV_ENC_BUFFER_FORMAT_NV12_PL:
Matthew Watersd6f7ea82016-03-31 01:21:42 +1100322#if defined (NV_ENC_BUFFER_FORMAT_NV12_TILED16x16)
Matthew Watersb1d13e12015-07-30 16:42:38 +1000323 case NV_ENC_BUFFER_FORMAT_NV12_TILED16x16:
Matthew Watersd6f7ea82016-03-31 01:21:42 +1100324#endif
325#if defined (NV_ENC_BUFFER_FORMAT_NV12_TILED64x16)
Matthew Watersb1d13e12015-07-30 16:42:38 +1000326 case NV_ENC_BUFFER_FORMAT_NV12_TILED64x16:
Matthew Watersd6f7ea82016-03-31 01:21:42 +1100327#endif
Matthew Watersb1d13e12015-07-30 16:42:38 +1000328 format_mask |= (1 << GST_VIDEO_FORMAT_NV12);
329 break;
330 case NV_ENC_BUFFER_FORMAT_YV12_PL:
Matthew Watersd6f7ea82016-03-31 01:21:42 +1100331#if defined(NV_ENC_BUFFER_FORMAT_YV12_TILED16x16)
Matthew Watersb1d13e12015-07-30 16:42:38 +1000332 case NV_ENC_BUFFER_FORMAT_YV12_TILED16x16:
Matthew Watersd6f7ea82016-03-31 01:21:42 +1100333#endif
334#if defined (NV_ENC_BUFFER_FORMAT_YV12_TILED64x16)
Matthew Watersb1d13e12015-07-30 16:42:38 +1000335 case NV_ENC_BUFFER_FORMAT_YV12_TILED64x16:
Matthew Watersd6f7ea82016-03-31 01:21:42 +1100336#endif
Matthew Watersb1d13e12015-07-30 16:42:38 +1000337 format_mask |= (1 << GST_VIDEO_FORMAT_YV12);
338 break;
339 case NV_ENC_BUFFER_FORMAT_IYUV_PL:
Matthew Watersd6f7ea82016-03-31 01:21:42 +1100340#if defined (NV_ENC_BUFFER_FORMAT_IYUV_TILED16x16)
Matthew Watersb1d13e12015-07-30 16:42:38 +1000341 case NV_ENC_BUFFER_FORMAT_IYUV_TILED16x16:
Matthew Watersd6f7ea82016-03-31 01:21:42 +1100342#endif
343#if defined (NV_ENC_BUFFER_FORMAT_IYUV_TILED64x16)
Matthew Watersb1d13e12015-07-30 16:42:38 +1000344 case NV_ENC_BUFFER_FORMAT_IYUV_TILED64x16:
Matthew Watersd6f7ea82016-03-31 01:21:42 +1100345#endif
Matthew Watersb1d13e12015-07-30 16:42:38 +1000346 format_mask |= (1 << GST_VIDEO_FORMAT_I420);
347 break;
348 case NV_ENC_BUFFER_FORMAT_YUV444_PL:
Matthew Watersd6f7ea82016-03-31 01:21:42 +1100349#if defined (NV_ENC_BUFFER_FORMAT_YUV444_TILED16x16)
Matthew Watersb1d13e12015-07-30 16:42:38 +1000350 case NV_ENC_BUFFER_FORMAT_YUV444_TILED16x16:
Matthew Watersd6f7ea82016-03-31 01:21:42 +1100351#endif
352#if defined (NV_ENC_BUFFER_FORMAT_YUV444_TILED64x16)
353 case NV_ENC_BUFFER_FORMAT_YUV444_TILED64x16:
354#endif
355 {
Matthew Watersb1d13e12015-07-30 16:42:38 +1000356 NV_ENC_CAPS_PARAM caps_param = { 0, };
357 int yuv444_supported = 0;
358
359 caps_param.version = NV_ENC_CAPS_PARAM_VER;
360 caps_param.capsToQuery = NV_ENC_CAPS_SUPPORT_YUV444_ENCODE;
361
362 if (NvEncGetEncodeCaps (nvenc->encoder, nvenc_class->codec_id,
363 &caps_param, &yuv444_supported) != NV_ENC_SUCCESS)
364 yuv444_supported = 0;
365
366 if (yuv444_supported)
367 format_mask |= (1 << GST_VIDEO_FORMAT_Y444);
368 break;
369 }
370 default:
371 GST_FIXME ("unmapped input format: 0x%08x", formats[i]);
372 break;
373 }
374 }
375
376 if (format_mask == 0)
377 return FALSE;
378
379 /* process a second time so we can add formats in the order we want */
380 g_value_init (&list, GST_TYPE_LIST);
381 g_value_init (&val, G_TYPE_STRING);
382 if ((format_mask & (1 << GST_VIDEO_FORMAT_NV12))) {
383 g_value_set_static_string (&val, "NV12");
384 gst_value_list_append_value (&list, &val);
385 }
386 if ((format_mask & (1 << GST_VIDEO_FORMAT_YV12))) {
387 g_value_set_static_string (&val, "YV12");
388 gst_value_list_append_value (&list, &val);
389 }
390 if ((format_mask & (1 << GST_VIDEO_FORMAT_I420))) {
391 g_value_set_static_string (&val, "I420");
392 gst_value_list_append_value (&list, &val);
393 }
394 if ((format_mask & (1 << GST_VIDEO_FORMAT_Y444))) {
395 g_value_set_static_string (&val, "Y444");
396 gst_value_list_append_value (&list, &val);
397 }
398 g_value_unset (&val);
399
400 GST_OBJECT_LOCK (nvenc);
401 g_free (nvenc->input_formats);
402 nvenc->input_formats = g_memdup (&list, sizeof (GValue));
403 GST_OBJECT_UNLOCK (nvenc);
404
405 return TRUE;
406}
407
408static gboolean
409gst_nv_base_enc_open (GstVideoEncoder * enc)
410{
411 GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (enc);
412
413 nvenc->cuda_ctx = gst_nvenc_create_cuda_context (nvenc->cuda_device_id);
414 if (nvenc->cuda_ctx == NULL) {
415 GST_ELEMENT_ERROR (enc, LIBRARY, INIT, (NULL),
416 ("Failed to create CUDA context, perhaps CUDA is not supported."));
417 return FALSE;
418 }
419
420 {
421 NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS params = { 0, };
422 NVENCSTATUS nv_ret;
423
424 params.version = NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER;
425 params.apiVersion = NVENCAPI_VERSION;
426 params.device = nvenc->cuda_ctx;
427 params.deviceType = NV_ENC_DEVICE_TYPE_CUDA;
428 nv_ret = NvEncOpenEncodeSessionEx (&params, &nvenc->encoder);
429 if (nv_ret != NV_ENC_SUCCESS) {
430 GST_ERROR ("Failed to create NVENC encoder session, ret=%d", nv_ret);
431 if (gst_nvenc_destroy_cuda_context (nvenc->cuda_ctx))
432 nvenc->cuda_ctx = NULL;
433 return FALSE;
434 }
435 GST_INFO ("created NVENC encoder %p", nvenc->encoder);
436 }
437
438 /* query supported input formats */
439 if (!_get_supported_input_formats (nvenc)) {
440 GST_WARNING_OBJECT (nvenc, "No supported input formats");
441 gst_nv_base_enc_close (enc);
442 return FALSE;
443 }
444
445 return TRUE;
446}
447
448static void
449gst_nv_base_enc_set_context (GstElement * element, GstContext * context)
450{
451 GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (element);
452
453#if HAVE_NVENC_GST_GL
454 gst_gl_handle_set_context (element, context,
455 (GstGLDisplay **) & nvenc->display,
456 (GstGLContext **) & nvenc->other_context);
457 if (nvenc->display)
458 gst_gl_display_filter_gl_api (GST_GL_DISPLAY (nvenc->display),
459 SUPPORTED_GL_APIS);
460#endif
Matthew Waters63a7cbf2015-09-29 16:17:22 +1000461
462 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
Matthew Watersb1d13e12015-07-30 16:42:38 +1000463}
464
465static gboolean
466gst_nv_base_enc_sink_query (GstVideoEncoder * enc, GstQuery * query)
467{
468 GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (enc);
469
470 switch (GST_QUERY_TYPE (query)) {
471#if HAVE_NVENC_GST_GL
472 case GST_QUERY_CONTEXT:{
473 gboolean ret;
474
475 ret = gst_gl_handle_context_query ((GstElement *) nvenc, query,
Ole André Vadla Ravnås70ac63a2017-04-14 13:58:21 +0200476 nvenc->display, NULL, nvenc->other_context);
Matthew Watersb1d13e12015-07-30 16:42:38 +1000477 if (nvenc->display)
478 gst_gl_display_filter_gl_api (GST_GL_DISPLAY (nvenc->display),
479 SUPPORTED_GL_APIS);
480
481 if (ret)
482 return ret;
483 break;
484 }
485#endif
486 default:
487 break;
488 }
489
490 return GST_VIDEO_ENCODER_CLASS (parent_class)->sink_query (enc, query);
491}
492
493static gboolean
494gst_nv_base_enc_start (GstVideoEncoder * enc)
495{
496 GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (enc);
497
498 nvenc->bitstream_pool = g_async_queue_new ();
499 nvenc->bitstream_queue = g_async_queue_new ();
500 nvenc->in_bufs_pool = g_async_queue_new ();
501
502 nvenc->last_flow = GST_FLOW_OK;
503
504#if HAVE_NVENC_GST_GL
505 {
506 gst_gl_ensure_element_data (GST_ELEMENT (nvenc),
507 (GstGLDisplay **) & nvenc->display,
508 (GstGLContext **) & nvenc->other_context);
509 if (nvenc->display)
510 gst_gl_display_filter_gl_api (GST_GL_DISPLAY (nvenc->display),
511 SUPPORTED_GL_APIS);
512 }
513#endif
514
515 return TRUE;
516}
517
518static gboolean
519gst_nv_base_enc_stop (GstVideoEncoder * enc)
520{
521 GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (enc);
522
Ole André Vadla Ravnåscb283142017-04-17 19:25:49 +0200523 gst_nv_base_enc_stop_bitstream_thread (nvenc);
524
Matthew Watersb1d13e12015-07-30 16:42:38 +1000525 gst_nv_base_enc_free_buffers (nvenc);
526
527 if (nvenc->bitstream_pool) {
528 g_async_queue_unref (nvenc->bitstream_pool);
529 nvenc->bitstream_pool = NULL;
530 }
531 if (nvenc->bitstream_queue) {
532 g_async_queue_unref (nvenc->bitstream_queue);
533 nvenc->bitstream_queue = NULL;
534 }
535 if (nvenc->in_bufs_pool) {
536 g_async_queue_unref (nvenc->in_bufs_pool);
537 nvenc->in_bufs_pool = NULL;
538 }
539 if (nvenc->display) {
540 gst_object_unref (nvenc->display);
541 nvenc->display = NULL;
542 }
543 if (nvenc->other_context) {
544 gst_object_unref (nvenc->other_context);
545 nvenc->other_context = NULL;
546 }
547
548 return TRUE;
549}
550
551static GValue *
552_get_interlace_modes (GstNvBaseEnc * nvenc)
553{
554 GstNvBaseEncClass *nvenc_class = GST_NV_BASE_ENC_GET_CLASS (nvenc);
555 NV_ENC_CAPS_PARAM caps_param = { 0, };
556 GValue *list = g_new0 (GValue, 1);
557 GValue val = G_VALUE_INIT;
558
559 g_value_init (list, GST_TYPE_LIST);
560 g_value_init (&val, G_TYPE_STRING);
561
562 g_value_set_static_string (&val, "progressive");
563 gst_value_list_append_value (list, &val);
564
565 caps_param.version = NV_ENC_CAPS_PARAM_VER;
566 caps_param.capsToQuery = NV_ENC_CAPS_SUPPORT_FIELD_ENCODING;
567
568 if (NvEncGetEncodeCaps (nvenc->encoder, nvenc_class->codec_id,
569 &caps_param, &nvenc->interlace_modes) != NV_ENC_SUCCESS)
570 nvenc->interlace_modes = 0;
571
572 if (nvenc->interlace_modes >= 1) {
573 g_value_set_static_string (&val, "interleaved");
574 gst_value_list_append_value (list, &val);
575 g_value_set_static_string (&val, "mixed");
576 gst_value_list_append_value (list, &val);
577 }
578 /* TODO: figure out what nvenc frame based interlacing means in gst terms */
579
580 return list;
581}
582
583static GstCaps *
584gst_nv_base_enc_getcaps (GstVideoEncoder * enc, GstCaps * filter)
585{
586 GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (enc);
587 GstCaps *supported_incaps = NULL;
588 GstCaps *template_caps, *caps;
589
590 GST_OBJECT_LOCK (nvenc);
591
592 if (nvenc->input_formats != NULL) {
593 GValue *val;
594
595 template_caps = gst_pad_get_pad_template_caps (enc->sinkpad);
596 supported_incaps = gst_caps_copy (template_caps);
597 gst_caps_set_value (supported_incaps, "format", nvenc->input_formats);
598
599 val = _get_interlace_modes (nvenc);
600 gst_caps_set_value (supported_incaps, "interlace-mode", val);
601 g_free (val);
602
603 GST_LOG_OBJECT (enc, "codec input caps %" GST_PTR_FORMAT, supported_incaps);
604 GST_LOG_OBJECT (enc, " template caps %" GST_PTR_FORMAT, template_caps);
605 caps = gst_caps_intersect (template_caps, supported_incaps);
606 gst_caps_unref (template_caps);
607 gst_caps_unref (supported_incaps);
608 supported_incaps = caps;
609 GST_LOG_OBJECT (enc, " supported caps %" GST_PTR_FORMAT, supported_incaps);
610 }
611
612 GST_OBJECT_UNLOCK (nvenc);
613
614 caps = gst_video_encoder_proxy_getcaps (enc, supported_incaps, filter);
615
616 if (supported_incaps)
617 gst_caps_unref (supported_incaps);
618
619 GST_DEBUG_OBJECT (nvenc, " returning caps %" GST_PTR_FORMAT, caps);
620
621 return caps;
622}
623
624static gboolean
625gst_nv_base_enc_close (GstVideoEncoder * enc)
626{
627 GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (enc);
628
629 if (nvenc->encoder) {
630 if (NvEncDestroyEncoder (nvenc->encoder) != NV_ENC_SUCCESS)
631 return FALSE;
632 nvenc->encoder = NULL;
633 }
634
635 if (nvenc->cuda_ctx) {
636 if (!gst_nvenc_destroy_cuda_context (nvenc->cuda_ctx))
637 return FALSE;
638 nvenc->cuda_ctx = NULL;
639 }
640
641 GST_OBJECT_LOCK (nvenc);
642 g_free (nvenc->input_formats);
643 nvenc->input_formats = NULL;
644 GST_OBJECT_UNLOCK (nvenc);
645
646 if (nvenc->input_state) {
647 gst_video_codec_state_unref (nvenc->input_state);
648 nvenc->input_state = NULL;
649 }
650
651 if (nvenc->bitstream_pool != NULL) {
652 g_assert (g_async_queue_length (nvenc->bitstream_pool) == 0);
653 g_async_queue_unref (nvenc->bitstream_pool);
654 nvenc->bitstream_pool = NULL;
655 }
656
657 return TRUE;
658}
659
660static void
661gst_nv_base_enc_init (GstNvBaseEnc * nvenc)
662{
663 GstVideoEncoder *encoder = GST_VIDEO_ENCODER (nvenc);
664
Matthew Watersc45fc2e2016-04-07 22:46:08 +1000665 nvenc->preset_enum = DEFAULT_PRESET;
666 nvenc->selected_preset = _nv_preset_to_guid (nvenc->preset_enum);
Matthew Watersdc1a3262016-04-08 14:51:44 +1000667 nvenc->rate_control_mode = DEFAULT_RC_MODE;
668 nvenc->qp_min = DEFAULT_QP_MIN;
669 nvenc->qp_max = DEFAULT_QP_MAX;
670 nvenc->qp_const = DEFAULT_QP_CONST;
671 nvenc->bitrate = DEFAULT_BITRATE;
Tim-Philipp Müller07c84172017-04-16 16:08:27 +0200672 nvenc->gop_size = DEFAULT_GOP_SIZE;
Matthew Watersc45fc2e2016-04-07 22:46:08 +1000673
Matthew Watersb1d13e12015-07-30 16:42:38 +1000674 GST_VIDEO_ENCODER_STREAM_LOCK (encoder);
675 GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder);
676}
677
678static void
679gst_nv_base_enc_finalize (GObject * obj)
680{
681 G_OBJECT_CLASS (gst_nv_base_enc_parent_class)->finalize (obj);
682}
683
684static GstVideoCodecFrame *
685_find_frame_with_output_buffer (GstNvBaseEnc * nvenc, NV_ENC_OUTPUT_PTR out_buf)
686{
Matthew Watersb48049a2016-02-24 23:48:19 +1100687 GList *l, *walk = gst_video_encoder_get_frames (GST_VIDEO_ENCODER (nvenc));
688 GstVideoCodecFrame *ret = NULL;
Matthew Watersb1d13e12015-07-30 16:42:38 +1000689 gint i;
690
Matthew Watersb48049a2016-02-24 23:48:19 +1100691 for (l = walk; l; l = l->next) {
Matthew Watersb1d13e12015-07-30 16:42:38 +1000692 GstVideoCodecFrame *frame = (GstVideoCodecFrame *) l->data;
693 struct frame_state *state = frame->user_data;
694
Matthew Watersb48049a2016-02-24 23:48:19 +1100695 if (!state)
696 continue;
697
Matthew Watersb1d13e12015-07-30 16:42:38 +1000698 for (i = 0; i < N_BUFFERS_PER_FRAME; i++) {
Matthew Watersb48049a2016-02-24 23:48:19 +1100699
Matthew Watersb1d13e12015-07-30 16:42:38 +1000700 if (!state->out_bufs[i])
701 break;
702
703 if (state->out_bufs[i] == out_buf)
Matthew Watersb48049a2016-02-24 23:48:19 +1100704 ret = frame;
Matthew Watersb1d13e12015-07-30 16:42:38 +1000705 }
706 }
707
Matthew Watersb48049a2016-02-24 23:48:19 +1100708 if (ret)
709 gst_video_codec_frame_ref (ret);
710
711 g_list_free_full (walk, (GDestroyNotify) gst_video_codec_frame_unref);
712
713 return ret;
Matthew Watersb1d13e12015-07-30 16:42:38 +1000714}
715
716static gpointer
717gst_nv_base_enc_bitstream_thread (gpointer user_data)
718{
719 GstVideoEncoder *enc = user_data;
720 GstNvBaseEnc *nvenc = user_data;
721
722 /* overview of operation:
723 * 1. retreive the next buffer submitted to the bitstream pool
724 * 2. wait for that buffer to be ready from nvenc (LockBitsream)
725 * 3. retreive the GstVideoCodecFrame associated with that buffer
726 * 4. for each buffer in the frame
727 * 4.1 (step 2): wait for that buffer to be ready from nvenc (LockBitsream)
728 * 4.2 create an output GstBuffer from the nvenc buffers
729 * 4.3 unlock the nvenc bitstream buffers UnlockBitsream
730 * 5. finish_frame()
731 * 6. cleanup
732 */
733 do {
734 GstBuffer *buffers[N_BUFFERS_PER_FRAME];
735 struct frame_state *state = NULL;
736 GstVideoCodecFrame *frame = NULL;
737 NVENCSTATUS nv_ret;
738 GstFlowReturn flow = GST_FLOW_OK;
739 gint i;
740
741 {
742 NV_ENC_LOCK_BITSTREAM lock_bs = { 0, };
743 NV_ENC_OUTPUT_PTR out_buf;
744
745 for (i = 0; i < N_BUFFERS_PER_FRAME; i++) {
746 /* get and lock bitstream buffers */
747 GstVideoCodecFrame *tmp_frame;
748
749 if (state && i >= state->n_buffers)
750 break;
751
752 GST_LOG_OBJECT (enc, "wait for bitstream buffer..");
753
754 /* assumes buffers are submitted in order */
755 out_buf = g_async_queue_pop (nvenc->bitstream_queue);
756 if ((gpointer) out_buf == SHUTDOWN_COOKIE)
757 break;
758
759 GST_LOG_OBJECT (nvenc, "waiting for output buffer %p to be ready",
760 out_buf);
761
762 lock_bs.version = NV_ENC_LOCK_BITSTREAM_VER;
763 lock_bs.outputBitstream = out_buf;
764 lock_bs.doNotWait = 0;
765
766 /* FIXME: this would need to be updated for other slice modes */
767 lock_bs.sliceOffsets = NULL;
768
769 nv_ret = NvEncLockBitstream (nvenc->encoder, &lock_bs);
770 if (nv_ret != NV_ENC_SUCCESS) {
771 /* FIXME: what to do here? */
772 GST_ELEMENT_ERROR (nvenc, STREAM, ENCODE, (NULL),
773 ("Failed to lock bitstream buffer %p, ret %d",
774 lock_bs.outputBitstream, nv_ret));
775 out_buf = SHUTDOWN_COOKIE;
776 break;
777 }
778
779 GST_LOG_OBJECT (nvenc, "picture type %d", lock_bs.pictureType);
780
781 tmp_frame = _find_frame_with_output_buffer (nvenc, out_buf);
782 g_assert (tmp_frame != NULL);
783 if (frame)
784 g_assert (frame == tmp_frame);
785 frame = tmp_frame;
786
787 state = frame->user_data;
788 g_assert (state->out_bufs[i] == out_buf);
789
790 /* copy into output buffer */
791 buffers[i] =
792 gst_buffer_new_allocate (NULL, lock_bs.bitstreamSizeInBytes, NULL);
793 gst_buffer_fill (buffers[i], 0, lock_bs.bitstreamBufferPtr,
794 lock_bs.bitstreamSizeInBytes);
795
796 if (lock_bs.pictureType == NV_ENC_PIC_TYPE_IDR) {
797 GST_DEBUG_OBJECT (nvenc, "This is a keyframe");
798 GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
799 }
800
801 /* TODO: use lock_bs.outputTimeStamp and lock_bs.outputDuration */
802 /* TODO: check pts/dts is handled properly if there are B-frames */
803
804 nv_ret = NvEncUnlockBitstream (nvenc->encoder, state->out_bufs[i]);
805 if (nv_ret != NV_ENC_SUCCESS) {
806 /* FIXME: what to do here? */
807 GST_ELEMENT_ERROR (nvenc, STREAM, ENCODE, (NULL),
808 ("Failed to unlock bitstream buffer %p, ret %d",
809 lock_bs.outputBitstream, nv_ret));
810 state->out_bufs[i] = SHUTDOWN_COOKIE;
811 break;
812 }
813
814 GST_LOG_OBJECT (nvenc, "returning bitstream buffer %p to pool",
815 state->out_bufs[i]);
816 g_async_queue_push (nvenc->bitstream_pool, state->out_bufs[i]);
817 }
818
819 if (out_buf == SHUTDOWN_COOKIE)
820 break;
821 }
822
823 {
824 GstBuffer *output_buffer = gst_buffer_new ();
825
826 for (i = 0; i < state->n_buffers; i++)
827 output_buffer = gst_buffer_append (output_buffer, buffers[i]);
828
829 frame->output_buffer = output_buffer;
830 }
831
832 for (i = 0; i < state->n_buffers; i++) {
833 void *in_buf = state->in_bufs[i];
834 g_assert (in_buf != NULL);
835
836#if HAVE_NVENC_GST_GL
837 if (nvenc->gl_input) {
838 struct gl_input_resource *in_gl_resource = in_buf;
839
840 nv_ret =
841 NvEncUnmapInputResource (nvenc->encoder,
842 in_gl_resource->nv_mapped_resource.mappedResource);
843 if (nv_ret != NV_ENC_SUCCESS) {
844 GST_ERROR_OBJECT (nvenc, "Failed to unmap input resource %p, ret %d",
845 in_gl_resource, nv_ret);
846 break;
847 }
848
849 memset (&in_gl_resource->nv_mapped_resource, 0,
850 sizeof (in_gl_resource->nv_mapped_resource));
851 }
852#endif
853
854 g_async_queue_push (nvenc->in_bufs_pool, in_buf);
855 }
856
857 flow = gst_video_encoder_finish_frame (enc, frame);
858 frame = NULL;
859
860 if (flow != GST_FLOW_OK) {
861 GST_INFO_OBJECT (enc, "got flow %s", gst_flow_get_name (flow));
862 g_atomic_int_set (&nvenc->last_flow, flow);
863 break;
864 }
865 }
866 while (TRUE);
867
868 GST_INFO_OBJECT (nvenc, "exiting thread");
869
870 return NULL;
871}
872
873static gboolean
874gst_nv_base_enc_start_bitstream_thread (GstNvBaseEnc * nvenc)
875{
876 gchar *name = g_strdup_printf ("%s-read-bits", GST_OBJECT_NAME (nvenc));
877
878 g_assert (nvenc->bitstream_thread == NULL);
879
880 g_assert (g_async_queue_length (nvenc->bitstream_queue) == 0);
881
882 nvenc->bitstream_thread =
883 g_thread_try_new (name, gst_nv_base_enc_bitstream_thread, nvenc, NULL);
884
885 g_free (name);
886
887 if (nvenc->bitstream_thread == NULL)
888 return FALSE;
889
890 GST_INFO_OBJECT (nvenc, "started thread to read bitstream");
891 return TRUE;
892}
893
894static gboolean
895gst_nv_base_enc_stop_bitstream_thread (GstNvBaseEnc * nvenc)
896{
897 gpointer out_buf;
898
899 if (nvenc->bitstream_thread == NULL)
900 return TRUE;
901
902 /* FIXME */
903 GST_FIXME_OBJECT (nvenc, "stop bitstream reading thread properly");
904 g_async_queue_lock (nvenc->bitstream_queue);
905 g_async_queue_lock (nvenc->bitstream_pool);
906 while ((out_buf = g_async_queue_try_pop_unlocked (nvenc->bitstream_queue))) {
907 GST_INFO_OBJECT (nvenc, "stole bitstream buffer %p from queue", out_buf);
908 g_async_queue_push_unlocked (nvenc->bitstream_pool, out_buf);
909 }
910 g_async_queue_push_unlocked (nvenc->bitstream_queue, SHUTDOWN_COOKIE);
911 g_async_queue_unlock (nvenc->bitstream_pool);
912 g_async_queue_unlock (nvenc->bitstream_queue);
913
914 /* temporary unlock, so other thread can find and push frame */
915 GST_VIDEO_ENCODER_STREAM_UNLOCK (nvenc);
916 g_thread_join (nvenc->bitstream_thread);
917 GST_VIDEO_ENCODER_STREAM_LOCK (nvenc);
918
919 nvenc->bitstream_thread = NULL;
920 return TRUE;
921}
922
923static void
924gst_nv_base_enc_reset_queues (GstNvBaseEnc * nvenc, gboolean refill)
925{
926 gpointer ptr;
927 gint i;
928
929 GST_INFO_OBJECT (nvenc, "clearing queues");
930
931 while ((ptr = g_async_queue_try_pop (nvenc->bitstream_queue))) {
932 /* do nothing */
933 }
934 while ((ptr = g_async_queue_try_pop (nvenc->bitstream_pool))) {
935 /* do nothing */
936 }
937 while ((ptr = g_async_queue_try_pop (nvenc->in_bufs_pool))) {
938 /* do nothing */
939 }
940
941 if (refill) {
942 GST_INFO_OBJECT (nvenc, "refilling buffer pools");
943 for (i = 0; i < nvenc->n_bufs; ++i) {
944 g_async_queue_push (nvenc->bitstream_pool, nvenc->input_bufs[i]);
945 g_async_queue_push (nvenc->in_bufs_pool, nvenc->output_bufs[i]);
946 }
947 }
948}
949
950static void
951gst_nv_base_enc_free_buffers (GstNvBaseEnc * nvenc)
952{
953 NVENCSTATUS nv_ret;
954 guint i;
955
956 if (nvenc->encoder == NULL)
957 return;
958
959 gst_nv_base_enc_reset_queues (nvenc, FALSE);
960
961 for (i = 0; i < nvenc->n_bufs; ++i) {
962 NV_ENC_OUTPUT_PTR out_buf = nvenc->output_bufs[i];
963
964#if HAVE_NVENC_GST_GL
965 if (nvenc->gl_input) {
966 struct gl_input_resource *in_gl_resource = nvenc->input_bufs[i];
967
968 cuCtxPushCurrent (nvenc->cuda_ctx);
969 nv_ret =
970 NvEncUnregisterResource (nvenc->encoder,
971 in_gl_resource->nv_resource.registeredResource);
972 if (nv_ret != NV_ENC_SUCCESS)
973 GST_ERROR_OBJECT (nvenc, "Failed to unregister resource %p, ret %d",
974 in_gl_resource, nv_ret);
975
976 g_free (in_gl_resource);
977 cuCtxPopCurrent (NULL);
978 } else
979#endif
980 {
981 NV_ENC_INPUT_PTR in_buf = (NV_ENC_INPUT_PTR) nvenc->input_bufs[i];
982
983 GST_DEBUG_OBJECT (nvenc, "Destroying input buffer %p", in_buf);
984 nv_ret = NvEncDestroyInputBuffer (nvenc->encoder, in_buf);
985 if (nv_ret != NV_ENC_SUCCESS) {
986 GST_ERROR_OBJECT (nvenc, "Failed to destroy input buffer %p, ret %d",
987 in_buf, nv_ret);
988 }
989 }
990
991 GST_DEBUG_OBJECT (nvenc, "Destroying output bitstream buffer %p", out_buf);
992 nv_ret = NvEncDestroyBitstreamBuffer (nvenc->encoder, out_buf);
993 if (nv_ret != NV_ENC_SUCCESS) {
994 GST_ERROR_OBJECT (nvenc, "Failed to destroy output buffer %p, ret %d",
995 out_buf, nv_ret);
996 }
997 }
998
999 nvenc->n_bufs = 0;
1000 g_free (nvenc->output_bufs);
1001 nvenc->output_bufs = NULL;
1002 g_free (nvenc->input_bufs);
1003 nvenc->input_bufs = NULL;
1004}
1005
1006static inline guint
1007_get_plane_width (GstVideoInfo * info, guint plane)
1008{
1009 if (GST_VIDEO_INFO_IS_YUV (info))
1010 /* For now component width and plane width are the same and the
1011 * plane-component mapping matches
1012 */
1013 return GST_VIDEO_INFO_COMP_WIDTH (info, plane);
1014 else /* RGB, GRAY */
1015 return GST_VIDEO_INFO_WIDTH (info);
1016}
1017
1018static inline guint
1019_get_plane_height (GstVideoInfo * info, guint plane)
1020{
1021 if (GST_VIDEO_INFO_IS_YUV (info))
1022 /* For now component width and plane width are the same and the
1023 * plane-component mapping matches
1024 */
1025 return GST_VIDEO_INFO_COMP_HEIGHT (info, plane);
1026 else /* RGB, GRAY */
1027 return GST_VIDEO_INFO_HEIGHT (info);
1028}
1029
1030static inline gsize
1031_get_frame_data_height (GstVideoInfo * info)
1032{
1033 gsize ret = 0;
1034 gint i;
1035
1036 for (i = 0; i < GST_VIDEO_INFO_N_PLANES (info); i++) {
1037 ret += _get_plane_height (info, i);
1038 }
1039
1040 return ret;
1041}
1042
1043void
1044gst_nv_base_enc_set_max_encode_size (GstNvBaseEnc * nvenc, guint max_width,
1045 guint max_height)
1046{
1047 nvenc->max_encode_width = max_width;
1048 nvenc->max_encode_height = max_height;
1049}
1050
1051void
1052gst_nv_base_enc_get_max_encode_size (GstNvBaseEnc * nvenc, guint * max_width,
1053 guint * max_height)
1054{
1055 *max_width = nvenc->max_encode_width;
1056 *max_height = nvenc->max_encode_height;
1057}
1058
1059static gboolean
1060gst_nv_base_enc_set_format (GstVideoEncoder * enc, GstVideoCodecState * state)
1061{
1062 GstNvBaseEncClass *nvenc_class = GST_NV_BASE_ENC_GET_CLASS (enc);
1063 GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (enc);
1064 GstVideoInfo *info = &state->info;
1065 GstVideoCodecState *old_state = nvenc->input_state;
Matthew Waters065f4dc2016-04-07 23:24:47 +10001066 NV_ENC_RECONFIGURE_PARAMS reconfigure_params = { 0, };
1067 NV_ENC_INITIALIZE_PARAMS init_params = { 0, };
1068 NV_ENC_INITIALIZE_PARAMS *params;
1069 NV_ENC_PRESET_CONFIG preset_config = { 0, };
Matthew Watersb1d13e12015-07-30 16:42:38 +10001070 NVENCSTATUS nv_ret;
1071
Ole André Vadla Ravnås59365e32017-04-17 13:58:53 +02001072 g_atomic_int_set (&nvenc->reconfig, FALSE);
1073
Matthew Waters065f4dc2016-04-07 23:24:47 +10001074 if (old_state) {
1075 reconfigure_params.version = NV_ENC_RECONFIGURE_PARAMS_VER;
1076 params = &reconfigure_params.reInitEncodeParams;
1077 } else {
1078 params = &init_params;
1079 }
1080
1081 params->version = NV_ENC_INITIALIZE_PARAMS_VER;
1082 params->encodeGUID = nvenc_class->codec_id;
1083 params->encodeWidth = GST_VIDEO_INFO_WIDTH (info);
1084 params->encodeHeight = GST_VIDEO_INFO_HEIGHT (info);
1085
1086 {
1087 guint32 n_presets;
1088 GUID *presets;
1089 guint32 i;
1090
1091 nv_ret =
1092 NvEncGetEncodePresetCount (nvenc->encoder,
1093 params->encodeGUID, &n_presets);
1094 if (nv_ret != NV_ENC_SUCCESS) {
1095 GST_ELEMENT_ERROR (nvenc, LIBRARY, SETTINGS, (NULL),
1096 ("Failed to get encoder presets"));
1097 return FALSE;
1098 }
1099
1100 presets = g_new0 (GUID, n_presets);
1101 nv_ret =
1102 NvEncGetEncodePresetGUIDs (nvenc->encoder,
1103 params->encodeGUID, presets, n_presets, &n_presets);
1104 if (nv_ret != NV_ENC_SUCCESS) {
1105 GST_ELEMENT_ERROR (nvenc, LIBRARY, SETTINGS, (NULL),
1106 ("Failed to get encoder presets"));
1107 g_free (presets);
1108 return FALSE;
1109 }
1110
1111 for (i = 0; i < n_presets; i++) {
1112 if (gst_nvenc_cmp_guid (presets[i], nvenc->selected_preset))
1113 break;
1114 }
1115 g_free (presets);
1116 if (i >= n_presets) {
1117 GST_ELEMENT_ERROR (nvenc, LIBRARY, SETTINGS, (NULL),
1118 ("Selected preset not supported"));
1119 return FALSE;
1120 }
1121
1122 params->presetGUID = nvenc->selected_preset;
1123 }
1124
1125 params->enablePTD = 1;
1126 if (!old_state) {
1127 /* this sets the required buffer size and the maximum allowed size on
1128 * subsequent reconfigures */
1129 /* FIXME: propertise this */
1130 params->maxEncodeWidth = GST_VIDEO_INFO_WIDTH (info);
1131 params->maxEncodeHeight = GST_VIDEO_INFO_HEIGHT (info);
1132 gst_nv_base_enc_set_max_encode_size (nvenc, params->maxEncodeWidth,
1133 params->maxEncodeHeight);
1134 } else {
1135 guint max_width, max_height;
1136
1137 gst_nv_base_enc_get_max_encode_size (nvenc, &max_width, &max_height);
1138
1139 if (GST_VIDEO_INFO_WIDTH (info) > max_width
1140 || GST_VIDEO_INFO_HEIGHT (info) > max_height) {
1141 GST_ELEMENT_ERROR (nvenc, STREAM, FORMAT, ("%s", "Requested stream "
1142 "size is larger than the maximum configured size"), (NULL));
1143 return FALSE;
1144 }
1145 }
1146
1147 preset_config.version = NV_ENC_PRESET_CONFIG_VER;
1148 preset_config.presetCfg.version = NV_ENC_CONFIG_VER;
1149
1150 nv_ret =
1151 NvEncGetEncodePresetConfig (nvenc->encoder,
1152 params->encodeGUID, params->presetGUID, &preset_config);
1153 if (nv_ret != NV_ENC_SUCCESS) {
1154 GST_ELEMENT_ERROR (nvenc, LIBRARY, SETTINGS, (NULL),
1155 ("Failed to get encode preset configuration: %d", nv_ret));
1156 return FALSE;
1157 }
1158
Matthew Watersdc1a3262016-04-08 14:51:44 +10001159 params->encodeConfig = &preset_config.presetCfg;
1160
Matthew Waters065f4dc2016-04-07 23:24:47 +10001161 if (GST_VIDEO_INFO_IS_INTERLACED (info)) {
1162 if (GST_VIDEO_INFO_INTERLACE_MODE (info) ==
1163 GST_VIDEO_INTERLACE_MODE_INTERLEAVED
1164 || GST_VIDEO_INFO_INTERLACE_MODE (info) ==
1165 GST_VIDEO_INTERLACE_MODE_MIXED) {
1166 preset_config.presetCfg.frameFieldMode =
1167 NV_ENC_PARAMS_FRAME_FIELD_MODE_FIELD;
1168 }
1169 }
1170
1171 if (info->fps_d > 0 && info->fps_n > 0) {
1172 params->frameRateNum = info->fps_n;
1173 params->frameRateDen = info->fps_d;
1174 } else {
1175 GST_FIXME_OBJECT (nvenc, "variable framerate");
1176 }
1177
Matthew Watersdc1a3262016-04-08 14:51:44 +10001178 if (nvenc->rate_control_mode != GST_NV_RC_MODE_DEFAULT) {
1179 params->encodeConfig->rcParams.rateControlMode =
1180 _rc_mode_to_nv (nvenc->rate_control_mode);
1181 if (nvenc->bitrate > 0) {
1182 /* FIXME: this produces larger bitrates?! */
1183 params->encodeConfig->rcParams.averageBitRate = nvenc->bitrate * 1024;
1184 params->encodeConfig->rcParams.maxBitRate = nvenc->bitrate * 1024;
1185 }
1186 if (nvenc->qp_const > 0) {
1187 params->encodeConfig->rcParams.constQP.qpInterB = nvenc->qp_const;
1188 params->encodeConfig->rcParams.constQP.qpInterP = nvenc->qp_const;
1189 params->encodeConfig->rcParams.constQP.qpIntra = nvenc->qp_const;
1190 }
1191 if (nvenc->qp_min >= 0) {
1192 params->encodeConfig->rcParams.enableMinQP = 1;
1193 params->encodeConfig->rcParams.minQP.qpInterB = nvenc->qp_min;
1194 params->encodeConfig->rcParams.minQP.qpInterP = nvenc->qp_min;
1195 params->encodeConfig->rcParams.minQP.qpIntra = nvenc->qp_min;
1196 }
1197 if (nvenc->qp_max >= 0) {
1198 params->encodeConfig->rcParams.enableMaxQP = 1;
1199 params->encodeConfig->rcParams.maxQP.qpInterB = nvenc->qp_max;
1200 params->encodeConfig->rcParams.maxQP.qpInterP = nvenc->qp_max;
1201 params->encodeConfig->rcParams.maxQP.qpIntra = nvenc->qp_max;
1202 }
1203 }
Matthew Waters065f4dc2016-04-07 23:24:47 +10001204
Tim-Philipp Müller07c84172017-04-16 16:08:27 +02001205 if (nvenc->gop_size < 0) {
1206 params->encodeConfig->gopLength = NVENC_INFINITE_GOPLENGTH;
1207 params->encodeConfig->frameIntervalP = 1;
1208 } else if (nvenc->gop_size > 0) {
1209 params->encodeConfig->gopLength = nvenc->gop_size;
1210 }
1211
Matthew Waters065f4dc2016-04-07 23:24:47 +10001212 g_assert (nvenc_class->set_encoder_config);
1213 if (!nvenc_class->set_encoder_config (nvenc, state, params->encodeConfig)) {
1214 GST_ERROR_OBJECT (enc, "Subclass failed to set encoder configuration");
1215 return FALSE;
1216 }
Matthew Marsh0e34c022015-12-22 11:10:31 +02001217
1218 G_LOCK (initialization_lock);
Matthew Waters065f4dc2016-04-07 23:24:47 +10001219 if (old_state) {
1220 nv_ret = NvEncReconfigureEncoder (nvenc->encoder, &reconfigure_params);
1221 } else {
1222 nv_ret = NvEncInitializeEncoder (nvenc->encoder, params);
Matthew Watersb1d13e12015-07-30 16:42:38 +10001223 }
Matthew Marsh0e34c022015-12-22 11:10:31 +02001224 G_UNLOCK (initialization_lock);
Matthew Watersb1d13e12015-07-30 16:42:38 +10001225
Matthew Waters065f4dc2016-04-07 23:24:47 +10001226 if (nv_ret != NV_ENC_SUCCESS) {
1227 GST_ELEMENT_ERROR (nvenc, LIBRARY, SETTINGS, (NULL),
1228 ("Failed to %sinit encoder: %d", old_state ? "re" : "", nv_ret));
1229 return FALSE;
Matthew Watersb1d13e12015-07-30 16:42:38 +10001230 }
Matthew Waters065f4dc2016-04-07 23:24:47 +10001231 GST_INFO_OBJECT (nvenc, "configured encoder");
Matthew Watersb1d13e12015-07-30 16:42:38 +10001232
1233 if (!old_state) {
1234 nvenc->input_info = *info;
1235 nvenc->gl_input = FALSE;
1236 }
1237
1238 if (nvenc->input_state)
1239 gst_video_codec_state_unref (nvenc->input_state);
1240 nvenc->input_state = gst_video_codec_state_ref (state);
1241 GST_INFO_OBJECT (nvenc, "configured encoder");
1242
1243 /* now allocate some buffers only on first configuration */
1244 if (!old_state) {
1245#if HAVE_NVENC_GST_GL
1246 GstCapsFeatures *features;
1247#endif
1248 guint num_macroblocks, i;
1249 guint input_width, input_height;
1250
1251 input_width = GST_VIDEO_INFO_WIDTH (info);
1252 input_height = GST_VIDEO_INFO_HEIGHT (info);
1253
1254 num_macroblocks = (GST_ROUND_UP_16 (input_width) >> 4)
1255 * (GST_ROUND_UP_16 (input_height) >> 4);
1256 nvenc->n_bufs = (num_macroblocks >= 8160) ? 32 : 48;
1257
1258 /* input buffers */
1259 nvenc->input_bufs = g_new0 (gpointer, nvenc->n_bufs);
1260
1261#if HAVE_NVENC_GST_GL
1262 features = gst_caps_get_features (state->caps, 0);
1263 if (gst_caps_features_contains (features,
1264 GST_CAPS_FEATURE_MEMORY_GL_MEMORY)) {
1265 guint pixel_depth = 0;
1266 nvenc->gl_input = TRUE;
1267
1268 for (i = 0; i < GST_VIDEO_INFO_N_COMPONENTS (info); i++) {
1269 pixel_depth += GST_VIDEO_INFO_COMP_DEPTH (info, i);
1270 }
1271
1272 cuCtxPushCurrent (nvenc->cuda_ctx);
1273 for (i = 0; i < nvenc->n_bufs; ++i) {
1274 struct gl_input_resource *in_gl_resource =
1275 g_new0 (struct gl_input_resource, 1);
1276 CUresult cu_ret;
1277
1278 memset (&in_gl_resource->nv_resource, 0,
1279 sizeof (in_gl_resource->nv_resource));
1280 memset (&in_gl_resource->nv_mapped_resource, 0,
1281 sizeof (in_gl_resource->nv_mapped_resource));
1282
1283 /* scratch buffer for non-contigious planer into a contigious buffer */
1284 cu_ret =
1285 cuMemAllocPitch ((CUdeviceptr *) & in_gl_resource->cuda_pointer,
1286 &in_gl_resource->cuda_stride, input_width,
1287 _get_frame_data_height (info), 16);
1288 if (cu_ret != CUDA_SUCCESS) {
1289 const gchar *err;
1290
1291 cuGetErrorString (cu_ret, &err);
1292 GST_ERROR_OBJECT (nvenc, "failed to alocate cuda scratch buffer "
1293 "ret %d error :%s", cu_ret, err);
1294 g_assert_not_reached ();
1295 }
1296
1297 in_gl_resource->nv_resource.version = NV_ENC_REGISTER_RESOURCE_VER;
1298 in_gl_resource->nv_resource.resourceType =
1299 NV_ENC_INPUT_RESOURCE_TYPE_CUDADEVICEPTR;
1300 in_gl_resource->nv_resource.width = input_width;
1301 in_gl_resource->nv_resource.height = input_height;
1302 in_gl_resource->nv_resource.pitch = in_gl_resource->cuda_stride;
1303 in_gl_resource->nv_resource.bufferFormat =
1304 gst_nvenc_get_nv_buffer_format (GST_VIDEO_INFO_FORMAT (info));
1305 in_gl_resource->nv_resource.resourceToRegister =
1306 in_gl_resource->cuda_pointer;
1307
1308 nv_ret =
1309 NvEncRegisterResource (nvenc->encoder,
1310 &in_gl_resource->nv_resource);
1311 if (nv_ret != NV_ENC_SUCCESS)
1312 GST_ERROR_OBJECT (nvenc, "Failed to register resource %p, ret %d",
1313 in_gl_resource, nv_ret);
1314
1315 nvenc->input_bufs[i] = in_gl_resource;
1316 g_async_queue_push (nvenc->in_bufs_pool, nvenc->input_bufs[i]);
1317 }
1318
1319 cuCtxPopCurrent (NULL);
1320 } else
1321#endif
1322 {
1323 for (i = 0; i < nvenc->n_bufs; ++i) {
1324 NV_ENC_CREATE_INPUT_BUFFER cin_buf = { 0, };
1325
1326 cin_buf.version = NV_ENC_CREATE_INPUT_BUFFER_VER;
1327
1328 cin_buf.width = GST_ROUND_UP_32 (input_width);
1329 cin_buf.height = GST_ROUND_UP_32 (input_height);
1330
1331 cin_buf.memoryHeap = NV_ENC_MEMORY_HEAP_SYSMEM_CACHED;
1332 cin_buf.bufferFmt =
1333 gst_nvenc_get_nv_buffer_format (GST_VIDEO_INFO_FORMAT (info));
1334
1335 nv_ret = NvEncCreateInputBuffer (nvenc->encoder, &cin_buf);
1336
1337 if (nv_ret != NV_ENC_SUCCESS) {
1338 GST_WARNING_OBJECT (enc, "Failed to allocate input buffer: %d",
1339 nv_ret);
1340 /* FIXME: clean up */
1341 return FALSE;
1342 }
1343
1344 nvenc->input_bufs[i] = cin_buf.inputBuffer;
1345
1346 GST_INFO_OBJECT (nvenc, "allocated input buffer %2d: %p", i,
1347 nvenc->input_bufs[i]);
1348
1349 g_async_queue_push (nvenc->in_bufs_pool, nvenc->input_bufs[i]);
1350 }
1351 }
1352
1353 /* output buffers */
1354 nvenc->output_bufs = g_new0 (NV_ENC_OUTPUT_PTR, nvenc->n_bufs);
1355 for (i = 0; i < nvenc->n_bufs; ++i) {
1356 NV_ENC_CREATE_BITSTREAM_BUFFER cout_buf = { 0, };
1357
1358 cout_buf.version = NV_ENC_CREATE_BITSTREAM_BUFFER_VER;
1359
1360 /* 1 MB should be large enough to hold most output frames.
1361 * NVENC will automatically increase this if it's not enough. */
1362 cout_buf.size = 1024 * 1024;
1363 cout_buf.memoryHeap = NV_ENC_MEMORY_HEAP_SYSMEM_CACHED;
1364
Matthew Marsh0e34c022015-12-22 11:10:31 +02001365 G_LOCK (initialization_lock);
Matthew Watersb1d13e12015-07-30 16:42:38 +10001366 nv_ret = NvEncCreateBitstreamBuffer (nvenc->encoder, &cout_buf);
Matthew Marsh0e34c022015-12-22 11:10:31 +02001367 G_UNLOCK (initialization_lock);
1368
Matthew Watersb1d13e12015-07-30 16:42:38 +10001369 if (nv_ret != NV_ENC_SUCCESS) {
1370 GST_WARNING_OBJECT (enc, "Failed to allocate input buffer: %d", nv_ret);
1371 /* FIXME: clean up */
1372 return FALSE;
1373 }
1374
1375 nvenc->output_bufs[i] = cout_buf.bitstreamBuffer;
1376
1377 GST_INFO_OBJECT (nvenc, "allocated output buffer %2d: %p", i,
1378 nvenc->output_bufs[i]);
1379
1380 g_async_queue_push (nvenc->bitstream_pool, nvenc->output_bufs[i]);
1381 }
1382
1383#if 0
1384 /* Get SPS/PPS */
1385 {
1386 NV_ENC_SEQUENCE_PARAM_PAYLOAD seq_param = { 0 };
1387 uint32_t seq_size = 0;
1388
1389 seq_param.version = NV_ENC_SEQUENCE_PARAM_PAYLOAD_VER;
1390 seq_param.spsppsBuffer = g_alloca (1024);
1391 seq_param.inBufferSize = 1024;
1392 seq_param.outSPSPPSPayloadSize = &seq_size;
1393
1394 nv_ret = NvEncGetSequenceParams (nvenc->encoder, &seq_param);
1395 if (nv_ret != NV_ENC_SUCCESS) {
1396 GST_WARNING_OBJECT (enc, "Failed to retrieve SPS/PPS: %d", nv_ret);
1397 return FALSE;
1398 }
1399
1400 /* FIXME: use SPS/PPS */
1401 GST_MEMDUMP_OBJECT (enc, "SPS/PPS", seq_param.spsppsBuffer, seq_size);
1402 }
1403#endif
1404 }
1405
1406 g_assert (nvenc_class->set_src_caps);
1407 if (!nvenc_class->set_src_caps (nvenc, state)) {
1408 GST_ERROR_OBJECT (nvenc, "Subclass failed to set output caps");
1409 /* FIXME: clean up */
1410 return FALSE;
1411 }
1412
1413 return TRUE;
1414}
1415
1416static inline guint
1417_plane_get_n_components (GstVideoInfo * info, guint plane)
1418{
1419 switch (GST_VIDEO_INFO_FORMAT (info)) {
1420 case GST_VIDEO_FORMAT_RGBx:
1421 case GST_VIDEO_FORMAT_BGRx:
1422 case GST_VIDEO_FORMAT_xRGB:
1423 case GST_VIDEO_FORMAT_xBGR:
1424 case GST_VIDEO_FORMAT_RGBA:
1425 case GST_VIDEO_FORMAT_BGRA:
1426 case GST_VIDEO_FORMAT_ARGB:
1427 case GST_VIDEO_FORMAT_ABGR:
1428 case GST_VIDEO_FORMAT_AYUV:
1429 return 4;
1430 case GST_VIDEO_FORMAT_RGB:
1431 case GST_VIDEO_FORMAT_BGR:
1432 case GST_VIDEO_FORMAT_RGB16:
1433 case GST_VIDEO_FORMAT_BGR16:
1434 return 3;
1435 case GST_VIDEO_FORMAT_GRAY16_BE:
1436 case GST_VIDEO_FORMAT_GRAY16_LE:
1437 case GST_VIDEO_FORMAT_YUY2:
1438 case GST_VIDEO_FORMAT_UYVY:
1439 return 2;
1440 case GST_VIDEO_FORMAT_NV12:
1441 case GST_VIDEO_FORMAT_NV21:
1442 return plane == 0 ? 1 : 2;
1443 case GST_VIDEO_FORMAT_GRAY8:
1444 case GST_VIDEO_FORMAT_Y444:
1445 case GST_VIDEO_FORMAT_Y42B:
1446 case GST_VIDEO_FORMAT_Y41B:
1447 case GST_VIDEO_FORMAT_I420:
1448 case GST_VIDEO_FORMAT_YV12:
1449 return 1;
1450 default:
1451 g_assert_not_reached ();
1452 return 1;
1453 }
1454}
1455
1456#if HAVE_NVENC_GST_GL
1457struct map_gl_input
1458{
1459 GstNvBaseEnc *nvenc;
1460 GstVideoCodecFrame *frame;
1461 GstVideoInfo *info;
1462 struct gl_input_resource *in_gl_resource;
1463};
1464
1465static void
1466_map_gl_input_buffer (GstGLContext * context, struct map_gl_input *data)
1467{
1468 cudaError_t cuda_ret;
1469 guint8 *data_pointer;
1470 guint i;
1471
1472 cuCtxPushCurrent (data->nvenc->cuda_ctx);
1473 data_pointer = data->in_gl_resource->cuda_pointer;
1474 for (i = 0; i < GST_VIDEO_INFO_N_PLANES (data->info); i++) {
1475 guint plane_n_components;
Matthew Watersffba31b2016-01-12 23:34:31 +11001476 GstGLBuffer *gl_buf_obj;
1477 GstGLMemoryPBO *gl_mem;
Matthew Watersb1d13e12015-07-30 16:42:38 +10001478 guint src_stride, dest_stride;
1479
1480 gl_mem =
Matthew Watersffba31b2016-01-12 23:34:31 +11001481 (GstGLMemoryPBO *) gst_buffer_peek_memory (data->frame->input_buffer,
1482 i);
1483 g_return_if_fail (gst_is_gl_memory_pbo ((GstMemory *) gl_mem));
1484 data->in_gl_resource->gl_mem[i] = GST_GL_MEMORY_CAST (gl_mem);
Matthew Watersb1d13e12015-07-30 16:42:38 +10001485 plane_n_components = _plane_get_n_components (data->info, i);
1486
Matthew Watersffba31b2016-01-12 23:34:31 +11001487 gl_buf_obj = (GstGLBuffer *) gl_mem->pbo;
1488 g_return_if_fail (gl_buf_obj != NULL);
Matthew Watersb1d13e12015-07-30 16:42:38 +10001489
1490 /* get the texture into the PBO */
Matthew Watersffba31b2016-01-12 23:34:31 +11001491 gst_gl_memory_pbo_upload_transfer (gl_mem);
1492 gst_gl_memory_pbo_download_transfer (gl_mem);
Matthew Watersb1d13e12015-07-30 16:42:38 +10001493
1494 GST_LOG_OBJECT (data->nvenc, "attempting to copy texture %u into cuda",
Matthew Watersffba31b2016-01-12 23:34:31 +11001495 gl_mem->mem.tex_id);
Matthew Watersb1d13e12015-07-30 16:42:38 +10001496
1497 cuda_ret =
1498 cudaGraphicsGLRegisterBuffer (&data->in_gl_resource->cuda_texture,
1499 gl_buf_obj->id, cudaGraphicsRegisterFlagsReadOnly);
1500 if (cuda_ret != cudaSuccess) {
1501 GST_ERROR_OBJECT (data->nvenc, "failed to register GL texture %u to cuda "
Matthew Watersffba31b2016-01-12 23:34:31 +11001502 "ret :%d", gl_mem->mem.tex_id, cuda_ret);
Matthew Watersb1d13e12015-07-30 16:42:38 +10001503 g_assert_not_reached ();
1504 }
1505
1506 cuda_ret =
1507 cudaGraphicsMapResources (1, &data->in_gl_resource->cuda_texture, 0);
1508 if (cuda_ret != cudaSuccess) {
1509 GST_ERROR_OBJECT (data->nvenc, "failed to map GL texture %u into cuda "
Matthew Watersffba31b2016-01-12 23:34:31 +11001510 "ret :%d", gl_mem->mem.tex_id, cuda_ret);
Matthew Watersb1d13e12015-07-30 16:42:38 +10001511 g_assert_not_reached ();
1512 }
1513
1514 cuda_ret =
Matthew Waters065f4dc2016-04-07 23:24:47 +10001515 cudaGraphicsResourceGetMappedPointer (&data->in_gl_resource->
1516 cuda_plane_pointers[i], &data->in_gl_resource->cuda_num_bytes,
Matthew Watersb1d13e12015-07-30 16:42:38 +10001517 data->in_gl_resource->cuda_texture);
1518 if (cuda_ret != cudaSuccess) {
1519 GST_ERROR_OBJECT (data->nvenc, "failed to get mapped pointer of map GL "
Matthew Watersffba31b2016-01-12 23:34:31 +11001520 "texture %u in cuda ret :%d", gl_mem->mem.tex_id, cuda_ret);
Matthew Watersb1d13e12015-07-30 16:42:38 +10001521 g_assert_not_reached ();
1522 }
1523
1524 src_stride = GST_VIDEO_INFO_PLANE_STRIDE (data->info, i);
1525 dest_stride = data->in_gl_resource->cuda_stride;
1526
1527 /* copy into scratch buffer */
1528 cuda_ret =
1529 cudaMemcpy2D (data_pointer, dest_stride,
1530 data->in_gl_resource->cuda_plane_pointers[i], src_stride,
1531 _get_plane_width (data->info, i) * plane_n_components,
1532 _get_plane_height (data->info, i), cudaMemcpyDeviceToDevice);
1533 if (cuda_ret != cudaSuccess) {
1534 GST_ERROR_OBJECT (data->nvenc, "failed to copy GL texture %u into cuda "
Matthew Watersffba31b2016-01-12 23:34:31 +11001535 "ret :%d", gl_mem->mem.tex_id, cuda_ret);
Matthew Watersb1d13e12015-07-30 16:42:38 +10001536 g_assert_not_reached ();
1537 }
1538
1539 cuda_ret =
1540 cudaGraphicsUnmapResources (1, &data->in_gl_resource->cuda_texture, 0);
1541 if (cuda_ret != cudaSuccess) {
1542 GST_ERROR_OBJECT (data->nvenc, "failed to unmap GL texture %u from cuda "
Matthew Watersffba31b2016-01-12 23:34:31 +11001543 "ret :%d", gl_mem->mem.tex_id, cuda_ret);
Matthew Watersb1d13e12015-07-30 16:42:38 +10001544 g_assert_not_reached ();
1545 }
1546
1547 cuda_ret =
1548 cudaGraphicsUnregisterResource (data->in_gl_resource->cuda_texture);
1549 if (cuda_ret != cudaSuccess) {
1550 GST_ERROR_OBJECT (data->nvenc, "failed to unregister GL texture %u from "
Matthew Watersffba31b2016-01-12 23:34:31 +11001551 "cuda ret :%d", gl_mem->mem.tex_id, cuda_ret);
Matthew Watersb1d13e12015-07-30 16:42:38 +10001552 g_assert_not_reached ();
1553 }
1554
1555 data_pointer =
1556 data_pointer +
1557 data->in_gl_resource->cuda_stride *
1558 _get_plane_height (&data->nvenc->input_info, i);
1559 }
1560 cuCtxPopCurrent (NULL);
1561}
1562#endif
1563
1564static GstFlowReturn
1565_acquire_input_buffer (GstNvBaseEnc * nvenc, gpointer * input)
1566{
1567 g_assert (input);
1568
1569 GST_LOG_OBJECT (nvenc, "acquiring input buffer..");
1570 GST_VIDEO_ENCODER_STREAM_UNLOCK (nvenc);
1571 *input = g_async_queue_pop (nvenc->in_bufs_pool);
1572 GST_VIDEO_ENCODER_STREAM_LOCK (nvenc);
1573
1574 return GST_FLOW_OK;
1575}
1576
1577static GstFlowReturn
1578_submit_input_buffer (GstNvBaseEnc * nvenc, GstVideoCodecFrame * frame,
1579 GstVideoFrame * vframe, void *inputBuffer, void *inputBufferPtr,
1580 NV_ENC_BUFFER_FORMAT bufferFormat, void *outputBufferPtr)
1581{
1582 GstNvBaseEncClass *nvenc_class = GST_NV_BASE_ENC_GET_CLASS (nvenc);
1583 NV_ENC_PIC_PARAMS pic_params = { 0, };
1584 NVENCSTATUS nv_ret;
1585
1586 GST_LOG_OBJECT (nvenc, "%u: input buffer %p, output buffer %p, "
1587 "pts %" GST_TIME_FORMAT, frame->system_frame_number, inputBuffer,
1588 outputBufferPtr, GST_TIME_ARGS (frame->pts));
1589
1590 pic_params.version = NV_ENC_PIC_PARAMS_VER;
1591 pic_params.inputBuffer = inputBufferPtr;
1592 pic_params.bufferFmt = bufferFormat;
1593
1594 pic_params.inputWidth = GST_VIDEO_FRAME_WIDTH (vframe);
1595 pic_params.inputHeight = GST_VIDEO_FRAME_HEIGHT (vframe);
1596 pic_params.outputBitstream = outputBufferPtr;
1597 pic_params.completionEvent = NULL;
1598 if (GST_VIDEO_FRAME_IS_INTERLACED (vframe)) {
1599 if (GST_VIDEO_FRAME_IS_TFF (vframe))
1600 pic_params.pictureStruct = NV_ENC_PIC_STRUCT_FIELD_TOP_BOTTOM;
1601 else
1602 pic_params.pictureStruct = NV_ENC_PIC_STRUCT_FIELD_BOTTOM_TOP;
1603 } else {
1604 pic_params.pictureStruct = NV_ENC_PIC_STRUCT_FRAME;
1605 }
1606 pic_params.inputTimeStamp = frame->pts;
1607 pic_params.inputDuration =
1608 GST_CLOCK_TIME_IS_VALID (frame->duration) ? frame->duration : 0;
1609 pic_params.frameIdx = frame->system_frame_number;
1610
1611 if (GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame))
1612 pic_params.encodePicFlags = NV_ENC_PIC_FLAG_FORCEIDR;
1613 else
1614 pic_params.encodePicFlags = 0;
1615
1616 if (nvenc_class->set_pic_params
1617 && !nvenc_class->set_pic_params (nvenc, frame, &pic_params)) {
1618 GST_ERROR_OBJECT (nvenc, "Subclass failed to submit buffer");
1619 return GST_FLOW_ERROR;
1620 }
1621
1622 nv_ret = NvEncEncodePicture (nvenc->encoder, &pic_params);
1623 if (nv_ret == NV_ENC_SUCCESS) {
1624 GST_LOG_OBJECT (nvenc, "Encoded picture");
1625 } else if (nv_ret == NV_ENC_ERR_NEED_MORE_INPUT) {
1626 /* FIXME: we should probably queue pending output buffers here and only
1627 * submit them to the async queue once we got sucess back */
1628 GST_DEBUG_OBJECT (nvenc, "Encoded picture (encoder needs more input)");
1629 } else {
1630 GST_ERROR_OBJECT (nvenc, "Failed to encode picture: %d", nv_ret);
1631 GST_DEBUG_OBJECT (nvenc, "re-enqueueing input buffer %p", inputBuffer);
1632 g_async_queue_push (nvenc->in_bufs_pool, inputBuffer);
1633 GST_DEBUG_OBJECT (nvenc, "re-enqueueing output buffer %p", outputBufferPtr);
1634 g_async_queue_push (nvenc->bitstream_pool, outputBufferPtr);
1635
1636 return GST_FLOW_ERROR;
1637 }
1638
1639 g_async_queue_push (nvenc->bitstream_queue, outputBufferPtr);
1640
1641 return GST_FLOW_OK;
1642}
1643
1644static GstFlowReturn
1645gst_nv_base_enc_handle_frame (GstVideoEncoder * enc, GstVideoCodecFrame * frame)
1646{
1647 gpointer input_buffer = NULL;
1648 GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (enc);
1649 NV_ENC_OUTPUT_PTR out_buf;
1650 NVENCSTATUS nv_ret;
1651 GstVideoFrame vframe;
1652 GstVideoInfo *info = &nvenc->input_state->info;
1653 GstFlowReturn flow = GST_FLOW_OK;
1654 GstMapFlags in_map_flags = GST_MAP_READ;
Ponnam Srinivas53ea2f82017-10-07 14:57:44 +05301655 struct frame_state *state = NULL;
Matthew Watersb1d13e12015-07-30 16:42:38 +10001656 guint frame_n = 0;
1657
1658 g_assert (nvenc->encoder != NULL);
1659
Ole André Vadla Ravnås59365e32017-04-17 13:58:53 +02001660 if (g_atomic_int_compare_and_exchange (&nvenc->reconfig, TRUE, FALSE)) {
1661 if (!gst_nv_base_enc_set_format (enc, nvenc->input_state))
1662 return GST_FLOW_ERROR;
1663 }
Matthew Watersb1d13e12015-07-30 16:42:38 +10001664#if HAVE_NVENC_GST_GL
1665 if (nvenc->gl_input)
1666 in_map_flags |= GST_MAP_GL;
1667#endif
1668
1669 if (!gst_video_frame_map (&vframe, info, frame->input_buffer, in_map_flags))
1670 return GST_FLOW_ERROR;
1671
1672 /* make sure our thread that waits for output to be ready is started */
1673 if (nvenc->bitstream_thread == NULL) {
1674 if (!gst_nv_base_enc_start_bitstream_thread (nvenc))
1675 goto error;
1676 }
1677
1678 flow = _acquire_input_buffer (nvenc, &input_buffer);
1679 if (flow != GST_FLOW_OK)
Ponnam Srinivas53ea2f82017-10-07 14:57:44 +05301680 goto out;
Matthew Watersb1d13e12015-07-30 16:42:38 +10001681 if (input_buffer == NULL)
Ponnam Srinivas53ea2f82017-10-07 14:57:44 +05301682 goto error;
Matthew Watersb1d13e12015-07-30 16:42:38 +10001683
1684 state = frame->user_data;
1685 if (!state)
1686 state = g_new0 (struct frame_state, 1);
1687 state->n_buffers = 1;
1688
1689#if HAVE_NVENC_GST_GL
1690 if (nvenc->gl_input) {
1691 struct gl_input_resource *in_gl_resource = input_buffer;
1692 struct map_gl_input data;
1693
1694 GST_LOG_OBJECT (enc, "got input buffer %p", in_gl_resource);
1695
1696 in_gl_resource->gl_mem[0] =
1697 (GstGLMemory *) gst_buffer_peek_memory (frame->input_buffer, 0);
1698 g_assert (gst_is_gl_memory ((GstMemory *) in_gl_resource->gl_mem[0]));
1699
1700 data.nvenc = nvenc;
1701 data.frame = frame;
1702 data.info = &vframe.info;
1703 data.in_gl_resource = in_gl_resource;
1704
1705 gst_gl_context_thread_add (in_gl_resource->gl_mem[0]->mem.context,
1706 (GstGLContextThreadFunc) _map_gl_input_buffer, &data);
1707
1708 in_gl_resource->nv_mapped_resource.version = NV_ENC_MAP_INPUT_RESOURCE_VER;
1709 in_gl_resource->nv_mapped_resource.registeredResource =
1710 in_gl_resource->nv_resource.registeredResource;
1711
1712 nv_ret =
1713 NvEncMapInputResource (nvenc->encoder,
1714 &in_gl_resource->nv_mapped_resource);
1715 if (nv_ret != NV_ENC_SUCCESS) {
1716 GST_ERROR_OBJECT (nvenc, "Failed to map input resource %p, ret %d",
1717 in_gl_resource, nv_ret);
1718 goto error;
1719 }
1720
1721 out_buf = g_async_queue_try_pop (nvenc->bitstream_pool);
1722 if (out_buf == NULL) {
1723 GST_DEBUG_OBJECT (nvenc, "wait for output buf to become available again");
1724 out_buf = g_async_queue_pop (nvenc->bitstream_pool);
1725 }
1726
1727 state->in_bufs[frame_n] = in_gl_resource;
1728 state->out_bufs[frame_n++] = out_buf;
1729
1730 frame->user_data = state;
1731 frame->user_data_destroy_notify = (GDestroyNotify) g_free;
1732
1733 flow =
1734 _submit_input_buffer (nvenc, frame, &vframe, in_gl_resource,
1735 in_gl_resource->nv_mapped_resource.mappedResource,
1736 in_gl_resource->nv_mapped_resource.mappedBufferFmt, out_buf);
1737
1738 /* encoder will keep frame in list internally, we'll look it up again later
1739 * in the thread where we get the output buffers and finish it there */
1740 gst_video_codec_frame_unref (frame);
1741 frame = NULL;
1742 }
1743#endif
1744
1745 if (!nvenc->gl_input) {
1746 NV_ENC_LOCK_INPUT_BUFFER in_buf_lock = { 0, };
1747 NV_ENC_INPUT_PTR in_buf = input_buffer;
1748 guint8 *src, *dest;
1749 guint src_stride, dest_stride;
1750 guint height, width;
1751 guint y;
1752
1753 GST_LOG_OBJECT (enc, "got input buffer %p", in_buf);
1754
1755 in_buf_lock.version = NV_ENC_LOCK_INPUT_BUFFER_VER;
1756 in_buf_lock.inputBuffer = in_buf;
1757
1758 nv_ret = NvEncLockInputBuffer (nvenc->encoder, &in_buf_lock);
1759 if (nv_ret != NV_ENC_SUCCESS) {
1760 GST_ERROR_OBJECT (nvenc, "Failed to lock input buffer: %d", nv_ret);
1761 /* FIXME: post proper error message */
1762 goto error;
1763 }
1764 GST_LOG_OBJECT (nvenc, "Locked input buffer %p", in_buf);
1765
1766 width = GST_VIDEO_FRAME_WIDTH (&vframe);
1767 height = GST_VIDEO_FRAME_HEIGHT (&vframe);
1768
Matthew Watersb1d13e12015-07-30 16:42:38 +10001769 /* copy Y plane */
1770 src = GST_VIDEO_FRAME_PLANE_DATA (&vframe, 0);
1771 src_stride = GST_VIDEO_FRAME_PLANE_STRIDE (&vframe, 0);
1772 dest = in_buf_lock.bufferDataPtr;
1773 dest_stride = in_buf_lock.pitch;
1774 for (y = 0; y < height; ++y) {
1775 memcpy (dest, src, width);
1776 dest += dest_stride;
1777 src += src_stride;
1778 }
1779
Ole André Vadla Ravnåsbc92b102017-04-14 15:30:44 +02001780 if (GST_VIDEO_FRAME_FORMAT (&vframe) == GST_VIDEO_FORMAT_NV12) {
1781 /* copy UV plane */
1782 src = GST_VIDEO_FRAME_PLANE_DATA (&vframe, 1);
1783 src_stride = GST_VIDEO_FRAME_PLANE_STRIDE (&vframe, 1);
1784 dest =
1785 (guint8 *) in_buf_lock.bufferDataPtr +
1786 GST_ROUND_UP_32 (height) * in_buf_lock.pitch;
1787 dest_stride = in_buf_lock.pitch;
1788 for (y = 0; y < GST_ROUND_UP_2 (height) / 2; ++y) {
1789 memcpy (dest, src, width);
1790 dest += dest_stride;
1791 src += src_stride;
1792 }
1793 } else if (GST_VIDEO_FRAME_FORMAT (&vframe) == GST_VIDEO_FORMAT_I420) {
1794 guint8 *dest_u, *dest_v;
1795
1796 dest_u = (guint8 *) in_buf_lock.bufferDataPtr +
1797 GST_ROUND_UP_32 (height) * in_buf_lock.pitch;
1798 dest_v = dest_u + ((GST_ROUND_UP_32 (height) / 2) *
1799 (in_buf_lock.pitch / 2));
1800 dest_stride = in_buf_lock.pitch / 2;
1801
1802 /* copy U plane */
1803 src = GST_VIDEO_FRAME_PLANE_DATA (&vframe, 1);
1804 src_stride = GST_VIDEO_FRAME_PLANE_STRIDE (&vframe, 1);
1805 dest = dest_u;
1806 for (y = 0; y < GST_ROUND_UP_2 (height) / 2; ++y) {
1807 memcpy (dest, src, width / 2);
1808 dest += dest_stride;
1809 src += src_stride;
1810 }
1811
1812 /* copy V plane */
1813 src = GST_VIDEO_FRAME_PLANE_DATA (&vframe, 2);
1814 src_stride = GST_VIDEO_FRAME_PLANE_STRIDE (&vframe, 2);
1815 dest = dest_v;
1816 for (y = 0; y < GST_ROUND_UP_2 (height) / 2; ++y) {
1817 memcpy (dest, src, width / 2);
1818 dest += dest_stride;
1819 src += src_stride;
1820 }
1821 } else {
1822 // FIXME: this only works for NV12 and I420
1823 g_assert_not_reached ();
Matthew Watersb1d13e12015-07-30 16:42:38 +10001824 }
1825
1826 nv_ret = NvEncUnlockInputBuffer (nvenc->encoder, in_buf);
1827 if (nv_ret != NV_ENC_SUCCESS) {
1828 GST_ERROR_OBJECT (nvenc, "Failed to unlock input buffer: %d", nv_ret);
1829 goto error;
1830 }
1831
1832 out_buf = g_async_queue_try_pop (nvenc->bitstream_pool);
1833 if (out_buf == NULL) {
1834 GST_DEBUG_OBJECT (nvenc, "wait for output buf to become available again");
1835 out_buf = g_async_queue_pop (nvenc->bitstream_pool);
1836 }
1837
1838 state->in_bufs[frame_n] = in_buf;
1839 state->out_bufs[frame_n++] = out_buf;
1840 frame->user_data = state;
1841 frame->user_data_destroy_notify = (GDestroyNotify) g_free;
1842
1843 flow =
1844 _submit_input_buffer (nvenc, frame, &vframe, in_buf, in_buf,
1845 gst_nvenc_get_nv_buffer_format (GST_VIDEO_INFO_FORMAT (info)), out_buf);
1846
1847 /* encoder will keep frame in list internally, we'll look it up again later
1848 * in the thread where we get the output buffers and finish it there */
1849 gst_video_codec_frame_unref (frame);
1850 frame = NULL;
1851 }
1852
1853 if (flow != GST_FLOW_OK)
1854 goto out;
1855
1856 flow = g_atomic_int_get (&nvenc->last_flow);
1857
1858out:
1859
1860 gst_video_frame_unmap (&vframe);
1861
1862 return flow;
1863
1864error:
1865 flow = GST_FLOW_ERROR;
Ponnam Srinivas53ea2f82017-10-07 14:57:44 +05301866 if (state)
1867 g_free (state);
1868 if (input_buffer)
1869 g_free (input_buffer);
Matthew Watersb1d13e12015-07-30 16:42:38 +10001870 goto out;
1871}
1872
1873static gboolean
1874gst_nv_base_enc_drain_encoder (GstNvBaseEnc * nvenc)
1875{
1876 NV_ENC_PIC_PARAMS pic_params = { 0, };
1877 NVENCSTATUS nv_ret;
1878
1879 GST_INFO_OBJECT (nvenc, "draining encoder");
1880
1881 if (nvenc->input_state == NULL) {
1882 GST_DEBUG_OBJECT (nvenc, "no input state, nothing to do");
1883 return TRUE;
1884 }
1885
1886 pic_params.version = NV_ENC_PIC_PARAMS_VER;
1887 pic_params.encodePicFlags = NV_ENC_PIC_FLAG_EOS;
1888
1889 nv_ret = NvEncEncodePicture (nvenc->encoder, &pic_params);
1890 if (nv_ret != NV_ENC_SUCCESS) {
1891 GST_LOG_OBJECT (nvenc, "Failed to drain encoder, ret %d", nv_ret);
1892 return FALSE;
1893 }
1894
1895 return TRUE;
1896}
1897
1898static GstFlowReturn
1899gst_nv_base_enc_finish (GstVideoEncoder * enc)
1900{
1901 GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (enc);
1902
1903 GST_FIXME_OBJECT (enc, "implement finish");
1904
1905 gst_nv_base_enc_drain_encoder (nvenc);
1906
1907 /* wait for encoder to output the remaining buffers */
1908 gst_nv_base_enc_stop_bitstream_thread (nvenc);
1909
1910 return GST_FLOW_OK;
1911}
1912
1913#if 0
1914static gboolean
1915gst_nv_base_enc_flush (GstVideoEncoder * enc)
1916{
1917 GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (enc);
1918 GST_INFO_OBJECT (nvenc, "done flushing encoder");
1919 return TRUE;
1920}
1921#endif
1922
1923static void
Ole André Vadla Ravnås59365e32017-04-17 13:58:53 +02001924gst_nv_base_enc_schedule_reconfig (GstNvBaseEnc * nvenc)
1925{
1926 g_atomic_int_set (&nvenc->reconfig, TRUE);
1927}
1928
1929static void
Matthew Watersb1d13e12015-07-30 16:42:38 +10001930gst_nv_base_enc_set_property (GObject * object, guint prop_id,
1931 const GValue * value, GParamSpec * pspec)
1932{
1933 GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (object);
1934
1935 switch (prop_id) {
1936 case PROP_DEVICE_ID:
1937 nvenc->cuda_device_id = g_value_get_uint (value);
1938 break;
Matthew Watersc45fc2e2016-04-07 22:46:08 +10001939 case PROP_PRESET:
1940 nvenc->preset_enum = g_value_get_enum (value);
1941 nvenc->selected_preset = _nv_preset_to_guid (nvenc->preset_enum);
Ole André Vadla Ravnås59365e32017-04-17 13:58:53 +02001942 gst_nv_base_enc_schedule_reconfig (nvenc);
Matthew Watersc45fc2e2016-04-07 22:46:08 +10001943 break;
Matthew Watersdc1a3262016-04-08 14:51:44 +10001944 case PROP_RC_MODE:
1945 nvenc->rate_control_mode = g_value_get_enum (value);
Ole André Vadla Ravnås59365e32017-04-17 13:58:53 +02001946 gst_nv_base_enc_schedule_reconfig (nvenc);
Matthew Watersdc1a3262016-04-08 14:51:44 +10001947 break;
1948 case PROP_QP_MIN:
1949 nvenc->qp_min = g_value_get_int (value);
Ole André Vadla Ravnås59365e32017-04-17 13:58:53 +02001950 gst_nv_base_enc_schedule_reconfig (nvenc);
Matthew Watersdc1a3262016-04-08 14:51:44 +10001951 break;
1952 case PROP_QP_MAX:
1953 nvenc->qp_max = g_value_get_int (value);
Ole André Vadla Ravnås59365e32017-04-17 13:58:53 +02001954 gst_nv_base_enc_schedule_reconfig (nvenc);
Matthew Watersdc1a3262016-04-08 14:51:44 +10001955 break;
1956 case PROP_QP_CONST:
1957 nvenc->qp_const = g_value_get_int (value);
Ole André Vadla Ravnås59365e32017-04-17 13:58:53 +02001958 gst_nv_base_enc_schedule_reconfig (nvenc);
Matthew Watersdc1a3262016-04-08 14:51:44 +10001959 break;
1960 case PROP_BITRATE:
1961 nvenc->bitrate = g_value_get_uint (value);
Ole André Vadla Ravnås59365e32017-04-17 13:58:53 +02001962 gst_nv_base_enc_schedule_reconfig (nvenc);
Matthew Watersdc1a3262016-04-08 14:51:44 +10001963 break;
Tim-Philipp Müller07c84172017-04-16 16:08:27 +02001964 case PROP_GOP_SIZE:
1965 nvenc->gop_size = g_value_get_int (value);
1966 gst_nv_base_enc_schedule_reconfig (nvenc);
1967 break;
Matthew Watersb1d13e12015-07-30 16:42:38 +10001968 default:
1969 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1970 break;
1971 }
1972}
1973
1974static void
1975gst_nv_base_enc_get_property (GObject * object, guint prop_id, GValue * value,
1976 GParamSpec * pspec)
1977{
1978 GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (object);
1979
1980 switch (prop_id) {
1981 case PROP_DEVICE_ID:
1982 g_value_set_uint (value, nvenc->cuda_device_id);
1983 break;
Matthew Watersc45fc2e2016-04-07 22:46:08 +10001984 case PROP_PRESET:
1985 g_value_set_enum (value, nvenc->preset_enum);
1986 break;
Matthew Watersdc1a3262016-04-08 14:51:44 +10001987 case PROP_RC_MODE:
1988 g_value_set_enum (value, nvenc->rate_control_mode);
1989 break;
1990 case PROP_QP_MIN:
1991 g_value_set_int (value, nvenc->qp_min);
1992 break;
1993 case PROP_QP_MAX:
1994 g_value_set_int (value, nvenc->qp_max);
1995 break;
1996 case PROP_QP_CONST:
1997 g_value_set_int (value, nvenc->qp_const);
1998 break;
1999 case PROP_BITRATE:
2000 g_value_set_uint (value, nvenc->bitrate);
2001 break;
Tim-Philipp Müller07c84172017-04-16 16:08:27 +02002002 case PROP_GOP_SIZE:
2003 g_value_set_int (value, nvenc->gop_size);
2004 break;
Matthew Watersb1d13e12015-07-30 16:42:38 +10002005 default:
2006 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2007 break;
2008 }
2009}