FFmpeg
Loading...
Searching...
No Matches
vf_sr_amf.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/**
20 * @file
21 * Super resolution video filter with AMF hardware acceleration
22 */
23
24#include <stdio.h>
25#include <string.h>
26
27#include "libavutil/avassert.h"
28#include "libavutil/imgutils.h"
29#include "libavutil/opt.h"
30#include "libavutil/pixdesc.h"
31#include "libavutil/time.h"
32
33#include "libavutil/hwcontext.h"
36
37#include "AMF/components/HQScaler.h"
38#include "AMF/components/VideoConverter.h"
39#include "AMF/components/ColorSpace.h"
40#include "vf_amf_common.h"
41
42#include "avfilter.h"
43#include "avfilter_internal.h"
44#include "formats.h"
45#include "video.h"
46
47#if CONFIG_DXVA2
48#include <d3d9.h>
49#endif
50
51#if CONFIG_D3D11VA
52#include <d3d11.h>
53#endif
54
55
56static int amf_hq_scaler_needs_packed_rgb(int algorithm)
57{
58 return algorithm == AMF_HQ_SCALER_ALGORITHM_VIDEOSR1_1 ||
59 algorithm == AMF_HQ_SCALER_ALGORITHM_POINT;
60}
61
67
69{
70 AMFFilterContext *ctx = avctx->priv;
71 const enum AVPixelFormat *input_pix_fmts;
72 static const enum AVPixelFormat input_pix_fmts_default[] = {
82 };
83 // sr1-1 and point need packed RGB; YUV is converted on the GPU
84 static const enum AVPixelFormat pix_fmts_packed_rgb[] = {
93 };
94 enum AVPixelFormat pix_fmts_requested[] = {
100 };
101 int i;
102
103 if (amf_hq_scaler_needs_packed_rgb(ctx->algorithm))
104 input_pix_fmts = pix_fmts_packed_rgb;
105 else
106 input_pix_fmts = input_pix_fmts_default;
107
108 if (ctx->format_opt != AV_PIX_FMT_NONE) {
109 for (i = 0; input_pix_fmts[i] != AV_PIX_FMT_NONE; i++) {
110 if (input_pix_fmts[i] == ctx->format_opt) {
111 pix_fmts_requested[0] = ctx->format_opt;
112 input_pix_fmts = pix_fmts_requested;
113 break;
114 }
115 }
116 }
117
118 return amf_setup_input_output_formats(avctx, input_pix_fmts);
119}
120
122{
123 AVFilterContext *avctx = outlink->src;
124 AVFilterLink *inlink = avctx->inputs[0];
125 AMFFilterContext *ctx = avctx->priv;
126 AMFSize out_size;
127 int err;
128 AMF_RESULT res;
129 enum AVPixelFormat in_format;
130 enum AMF_MEMORY_TYPE mem_type = AMF_MEMORY_UNKNOWN;
131 enum AVPixelFormat in_sw_format;
132 int needs_conversion;
133
134 in_sw_format = amf_inlink_sw_format(inlink);
135 ctx->format = ctx->format_opt;
136
137 if (amf_hq_scaler_needs_packed_rgb(ctx->algorithm)) {
138 if (ctx->format == AV_PIX_FMT_NONE) {
139 if (amf_is_packed_rgb(in_sw_format))
140 ctx->format = in_sw_format;
141 else
142 ctx->format = in_sw_format == AV_PIX_FMT_P010 ? AV_PIX_FMT_X2BGR10 : AV_PIX_FMT_RGBA;
143 } else if (!amf_is_packed_rgb(ctx->format)) {
144 av_log(avctx, AV_LOG_ERROR, "This algorithm only outputs packed RGB, format=%s is not supported.\n",
145 av_get_pix_fmt_name(ctx->format));
146 return AVERROR(EINVAL);
147 }
148 needs_conversion = ctx->format != in_sw_format;
149 } else if (ctx->format != AV_PIX_FMT_NONE && ctx->format != in_sw_format) {
150 av_log(avctx, AV_LOG_ERROR, "The HQ scaler does not convert formats, format must be same or %s.\n",
151 av_get_pix_fmt_name(in_sw_format));
152 return AVERROR(EINVAL);
153 } else {
154 ctx->format = in_sw_format;
155 needs_conversion = 0;
156 }
157
158 err = amf_init_filter_config(outlink, &in_format);
159 if (err < 0)
160 return err;
161
162 if (needs_conversion) {
163 AMFSize in_size = { inlink->w, inlink->h };
164
165 res = ctx->amf_device_ctx->factory->pVtbl->CreateComponent(ctx->amf_device_ctx->factory, ctx->amf_device_ctx->context, AMFVideoConverter, &ctx->pre_converter);
166 AMF_RETURN_IF_FALSE(avctx, res == AMF_OK, AVERROR_FILTER_NOT_FOUND, "CreateComponent(%ls) failed with error %d\n", AMFVideoConverter, res);
167
168 AMF_ASSIGN_PROPERTY_INT64(res, ctx->pre_converter, AMF_VIDEO_CONVERTER_OUTPUT_FORMAT, (amf_int32)av_av_to_amf_format(ctx->format));
169 AMF_RETURN_IF_FALSE(avctx, res == AMF_OK, AVERROR_UNKNOWN, "AMFConverter-SetProperty() failed with error %d\n", res);
170 AMF_ASSIGN_PROPERTY_SIZE(res, ctx->pre_converter, AMF_VIDEO_CONVERTER_OUTPUT_SIZE, in_size);
171 AMF_RETURN_IF_FALSE(avctx, res == AMF_OK, AVERROR_UNKNOWN, "AMFConverter-SetProperty() failed with error %d\n", res);
172 AMF_ASSIGN_PROPERTY_INT64(res, ctx->pre_converter, AMF_VIDEO_CONVERTER_OUTPUT_COLOR_RANGE, AMF_COLOR_RANGE_FULL);
173 AMF_RETURN_IF_FALSE(avctx, res == AMF_OK, AVERROR_UNKNOWN, "AMFConverter-SetProperty() failed with error %d\n", res);
174
175 res = ctx->pre_converter->pVtbl->Init(ctx->pre_converter, av_av_to_amf_format(in_format), inlink->w, inlink->h);
176 AMF_RETURN_IF_FALSE(avctx, res == AMF_OK, AVERROR_UNKNOWN,
177 "AMFConverter-Init() failed with error %d, %s to %s is not supported by this device%s\n",
178 res, av_get_pix_fmt_name(in_format), av_get_pix_fmt_name(ctx->format),
179 ctx->format == AV_PIX_FMT_X2BGR10 ? ", try format=rgba" : "");
180
181 in_format = ctx->format;
182 }
183
184 // HQ scaler should be used for upscaling only
185 if (inlink->w > outlink->w || inlink->h > outlink->h) {
186 av_log(avctx, AV_LOG_ERROR, "AMF HQ scaler should be used for upscaling only.\n");
187 return AVERROR_UNKNOWN;
188 }
189 // FIXME: add checks whether we have HW context
190 res = ctx->amf_device_ctx->factory->pVtbl->CreateComponent(ctx->amf_device_ctx->factory, ctx->amf_device_ctx->context, AMFHQScaler, &ctx->component);
191 AMF_RETURN_IF_FALSE(avctx, res == AMF_OK, AVERROR_FILTER_NOT_FOUND, "CreateComponent(%ls) failed with error %d\n", AMFHQScaler, res);
192
193 mem_type = av_amf_get_memory_type(ctx->amf_device_ctx);
194 if (mem_type != AMF_MEMORY_UNKNOWN)
195 AMF_ASSIGN_PROPERTY_INT64(res, ctx->component, AMF_HQ_SCALER_ENGINE_TYPE, mem_type);
196
197 out_size.width = outlink->w;
198 out_size.height = outlink->h;
199 AMF_ASSIGN_PROPERTY_SIZE(res, ctx->component, AMF_HQ_SCALER_OUTPUT_SIZE, out_size);
200 AMF_RETURN_IF_FALSE(avctx, res == AMF_OK, AVERROR_UNKNOWN, "AMFHQScaler-SetProperty() failed with error %d\n", res);
201
202 if (ctx->algorithm != -1) {
203 AMF_ASSIGN_PROPERTY_INT64(res, ctx->component, AMF_HQ_SCALER_ALGORITHM, ctx->algorithm);
204 }
205 if (ctx->sharpness != -1) {
206 AMF_ASSIGN_PROPERTY_DOUBLE(res, ctx->component, AMF_HQ_SCALER_SHARPNESS, ctx->sharpness);
207 }
208 AMF_ASSIGN_PROPERTY_BOOL(res, ctx->component, AMF_HQ_SCALER_FILL, ctx->fill);
209 AMF_ASSIGN_PROPERTY_BOOL(res, ctx->component, AMF_HQ_SCALER_KEEP_ASPECT_RATIO, ctx->keep_ratio);
210 // Setup default options to skip color conversion
211 ctx->in_color_range = AMF_COLOR_RANGE_UNDEFINED;
212 ctx->in_primaries = AMF_COLOR_PRIMARIES_UNDEFINED;
213 ctx->in_trc = AMF_COLOR_TRANSFER_CHARACTERISTIC_UNDEFINED;
214 ctx->color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_UNKNOWN;
215 ctx->out_color_range = needs_conversion ? AMF_COLOR_RANGE_FULL : AMF_COLOR_RANGE_UNDEFINED;
216 ctx->out_primaries = AMF_COLOR_PRIMARIES_UNDEFINED;
217 ctx->out_trc = AMF_COLOR_TRANSFER_CHARACTERISTIC_UNDEFINED;
218
219 res = ctx->component->pVtbl->Init(ctx->component, av_av_to_amf_format(in_format), inlink->w, inlink->h);
220 AMF_RETURN_IF_FALSE(avctx, res == AMF_OK, AVERROR_UNKNOWN, "AMFHQScaler-Init() failed with error %d\n", res);
221
222 return 0;
223}
224
225#define OFFSET(x) offsetof(AMFFilterContext, x)
226#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
227static const AVOption sr_amf_options[] = {
228 { "w", "Output video width", OFFSET(w_expr), AV_OPT_TYPE_STRING, { .str = "iw" }, .flags = FLAGS },
229 { "h", "Output video height", OFFSET(h_expr), AV_OPT_TYPE_STRING, { .str = "ih" }, .flags = FLAGS },
230
231 { "format", "Output pixel format", OFFSET(format_str), AV_OPT_TYPE_STRING, { .str = "same" }, .flags = FLAGS },
232 { "sharpness", "Sharpness", OFFSET(sharpness), AV_OPT_TYPE_FLOAT, { .dbl = -1 }, -1, 2., FLAGS, "sharpness" },
233 { "keep-ratio", "Keep aspect ratio", OFFSET(keep_ratio), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS, "keep_ration" },
234 { "fill", "Fill", OFFSET(fill), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS, "fill" },
235
236 { "algorithm", "Scaling algorithm", OFFSET(algorithm), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, AMF_HQ_SCALER_ALGORITHM_VIDEOSR1_1, FLAGS, "algorithm" },
237 { "bilinear", "Bilinear", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_HQ_SCALER_ALGORITHM_BILINEAR }, 0, 0, FLAGS, "algorithm" },
238 { "bicubic", "Bicubic", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_HQ_SCALER_ALGORITHM_BICUBIC }, 0, 0, FLAGS, "algorithm" },
239 { "sr1-0", "Video SR1.0", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_HQ_SCALER_ALGORITHM_VIDEOSR1_0 }, 0, 0, FLAGS, "algorithm" },
240 { "point", "Point", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_HQ_SCALER_ALGORITHM_POINT }, 0, 0, FLAGS, "algorithm" },
241 { "sr1-1", "Video SR1.1", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_HQ_SCALER_ALGORITHM_VIDEOSR1_1 }, 0, 0, FLAGS, "algorithm" },
242
243 { NULL },
244};
245
246
248
250 {
251 .name = "default",
252 .type = AVMEDIA_TYPE_VIDEO,
253 }
254};
255
257 {
258 .name = "default",
259 .type = AVMEDIA_TYPE_VIDEO,
260 .config_props = amf_filter_config_output,
261 }
262};
263
265 .p.name = "sr_amf",
266 .p.description = NULL_IF_CONFIG_SMALL("AMF HQ video upscaling"),
267 .p.priv_class = &sr_amf_class,
268 .p.flags = AVFILTER_FLAG_HWDEVICE,
269 .priv_size = sizeof(AMFFilterContext),
270
277 .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
278};
static const char *const format[]
Definition af_aiir.c:445
const FFFilter ff_vf_sr_amf
Definition vf_sr_amf.c:264
#define AMF_RETURN_IF_FALSE(avctx, exp, ret_value,...)
Error handling helper.
Definition amfenc.h:169
static int out_size
static AVFormatContext * ctx
simple assert() macros that are a bit more flexible than ISO C assert().
Main libavfilter public API header.
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define FLAGS
Definition cmdutils.c:596
#define NULL
Definition coverity.c:32
int(* init)(AVBSFContext *ctx)
Definition dts2pts.c:608
@ AV_OPT_TYPE_CONST
Special option type for declaring named constants.
Definition opt.h:298
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition opt.h:258
@ AV_OPT_TYPE_FLOAT
Underlying C type is float.
Definition opt.h:270
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
Definition opt.h:326
@ AV_OPT_TYPE_STRING
Underlying C type is a uint8_t* that is either NULL or points to a C string allocated with the av_mal...
Definition opt.h:275
#define AVFILTER_FLAG_HWDEVICE
The filter can create hardware frames using AVFilterContext.hw_device_ctx.
Definition avfilter.h:187
#define AVERROR_FILTER_NOT_FOUND
Filter not found.
Definition error.h:60
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
Definition error.h:73
#define AVERROR(e)
Definition error.h:45
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
@ AVMEDIA_TYPE_VIDEO
Definition avutil.h:200
enum AMF_MEMORY_TYPE av_amf_get_memory_type(AVAMFDeviceContext *amf_ctx)
enum AMF_SURFACE_FORMAT av_av_to_amf_format(enum AVPixelFormat fmt)
misc image utilities
static av_cold void uninit(AVBitStreamFilterContext *ctx)
static int activate(AVBitStreamFilterContext *ctx)
#define FILTER_INPUTS(array)
Definition filters.h:264
#define FILTER_OUTPUTS(array)
Definition filters.h:265
#define FF_FILTER_FLAG_HWFRAME_AWARE
The filter is aware of hardware frames, and any hardware frame context should not be automatically pr...
Definition filters.h:208
#define FILTER_QUERY_FUNC(func)
Definition filters.h:238
#define AVFILTER_DEFINE_CLASS(fname)
Definition filters.h:478
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition internal.h:97
AVOptions.
const char * av_get_pix_fmt_name(enum AVPixelFormat pix_fmt)
Return the short name for a pixel format, NULL in case pix_fmt is unknown.
Definition pixdesc.c:3380
#define AV_PIX_FMT_RGBAF16
Definition pixfmt.h:630
#define AV_PIX_FMT_P010
Definition pixfmt.h:608
AVPixelFormat
Pixel format.
Definition pixfmt.h:71
@ AV_PIX_FMT_NV12
planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (firs...
Definition pixfmt.h:96
@ AV_PIX_FMT_NONE
Definition pixfmt.h:72
@ AV_PIX_FMT_DXVA2_VLD
HW decoding through DXVA2, Picture.data[3] contains a LPDIRECT3DSURFACE9 pointer.
Definition pixfmt.h:134
@ AV_PIX_FMT_BGRA
packed BGRA 8:8:8:8, 32bpp, BGRABGRA...
Definition pixfmt.h:102
@ AV_PIX_FMT_RGBA
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
Definition pixfmt.h:100
@ AV_PIX_FMT_D3D11
Hardware surfaces for Direct3D11.
Definition pixfmt.h:336
@ AV_PIX_FMT_AMF_SURFACE
HW acceleration through AMF.
Definition pixfmt.h:477
#define AV_PIX_FMT_X2BGR10
Definition pixfmt.h:620
An instance of a filter.
Definition avfilter.h:273
AVFilterLink ** inputs
array of pointers to input links
Definition avfilter.h:281
void * priv
private data for use by the filter
Definition avfilter.h:288
A filter pad used for either input or output.
Definition filters.h:40
AVOption.
Definition opt.h:428
#define av_log(a,...)
int amf_setup_input_output_formats(AVFilterContext *avctx, const enum AVPixelFormat *input_pix_fmts)
int amf_filter_activate(AVFilterContext *avctx)
int amf_filter_init(AVFilterContext *avctx)
int amf_init_filter_config(AVFilterLink *outlink, enum AVPixelFormat *in_format)
enum AVPixelFormat amf_inlink_sw_format(AVFilterLink *inlink)
void amf_filter_uninit(AVFilterContext *avctx)
static const AVFilterPad amf_filter_inputs[]
Definition vf_frc_amf.c:181
static int amf_filter_query_formats(AVFilterContext *avctx)
Definition vf_frc_amf.c:69
static const AVFilterPad amf_filter_outputs[]
Definition vf_frc_amf.c:189
static int amf_hq_scaler_needs_packed_rgb(int algorithm)
Definition vf_sr_amf.c:56
static int amf_is_packed_rgb(enum AVPixelFormat format)
Definition vf_sr_amf.c:62
static int amf_filter_config_output(AVFilterLink *outlink)
Definition vf_sr_amf.c:121
#define OFFSET(x)
Definition vf_sr_amf.c:225
static int amf_filter_query_formats(AVFilterContext *avctx)
Definition vf_sr_amf.c:68
static const AVOption sr_amf_options[]
Definition vf_sr_amf.c:227