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 "vulkan_filter.h"
20
vulkan_filter_set_device(AVFilterContext * avctx,AVBufferRef * device)21 static int vulkan_filter_set_device(AVFilterContext *avctx,
22 AVBufferRef *device)
23 {
24 FFVulkanContext *s = avctx->priv;
25
26 av_buffer_unref(&s->device_ref);
27
28 s->device_ref = av_buffer_ref(device);
29 if (!s->device_ref)
30 return AVERROR(ENOMEM);
31
32 s->device = (AVHWDeviceContext*)s->device_ref->data;
33 s->hwctx = s->device->hwctx;
34
35 return 0;
36 }
37
vulkan_filter_set_frames(AVFilterContext * avctx,AVBufferRef * frames)38 static int vulkan_filter_set_frames(AVFilterContext *avctx,
39 AVBufferRef *frames)
40 {
41 FFVulkanContext *s = avctx->priv;
42
43 av_buffer_unref(&s->frames_ref);
44
45 s->frames_ref = av_buffer_ref(frames);
46 if (!s->frames_ref)
47 return AVERROR(ENOMEM);
48
49 return 0;
50 }
51
ff_vk_filter_config_input(AVFilterLink * inlink)52 int ff_vk_filter_config_input(AVFilterLink *inlink)
53 {
54 int err;
55 AVFilterContext *avctx = inlink->dst;
56 FFVulkanContext *s = avctx->priv;
57 FFVulkanFunctions *vk = &s->vkfn;
58 AVHWFramesContext *input_frames;
59
60 if (!inlink->hw_frames_ctx) {
61 av_log(avctx, AV_LOG_ERROR, "Vulkan filtering requires a "
62 "hardware frames context on the input.\n");
63 return AVERROR(EINVAL);
64 }
65
66 /* Extract the device and default output format from the first input. */
67 if (avctx->inputs[0] != inlink)
68 return 0;
69
70 input_frames = (AVHWFramesContext *)inlink->hw_frames_ctx->data;
71 if (input_frames->format != AV_PIX_FMT_VULKAN)
72 return AVERROR(EINVAL);
73
74 err = vulkan_filter_set_device(avctx, input_frames->device_ref);
75 if (err < 0)
76 return err;
77 err = vulkan_filter_set_frames(avctx, inlink->hw_frames_ctx);
78 if (err < 0)
79 return err;
80
81 s->extensions = ff_vk_extensions_to_mask(s->hwctx->enabled_dev_extensions,
82 s->hwctx->nb_enabled_dev_extensions);
83
84 err = ff_vk_load_functions(s->device, &s->vkfn, s->extensions, 1, 1);
85 if (err < 0)
86 return err;
87
88 vk->GetPhysicalDeviceProperties(s->hwctx->phys_dev, &s->props);
89 vk->GetPhysicalDeviceMemoryProperties(s->hwctx->phys_dev, &s->mprops);
90
91 /* Default output parameters match input parameters. */
92 s->input_format = input_frames->sw_format;
93 if (s->output_format == AV_PIX_FMT_NONE)
94 s->output_format = input_frames->sw_format;
95 if (!s->output_width)
96 s->output_width = inlink->w;
97 if (!s->output_height)
98 s->output_height = inlink->h;
99
100 return 0;
101 }
102
ff_vk_filter_config_output_inplace(AVFilterLink * outlink)103 int ff_vk_filter_config_output_inplace(AVFilterLink *outlink)
104 {
105 int err;
106 AVFilterContext *avctx = outlink->src;
107 FFVulkanContext *s = avctx->priv;
108
109 av_buffer_unref(&outlink->hw_frames_ctx);
110
111 if (!s->device_ref) {
112 if (!avctx->hw_device_ctx) {
113 av_log(avctx, AV_LOG_ERROR, "Vulkan filtering requires a "
114 "Vulkan device.\n");
115 return AVERROR(EINVAL);
116 }
117
118 err = vulkan_filter_set_device(avctx, avctx->hw_device_ctx);
119 if (err < 0)
120 return err;
121 }
122
123 outlink->hw_frames_ctx = av_buffer_ref(s->frames_ref);
124 if (!outlink->hw_frames_ctx)
125 return AVERROR(ENOMEM);
126
127 outlink->w = s->output_width;
128 outlink->h = s->output_height;
129
130 return 0;
131 }
132
ff_vk_filter_config_output(AVFilterLink * outlink)133 int ff_vk_filter_config_output(AVFilterLink *outlink)
134 {
135 int err;
136 AVFilterContext *avctx = outlink->src;
137 FFVulkanContext *s = avctx->priv;
138 AVBufferRef *output_frames_ref;
139 AVHWFramesContext *output_frames;
140
141 av_buffer_unref(&outlink->hw_frames_ctx);
142
143 if (!s->device_ref) {
144 if (!avctx->hw_device_ctx) {
145 av_log(avctx, AV_LOG_ERROR, "Vulkan filtering requires a "
146 "Vulkan device.\n");
147 return AVERROR(EINVAL);
148 }
149
150 err = vulkan_filter_set_device(avctx, avctx->hw_device_ctx);
151 if (err < 0)
152 return err;
153 }
154
155 output_frames_ref = av_hwframe_ctx_alloc(s->device_ref);
156 if (!output_frames_ref) {
157 err = AVERROR(ENOMEM);
158 goto fail;
159 }
160 output_frames = (AVHWFramesContext*)output_frames_ref->data;
161
162 output_frames->format = AV_PIX_FMT_VULKAN;
163 output_frames->sw_format = s->output_format;
164 output_frames->width = s->output_width;
165 output_frames->height = s->output_height;
166
167 err = av_hwframe_ctx_init(output_frames_ref);
168 if (err < 0) {
169 av_log(avctx, AV_LOG_ERROR, "Failed to initialise output "
170 "frames: %d.\n", err);
171 goto fail;
172 }
173
174 outlink->hw_frames_ctx = output_frames_ref;
175 outlink->w = s->output_width;
176 outlink->h = s->output_height;
177
178 return 0;
179 fail:
180 av_buffer_unref(&output_frames_ref);
181 return err;
182 }
183
ff_vk_filter_init(AVFilterContext * avctx)184 int ff_vk_filter_init(AVFilterContext *avctx)
185 {
186 FFVulkanContext *s = avctx->priv;
187
188 s->output_format = AV_PIX_FMT_NONE;
189
190 return 0;
191 }
192