]> git.sesse.net Git - ffmpeg/blob - ffmpeg_cuvid.c
avcodec/nvenc: Bring encoder names in line with other encoders
[ffmpeg] / ffmpeg_cuvid.c
1 /*
2  * This file is part of FFmpeg.
3  *
4  * FFmpeg is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * FFmpeg is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with FFmpeg; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18
19 #include "libavutil/hwcontext.h"
20 #include "libavutil/hwcontext_cuda.h"
21
22 #include "ffmpeg.h"
23
24 #include <cuda.h>
25 #include <nvcuvid.h>
26
27 typedef struct CUVIDContext {
28     AVBufferRef *hw_frames_ctx;
29 } CUVIDContext;
30
31 static void cuvid_uninit(AVCodecContext *avctx)
32 {
33     InputStream  *ist = avctx->opaque;
34     CUVIDContext *ctx = ist->hwaccel_ctx;
35
36     if (ctx) {
37         av_buffer_unref(&ctx->hw_frames_ctx);
38         av_freep(&ctx);
39     }
40
41     av_buffer_unref(&ist->hw_frames_ctx);
42
43     ist->hwaccel_ctx = 0;
44     ist->hwaccel_uninit = 0;
45 }
46
47 int cuvid_init(AVCodecContext *avctx)
48 {
49     InputStream  *ist = avctx->opaque;
50     CUVIDContext *ctx = ist->hwaccel_ctx;
51
52     av_log(NULL, AV_LOG_TRACE, "Initializing cuvid hwaccel\n");
53
54     if (!ctx) {
55         av_log(NULL, AV_LOG_ERROR, "CUVID transcoding is not initialized. "
56                "-hwaccel cuvid should only be used for one-to-one CUVID transcoding "
57                "with no (software) filters.\n");
58         return AVERROR(EINVAL);
59     }
60
61     return 0;
62 }
63
64 static void cuvid_ctx_free(AVHWDeviceContext *ctx)
65 {
66     AVCUDADeviceContext *hwctx = ctx->hwctx;
67     cuCtxDestroy(hwctx->cuda_ctx);
68 }
69
70 int cuvid_transcode_init(OutputStream *ost)
71 {
72     InputStream *ist;
73     const enum AVPixelFormat *pix_fmt;
74     AVCUDADeviceContext *device_hwctx;
75     AVHWDeviceContext *device_ctx;
76     AVHWFramesContext *hwframe_ctx;
77     CUVIDContext *ctx = NULL;
78     CUdevice device;
79     CUcontext cuda_ctx = NULL;
80     CUcontext dummy;
81     CUresult err;
82     int ret = 0;
83
84     av_log(NULL, AV_LOG_TRACE, "Initializing cuvid transcoding\n");
85
86     if (ost->source_index < 0)
87         return 0;
88
89     ist = input_streams[ost->source_index];
90
91     /* check if the encoder supports CUVID */
92     if (!ost->enc->pix_fmts)
93         goto cancel;
94     for (pix_fmt = ost->enc->pix_fmts; *pix_fmt != AV_PIX_FMT_NONE; pix_fmt++)
95         if (*pix_fmt == AV_PIX_FMT_CUDA)
96             break;
97     if (*pix_fmt == AV_PIX_FMT_NONE)
98         goto cancel;
99
100     /* check if the decoder supports CUVID */
101     if (ist->hwaccel_id != HWACCEL_CUVID || !ist->dec || !ist->dec->pix_fmts)
102         goto cancel;
103     for (pix_fmt = ist->dec->pix_fmts; *pix_fmt != AV_PIX_FMT_NONE; pix_fmt++)
104         if (*pix_fmt == AV_PIX_FMT_CUDA)
105             break;
106     if (*pix_fmt == AV_PIX_FMT_NONE)
107         goto cancel;
108
109     av_log(NULL, AV_LOG_VERBOSE, "Setting up CUVID transcoding\n");
110
111     if (ist->hwaccel_ctx) {
112         ctx = ist->hwaccel_ctx;
113     } else {
114         ctx = av_mallocz(sizeof(*ctx));
115         if (!ctx) {
116             ret = AVERROR(ENOMEM);
117             goto error;
118         }
119     }
120
121     if (!hw_device_ctx) {
122         hw_device_ctx = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_CUDA);
123         if (!hw_device_ctx) {
124             av_log(NULL, AV_LOG_ERROR, "av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_CUDA) failed\n");
125             ret = AVERROR(ENOMEM);
126             goto error;
127         }
128
129         err = cuInit(0);
130         if (err != CUDA_SUCCESS) {
131             av_log(NULL, AV_LOG_ERROR, "Could not initialize the CUDA driver API\n");
132             ret = AVERROR_UNKNOWN;
133             goto error;
134         }
135
136         err = cuDeviceGet(&device, 0); ///TODO: Make device index configurable
137         if (err != CUDA_SUCCESS) {
138             av_log(NULL, AV_LOG_ERROR, "Could not get the device number %d\n", 0);
139             ret = AVERROR_UNKNOWN;
140             goto error;
141         }
142
143         err = cuCtxCreate(&cuda_ctx, CU_CTX_SCHED_BLOCKING_SYNC, device);
144         if (err != CUDA_SUCCESS) {
145             av_log(NULL, AV_LOG_ERROR, "Error creating a CUDA context\n");
146             ret = AVERROR_UNKNOWN;
147             goto error;
148         }
149
150         device_ctx = (AVHWDeviceContext*)hw_device_ctx->data;
151         device_ctx->free = cuvid_ctx_free;
152
153         device_hwctx = device_ctx->hwctx;
154         device_hwctx->cuda_ctx = cuda_ctx;
155
156         err = cuCtxPopCurrent(&dummy);
157         if (err != CUDA_SUCCESS) {
158             av_log(NULL, AV_LOG_ERROR, "cuCtxPopCurrent failed\n");
159             ret = AVERROR_UNKNOWN;
160             goto error;
161         }
162
163         ret = av_hwdevice_ctx_init(hw_device_ctx);
164         if (ret < 0) {
165             av_log(NULL, AV_LOG_ERROR, "av_hwdevice_ctx_init failed\n");
166             goto error;
167         }
168     } else {
169         device_ctx = (AVHWDeviceContext*)hw_device_ctx->data;
170         device_hwctx = device_ctx->hwctx;
171         cuda_ctx = device_hwctx->cuda_ctx;
172     }
173
174     if (device_ctx->type != AV_HWDEVICE_TYPE_CUDA) {
175         av_log(NULL, AV_LOG_ERROR, "Hardware device context is already initialized for a diffrent hwaccel.\n");
176         ret = AVERROR(EINVAL);
177         goto error;
178     }
179
180     if (!ctx->hw_frames_ctx) {
181         ctx->hw_frames_ctx = av_hwframe_ctx_alloc(hw_device_ctx);
182         if (!ctx->hw_frames_ctx) {
183             av_log(NULL, AV_LOG_ERROR, "av_hwframe_ctx_alloc failed\n");
184             ret = AVERROR(ENOMEM);
185             goto error;
186         }
187     }
188
189     /* This is a bit hacky, av_hwframe_ctx_init is called by the cuvid decoder
190      * once it has probed the neccesary format information. But as filters/nvenc
191      * need to know the format/sw_format, set them here so they are happy.
192      * This is fine as long as CUVID doesn't add another supported pix_fmt.
193      */
194     hwframe_ctx = (AVHWFramesContext*)ctx->hw_frames_ctx->data;
195     hwframe_ctx->format = AV_PIX_FMT_CUDA;
196     hwframe_ctx->sw_format = AV_PIX_FMT_NV12;
197
198     ost->hwaccel_ctx = ctx;
199     ost->enc_ctx->hw_frames_ctx = av_buffer_ref(ctx->hw_frames_ctx);
200     ost->enc_ctx->pix_fmt = AV_PIX_FMT_CUDA;
201
202     if (!ost->enc_ctx->hw_frames_ctx) {
203         av_log(NULL, AV_LOG_ERROR, "av_buffer_ref failed\n");
204         ret = AVERROR(ENOMEM);
205         goto error;
206     }
207
208     if (!ist->hwaccel_ctx) {
209         ist->hwaccel_ctx = ctx;
210         ist->hw_frames_ctx = av_buffer_ref(ctx->hw_frames_ctx);
211         ist->dec_ctx->hw_frames_ctx = av_buffer_ref(ctx->hw_frames_ctx);
212         ist->dec_ctx->pix_fmt = AV_PIX_FMT_CUDA;
213         ist->resample_pix_fmt = AV_PIX_FMT_CUDA;
214
215         ist->hwaccel_uninit = cuvid_uninit;
216
217         if (!ist->hw_frames_ctx || !ist->dec_ctx->hw_frames_ctx) {
218             av_log(NULL, AV_LOG_ERROR, "av_buffer_ref failed\n");
219             ret = AVERROR(ENOMEM);
220             goto error;
221         }
222     }
223
224     return 0;
225
226 error:
227     av_freep(&ctx);
228     return ret;
229
230 cancel:
231     if (ist->hwaccel_id == HWACCEL_CUVID) {
232         av_log(NULL, AV_LOG_ERROR, "CUVID hwaccel requested, but impossible to achive.\n");
233         return AVERROR(EINVAL);
234     }
235
236     return 0;
237 }