From b74422dcbc52387c55996c9d6fe16832d5f15df3 Mon Sep 17 00:00:00 2001 From: Seungha Yang Date: Sun, 12 May 2024 18:49:09 +0900 Subject: [PATCH] nvcodec: Remove old nvenc implementation Stop shipping deprecated implementation Part-of: --- .../sys/nvcodec/gstnvbaseenc.c | 2893 ----------------- .../sys/nvcodec/gstnvbaseenc.h | 194 -- .../gst-plugins-bad/sys/nvcodec/gstnvenc.c | 605 ---- .../gst-plugins-bad/sys/nvcodec/gstnvenc.h | 18 - .../sys/nvcodec/gstnvh264enc.c | 748 ----- .../sys/nvcodec/gstnvh264enc.h | 43 - .../sys/nvcodec/gstnvh265enc.c | 861 ----- .../sys/nvcodec/gstnvh265enc.h | 47 - .../gst-plugins-bad/sys/nvcodec/meson.build | 3 - .../gst-plugins-bad/sys/nvcodec/plugin.c | 2 - 10 files changed, 5414 deletions(-) delete mode 100644 subprojects/gst-plugins-bad/sys/nvcodec/gstnvbaseenc.c delete mode 100644 subprojects/gst-plugins-bad/sys/nvcodec/gstnvbaseenc.h delete mode 100644 subprojects/gst-plugins-bad/sys/nvcodec/gstnvh264enc.c delete mode 100644 subprojects/gst-plugins-bad/sys/nvcodec/gstnvh264enc.h delete mode 100644 subprojects/gst-plugins-bad/sys/nvcodec/gstnvh265enc.c delete mode 100644 subprojects/gst-plugins-bad/sys/nvcodec/gstnvh265enc.h diff --git a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvbaseenc.c b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvbaseenc.c deleted file mode 100644 index b66c08aff0..0000000000 --- a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvbaseenc.c +++ /dev/null @@ -1,2893 +0,0 @@ -/* GStreamer NVENC plugin - * Copyright (C) 2015 Centricular Ltd - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gstnvbaseenc.h" - -#include - -#include - -GST_DEBUG_CATEGORY_EXTERN (gst_nvenc_debug); -#define GST_CAT_DEFAULT gst_nvenc_debug - -#ifdef HAVE_CUDA_GST_GL -#include -#endif - -/* This currently supports both 5.x and 6.x versions of the NvEncodeAPI.h - * header which are mostly API compatible. */ - -#define SUPPORTED_GL_APIS GST_GL_API_OPENGL3 - -/* magic pointer value we can put in the async queue to signal shut down */ -#define SHUTDOWN_COOKIE ((gpointer)GINT_TO_POINTER (1)) - -#define parent_class gst_nv_base_enc_parent_class -G_DEFINE_ABSTRACT_TYPE (GstNvBaseEnc, gst_nv_base_enc, GST_TYPE_VIDEO_ENCODER); - -#define GST_TYPE_NV_PRESET (gst_nv_preset_get_type()) -static GType -gst_nv_preset_get_type (void) -{ - static GType nv_preset_type = 0; - - static const GEnumValue presets[] = { - {GST_NV_PRESET_DEFAULT, "Default", "default"}, - {GST_NV_PRESET_HP, "High Performance", "hp"}, - {GST_NV_PRESET_HQ, "High Quality", "hq"}, -/* {GST_NV_PRESET_BD, "BD", "bd"}, */ - {GST_NV_PRESET_LOW_LATENCY_DEFAULT, "Low Latency", "low-latency"}, - {GST_NV_PRESET_LOW_LATENCY_HQ, "Low Latency, High Quality", - "low-latency-hq"}, - {GST_NV_PRESET_LOW_LATENCY_HP, "Low Latency, High Performance", - "low-latency-hp"}, - {GST_NV_PRESET_LOSSLESS_DEFAULT, "Lossless", "lossless"}, - {GST_NV_PRESET_LOSSLESS_HP, "Lossless, High Performance", "lossless-hp"}, - {0, NULL, NULL}, - }; - - if (!nv_preset_type) { - nv_preset_type = g_enum_register_static ("GstNvPreset", presets); - } - return nv_preset_type; -} - -static GUID -_nv_preset_to_guid (GstNvPreset preset) -{ - GUID null = { 0, }; - - switch (preset) { -#define CASE(gst,nv) case G_PASTE(GST_NV_PRESET_,gst): return G_PASTE(G_PASTE(NV_ENC_PRESET_,nv),_GUID) - CASE (DEFAULT, DEFAULT); - CASE (HP, HP); - CASE (HQ, HQ); -/* CASE (BD, BD);*/ - CASE (LOW_LATENCY_DEFAULT, LOW_LATENCY_DEFAULT); - CASE (LOW_LATENCY_HQ, LOW_LATENCY_HQ); - CASE (LOW_LATENCY_HP, LOW_LATENCY_HQ); - CASE (LOSSLESS_DEFAULT, LOSSLESS_DEFAULT); - CASE (LOSSLESS_HP, LOSSLESS_HP); -#undef CASE - default: - return null; - } -} - -#define GST_TYPE_NV_RC_MODE (gst_nv_rc_mode_get_type()) -static GType -gst_nv_rc_mode_get_type (void) -{ - static GType nv_rc_mode_type = 0; - - static const GEnumValue modes[] = { - {GST_NV_RC_MODE_DEFAULT, "Default", "default"}, - {GST_NV_RC_MODE_CONSTQP, "Constant Quantization", "constqp"}, - {GST_NV_RC_MODE_CBR, "Constant Bit Rate", "cbr"}, - {GST_NV_RC_MODE_VBR, "Variable Bit Rate", "vbr"}, - {GST_NV_RC_MODE_VBR_MINQP, - "Variable Bit Rate " - "(with minimum quantization parameter, DEPRECATED)", "vbr-minqp"}, - {GST_NV_RC_MODE_CBR_LOWDELAY_HQ, - "Low-Delay CBR, High Quality", "cbr-ld-hq"}, - {GST_NV_RC_MODE_CBR_HQ, "CBR, High Quality (slower)", "cbr-hq"}, - {GST_NV_RC_MODE_VBR_HQ, "VBR, High Quality (slower)", "vbr-hq"}, - {0, NULL, NULL}, - }; - - if (!nv_rc_mode_type) { - nv_rc_mode_type = g_enum_register_static ("GstNvRCMode", modes); - } - return nv_rc_mode_type; -} - -static NV_ENC_PARAMS_RC_MODE -_rc_mode_to_nv (GstNvRCMode mode) -{ - switch (mode) { - case GST_NV_RC_MODE_DEFAULT: - return NV_ENC_PARAMS_RC_VBR; -#define CASE(gst,nv) case G_PASTE(GST_NV_RC_MODE_,gst): return G_PASTE(NV_ENC_PARAMS_RC_,nv) - CASE (CONSTQP, CONSTQP); - CASE (CBR, CBR); - CASE (VBR, VBR); - CASE (VBR_MINQP, VBR_MINQP); - CASE (CBR_LOWDELAY_HQ, CBR_LOWDELAY_HQ); - CASE (CBR_HQ, CBR_HQ); - CASE (VBR_HQ, VBR_HQ); -#undef CASE - default: - return NV_ENC_PARAMS_RC_VBR; - } -} - -enum -{ - PROP_0, - PROP_DEVICE_ID, - PROP_PRESET, - PROP_BITRATE, - PROP_RC_MODE, - PROP_QP_MIN, - PROP_QP_MAX, - PROP_QP_CONST, - PROP_GOP_SIZE, - PROP_MAX_BITRATE, - PROP_SPATIAL_AQ, - PROP_AQ_STRENGTH, - PROP_NON_REF_P, - PROP_ZEROLATENCY, - PROP_STRICT_GOP, - PROP_CONST_QUALITY, - PROP_I_ADAPT, - PROP_QP_MIN_I, - PROP_QP_MIN_P, - PROP_QP_MIN_B, - PROP_QP_MAX_I, - PROP_QP_MAX_P, - PROP_QP_MAX_B, - PROP_QP_CONST_I, - PROP_QP_CONST_P, - PROP_QP_CONST_B, -}; - -#define DEFAULT_PRESET GST_NV_PRESET_DEFAULT -#define DEFAULT_BITRATE 0 -#define DEFAULT_RC_MODE GST_NV_RC_MODE_DEFAULT -#define DEFAULT_QP_MIN -1 -#define DEFAULT_QP_MAX -1 -#define DEFAULT_QP_CONST -1 -#define DEFAULT_GOP_SIZE 75 -#define DEFAULT_MAX_BITRATE 0 -#define DEFAULT_SPATIAL_AQ FALSE -#define DEFAULT_AQ_STRENGTH 0 -#define DEFAULT_NON_REF_P FALSE -#define DEFAULT_ZEROLATENCY FALSE -#define DEFAULT_STRICT_GOP FALSE -#define DEFAULT_CONST_QUALITY 0 -#define DEFAULT_I_ADAPT FALSE -#define DEFAULT_QP_DETAIL -1 - -/* This lock is needed to prevent the situation where multiple encoders are - * initialised at the same time which appears to cause excessive CPU usage over - * some period of time. */ -G_LOCK_DEFINE_STATIC (initialization_lock); - -typedef struct -{ - /* Allocated CUDA device memory and registered to NVENC to be used as input - * buffer regardless of the input memory type (OpenGL or System memory) */ - CUdeviceptr cuda_pointer; - - /* The stride of allocated CUDA device memory (CuMemAllocPitch). - * This might be different from the stride of GstVideoInfo */ - gsize cuda_stride; - - /* Registered NVENC resource (cuda_pointer is used for this) */ - NV_ENC_REGISTER_RESOURCE nv_resource; - - /* Mapped resource of nv_resource */ - NV_ENC_MAP_INPUT_RESOURCE nv_mapped_resource; - - /* whether nv_mapped_resource was mapped via NvEncMapInputResource() - * and therefore should unmap via NvEncUnmapInputResource or not */ - gboolean mapped; -} GstNvEncInputResource; - -/* The pair of GstNvEncInputResource () and NV_ENC_OUTPUT_PTR. - * The number of input/output resource are always identical */ -typedef struct -{ - GstNvEncInputResource *in_buf; - NV_ENC_OUTPUT_PTR out_buf; -} GstNvEncFrameState; - -static gboolean gst_nv_base_enc_open (GstVideoEncoder * enc); -static gboolean gst_nv_base_enc_close (GstVideoEncoder * enc); -static gboolean gst_nv_base_enc_start (GstVideoEncoder * enc); -static gboolean gst_nv_base_enc_stop (GstVideoEncoder * enc); -static void gst_nv_base_enc_set_context (GstElement * element, - GstContext * context); -static gboolean gst_nv_base_enc_sink_query (GstVideoEncoder * enc, - GstQuery * query); -static gboolean gst_nv_base_enc_sink_event (GstVideoEncoder * enc, - GstEvent * event); -static gboolean gst_nv_base_enc_set_format (GstVideoEncoder * enc, - GstVideoCodecState * state); -static GstFlowReturn gst_nv_base_enc_handle_frame (GstVideoEncoder * enc, - GstVideoCodecFrame * frame); -static void gst_nv_base_enc_free_buffers (GstNvBaseEnc * nvenc); -static GstFlowReturn gst_nv_base_enc_finish (GstVideoEncoder * enc); -static void gst_nv_base_enc_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_nv_base_enc_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); -static void gst_nv_base_enc_finalize (GObject * obj); -static GstCaps *gst_nv_base_enc_getcaps (GstVideoEncoder * enc, - GstCaps * filter); -static gboolean gst_nv_base_enc_stop_bitstream_thread (GstNvBaseEnc * nvenc, - gboolean force); -static gboolean gst_nv_base_enc_drain_encoder (GstNvBaseEnc * nvenc); -static gboolean gst_nv_base_enc_propose_allocation (GstVideoEncoder * enc, - GstQuery * query); - -static void -gst_nv_base_enc_class_init (GstNvBaseEncClass * klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - GstVideoEncoderClass *videoenc_class = GST_VIDEO_ENCODER_CLASS (klass); - - gobject_class->set_property = gst_nv_base_enc_set_property; - gobject_class->get_property = gst_nv_base_enc_get_property; - gobject_class->finalize = gst_nv_base_enc_finalize; - - element_class->set_context = GST_DEBUG_FUNCPTR (gst_nv_base_enc_set_context); - - videoenc_class->open = GST_DEBUG_FUNCPTR (gst_nv_base_enc_open); - videoenc_class->close = GST_DEBUG_FUNCPTR (gst_nv_base_enc_close); - - videoenc_class->start = GST_DEBUG_FUNCPTR (gst_nv_base_enc_start); - videoenc_class->stop = GST_DEBUG_FUNCPTR (gst_nv_base_enc_stop); - - videoenc_class->set_format = GST_DEBUG_FUNCPTR (gst_nv_base_enc_set_format); - videoenc_class->getcaps = GST_DEBUG_FUNCPTR (gst_nv_base_enc_getcaps); - videoenc_class->handle_frame = - GST_DEBUG_FUNCPTR (gst_nv_base_enc_handle_frame); - videoenc_class->finish = GST_DEBUG_FUNCPTR (gst_nv_base_enc_finish); - videoenc_class->sink_query = GST_DEBUG_FUNCPTR (gst_nv_base_enc_sink_query); - videoenc_class->sink_event = GST_DEBUG_FUNCPTR (gst_nv_base_enc_sink_event); - videoenc_class->propose_allocation = - GST_DEBUG_FUNCPTR (gst_nv_base_enc_propose_allocation); - - g_object_class_install_property (gobject_class, PROP_DEVICE_ID, - g_param_spec_uint ("cuda-device-id", - "Cuda Device ID", - "Get the GPU device to use for operations", - 0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_PRESET, - g_param_spec_enum ("preset", "Encoding Preset", - "Encoding Preset", - GST_TYPE_NV_PRESET, DEFAULT_PRESET, - G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING | - G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_RC_MODE, - g_param_spec_enum ("rc-mode", "RC Mode", "Rate Control Mode", - GST_TYPE_NV_RC_MODE, DEFAULT_RC_MODE, - G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING | - G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_QP_MIN, - g_param_spec_int ("qp-min", "Minimum Quantizer", - "Minimum quantizer (-1 = from NVENC preset)", -1, 51, DEFAULT_QP_MIN, - G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING | - G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_QP_MAX, - g_param_spec_int ("qp-max", "Maximum Quantizer", - "Maximum quantizer (-1 = from NVENC preset)", -1, 51, DEFAULT_QP_MAX, - G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING | - G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_QP_CONST, - g_param_spec_int ("qp-const", "Constant Quantizer", - "Constant quantizer (-1 = from NVENC preset)", -1, 51, - DEFAULT_QP_CONST, - G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING | - G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_GOP_SIZE, - g_param_spec_int ("gop-size", "GOP size", - "Number of frames between intra frames (-1 = infinite)", - -1, G_MAXINT, DEFAULT_GOP_SIZE, - (GParamFlags) (G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING | - G_PARAM_STATIC_STRINGS))); - g_object_class_install_property (gobject_class, PROP_BITRATE, - g_param_spec_uint ("bitrate", "Bitrate", - "Bitrate in kbit/sec (0 = from NVENC preset)", 0, 2000 * 1024, - DEFAULT_BITRATE, - G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING | - G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_MAX_BITRATE, - g_param_spec_uint ("max-bitrate", "Max Bitrate", - "Maximum Bitrate in kbit/sec (ignored for CBR mode)", 0, 2000 * 1024, - DEFAULT_MAX_BITRATE, - G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING | - G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_SPATIAL_AQ, - g_param_spec_boolean ("spatial-aq", "Spatial AQ", - "Spatial Adaptive Quantization", - DEFAULT_SPATIAL_AQ, - G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING | - G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_AQ_STRENGTH, - g_param_spec_uint ("aq-strength", "AQ Strength", - "Adaptive Quantization Strength when spatial-aq is enabled" - " from 1 (low) to 15 (aggressive), (0 = autoselect)", - 0, 15, DEFAULT_AQ_STRENGTH, - G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING | - G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_NON_REF_P, - g_param_spec_boolean ("nonref-p", "Nonref P", - "Automatic insertion of non-reference P-frames", DEFAULT_NON_REF_P, - G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING | - G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_ZEROLATENCY, - g_param_spec_boolean ("zerolatency", "Zerolatency", - "Zero latency operation (no reordering delay)", DEFAULT_ZEROLATENCY, - G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING | - G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_STRICT_GOP, - g_param_spec_boolean ("strict-gop", "Strict GOP", - "Minimize GOP-to-GOP rate fluctuations", DEFAULT_STRICT_GOP, - G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING | - G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_CONST_QUALITY, - g_param_spec_double ("const-quality", "Constant Quality", - "Target Constant Quality level for VBR mode (0 = automatic)", - 0, 51, DEFAULT_CONST_QUALITY, - G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING | - G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_I_ADAPT, - g_param_spec_boolean ("i-adapt", "I Adapt", - "Enable adaptive I-frame insert when lookahead is enabled", - DEFAULT_I_ADAPT, - G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY | - G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_QP_MIN_I, - g_param_spec_int ("qp-min-i", "QP Min I", - "Minimum QP value for I frame, When >= 0, \"qp-min-p\" and " - "\"qp-min-b\" should be also >= 0. Overwritten by \"qp-min\"" - " (-1 = from NVENC preset)", -1, 51, - DEFAULT_QP_DETAIL, - G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING | - G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_QP_MIN_P, - g_param_spec_int ("qp-min-p", "QP Min P", - "Minimum QP value for P frame, When >= 0, \"qp-min-i\" and " - "\"qp-min-b\" should be also >= 0. Overwritten by \"qp-min\"" - " (-1 = from NVENC preset)", -1, 51, - DEFAULT_QP_DETAIL, - G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING | - G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_QP_MIN_B, - g_param_spec_int ("qp-min-b", "QP Min B", - "Minimum QP value for B frame, When >= 0, \"qp-min-i\" and " - "\"qp-min-p\" should be also >= 0. Overwritten by \"qp-min\"" - " (-1 = from NVENC preset)", -1, 51, - DEFAULT_QP_DETAIL, - G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING | - G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_QP_MAX_I, - g_param_spec_int ("qp-max-i", "QP Max I", - "Maximum QP value for I frame, When >= 0, \"qp-max-p\" and " - "\"qp-max-b\" should be also >= 0. Overwritten by \"qp-max\"" - " (-1 = from NVENC preset)", -1, 51, - DEFAULT_QP_DETAIL, - G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING | - G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_QP_MAX_P, - g_param_spec_int ("qp-max-p", "QP Max P", - "Maximum QP value for P frame, When >= 0, \"qp-max-i\" and " - "\"qp-max-b\" should be also >= 0. Overwritten by \"qp-max\"" - " (-1 = from NVENC preset)", -1, 51, - DEFAULT_QP_DETAIL, - G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING | - G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_QP_MAX_B, - g_param_spec_int ("qp-max-b", "QP Max B", - "Maximum QP value for B frame, When >= 0, \"qp-max-i\" and " - "\"qp-max-p\" should be also >= 0. Overwritten by \"qp-max\"" - " (-1 = from NVENC preset)", -1, 51, - DEFAULT_QP_DETAIL, - G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING | - G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_QP_CONST_I, - g_param_spec_int ("qp-const-i", "QP Const I", - "Constant QP value for I frame, When >= 0, \"qp-const-p\" and " - "\"qp-const-b\" should be also >= 0. Overwritten by \"qp-const\"" - " (-1 = from NVENC preset)", -1, 51, - DEFAULT_QP_DETAIL, - G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING | - G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_QP_CONST_P, - g_param_spec_int ("qp-const-p", "QP Const P", - "Constant QP value for P frame, When >= 0, \"qp-const-i\" and " - "\"qp-const-b\" should be also >= 0. Overwritten by \"qp-const\"" - " (-1 = from NVENC preset)", -1, 51, - DEFAULT_QP_DETAIL, - G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING | - G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_QP_CONST_B, - g_param_spec_int ("qp-const-b", "QP Const B", - "Constant QP value for B frame, When >= 0, \"qp-const-i\" and " - "\"qp-const-p\" should be also >= 0. Overwritten by \"qp-const\"" - " (-1 = from NVENC preset)", -1, 51, - DEFAULT_QP_DETAIL, - G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING | - G_PARAM_STATIC_STRINGS)); - - gst_type_mark_as_plugin_api (GST_TYPE_NV_BASE_ENC, 0); - gst_type_mark_as_plugin_api (GST_TYPE_NV_PRESET, 0); - gst_type_mark_as_plugin_api (GST_TYPE_NV_RC_MODE, 0); -} - -static gboolean -gst_nv_base_enc_open_encode_session (GstNvBaseEnc * nvenc) -{ - NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS params = { 0, }; - NVENCSTATUS nv_ret; - - params.version = gst_nvenc_get_open_encode_session_ex_params_version (); - params.apiVersion = gst_nvenc_get_api_version (); - params.device = gst_cuda_context_get_handle (nvenc->cuda_ctx); - params.deviceType = NV_ENC_DEVICE_TYPE_CUDA; - nv_ret = NvEncOpenEncodeSessionEx (¶ms, &nvenc->encoder); - - if (nv_ret != NV_ENC_SUCCESS) { - /* Report error to abort if GST_CUDA_CRITICAL_ERRORS is configured */ - gst_cuda_result (CUDA_ERROR_NO_DEVICE); - return FALSE; - } - - return TRUE; -} - -static gboolean -gst_nv_base_enc_open (GstVideoEncoder * enc) -{ - GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (enc); - GstNvBaseEncClass *klass = GST_NV_BASE_ENC_GET_CLASS (enc); - GValue *formats = NULL; - - if (!gst_cuda_ensure_element_context (GST_ELEMENT_CAST (enc), - klass->cuda_device_id, &nvenc->cuda_ctx)) { - GST_ERROR_OBJECT (nvenc, "failed to create CUDA context"); - return FALSE; - } - - nvenc->stream = gst_cuda_stream_new (nvenc->cuda_ctx); - if (!nvenc->stream) { - GST_WARNING_OBJECT (nvenc, - "Could not create cuda stream, will use default stream"); - } - - if (!gst_nv_base_enc_open_encode_session (nvenc)) { - GST_ERROR ("Failed to create NVENC encoder session"); - gst_clear_object (&nvenc->cuda_ctx); - return FALSE; - } - - GST_INFO ("created NVENC encoder %p", nvenc->encoder); - - /* query supported input formats */ - if (!gst_nvenc_get_supported_input_formats (nvenc->encoder, klass->codec_id, - &formats)) { - GST_WARNING_OBJECT (nvenc, "No supported input formats"); - gst_nv_base_enc_close (enc); - return FALSE; - } - - nvenc->input_formats = formats; - - return TRUE; -} - -static void -gst_nv_base_enc_set_context (GstElement * element, GstContext * context) -{ - GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (element); - GstNvBaseEncClass *klass = GST_NV_BASE_ENC_GET_CLASS (nvenc); - - if (gst_cuda_handle_set_context (element, context, klass->cuda_device_id, - &nvenc->cuda_ctx)) { - goto done; - } -#ifdef HAVE_CUDA_GST_GL - gst_gl_handle_set_context (element, context, - (GstGLDisplay **) & nvenc->display, - (GstGLContext **) & nvenc->other_context); - if (nvenc->display) - gst_gl_display_filter_gl_api (GST_GL_DISPLAY (nvenc->display), - SUPPORTED_GL_APIS); -#endif - -done: - GST_ELEMENT_CLASS (parent_class)->set_context (element, context); -} - -static gboolean -gst_nv_base_enc_sink_query (GstVideoEncoder * enc, GstQuery * query) -{ - GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (enc); - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_CONTEXT:{ - if (gst_cuda_handle_context_query (GST_ELEMENT (nvenc), - query, nvenc->cuda_ctx)) - return TRUE; - -#ifdef HAVE_CUDA_GST_GL - { - gboolean ret; - - ret = gst_gl_handle_context_query ((GstElement *) nvenc, query, - (GstGLDisplay *) nvenc->display, NULL, - (GstGLContext *) nvenc->other_context); - if (nvenc->display) { - gst_gl_display_filter_gl_api (GST_GL_DISPLAY (nvenc->display), - SUPPORTED_GL_APIS); - } - - if (ret) - return ret; - } -#endif - break; - } - default: - break; - } - - return GST_VIDEO_ENCODER_CLASS (parent_class)->sink_query (enc, query); -} - -#ifdef HAVE_CUDA_GST_GL -static gboolean -gst_nv_base_enc_ensure_gl_context (GstNvBaseEnc * nvenc) -{ - if (!nvenc->display) { - GST_DEBUG_OBJECT (nvenc, "No available OpenGL display"); - return FALSE; - } - - if (!gst_gl_query_local_gl_context (GST_ELEMENT (nvenc), GST_PAD_SINK, - (GstGLContext **) & nvenc->gl_context)) { - GST_INFO_OBJECT (nvenc, "failed to query local OpenGL context"); - if (nvenc->gl_context) - gst_object_unref (nvenc->gl_context); - nvenc->gl_context = - (GstObject *) gst_gl_display_get_gl_context_for_thread ((GstGLDisplay *) - nvenc->display, NULL); - if (!nvenc->gl_context - || !gst_gl_display_add_context ((GstGLDisplay *) nvenc->display, - (GstGLContext *) nvenc->gl_context)) { - if (nvenc->gl_context) - gst_object_unref (nvenc->gl_context); - if (!gst_gl_display_create_context ((GstGLDisplay *) nvenc->display, - (GstGLContext *) nvenc->other_context, - (GstGLContext **) & nvenc->gl_context, NULL)) { - GST_ERROR_OBJECT (nvenc, "failed to create OpenGL context"); - return FALSE; - } - if (!gst_gl_display_add_context ((GstGLDisplay *) nvenc->display, - (GstGLContext *) nvenc->gl_context)) { - GST_ERROR_OBJECT (nvenc, - "failed to add the OpenGL context to the display"); - return FALSE; - } - } - } - - if (!gst_gl_context_check_gl_version ((GstGLContext *) nvenc->gl_context, - SUPPORTED_GL_APIS, 3, 0)) { - GST_WARNING_OBJECT (nvenc, "OpenGL context could not support PBO download"); - return FALSE; - } - - return TRUE; -} -#endif - -static gboolean -gst_nv_base_enc_propose_allocation (GstVideoEncoder * enc, GstQuery * query) -{ - GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (enc); - GstCaps *caps; - GstVideoInfo info; - GstBufferPool *pool; - GstStructure *config; - GstCapsFeatures *features; - guint size; - - GST_DEBUG_OBJECT (nvenc, "propose allocation"); - - gst_query_parse_allocation (query, &caps, NULL); - - if (caps == NULL) - return FALSE; - - if (!gst_video_info_from_caps (&info, caps)) { - GST_WARNING_OBJECT (nvenc, "failed to get video info"); - return FALSE; - } - - features = gst_caps_get_features (caps, 0); -#ifdef HAVE_CUDA_GST_GL - if (features && gst_caps_features_contains (features, - GST_CAPS_FEATURE_MEMORY_GL_MEMORY)) { - GST_DEBUG_OBJECT (nvenc, "upsteram support GL memory"); - if (!gst_nv_base_enc_ensure_gl_context (nvenc)) { - GST_WARNING_OBJECT (nvenc, "Could not get gl context"); - goto done; - } - - pool = gst_gl_buffer_pool_new ((GstGLContext *) nvenc->gl_context); - } else -#endif - if (features && gst_caps_features_contains (features, - GST_CAPS_FEATURE_MEMORY_CUDA_MEMORY)) { - GST_DEBUG_OBJECT (nvenc, "upstream support CUDA memory"); - pool = gst_cuda_buffer_pool_new (nvenc->cuda_ctx); - } else { - GST_DEBUG_OBJECT (nvenc, "use system memory"); - goto done; - } - - if (G_UNLIKELY (pool == NULL)) { - GST_WARNING_OBJECT (nvenc, "cannot create buffer pool"); - goto done; - } - - size = GST_VIDEO_INFO_SIZE (&info); - - config = gst_buffer_pool_get_config (pool); - gst_buffer_pool_config_set_params (config, caps, size, nvenc->items->len, 0); - gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META); - - if (!gst_buffer_pool_set_config (pool, config)) - goto error_pool_config; - - /* Get updated size by cuda buffer pool */ - config = gst_buffer_pool_get_config (pool); - gst_buffer_pool_config_get_params (config, NULL, &size, NULL, NULL); - gst_structure_free (config); - - gst_query_add_allocation_pool (query, pool, size, nvenc->items->len, 0); - gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL); - - gst_object_unref (pool); - -done: - return GST_VIDEO_ENCODER_CLASS (parent_class)->propose_allocation (enc, - query); - -error_pool_config: - { - if (pool) - gst_object_unref (pool); - GST_WARNING_OBJECT (nvenc, "failed to set config"); - return FALSE; - } -} - -static gboolean -gst_nv_base_enc_sink_event (GstVideoEncoder * enc, GstEvent * event) -{ - GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (enc); - gboolean ret; - - ret = GST_VIDEO_ENCODER_CLASS (parent_class)->sink_event (enc, event); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_STREAM_START: - case GST_EVENT_FLUSH_STOP: - nvenc->last_flow = GST_FLOW_OK; - break; - default: - break; - } - - return ret; -} - -static gboolean -gst_nv_base_enc_start (GstVideoEncoder * enc) -{ - GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (enc); - - nvenc->available_queue = g_async_queue_new (); - nvenc->pending_queue = g_async_queue_new (); - nvenc->bitstream_queue = g_async_queue_new (); - nvenc->items = g_array_new (FALSE, TRUE, sizeof (GstNvEncFrameState)); - - nvenc->last_flow = GST_FLOW_OK; - memset (&nvenc->init_params, 0, sizeof (NV_ENC_INITIALIZE_PARAMS)); - memset (&nvenc->config, 0, sizeof (NV_ENC_CONFIG)); - -#ifdef HAVE_CUDA_GST_GL - { - gst_gl_ensure_element_data (GST_ELEMENT (nvenc), - (GstGLDisplay **) & nvenc->display, - (GstGLContext **) & nvenc->other_context); - if (nvenc->display) - gst_gl_display_filter_gl_api (GST_GL_DISPLAY (nvenc->display), - SUPPORTED_GL_APIS); - } -#endif - - /* DTS can be negative if bframe was enabled */ - gst_video_encoder_set_min_pts (enc, GST_SECOND * 60 * 60 * 1000); - - return TRUE; -} - -static gboolean -gst_nv_base_enc_stop (GstVideoEncoder * enc) -{ - GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (enc); - - gst_nv_base_enc_stop_bitstream_thread (nvenc, TRUE); - - gst_nv_base_enc_free_buffers (nvenc); - - if (nvenc->input_state) { - gst_video_codec_state_unref (nvenc->input_state); - nvenc->input_state = NULL; - } - - if (nvenc->available_queue) { - g_async_queue_unref (nvenc->available_queue); - nvenc->available_queue = NULL; - } - if (nvenc->pending_queue) { - g_async_queue_unref (nvenc->pending_queue); - nvenc->pending_queue = NULL; - } - if (nvenc->bitstream_queue) { - g_async_queue_unref (nvenc->bitstream_queue); - nvenc->bitstream_queue = NULL; - } - if (nvenc->display) { - gst_object_unref (nvenc->display); - nvenc->display = NULL; - } - if (nvenc->other_context) { - gst_object_unref (nvenc->other_context); - nvenc->other_context = NULL; - } - if (nvenc->gl_context) { - gst_object_unref (nvenc->gl_context); - nvenc->gl_context = NULL; - } - - if (nvenc->items) { - g_array_free (nvenc->items, TRUE); - nvenc->items = NULL; - } - - return TRUE; -} - -static void -check_formats (const gchar * str, guint * max_chroma, guint * max_bit_minus8) -{ - if (!str) - return; - - if (g_strrstr (str, "-444") || g_strrstr (str, "-4:4:4")) - *max_chroma = 2; - else if ((g_strrstr (str, "-4:2:2") || g_strrstr (str, "-422")) - && *max_chroma < 1) - *max_chroma = 1; - - if (g_strrstr (str, "-12")) - *max_bit_minus8 = 4; - else if (g_strrstr (str, "-10") && *max_bit_minus8 < 2) - *max_bit_minus8 = 2; -} - -static gboolean -gst_nv_base_enc_set_filtered_input_formats (GstNvBaseEnc * nvenc, - GstCaps * caps, const GValue * input_formats, guint max_chroma, - guint max_bit_minus8) -{ - gint i; - GValue supported_format = G_VALUE_INIT; - gint num_format = 0; - const GValue *last_format = NULL; - - g_value_init (&supported_format, GST_TYPE_LIST); - - for (i = 0; i < gst_value_list_get_size (input_formats); i++) { - const GValue *val; - GstVideoFormat format; - - val = gst_value_list_get_value (input_formats, i); - format = gst_video_format_from_string (g_value_get_string (val)); - - switch (format) { - case GST_VIDEO_FORMAT_NV12: - case GST_VIDEO_FORMAT_YV12: - case GST_VIDEO_FORMAT_I420: - /* 8bits 4:2:0 formats are always supported */ - case GST_VIDEO_FORMAT_BGRA: - case GST_VIDEO_FORMAT_RGBA: - /* NOTE: RGB formats seems to also supported format, which are - * encoded to 4:2:0 formats */ - gst_value_list_append_value (&supported_format, val); - last_format = val; - num_format++; - break; - case GST_VIDEO_FORMAT_Y444: - case GST_VIDEO_FORMAT_VUYA: - if (max_chroma >= 2) { - gst_value_list_append_value (&supported_format, val); - last_format = val; - num_format++; - } - break; - case GST_VIDEO_FORMAT_P010_10LE: - case GST_VIDEO_FORMAT_P010_10BE: - case GST_VIDEO_FORMAT_BGR10A2_LE: - case GST_VIDEO_FORMAT_RGB10A2_LE: - case GST_VIDEO_FORMAT_Y444_16LE: - case GST_VIDEO_FORMAT_Y444_16BE: - if (max_bit_minus8 >= 2) { - gst_value_list_append_value (&supported_format, val); - last_format = val; - num_format++; - } - break; - default: - break; - } - } - - if (num_format == 0) { - g_value_unset (&supported_format); - GST_WARNING_OBJECT (nvenc, "Cannot find matching input format"); - return FALSE; - } - - if (num_format > 1) - gst_caps_set_value (caps, "format", &supported_format); - else - gst_caps_set_value (caps, "format", last_format); - - g_value_unset (&supported_format); - - return TRUE; -} - -static GstCaps * -gst_nv_base_enc_getcaps (GstVideoEncoder * enc, GstCaps * filter) -{ - GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (enc); - GstNvBaseEncClass *klass = GST_NV_BASE_ENC_GET_CLASS (enc); - GstCaps *supported_incaps = NULL; - GstCaps *template_caps, *caps, *allowed; - - template_caps = gst_pad_get_pad_template_caps (enc->sinkpad); - allowed = gst_pad_get_allowed_caps (enc->srcpad); - - GST_LOG_OBJECT (enc, "template caps %" GST_PTR_FORMAT, template_caps); - GST_LOG_OBJECT (enc, "allowed caps %" GST_PTR_FORMAT, allowed); - - if (!allowed) { - /* no peer */ - supported_incaps = template_caps; - template_caps = NULL; - goto done; - } else if (gst_caps_is_empty (allowed)) { - /* couldn't be negotiated, just return empty caps */ - gst_caps_unref (template_caps); - return allowed; - } - - GST_OBJECT_LOCK (nvenc); - - if (nvenc->input_formats != NULL) { - gboolean has_profile = FALSE; - guint max_chroma_index = 0; - guint max_bit_minus8 = 0; - gint i, j; - - for (i = 0; i < gst_caps_get_size (allowed); i++) { - const GstStructure *allowed_s = gst_caps_get_structure (allowed, i); - const GValue *val; - - if ((val = gst_structure_get_value (allowed_s, "profile"))) { - if (G_VALUE_HOLDS_STRING (val)) { - check_formats (g_value_get_string (val), &max_chroma_index, - &max_bit_minus8); - has_profile = TRUE; - } else if (GST_VALUE_HOLDS_LIST (val)) { - for (j = 0; j < gst_value_list_get_size (val); j++) { - const GValue *vlist = gst_value_list_get_value (val, j); - - if (G_VALUE_HOLDS_STRING (vlist)) { - check_formats (g_value_get_string (vlist), &max_chroma_index, - &max_bit_minus8); - has_profile = TRUE; - } - } - } - } - } - - GST_LOG_OBJECT (enc, - "downstream requested profile %d, max bitdepth %d, max chroma %d", - has_profile, max_bit_minus8 + 8, max_chroma_index); - - supported_incaps = gst_caps_copy (template_caps); - if (!has_profile || - !gst_nv_base_enc_set_filtered_input_formats (nvenc, supported_incaps, - nvenc->input_formats, max_chroma_index, max_bit_minus8)) { - gst_caps_set_value (supported_incaps, "format", nvenc->input_formats); - } - - if (nvenc->encoder) { - GValue *interlace_mode; - - interlace_mode = - gst_nvenc_get_interlace_modes (nvenc->encoder, klass->codec_id); - gst_caps_set_value (supported_incaps, "interlace-mode", interlace_mode); - g_value_unset (interlace_mode); - g_free (interlace_mode); - } - - GST_LOG_OBJECT (enc, "codec input caps %" GST_PTR_FORMAT, supported_incaps); - GST_LOG_OBJECT (enc, " template caps %" GST_PTR_FORMAT, template_caps); - caps = gst_caps_intersect (template_caps, supported_incaps); - gst_caps_unref (supported_incaps); - supported_incaps = caps; - GST_LOG_OBJECT (enc, " supported caps %" GST_PTR_FORMAT, supported_incaps); - } - - GST_OBJECT_UNLOCK (nvenc); - -done: - caps = gst_video_encoder_proxy_getcaps (enc, supported_incaps, filter); - - if (supported_incaps) - gst_caps_unref (supported_incaps); - gst_clear_caps (&allowed); - gst_clear_caps (&template_caps); - - GST_DEBUG_OBJECT (nvenc, " returning caps %" GST_PTR_FORMAT, caps); - - return caps; -} - -static gboolean -gst_nv_base_enc_close (GstVideoEncoder * enc) -{ - GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (enc); - gboolean ret = TRUE; - - if (nvenc->encoder) { - if (NvEncDestroyEncoder (nvenc->encoder) != NV_ENC_SUCCESS) - ret = FALSE; - - nvenc->encoder = NULL; - } - - gst_clear_cuda_stream (&nvenc->stream); - gst_clear_object (&nvenc->cuda_ctx); - - GST_OBJECT_LOCK (nvenc); - if (nvenc->input_formats) - g_value_unset (nvenc->input_formats); - g_free (nvenc->input_formats); - nvenc->input_formats = NULL; - GST_OBJECT_UNLOCK (nvenc); - - if (nvenc->input_state) { - gst_video_codec_state_unref (nvenc->input_state); - nvenc->input_state = NULL; - } - - return ret; -} - -static void -gst_nv_base_enc_init (GstNvBaseEnc * nvenc) -{ - GstVideoEncoder *encoder = GST_VIDEO_ENCODER (nvenc); - GstNvEncQP qp_detail = - { DEFAULT_QP_DETAIL, DEFAULT_QP_DETAIL, DEFAULT_QP_DETAIL }; - - nvenc->preset_enum = DEFAULT_PRESET; - nvenc->selected_preset = _nv_preset_to_guid (nvenc->preset_enum); - nvenc->rate_control_mode = DEFAULT_RC_MODE; - nvenc->qp_min = DEFAULT_QP_MIN; - nvenc->qp_max = DEFAULT_QP_MAX; - nvenc->qp_const = DEFAULT_QP_CONST; - nvenc->bitrate = DEFAULT_BITRATE; - nvenc->gop_size = DEFAULT_GOP_SIZE; - nvenc->max_bitrate = DEFAULT_MAX_BITRATE; - nvenc->spatial_aq = DEFAULT_SPATIAL_AQ; - nvenc->aq_strength = DEFAULT_AQ_STRENGTH; - nvenc->non_refp = DEFAULT_NON_REF_P; - nvenc->zerolatency = DEFAULT_ZEROLATENCY; - nvenc->strict_gop = DEFAULT_STRICT_GOP; - nvenc->const_quality = DEFAULT_CONST_QUALITY; - nvenc->i_adapt = DEFAULT_I_ADAPT; - nvenc->qp_min_detail = qp_detail; - nvenc->qp_max_detail = qp_detail; - nvenc->qp_const_detail = qp_detail; - - GST_VIDEO_ENCODER_STREAM_LOCK (encoder); - GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder); - - GST_PAD_SET_ACCEPT_INTERSECT (GST_VIDEO_ENCODER_SINK_PAD (encoder)); -} - -static void -gst_nv_base_enc_finalize (GObject * obj) -{ - G_OBJECT_CLASS (gst_nv_base_enc_parent_class)->finalize (obj); -} - -static GstVideoCodecFrame * -_find_frame_with_output_buffer (GstNvBaseEnc * nvenc, NV_ENC_OUTPUT_PTR out_buf) -{ - GList *l, *walk = gst_video_encoder_get_frames (GST_VIDEO_ENCODER (nvenc)); - GstVideoCodecFrame *ret = NULL; - - for (l = walk; l; l = l->next) { - GstVideoCodecFrame *frame = (GstVideoCodecFrame *) l->data; - GstNvEncFrameState *state = gst_video_codec_frame_get_user_data (frame); - - if (!state || !state->out_buf) - continue; - - if (state->out_buf == out_buf) { - ret = frame; - break; - } - } - - if (ret) - gst_video_codec_frame_ref (ret); - - g_list_free_full (walk, (GDestroyNotify) gst_video_codec_frame_unref); - - return ret; -} - -static const gchar * -picture_type_to_string (NV_ENC_PIC_TYPE type) -{ - switch (type) { - case NV_ENC_PIC_TYPE_P: - return "P"; - case NV_ENC_PIC_TYPE_B: - return "B"; - case NV_ENC_PIC_TYPE_I: - return "I"; - case NV_ENC_PIC_TYPE_IDR: - return "IDR"; - case NV_ENC_PIC_TYPE_BI: - return "BI"; - case NV_ENC_PIC_TYPE_SKIPPED: - return "SKIPPED"; - case NV_ENC_PIC_TYPE_INTRA_REFRESH: - return "INTRA-REFRESH"; - case NV_ENC_PIC_TYPE_UNKNOWN: - default: - break; - } - - return "UNKNOWN"; -} - -static gpointer -gst_nv_base_enc_bitstream_thread (gpointer user_data) -{ - GstVideoEncoder *enc = user_data; - GstNvBaseEnc *nvenc = user_data; - GstFlowReturn flow = GST_FLOW_OK; - - /* overview of operation: - * 1. retrieve the next buffer submitted to the bitstream pool - * 2. wait for that buffer to be ready from nvenc (LockBitsream) - * 3. retrieve the GstVideoCodecFrame associated with that buffer - * 4. for each buffer in the frame - * 4.1 (step 2): wait for that buffer to be ready from nvenc (LockBitsream) - * 4.2 create an output GstBuffer from the nvenc buffers - * 4.3 unlock the nvenc bitstream buffers UnlockBitsream - * 5. finish_frame() - * 6. cleanup - */ - do { - GstBuffer *buffer = NULL; - GstNvEncFrameState *state_in_queue = NULL; - GstNvEncFrameState *state = NULL; - GstVideoCodecFrame *frame = NULL; - NVENCSTATUS nv_ret; - NV_ENC_LOCK_BITSTREAM lock_bs = { 0, }; - NV_ENC_OUTPUT_PTR out_buf; - GstNvEncInputResource *resource; - - GST_LOG_OBJECT (enc, "wait for bitstream buffer.."); - - state_in_queue = g_async_queue_pop (nvenc->bitstream_queue); - if ((gpointer) state_in_queue == SHUTDOWN_COOKIE) - goto exit_thread; - - out_buf = state_in_queue->out_buf; - resource = state_in_queue->in_buf; - - GST_LOG_OBJECT (nvenc, "waiting for output buffer %p to be ready", out_buf); - - lock_bs.version = gst_nvenc_get_lock_bitstream_version (); - lock_bs.outputBitstream = out_buf; - lock_bs.doNotWait = 0; - - /* FIXME: this would need to be updated for other slice modes */ - lock_bs.sliceOffsets = NULL; - - if (!gst_cuda_context_push (nvenc->cuda_ctx)) { - GST_ELEMENT_ERROR (nvenc, LIBRARY, ENCODE, (NULL), - ("Failed to push current context")); - goto error_shutdown; - } - - nv_ret = NvEncLockBitstream (nvenc->encoder, &lock_bs); - if (nv_ret != NV_ENC_SUCCESS) { - gst_cuda_context_pop (NULL); - - GST_ELEMENT_ERROR (nvenc, STREAM, ENCODE, (NULL), - ("Failed to lock bitstream buffer %p, ret %d", - lock_bs.outputBitstream, nv_ret)); - goto error_shutdown; - } - - frame = _find_frame_with_output_buffer (nvenc, out_buf); - state = gst_video_codec_frame_get_user_data (frame); - g_assert (state->out_buf == out_buf); - - /* copy into output buffer */ - buffer = gst_buffer_new_allocate (NULL, lock_bs.bitstreamSizeInBytes, NULL); - gst_buffer_fill (buffer, 0, lock_bs.bitstreamBufferPtr, - lock_bs.bitstreamSizeInBytes); - - if (lock_bs.pictureType == NV_ENC_PIC_TYPE_IDR) { - GST_DEBUG_OBJECT (nvenc, "This is a keyframe"); - GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame); - } - - nv_ret = NvEncUnlockBitstream (nvenc->encoder, state->out_buf); - - if (nv_ret != NV_ENC_SUCCESS) { - gst_cuda_context_pop (NULL); - - GST_ELEMENT_ERROR (nvenc, STREAM, ENCODE, (NULL), - ("Failed to unlock bitstream buffer %p, ret %d", - lock_bs.outputBitstream, nv_ret)); - gst_buffer_unref (buffer); - gst_video_encoder_finish_frame (enc, frame); - - goto error_shutdown; - } - - frame->dts = frame->pts; - frame->pts = lock_bs.outputTimeStamp; - frame->duration = lock_bs.outputDuration; - - GST_LOG_OBJECT (nvenc, "frame index %" G_GUINT32_FORMAT - ", frame type %s, dts %" GST_TIME_FORMAT - ", pts %" GST_TIME_FORMAT, - lock_bs.frameIdx, picture_type_to_string (lock_bs.pictureType), - GST_TIME_ARGS (frame->dts), GST_TIME_ARGS (frame->pts)); - - frame->output_buffer = buffer; - - nv_ret = - NvEncUnmapInputResource (nvenc->encoder, - resource->nv_mapped_resource.mappedResource); - resource->mapped = FALSE; - - if (nv_ret != NV_ENC_SUCCESS) { - GST_ERROR_OBJECT (nvenc, "Failed to unmap input resource %p, ret %d", - resource, nv_ret); - } - - gst_cuda_context_pop (NULL); - - memset (&resource->nv_mapped_resource, 0, - sizeof (resource->nv_mapped_resource)); - - g_async_queue_push (nvenc->available_queue, state_in_queue); - - /* Ugly but no other way to get DTS offset since nvenc dose not adjust - * dts/pts even if bframe was enabled. So the output PTS can be smaller - * than DTS. The maximum difference between DTS and PTS can be calculated - * using the PTS difference between the first frame and the second frame. - */ - if (nvenc->bframes > 0) { - if (nvenc->dts_offset == 0) { - if (!nvenc->first_frame) { - /* store the first frame to get dts offset */ - nvenc->first_frame = frame; - continue; - } else { - if (nvenc->first_frame->pts >= frame->pts) { - GstClockTime duration = 0; - - GST_WARNING_OBJECT (enc, "Could not calculate DTS offset"); - - if (nvenc->input_info.fps_n > 0 && nvenc->input_info.fps_d > 0) { - duration = - gst_util_uint64_scale (GST_SECOND, nvenc->input_info.fps_d, - nvenc->input_info.fps_n); - } else if (nvenc->first_frame->duration > 0 && - GST_CLOCK_TIME_IS_VALID (nvenc->first_frame->duration)) { - duration = nvenc->first_frame->duration; - } else { - GST_WARNING_OBJECT (enc, - "No way to get frame duration, assuming 30fps"); - duration = gst_util_uint64_scale (GST_SECOND, 1, 30); - } - - nvenc->dts_offset = duration * nvenc->bframes; - } else { - nvenc->dts_offset = frame->pts - nvenc->first_frame->pts; - } - - /* + 1 to dts_offset to adjust fraction */ - nvenc->dts_offset++; - - GST_DEBUG_OBJECT (enc, - "Calculated DTS offset %" GST_TIME_FORMAT, - GST_TIME_ARGS (nvenc->dts_offset)); - } - - nvenc->first_frame->dts -= nvenc->dts_offset; - gst_video_encoder_finish_frame (enc, nvenc->first_frame); - nvenc->first_frame = NULL; - } - - frame->dts -= nvenc->dts_offset; - } - - flow = gst_video_encoder_finish_frame (enc, frame); - - if (flow != GST_FLOW_OK) { - GST_INFO_OBJECT (enc, "got flow %s", gst_flow_get_name (flow)); - g_atomic_int_set (&nvenc->last_flow, flow); - g_async_queue_push (nvenc->available_queue, SHUTDOWN_COOKIE); - goto exit_thread; - } - } - while (TRUE); - -error_shutdown: - { - if (nvenc->first_frame) { - gst_clear_buffer (&nvenc->first_frame->output_buffer); - gst_video_encoder_finish_frame (enc, nvenc->first_frame); - nvenc->first_frame = NULL; - } - g_atomic_int_set (&nvenc->last_flow, GST_FLOW_ERROR); - g_async_queue_push (nvenc->available_queue, SHUTDOWN_COOKIE); - - goto exit_thread; - } - -exit_thread: - { - if (nvenc->first_frame) { - gst_video_encoder_finish_frame (enc, nvenc->first_frame); - nvenc->first_frame = NULL; - } - - GST_INFO_OBJECT (nvenc, "exiting thread"); - - return NULL; - } -} - -static gboolean -gst_nv_base_enc_start_bitstream_thread (GstNvBaseEnc * nvenc) -{ - gchar *name = g_strdup_printf ("%s-read-bits", GST_OBJECT_NAME (nvenc)); - - g_assert (nvenc->bitstream_thread == NULL); - - g_assert (g_async_queue_length (nvenc->bitstream_queue) == 0); - - nvenc->bitstream_thread = - g_thread_try_new (name, gst_nv_base_enc_bitstream_thread, nvenc, NULL); - - g_free (name); - - if (nvenc->bitstream_thread == NULL) - return FALSE; - - GST_INFO_OBJECT (nvenc, "started thread to read bitstream"); - return TRUE; -} - -static gboolean -gst_nv_base_enc_stop_bitstream_thread (GstNvBaseEnc * nvenc, gboolean force) -{ - GstNvEncFrameState *state; - - if (nvenc->bitstream_thread == NULL) - return TRUE; - - /* Always send EOS packet to flush GPU. Otherwise, randomly crash happens - * during NvEncDestroyEncoder especially when rc-lookahead or bframe was - * enabled */ - gst_nv_base_enc_drain_encoder (nvenc); - - if (force) { - g_async_queue_lock (nvenc->available_queue); - g_async_queue_lock (nvenc->pending_queue); - g_async_queue_lock (nvenc->bitstream_queue); - while ((state = g_async_queue_try_pop_unlocked (nvenc->bitstream_queue))) { - GST_INFO_OBJECT (nvenc, "stole bitstream buffer %p from queue", state); - g_async_queue_push_unlocked (nvenc->available_queue, state); - } - g_async_queue_push_unlocked (nvenc->bitstream_queue, SHUTDOWN_COOKIE); - g_async_queue_unlock (nvenc->available_queue); - g_async_queue_unlock (nvenc->pending_queue); - g_async_queue_unlock (nvenc->bitstream_queue); - } else { - /* wait for encoder to drain the remaining buffers */ - g_async_queue_push (nvenc->bitstream_queue, SHUTDOWN_COOKIE); - } - - if (!force) { - /* temporary unlock during finish, so other thread can find and push frame */ - GST_VIDEO_ENCODER_STREAM_UNLOCK (nvenc); - } - - g_thread_join (nvenc->bitstream_thread); - - if (!force) - GST_VIDEO_ENCODER_STREAM_LOCK (nvenc); - - nvenc->bitstream_thread = NULL; - return TRUE; -} - -static void -gst_nv_base_enc_reset_queues (GstNvBaseEnc * nvenc) -{ - gpointer ptr; - - GST_INFO_OBJECT (nvenc, "clearing queues"); - - while ((ptr = g_async_queue_try_pop (nvenc->available_queue))) { - /* do nothing */ - } - while ((ptr = g_async_queue_try_pop (nvenc->pending_queue))) { - /* do nothing */ - } - while ((ptr = g_async_queue_try_pop (nvenc->bitstream_queue))) { - /* do nothing */ - } -} - -static void -gst_nv_base_enc_free_buffers (GstNvBaseEnc * nvenc) -{ - NVENCSTATUS nv_ret; - CUresult cuda_ret; - guint i; - - if (nvenc->encoder == NULL) - return; - - gst_nv_base_enc_reset_queues (nvenc); - - if (!nvenc->items || !nvenc->items->len) - return; - - gst_cuda_context_push (nvenc->cuda_ctx); - for (i = 0; i < nvenc->items->len; ++i) { - NV_ENC_OUTPUT_PTR out_buf = - g_array_index (nvenc->items, GstNvEncFrameState, i).out_buf; - GstNvEncInputResource *in_buf = - g_array_index (nvenc->items, GstNvEncFrameState, i).in_buf; - - if (in_buf->mapped) { - GST_LOG_OBJECT (nvenc, "Unmap resource %p", in_buf); - - nv_ret = - NvEncUnmapInputResource (nvenc->encoder, - in_buf->nv_mapped_resource.mappedResource); - - if (nv_ret != NV_ENC_SUCCESS) { - GST_ERROR_OBJECT (nvenc, "Failed to unmap input resource %p, ret %d", - in_buf, nv_ret); - } - } - - nv_ret = - NvEncUnregisterResource (nvenc->encoder, - in_buf->nv_resource.registeredResource); - if (nv_ret != NV_ENC_SUCCESS) - GST_ERROR_OBJECT (nvenc, "Failed to unregister resource %p, ret %d", - in_buf, nv_ret); - - cuda_ret = CuMemFree (in_buf->cuda_pointer); - if (!gst_cuda_result (cuda_ret)) { - GST_ERROR_OBJECT (nvenc, "Failed to free CUDA device memory, ret %d", - cuda_ret); - } - - g_free (in_buf); - - GST_DEBUG_OBJECT (nvenc, "Destroying output bitstream buffer %p", out_buf); - nv_ret = NvEncDestroyBitstreamBuffer (nvenc->encoder, out_buf); - if (nv_ret != NV_ENC_SUCCESS) { - GST_ERROR_OBJECT (nvenc, "Failed to destroy output buffer %p, ret %d", - out_buf, nv_ret); - } - } - gst_cuda_context_pop (NULL); - g_array_set_size (nvenc->items, 0); -} - -static inline guint -_get_plane_width (GstVideoInfo * info, guint plane) -{ - return GST_VIDEO_INFO_COMP_WIDTH (info, plane) - * GST_VIDEO_INFO_COMP_PSTRIDE (info, plane); -} - -static inline guint -_get_plane_height (GstVideoInfo * info, guint plane) -{ - if (GST_VIDEO_INFO_IS_YUV (info)) - /* For now component width and plane width are the same and the - * plane-component mapping matches - */ - return GST_VIDEO_INFO_COMP_HEIGHT (info, plane); - else /* RGB, GRAY */ - return GST_VIDEO_INFO_HEIGHT (info); -} - -static inline gsize -_get_frame_data_height (GstVideoInfo * info) -{ - gsize ret = 0; - gint i; - - for (i = 0; i < GST_VIDEO_INFO_N_PLANES (info); i++) { - ret += _get_plane_height (info, i); - } - - return ret; -} - -static gboolean -qp_has_values (const GstNvEncQP * qp) -{ - return qp->qp_i >= 0 && qp->qp_p >= 0 && qp->qp_b >= 0; -} - -static void -gst_nv_base_enc_setup_rate_control (GstNvBaseEnc * nvenc, - NV_ENC_RC_PARAMS * rc_params) -{ - GstNvRCMode rc_mode = nvenc->rate_control_mode; - NV_ENC_PARAMS_RC_MODE nv_rcmode; - - if (nvenc->bitrate) - rc_params->averageBitRate = nvenc->bitrate * 1024; - - if (nvenc->max_bitrate) - rc_params->maxBitRate = nvenc->max_bitrate * 1024; - - if (nvenc->vbv_buffersize) - rc_params->vbvBufferSize = nvenc->vbv_buffersize * 1024; - - /* Guess the best matching mode */ - if (rc_mode == GST_NV_RC_MODE_DEFAULT) { - if (nvenc->qp_const >= 0) { - /* constQP is used only for RC_CONSTQP mode */ - rc_mode = GST_NV_RC_MODE_CONSTQP; - } - } - - if (nvenc->qp_min >= 0) { - rc_params->enableMinQP = 1; - rc_params->minQP.qpInterB = nvenc->qp_min; - rc_params->minQP.qpInterP = nvenc->qp_min; - rc_params->minQP.qpIntra = nvenc->qp_min; - } else if (qp_has_values (&nvenc->qp_min_detail)) { - rc_params->enableMinQP = 1; - rc_params->minQP.qpInterB = nvenc->qp_min_detail.qp_b; - rc_params->minQP.qpInterP = nvenc->qp_min_detail.qp_p; - rc_params->minQP.qpIntra = nvenc->qp_min_detail.qp_i; - } - - if (nvenc->qp_max >= 0) { - rc_params->enableMaxQP = 1; - rc_params->maxQP.qpInterB = nvenc->qp_max; - rc_params->maxQP.qpInterP = nvenc->qp_max; - rc_params->maxQP.qpIntra = nvenc->qp_max; - } else if (qp_has_values (&nvenc->qp_max_detail)) { - rc_params->enableMaxQP = 1; - rc_params->maxQP.qpInterB = nvenc->qp_max_detail.qp_b; - rc_params->maxQP.qpInterP = nvenc->qp_max_detail.qp_p; - rc_params->maxQP.qpIntra = nvenc->qp_max_detail.qp_i; - } - - if (nvenc->qp_const >= 0) { - rc_params->constQP.qpInterB = nvenc->qp_const; - rc_params->constQP.qpInterP = nvenc->qp_const; - rc_params->constQP.qpIntra = nvenc->qp_const; - } else if (qp_has_values (&nvenc->qp_const_detail)) { - rc_params->constQP.qpInterB = nvenc->qp_const_detail.qp_b; - rc_params->constQP.qpInterP = nvenc->qp_const_detail.qp_p; - rc_params->constQP.qpIntra = nvenc->qp_const_detail.qp_i; - } - - nv_rcmode = _rc_mode_to_nv (rc_mode); - if (nv_rcmode == NV_ENC_PARAMS_RC_VBR_MINQP && nvenc->qp_min < 0) { - GST_WARNING_OBJECT (nvenc, "vbr-minqp was requested without qp-min"); - nv_rcmode = NV_ENC_PARAMS_RC_VBR; - } - - rc_params->rateControlMode = nv_rcmode; - - if (nvenc->spatial_aq) { - rc_params->enableAQ = 1; - rc_params->aqStrength = nvenc->aq_strength; - } - - rc_params->enableTemporalAQ = nvenc->temporal_aq; - - if (nvenc->rc_lookahead) { - rc_params->enableLookahead = 1; - rc_params->lookaheadDepth = nvenc->rc_lookahead; - rc_params->disableIadapt = !nvenc->i_adapt; - rc_params->disableBadapt = !nvenc->b_adapt; - } - - rc_params->strictGOPTarget = nvenc->strict_gop; - rc_params->enableNonRefP = nvenc->non_refp; - rc_params->zeroReorderDelay = nvenc->zerolatency; - - if (nvenc->const_quality) { - guint scaled = (gint) (nvenc->const_quality * 256.0); - - rc_params->targetQuality = (guint8) (scaled >> 8); - rc_params->targetQualityLSB = (guint8) (scaled & 0xff); - } -} - -static guint -gst_nv_base_enc_calculate_num_prealloc_buffers (GstNvBaseEnc * enc, - NV_ENC_CONFIG * config) -{ - guint num_buffers; - - /* At least 4 surfaces are required as documented by Nvidia Encoder guide */ - num_buffers = 4; - - /* + lookahead depth */ - num_buffers += config->rcParams.lookaheadDepth; - - /* + GOP size */ - num_buffers += config->frameIntervalP; - - /* hardcoded upper bound "48" - * The worst case - * default num buffers: 4 - * maximum allowed lookahead: 32 - * max bfraems: 4 -> frameIntervalP: 5 - * "4 + 32 + 5" < "48" so it seems to sufficiently safe upper bound */ - num_buffers = MIN (num_buffers, 48); - - GST_DEBUG_OBJECT (enc, "Calculated num buffers: %d " - "(lookahead %d, frameIntervalP %d)", - num_buffers, config->rcParams.lookaheadDepth, config->frameIntervalP); - - return num_buffers; -} - -/* GstVideoEncoder::set_format or by nvenc self if new properties were set. - * - * NvEncReconfigureEncoder with following conditions are not allowed - * 1) GOP structure change - * 2) sync-Async mode change (Async mode is Windows only and we didn't support it) - * 3) MaxWidth, MaxHeight - * 4) PTDmode (Picture Type Decision mode) - * - * So we will force to re-init the encode session if - * 1) New resolution is larger than previous config - * 2) GOP size changed - * 3) Input pixel format change - * pre-allocated CUDA memory could not ensure stride, width and height - * - * TODO: bframe also considered as force re-init case - */ -static gboolean -gst_nv_base_enc_set_format (GstVideoEncoder * enc, GstVideoCodecState * state) -{ - GstNvBaseEncClass *nvenc_class = GST_NV_BASE_ENC_GET_CLASS (enc); - GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (enc); - GstVideoInfo *info = &state->info; - GstVideoCodecState *old_state = nvenc->input_state; - NV_ENC_RECONFIGURE_PARAMS reconfigure_params = { 0, }; - NV_ENC_INITIALIZE_PARAMS *params = &nvenc->init_params; - NV_ENC_PRESET_CONFIG preset_config = { 0, }; - NVENCSTATUS nv_ret; - gint dar_n, dar_d; - gboolean reconfigure = FALSE; - - g_atomic_int_set (&nvenc->reconfig, FALSE); - - if (!nvenc->encoder && !gst_nv_base_enc_open_encode_session (nvenc)) { - GST_ELEMENT_ERROR (nvenc, LIBRARY, INIT, (NULL), - ("Failed to open encode session")); - return FALSE; - } - - if (old_state) { - gboolean larger_resolution; - gboolean format_changed; - gboolean gop_size_changed; - - larger_resolution = - (GST_VIDEO_INFO_WIDTH (info) > nvenc->init_params.maxEncodeWidth || - GST_VIDEO_INFO_HEIGHT (info) > nvenc->init_params.maxEncodeHeight); - format_changed = - GST_VIDEO_INFO_FORMAT (info) != - GST_VIDEO_INFO_FORMAT (&old_state->info); - - if (nvenc->config.gopLength == NVENC_INFINITE_GOPLENGTH - && nvenc->gop_size == -1) { - gop_size_changed = FALSE; - } else if (nvenc->config.gopLength != nvenc->gop_size) { - gop_size_changed = TRUE; - } else { - gop_size_changed = FALSE; - } - - if (larger_resolution || format_changed || gop_size_changed) { - GST_DEBUG_OBJECT (nvenc, - "resolution %dx%d -> %dx%d, format %s -> %s, re-init", - nvenc->init_params.maxEncodeWidth, nvenc->init_params.maxEncodeHeight, - GST_VIDEO_INFO_WIDTH (info), GST_VIDEO_INFO_HEIGHT (info), - gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (&old_state->info)), - gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (info))); - - gst_nv_base_enc_drain_encoder (nvenc); - gst_nv_base_enc_stop_bitstream_thread (nvenc, FALSE); - gst_nv_base_enc_free_buffers (nvenc); - NvEncDestroyEncoder (nvenc->encoder); - nvenc->encoder = NULL; - - if (!gst_nv_base_enc_open_encode_session (nvenc)) { - GST_ERROR_OBJECT (nvenc, "Failed to open encode session"); - return FALSE; - } - } else { - reconfigure_params.version = gst_nvenc_get_reconfigure_params_version (); - /* reset rate control state and start from IDR */ - reconfigure_params.resetEncoder = TRUE; - reconfigure_params.forceIDR = TRUE; - reconfigure = TRUE; - } - } - - params->version = gst_nvenc_get_initialize_params_version (); - params->encodeGUID = nvenc_class->codec_id; - params->encodeWidth = GST_VIDEO_INFO_WIDTH (info); - params->encodeHeight = GST_VIDEO_INFO_HEIGHT (info); - - { - guint32 n_presets; - GUID *presets; - guint32 i; - - nv_ret = - NvEncGetEncodePresetCount (nvenc->encoder, - params->encodeGUID, &n_presets); - if (nv_ret != NV_ENC_SUCCESS) { - GST_ELEMENT_ERROR (nvenc, LIBRARY, SETTINGS, (NULL), - ("Failed to get encoder presets")); - return FALSE; - } - - presets = g_new0 (GUID, n_presets); - nv_ret = - NvEncGetEncodePresetGUIDs (nvenc->encoder, - params->encodeGUID, presets, n_presets, &n_presets); - if (nv_ret != NV_ENC_SUCCESS) { - GST_ELEMENT_ERROR (nvenc, LIBRARY, SETTINGS, (NULL), - ("Failed to get encoder presets")); - g_free (presets); - return FALSE; - } - - for (i = 0; i < n_presets; i++) { - if (gst_nvenc_cmp_guid (presets[i], nvenc->selected_preset)) - break; - } - g_free (presets); - if (i >= n_presets) { - GST_ELEMENT_ERROR (nvenc, LIBRARY, SETTINGS, (NULL), - ("Selected preset not supported")); - return FALSE; - } - - params->presetGUID = nvenc->selected_preset; - } - - params->enablePTD = 1; - if (!reconfigure) { - /* this sets the required buffer size and the maximum allowed size on - * subsequent reconfigures */ - params->maxEncodeWidth = GST_VIDEO_INFO_WIDTH (info); - params->maxEncodeHeight = GST_VIDEO_INFO_HEIGHT (info); - } - - preset_config.version = gst_nvenc_get_preset_config_version (); - preset_config.presetCfg.version = gst_nvenc_get_config_version (); - - nv_ret = - NvEncGetEncodePresetConfig (nvenc->encoder, - params->encodeGUID, params->presetGUID, &preset_config); - if (nv_ret != NV_ENC_SUCCESS) { - GST_ELEMENT_ERROR (nvenc, LIBRARY, SETTINGS, (NULL), - ("Failed to get encode preset configuration: %d", nv_ret)); - return FALSE; - } - - params->encodeConfig = &preset_config.presetCfg; - - if (GST_VIDEO_INFO_IS_INTERLACED (info)) { - if (GST_VIDEO_INFO_INTERLACE_MODE (info) == - GST_VIDEO_INTERLACE_MODE_INTERLEAVED - || GST_VIDEO_INFO_INTERLACE_MODE (info) == - GST_VIDEO_INTERLACE_MODE_MIXED) { - preset_config.presetCfg.frameFieldMode = - NV_ENC_PARAMS_FRAME_FIELD_MODE_FIELD; - } - } - - if (info->fps_d > 0 && info->fps_n > 0) { - params->frameRateNum = info->fps_n; - params->frameRateDen = info->fps_d; - } else { - params->frameRateNum = 0; - params->frameRateDen = 1; - } - - if (gst_util_fraction_multiply (GST_VIDEO_INFO_WIDTH (info), - GST_VIDEO_INFO_HEIGHT (info), GST_VIDEO_INFO_PAR_N (info), - GST_VIDEO_INFO_PAR_D (info), &dar_n, &dar_d) && dar_n > 0 - && dar_d > 0) { - params->darWidth = dar_n; - params->darHeight = dar_d; - } - - gst_nv_base_enc_setup_rate_control (nvenc, ¶ms->encodeConfig->rcParams); - - params->enableWeightedPrediction = nvenc->weighted_pred; - - if (nvenc->gop_size < 0) { - params->encodeConfig->gopLength = NVENC_INFINITE_GOPLENGTH; - params->encodeConfig->frameIntervalP = 1; - } else if (nvenc->gop_size > 0) { - params->encodeConfig->gopLength = nvenc->gop_size; - /* frameIntervalP - * 0: All Intra frames - * 1: I/P only - * n ( > 1): n - 1 bframes - */ - params->encodeConfig->frameIntervalP = nvenc->bframes + 1; - } else { - /* gop size == 0 means all intra frames */ - params->encodeConfig->gopLength = 1; - params->encodeConfig->frameIntervalP = 0; - } - - g_assert (nvenc_class->set_encoder_config); - if (!nvenc_class->set_encoder_config (nvenc, state, params->encodeConfig)) { - GST_ERROR_OBJECT (enc, "Subclass failed to set encoder configuration"); - return FALSE; - } - - /* store the last config to reconfig/re-init decision in the next time */ - nvenc->config = *params->encodeConfig; - - G_LOCK (initialization_lock); - if (reconfigure) { - reconfigure_params.reInitEncodeParams = nvenc->init_params; - nv_ret = NvEncReconfigureEncoder (nvenc->encoder, &reconfigure_params); - } else { - nv_ret = NvEncInitializeEncoder (nvenc->encoder, params); - } - G_UNLOCK (initialization_lock); - - if (nv_ret != NV_ENC_SUCCESS) { - GST_ELEMENT_ERROR (nvenc, LIBRARY, SETTINGS, (NULL), - ("Failed to %sinit encoder: %d- %s", reconfigure ? "re" : "", nv_ret, - NvEncGetLastErrorString (nvenc->encoder))); - NvEncDestroyEncoder (nvenc->encoder); - nvenc->encoder = NULL; - return FALSE; - } - - if (!reconfigure) { - nvenc->input_info = *info; - } - - if (nvenc->input_state) - gst_video_codec_state_unref (nvenc->input_state); - nvenc->input_state = gst_video_codec_state_ref (state); - GST_INFO_OBJECT (nvenc, "%sconfigured encoder", reconfigure ? "re" : ""); - - /* now allocate some buffers only on first configuration */ - if (!reconfigure) { - GstCapsFeatures *features; - guint i; - guint input_width, input_height; - guint n_bufs; - - input_width = GST_VIDEO_INFO_WIDTH (info); - input_height = GST_VIDEO_INFO_HEIGHT (info); - - n_bufs = - gst_nv_base_enc_calculate_num_prealloc_buffers (nvenc, - params->encodeConfig); - - /* input buffers */ - g_array_set_size (nvenc->items, n_bufs); - - nvenc->mem_type = GST_NVENC_MEM_TYPE_SYSTEM; - - features = gst_caps_get_features (state->caps, 0); - if (gst_caps_features_contains (features, - GST_CAPS_FEATURE_MEMORY_CUDA_MEMORY)) { - nvenc->mem_type = GST_NVENC_MEM_TYPE_CUDA; - } -#ifdef HAVE_CUDA_GST_GL - else if (gst_caps_features_contains (features, - GST_CAPS_FEATURE_MEMORY_GL_MEMORY)) { - nvenc->mem_type = GST_NVENC_MEM_TYPE_GL; - } -#endif - - gst_cuda_context_push (nvenc->cuda_ctx); - for (i = 0; i < nvenc->items->len; ++i) { - GstNvEncInputResource *resource = g_new0 (GstNvEncInputResource, 1); - CUresult cu_ret; - - memset (&resource->nv_resource, 0, sizeof (resource->nv_resource)); - memset (&resource->nv_mapped_resource, 0, - sizeof (resource->nv_mapped_resource)); - - /* scratch buffer for non-contiguous planer into a contiguous buffer */ - cu_ret = - CuMemAllocPitch (&resource->cuda_pointer, - &resource->cuda_stride, _get_plane_width (info, 0), - _get_frame_data_height (info), 16); - if (!gst_cuda_result (cu_ret)) { - GST_ERROR_OBJECT (nvenc, "failed to allocate cuda scratch buffer " - "ret %d", cu_ret); - g_assert_not_reached (); - } - - resource->nv_resource.version = - gst_nvenc_get_register_resource_version (); - resource->nv_resource.resourceType = - NV_ENC_INPUT_RESOURCE_TYPE_CUDADEVICEPTR; - resource->nv_resource.width = input_width; - resource->nv_resource.height = input_height; - resource->nv_resource.pitch = resource->cuda_stride; - resource->nv_resource.bufferFormat = - gst_nvenc_get_nv_buffer_format (GST_VIDEO_INFO_FORMAT (info)); - resource->nv_resource.resourceToRegister = - (gpointer) resource->cuda_pointer; - - nv_ret = NvEncRegisterResource (nvenc->encoder, &resource->nv_resource); - if (nv_ret != NV_ENC_SUCCESS) - GST_ERROR_OBJECT (nvenc, "Failed to register resource %p, ret %d", - resource, nv_ret); - - g_array_index (nvenc->items, GstNvEncFrameState, i).in_buf = resource; - } - gst_cuda_context_pop (NULL); - - /* output buffers */ - for (i = 0; i < nvenc->items->len; ++i) { - NV_ENC_CREATE_BITSTREAM_BUFFER cout_buf = { 0, }; - - cout_buf.version = gst_nvenc_get_create_bitstream_buffer_version (); - - /* 1 MB should be large enough to hold most output frames. - * NVENC will automatically increase this if it's not enough. */ - cout_buf.size = 1024 * 1024; - cout_buf.memoryHeap = NV_ENC_MEMORY_HEAP_SYSMEM_CACHED; - - G_LOCK (initialization_lock); - nv_ret = NvEncCreateBitstreamBuffer (nvenc->encoder, &cout_buf); - G_UNLOCK (initialization_lock); - - if (nv_ret != NV_ENC_SUCCESS) { - GST_WARNING_OBJECT (enc, "Failed to allocate input buffer: %d", nv_ret); - /* FIXME: clean up */ - return FALSE; - } - - GST_INFO_OBJECT (nvenc, "allocated output buffer %2d: %p", i, - cout_buf.bitstreamBuffer); - - g_array_index (nvenc->items, GstNvEncFrameState, i).out_buf = - cout_buf.bitstreamBuffer; - - g_async_queue_push (nvenc->available_queue, &g_array_index (nvenc->items, - GstNvEncFrameState, i)); - } - -#if 0 - /* Get SPS/PPS */ - { - NV_ENC_SEQUENCE_PARAM_PAYLOAD seq_param = { 0 }; - uint32_t seq_size = 0; - - seq_param.version = gst_nvenc_get_sequence_param_payload_version (); - seq_param.spsppsBuffer = g_alloca (1024); - seq_param.inBufferSize = 1024; - seq_param.outSPSPPSPayloadSize = &seq_size; - - nv_ret = NvEncGetSequenceParams (nvenc->encoder, &seq_param); - if (nv_ret != NV_ENC_SUCCESS) { - GST_WARNING_OBJECT (enc, "Failed to retrieve SPS/PPS: %d", nv_ret); - return FALSE; - } - - /* FIXME: use SPS/PPS */ - GST_MEMDUMP_OBJECT (enc, "SPS/PPS", seq_param.spsppsBuffer, seq_size); - } -#endif - } - - g_assert (nvenc_class->set_src_caps); - if (!nvenc_class->set_src_caps (nvenc, state)) { - GST_ERROR_OBJECT (nvenc, "Subclass failed to set output caps"); - /* FIXME: clean up */ - return FALSE; - } - - return TRUE; -} - -static guint -_get_cuda_device_stride (GstVideoInfo * info, guint plane, gsize cuda_stride) -{ - switch (GST_VIDEO_INFO_FORMAT (info)) { - case GST_VIDEO_FORMAT_NV12: - case GST_VIDEO_FORMAT_NV21: - case GST_VIDEO_FORMAT_P010_10LE: - case GST_VIDEO_FORMAT_P010_10BE: - case GST_VIDEO_FORMAT_Y444: - case GST_VIDEO_FORMAT_BGRA: - case GST_VIDEO_FORMAT_RGBA: - case GST_VIDEO_FORMAT_BGR10A2_LE: - case GST_VIDEO_FORMAT_RGB10A2_LE: - case GST_VIDEO_FORMAT_Y444_16LE: - case GST_VIDEO_FORMAT_Y444_16BE: - case GST_VIDEO_FORMAT_VUYA: - return cuda_stride; - case GST_VIDEO_FORMAT_I420: - case GST_VIDEO_FORMAT_YV12: - return plane == 0 ? cuda_stride : (GST_ROUND_UP_2 (cuda_stride) / 2); - default: - g_assert_not_reached (); - return cuda_stride; - } -} - -#ifdef HAVE_CUDA_GST_GL -typedef struct _GstNvEncRegisterResourceData -{ - GstMemory *mem; - GstCudaGraphicsResource *resource; - GstNvBaseEnc *nvenc; - gboolean ret; -} GstNvEncRegisterResourceData; - -static void -register_cuda_resource (GstGLContext * context, - GstNvEncRegisterResourceData * data) -{ - GstMemory *mem = data->mem; - GstCudaGraphicsResource *resource = data->resource; - GstNvBaseEnc *nvenc = data->nvenc; - GstMapInfo map_info = GST_MAP_INFO_INIT; - GstGLBuffer *gl_buf_obj; - - data->ret = FALSE; - - if (!gst_cuda_context_push (nvenc->cuda_ctx)) { - GST_WARNING_OBJECT (nvenc, "failed to push CUDA context"); - return; - } - - if (gst_memory_map (mem, &map_info, GST_MAP_READ | GST_MAP_GL)) { - GstGLMemoryPBO *gl_mem = (GstGLMemoryPBO *) data->mem; - gl_buf_obj = gl_mem->pbo; - - GST_LOG_OBJECT (nvenc, - "register glbuffer %d to CUDA resource", gl_buf_obj->id); - - if (gst_cuda_graphics_resource_register_gl_buffer (resource, - gl_buf_obj->id, CU_GRAPHICS_REGISTER_FLAGS_NONE)) { - data->ret = TRUE; - } else { - GST_WARNING_OBJECT (nvenc, "failed to register memory"); - } - - gst_memory_unmap (mem, &map_info); - } else { - GST_WARNING_OBJECT (nvenc, "failed to map memory"); - } - - if (!gst_cuda_context_pop (NULL)) - GST_WARNING_OBJECT (nvenc, "failed to unlock CUDA context"); -} - -static GstCudaGraphicsResource * -ensure_cuda_graphics_resource (GstMemory * mem, GstNvBaseEnc * nvenc) -{ - GQuark quark; - GstCudaGraphicsResource *cgr_info; - GstNvEncRegisterResourceData data; - - if (!gst_is_gl_memory_pbo (mem)) { - GST_WARNING_OBJECT (nvenc, "memory is not GL PBO memory, %s", - mem->allocator->mem_type); - return NULL; - } - - quark = gst_cuda_quark_from_id (GST_CUDA_QUARK_GRAPHICS_RESOURCE); - - cgr_info = gst_mini_object_get_qdata (GST_MINI_OBJECT (mem), quark); - if (!cgr_info) { - cgr_info = gst_cuda_graphics_resource_new (nvenc->cuda_ctx, - GST_OBJECT (GST_GL_BASE_MEMORY_CAST (mem)->context), - GST_CUDA_GRAPHICS_RESOURCE_GL_BUFFER); - data.mem = mem; - data.resource = cgr_info; - data.nvenc = nvenc; - gst_gl_context_thread_add ((GstGLContext *) cgr_info->graphics_context, - (GstGLContextThreadFunc) register_cuda_resource, &data); - if (!data.ret) { - GST_WARNING_OBJECT (nvenc, "could not register resource"); - gst_cuda_graphics_resource_free (cgr_info); - - return NULL; - } - - gst_mini_object_set_qdata (GST_MINI_OBJECT (mem), quark, cgr_info, - (GDestroyNotify) gst_cuda_graphics_resource_free); - } - - return cgr_info; -} - -typedef struct _GstNvEncGLMapData -{ - GstNvBaseEnc *nvenc; - GstBuffer *buffer; - GstVideoInfo *info; - GstNvEncInputResource *resource; - - gboolean ret; -} GstNvEncGLMapData; - -static void -_map_gl_input_buffer (GstGLContext * context, GstNvEncGLMapData * data) -{ - GstNvBaseEnc *nvenc = data->nvenc; - CUresult cuda_ret; - CUdeviceptr data_pointer; - guint i; - CUDA_MEMCPY2D param; - GstCudaGraphicsResource **resources; - guint num_resources; - CUstream stream = gst_cuda_stream_get_handle (nvenc->stream); - - data->ret = FALSE; - - num_resources = gst_buffer_n_memory (data->buffer); - resources = g_newa (GstCudaGraphicsResource *, num_resources); - - for (i = 0; i < num_resources; i++) { - GstMemory *mem; - - mem = gst_buffer_peek_memory (data->buffer, i); - resources[i] = ensure_cuda_graphics_resource (mem, nvenc); - if (!resources[i]) { - GST_ERROR_OBJECT (nvenc, "could not register %dth memory", i); - return; - } - } - - gst_cuda_context_push (nvenc->cuda_ctx); - data_pointer = data->resource->cuda_pointer; - for (i = 0; i < GST_VIDEO_INFO_N_PLANES (data->info); i++) { - GstGLBuffer *gl_buf_obj; - GstGLMemoryPBO *gl_mem; - guint src_stride, dest_stride; - CUgraphicsResource cuda_resource; - gsize cuda_num_bytes; - CUdeviceptr cuda_plane_pointer; - - gl_mem = (GstGLMemoryPBO *) gst_buffer_peek_memory (data->buffer, i); - g_return_if_fail (gst_is_gl_memory_pbo ((GstMemory *) gl_mem)); - - gl_buf_obj = (GstGLBuffer *) gl_mem->pbo; - g_return_if_fail (gl_buf_obj != NULL); - - /* get the texture into the PBO */ - gst_gl_memory_pbo_upload_transfer (gl_mem); - gst_gl_memory_pbo_download_transfer (gl_mem); - - GST_LOG_OBJECT (nvenc, "attempting to copy texture %u into cuda", - gl_mem->mem.tex_id); - - cuda_resource = - gst_cuda_graphics_resource_map (resources[i], stream, - CU_GRAPHICS_MAP_RESOURCE_FLAGS_READ_ONLY); - - if (!cuda_resource) { - GST_ERROR_OBJECT (nvenc, "failed to map GL texture %u into cuda", - gl_mem->mem.tex_id); - g_assert_not_reached (); - } - - cuda_ret = - CuGraphicsResourceGetMappedPointer (&cuda_plane_pointer, - &cuda_num_bytes, cuda_resource); - - if (!gst_cuda_result (cuda_ret)) { - GST_ERROR_OBJECT (nvenc, "failed to get mapped pointer of map GL " - "texture %u in cuda ret :%d", gl_mem->mem.tex_id, cuda_ret); - g_assert_not_reached (); - } - - src_stride = GST_VIDEO_INFO_PLANE_STRIDE (data->info, i); - dest_stride = _get_cuda_device_stride (&nvenc->input_info, - i, data->resource->cuda_stride); - - /* copy into scratch buffer */ - param.srcXInBytes = 0; - param.srcY = 0; - param.srcMemoryType = CU_MEMORYTYPE_DEVICE; - param.srcDevice = cuda_plane_pointer; - param.srcPitch = src_stride; - - param.dstXInBytes = 0; - param.dstY = 0; - param.dstMemoryType = CU_MEMORYTYPE_DEVICE; - param.dstDevice = data_pointer; - param.dstPitch = dest_stride; - param.WidthInBytes = _get_plane_width (data->info, i); - param.Height = _get_plane_height (data->info, i); - - cuda_ret = CuMemcpy2DAsync (¶m, stream); - if (!gst_cuda_result (cuda_ret)) { - GST_ERROR_OBJECT (data->nvenc, "failed to copy GL texture %u into cuda " - "ret :%d", gl_mem->mem.tex_id, cuda_ret); - g_assert_not_reached (); - } - - gst_cuda_graphics_resource_unmap (resources[i], stream); - - data_pointer += dest_stride * _get_plane_height (&nvenc->input_info, i); - } - gst_cuda_result (CuStreamSynchronize (stream)); - gst_cuda_context_pop (NULL); - - data->ret = TRUE; -} -#endif - -static gboolean -gst_nv_base_enc_upload_frame (GstNvBaseEnc * nvenc, GstVideoFrame * frame, - GstNvEncInputResource * resource, gboolean use_device_memory, - GstCudaStream * stream) -{ - gint i; - CUdeviceptr dst = resource->cuda_pointer; - GstVideoInfo *info = &frame->info; - CUresult cuda_ret; - CUstream stream_handle = gst_cuda_stream_get_handle (stream); - - if (!gst_cuda_context_push (nvenc->cuda_ctx)) { - GST_ERROR_OBJECT (nvenc, "cannot push context"); - return FALSE; - } - - for (i = 0; i < GST_VIDEO_FRAME_N_PLANES (frame); i++) { - CUDA_MEMCPY2D param = { 0, }; - guint dest_stride = _get_cuda_device_stride (&nvenc->input_info, i, - resource->cuda_stride); - - if (use_device_memory) { - param.srcMemoryType = CU_MEMORYTYPE_DEVICE; - param.srcDevice = (CUdeviceptr) GST_VIDEO_FRAME_PLANE_DATA (frame, i); - } else { - param.srcMemoryType = CU_MEMORYTYPE_HOST; - param.srcHost = GST_VIDEO_FRAME_PLANE_DATA (frame, i); - } - param.srcPitch = GST_VIDEO_FRAME_PLANE_STRIDE (frame, i); - - param.dstMemoryType = CU_MEMORYTYPE_DEVICE; - param.dstDevice = dst; - param.dstPitch = dest_stride; - param.WidthInBytes = _get_plane_width (info, i); - param.Height = _get_plane_height (info, i); - - cuda_ret = CuMemcpy2DAsync (¶m, stream_handle); - if (!gst_cuda_result (cuda_ret)) { - GST_ERROR_OBJECT (nvenc, "cannot copy %dth plane, ret %d", i, cuda_ret); - gst_cuda_context_pop (NULL); - - return FALSE; - } - - dst += dest_stride * _get_plane_height (&nvenc->input_info, i); - } - - gst_cuda_result (CuStreamSynchronize (stream_handle)); - gst_cuda_context_pop (NULL); - - return TRUE; -} - -static GstFlowReturn -_acquire_input_buffer (GstNvBaseEnc * nvenc, GstNvEncFrameState ** input) -{ - GST_LOG_OBJECT (nvenc, "acquiring input buffer.."); - GST_VIDEO_ENCODER_STREAM_UNLOCK (nvenc); - *input = g_async_queue_pop (nvenc->available_queue); - GST_VIDEO_ENCODER_STREAM_LOCK (nvenc); - - if (*input == SHUTDOWN_COOKIE) - return g_atomic_int_get (&nvenc->last_flow); - - return GST_FLOW_OK; -} - -static GstFlowReturn -_submit_input_buffer (GstNvBaseEnc * nvenc, GstVideoCodecFrame * frame, - GstVideoFrame * vframe, GstNvEncFrameState * state, void *inputBufferPtr, - NV_ENC_BUFFER_FORMAT bufferFormat) -{ - GstNvBaseEncClass *nvenc_class = GST_NV_BASE_ENC_GET_CLASS (nvenc); - NV_ENC_PIC_PARAMS pic_params = { 0, }; - NVENCSTATUS nv_ret; - gpointer inputBuffer, outputBufferPtr; - - inputBuffer = state->in_buf; - outputBufferPtr = state->out_buf; - - GST_LOG_OBJECT (nvenc, "%u: input buffer %p, output buffer %p, " - "pts %" GST_TIME_FORMAT, frame->system_frame_number, inputBuffer, - outputBufferPtr, GST_TIME_ARGS (frame->pts)); - - pic_params.version = gst_nvenc_get_pic_params_version (); - pic_params.inputBuffer = inputBufferPtr; - pic_params.bufferFmt = bufferFormat; - - pic_params.inputWidth = GST_VIDEO_FRAME_WIDTH (vframe); - pic_params.inputHeight = GST_VIDEO_FRAME_HEIGHT (vframe); - pic_params.outputBitstream = outputBufferPtr; - pic_params.completionEvent = NULL; - if (GST_VIDEO_FRAME_IS_INTERLACED (vframe)) { - if (GST_VIDEO_FRAME_IS_TFF (vframe)) - pic_params.pictureStruct = NV_ENC_PIC_STRUCT_FIELD_TOP_BOTTOM; - else - pic_params.pictureStruct = NV_ENC_PIC_STRUCT_FIELD_BOTTOM_TOP; - } else { - pic_params.pictureStruct = NV_ENC_PIC_STRUCT_FRAME; - } - pic_params.inputTimeStamp = frame->pts; - pic_params.inputDuration = - GST_CLOCK_TIME_IS_VALID (frame->duration) ? frame->duration : 0; - pic_params.frameIdx = frame->system_frame_number; - - if (GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame)) - pic_params.encodePicFlags = NV_ENC_PIC_FLAG_FORCEIDR; - else - pic_params.encodePicFlags = 0; - - if (nvenc_class->set_pic_params - && !nvenc_class->set_pic_params (nvenc, frame, &pic_params)) { - GST_ERROR_OBJECT (nvenc, "Subclass failed to submit buffer"); - return GST_FLOW_ERROR; - } - - if (!gst_cuda_context_push (nvenc->cuda_ctx)) { - GST_ELEMENT_ERROR (nvenc, LIBRARY, ENCODE, (NULL), - ("Failed to push current context")); - return GST_FLOW_ERROR; - } - - nv_ret = NvEncEncodePicture (nvenc->encoder, &pic_params); - - gst_cuda_context_pop (NULL); - - if (nv_ret == NV_ENC_SUCCESS) { - GST_LOG_OBJECT (nvenc, "Encoded picture"); - } else if (nv_ret == NV_ENC_ERR_NEED_MORE_INPUT) { - GST_DEBUG_OBJECT (nvenc, "Encoded picture (encoder needs more input)"); - } else { - GST_ERROR_OBJECT (nvenc, "Failed to encode picture: %d", nv_ret); - g_async_queue_push (nvenc->available_queue, state); - - return GST_FLOW_ERROR; - } - - /* GstNvEncFrameState shouldn't be freed by DestroyNotify */ - gst_video_codec_frame_set_user_data (frame, state, NULL); - g_async_queue_push (nvenc->pending_queue, state); - - if (nv_ret == NV_ENC_SUCCESS) { - GstNvEncFrameState *pending_state; - gint len, i, end; - - /* HACK: NvEncEncodePicture() with returning NV_ENC_SUCCESS means that - * we can pop encoded bitstream from GPU - * (via NvEncLockBitstream and copy to memory then NvEncUnlockBitstream). - * But if we try to pop every buffer from GPU when the rc-lookahead - * was enabled, NvEncLockBitstream returns error NV_ENC_ERR_INVALID_PARAM - * randomly (seemingly it's dependent on how fast the encoding thread - * dequeued the encoded picture). - * So make "pending_queue" having the number of lookahead pictures always, - * so that GPU should be able to reference the lookahead pictures. - * - * This behavior is not documented by Nvidia. The guess here is that - * the lookahead pictures are still used for rate-control by Nvidia driver - * and dequeuing the lookahead picture from GPU seems to be causing the - * problem. - */ - end = nvenc->rc_lookahead; - - g_async_queue_lock (nvenc->pending_queue); - - len = g_async_queue_length_unlocked (nvenc->pending_queue); - for (i = len; i > end; i--) { - pending_state = g_async_queue_pop_unlocked (nvenc->pending_queue); - g_async_queue_push (nvenc->bitstream_queue, pending_state); - } - - g_async_queue_unlock (nvenc->pending_queue); - } - - return GST_FLOW_OK; -} - -static GstFlowReturn -gst_nv_base_enc_handle_frame (GstVideoEncoder * enc, GstVideoCodecFrame * frame) -{ - GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (enc); - NVENCSTATUS nv_ret; - GstVideoFrame vframe; - GstVideoInfo *info = &nvenc->input_state->info; - GstFlowReturn flow = GST_FLOW_OK; - GstMapFlags in_map_flags = GST_MAP_READ; - GstNvEncFrameState *state = NULL; - GstNvEncInputResource *resource = NULL; - gboolean use_device_memory = FALSE; - GstCudaStream *stream = nvenc->stream; - - g_assert (nvenc->encoder != NULL); - - /* check last flow and if it's not OK, just return the last flow, - * non-OK flow means that encoding thread was terminated */ - flow = g_atomic_int_get (&nvenc->last_flow); - if (flow != GST_FLOW_OK) { - GST_DEBUG_OBJECT (nvenc, "last flow was %s", gst_flow_get_name (flow)); - /* just drop this frame */ - gst_video_encoder_finish_frame (enc, frame); - - return flow; - } - - if (g_atomic_int_compare_and_exchange (&nvenc->reconfig, TRUE, FALSE)) { - if (!gst_nv_base_enc_set_format (enc, nvenc->input_state)) { - flow = GST_FLOW_NOT_NEGOTIATED; - goto drop; - } - - /* reconfigured encode session should start from keyframe */ - GST_VIDEO_CODEC_FRAME_SET_FORCE_KEYFRAME (frame); - } -#ifdef HAVE_CUDA_GST_GL - if (nvenc->mem_type == GST_NVENC_MEM_TYPE_GL) - in_map_flags |= GST_MAP_GL; -#endif - - if (nvenc->mem_type == GST_NVENC_MEM_TYPE_CUDA) { - GstMemory *mem; - - if ((mem = gst_buffer_peek_memory (frame->input_buffer, 0)) && - gst_is_cuda_memory (mem)) { - GstCudaMemory *cmem = GST_CUDA_MEMORY_CAST (mem); - - if (cmem->context == nvenc->cuda_ctx || - gst_cuda_context_get_handle (cmem->context) == - gst_cuda_context_get_handle (nvenc->cuda_ctx) || - (gst_cuda_context_can_access_peer (cmem->context, nvenc->cuda_ctx) && - gst_cuda_context_can_access_peer (nvenc->cuda_ctx, - cmem->context))) { - GstCudaStream *mem_stream; - - use_device_memory = TRUE; - in_map_flags |= GST_MAP_CUDA; - - mem_stream = gst_cuda_memory_get_stream (cmem); - if (mem_stream) - stream = mem_stream; - } - } - } - - if (!gst_video_frame_map (&vframe, info, frame->input_buffer, in_map_flags)) { - goto drop; - } - - /* make sure our thread that waits for output to be ready is started */ - if (nvenc->bitstream_thread == NULL) { - if (!gst_nv_base_enc_start_bitstream_thread (nvenc)) { - gst_video_frame_unmap (&vframe); - goto unmap_and_drop; - } - } - - flow = _acquire_input_buffer (nvenc, &state); - if (flow != GST_FLOW_OK || state == SHUTDOWN_COOKIE || !state) - goto unmap_and_drop; - - resource = state->in_buf; - -#ifdef HAVE_CUDA_GST_GL - if (nvenc->mem_type == GST_NVENC_MEM_TYPE_GL) { - GstGLMemory *gl_mem; - GstNvEncGLMapData data; - - gl_mem = (GstGLMemory *) gst_buffer_peek_memory (frame->input_buffer, 0); - g_assert (gst_is_gl_memory ((GstMemory *) gl_mem)); - - data.nvenc = nvenc; - data.buffer = frame->input_buffer; - data.info = &vframe.info; - data.resource = resource; - - gst_gl_context_thread_add (gl_mem->mem.context, - (GstGLContextThreadFunc) _map_gl_input_buffer, &data); - if (!data.ret) { - flow = GST_FLOW_ERROR; - goto unmap_and_drop; - } - } else -#endif - if (!gst_nv_base_enc_upload_frame (nvenc, - &vframe, resource, use_device_memory, stream)) { - flow = GST_FLOW_ERROR; - goto unmap_and_drop; - } - - resource->nv_mapped_resource.version = - gst_nvenc_get_map_input_resource_version (); - resource->nv_mapped_resource.registeredResource = - resource->nv_resource.registeredResource; - - if (!gst_cuda_context_push (nvenc->cuda_ctx)) { - GST_ELEMENT_ERROR (nvenc, LIBRARY, ENCODE, (NULL), - ("Failed to push current context")); - flow = GST_FLOW_ERROR; - goto unmap_and_drop; - } - - nv_ret = - NvEncMapInputResource (nvenc->encoder, &resource->nv_mapped_resource); - gst_cuda_context_pop (NULL); - - if (nv_ret != NV_ENC_SUCCESS) { - GST_ERROR_OBJECT (nvenc, "Failed to map input resource %p, ret %d", - resource, nv_ret); - flow = GST_FLOW_ERROR; - goto unmap_and_drop; - } - - resource->mapped = TRUE; - - flow = - _submit_input_buffer (nvenc, frame, &vframe, state, - resource->nv_mapped_resource.mappedResource, - resource->nv_mapped_resource.mappedBufferFmt); - - if (flow != GST_FLOW_OK) { - GST_DEBUG_OBJECT (nvenc, "return state to pool"); - g_async_queue_push (nvenc->available_queue, state); - goto unmap_and_drop; - } - - flow = g_atomic_int_get (&nvenc->last_flow); - - gst_video_frame_unmap (&vframe); - /* encoder will keep frame in list internally, we'll look it up again later - * in the thread where we get the output buffers and finish it there */ - gst_video_codec_frame_unref (frame); - - return flow; - -/* ERRORS */ -unmap_and_drop: - { - gst_video_frame_unmap (&vframe); - goto drop; - } -drop: - { - gst_video_encoder_finish_frame (enc, frame); - return flow; - } -} - -static gboolean -gst_nv_base_enc_drain_encoder (GstNvBaseEnc * nvenc) -{ - NV_ENC_PIC_PARAMS pic_params = { 0, }; - NVENCSTATUS nv_ret; - gboolean ret = TRUE; - - GST_INFO_OBJECT (nvenc, "draining encoder"); - - if (nvenc->input_state == NULL) { - GST_DEBUG_OBJECT (nvenc, "no input state, nothing to do"); - return TRUE; - } - - if (!nvenc->encoder) { - GST_DEBUG_OBJECT (nvenc, "no configured encode session"); - return TRUE; - } - - pic_params.version = gst_nvenc_get_pic_params_version (); - pic_params.encodePicFlags = NV_ENC_PIC_FLAG_EOS; - - if (!gst_cuda_context_push (nvenc->cuda_ctx)) { - GST_ERROR_OBJECT (nvenc, "Could not push context"); - return GST_FLOW_ERROR; - } - - nv_ret = NvEncEncodePicture (nvenc->encoder, &pic_params); - - if (nv_ret != NV_ENC_SUCCESS) { - GST_LOG_OBJECT (nvenc, "Failed to drain encoder, ret %d", nv_ret); - - ret = FALSE; - } else { - GstNvEncFrameState *pending_state; - - g_async_queue_lock (nvenc->pending_queue); - while ((pending_state = - g_async_queue_try_pop_unlocked (nvenc->pending_queue))) { - g_async_queue_push (nvenc->bitstream_queue, pending_state); - } - g_async_queue_unlock (nvenc->pending_queue); - } - - gst_cuda_context_pop (NULL); - - return ret; -} - -static GstFlowReturn -gst_nv_base_enc_finish (GstVideoEncoder * enc) -{ - GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (enc); - - gst_nv_base_enc_stop_bitstream_thread (nvenc, FALSE); - - return GST_FLOW_OK; -} - -#if 0 -static gboolean -gst_nv_base_enc_flush (GstVideoEncoder * enc) -{ - GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (enc); - GST_INFO_OBJECT (nvenc, "done flushing encoder"); - return TRUE; -} -#endif - -void -gst_nv_base_enc_schedule_reconfig (GstNvBaseEnc * nvenc) -{ - g_atomic_int_set (&nvenc->reconfig, TRUE); -} - -static void -gst_nv_base_enc_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (object); - GstNvBaseEncClass *klass = GST_NV_BASE_ENC_GET_CLASS (nvenc); - gboolean reconfig = TRUE; - - switch (prop_id) { - case PROP_PRESET: - nvenc->preset_enum = g_value_get_enum (value); - nvenc->selected_preset = _nv_preset_to_guid (nvenc->preset_enum); - gst_nv_base_enc_schedule_reconfig (nvenc); - break; - case PROP_RC_MODE: - { - GstNvRCMode rc_mode = g_value_get_enum (value); - NV_ENC_PARAMS_RC_MODE nv_rc_mode = _rc_mode_to_nv (rc_mode); - - if ((klass->device_caps.rc_modes & nv_rc_mode) == nv_rc_mode) { - nvenc->rate_control_mode = rc_mode; - } else { - GST_WARNING_OBJECT (nvenc, - "device does not support requested rate control mode %d", rc_mode); - reconfig = FALSE; - } - break; - } - case PROP_QP_MIN: - nvenc->qp_min = g_value_get_int (value); - break; - case PROP_QP_MAX: - nvenc->qp_max = g_value_get_int (value); - break; - case PROP_QP_CONST: - nvenc->qp_const = g_value_get_int (value); - break; - case PROP_BITRATE: - nvenc->bitrate = g_value_get_uint (value); - break; - case PROP_GOP_SIZE: - nvenc->gop_size = g_value_get_int (value); - break; - case PROP_MAX_BITRATE: - nvenc->max_bitrate = g_value_get_uint (value); - break; - case PROP_SPATIAL_AQ: - nvenc->spatial_aq = g_value_get_boolean (value); - break; - case PROP_AQ_STRENGTH: - nvenc->aq_strength = g_value_get_uint (value); - break; - case PROP_NON_REF_P: - nvenc->non_refp = g_value_get_boolean (value); - break; - case PROP_ZEROLATENCY: - nvenc->zerolatency = g_value_get_boolean (value); - break; - case PROP_STRICT_GOP: - nvenc->strict_gop = g_value_get_boolean (value); - break; - case PROP_CONST_QUALITY: - nvenc->const_quality = g_value_get_double (value); - break; - case PROP_I_ADAPT: - nvenc->i_adapt = g_value_get_boolean (value); - break; - case PROP_QP_MIN_I: - nvenc->qp_min_detail.qp_i = g_value_get_int (value); - break; - case PROP_QP_MIN_P: - nvenc->qp_min_detail.qp_p = g_value_get_int (value); - break; - case PROP_QP_MIN_B: - nvenc->qp_min_detail.qp_b = g_value_get_int (value); - break; - case PROP_QP_MAX_I: - nvenc->qp_max_detail.qp_i = g_value_get_int (value); - break; - case PROP_QP_MAX_P: - nvenc->qp_max_detail.qp_p = g_value_get_int (value); - break; - case PROP_QP_MAX_B: - nvenc->qp_max_detail.qp_b = g_value_get_int (value); - break; - case PROP_QP_CONST_I: - nvenc->qp_const_detail.qp_i = g_value_get_int (value); - break; - case PROP_QP_CONST_P: - nvenc->qp_const_detail.qp_p = g_value_get_int (value); - break; - case PROP_QP_CONST_B: - nvenc->qp_const_detail.qp_b = g_value_get_int (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - reconfig = FALSE; - break; - } - - if (reconfig) - gst_nv_base_enc_schedule_reconfig (nvenc); -} - -static void -gst_nv_base_enc_get_property (GObject * object, guint prop_id, GValue * value, - GParamSpec * pspec) -{ - GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (object); - GstNvBaseEncClass *nvenc_class = GST_NV_BASE_ENC_GET_CLASS (object); - - switch (prop_id) { - case PROP_DEVICE_ID: - g_value_set_uint (value, nvenc_class->cuda_device_id); - break; - case PROP_PRESET: - g_value_set_enum (value, nvenc->preset_enum); - break; - case PROP_RC_MODE: - g_value_set_enum (value, nvenc->rate_control_mode); - break; - case PROP_QP_MIN: - g_value_set_int (value, nvenc->qp_min); - break; - case PROP_QP_MAX: - g_value_set_int (value, nvenc->qp_max); - break; - case PROP_QP_CONST: - g_value_set_int (value, nvenc->qp_const); - break; - case PROP_BITRATE: - g_value_set_uint (value, nvenc->bitrate); - break; - case PROP_GOP_SIZE: - g_value_set_int (value, nvenc->gop_size); - break; - case PROP_MAX_BITRATE: - g_value_set_uint (value, nvenc->max_bitrate); - break; - case PROP_SPATIAL_AQ: - g_value_set_boolean (value, nvenc->spatial_aq); - break; - case PROP_AQ_STRENGTH: - g_value_set_uint (value, nvenc->aq_strength); - break; - case PROP_NON_REF_P: - g_value_set_boolean (value, nvenc->non_refp); - break; - case PROP_ZEROLATENCY: - g_value_set_boolean (value, nvenc->zerolatency); - break; - case PROP_STRICT_GOP: - g_value_set_boolean (value, nvenc->strict_gop); - break; - case PROP_CONST_QUALITY: - g_value_set_double (value, nvenc->const_quality); - break; - case PROP_I_ADAPT: - g_value_set_boolean (value, nvenc->i_adapt); - break; - case PROP_QP_MIN_I: - g_value_set_int (value, nvenc->qp_min_detail.qp_i); - break; - case PROP_QP_MIN_P: - g_value_set_int (value, nvenc->qp_min_detail.qp_p); - break; - case PROP_QP_MIN_B: - g_value_set_int (value, nvenc->qp_min_detail.qp_b); - break; - case PROP_QP_MAX_I: - g_value_set_int (value, nvenc->qp_max_detail.qp_i); - break; - case PROP_QP_MAX_P: - g_value_set_int (value, nvenc->qp_max_detail.qp_p); - break; - case PROP_QP_MAX_B: - g_value_set_int (value, nvenc->qp_max_detail.qp_b); - break; - case PROP_QP_CONST_I: - g_value_set_int (value, nvenc->qp_const_detail.qp_i); - break; - case PROP_QP_CONST_P: - g_value_set_int (value, nvenc->qp_const_detail.qp_p); - break; - case PROP_QP_CONST_B: - g_value_set_int (value, nvenc->qp_const_detail.qp_b); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -typedef struct -{ - guint cuda_device_id; - GstNvEncDeviceCaps device_caps; -} GstNvEncClassData; - -static void -gst_nv_base_enc_subclass_init (gpointer g_class, gpointer data) -{ - GstNvBaseEncClass *nvbaseenc_class = GST_NV_BASE_ENC_CLASS (g_class); - GstNvEncClassData *cdata = (GstNvEncClassData *) data; - - nvbaseenc_class->cuda_device_id = cdata->cuda_device_id; - nvbaseenc_class->device_caps = cdata->device_caps; - - g_free (cdata); -} - -GType -gst_nv_base_enc_register (const char *codec, guint device_id, - GstNvEncDeviceCaps * device_caps) -{ - GTypeQuery type_query; - GTypeInfo type_info = { 0, }; - GType subtype; - gchar *type_name; - GstNvEncClassData *cdata; - - type_name = g_strdup_printf ("GstNvDevice%d%sEnc", device_id, codec); - subtype = g_type_from_name (type_name); - - /* has already registered nvdeviceenc class */ - if (subtype) - goto done; - - cdata = g_new0 (GstNvEncClassData, 1); - cdata->cuda_device_id = device_id; - cdata->device_caps = *device_caps; - - g_type_query (GST_TYPE_NV_BASE_ENC, &type_query); - memset (&type_info, 0, sizeof (type_info)); - type_info.class_size = type_query.class_size; - type_info.instance_size = type_query.instance_size; - type_info.class_init = (GClassInitFunc) gst_nv_base_enc_subclass_init; - type_info.class_data = cdata; - - subtype = g_type_register_static (GST_TYPE_NV_BASE_ENC, - type_name, &type_info, 0); - - gst_type_mark_as_plugin_api (subtype, 0); - -done: - g_free (type_name); - return subtype; -} diff --git a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvbaseenc.h b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvbaseenc.h deleted file mode 100644 index dabc1d3542..0000000000 --- a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvbaseenc.h +++ /dev/null @@ -1,194 +0,0 @@ -/* GStreamer NVENC plugin - * Copyright (C) 2015 Centricular Ltd - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef __GST_NV_BASE_ENC_H_INCLUDED__ -#define __GST_NV_BASE_ENC_H_INCLUDED__ - -#include "gstnvenc.h" - -#include -#include - -#define GST_TYPE_NV_BASE_ENC \ - (gst_nv_base_enc_get_type()) -#define GST_NV_BASE_ENC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_NV_BASE_ENC,GstNvBaseEnc)) -#define GST_NV_BASE_ENC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_NV_BASE_ENC,GstNvBaseEncClass)) -#define GST_NV_BASE_ENC_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_NV_BASE_ENC,GstNvBaseEncClass)) -#define GST_IS_NV_BASE_ENC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_NV_BASE_ENC)) -#define GST_IS_NV_BASE_ENC_CLASS(obj) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_NV_BASE_ENC)) - -typedef enum { - GST_NV_PRESET_DEFAULT, - GST_NV_PRESET_HP, - GST_NV_PRESET_HQ, -/* FIXME: problematic GST_NV_PRESET_BD, */ - GST_NV_PRESET_LOW_LATENCY_DEFAULT, - GST_NV_PRESET_LOW_LATENCY_HQ, - GST_NV_PRESET_LOW_LATENCY_HP, - GST_NV_PRESET_LOSSLESS_DEFAULT, - GST_NV_PRESET_LOSSLESS_HP, -} GstNvPreset; - -typedef enum { - GST_NV_RC_MODE_DEFAULT, - GST_NV_RC_MODE_CONSTQP, - GST_NV_RC_MODE_CBR, - GST_NV_RC_MODE_VBR, - GST_NV_RC_MODE_VBR_MINQP, - GST_NV_RC_MODE_CBR_LOWDELAY_HQ, - GST_NV_RC_MODE_CBR_HQ, - GST_NV_RC_MODE_VBR_HQ, -} GstNvRCMode; - -typedef enum -{ - GST_NVENC_MEM_TYPE_SYSTEM = 0, - GST_NVENC_MEM_TYPE_GL, - GST_NVENC_MEM_TYPE_CUDA, - /* FIXME: add support D3D11 memory */ -} GstNvEncMemType; - -typedef struct { - gboolean weighted_prediction; - gint rc_modes; - gboolean custom_vbv_bufsize; - gboolean lookahead; - gboolean temporal_aq; - gint bframes; -} GstNvEncDeviceCaps; - -typedef struct { - gint qp_i; - gint qp_p; - gint qp_b; -} GstNvEncQP; - -typedef struct { - GstVideoEncoder video_encoder; - - /* properties */ - GstNvPreset preset_enum; - GUID selected_preset; - GstNvRCMode rate_control_mode; - gint qp_min; - GstNvEncQP qp_min_detail; - gint qp_max; - GstNvEncQP qp_max_detail; - gint qp_const; - GstNvEncQP qp_const_detail; - guint bitrate; - gint gop_size; - guint max_bitrate; - gboolean spatial_aq; - guint aq_strength; - gboolean non_refp; - /* zero reorder delay (consistent naming with x264) */ - gboolean zerolatency; - gboolean strict_gop; - gdouble const_quality; - gboolean i_adapt; - - GstCudaContext * cuda_ctx; - GstCudaStream * stream; - void * encoder; - NV_ENC_INITIALIZE_PARAMS init_params; - NV_ENC_CONFIG config; - - /* the supported input formats */ - GValue * input_formats; /* OBJECT LOCK */ - - GstVideoCodecState *input_state; - gint reconfig; /* ATOMIC */ - GstNvEncMemType mem_type; - - /* array of allocated input/output buffers (GstNvEncFrameState), - * and hold the ownership of the GstNvEncFrameState. */ - GArray *items; - - /* (GstNvEncFrameState) available empty items which could be submitted - * to encoder */ - GAsyncQueue *available_queue; - - /* (GstNvEncFrameState) submitted to encoder but not ready to finish - * (due to bframe or lookhead operation) */ - GAsyncQueue *pending_queue; - - /* (GstNvEncFrameState) submitted to encoder and ready to finish. - * finished items will go back to available item queue */ - GAsyncQueue *bitstream_queue; - - /* we spawn a thread that does the (blocking) waits for output buffers - * to become available, so we can continue to feed data to the encoder - * while we wait */ - GThread *bitstream_thread; - - GstObject *display; /* GstGLDisplay */ - GstObject *other_context; /* GstGLContext */ - GstObject *gl_context; /* GstGLContext */ - - GstVideoInfo input_info; /* buffer configuration for buffers sent to NVENC */ - - GstFlowReturn last_flow; /* ATOMIC */ - - /* the first frame when bframe was enabled */ - GstVideoCodecFrame *first_frame; - GstClockTime dts_offset; - - /*< protected >*/ - /* device capability dependent properties, set by subclass */ - gboolean weighted_pred; - guint vbv_buffersize; - guint rc_lookahead; - gboolean temporal_aq; - guint bframes; - gboolean b_adapt; -} GstNvBaseEnc; - -typedef struct { - GstVideoEncoderClass video_encoder_class; - - GUID codec_id; - guint cuda_device_id; - GstNvEncDeviceCaps device_caps; - - gboolean (*set_src_caps) (GstNvBaseEnc * nvenc, - GstVideoCodecState * state); - gboolean (*set_pic_params) (GstNvBaseEnc * nvenc, - GstVideoCodecFrame * frame, - NV_ENC_PIC_PARAMS * pic_params); - gboolean (*set_encoder_config) (GstNvBaseEnc * nvenc, - GstVideoCodecState * state, - NV_ENC_CONFIG * config); -} GstNvBaseEncClass; - -GType gst_nv_base_enc_get_type (void); - -GType gst_nv_base_enc_register (const char * codec, - guint device_id, - GstNvEncDeviceCaps * device_caps); - -void gst_nv_base_enc_schedule_reconfig (GstNvBaseEnc * nvenc); - - -#endif /* __GST_NV_BASE_ENC_H_INCLUDED__ */ diff --git a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvenc.c b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvenc.c index d150dee1fc..9f060e47b1 100644 --- a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvenc.c +++ b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvenc.c @@ -22,10 +22,7 @@ #endif #include "gstnvenc.h" -#include "gstnvh264enc.h" -#include "gstnvh265enc.h" #include -#include #include #include @@ -305,598 +302,6 @@ NvEncSetIOCudaStreams (void *encoder, NV_ENC_CUSTREAM_PTR input_stream, return nvenc_api.nvEncSetIOCudaStreams (encoder, input_stream, output_stream); } -gboolean -gst_nvenc_cmp_guid (GUID g1, GUID g2) -{ - return (g1.Data1 == g2.Data1 && g1.Data2 == g2.Data2 && g1.Data3 == g2.Data3 - && g1.Data4[0] == g2.Data4[0] && g1.Data4[1] == g2.Data4[1] - && g1.Data4[2] == g2.Data4[2] && g1.Data4[3] == g2.Data4[3] - && g1.Data4[4] == g2.Data4[4] && g1.Data4[5] == g2.Data4[5] - && g1.Data4[6] == g2.Data4[6] && g1.Data4[7] == g2.Data4[7]); -} - -NV_ENC_BUFFER_FORMAT -gst_nvenc_get_nv_buffer_format (GstVideoFormat fmt) -{ - switch (fmt) { - case GST_VIDEO_FORMAT_NV12: - return NV_ENC_BUFFER_FORMAT_NV12_PL; - case GST_VIDEO_FORMAT_YV12: - return NV_ENC_BUFFER_FORMAT_YV12_PL; - case GST_VIDEO_FORMAT_I420: - return NV_ENC_BUFFER_FORMAT_IYUV_PL; - case GST_VIDEO_FORMAT_Y444: - return NV_ENC_BUFFER_FORMAT_YUV444_PL; - case GST_VIDEO_FORMAT_P010_10LE: - case GST_VIDEO_FORMAT_P010_10BE: - return NV_ENC_BUFFER_FORMAT_YUV420_10BIT; - case GST_VIDEO_FORMAT_BGRA: - return NV_ENC_BUFFER_FORMAT_ARGB; - case GST_VIDEO_FORMAT_RGBA: - return NV_ENC_BUFFER_FORMAT_ABGR; - case GST_VIDEO_FORMAT_BGR10A2_LE: - return NV_ENC_BUFFER_FORMAT_ARGB10; - case GST_VIDEO_FORMAT_RGB10A2_LE: - return NV_ENC_BUFFER_FORMAT_ABGR10; - case GST_VIDEO_FORMAT_Y444_16LE: - case GST_VIDEO_FORMAT_Y444_16BE: - return NV_ENC_BUFFER_FORMAT_YUV444_10BIT; - case GST_VIDEO_FORMAT_VUYA: - return NV_ENC_BUFFER_FORMAT_AYUV; - default: - break; - } - return NV_ENC_BUFFER_FORMAT_UNDEFINED; -} - -typedef struct -{ - GstVideoFormat gst_format; - NV_ENC_BUFFER_FORMAT nv_format; - gboolean is_10bit; - - gboolean supported; -} GstNvEncFormat; - -gboolean -gst_nvenc_get_supported_input_formats (gpointer encoder, GUID codec_id, - GValue ** formats) -{ - guint32 i, count = 0; - NV_ENC_BUFFER_FORMAT format_list[64]; - GValue val = G_VALUE_INIT; - GValue *ret = NULL; - NV_ENC_CAPS_PARAM param = { 0, }; - gint support_yuv444 = 0; - gint support_10bit = 0; - guint num_format = 0; - GstNvEncFormat format_map[] = { - {GST_VIDEO_FORMAT_NV12, NV_ENC_BUFFER_FORMAT_NV12, FALSE, FALSE}, - {GST_VIDEO_FORMAT_YV12, NV_ENC_BUFFER_FORMAT_YV12, FALSE, FALSE}, - {GST_VIDEO_FORMAT_I420, NV_ENC_BUFFER_FORMAT_IYUV, FALSE, FALSE}, - {GST_VIDEO_FORMAT_BGRA, NV_ENC_BUFFER_FORMAT_ARGB, FALSE, FALSE}, - {GST_VIDEO_FORMAT_RGBA, NV_ENC_BUFFER_FORMAT_ABGR, FALSE, FALSE}, - {GST_VIDEO_FORMAT_Y444, NV_ENC_BUFFER_FORMAT_YUV444, FALSE, FALSE}, - {GST_VIDEO_FORMAT_VUYA, NV_ENC_BUFFER_FORMAT_AYUV, FALSE, FALSE}, -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - {GST_VIDEO_FORMAT_P010_10LE, NV_ENC_BUFFER_FORMAT_YUV420_10BIT, TRUE, - FALSE}, - {GST_VIDEO_FORMAT_BGR10A2_LE, NV_ENC_BUFFER_FORMAT_ARGB10, TRUE, - FALSE}, - {GST_VIDEO_FORMAT_RGB10A2_LE, NV_ENC_BUFFER_FORMAT_ABGR10, TRUE, - FALSE}, - {GST_VIDEO_FORMAT_Y444_16LE, NV_ENC_BUFFER_FORMAT_YUV444_10BIT, TRUE, - FALSE}, -#else - {GST_VIDEO_FORMAT_P010_10BE, NV_ENC_BUFFER_FORMAT_YUV420_10BIT, TRUE, - FALSE}, - {GST_VIDEO_FORMAT_Y444_16BE, NV_ENC_BUFFER_FORMAT_YUV444_10BIT, TRUE, - FALSE}, - /* FIXME: No 10bits big-endian ARGB10 format is defined */ -#endif - }; - - param.version = gst_nvenc_get_caps_param_version (); - param.capsToQuery = NV_ENC_CAPS_SUPPORT_YUV444_ENCODE; - if (NvEncGetEncodeCaps (encoder, - codec_id, ¶m, &support_yuv444) != NV_ENC_SUCCESS) { - support_yuv444 = 0; - } - - param.capsToQuery = NV_ENC_CAPS_SUPPORT_10BIT_ENCODE; - if (NvEncGetEncodeCaps (encoder, - codec_id, ¶m, &support_10bit) != NV_ENC_SUCCESS) { - support_10bit = 0; - } - - if (NvEncGetInputFormats (encoder, - codec_id, format_list, G_N_ELEMENTS (format_list), - &count) != NV_ENC_SUCCESS || count == 0) { - return FALSE; - } - - for (i = 0; i < count; i++) { - GST_INFO ("input format: 0x%08x", format_list[i]); - switch (format_list[i]) { - case NV_ENC_BUFFER_FORMAT_NV12: - case NV_ENC_BUFFER_FORMAT_YV12: - case NV_ENC_BUFFER_FORMAT_IYUV: - case NV_ENC_BUFFER_FORMAT_ARGB: - case NV_ENC_BUFFER_FORMAT_ABGR: - if (!format_map[i].supported) { - format_map[i].supported = TRUE; - num_format++; - } - break; - case NV_ENC_BUFFER_FORMAT_YUV444: - case NV_ENC_BUFFER_FORMAT_AYUV: - if (support_yuv444 && !format_map[i].supported) { - format_map[i].supported = TRUE; - num_format++; - } - break; - case NV_ENC_BUFFER_FORMAT_YUV420_10BIT: - if (support_10bit && !format_map[i].supported) { - format_map[i].supported = TRUE; - num_format++; - } - break; - case NV_ENC_BUFFER_FORMAT_YUV444_10BIT: - if (support_yuv444 && support_10bit && !format_map[i].supported) { - format_map[i].supported = TRUE; - num_format++; - } - break; -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - case NV_ENC_BUFFER_FORMAT_ARGB10: - case NV_ENC_BUFFER_FORMAT_ABGR10: - if (support_10bit && !format_map[i].supported) { - format_map[i].supported = TRUE; - num_format++; - } - break; -#endif - default: - GST_FIXME ("unmapped input format: 0x%08x", format_list[i]); - break; - } - } - - if (num_format == 0) - return FALSE; - - /* process a second time so we can add formats in the order we want */ - g_value_init (&val, G_TYPE_STRING); - ret = g_new0 (GValue, 1); - g_value_init (ret, GST_TYPE_LIST); - - for (i = 0; i < G_N_ELEMENTS (format_map); i++) { - if (!format_map[i].supported) - continue; - - g_value_set_static_string (&val, - gst_video_format_to_string (format_map[i].gst_format)); - - gst_value_list_append_value (ret, &val); - } - - g_value_unset (&val); - - *formats = ret; - - return TRUE; -} - -GValue * -gst_nvenc_get_interlace_modes (gpointer enc, GUID codec_id) -{ - NV_ENC_CAPS_PARAM caps_param = { 0, }; - GValue *list; - GValue val = G_VALUE_INIT; - gint interlace_modes = 0; - - caps_param.version = gst_nvenc_get_caps_param_version (); - caps_param.capsToQuery = NV_ENC_CAPS_SUPPORT_FIELD_ENCODING; - - if (NvEncGetEncodeCaps (enc, codec_id, &caps_param, - &interlace_modes) != NV_ENC_SUCCESS) - interlace_modes = 0; - - list = g_new0 (GValue, 1); - - g_value_init (list, GST_TYPE_LIST); - g_value_init (&val, G_TYPE_STRING); - - g_value_set_static_string (&val, "progressive"); - gst_value_list_append_value (list, &val); - - if (interlace_modes == 0) - return list; - - if (interlace_modes >= 1) { - g_value_set_static_string (&val, "interleaved"); - gst_value_list_append_value (list, &val); - g_value_set_static_string (&val, "mixed"); - gst_value_list_append_value (list, &val); - g_value_unset (&val); - } - /* TODO: figure out what nvenc frame based interlacing means in gst terms */ - - return list; -} - -typedef struct -{ - const gchar *gst_profile; - const GUID nv_profile; - const GUID codec_id; - const gboolean need_yuv444; - const gboolean need_10bit; - - gboolean supported; -} GstNvEncCodecProfile; - -GValue * -gst_nvenc_get_supported_codec_profiles (gpointer enc, GUID codec_id) -{ - NVENCSTATUS nv_ret; - GUID profile_guids[64]; - GValue *ret; - GValue val = G_VALUE_INIT; - guint i, j, n, n_profiles; - NV_ENC_CAPS_PARAM param = { 0, }; - gint support_yuv444 = 0; - gint support_10bit = 0; - GstNvEncCodecProfile profiles[] = { - /* avc profiles */ - {"main", NV_ENC_H264_PROFILE_MAIN_GUID, NV_ENC_CODEC_H264_GUID, FALSE, - FALSE, FALSE}, - {"high", NV_ENC_H264_PROFILE_HIGH_GUID, NV_ENC_CODEC_H264_GUID, FALSE, - FALSE, FALSE}, - {"high-4:4:4", NV_ENC_H264_PROFILE_HIGH_444_GUID, NV_ENC_CODEC_H264_GUID, - TRUE, FALSE, FALSE}, - /* put baseline to last since it does not support bframe */ - {"baseline", NV_ENC_H264_PROFILE_BASELINE_GUID, NV_ENC_CODEC_H264_GUID, - FALSE, FALSE, FALSE}, - {"constrained-baseline", NV_ENC_H264_PROFILE_BASELINE_GUID, - NV_ENC_CODEC_H264_GUID, - FALSE, FALSE, FALSE}, - /* hevc profiles */ - {"main", NV_ENC_HEVC_PROFILE_MAIN_GUID, NV_ENC_CODEC_HEVC_GUID, FALSE, - FALSE, FALSE}, - {"main-10", NV_ENC_HEVC_PROFILE_MAIN10_GUID, NV_ENC_CODEC_HEVC_GUID, FALSE, - TRUE, FALSE}, - {"main-444", NV_ENC_HEVC_PROFILE_FREXT_GUID, NV_ENC_CODEC_HEVC_GUID, TRUE, - FALSE, FALSE}, -#if 0 - /* FIXME: seems to unsupported format */ - {"main-444-10", NV_ENC_HEVC_PROFILE_FREXT_GUID, FALSE} -#endif - }; - - param.version = gst_nvenc_get_caps_param_version (); - param.capsToQuery = NV_ENC_CAPS_SUPPORT_YUV444_ENCODE; - if (NvEncGetEncodeCaps (enc, - codec_id, ¶m, &support_yuv444) != NV_ENC_SUCCESS) { - support_yuv444 = 0; - } - - param.capsToQuery = NV_ENC_CAPS_SUPPORT_10BIT_ENCODE; - if (NvEncGetEncodeCaps (enc, - codec_id, ¶m, &support_10bit) != NV_ENC_SUCCESS) { - support_10bit = 0; - } - - nv_ret = NvEncGetEncodeProfileGUIDCount (enc, codec_id, &n); - - if (nv_ret != NV_ENC_SUCCESS) - return NULL; - - nv_ret = NvEncGetEncodeProfileGUIDs (enc, - codec_id, profile_guids, G_N_ELEMENTS (profile_guids), &n); - - if (nv_ret != NV_ENC_SUCCESS) - return NULL; - - n_profiles = 0; - - for (i = 0; i < n; i++) { - for (j = 0; j < G_N_ELEMENTS (profiles); j++) { - if (profiles[j].supported == FALSE && - gst_nvenc_cmp_guid (profile_guids[i], profiles[j].nv_profile) && - gst_nvenc_cmp_guid (codec_id, profiles[j].codec_id)) { - if (profiles[j].need_yuv444 && !support_yuv444) - continue; - - if (profiles[j].need_10bit && !support_10bit) - continue; - - profiles[j].supported = TRUE; - n_profiles++; - } - } - } - - if (n_profiles == 0) - return NULL; - - ret = g_new0 (GValue, 1); - - g_value_init (ret, GST_TYPE_LIST); - g_value_init (&val, G_TYPE_STRING); - - for (i = 0; i < G_N_ELEMENTS (profiles); i++) { - if (!profiles[i].supported) - continue; - - g_value_set_static_string (&val, profiles[i].gst_profile); - gst_value_list_append_value (ret, &val); - } - - g_value_unset (&val); - - return ret; -} - -#define DEBUG_DEVICE_CAPS(d,c,caps,s) \ - GST_DEBUG ("[device-%d %s] %s: %s", \ - d, c, caps, s ? "supported" : "not supported"); - -#define ERROR_DETAILS "codec %s, device %i, error code %i" - -static void -gst_nv_enc_register (GstPlugin * plugin, GUID codec_id, const gchar * codec, - guint rank, gint device_index, CUcontext cuda_ctx) -{ - { - GValue *formats = NULL; - GValue *profiles; - GValue *interlace_modes; - gpointer enc; - NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS params = { 0, }; - NV_ENC_CAPS_PARAM caps_param = { 0, }; - GUID guids[16]; - guint32 count; - gint max_width = 0; - gint max_height = 0; - gint min_width = 16; - gint min_height = 16; - GstCaps *sink_templ = NULL; - GstCaps *src_templ = NULL; - gchar *name; - gint j; - GstNvEncDeviceCaps device_caps = { 0, }; - NVENCSTATUS status; - CUresult cu_res; - - params.version = gst_nvenc_get_open_encode_session_ex_params_version (); - params.apiVersion = gst_nvenc_get_api_version (); - params.device = cuda_ctx; - params.deviceType = NV_ENC_DEVICE_TYPE_CUDA; - - if ((cu_res = CuCtxPushCurrent (cuda_ctx)) != CUDA_SUCCESS) { - GST_ERROR ("CuCtxPushCurrent failed: " ERROR_DETAILS, codec, - device_index, cu_res); - goto done; - } - - if ((status = NvEncOpenEncodeSessionEx (¶ms, &enc)) != NV_ENC_SUCCESS) { - CuCtxPopCurrent (NULL); - GST_ERROR ("NvEncOpenEncodeSessionEx failed: " ERROR_DETAILS, codec, - device_index, status); - goto done; - } - - if ((status = NvEncGetEncodeGUIDs (enc, guids, G_N_ELEMENTS (guids), - &count)) != NV_ENC_SUCCESS) { - GST_ERROR ("NvEncGetEncodeGUIDs failed: " ERROR_DETAILS, codec, - device_index, status); - goto enc_free; - } - - for (j = 0; j < count; j++) { - if (gst_nvenc_cmp_guid (guids[j], codec_id)) - break; - } - - if (j == count) - goto enc_free; - - if (!gst_nvenc_get_supported_input_formats (enc, codec_id, &formats)) - goto enc_free; - - profiles = gst_nvenc_get_supported_codec_profiles (enc, codec_id); - if (!profiles) - goto free_format; - - caps_param.version = gst_nvenc_get_caps_param_version (); - caps_param.capsToQuery = NV_ENC_CAPS_WIDTH_MAX; - if ((status = NvEncGetEncodeCaps (enc, - codec_id, &caps_param, &max_width)) != NV_ENC_SUCCESS) { - max_width = 4096; - GST_WARNING ("could not query max width, setting as %i: " - ERROR_DETAILS, max_width, codec, device_index, status); - } else if (max_width < 4096) { - GST_WARNING ("max width %d is less than expected value", max_width); - max_width = 4096; - } - - caps_param.capsToQuery = NV_ENC_CAPS_HEIGHT_MAX; - if ((status = NvEncGetEncodeCaps (enc, - codec_id, &caps_param, &max_height)) != NV_ENC_SUCCESS) { - GST_WARNING ("could not query max height, setting as %i: " - ERROR_DETAILS, max_height, codec, device_index, status); - max_height = 4096; - } else if (max_height < 4096) { - GST_WARNING ("max height %d is less than expected value", max_height); - max_height = 4096; - } - - caps_param.capsToQuery = NV_ENC_CAPS_WIDTH_MIN; - if ((status = NvEncGetEncodeCaps (enc, - codec_id, &caps_param, &min_width)) != NV_ENC_SUCCESS) { - GST_WARNING ("could not query min width, setting as %i: " - ERROR_DETAILS, min_width, codec, device_index, status); - min_width = 16; - } - - caps_param.capsToQuery = NV_ENC_CAPS_HEIGHT_MIN; - if ((status = NvEncGetEncodeCaps (enc, - codec_id, &caps_param, &min_height)) != NV_ENC_SUCCESS) { - GST_WARNING ("could not query min height, setting as %i: " - ERROR_DETAILS, min_height, codec, device_index, status); - min_height = 16; - } - - caps_param.capsToQuery = NV_ENC_CAPS_SUPPORTED_RATECONTROL_MODES; - if (NvEncGetEncodeCaps (enc, codec_id, &caps_param, - &device_caps.rc_modes) != NV_ENC_SUCCESS) { - device_caps.rc_modes = 0; - } else { - GST_DEBUG ("[device-%d %s] rate control modes: 0x%x", - device_index, codec, device_caps.rc_modes); -#define IS_SUPPORTED_RC(rc_modes,mode) \ - ((((rc_modes) & (mode)) == mode) ? "supported" : "not supported") - - GST_DEBUG ("\tconst-qp: %s", - IS_SUPPORTED_RC (device_caps.rc_modes, NV_ENC_PARAMS_RC_CONSTQP)); - GST_DEBUG ("\tvbr: %s", - IS_SUPPORTED_RC (device_caps.rc_modes, NV_ENC_PARAMS_RC_VBR)); - GST_DEBUG ("\tcbr: %s", - IS_SUPPORTED_RC (device_caps.rc_modes, NV_ENC_PARAMS_RC_CBR)); - GST_DEBUG ("\tcbr-lowdelay-hq: %s", - IS_SUPPORTED_RC (device_caps.rc_modes, - NV_ENC_PARAMS_RC_CBR_LOWDELAY_HQ)); - GST_DEBUG ("\tcbr-hq: %s", - IS_SUPPORTED_RC (device_caps.rc_modes, NV_ENC_PARAMS_RC_CBR_HQ)); - GST_DEBUG ("\tvbr-hq: %s", - IS_SUPPORTED_RC (device_caps.rc_modes, NV_ENC_PARAMS_RC_VBR_HQ)); - GST_DEBUG ("\tvbr-minqp: %s (deprecated)", - IS_SUPPORTED_RC (device_caps.rc_modes, NV_ENC_PARAMS_RC_VBR_MINQP)); -#undef IS_SUPPORTED_RC - } - - caps_param.capsToQuery = NV_ENC_CAPS_SUPPORT_WEIGHTED_PREDICTION; - if (NvEncGetEncodeCaps (enc, codec_id, &caps_param, - &device_caps.weighted_prediction) != NV_ENC_SUCCESS) { - device_caps.weighted_prediction = FALSE; - } - - caps_param.capsToQuery = NV_ENC_CAPS_SUPPORT_CUSTOM_VBV_BUF_SIZE; - if (NvEncGetEncodeCaps (enc, codec_id, &caps_param, - &device_caps.custom_vbv_bufsize) != NV_ENC_SUCCESS) { - device_caps.custom_vbv_bufsize = FALSE; - } - - caps_param.capsToQuery = NV_ENC_CAPS_SUPPORT_LOOKAHEAD; - if (NvEncGetEncodeCaps (enc, - codec_id, &caps_param, &device_caps.lookahead) != NV_ENC_SUCCESS) { - device_caps.lookahead = FALSE; - } - - caps_param.capsToQuery = NV_ENC_CAPS_SUPPORT_TEMPORAL_AQ; - if (NvEncGetEncodeCaps (enc, codec_id, &caps_param, - &device_caps.temporal_aq) != NV_ENC_SUCCESS) { - device_caps.temporal_aq = FALSE; - } - - caps_param.capsToQuery = NV_ENC_CAPS_NUM_MAX_BFRAMES; - if (NvEncGetEncodeCaps (enc, codec_id, &caps_param, - &device_caps.bframes) != NV_ENC_SUCCESS) { - device_caps.bframes = 0; - } - - DEBUG_DEVICE_CAPS (device_index, - codec, "weighted prediction", device_caps.weighted_prediction); - - DEBUG_DEVICE_CAPS (device_index, codec, "custom vbv-buffer-size", - device_caps.custom_vbv_bufsize); - - DEBUG_DEVICE_CAPS (device_index, codec, "rc-loockahead", - device_caps.lookahead); - - DEBUG_DEVICE_CAPS (device_index, codec, "temporal adaptive quantization", - device_caps.temporal_aq); - - GST_DEBUG ("[device-%d %s] max bframes: %d", device_index, codec, - device_caps.bframes); - - interlace_modes = gst_nvenc_get_interlace_modes (enc, codec_id); - - sink_templ = gst_caps_new_empty_simple ("video/x-raw"); - gst_caps_set_value (sink_templ, "format", formats); - - gst_caps_set_simple (sink_templ, - "width", GST_TYPE_INT_RANGE, min_width, max_width, - "height", GST_TYPE_INT_RANGE, min_height, max_height, - "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL); - - if (interlace_modes) { - gst_caps_set_value (sink_templ, "interlace-mode", interlace_modes); - g_value_unset (interlace_modes); - g_free (interlace_modes); - } - - { - GstCaps *cuda_caps = gst_caps_copy (sink_templ); -#ifdef HAVE_CUDA_GST_GL - GstCaps *gl_caps = gst_caps_copy (sink_templ); - gst_caps_set_features_simple (gl_caps, - gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_GL_MEMORY)); - gst_caps_append (sink_templ, gl_caps); -#endif - - gst_caps_set_features_simple (cuda_caps, - gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_CUDA_MEMORY)); - gst_caps_append (sink_templ, cuda_caps); - } - - name = g_strdup_printf ("video/x-%s", codec); - src_templ = gst_caps_new_simple (name, - "width", GST_TYPE_INT_RANGE, min_width, max_width, - "height", GST_TYPE_INT_RANGE, min_height, max_height, - "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, - "stream-format", G_TYPE_STRING, "byte-stream", - "alignment", G_TYPE_STRING, "au", NULL); - gst_caps_set_value (src_templ, "profile", profiles); - g_free (name); - - GST_DEBUG ("sink template caps %" GST_PTR_FORMAT, sink_templ); - GST_DEBUG ("src template caps %" GST_PTR_FORMAT, src_templ); - - g_value_unset (profiles); - g_free (profiles); - - free_format: - if (formats) { - g_value_unset (formats); - g_free (formats); - } - /* fall-through */ - - enc_free: - NvEncDestroyEncoder (enc); - CuCtxPopCurrent (NULL); - /* fall-through */ - - done: - if (sink_templ && src_templ) { - if (gst_nvenc_cmp_guid (codec_id, NV_ENC_CODEC_H264_GUID)) { - gst_nv_h264_enc_register (plugin, device_index, rank, sink_templ, - src_templ, &device_caps); - } else if (gst_nvenc_cmp_guid (codec_id, NV_ENC_CODEC_HEVC_GUID)) { - gst_nv_h265_enc_register (plugin, device_index, rank, sink_templ, - src_templ, &device_caps); - } else { - g_assert_not_reached (); - } - } - - gst_clear_caps (&sink_templ); - gst_clear_caps (&src_templ); - } -} - typedef struct { gint major; @@ -1028,16 +433,6 @@ gst_nvenc_load_library (guint * api_major_ver, guint * api_minor_ver) return ret == NV_ENC_SUCCESS; } -void -gst_nvenc_plugin_init (GstPlugin * plugin, guint device_index, - CUcontext cuda_ctx) -{ - gst_nv_enc_register (plugin, NV_ENC_CODEC_H264_GUID, - "h264", GST_RANK_PRIMARY * 2, device_index, cuda_ctx); - gst_nv_enc_register (plugin, NV_ENC_CODEC_HEVC_GUID, - "h265", GST_RANK_PRIMARY * 2, device_index, cuda_ctx); -} - /* To verify things when updating SDK */ #define USE_STATIC_SDK_VER 0 diff --git a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvenc.h b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvenc.h index f60bddf1c0..ab56df9764 100644 --- a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvenc.h +++ b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvenc.h @@ -28,24 +28,6 @@ G_BEGIN_DECLS -gboolean gst_nvenc_cmp_guid (GUID g1, GUID g2); - -NV_ENC_BUFFER_FORMAT gst_nvenc_get_nv_buffer_format (GstVideoFormat fmt); - -gboolean gst_nvenc_get_supported_input_formats (gpointer encoder, - GUID codec_id, - GValue ** formats); - -GValue * gst_nvenc_get_interlace_modes (gpointer enc, - GUID codec_id); - -GValue * gst_nvenc_get_supported_codec_profiles (gpointer enc, - GUID codec_id); - -void gst_nvenc_plugin_init (GstPlugin * plugin, - guint device_index, - CUcontext cuda_ctx); - guint32 gst_nvenc_get_api_version (void); guint32 gst_nvenc_get_caps_param_version (void); diff --git a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvh264enc.c b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvh264enc.c deleted file mode 100644 index 4e436d876d..0000000000 --- a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvh264enc.c +++ /dev/null @@ -1,748 +0,0 @@ -/* GStreamer NVENC plugin - * Copyright (C) 2015 Centricular Ltd - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gstnvh264enc.h" - -#include - -#include - -typedef struct -{ - GstCaps *sink_caps; - GstCaps *src_caps; - gboolean is_default; -} GstNvH264EncClassData; - -GST_DEBUG_CATEGORY_STATIC (gst_nv_h264_enc_debug); -#define GST_CAT_DEFAULT gst_nv_h264_enc_debug - -static GstElementClass *parent_class = NULL; - -enum -{ - PROP_0, - PROP_AUD, - PROP_WEIGHTED_PRED, - PROP_VBV_BUFFER_SIZE, - PROP_RC_LOOKAHEAD, - PROP_TEMPORAL_AQ, - PROP_BFRAMES, - PROP_B_ADAPT, -}; - -#define DEFAULT_AUD TRUE -#define DEFAULT_WEIGHTED_PRED FALSE -#define DEFAULT_VBV_BUFFER_SIZE 0 -#define DEFAULT_RC_LOOKAHEAD 0 -#define DEFAULT_TEMPORAL_AQ FALSE -#define DEFAULT_BFRAMES 0 -#define DEFAULT_B_ADAPT FALSE - -/* captured using RTX 2080 */ -#define DOCUMENTATION_SINK_CAPS_COMM \ - "format = (string) { NV12, YV12, I420, BGRA, RGBA, Y444, VUYA }, " \ - "width = (int) [ 145, 4096 ], " \ - "height = (int) [ 49, 4096 ], " \ - "framerate = " GST_VIDEO_FPS_RANGE ", " \ - "interlace-mode = (string) { progressive } " - -#define DOCUMENTATION_SINK_CAPS \ - "video/x-raw, " DOCUMENTATION_SINK_CAPS_COMM "; " \ - "video/x-raw(memory:GLMemory), " DOCUMENTATION_SINK_CAPS_COMM "; " \ - "video/x-raw(memory:CUDAMemory), " DOCUMENTATION_SINK_CAPS_COMM - -#define DOCUMENTATION_SRC_CAPS \ - "video/x-h264, " \ - "width = (int) [ 145, 4096 ], " \ - "height = (int) [ 49, 4096 ], " \ - "framerate = " GST_VIDEO_FPS_RANGE ", " \ - "stream-format = (string) byte-stream, " \ - "alignment = (string) au, " \ - "profile = (string) { main, high, high-4:4:4, baseline, constrained-baseline }" - -static gboolean gst_nv_h264_enc_open (GstVideoEncoder * enc); -static gboolean gst_nv_h264_enc_close (GstVideoEncoder * enc); -static gboolean gst_nv_h264_enc_set_src_caps (GstNvBaseEnc * nvenc, - GstVideoCodecState * state); -static gboolean gst_nv_h264_enc_set_encoder_config (GstNvBaseEnc * nvenc, - GstVideoCodecState * state, NV_ENC_CONFIG * config); -static gboolean gst_nv_h264_enc_set_pic_params (GstNvBaseEnc * nvenc, - GstVideoCodecFrame * frame, NV_ENC_PIC_PARAMS * pic_params); -static void gst_nv_h264_enc_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_nv_h264_enc_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); -static void gst_nv_h264_enc_finalize (GObject * obj); - -static void -gst_nv_h264_enc_class_init (GstNvH264EncClass * klass, gpointer data) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - GstVideoEncoderClass *videoenc_class = GST_VIDEO_ENCODER_CLASS (klass); - GstNvBaseEncClass *nvenc_class = GST_NV_BASE_ENC_CLASS (klass); - GstNvEncDeviceCaps *device_caps = &nvenc_class->device_caps; - GstNvH264EncClassData *cdata = (GstNvH264EncClassData *) data; - gchar *long_name; - GstPadTemplate *pad_templ; - GstCaps *doc_caps; - - parent_class = g_type_class_peek_parent (klass); - - gobject_class->set_property = gst_nv_h264_enc_set_property; - gobject_class->get_property = gst_nv_h264_enc_get_property; - gobject_class->finalize = gst_nv_h264_enc_finalize; - - videoenc_class->open = GST_DEBUG_FUNCPTR (gst_nv_h264_enc_open); - videoenc_class->close = GST_DEBUG_FUNCPTR (gst_nv_h264_enc_close); - - nvenc_class->codec_id = NV_ENC_CODEC_H264_GUID; - nvenc_class->set_encoder_config = gst_nv_h264_enc_set_encoder_config; - nvenc_class->set_src_caps = gst_nv_h264_enc_set_src_caps; - nvenc_class->set_pic_params = gst_nv_h264_enc_set_pic_params; - - /** - * GstNvH264Enc:aud: - * - * Use AU (Access Unit) delimiter - * - * Since: 1.18 - */ - g_object_class_install_property (gobject_class, PROP_AUD, - g_param_spec_boolean ("aud", "AUD", - "Use AU (Access Unit) delimiter", DEFAULT_AUD, - G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING | - G_PARAM_STATIC_STRINGS)); - - if (device_caps->weighted_prediction) { - /** - * GstNvH264Enc:weighted-pred: - * - * Weighted Prediction - * - * Since: 1.18 - */ - g_object_class_install_property (gobject_class, PROP_WEIGHTED_PRED, - g_param_spec_boolean ("weighted-pred", "Weighted Pred", - "Weighted Prediction", DEFAULT_WEIGHTED_PRED, - G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING | - GST_PARAM_CONDITIONALLY_AVAILABLE | G_PARAM_STATIC_STRINGS)); - } - - if (device_caps->custom_vbv_bufsize) { - /** - * GstNvH264Enc:vbv-buffer-size: - * - * VBV(HRD) Buffer Size in kbits (0 = NVENC default) - * - * Since: 1.18 - */ - g_object_class_install_property (gobject_class, - PROP_VBV_BUFFER_SIZE, - g_param_spec_uint ("vbv-buffer-size", "VBV Buffer Size", - "VBV(HRD) Buffer Size in kbits (0 = NVENC default)", - 0, G_MAXUINT, DEFAULT_VBV_BUFFER_SIZE, - G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY | - GST_PARAM_CONDITIONALLY_AVAILABLE | G_PARAM_STATIC_STRINGS)); - } - - if (device_caps->lookahead) { - /** - * GstNvH264Enc:rc-lookahead: - * - * Number of frames for frame type lookahead - * - * Since: 1.18 - */ - g_object_class_install_property (gobject_class, PROP_RC_LOOKAHEAD, - g_param_spec_uint ("rc-lookahead", "Rate Control Lookahead", - "Number of frames for frame type lookahead", - 0, 32, DEFAULT_RC_LOOKAHEAD, - G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY | - GST_PARAM_CONDITIONALLY_AVAILABLE | G_PARAM_STATIC_STRINGS)); - } - - if (device_caps->temporal_aq) { - /** - * GstNvH264Enc:temporal-aq: - * - * Temporal Adaptive Quantization - * - * Since: 1.18 - */ - g_object_class_install_property (gobject_class, PROP_TEMPORAL_AQ, - g_param_spec_boolean ("temporal-aq", "Temporal AQ", - "Temporal Adaptive Quantization", DEFAULT_TEMPORAL_AQ, - G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING | - GST_PARAM_CONDITIONALLY_AVAILABLE | G_PARAM_STATIC_STRINGS)); - } - - if (device_caps->bframes > 0) { - /** - * GstNvH264Enc:bframes: - * - * Number of B-frames between I and P - * - * Since: 1.18 - */ - g_object_class_install_property (gobject_class, PROP_BFRAMES, - g_param_spec_uint ("bframes", "B-Frames", - "Number of B-frames between I and P", 0, device_caps->bframes, - DEFAULT_BFRAMES, - G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY | - GST_PARAM_CONDITIONALLY_AVAILABLE | G_PARAM_STATIC_STRINGS)); - - /** - * GstNvH264Enc:b-adapt: - * - * Enable adaptive B-frame insert when lookahead is enabled - * - * Since: 1.18 - */ - g_object_class_install_property (gobject_class, PROP_B_ADAPT, - g_param_spec_boolean ("b-adapt", "B Adapt", - "Enable adaptive B-frame insert when lookahead is enabled", - DEFAULT_B_ADAPT, - G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY | - GST_PARAM_CONDITIONALLY_AVAILABLE | G_PARAM_STATIC_STRINGS)); - } - - if (cdata->is_default) - long_name = g_strdup ("NVENC H.264 Video Encoder"); - else - long_name = g_strdup_printf ("NVENC H.264 Video Encoder with device %d", - nvenc_class->cuda_device_id); - - gst_element_class_set_metadata (element_class, long_name, - "Codec/Encoder/Video/Hardware", - "Encode H.264 video streams using NVIDIA's hardware-accelerated NVENC encoder API", - "Tim-Philipp Müller , " - "Matthew Waters , " - "Seungha Yang "); - g_free (long_name); - - GST_DEBUG_CATEGORY_INIT (gst_nv_h264_enc_debug, - "nvh264enc", 0, "Nvidia H.264 encoder"); - - pad_templ = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - cdata->sink_caps); - doc_caps = gst_caps_from_string (DOCUMENTATION_SINK_CAPS); - gst_pad_template_set_documentation_caps (pad_templ, doc_caps); - gst_caps_unref (doc_caps); - gst_element_class_add_pad_template (element_class, pad_templ); - - pad_templ = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, - cdata->src_caps); - doc_caps = gst_caps_from_string (DOCUMENTATION_SRC_CAPS); - gst_pad_template_set_documentation_caps (pad_templ, doc_caps); - gst_caps_unref (doc_caps); - gst_element_class_add_pad_template (element_class, pad_templ); - - gst_caps_unref (cdata->sink_caps); - gst_caps_unref (cdata->src_caps); - g_free (cdata); -} - -static void -gst_nv_h264_enc_init (GstNvH264Enc * nvenc) -{ - GstNvBaseEnc *baseenc = GST_NV_BASE_ENC (nvenc); - - nvenc->aud = DEFAULT_AUD; - - /* device capability dependent properties */ - baseenc->weighted_pred = DEFAULT_WEIGHTED_PRED; - baseenc->vbv_buffersize = DEFAULT_VBV_BUFFER_SIZE; - baseenc->rc_lookahead = DEFAULT_RC_LOOKAHEAD; - baseenc->temporal_aq = DEFAULT_TEMPORAL_AQ; - baseenc->bframes = DEFAULT_BFRAMES; - baseenc->b_adapt = DEFAULT_B_ADAPT; -} - -static void -gst_nv_h264_enc_finalize (GObject * obj) -{ - G_OBJECT_CLASS (parent_class)->finalize (obj); -} - -static gboolean -gst_nv_h264_enc_open (GstVideoEncoder * enc) -{ - GstNvBaseEnc *base = GST_NV_BASE_ENC (enc); - - if (!GST_VIDEO_ENCODER_CLASS (parent_class)->open (enc)) - return FALSE; - - /* Check if H.264 is supported */ - { - uint32_t i, num = 0; - GUID guids[16]; - - NvEncGetEncodeGUIDs (base->encoder, guids, G_N_ELEMENTS (guids), &num); - - for (i = 0; i < num; ++i) { - if (gst_nvenc_cmp_guid (guids[i], NV_ENC_CODEC_H264_GUID)) - break; - } - GST_INFO_OBJECT (enc, "H.264 encoding %ssupported", (i == num) ? "un" : ""); - if (i == num) { - gst_nv_h264_enc_close (enc); - return FALSE; - } - } - - return TRUE; -} - -static gboolean -gst_nv_h264_enc_close (GstVideoEncoder * enc) -{ - return GST_VIDEO_ENCODER_CLASS (parent_class)->close (enc); -} - -static gboolean -gst_nv_h264_enc_set_profile_and_level (GstNvH264Enc * nvenc, GstCaps * caps) -{ -#define N_BYTES_SPS 128 - guint8 sps[N_BYTES_SPS]; - NV_ENC_SEQUENCE_PARAM_PAYLOAD spp = { 0, }; - GstStructure *s; - const gchar *profile; - GstCaps *allowed_caps; - GstStructure *s2; - const gchar *allowed_profile; - NVENCSTATUS nv_ret; - guint32 seq_size; - - spp.version = gst_nvenc_get_sequence_param_payload_version (); - spp.inBufferSize = N_BYTES_SPS; - spp.spsId = 0; - spp.ppsId = 0; - spp.spsppsBuffer = &sps; - spp.outSPSPPSPayloadSize = &seq_size; - nv_ret = NvEncGetSequenceParams (GST_NV_BASE_ENC (nvenc)->encoder, &spp); - if (nv_ret != NV_ENC_SUCCESS) { - GST_ELEMENT_ERROR (nvenc, STREAM, ENCODE, ("Encode header failed."), - ("NvEncGetSequenceParams return code=%d", nv_ret)); - return FALSE; - } - - if (seq_size < 8) { - GST_ELEMENT_ERROR (nvenc, STREAM, ENCODE, ("Encode header failed."), - ("NvEncGetSequenceParams returned incomplete data")); - return FALSE; - } - - /* skip nal header and identifier */ - gst_codec_utils_h264_caps_set_level_and_profile (caps, &sps[5], 3); - - /* Constrained baseline is a strict subset of baseline. If downstream - * wanted baseline and we produced constrained baseline, we can just - * set the profile to baseline in the caps to make negotiation happy. - * Same goes for baseline as subset of main profile and main as a subset - * of high profile. - */ - s = gst_caps_get_structure (caps, 0); - profile = gst_structure_get_string (s, "profile"); - - allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (nvenc)); - - if (allowed_caps == NULL) - goto no_peer; - - if (!gst_caps_can_intersect (allowed_caps, caps)) { - allowed_caps = gst_caps_make_writable (allowed_caps); - allowed_caps = gst_caps_truncate (allowed_caps); - s2 = gst_caps_get_structure (allowed_caps, 0); - gst_structure_fixate_field_string (s2, "profile", profile); - allowed_profile = gst_structure_get_string (s2, "profile"); - if (!strcmp (allowed_profile, "high")) { - if (!strcmp (profile, "constrained-baseline") - || !strcmp (profile, "baseline") || !strcmp (profile, "main")) { - gst_structure_set (s, "profile", G_TYPE_STRING, "high", NULL); - GST_INFO_OBJECT (nvenc, "downstream requested high profile, but " - "encoder will now output %s profile (which is a subset), due " - "to how it's been configured", profile); - } - } else if (!strcmp (allowed_profile, "main")) { - if (!strcmp (profile, "constrained-baseline") - || !strcmp (profile, "baseline")) { - gst_structure_set (s, "profile", G_TYPE_STRING, "main", NULL); - GST_INFO_OBJECT (nvenc, "downstream requested main profile, but " - "encoder will now output %s profile (which is a subset), due " - "to how it's been configured", profile); - } - } else if (!strcmp (allowed_profile, "baseline")) { - if (!strcmp (profile, "constrained-baseline")) - gst_structure_set (s, "profile", G_TYPE_STRING, "baseline", NULL); - } - } - gst_caps_unref (allowed_caps); - -no_peer: - - return TRUE; - -#undef N_BYTES_SPS -} - -static gboolean -gst_nv_h264_enc_set_src_caps (GstNvBaseEnc * nvenc, GstVideoCodecState * state) -{ - GstNvH264Enc *h264enc = (GstNvH264Enc *) nvenc; - GstVideoCodecState *out_state; - GstStructure *s; - GstCaps *out_caps; - - out_caps = gst_caps_new_empty_simple ("video/x-h264"); - s = gst_caps_get_structure (out_caps, 0); - - /* TODO: add support for avc format as well */ - gst_structure_set (s, "stream-format", G_TYPE_STRING, "byte-stream", - "alignment", G_TYPE_STRING, "au", NULL); - - if (!gst_nv_h264_enc_set_profile_and_level (h264enc, out_caps)) { - gst_caps_unref (out_caps); - return FALSE; - } - - out_state = gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (nvenc), - out_caps, state); - - GST_INFO_OBJECT (nvenc, "output caps: %" GST_PTR_FORMAT, out_state->caps); - - /* encoder will keep it around for us */ - gst_video_codec_state_unref (out_state); - - /* TODO: would be nice to also send some tags with the codec name */ - return TRUE; -} - -static gboolean -gst_nv_h264_enc_set_encoder_config (GstNvBaseEnc * nvenc, - GstVideoCodecState * state, NV_ENC_CONFIG * config) -{ - GstNvH264Enc *h264enc = (GstNvH264Enc *) nvenc; - GstCaps *allowed_caps, *template_caps; - GUID selected_profile = NV_ENC_CODEC_PROFILE_AUTOSELECT_GUID; - int level_idc = NV_ENC_LEVEL_AUTOSELECT; - GstVideoInfo *info = &state->info; - NV_ENC_CONFIG_H264 *h264_config = &config->encodeCodecConfig.h264Config; - NV_ENC_CONFIG_H264_VUI_PARAMETERS *vui = &h264_config->h264VUIParameters; - - template_caps = - gst_pad_get_pad_template_caps (GST_VIDEO_ENCODER_SRC_PAD (h264enc)); - allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (h264enc)); - - if (template_caps == allowed_caps) { - GST_INFO_OBJECT (h264enc, "downstream has ANY caps"); - } else if (allowed_caps) { - GstStructure *s; - const gchar *profile; - const gchar *level; - - if (gst_caps_is_empty (allowed_caps)) { - gst_caps_unref (allowed_caps); - gst_caps_unref (template_caps); - return FALSE; - } - - allowed_caps = gst_caps_make_writable (allowed_caps); - allowed_caps = gst_caps_fixate (allowed_caps); - s = gst_caps_get_structure (allowed_caps, 0); - - profile = gst_structure_get_string (s, "profile"); - if (profile) { - if (!strcmp (profile, "baseline") - || !strcmp (profile, "constrained-baseline")) { - selected_profile = NV_ENC_H264_PROFILE_BASELINE_GUID; - } else if (g_str_has_prefix (profile, "high-4:4:4")) { - selected_profile = NV_ENC_H264_PROFILE_HIGH_444_GUID; - } else if (g_str_has_prefix (profile, "high-10")) { - g_assert_not_reached (); - } else if (g_str_has_prefix (profile, "high-4:2:2")) { - g_assert_not_reached (); - } else if (g_str_has_prefix (profile, "high")) { - selected_profile = NV_ENC_H264_PROFILE_HIGH_GUID; - } else if (g_str_has_prefix (profile, "main")) { - selected_profile = NV_ENC_H264_PROFILE_MAIN_GUID; - } else { - g_assert_not_reached (); - } - } - - level = gst_structure_get_string (s, "level"); - if (level) - /* matches values stored in NV_ENC_LEVEL */ - level_idc = gst_codec_utils_h264_get_level_idc (level); - - gst_caps_unref (allowed_caps); - } - gst_caps_unref (template_caps); - - /* override some defaults */ - GST_LOG_OBJECT (h264enc, "setting parameters"); - config->profileGUID = selected_profile; - h264_config->level = level_idc; - h264_config->chromaFormatIDC = 1; - if (GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_Y444 || - GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_VUYA) { - GST_DEBUG_OBJECT (h264enc, "have Y444 input, setting config accordingly"); - config->profileGUID = NV_ENC_H264_PROFILE_HIGH_444_GUID; - h264_config->chromaFormatIDC = 3; - } - - h264_config->idrPeriod = config->gopLength; - h264_config->outputAUD = h264enc->aud; - - vui->videoSignalTypePresentFlag = 1; - /* NOTE: vui::video_format represents the video format before - * being encoded such as PAL, NTSC, SECAM, and MAC. That's not much informal - * and can be inferred with resolution and framerate by any application. - */ - /* Unspecified video format (5) */ - vui->videoFormat = 5; - - if (info->colorimetry.range == GST_VIDEO_COLOR_RANGE_0_255) { - vui->videoFullRangeFlag = 1; - } else { - vui->videoFullRangeFlag = 0; - } - - vui->colourDescriptionPresentFlag = 1; - vui->colourMatrix = gst_video_color_matrix_to_iso (info->colorimetry.matrix); - vui->colourPrimaries = - gst_video_color_primaries_to_iso (info->colorimetry.primaries); - vui->transferCharacteristics = - gst_video_transfer_function_to_iso (info->colorimetry.transfer); - - return TRUE; -} - -static gboolean -gst_nv_h264_enc_set_pic_params (GstNvBaseEnc * enc, GstVideoCodecFrame * frame, - NV_ENC_PIC_PARAMS * pic_params) -{ - /* encode whole picture in one single slice */ - pic_params->codecPicParams.h264PicParams.sliceMode = 0; - pic_params->codecPicParams.h264PicParams.sliceModeData = 0; - - return TRUE; -} - -static void -gst_nv_h264_enc_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstNvH264Enc *self = (GstNvH264Enc *) object; - GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (object); - GstNvBaseEncClass *klass = GST_NV_BASE_ENC_GET_CLASS (object); - GstNvEncDeviceCaps *device_caps = &klass->device_caps; - gboolean reconfig = FALSE; - - switch (prop_id) { - case PROP_AUD: - { - gboolean aud; - - aud = g_value_get_boolean (value); - if (aud != self->aud) { - self->aud = aud; - reconfig = TRUE; - } - break; - } - case PROP_WEIGHTED_PRED: - if (!device_caps->weighted_prediction) { - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } else { - nvenc->weighted_pred = g_value_get_boolean (value); - reconfig = TRUE; - } - break; - case PROP_VBV_BUFFER_SIZE: - if (!device_caps->custom_vbv_bufsize) { - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } else { - nvenc->vbv_buffersize = g_value_get_uint (value); - reconfig = TRUE; - } - break; - case PROP_RC_LOOKAHEAD: - if (!device_caps->lookahead) { - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } else { - nvenc->rc_lookahead = g_value_get_uint (value); - reconfig = TRUE; - } - break; - case PROP_TEMPORAL_AQ: - if (!device_caps->temporal_aq) { - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } else { - nvenc->temporal_aq = g_value_get_boolean (value); - reconfig = TRUE; - } - break; - case PROP_BFRAMES: - if (!device_caps->bframes) { - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } else { - nvenc->bframes = g_value_get_uint (value); - reconfig = TRUE; - } - break; - case PROP_B_ADAPT: - if (!device_caps->bframes) { - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } else { - nvenc->b_adapt = g_value_get_boolean (value); - } - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } - - if (reconfig) - gst_nv_base_enc_schedule_reconfig (GST_NV_BASE_ENC (self)); -} - -static void -gst_nv_h264_enc_get_property (GObject * object, guint prop_id, GValue * value, - GParamSpec * pspec) -{ - GstNvH264Enc *self = (GstNvH264Enc *) object; - GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (object); - GstNvBaseEncClass *klass = GST_NV_BASE_ENC_GET_CLASS (object); - GstNvEncDeviceCaps *device_caps = &klass->device_caps; - - switch (prop_id) { - case PROP_AUD: - g_value_set_boolean (value, self->aud); - break; - case PROP_WEIGHTED_PRED: - if (!device_caps->weighted_prediction) { - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } else { - g_value_set_boolean (value, nvenc->weighted_pred); - } - break; - case PROP_VBV_BUFFER_SIZE: - if (!device_caps->custom_vbv_bufsize) { - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } else { - g_value_set_uint (value, nvenc->vbv_buffersize); - } - break; - case PROP_RC_LOOKAHEAD: - if (!device_caps->lookahead) { - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } else { - g_value_set_uint (value, nvenc->rc_lookahead); - } - break; - case PROP_TEMPORAL_AQ: - if (!device_caps->temporal_aq) { - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } else { - g_value_set_boolean (value, nvenc->temporal_aq); - } - break; - case PROP_BFRAMES: - if (!device_caps->bframes) { - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } else { - g_value_set_uint (value, nvenc->bframes); - } - break; - case PROP_B_ADAPT: - if (!device_caps->bframes) { - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } else { - g_value_set_boolean (value, nvenc->b_adapt); - } - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -void -gst_nv_h264_enc_register (GstPlugin * plugin, guint device_id, guint rank, - GstCaps * sink_caps, GstCaps * src_caps, GstNvEncDeviceCaps * device_caps) -{ - GType parent_type; - GType type; - gchar *type_name; - gchar *feature_name; - GstNvH264EncClassData *cdata; - gboolean is_default = TRUE; - GTypeInfo type_info = { - sizeof (GstNvH264EncClass), - NULL, - NULL, - (GClassInitFunc) gst_nv_h264_enc_class_init, - NULL, - NULL, - sizeof (GstNvH264Enc), - 0, - (GInstanceInitFunc) gst_nv_h264_enc_init, - }; - - parent_type = gst_nv_base_enc_register ("H264", device_id, device_caps); - - cdata = g_new0 (GstNvH264EncClassData, 1); - cdata->sink_caps = gst_caps_ref (sink_caps); - cdata->src_caps = gst_caps_ref (src_caps); - type_info.class_data = cdata; - /* class data will be leaked if the element never gets instantiated */ - GST_MINI_OBJECT_FLAG_SET (sink_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED); - GST_MINI_OBJECT_FLAG_SET (src_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED); - - type_name = g_strdup ("GstNvH264Enc"); - feature_name = g_strdup ("nvh264enc"); - - if (g_type_from_name (type_name) != 0) { - g_free (type_name); - g_free (feature_name); - type_name = g_strdup_printf ("GstNvH264Device%dEnc", device_id); - feature_name = g_strdup_printf ("nvh264device%denc", device_id); - is_default = FALSE; - } - - cdata->is_default = is_default; - type = g_type_register_static (parent_type, type_name, &type_info, 0); - - /* make lower rank than default device */ - if (rank > 0 && !is_default) - rank--; - - if (!gst_element_register (plugin, feature_name, rank, type)) - GST_WARNING ("Failed to register plugin '%s'", type_name); - - g_free (type_name); - g_free (feature_name); -} diff --git a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvh264enc.h b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvh264enc.h deleted file mode 100644 index 882fd11f66..0000000000 --- a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvh264enc.h +++ /dev/null @@ -1,43 +0,0 @@ -/* GStreamer NVENC plugin - * Copyright (C) 2015 Centricular Ltd - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef __GST_NV_H264_ENC_H_INCLUDED__ -#define __GST_NV_H264_ENC_H_INCLUDED__ - -#include "gstnvbaseenc.h" - -typedef struct { - GstNvBaseEnc base_nvenc; - /* properties */ - gboolean aud; -} GstNvH264Enc; - -typedef struct { - GstNvBaseEncClass video_encoder_class; -} GstNvH264EncClass; - -void gst_nv_h264_enc_register (GstPlugin * plugin, - guint device_id, - guint rank, - GstCaps * sink_caps, - GstCaps * src_caps, - GstNvEncDeviceCaps * device_caps); - - -#endif /* __GST_NV_H264_ENC_H_INCLUDED__ */ diff --git a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvh265enc.c b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvh265enc.c deleted file mode 100644 index df0bdf55d8..0000000000 --- a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvh265enc.c +++ /dev/null @@ -1,861 +0,0 @@ -/* GStreamer NVENC plugin - * Copyright (C) 2015 Centricular Ltd - * Copyright (C) 2018 Seungha Yang - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gstnvh265enc.h" - -#include -#include - -#include - -typedef struct -{ - GstCaps *sink_caps; - GstCaps *src_caps; - gboolean is_default; -} GstNvH265EncClassData; - -GST_DEBUG_CATEGORY_STATIC (gst_nv_h265_enc_debug); -#define GST_CAT_DEFAULT gst_nv_h265_enc_debug - -static GstElementClass *parent_class = NULL; - -enum -{ - PROP_0, - PROP_AUD, - PROP_WEIGHTED_PRED, - PROP_VBV_BUFFER_SIZE, - PROP_RC_LOOKAHEAD, - PROP_TEMPORAL_AQ, - PROP_BFRAMES, - PROP_B_ADAPT, -}; - -#define DEFAULT_AUD TRUE -#define DEFAULT_WEIGHTED_PRED FALSE -#define DEFAULT_VBV_BUFFER_SIZE 0 -#define DEFAULT_RC_LOOKAHEAD 0 -#define DEFAULT_TEMPORAL_AQ FALSE -#define DEFAULT_BFRAMES 0 -#define DEFAULT_B_ADAPT FALSE - -/* captured using RTX 2080 */ -#define DOCUMENTATION_SINK_CAPS_COMM \ - "format = (string) { NV12, P010_10LE, P016_LE, Y444, Y444_16LE, Y444_16LE }, " \ - "width = (int) [ 144, 8192 ], " \ - "height = (int) [ 144, 8192 ], " \ - "framerate = " GST_VIDEO_FPS_RANGE - -#define DOCUMENTATION_SINK_CAPS \ - "video/x-raw, " DOCUMENTATION_SINK_CAPS_COMM "; " \ - "video/x-raw(memory:GLMemory), " DOCUMENTATION_SINK_CAPS_COMM "; " \ - "video/x-raw(memory:CUDAMemory), " DOCUMENTATION_SINK_CAPS_COMM - -#define DOCUMENTATION_SRC_CAPS \ - "video/x-h265, " \ - "width = (int) [ 144, 8192 ], " \ - "height = (int) [ 144, 8192 ], " \ - "stream-format = (string) byte-stream, " \ - "alignment = (string) au, " \ - "profile = (string) { main, main-10, main-12, main-444, main-444-10, main-444-12 }" - -static gboolean gst_nv_h265_enc_open (GstVideoEncoder * enc); -static gboolean gst_nv_h265_enc_close (GstVideoEncoder * enc); -static gboolean gst_nv_h265_enc_stop (GstVideoEncoder * enc); -static gboolean gst_nv_h265_enc_set_src_caps (GstNvBaseEnc * nvenc, - GstVideoCodecState * state); -static gboolean gst_nv_h265_enc_set_encoder_config (GstNvBaseEnc * nvenc, - GstVideoCodecState * state, NV_ENC_CONFIG * config); -static gboolean gst_nv_h265_enc_set_pic_params (GstNvBaseEnc * nvenc, - GstVideoCodecFrame * frame, NV_ENC_PIC_PARAMS * pic_params); -static void gst_nv_h265_enc_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_nv_h265_enc_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); -static void gst_nv_h265_enc_finalize (GObject * obj); - -static void -gst_nv_h265_enc_class_init (GstNvH265EncClass * klass, gpointer data) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - GstVideoEncoderClass *videoenc_class = GST_VIDEO_ENCODER_CLASS (klass); - GstNvBaseEncClass *nvenc_class = GST_NV_BASE_ENC_CLASS (klass); - GstNvEncDeviceCaps *device_caps = &nvenc_class->device_caps; - GstNvH265EncClassData *cdata = (GstNvH265EncClassData *) data; - gchar *long_name; - GstPadTemplate *pad_templ; - GstCaps *doc_caps; - - parent_class = g_type_class_peek_parent (klass); - - gobject_class->set_property = gst_nv_h265_enc_set_property; - gobject_class->get_property = gst_nv_h265_enc_get_property; - gobject_class->finalize = gst_nv_h265_enc_finalize; - - videoenc_class->open = GST_DEBUG_FUNCPTR (gst_nv_h265_enc_open); - videoenc_class->close = GST_DEBUG_FUNCPTR (gst_nv_h265_enc_close); - videoenc_class->stop = GST_DEBUG_FUNCPTR (gst_nv_h265_enc_stop); - - nvenc_class->codec_id = NV_ENC_CODEC_HEVC_GUID; - nvenc_class->set_encoder_config = gst_nv_h265_enc_set_encoder_config; - nvenc_class->set_src_caps = gst_nv_h265_enc_set_src_caps; - nvenc_class->set_pic_params = gst_nv_h265_enc_set_pic_params; - - /** - * GstNvH265Enc:aud: - * - * Use AU (Access Unit) delimiter - * - * Since: 1.18 - */ - g_object_class_install_property (gobject_class, PROP_AUD, - g_param_spec_boolean ("aud", "AUD", - "Use AU (Access Unit) delimiter", DEFAULT_AUD, - G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING | - G_PARAM_STATIC_STRINGS)); - - if (device_caps->weighted_prediction) { - /** - * GstNvH265Enc:weighted-pred: - * - * Weighted Prediction - * - * Since: 1.18 - */ - g_object_class_install_property (gobject_class, PROP_WEIGHTED_PRED, - g_param_spec_boolean ("weighted-pred", "Weighted Pred", - "Weighted Prediction", DEFAULT_WEIGHTED_PRED, - G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING | - GST_PARAM_CONDITIONALLY_AVAILABLE | G_PARAM_STATIC_STRINGS)); - } - - if (device_caps->custom_vbv_bufsize) { - /** - * GstNvH265Enc:vbv-buffer-size: - * - * VBV(HRD) Buffer Size in kbits (0 = NVENC default) - * - * Since: 1.18 - */ - g_object_class_install_property (gobject_class, - PROP_VBV_BUFFER_SIZE, - g_param_spec_uint ("vbv-buffer-size", "VBV Buffer Size", - "VBV(HRD) Buffer Size in kbits (0 = NVENC default)", - 0, G_MAXUINT, DEFAULT_VBV_BUFFER_SIZE, - G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY | - GST_PARAM_CONDITIONALLY_AVAILABLE | G_PARAM_STATIC_STRINGS)); - } - - if (device_caps->lookahead) { - /** - * GstNvH265Enc:rc-lookahead: - * - * Number of frames for frame type lookahead - * - * Since: 1.18 - */ - g_object_class_install_property (gobject_class, PROP_RC_LOOKAHEAD, - g_param_spec_uint ("rc-lookahead", "Rate Control Lookahead", - "Number of frames for frame type lookahead", 0, 32, - DEFAULT_RC_LOOKAHEAD, - G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY | - GST_PARAM_CONDITIONALLY_AVAILABLE | G_PARAM_STATIC_STRINGS)); - } - - if (device_caps->temporal_aq) { - /** - * GstNvH265Enc:temporal-aq: - * - * Temporal Adaptive Quantization - * - * Since: 1.18 - */ - g_object_class_install_property (gobject_class, PROP_TEMPORAL_AQ, - g_param_spec_boolean ("temporal-aq", "Temporal AQ", - "Temporal Adaptive Quantization", DEFAULT_TEMPORAL_AQ, - G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING | - GST_PARAM_CONDITIONALLY_AVAILABLE | G_PARAM_STATIC_STRINGS)); - } - - if (device_caps->bframes > 0) { - /** - * GstNvH265Enc:bframes: - * - * Number of B-frames between I and P - * - * Since: 1.18 - */ - g_object_class_install_property (gobject_class, PROP_BFRAMES, - g_param_spec_uint ("bframes", "B-Frames", - "Number of B-frames between I and P", 0, device_caps->bframes, - DEFAULT_BFRAMES, - G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY | - GST_PARAM_CONDITIONALLY_AVAILABLE | G_PARAM_STATIC_STRINGS)); - - /** - * GstNvH265Enc:b-adapt: - * - * Enable adaptive B-frame insert when lookahead is enabled - * - * Since: 1.18 - */ - g_object_class_install_property (gobject_class, PROP_B_ADAPT, - g_param_spec_boolean ("b-adapt", "B Adapt", - "Enable adaptive B-frame insert when lookahead is enabled", - DEFAULT_B_ADAPT, - G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY | - GST_PARAM_CONDITIONALLY_AVAILABLE | G_PARAM_STATIC_STRINGS)); - } - - if (cdata->is_default) - long_name = g_strdup ("NVENC HEVC Video Encoder"); - else - long_name = g_strdup_printf ("NVENC HEVC Video Encoder with device %d", - nvenc_class->cuda_device_id); - - gst_element_class_set_metadata (element_class, long_name, - "Codec/Encoder/Video/Hardware", - "Encode HEVC video streams using NVIDIA's hardware-accelerated NVENC encoder API", - "Tim-Philipp Müller , " - "Matthew Waters , " - "Seungha Yang "); - g_free (long_name); - - GST_DEBUG_CATEGORY_INIT (gst_nv_h265_enc_debug, - "nvh265enc", 0, "Nvidia HEVC encoder"); - - pad_templ = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - cdata->sink_caps); - doc_caps = gst_caps_from_string (DOCUMENTATION_SINK_CAPS); - gst_pad_template_set_documentation_caps (pad_templ, doc_caps); - gst_caps_unref (doc_caps); - gst_element_class_add_pad_template (element_class, pad_templ); - - pad_templ = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, - cdata->src_caps); - doc_caps = gst_caps_from_string (DOCUMENTATION_SRC_CAPS); - gst_pad_template_set_documentation_caps (pad_templ, doc_caps); - gst_caps_unref (doc_caps); - gst_element_class_add_pad_template (element_class, pad_templ); - - - gst_caps_unref (cdata->sink_caps); - gst_caps_unref (cdata->src_caps); - g_free (cdata); -} - -static void -gst_nv_h265_enc_init (GstNvH265Enc * nvenc) -{ - GstNvBaseEnc *baseenc = GST_NV_BASE_ENC (nvenc); - - nvenc->aud = DEFAULT_AUD; - - /* device capability dependent properties */ - baseenc->weighted_pred = DEFAULT_WEIGHTED_PRED; - baseenc->vbv_buffersize = DEFAULT_VBV_BUFFER_SIZE; - baseenc->rc_lookahead = DEFAULT_RC_LOOKAHEAD; - baseenc->temporal_aq = DEFAULT_TEMPORAL_AQ; - baseenc->bframes = DEFAULT_BFRAMES; - baseenc->b_adapt = DEFAULT_B_ADAPT; -} - -static void -gst_nv_h265_enc_finalize (GObject * obj) -{ - G_OBJECT_CLASS (parent_class)->finalize (obj); -} - -static gboolean -gst_nv_h265_enc_open (GstVideoEncoder * enc) -{ - GstNvBaseEnc *base = GST_NV_BASE_ENC (enc); - - if (!GST_VIDEO_ENCODER_CLASS (parent_class)->open (enc)) - return FALSE; - - /* Check if HEVC is supported */ - { - uint32_t i, num = 0; - GUID guids[16]; - - NvEncGetEncodeGUIDs (base->encoder, guids, G_N_ELEMENTS (guids), &num); - - for (i = 0; i < num; ++i) { - if (gst_nvenc_cmp_guid (guids[i], NV_ENC_CODEC_HEVC_GUID)) - break; - } - GST_INFO_OBJECT (enc, "HEVC encoding %ssupported", (i == num) ? "un" : ""); - if (i == num) { - gst_nv_h265_enc_close (enc); - return FALSE; - } - } - - return TRUE; -} - -static gboolean -gst_nv_h265_enc_close (GstVideoEncoder * enc) -{ - return GST_VIDEO_ENCODER_CLASS (parent_class)->close (enc); -} - -static void -gst_nv_h265_enc_clear_stream_data (GstNvH265Enc * h265enc) -{ - gint i; - - if (!h265enc->sei_payload) - return; - - for (i = 0; i < h265enc->num_sei_payload; i++) - g_free (h265enc->sei_payload[i].payload); - - g_free (h265enc->sei_payload); - h265enc->sei_payload = NULL; - h265enc->num_sei_payload = 0; -} - -static gboolean -gst_nv_h265_enc_stop (GstVideoEncoder * enc) -{ - GstNvH265Enc *h265enc = (GstNvH265Enc *) enc; - - gst_nv_h265_enc_clear_stream_data (h265enc); - - return GST_VIDEO_ENCODER_CLASS (parent_class)->stop (enc); -} - -static gboolean -gst_nv_h265_enc_set_level_tier_and_profile (GstNvH265Enc * nvenc, - GstCaps * caps) -{ -#define N_BYTES_VPS 128 - guint8 vps[N_BYTES_VPS]; - NV_ENC_SEQUENCE_PARAM_PAYLOAD spp = { 0, }; - NVENCSTATUS nv_ret; - guint32 seq_size; - - spp.version = gst_nvenc_get_sequence_param_payload_version (); - spp.inBufferSize = N_BYTES_VPS; - spp.spsId = 0; - spp.ppsId = 0; - spp.spsppsBuffer = &vps; - spp.outSPSPPSPayloadSize = &seq_size; - nv_ret = NvEncGetSequenceParams (GST_NV_BASE_ENC (nvenc)->encoder, &spp); - if (nv_ret != NV_ENC_SUCCESS) { - GST_ELEMENT_ERROR (nvenc, STREAM, ENCODE, ("Encode header failed."), - ("NvEncGetSequenceParams return code=%d", nv_ret)); - return FALSE; - } - - if (seq_size < 8) { - GST_ELEMENT_ERROR (nvenc, STREAM, ENCODE, ("Encode header failed."), - ("NvEncGetSequenceParams returned incomplete data")); - return FALSE; - } - - GST_MEMDUMP ("Header", spp.spsppsBuffer, seq_size); - - /* skip nal header and identifier */ - gst_codec_utils_h265_caps_set_level_tier_and_profile (caps, - &vps[6], seq_size - 6); - - return TRUE; - -#undef N_BYTES_VPS -} - -static gboolean -gst_nv_h265_enc_set_src_caps (GstNvBaseEnc * nvenc, GstVideoCodecState * state) -{ - GstNvH265Enc *h265enc = (GstNvH265Enc *) nvenc; - GstVideoCodecState *out_state; - GstStructure *s; - GstCaps *out_caps; - - out_caps = gst_caps_new_empty_simple ("video/x-h265"); - s = gst_caps_get_structure (out_caps, 0); - - /* TODO: add support for hvc1,hev1 format as well */ - gst_structure_set (s, "stream-format", G_TYPE_STRING, "byte-stream", - "alignment", G_TYPE_STRING, "au", NULL); - - if (!gst_nv_h265_enc_set_level_tier_and_profile (h265enc, out_caps)) { - gst_caps_unref (out_caps); - return FALSE; - } - - out_state = gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (nvenc), - out_caps, state); - - GST_INFO_OBJECT (nvenc, "output caps: %" GST_PTR_FORMAT, out_state->caps); - - /* encoder will keep it around for us */ - gst_video_codec_state_unref (out_state); - - /* TODO: would be nice to also send some tags with the codec name */ - return TRUE; -} - -static guint8 * -gst_nv_h265_enc_create_mastering_display_sei_nal (GstNvH265Enc * h265enc, - GstVideoMasteringDisplayInfo * minfo, guint * size) -{ - guint sei_size; - gint i; - GstByteWriter br; - - GST_LOG_OBJECT (h265enc, "Apply mastering display info: " - "Red(%u, %u) " - "Green(%u, %u) " - "Blue(%u, %u) " - "White(%u, %u) " - "max_luminance(%u) " - "min_luminance(%u) ", - minfo->display_primaries[0].x, minfo->display_primaries[0].y, - minfo->display_primaries[1].x, minfo->display_primaries[1].y, - minfo->display_primaries[2].x, minfo->display_primaries[2].y, - minfo->white_point.x, minfo->white_point.y, - minfo->max_display_mastering_luminance, - minfo->min_display_mastering_luminance); - - /* x, y 16bits per RGB channel - * x, y 16bits white point - * max, min luminance 32bits - */ - sei_size = (2 * 2 * 3) + (2 * 2) + (4 * 2); - gst_byte_writer_init_with_size (&br, sei_size, TRUE); - - /* GstVideoMasteringDisplayInfo::display_primaries is rgb order but - * HEVC uses gbr order - * See spec D.3.28 display_primaries_x and display_primaries_y - */ - for (i = 0; i < 3; i++) { - gst_byte_writer_put_uint16_be (&br, - minfo->display_primaries[(i + 1) % 3].x); - gst_byte_writer_put_uint16_be (&br, - minfo->display_primaries[(i + 1) % 3].y); - } - - gst_byte_writer_put_uint16_be (&br, minfo->white_point.x); - gst_byte_writer_put_uint16_be (&br, minfo->white_point.y); - - gst_byte_writer_put_uint32_be (&br, minfo->max_display_mastering_luminance); - gst_byte_writer_put_uint32_be (&br, minfo->min_display_mastering_luminance); - - *size = sei_size; - - return gst_byte_writer_reset_and_get_data (&br); -} - -static guint8 * -gst_nv_h265_enc_create_content_light_level_sei_nal (GstNvH265Enc * h265enc, - GstVideoContentLightLevel * linfo, guint * size) -{ - guint sei_size; - GstByteWriter br; - - GST_LOG_OBJECT (h265enc, "Apply content light level: " - "maxCLL:(%u), maxFALL:(%u)", linfo->max_content_light_level, - linfo->max_frame_average_light_level); - - /* maxCLL and maxFALL per 16bits */ - sei_size = 2 * 2; - gst_byte_writer_init_with_size (&br, sei_size, TRUE); - - gst_byte_writer_put_uint16_be (&br, linfo->max_content_light_level); - gst_byte_writer_put_uint16_be (&br, linfo->max_frame_average_light_level); - - *size = sei_size; - - return gst_byte_writer_reset_and_get_data (&br); -} - -static gboolean -gst_nv_h265_enc_set_encoder_config (GstNvBaseEnc * nvenc, - GstVideoCodecState * state, NV_ENC_CONFIG * config) -{ - GstNvH265Enc *h265enc = (GstNvH265Enc *) nvenc; - GstCaps *allowed_caps, *template_caps; - GUID selected_profile = NV_ENC_CODEC_PROFILE_AUTOSELECT_GUID; - int level_idc = NV_ENC_LEVEL_AUTOSELECT; - GstVideoInfo *info = &state->info; - NV_ENC_CONFIG_HEVC *hevc_config = &config->encodeCodecConfig.hevcConfig; - NV_ENC_CONFIG_HEVC_VUI_PARAMETERS *vui = &hevc_config->hevcVUIParameters; - - template_caps = - gst_pad_get_pad_template_caps (GST_VIDEO_ENCODER_SRC_PAD (h265enc)); - allowed_caps = gst_pad_get_allowed_caps (GST_VIDEO_ENCODER_SRC_PAD (h265enc)); - - if (template_caps == allowed_caps) { - GST_INFO_OBJECT (h265enc, "downstream has ANY caps"); - } else if (allowed_caps) { - GstStructure *s; - const gchar *profile; - const gchar *level; - - if (gst_caps_is_empty (allowed_caps)) { - gst_caps_unref (allowed_caps); - gst_caps_unref (template_caps); - return FALSE; - } - - allowed_caps = gst_caps_make_writable (allowed_caps); - allowed_caps = gst_caps_fixate (allowed_caps); - s = gst_caps_get_structure (allowed_caps, 0); - - profile = gst_structure_get_string (s, "profile"); - /* FIXME: only support main profile only for now */ - if (profile) { - if (!strcmp (profile, "main")) { - selected_profile = NV_ENC_HEVC_PROFILE_MAIN_GUID; - } else if (g_str_has_prefix (profile, "main-10")) { - selected_profile = NV_ENC_HEVC_PROFILE_MAIN10_GUID; - } else if (g_str_has_prefix (profile, "main-444")) { - selected_profile = NV_ENC_HEVC_PROFILE_FREXT_GUID; - } else { - g_assert_not_reached (); - } - } - - level = gst_structure_get_string (s, "level"); - if (level) - /* matches values stored in NV_ENC_LEVEL */ - level_idc = gst_codec_utils_h265_get_level_idc (level); - - gst_caps_unref (allowed_caps); - } - gst_caps_unref (template_caps); - - /* override some defaults */ - GST_LOG_OBJECT (h265enc, "setting parameters"); - config->profileGUID = selected_profile; - hevc_config->level = level_idc; - hevc_config->idrPeriod = config->gopLength; - - config->encodeCodecConfig.hevcConfig.chromaFormatIDC = 1; - if (GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_Y444 || - GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_Y444_16LE || - GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_Y444_16BE || - GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_VUYA) { - GST_DEBUG_OBJECT (h265enc, "have Y444 input, setting config accordingly"); - config->profileGUID = NV_ENC_HEVC_PROFILE_FREXT_GUID; - config->encodeCodecConfig.hevcConfig.chromaFormatIDC = 3; - if (GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_Y444_16LE || - GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_Y444_16BE) - config->encodeCodecConfig.hevcConfig.pixelBitDepthMinus8 = 2; -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - } else if (GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_P010_10LE) { -#else - } else if (GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_P010_10BE) { -#endif - config->profileGUID = NV_ENC_HEVC_PROFILE_MAIN10_GUID; - config->encodeCodecConfig.hevcConfig.pixelBitDepthMinus8 = 2; - } - - hevc_config->outputAUD = h265enc->aud; - - vui->videoSignalTypePresentFlag = 1; - /* NOTE: vui::video_format represents the video format before - * being encoded such as PAL, NTSC, SECAM, and MAC. That's not much informal - * and can be inferred with resolution and framerate by any application. - */ - /* Unspecified video format (5) */ - vui->videoFormat = 5; - - if (info->colorimetry.range == GST_VIDEO_COLOR_RANGE_0_255) { - vui->videoFullRangeFlag = 1; - } else { - vui->videoFullRangeFlag = 0; - } - - vui->colourDescriptionPresentFlag = 1; - vui->colourMatrix = gst_video_color_matrix_to_iso (info->colorimetry.matrix); - vui->colourPrimaries = - gst_video_color_primaries_to_iso (info->colorimetry.primaries); - vui->transferCharacteristics = - gst_video_transfer_function_to_iso (info->colorimetry.transfer); - - gst_nv_h265_enc_clear_stream_data (h265enc); - - { - GstVideoMasteringDisplayInfo minfo; - GstVideoContentLightLevel linfo; - gboolean have_mastering; - gboolean have_cll; - guint size; - gint i = 0; - - have_mastering = - gst_video_mastering_display_info_from_caps (&minfo, state->caps); - have_cll = gst_video_content_light_level_from_caps (&linfo, state->caps); - - if (have_mastering) - h265enc->num_sei_payload++; - if (have_cll) - h265enc->num_sei_payload++; - - h265enc->sei_payload = - g_new0 (NV_ENC_SEI_PAYLOAD, h265enc->num_sei_payload); - - if (have_mastering) { - h265enc->sei_payload[i].payload = - gst_nv_h265_enc_create_mastering_display_sei_nal (h265enc, - &minfo, &size); - h265enc->sei_payload[i].payloadSize = size; - h265enc->sei_payload[i].payloadType = 137; - i++; - } - - if (have_cll) { - h265enc->sei_payload[i].payload = - gst_nv_h265_enc_create_content_light_level_sei_nal (h265enc, - &linfo, &size); - h265enc->sei_payload[i].payloadSize = size; - h265enc->sei_payload[i].payloadType = 144; - } - } - - return TRUE; -} - -static gboolean -gst_nv_h265_enc_set_pic_params (GstNvBaseEnc * enc, GstVideoCodecFrame * frame, - NV_ENC_PIC_PARAMS * pic_params) -{ - GstNvH265Enc *h265enc = (GstNvH265Enc *) enc; - - /* encode whole picture in one single slice */ - pic_params->codecPicParams.hevcPicParams.sliceMode = 0; - pic_params->codecPicParams.hevcPicParams.sliceModeData = 0; - - if (h265enc->sei_payload) { - pic_params->codecPicParams.hevcPicParams.seiPayloadArray = - h265enc->sei_payload; - pic_params->codecPicParams.hevcPicParams.seiPayloadArrayCnt = - h265enc->num_sei_payload; - } - - return TRUE; -} - -static void -gst_nv_h265_enc_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstNvH265Enc *self = (GstNvH265Enc *) object; - GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (object); - GstNvBaseEncClass *klass = GST_NV_BASE_ENC_GET_CLASS (object); - GstNvEncDeviceCaps *device_caps = &klass->device_caps; - gboolean reconfig = FALSE; - - switch (prop_id) { - case PROP_AUD: - { - gboolean aud; - - aud = g_value_get_boolean (value); - if (aud != self->aud) { - self->aud = aud; - reconfig = TRUE; - } - break; - } - case PROP_WEIGHTED_PRED: - if (!device_caps->weighted_prediction) { - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } else { - nvenc->weighted_pred = g_value_get_boolean (value); - reconfig = TRUE; - } - break; - case PROP_VBV_BUFFER_SIZE: - if (!device_caps->custom_vbv_bufsize) { - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } else { - nvenc->vbv_buffersize = g_value_get_uint (value); - reconfig = TRUE; - } - break; - case PROP_RC_LOOKAHEAD: - if (!device_caps->lookahead) { - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } else { - nvenc->rc_lookahead = g_value_get_uint (value); - reconfig = TRUE; - } - break; - case PROP_TEMPORAL_AQ: - if (!device_caps->temporal_aq) { - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } else { - nvenc->temporal_aq = g_value_get_boolean (value); - reconfig = TRUE; - } - break; - case PROP_BFRAMES: - if (!device_caps->bframes) { - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } else { - nvenc->bframes = g_value_get_uint (value); - reconfig = TRUE; - } - break; - case PROP_B_ADAPT: - if (!device_caps->bframes) { - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } else { - nvenc->b_adapt = g_value_get_boolean (value); - } - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } - - if (reconfig) - gst_nv_base_enc_schedule_reconfig (GST_NV_BASE_ENC (self)); -} - -static void -gst_nv_h265_enc_get_property (GObject * object, guint prop_id, GValue * value, - GParamSpec * pspec) -{ - GstNvH265Enc *self = (GstNvH265Enc *) object; - GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (object); - GstNvBaseEncClass *klass = GST_NV_BASE_ENC_GET_CLASS (object); - GstNvEncDeviceCaps *device_caps = &klass->device_caps; - - switch (prop_id) { - case PROP_AUD: - g_value_set_boolean (value, self->aud); - break; - case PROP_WEIGHTED_PRED: - if (!device_caps->weighted_prediction) { - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } else { - g_value_set_boolean (value, nvenc->weighted_pred); - } - break; - case PROP_VBV_BUFFER_SIZE: - if (!device_caps->custom_vbv_bufsize) { - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } else { - g_value_set_uint (value, nvenc->vbv_buffersize); - } - break; - case PROP_RC_LOOKAHEAD: - if (!device_caps->lookahead) { - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } else { - g_value_set_uint (value, nvenc->rc_lookahead); - } - break; - case PROP_TEMPORAL_AQ: - if (!device_caps->temporal_aq) { - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } else { - g_value_set_boolean (value, nvenc->temporal_aq); - } - break; - case PROP_BFRAMES: - if (!device_caps->bframes) { - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } else { - g_value_set_uint (value, nvenc->bframes); - } - break; - case PROP_B_ADAPT: - if (!device_caps->bframes) { - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } else { - g_value_set_boolean (value, nvenc->b_adapt); - } - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -void -gst_nv_h265_enc_register (GstPlugin * plugin, guint device_id, guint rank, - GstCaps * sink_caps, GstCaps * src_caps, GstNvEncDeviceCaps * device_caps) -{ - GType parent_type; - GType type; - gchar *type_name; - gchar *feature_name; - GstNvH265EncClassData *cdata; - gboolean is_default = TRUE; - GTypeInfo type_info = { - sizeof (GstNvH265EncClass), - NULL, - NULL, - (GClassInitFunc) gst_nv_h265_enc_class_init, - NULL, - NULL, - sizeof (GstNvH265Enc), - 0, - (GInstanceInitFunc) gst_nv_h265_enc_init, - }; - - parent_type = gst_nv_base_enc_register ("H265", device_id, device_caps); - - cdata = g_new0 (GstNvH265EncClassData, 1); - cdata->sink_caps = gst_caps_ref (sink_caps); - cdata->src_caps = gst_caps_ref (src_caps); - type_info.class_data = cdata; - /* class data will be leaked if the element never gets instantiated */ - GST_MINI_OBJECT_FLAG_SET (sink_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED); - GST_MINI_OBJECT_FLAG_SET (src_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED); - - type_name = g_strdup ("GstNvH265Enc"); - feature_name = g_strdup ("nvh265enc"); - - if (g_type_from_name (type_name) != 0) { - g_free (type_name); - g_free (feature_name); - type_name = g_strdup_printf ("GstNvH265Device%dEnc", device_id); - feature_name = g_strdup_printf ("nvh265device%denc", device_id); - is_default = FALSE; - } - - cdata->is_default = is_default; - type = g_type_register_static (parent_type, type_name, &type_info, 0); - - /* make lower rank than default device */ - if (rank > 0 && !is_default) - rank--; - - if (!gst_element_register (plugin, feature_name, rank, type)) - GST_WARNING ("Failed to register plugin '%s'", type_name); - - g_free (type_name); - g_free (feature_name); -} diff --git a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvh265enc.h b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvh265enc.h deleted file mode 100644 index d1637973af..0000000000 --- a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvh265enc.h +++ /dev/null @@ -1,47 +0,0 @@ -/* GStreamer NVENC plugin - * Copyright (C) 2015 Centricular Ltd - * Copyright (C) 2018 Seungha Yang - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef __GST_NV_HEVC_ENC_H_INCLUDED__ -#define __GST_NV_HEVC_ENC_H_INCLUDED__ - -#include "gstnvbaseenc.h" - -typedef struct { - GstNvBaseEnc base_nvenc; - - NV_ENC_SEI_PAYLOAD *sei_payload; - guint num_sei_payload; - - /* properties */ - gboolean aud; -} GstNvH265Enc; - -typedef struct { - GstNvBaseEncClass video_encoder_class; -} GstNvH265EncClass; - -void gst_nv_h265_enc_register (GstPlugin * plugin, - guint device_id, - guint rank, - GstCaps * sink_caps, - GstCaps * src_caps, - GstNvEncDeviceCaps * device_caps); - -#endif /* __GST_NV_HEVC_ENC_H_INCLUDED__ */ diff --git a/subprojects/gst-plugins-bad/sys/nvcodec/meson.build b/subprojects/gst-plugins-bad/sys/nvcodec/meson.build index 6ade635a57..231e2cea05 100644 --- a/subprojects/gst-plugins-bad/sys/nvcodec/meson.build +++ b/subprojects/gst-plugins-bad/sys/nvcodec/meson.build @@ -10,7 +10,6 @@ nvcodec_sources = [ 'gstcudamemorycopy.c', 'gstcuvidloader.c', 'gstnvav1dec.cpp', - 'gstnvbaseenc.c', 'gstnvdec.c', 'gstnvdecobject.cpp', 'gstnvdecoder.cpp', @@ -18,10 +17,8 @@ nvcodec_sources = [ 'gstnvencobject.cpp', 'gstnvencoder.cpp', 'gstnvh264dec.cpp', - 'gstnvh264enc.c', 'gstnvh264encoder.cpp', 'gstnvh265dec.cpp', - 'gstnvh265enc.c', 'gstnvh265encoder.cpp', 'gstnvjpegenc.cpp', 'gstnvvp8dec.cpp', diff --git a/subprojects/gst-plugins-bad/sys/nvcodec/plugin.c b/subprojects/gst-plugins-bad/sys/nvcodec/plugin.c index 08cac8f34c..2c5ed5a59c 100644 --- a/subprojects/gst-plugins-bad/sys/nvcodec/plugin.c +++ b/subprojects/gst-plugins-bad/sys/nvcodec/plugin.c @@ -304,8 +304,6 @@ plugin_init (GstPlugin * plugin) gst_nv_h265_encoder_register_cuda (plugin, context, GST_RANK_NONE); if (cdata) h265_enc_cdata = g_list_append (h265_enc_cdata, cdata); - - gst_nvenc_plugin_init (plugin, i, cuda_ctx); } gst_nv_jpeg_enc_register (plugin, context, GST_RANK_NONE, have_nvrtc);