FFmpeg  4.0
vf_hwmap.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/buffer.h"
20 #include "libavutil/hwcontext.h"
21 #include "libavutil/log.h"
22 #include "libavutil/opt.h"
23 #include "libavutil/pixdesc.h"
24 
25 #include "avfilter.h"
26 #include "formats.h"
27 #include "internal.h"
28 #include "video.h"
29 
30 typedef struct HWMapContext {
31  const AVClass *class;
32 
34 
35  int mode;
37  int reverse;
38 } HWMapContext;
39 
41 {
42  int ret;
43 
45  &avctx->inputs[0]->out_formats)) < 0 ||
47  &avctx->outputs[0]->in_formats)) < 0)
48  return ret;
49 
50  return 0;
51 }
52 
53 static int hwmap_config_output(AVFilterLink *outlink)
54 {
55  AVFilterContext *avctx = outlink->src;
56  HWMapContext *ctx = avctx->priv;
57  AVFilterLink *inlink = avctx->inputs[0];
58  AVHWFramesContext *hwfc;
59  AVBufferRef *device;
60  const AVPixFmtDescriptor *desc;
61  int err, device_is_derived;
62 
63  av_log(avctx, AV_LOG_DEBUG, "Configure hwmap %s -> %s.\n",
64  av_get_pix_fmt_name(inlink->format),
65  av_get_pix_fmt_name(outlink->format));
66 
68 
69  device = avctx->hw_device_ctx;
70  device_is_derived = 0;
71 
72  if (inlink->hw_frames_ctx) {
73  hwfc = (AVHWFramesContext*)inlink->hw_frames_ctx->data;
74 
75  if (ctx->derive_device_type) {
76  enum AVHWDeviceType type;
77 
79  if (type == AV_HWDEVICE_TYPE_NONE) {
80  av_log(avctx, AV_LOG_ERROR, "Invalid device type.\n");
81  err = AVERROR(EINVAL);
82  goto fail;
83  }
84 
85  err = av_hwdevice_ctx_create_derived(&device, type,
86  hwfc->device_ref, 0);
87  if (err < 0) {
88  av_log(avctx, AV_LOG_ERROR, "Failed to created derived "
89  "device context: %d.\n", err);
90  goto fail;
91  }
92  device_is_derived = 1;
93  }
94 
95  desc = av_pix_fmt_desc_get(outlink->format);
96  if (!desc) {
97  err = AVERROR(EINVAL);
98  goto fail;
99  }
100 
101  if (inlink->format == hwfc->format &&
102  (desc->flags & AV_PIX_FMT_FLAG_HWACCEL) &&
103  !ctx->reverse) {
104  // Map between two hardware formats (including the case of
105  // undoing an existing mapping).
106 
107  if (!device) {
108  av_log(avctx, AV_LOG_ERROR, "A device reference is "
109  "required to map to a hardware format.\n");
110  err = AVERROR(EINVAL);
111  goto fail;
112  }
113 
115  outlink->format,
116  device,
117  inlink->hw_frames_ctx,
118  ctx->mode);
119  if (err < 0) {
120  av_log(avctx, AV_LOG_ERROR, "Failed to create derived "
121  "frames context: %d.\n", err);
122  goto fail;
123  }
124 
125  } else if (inlink->format == hwfc->format &&
126  (desc->flags & AV_PIX_FMT_FLAG_HWACCEL) &&
127  ctx->reverse) {
128  // Map between two hardware formats, but do it in reverse.
129  // Make a new hwframe context for the target type, and then
130  // overwrite the input hwframe context with a derived context
131  // mapped from that back to the source type.
132  AVBufferRef *source;
134 
135  ctx->hwframes_ref = av_hwframe_ctx_alloc(device);
136  if (!ctx->hwframes_ref) {
137  err = AVERROR(ENOMEM);
138  goto fail;
139  }
140  frames = (AVHWFramesContext*)ctx->hwframes_ref->data;
141 
142  frames->format = outlink->format;
143  frames->sw_format = hwfc->sw_format;
144  frames->width = hwfc->width;
145  frames->height = hwfc->height;
146 
147  if (avctx->extra_hw_frames >= 0)
148  frames->initial_pool_size = 2 + avctx->extra_hw_frames;
149 
150  err = av_hwframe_ctx_init(ctx->hwframes_ref);
151  if (err < 0) {
152  av_log(avctx, AV_LOG_ERROR, "Failed to initialise "
153  "target frames context: %d.\n", err);
154  goto fail;
155  }
156 
157  err = av_hwframe_ctx_create_derived(&source,
158  inlink->format,
159  hwfc->device_ref,
160  ctx->hwframes_ref,
161  ctx->mode);
162  if (err < 0) {
163  av_log(avctx, AV_LOG_ERROR, "Failed to create "
164  "derived source frames context: %d.\n", err);
165  goto fail;
166  }
167 
168  // Here is the naughty bit. This overwriting changes what
169  // ff_get_video_buffer() in the previous filter returns -
170  // it will now give a frame allocated here mapped back to
171  // the format it expects. If there were any additional
172  // constraints on the output frames there then this may
173  // break nastily.
174  av_buffer_unref(&inlink->hw_frames_ctx);
175  inlink->hw_frames_ctx = source;
176 
177  } else if ((outlink->format == hwfc->format &&
178  inlink->format == hwfc->sw_format) ||
179  inlink->format == hwfc->format) {
180  // Map from a hardware format to a software format, or
181  // undo an existing such mapping.
182 
183  ctx->hwframes_ref = av_buffer_ref(inlink->hw_frames_ctx);
184  if (!ctx->hwframes_ref) {
185  err = AVERROR(ENOMEM);
186  goto fail;
187  }
188 
189  } else {
190  // Non-matching formats - not supported.
191 
192  av_log(avctx, AV_LOG_ERROR, "Unsupported formats for "
193  "hwmap: from %s (%s) to %s.\n",
194  av_get_pix_fmt_name(inlink->format),
196  av_get_pix_fmt_name(outlink->format));
197  err = AVERROR(EINVAL);
198  goto fail;
199  }
200  } else if (avctx->hw_device_ctx) {
201  // Map from a software format to a hardware format. This
202  // creates a new hwframe context like hwupload, but then
203  // returns frames mapped from that to the previous link in
204  // order to fill them without an additional copy.
205 
206  if (!device) {
207  av_log(avctx, AV_LOG_ERROR, "A device reference is "
208  "required to create new frames with reverse "
209  "mapping.\n");
210  err = AVERROR(EINVAL);
211  goto fail;
212  }
213 
214  ctx->reverse = 1;
215 
216  ctx->hwframes_ref = av_hwframe_ctx_alloc(device);
217  if (!ctx->hwframes_ref) {
218  err = AVERROR(ENOMEM);
219  goto fail;
220  }
221  hwfc = (AVHWFramesContext*)ctx->hwframes_ref->data;
222 
223  hwfc->format = outlink->format;
224  hwfc->sw_format = inlink->format;
225  hwfc->width = inlink->w;
226  hwfc->height = inlink->h;
227 
228  if (avctx->extra_hw_frames >= 0)
229  hwfc->initial_pool_size = 2 + avctx->extra_hw_frames;
230 
231  err = av_hwframe_ctx_init(ctx->hwframes_ref);
232  if (err < 0) {
233  av_log(avctx, AV_LOG_ERROR, "Failed to create frame "
234  "context for reverse mapping: %d.\n", err);
235  goto fail;
236  }
237 
238  } else {
239  av_log(avctx, AV_LOG_ERROR, "Mapping requires a hardware "
240  "context (a device, or frames on input).\n");
241  return AVERROR(EINVAL);
242  }
243 
244  outlink->hw_frames_ctx = av_buffer_ref(ctx->hwframes_ref);
245  if (!outlink->hw_frames_ctx) {
246  err = AVERROR(ENOMEM);
247  goto fail;
248  }
249 
250  outlink->w = inlink->w;
251  outlink->h = inlink->h;
252 
253  if (device_is_derived)
254  av_buffer_unref(&device);
255  return 0;
256 
257 fail:
258  if (device_is_derived)
259  av_buffer_unref(&device);
261  return err;
262 }
263 
264 static AVFrame *hwmap_get_buffer(AVFilterLink *inlink, int w, int h)
265 {
266  AVFilterContext *avctx = inlink->dst;
267  AVFilterLink *outlink = avctx->outputs[0];
268  HWMapContext *ctx = avctx->priv;
269 
270  if (ctx->reverse && !inlink->hw_frames_ctx) {
271  AVFrame *src, *dst;
272  int err;
273 
274  src = ff_get_video_buffer(outlink, w, h);
275  if (!src) {
276  av_log(avctx, AV_LOG_ERROR, "Failed to allocate source "
277  "frame for software mapping.\n");
278  return NULL;
279  }
280 
281  dst = av_frame_alloc();
282  if (!dst) {
283  av_frame_free(&src);
284  return NULL;
285  }
286 
287  err = av_hwframe_map(dst, src, ctx->mode);
288  if (err) {
289  av_log(avctx, AV_LOG_ERROR, "Failed to map frame to "
290  "software: %d.\n", err);
291  av_frame_free(&src);
292  av_frame_free(&dst);
293  return NULL;
294  }
295 
296  av_frame_free(&src);
297  return dst;
298  } else {
299  return ff_default_get_video_buffer(inlink, w, h);
300  }
301 }
302 
303 static int hwmap_filter_frame(AVFilterLink *link, AVFrame *input)
304 {
305  AVFilterContext *avctx = link->dst;
306  AVFilterLink *outlink = avctx->outputs[0];
307  HWMapContext *ctx = avctx->priv;
308  AVFrame *map = NULL;
309  int err;
310 
311  av_log(ctx, AV_LOG_DEBUG, "Filter input: %s, %ux%u (%"PRId64").\n",
312  av_get_pix_fmt_name(input->format),
313  input->width, input->height, input->pts);
314 
315  map = av_frame_alloc();
316  if (!map) {
317  err = AVERROR(ENOMEM);
318  goto fail;
319  }
320 
321  map->format = outlink->format;
323  if (!map->hw_frames_ctx) {
324  err = AVERROR(ENOMEM);
325  goto fail;
326  }
327 
328  if (ctx->reverse && !input->hw_frames_ctx) {
329  // If we mapped backwards from hardware to software, we need
330  // to attach the hardware frame context to the input frame to
331  // make the mapping visible to av_hwframe_map().
333  if (!input->hw_frames_ctx) {
334  err = AVERROR(ENOMEM);
335  goto fail;
336  }
337  }
338 
339  err = av_hwframe_map(map, input, ctx->mode);
340  if (err < 0) {
341  av_log(avctx, AV_LOG_ERROR, "Failed to map frame: %d.\n", err);
342  goto fail;
343  }
344 
345  err = av_frame_copy_props(map, input);
346  if (err < 0)
347  goto fail;
348 
349  av_frame_free(&input);
350 
351  av_log(ctx, AV_LOG_DEBUG, "Filter output: %s, %ux%u (%"PRId64").\n",
353  map->width, map->height, map->pts);
354 
355  return ff_filter_frame(outlink, map);
356 
357 fail:
358  av_frame_free(&input);
359  av_frame_free(&map);
360  return err;
361 }
362 
364 {
365  HWMapContext *ctx = avctx->priv;
366 
368 }
369 
370 #define OFFSET(x) offsetof(HWMapContext, x)
371 #define FLAGS (AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM)
372 static const AVOption hwmap_options[] = {
373  { "mode", "Frame mapping mode",
376  0, INT_MAX, FLAGS, "mode" },
377 
378  { "read", "Mapping should be readable",
379  0, AV_OPT_TYPE_CONST, { .i64 = AV_HWFRAME_MAP_READ },
380  INT_MIN, INT_MAX, FLAGS, "mode" },
381  { "write", "Mapping should be writeable",
383  INT_MIN, INT_MAX, FLAGS, "mode" },
384  { "overwrite", "Mapping will always overwrite the entire frame",
386  INT_MIN, INT_MAX, FLAGS, "mode" },
387  { "direct", "Mapping should not involve any copying",
389  INT_MIN, INT_MAX, FLAGS, "mode" },
390 
391  { "derive_device", "Derive a new device of this type",
393  { .str = NULL }, 0, 0, FLAGS },
394  { "reverse", "Map in reverse (create and allocate in the sink)",
396  { .i64 = 0 }, 0, 1, FLAGS },
397 
398  { NULL }
399 };
400 
401 AVFILTER_DEFINE_CLASS(hwmap);
402 
403 static const AVFilterPad hwmap_inputs[] = {
404  {
405  .name = "default",
406  .type = AVMEDIA_TYPE_VIDEO,
407  .get_video_buffer = hwmap_get_buffer,
408  .filter_frame = hwmap_filter_frame,
409  },
410  { NULL }
411 };
412 
413 static const AVFilterPad hwmap_outputs[] = {
414  {
415  .name = "default",
416  .type = AVMEDIA_TYPE_VIDEO,
417  .config_props = hwmap_config_output,
418  },
419  { NULL }
420 };
421 
423  .name = "hwmap",
424  .description = NULL_IF_CONFIG_SMALL("Map hardware frames"),
425  .uninit = hwmap_uninit,
426  .priv_size = sizeof(HWMapContext),
427  .priv_class = &hwmap_class,
429  .inputs = hwmap_inputs,
430  .outputs = hwmap_outputs,
431  .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
432 };
#define NULL
Definition: coverity.c:32
#define FF_FILTER_FLAG_HWFRAME_AWARE
The filter is aware of hardware frames, and any hardware frame context should not be automatically pr...
Definition: internal.h:385
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:125
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2363
This structure describes decoded (raw) audio or video data.
Definition: frame.h:218
AVOption.
Definition: opt.h:246
static int hwmap_filter_frame(AVFilterLink *link, AVFrame *input)
Definition: vf_hwmap.c:303
Main libavfilter public API header.
enum AVHWDeviceType av_hwdevice_find_type_by_name(const char *name)
Look up an AVHWDeviceType by name.
Definition: hwcontext.c:78
const char * desc
Definition: nvenc.c:65
int width
The allocated dimensions of the frames in this pool.
Definition: hwcontext.h:228
AVBufferRef * hw_device_ctx
For filters which will create hardware frames, sets the device the filter should create them in...
Definition: avfilter.h:394
enum AVPixelFormat format
The pixel format identifying the underlying HW surface type.
Definition: hwcontext.h:208
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
Definition: video.c:99
static av_cold void hwmap_uninit(AVFilterContext *avctx)
Definition: vf_hwmap.c:363
#define src
Definition: vp8dsp.c:254
AVBufferRef * hw_frames_ctx
For hwaccel-format frames, this should be a reference to the AVHWFramesContext describing the frame...
Definition: frame.h:556
const char * name
Pad name.
Definition: internal.h:60
AVFilterLink ** inputs
array of pointers to input links
Definition: avfilter.h:346
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1080
int av_hwframe_ctx_create_derived(AVBufferRef **derived_frame_ctx, enum AVPixelFormat format, AVBufferRef *derived_device_ctx, AVBufferRef *source_frame_ctx, int flags)
Create and initialise an AVHWFramesContext as a mapping of another existing AVHWFramesContext on a di...
Definition: hwcontext.c:799
#define av_cold
Definition: attributes.h:82
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition: frame.c:189
AVOptions.
static int hwmap_query_formats(AVFilterContext *avctx)
Definition: vf_hwmap.c:40
AVFILTER_DEFINE_CLASS(hwmap)
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
Definition: frame.h:311
static const AVOption hwmap_options[]
Definition: vf_hwmap.c:372
static const AVFilterPad hwmap_inputs[]
Definition: vf_hwmap.c:403
The mapped frame will be overwritten completely in subsequent operations, so the current frame data n...
Definition: hwcontext.h:513
#define av_log(a,...)
int extra_hw_frames
Sets the number of extra hardware frames which the filter will allocate on its output links for use i...
Definition: avfilter.h:424
AVFilterFormats * ff_all_formats(enum AVMediaType type)
Return a list of all formats supported by FFmpeg for the given media type.
Definition: formats.c:350
A filter pad used for either input or output.
Definition: internal.h:54
int width
Definition: frame.h:276
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
AVBufferRef * hwframes_ref
Definition: vf_hwmap.c:33
#define AVERROR(e)
Definition: error.h:43
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:202
The mapping must be direct.
Definition: hwcontext.h:519
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:186
int reverse
Definition: vf_hwmap.c:37
void * priv
private data for use by the filter
Definition: avfilter.h:353
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:197
#define AV_PIX_FMT_FLAG_HWACCEL
Pixel format is an HW accelerated format.
Definition: pixdesc.h:140
#define OFFSET(x)
Definition: vf_hwmap.c:370
int av_hwframe_ctx_init(AVBufferRef *ref)
Finalize the context before use.
Definition: hwcontext.c:329
#define fail()
Definition: checkasm.h:116
uint64_t flags
Combination of AV_PIX_FMT_FLAG_...
Definition: pixdesc.h:106
int initial_pool_size
Initial size of the frame pool.
Definition: hwcontext.h:198
The mapping must be readable.
Definition: hwcontext.h:503
int ff_formats_ref(AVFilterFormats *f, AVFilterFormats **ref)
Add *ref as a new reference to formats.
Definition: formats.c:440
uint8_t w
Definition: llviddspenc.c:38
AVFormatContext * ctx
Definition: movenc.c:48
The mapping must be writeable.
Definition: hwcontext.h:507
int av_hwdevice_ctx_create_derived(AVBufferRef **dst_ref_ptr, enum AVHWDeviceType type, AVBufferRef *src_ref, int flags)
Create a new device of the specified type from an existing device.
Definition: hwcontext.c:607
#define FLAGS
Definition: vf_hwmap.c:371
int frames
Definition: movenc.c:65
static const AVFilterPad inputs[]
Definition: af_acontrast.c:193
if(ret< 0)
Definition: vf_mcdeint.c:279
static const AVFilterPad outputs[]
Definition: af_acontrast.c:203
int format
format of the frame, -1 if unknown or unset Values correspond to enum AVPixelFormat for video frames...
Definition: frame.h:291
static AVFrame * hwmap_get_buffer(AVFilterLink *inlink, int w, int h)
Definition: vf_hwmap.c:264
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:81
uint8_t * data
The data buffer.
Definition: buffer.h:89
Describe the class of an AVClass context structure.
Definition: log.h:67
Filter definition.
Definition: avfilter.h:144
This struct describes a set or pool of "hardware" frames (i.e.
Definition: hwcontext.h:123
cl_device_type type
refcounted data buffer API
const char * name
Filter name.
Definition: avfilter.h:148
const VDPAUPixFmtMap * map
static const AVFilterPad hwmap_outputs[]
Definition: vf_hwmap.c:413
AVFilterLink ** outputs
array of pointers to output links
Definition: avfilter.h:350
AVBufferRef * device_ref
A reference to the parent AVHWDeviceContext.
Definition: hwcontext.h:140
AVFrame * ff_default_get_video_buffer(AVFilterLink *link, int w, int h)
Definition: video.c:44
static int hwmap_config_output(AVFilterLink *outlink)
Definition: vf_hwmap.c:53
AVFilter ff_vf_hwmap
Definition: vf_hwmap.c:422
A reference to a data buffer.
Definition: buffer.h:81
static int query_formats(AVFilterContext *ctx)
Definition: aeval.c:244
int av_hwframe_map(AVFrame *dst, const AVFrame *src, int flags)
Map a hardware frame.
Definition: hwcontext.c:741
AVBufferRef * av_hwframe_ctx_alloc(AVBufferRef *device_ref_in)
Allocate an AVHWFramesContext tied to a given device context.
Definition: hwcontext.c:243
AVBufferRef * av_buffer_ref(AVBufferRef *buf)
Create a new reference to an AVBuffer.
Definition: buffer.c:93
AVHWDeviceType
Definition: hwcontext.h:27
An instance of a filter.
Definition: avfilter.h:338
int height
Definition: frame.h:276
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:2279
internal API functions
enum AVPixelFormat sw_format
The pixel format identifying the actual data layout of the hardware frames.
Definition: hwcontext.h:221
char * derive_device_type
Definition: vf_hwmap.c:36
mode
Use these values in ebur128_init (or&#39;ed).
Definition: ebur128.h:83
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition: frame.c:652