1 /*
2 * Copyright (C) 2017 Ericsson AB. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32 #include "gstnvdec.h"
33 #include "gstnvenc.h"
34 #include "gstnvh264dec.h"
35 #include "gstnvh265dec.h"
36 #include "gstnvvp8dec.h"
37 #include "gstnvvp9dec.h"
38 #include "gstnvdecoder.h"
39 #include "gstcudadownload.h"
40 #include "gstcudaupload.h"
41 #include "gstcudafilter.h"
42
43 GST_DEBUG_CATEGORY (gst_nvcodec_debug);
44 GST_DEBUG_CATEGORY (gst_nvdec_debug);
45 GST_DEBUG_CATEGORY (gst_nvenc_debug);
46 GST_DEBUG_CATEGORY (gst_nv_decoder_debug);
47
48 #define GST_CAT_DEFAULT gst_nvcodec_debug
49
50 static gboolean
plugin_init(GstPlugin * plugin)51 plugin_init (GstPlugin * plugin)
52 {
53 CUresult cuda_ret;
54 gint dev_count = 0;
55 gint i;
56 gboolean nvdec_available = TRUE;
57 gboolean nvenc_available = TRUE;
58 /* hardcoded minimum supported version */
59 guint api_major_ver = 8;
60 guint api_minor_ver = 1;
61 const gchar *env;
62 gboolean use_h264_sl_dec = FALSE;
63 gboolean use_h265_sl_dec = FALSE;
64 gboolean use_vp8_sl_dec = FALSE;
65 gboolean use_vp9_sl_dec = FALSE;
66
67 GST_DEBUG_CATEGORY_INIT (gst_nvcodec_debug, "nvcodec", 0, "nvcodec");
68 GST_DEBUG_CATEGORY_INIT (gst_nvdec_debug, "nvdec", 0, "nvdec");
69 GST_DEBUG_CATEGORY_INIT (gst_nvenc_debug, "nvenc", 0, "nvenc");
70 GST_DEBUG_CATEGORY_INIT (gst_nv_decoder_debug, "nvdecoder", 0, "nvdecoder");
71
72 if (!gst_cuda_load_library ()) {
73 GST_WARNING ("Failed to load cuda library");
74 return TRUE;
75 }
76
77 /* get available API version from nvenc and it will be passed to
78 * nvdec */
79 if (!gst_nvenc_load_library (&api_major_ver, &api_minor_ver)) {
80 GST_WARNING ("Failed to load nvenc library");
81 nvenc_available = FALSE;
82 }
83
84 if (!gst_cuvid_load_library (api_major_ver, api_minor_ver)) {
85 GST_WARNING ("Failed to load nvdec library");
86 nvdec_available = FALSE;
87 }
88
89 if (!nvdec_available && !nvenc_available)
90 return TRUE;
91
92 cuda_ret = CuInit (0);
93 if (cuda_ret != CUDA_SUCCESS) {
94 GST_WARNING ("Failed to init cuda, ret: 0x%x", (gint) cuda_ret);
95 return TRUE;
96 }
97
98 if (CuDeviceGetCount (&dev_count) != CUDA_SUCCESS || !dev_count) {
99 GST_WARNING ("No available device, ret: 0x%x", (gint) cuda_ret);
100 return TRUE;
101 }
102
103 /* check environment to determine primary h264decoder */
104 env = g_getenv ("GST_USE_NV_STATELESS_CODEC");
105 if (env) {
106 gchar **split;
107 gchar **iter;
108
109 split = g_strsplit (env, ",", 0);
110
111 for (iter = split; *iter; iter++) {
112 if (g_ascii_strcasecmp (*iter, "h264") == 0) {
113 GST_INFO ("Found %s in GST_USE_NV_STATELESS_CODEC environment", *iter);
114 use_h264_sl_dec = TRUE;
115 } else if (g_ascii_strcasecmp (*iter, "h265") == 0) {
116 GST_INFO ("Found %s in GST_USE_NV_STATELESS_CODEC environment", *iter);
117 use_h265_sl_dec = TRUE;
118 } else if (g_ascii_strcasecmp (*iter, "vp8") == 0) {
119 GST_INFO ("Found %s in GST_USE_NV_STATELESS_CODEC environment", *iter);
120 use_vp8_sl_dec = TRUE;
121 } else if (g_ascii_strcasecmp (*iter, "vp9") == 0) {
122 GST_INFO ("Found %s in GST_USE_NV_STATELESS_CODEC environment", *iter);
123 use_vp9_sl_dec = TRUE;
124 }
125 }
126
127 g_strfreev (split);
128 }
129
130 for (i = 0; i < dev_count; i++) {
131 CUdevice cuda_device;
132 CUcontext cuda_ctx;
133
134 cuda_ret = CuDeviceGet (&cuda_device, i);
135 if (cuda_ret != CUDA_SUCCESS) {
136 GST_WARNING ("Failed to get device handle %d, ret: 0x%x", i,
137 (gint) cuda_ret);
138 continue;
139 }
140
141 cuda_ret = CuCtxCreate (&cuda_ctx, 0, cuda_device);
142 if (cuda_ret != CUDA_SUCCESS) {
143 GST_WARNING ("Failed to create cuda context, ret: 0x%x", (gint) cuda_ret);
144 continue;
145 }
146
147 CuCtxPopCurrent (NULL);
148
149 if (nvdec_available) {
150 gint j;
151
152 for (j = 0; j < cudaVideoCodec_NumCodecs; j++) {
153 GstCaps *sink_template = NULL;
154 GstCaps *src_template = NULL;
155 cudaVideoCodec codec = (cudaVideoCodec) j;
156 gboolean register_cuviddec = TRUE;
157
158 if (gst_nv_decoder_check_device_caps (cuda_ctx,
159 codec, &sink_template, &src_template)) {
160 const gchar *codec_name = gst_cuda_video_codec_to_string (codec);
161
162 GST_INFO ("CUDA video codec %s, sink template %" GST_PTR_FORMAT
163 "src template %" GST_PTR_FORMAT, codec_name,
164 sink_template, src_template);
165
166 switch (codec) {
167 case cudaVideoCodec_H264:
168 gst_nv_h264_dec_register (plugin,
169 i, GST_RANK_SECONDARY, sink_template, src_template, FALSE);
170 if (use_h264_sl_dec) {
171 GST_INFO
172 ("Skipping registration of CUVID parser based nvh264dec element");
173 register_cuviddec = FALSE;
174
175 gst_nv_h264_dec_register (plugin,
176 i, GST_RANK_PRIMARY, sink_template, src_template, TRUE);
177 }
178 break;
179 case cudaVideoCodec_HEVC:
180 gst_nv_h265_dec_register (plugin,
181 i, GST_RANK_SECONDARY, sink_template, src_template, FALSE);
182 if (use_h265_sl_dec) {
183 GST_INFO
184 ("Skipping registration of CUVID parser based nvh265dec element");
185 register_cuviddec = FALSE;
186
187 gst_nv_h265_dec_register (plugin,
188 i, GST_RANK_PRIMARY, sink_template, src_template, TRUE);
189 }
190 break;
191 case cudaVideoCodec_VP8:
192 gst_nv_vp8_dec_register (plugin,
193 i, GST_RANK_SECONDARY, sink_template, src_template, FALSE);
194 if (use_vp8_sl_dec) {
195 GST_INFO
196 ("Skipping registration of CUVID parser based nvhvp8dec element");
197 register_cuviddec = FALSE;
198
199 gst_nv_vp8_dec_register (plugin,
200 i, GST_RANK_PRIMARY, sink_template, src_template, TRUE);
201 }
202 break;
203 case cudaVideoCodec_VP9:
204 gst_nv_vp9_dec_register (plugin,
205 i, GST_RANK_SECONDARY, sink_template, src_template, FALSE);
206 if (use_vp9_sl_dec) {
207 GST_INFO ("Skip register cuvid parser based nvhvp9dec");
208 register_cuviddec = FALSE;
209
210 gst_nv_vp9_dec_register (plugin,
211 i, GST_RANK_PRIMARY, sink_template, src_template, TRUE);
212 }
213 break;
214 default:
215 break;
216 }
217
218 if (register_cuviddec) {
219 gst_nvdec_plugin_init (plugin,
220 i, codec, codec_name, sink_template, src_template);
221 }
222
223 gst_caps_unref (sink_template);
224 gst_caps_unref (src_template);
225 }
226 }
227 }
228
229 if (nvenc_available)
230 gst_nvenc_plugin_init (plugin, i, cuda_ctx);
231
232 CuCtxDestroy (cuda_ctx);
233 }
234
235 gst_element_register (plugin, "cudadownload", GST_RANK_NONE,
236 GST_TYPE_CUDA_DOWNLOAD);
237 gst_element_register (plugin, "cudaupload", GST_RANK_NONE,
238 GST_TYPE_CUDA_UPLOAD);
239
240 gst_cuda_filter_plugin_init (plugin);
241
242 return TRUE;
243 }
244
245 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, nvcodec,
246 "GStreamer NVCODEC plugin", plugin_init, VERSION, "LGPL",
247 GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
248