summaryrefslogtreecommitdiff
path: root/libavfilter/vf_hwupload_cuda.c (plain)
blob: ef98233d1260218e2e6e3d24ded41a0fd9e358d2
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/buffer.h"
20#include "libavutil/hwcontext.h"
21#include "libavutil/log.h"
22#include "libavutil/opt.h"
23
24#include "avfilter.h"
25#include "formats.h"
26#include "internal.h"
27#include "video.h"
28
29typedef struct CudaUploadContext {
30 const AVClass *class;
31 int device_idx;
32
33 AVBufferRef *hwdevice;
34 AVBufferRef *hwframe;
35} CudaUploadContext;
36
37static av_cold int cudaupload_init(AVFilterContext *ctx)
38{
39 CudaUploadContext *s = ctx->priv;
40 char buf[64] = { 0 };
41
42 snprintf(buf, sizeof(buf), "%d", s->device_idx);
43
44 return av_hwdevice_ctx_create(&s->hwdevice, AV_HWDEVICE_TYPE_CUDA, buf, NULL, 0);
45}
46
47static av_cold void cudaupload_uninit(AVFilterContext *ctx)
48{
49 CudaUploadContext *s = ctx->priv;
50
51 av_buffer_unref(&s->hwframe);
52 av_buffer_unref(&s->hwdevice);
53}
54
55static int cudaupload_query_formats(AVFilterContext *ctx)
56{
57 int ret;
58
59 static const enum AVPixelFormat input_pix_fmts[] = {
60 AV_PIX_FMT_NV12, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV444P,
61 AV_PIX_FMT_NONE,
62 };
63 static const enum AVPixelFormat output_pix_fmts[] = {
64 AV_PIX_FMT_CUDA, AV_PIX_FMT_NONE,
65 };
66 AVFilterFormats *in_fmts = ff_make_format_list(input_pix_fmts);
67 AVFilterFormats *out_fmts;
68
69 ret = ff_formats_ref(in_fmts, &ctx->inputs[0]->out_formats);
70 if (ret < 0)
71 return ret;
72
73 out_fmts = ff_make_format_list(output_pix_fmts);
74
75 ret = ff_formats_ref(out_fmts, &ctx->outputs[0]->in_formats);
76 if (ret < 0)
77 return ret;
78
79 return 0;
80}
81
82static int cudaupload_config_output(AVFilterLink *outlink)
83{
84 AVFilterContext *ctx = outlink->src;
85 AVFilterLink *inlink = ctx->inputs[0];
86 CudaUploadContext *s = ctx->priv;
87
88 AVHWFramesContext *hwframe_ctx;
89 int ret;
90
91 av_buffer_unref(&s->hwframe);
92 s->hwframe = av_hwframe_ctx_alloc(s->hwdevice);
93 if (!s->hwframe)
94 return AVERROR(ENOMEM);
95
96 hwframe_ctx = (AVHWFramesContext*)s->hwframe->data;
97 hwframe_ctx->format = AV_PIX_FMT_CUDA;
98 hwframe_ctx->sw_format = inlink->format;
99 hwframe_ctx->width = inlink->w;
100 hwframe_ctx->height = inlink->h;
101
102 ret = av_hwframe_ctx_init(s->hwframe);
103 if (ret < 0)
104 return ret;
105
106 outlink->hw_frames_ctx = av_buffer_ref(s->hwframe);
107 if (!outlink->hw_frames_ctx)
108 return AVERROR(ENOMEM);
109
110 return 0;
111}
112
113static int cudaupload_filter_frame(AVFilterLink *link, AVFrame *in)
114{
115 AVFilterContext *ctx = link->dst;
116 AVFilterLink *outlink = ctx->outputs[0];
117
118 AVFrame *out = NULL;
119 int ret;
120
121 out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
122 if (!out) {
123 ret = AVERROR(ENOMEM);
124 goto fail;
125 }
126
127 out->width = in->width;
128 out->height = in->height;
129
130 ret = av_hwframe_transfer_data(out, in, 0);
131 if (ret < 0) {
132 av_log(ctx, AV_LOG_ERROR, "Error transferring data to the GPU\n");
133 goto fail;
134 }
135
136 ret = av_frame_copy_props(out, in);
137 if (ret < 0)
138 goto fail;
139
140 av_frame_free(&in);
141
142 return ff_filter_frame(ctx->outputs[0], out);
143fail:
144 av_frame_free(&in);
145 av_frame_free(&out);
146 return ret;
147}
148
149#define OFFSET(x) offsetof(CudaUploadContext, x)
150#define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM)
151static const AVOption cudaupload_options[] = {
152 { "device", "Number of the device to use", OFFSET(device_idx), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS },
153 { NULL },
154};
155
156AVFILTER_DEFINE_CLASS(cudaupload);
157
158static const AVFilterPad cudaupload_inputs[] = {
159 {
160 .name = "default",
161 .type = AVMEDIA_TYPE_VIDEO,
162 .filter_frame = cudaupload_filter_frame,
163 },
164 { NULL }
165};
166
167static const AVFilterPad cudaupload_outputs[] = {
168 {
169 .name = "default",
170 .type = AVMEDIA_TYPE_VIDEO,
171 .config_props = cudaupload_config_output,
172 },
173 { NULL }
174};
175
176AVFilter ff_vf_hwupload_cuda = {
177 .name = "hwupload_cuda",
178 .description = NULL_IF_CONFIG_SMALL("Upload a system memory frame to a CUDA device."),
179
180 .init = cudaupload_init,
181 .uninit = cudaupload_uninit,
182
183 .query_formats = cudaupload_query_formats,
184
185 .priv_size = sizeof(CudaUploadContext),
186 .priv_class = &cudaupload_class,
187
188 .inputs = cudaupload_inputs,
189 .outputs = cudaupload_outputs,
190
191 .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
192};
193