FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ffmpeg_cuvid.c
Go to the documentation of this file.
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"
21 
22 #include "ffmpeg.h"
23 
24 #include <cuda.h>
25 #include <nvcuvid.h>
26 
27 typedef struct CUVIDContext {
29 } CUVIDContext;
30 
31 static void cuvid_uninit(AVCodecContext *avctx)
32 {
33  InputStream *ist = avctx->opaque;
35 
36  if (ctx) {
38  av_freep(&ctx);
39  }
40 
42 
43  ist->hwaccel_ctx = 0;
44  ist->hwaccel_uninit = 0;
45 }
46 
48 {
49  InputStream *ist = avctx->opaque;
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 
65 {
66  AVCUDADeviceContext *hwctx = ctx->hwctx;
67  cuCtxDestroy(hwctx->cuda_ctx);
68 }
69 
71 {
72  InputStream *ist;
73  const enum AVPixelFormat *pix_fmt;
74  AVCUDADeviceContext *device_hwctx;
75  AVHWDeviceContext *device_ctx;
76  AVHWFramesContext *hwframe_ctx;
78  CUdevice device;
79  CUcontext cuda_ctx = NULL;
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) {
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 
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) {
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;
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;
214 
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 }
This struct aggregates all the (hardware/vendor-specific) "high-level" state, i.e.
Definition: hwcontext.h:53
AVBufferRef * hw_frames_ctx
Definition: ffmpeg_cuvid.c:28
#define NULL
Definition: coverity.c:32
static enum AVPixelFormat pix_fmt
void av_buffer_unref(AVBufferRef **buf)
Free a given reference and automatically free the buffer if there are no more references to it...
Definition: buffer.c:124
AVBufferRef * hw_frames_ctx
Definition: ffmpeg.h:342
int CUdevice
Definition: nvenc.h:44
void * hwaccel_ctx
Definition: ffmpeg.h:428
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:1877
enum AVPixelFormat format
The pixel format identifying the underlying HW surface type.
Definition: hwcontext.h:201
int cuvid_transcode_init(OutputStream *ost)
Definition: ffmpeg_cuvid.c:70
#define AV_LOG_TRACE
Extremely verbose debugging, useful for libav* development.
Definition: log.h:202
void * hwctx
The format-specific data, allocated and freed by libavutil along with this context.
Definition: hwcontext.h:84
static void cuvid_ctx_free(AVHWDeviceContext *ctx)
Definition: ffmpeg_cuvid.c:64
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:192
AVCodec * dec
Definition: ffmpeg.h:268
int resample_pix_fmt
Definition: ffmpeg.h:299
#define av_log(a,...)
An API-specific header for AV_HWDEVICE_TYPE_CUDA.
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
void(* free)(struct AVHWDeviceContext *ctx)
This field may be set by the caller before calling av_hwdevice_ctx_init().
Definition: hwcontext.h:96
void(* hwaccel_uninit)(AVCodecContext *s)
Definition: ffmpeg.h:337
#define AVERROR(e)
Definition: error.h:43
planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (firs...
Definition: pixfmt.h:90
enum AVHWDeviceType type
This field identifies the underlying API used for hardware access.
Definition: hwcontext.h:71
enum AVPixelFormat * pix_fmts
array of supported pixel formats, or NULL if unknown, array is terminated by -1
Definition: avcodec.h:3563
AVBufferRef * hw_frames_ctx
Encoding only.
Definition: avcodec.h:3495
AVFormatContext * ctx
Definition: movenc.c:48
CUresult
Definition: nvenc.h:41
int dummy
Definition: motion.c:64
HW acceleration through CUDA.
Definition: pixfmt.h:248
AVCodecContext * enc
Definition: muxing.c:55
AVBufferRef * av_hwdevice_ctx_alloc(enum AVHWDeviceType type)
Allocate an AVHWDeviceContext for a given pixel format.
Definition: hwcontext.c:71
main external API structure.
Definition: avcodec.h:1649
uint8_t * data
The data buffer.
Definition: buffer.h:89
AVCodecContext * enc_ctx
Definition: ffmpeg.h:420
int av_hwdevice_ctx_init(AVBufferRef *ref)
Finalize the device context before use.
Definition: hwcontext.c:129
This struct is allocated as AVHWDeviceContext.hwctx.
AVCodecContext * dec_ctx
Definition: ffmpeg.h:267
This struct describes a set or pool of "hardware" frames (i.e.
Definition: hwcontext.h:116
int cuvid_init(AVCodecContext *avctx)
Definition: ffmpeg_cuvid.c:47
int source_index
Definition: ffmpeg.h:406
A reference to a data buffer.
Definition: buffer.h:81
AVBufferRef * av_hwframe_ctx_alloc(AVBufferRef *device_ref_in)
Allocate an AVHWFramesContext tied to a given device context.
Definition: hwcontext.c:174
AVBufferRef * av_buffer_ref(AVBufferRef *buf)
Create a new reference to an AVBuffer.
Definition: buffer.c:92
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
Definition: error.h:71
AVBufferRef * hw_device_ctx
Definition: ffmpeg_opt.c:93
void * hwaccel_ctx
Definition: ffmpeg.h:336
#define av_freep(p)
static void cuvid_uninit(AVCodecContext *avctx)
Definition: ffmpeg_cuvid.c:31
void * CUcontext
Definition: nvenc.h:45
enum HWAccelID hwaccel_id
Definition: ffmpeg.h:330
enum AVPixelFormat sw_format
The pixel format identifying the actual data layout of the hardware frames.
Definition: hwcontext.h:214
AVPixelFormat
Pixel format.
Definition: pixfmt.h:60
void * av_mallocz(size_t size)
Allocate a block of size bytes with alignment suitable for all memory accesses (including vectors if ...
Definition: mem.c:252
void * opaque
Private data of the user, can be used to carry app specific stuff.
Definition: avcodec.h:1706
InputStream ** input_streams
Definition: ffmpeg.c:137