FFmpeg
Loading...
Searching...
No Matches
vf_frc_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 * Video Frame Rate Converter filter with AMF hardware acceleration
22 */
23
24#include "libavutil/internal.h"
25#include "libavutil/opt.h"
26
27#include "avfilter_internal.h"
28
29#include "vf_amf_common.h"
30#include "AMF/components/FRC.h"
32
33#if CONFIG_D3D11VA
34#include <d3d11.h>
35#endif
36
37#if CONFIG_D3D12VA
38#include <d3d12.h>
39#endif
40
41// TODO: move this elsewhere.
42#define AMF_FRC_ASSIGN_PROPERTY_INT64_CHECK(avctx, this, name, val) {\
43 AMF_ASSIGN_PROPERTY_INT64(res, this, name, val);\
44 if (res != AMF_OK)\
45 av_log(avctx, AV_LOG_WARNING, "AMFFRC->SetProperty(%ls, %d) failed with error %d\n", name, val, res);\
46}
47
59
60static int amf_frc_init(AVFilterContext *avctx) {
62
63 ctx->common.format = AV_PIX_FMT_NONE;
64
65 return 0;
66}
67
69{
70 const enum AVPixelFormat *output_pix_fmts;
71 static const enum AVPixelFormat input_pix_fmts[] = {
80 };
81 static const enum AVPixelFormat output_pix_fmts_default[] = {
90 };
91 output_pix_fmts = output_pix_fmts_default;
92
93 return amf_setup_input_output_formats(avctx, input_pix_fmts, output_pix_fmts);
94}
95
97{
98 AVFilterContext *avctx = outlink->src;
99 AMFComponent *amf_filter = NULL;
100 AVFilterLink *inlink = avctx->inputs[0];
101 FilterLink *il = ff_filter_link(inlink);
102 FilterLink *ol = ff_filter_link(outlink);
103 AMFFRCFilterContext *frc_ctx = avctx->priv;
104 AMFFilterContext *amf_ctx = &frc_ctx->common;
105 AVAMFDeviceContext *device_ctx = NULL;
106
107 int err;
108 AMF_RESULT res;
109 enum AVPixelFormat in_format;
110
111 err = amf_init_filter_config(outlink, &in_format);
112 if (err < 0)
113 return err;
114
115 device_ctx = amf_ctx->amf_device_ctx;
116
117 res = AMF_IFACE_CALL(device_ctx->factory, CreateComponent, device_ctx->context, AMFFRC, &amf_ctx->component);
118 AMF_RETURN_IF_FALSE(avctx, res == AMF_OK, AVERROR_FILTER_NOT_FOUND, "CreateComponent(%ls) failed with error %d\n", AMFFRC, res);
119
120 amf_filter = amf_ctx->component;
121
122 outlink->time_base = inlink->time_base;
123 ol->frame_rate = il->frame_rate;
124 ol->frame_rate.num *= 2;
125
126 // Possible bug: FRC must be initialized enabled to be toggleable on the fly after init.
127 AMF_FRC_ASSIGN_PROPERTY_INT64_CHECK(avctx, amf_filter, AMF_FRC_MODE, FRC_x2_PRESENT);
128
129 if (frc_ctx->engine_type != -1)
130 AMF_FRC_ASSIGN_PROPERTY_INT64_CHECK(avctx, amf_filter, AMF_FRC_ENGINE_TYPE, frc_ctx->engine_type);
131
132 AMF_FRC_ASSIGN_PROPERTY_INT64_CHECK(avctx, amf_filter, AMF_FRC_ENABLE_FALLBACK, frc_ctx->fallback);
133
134 AMF_FRC_ASSIGN_PROPERTY_INT64_CHECK(avctx, amf_filter, AMF_FRC_INDICATOR, frc_ctx->indicator);
135
136 AMF_FRC_ASSIGN_PROPERTY_INT64_CHECK(avctx, amf_filter, AMF_FRC_PROFILE, frc_ctx->profile);
137
138 AMF_FRC_ASSIGN_PROPERTY_INT64_CHECK(avctx, amf_filter, AMF_FRC_MV_SEARCH_MODE, frc_ctx->mv_search_mode);
139
140 AMF_FRC_ASSIGN_PROPERTY_INT64_CHECK(avctx, amf_filter, AMF_FRC_USE_FUTURE_FRAME, frc_ctx->use_future_frame);
141
142 res = AMF_IFACE_CALL(amf_filter, Init, av_av_to_amf_format(in_format), inlink->w, inlink->h);
143 AMF_RETURN_IF_FALSE(avctx, res == AMF_OK, AVERROR_UNKNOWN, "AMFFRC->Init() failed with error %d\n", res);
144
145 return 0;
146}
147
148#define OFFSET(x) offsetof(AMFFRCFilterContext, x)
149#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
150static const AVOption frc_amf_options[] = {
151 { "engine_type", "Engine type", OFFSET(engine_type), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, FRC_ENGINE_DX11, .flags = FLAGS, "engine_type" },
152 { "dx11", "DirectX 11", 0, AV_OPT_TYPE_CONST, { .i64 = FRC_ENGINE_DX11 }, 0, 0, FLAGS, "engine_type" },
153 { "dx12", "DirectX 12", 0, AV_OPT_TYPE_CONST, { .i64 = FRC_ENGINE_DX12 }, 0, 0, FLAGS, "engine_type" },
154
155 { "enable", "Enable FRC", OFFSET(enable), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, .flags = FLAGS },
156
157 { "fallback_mode", "Fallback behavior in case of low interpolation confidence", OFFSET(fallback), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, .flags = FLAGS, "fallback_mode" },
158 { "duplicate", "Duplicate frame", 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, 0, FLAGS, "fallback_mode" },
159 { "blend", "Blend two frames together", 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, 0, 0, FLAGS, "fallback_mode" },
160
161 { "indicator", "Show FRC indicator square in the top left corner of the video.", OFFSET(indicator), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, .flags = FLAGS },
162
163 { "profile", "Level of hierarchical motion search", OFFSET(profile), AV_OPT_TYPE_INT, { .i64 = FRC_PROFILE_HIGH }, FRC_PROFILE_LOW, FRC_PROFILE_SUPER, FLAGS, "profile" },
164 { "low", "Less levels of hierarchical motion search. "
165 "Only recommended for extremely low resolutions.", 0, AV_OPT_TYPE_CONST, { .i64 = FRC_PROFILE_LOW }, 0, 0, FLAGS, "profile" },
166 { "high", "Recommended for any resolution up to 1440p.", 0, AV_OPT_TYPE_CONST, { .i64 = FRC_PROFILE_HIGH }, 0, 0, FLAGS, "profile" },
167 { "super", "More levels of hierarchical motion search. "
168 "Recommended for resolutions 1440p or higher.", 0, AV_OPT_TYPE_CONST, { .i64 = FRC_PROFILE_SUPER }, 0, 0, FLAGS, "profile" },
169
170 { "mv_search_mode", "Performance mode of the motion search", OFFSET(mv_search_mode), AV_OPT_TYPE_INT, { .i64 = FRC_MV_SEARCH_NATIVE }, FRC_MV_SEARCH_NATIVE, FRC_MV_SEARCH_PERFORMANCE, FLAGS, "mv_search_mode" },
171 { "native", "Conduct motion search on the full resolution of source images.", 0, AV_OPT_TYPE_CONST, { .i64 = FRC_MV_SEARCH_NATIVE }, 0, 0, FLAGS, "mv_search_mode" },
172 { "performance", "Conduct motion search on the down scaled source images. "
173 "Recommended for APU or low end GPU for better performance.", 0, AV_OPT_TYPE_CONST, { .i64 = FRC_MV_SEARCH_PERFORMANCE }, 0, 0, FLAGS, "mv_search_mode" },
174
175 { "use_future_frame", "Enable dependency on future frame, improves quality for the cost of latency", OFFSET(use_future_frame), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, .flags = FLAGS },
176
177 { NULL },
178};
179
181
183{
184 AVFilterContext *avctx = inlink->dst;
185 AMFFRCFilterContext *frc_ctx = avctx->priv;
186 AMFFilterContext *amf_ctx = &frc_ctx->common;
187 AMFComponent *amf_filter = amf_ctx->component;
188 AVFilterLink *outlink = avctx->outputs[0];
189 AMFSurface *surface_out = NULL;
190 AMFSurface *surface_in = NULL;
191 FilterLink *il = ff_filter_link(inlink);
192 FilterLink *ol = ff_filter_link(outlink);
193 AMF_RESULT res = AMF_FAIL;
194 AMFData *data_out = NULL;
195 AVFrame *out = NULL;
196 int ret = 0;
197
198 if (!amf_filter)
199 return AVERROR(EINVAL);
200
201 ret = amf_avframe_to_amfsurface(avctx, in, &surface_in);
202 if (ret < 0)
203 goto fail;
204
205 if (frc_ctx->enable) {
206 AMF_ASSIGN_PROPERTY_INT64(res, amf_filter, AMF_FRC_MODE, FRC_x2_PRESENT);
207 ol->frame_rate.num = il->frame_rate.num * 2;
208 } else {
209 AMF_ASSIGN_PROPERTY_INT64(res, amf_filter, AMF_FRC_MODE, FRC_OFF);
210 ol->frame_rate.num = il->frame_rate.num;
211 }
212 AMF_GOTO_FAIL_IF_FALSE(avctx, res == AMF_OK, AVERROR_UNKNOWN, "SubmitInput(): Failed to %s FRC, error:%d\n", frc_ctx->enable ? "enable" : "disable", res);
213
214 res = AMF_IFACE_CALL(amf_filter, SubmitInput, (AMFData*)surface_in);
215 AMF_IFACE_CALL(surface_in, Release);
216 surface_in = NULL;
217 AMF_GOTO_FAIL_IF_FALSE(avctx, (res == AMF_OK || res == AMF_INPUT_FULL), AVERROR_UNKNOWN, "SubmitInput() failed with error %d\n", res);
218
219 while (true) {
220 res = AMF_IFACE_CALL(amf_filter, QueryOutput, &data_out);
221
222 AMF_GOTO_FAIL_IF_FALSE(avctx, (res == AMF_OK || res == AMF_REPEAT), AVERROR_UNKNOWN, "QueryOutput() failed with error %d\n", res);
223 if (data_out == NULL)
224 break;
225
226 AMFGuid guid = IID_AMFSurface();
227 res = AMF_IFACE_CALL(data_out, QueryInterface, &guid, (void**)&surface_out);
228 AMF_IFACE_CALL(data_out, Release);
229 data_out = NULL;
230 AMF_RETURN_IF_FALSE(avctx, res == AMF_OK, AVERROR_UNKNOWN, "QueryInterface(IID_AMFSurface) failed with error %d\n", res);
231
232 out = amf_amfsurface_to_avframe(avctx, surface_out);
233 AMF_GOTO_FAIL_IF_FALSE(avctx, out != NULL, AVERROR(ENOMEM), "Failed to convert AMFSurface to AVFrame\n");
234
235 ret = av_frame_copy_props(out, in);
236 AMF_GOTO_FAIL_IF_FALSE(avctx, ret >= 0, AVERROR(ENOMEM), "Failed to copy frame properties\n");
237
238 out->pts = AMF_IFACE_CALL(surface_out, GetPts);
239
240 if (frc_ctx->enable)
241 out->duration /= 2;
242
243 out->hw_frames_ctx = av_buffer_ref(amf_ctx->hwframes_out_ref);
244 if (!out->hw_frames_ctx) {
245 ret = AVERROR(ENOMEM);
246 goto fail;
247 }
248
249 ret = ff_filter_frame(outlink, out);
250 out = NULL;
251 if (ret < 0)
252 goto fail;
253 }
254
255fail:
256 av_frame_unref(in);
257 av_frame_free(&in);
258 if (out != NULL)
260
261 return ret;
262}
263
265 {
266 .name = "default",
267 .type = AVMEDIA_TYPE_VIDEO,
268 .filter_frame = amf_frc_filter_avframe,
269 }
270};
271
272
274 {
275 .name = "default",
276 .type = AVMEDIA_TYPE_VIDEO,
277 .config_props = amf_frc_filter_config_output,
278 }
279};
280
282 .p.name = "frc_amf",
283 .p.description = NULL_IF_CONFIG_SMALL("AMF video Frame Rate Converter"),
284 .p.priv_class = &frc_amf_class,
285 .p.flags = AVFILTER_FLAG_HWDEVICE,
286 .priv_size = sizeof(AMFFRCFilterContext),
292 .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
293};
const FFFilter ff_vf_frc_amf
Definition vf_frc_amf.c:281
static int amf_amfsurface_to_avframe(AVCodecContext *avctx, AMFSurface *surface, AVFrame *frame)
Definition amfdec.c:506
#define AMF_RETURN_IF_FALSE(avctx, exp, ret_value,...)
Error handling helper.
Definition amfenc.h:169
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition avfilter.c:1068
#define FLAGS
Definition cmdutils.c:598
#define NULL
Definition coverity.c:32
int(* init)(AVBSFContext *ctx)
Definition dts2pts.c:608
#define fail
Definition test.h:479
@ 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_BOOL
Underlying C type is int.
Definition opt.h:326
#define AVFILTER_FLAG_HWDEVICE
The filter can create hardware frames using AVFilterContext.hw_device_ctx.
Definition avfilter.h:187
AVBufferRef * av_buffer_ref(const AVBufferRef *buf)
Create a new reference to an AVBuffer.
Definition buffer.c:103
#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
void av_frame_unref(AVFrame *frame)
Unreference all the buffers referenced by frame and reset the frame fields.
Definition frame.c:496
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition frame.c:64
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition frame.c:599
@ AVMEDIA_TYPE_VIDEO
Definition avutil.h:200
enum AMF_SURFACE_FORMAT av_av_to_amf_format(enum AVPixelFormat fmt)
#define AMF_GOTO_FAIL_IF_FALSE(avctx, exp, ret_value,...)
#define AMF_IFACE_CALL(this, function,...)
static av_cold void uninit(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
static FilterLink * ff_filter_link(AVFilterLink *link)
Definition filters.h:199
#define AVFILTER_DEFINE_CLASS(fname)
Definition filters.h:478
common internal API header
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition internal.h:88
int profile
Definition mxfenc.c:2299
AVOptions.
#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_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_AMF_SURFACE
HW acceleration through AMF.
Definition pixfmt.h:477
#define AV_PIX_FMT_X2BGR10
Definition pixfmt.h:620
AMFFilterContext common
Definition vf_frc_amf.c:49
AVBufferRef * hwframes_out_ref
AVAMFDeviceContext * amf_device_ctx
AMFComponent * component
This struct is allocated as AVHWDeviceContext.hwctx.
AMFContext * context
AMFFactory * factory
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
AVFilterLink ** outputs
array of pointers to output links
Definition avfilter.h:285
A filter pad used for either input or output.
Definition filters.h:40
This structure describes decoded (raw) audio or video data.
Definition frame.h:472
AVOption.
Definition opt.h:428
int num
Numerator.
Definition rational.h:59
static FILE * out
Definition movenc.c:55
static AVFormatContext * ctx
Definition movenc.c:49
int amf_avframe_to_amfsurface(AVFilterContext *avctx, const AVFrame *frame, AMFSurface **ppSurface)
int amf_init_filter_config(AVFilterLink *outlink, enum AVPixelFormat *in_format)
int amf_setup_input_output_formats(AVFilterContext *avctx, const enum AVPixelFormat *input_pix_fmts, const enum AVPixelFormat *output_pix_fmts)
void amf_filter_uninit(AVFilterContext *avctx)
static const AVOption frc_amf_options[]
Definition vf_frc_amf.c:150
static const AVFilterPad amf_filter_inputs[]
Definition vf_frc_amf.c:264
static int amf_frc_filter_avframe(AVFilterLink *inlink, AVFrame *in)
Definition vf_frc_amf.c:182
static int amf_frc_filter_config_output(AVFilterLink *outlink)
Definition vf_frc_amf.c:96
static int amf_frc_init(AVFilterContext *avctx)
Definition vf_frc_amf.c:60
#define OFFSET(x)
Definition vf_frc_amf.c:148
static int amf_filter_query_formats(AVFilterContext *avctx)
Definition vf_frc_amf.c:68
#define AMF_FRC_ASSIGN_PROPERTY_INT64_CHECK(avctx, this, name, val)
Definition vf_frc_amf.c:42
static const AVFilterPad amf_filter_outputs[]
Definition vf_frc_amf.c:273