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