• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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