FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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, 0);
118  if (err < 0) {
119  av_log(avctx, AV_LOG_ERROR, "Failed to create derived "
120  "frames context: %d.\n", err);
121  goto fail;
122  }
123 
124  } else if (inlink->format == hwfc->format &&
125  (desc->flags & AV_PIX_FMT_FLAG_HWACCEL) &&
126  ctx->reverse) {
127  // Map between two hardware formats, but do it in reverse.
128  // Make a new hwframe context for the target type, and then
129  // overwrite the input hwframe context with a derived context
130  // mapped from that back to the source type.
131  AVBufferRef *source;
133 
134  ctx->hwframes_ref = av_hwframe_ctx_alloc(device);
135  if (!ctx->hwframes_ref) {
136  err = AVERROR(ENOMEM);
137  goto fail;
138  }
139  frames = (AVHWFramesContext*)ctx->hwframes_ref->data;
140 
141  frames->format = outlink->format;
142  frames->sw_format = hwfc->sw_format;
143  frames->width = hwfc->width;
144  frames->height = hwfc->height;
145  frames->initial_pool_size = 64;
146 
147  err = av_hwframe_ctx_init(ctx->hwframes_ref);
148  if (err < 0) {
149  av_log(avctx, AV_LOG_ERROR, "Failed to initialise "
150  "target frames context: %d.\n", err);
151  goto fail;
152  }
153 
154  err = av_hwframe_ctx_create_derived(&source,
155  inlink->format,
156  hwfc->device_ref,
157  ctx->hwframes_ref,
158  ctx->mode);
159  if (err < 0) {
160  av_log(avctx, AV_LOG_ERROR, "Failed to create "
161  "derived source frames context: %d.\n", err);
162  goto fail;
163  }
164 
165  // Here is the naughty bit. This overwriting changes what
166  // ff_get_video_buffer() in the previous filter returns -
167  // it will now give a frame allocated here mapped back to
168  // the format it expects. If there were any additional
169  // constraints on the output frames there then this may
170  // break nastily.
171  av_buffer_unref(&inlink->hw_frames_ctx);
172  inlink->hw_frames_ctx = source;
173 
174  } else if ((outlink->format == hwfc->format &&
175  inlink->format == hwfc->sw_format) ||
176  inlink->format == hwfc->format) {
177  // Map from a hardware format to a software format, or
178  // undo an existing such mapping.
179 
180  ctx->hwframes_ref = av_buffer_ref(inlink->hw_frames_ctx);
181  if (!ctx->hwframes_ref) {
182  err = AVERROR(ENOMEM);
183  goto fail;
184  }
185 
186  } else {
187  // Non-matching formats - not supported.
188 
189  av_log(avctx, AV_LOG_ERROR, "Unsupported formats for "
190  "hwmap: from %s (%s) to %s.\n",
191  av_get_pix_fmt_name(inlink->format),
193  av_get_pix_fmt_name(outlink->format));
194  err = AVERROR(EINVAL);
195  goto fail;
196  }
197  } else if (avctx->hw_device_ctx) {
198  // Map from a software format to a hardware format. This
199  // creates a new hwframe context like hwupload, but then
200  // returns frames mapped from that to the previous link in
201  // order to fill them without an additional copy.
202 
203  if (!device) {
204  av_log(avctx, AV_LOG_ERROR, "A device reference is "
205  "required to create new frames with reverse "
206  "mapping.\n");
207  err = AVERROR(EINVAL);
208  goto fail;
209  }
210 
211  ctx->reverse = 1;
212 
213  ctx->hwframes_ref = av_hwframe_ctx_alloc(device);
214  if (!ctx->hwframes_ref) {
215  err = AVERROR(ENOMEM);
216  goto fail;
217  }
218  hwfc = (AVHWFramesContext*)ctx->hwframes_ref->data;
219 
220  hwfc->format = outlink->format;
221  hwfc->sw_format = inlink->format;
222  hwfc->width = inlink->w;
223  hwfc->height = inlink->h;
224 
225  err = av_hwframe_ctx_init(ctx->hwframes_ref);
226  if (err < 0) {
227  av_log(avctx, AV_LOG_ERROR, "Failed to create frame "
228  "context for reverse mapping: %d.\n", err);
229  goto fail;
230  }
231 
232  } else {
233  av_log(avctx, AV_LOG_ERROR, "Mapping requires a hardware "
234  "context (a device, or frames on input).\n");
235  return AVERROR(EINVAL);
236  }
237 
238  outlink->hw_frames_ctx = av_buffer_ref(ctx->hwframes_ref);
239  if (!outlink->hw_frames_ctx) {
240  err = AVERROR(ENOMEM);
241  goto fail;
242  }
243 
244  outlink->w = inlink->w;
245  outlink->h = inlink->h;
246 
247  if (device_is_derived)
248  av_buffer_unref(&device);
249  return 0;
250 
251 fail:
252  if (device_is_derived)
253  av_buffer_unref(&device);
255  return err;
256 }
257 
258 static AVFrame *hwmap_get_buffer(AVFilterLink *inlink, int w, int h)
259 {
260  AVFilterContext *avctx = inlink->dst;
261  AVFilterLink *outlink = avctx->outputs[0];
262  HWMapContext *ctx = avctx->priv;
263 
264  if (ctx->reverse && !inlink->hw_frames_ctx) {
265  AVFrame *src, *dst;
266  int err;
267 
268  src = ff_get_video_buffer(outlink, w, h);
269  if (!src) {
270  av_log(avctx, AV_LOG_ERROR, "Failed to allocate source "
271  "frame for software mapping.\n");
272  return NULL;
273  }
274 
275  dst = av_frame_alloc();
276  if (!dst) {
277  av_frame_free(&src);
278  return NULL;
279  }
280 
281  err = av_hwframe_map(dst, src, ctx->mode);
282  if (err) {
283  av_log(avctx, AV_LOG_ERROR, "Failed to map frame to "
284  "software: %d.\n", err);
285  av_frame_free(&src);
286  av_frame_free(&dst);
287  return NULL;
288  }
289 
290  av_frame_free(&src);
291  return dst;
292  } else {
293  return ff_default_get_video_buffer(inlink, w, h);
294  }
295 }
296 
297 static int hwmap_filter_frame(AVFilterLink *link, AVFrame *input)
298 {
299  AVFilterContext *avctx = link->dst;
300  AVFilterLink *outlink = avctx->outputs[0];
301  HWMapContext *ctx = avctx->priv;
302  AVFrame *map = NULL;
303  int err;
304 
305  av_log(ctx, AV_LOG_DEBUG, "Filter input: %s, %ux%u (%"PRId64").\n",
306  av_get_pix_fmt_name(input->format),
307  input->width, input->height, input->pts);
308 
309  map = av_frame_alloc();
310  if (!map) {
311  err = AVERROR(ENOMEM);
312  goto fail;
313  }
314 
315  map->format = outlink->format;
317  if (!map->hw_frames_ctx) {
318  err = AVERROR(ENOMEM);
319  goto fail;
320  }
321 
322  if (ctx->reverse && !input->hw_frames_ctx) {
323  // If we mapped backwards from hardware to software, we need
324  // to attach the hardware frame context to the input frame to
325  // make the mapping visible to av_hwframe_map().
327  if (!input->hw_frames_ctx) {
328  err = AVERROR(ENOMEM);
329  goto fail;
330  }
331  }
332 
333  err = av_hwframe_map(map, input, ctx->mode);
334  if (err < 0) {
335  av_log(avctx, AV_LOG_ERROR, "Failed to map frame: %d.\n", err);
336  goto fail;
337  }
338 
339  err = av_frame_copy_props(map, input);
340  if (err < 0)
341  goto fail;
342 
343  av_frame_free(&input);
344 
345  av_log(ctx, AV_LOG_DEBUG, "Filter output: %s, %ux%u (%"PRId64").\n",
347  map->width, map->height, map->pts);
348 
349  return ff_filter_frame(outlink, map);
350 
351 fail:
352  av_frame_free(&input);
353  av_frame_free(&map);
354  return err;
355 }
356 
358 {
359  HWMapContext *ctx = avctx->priv;
360 
362 }
363 
364 #define OFFSET(x) offsetof(HWMapContext, x)
365 #define FLAGS (AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM)
366 static const AVOption hwmap_options[] = {
367  { "mode", "Frame mapping mode",
370  0, INT_MAX, FLAGS, "mode" },
371 
372  { "read", "Mapping should be readable",
373  0, AV_OPT_TYPE_CONST, { .i64 = AV_HWFRAME_MAP_READ },
374  INT_MIN, INT_MAX, FLAGS, "mode" },
375  { "write", "Mapping should be writeable",
377  INT_MIN, INT_MAX, FLAGS, "mode" },
378  { "overwrite", "Mapping will always overwrite the entire frame",
380  INT_MIN, INT_MAX, FLAGS, "mode" },
381  { "direct", "Mapping should not involve any copying",
383  INT_MIN, INT_MAX, FLAGS, "mode" },
384 
385  { "derive_device", "Derive a new device of this type",
386  OFFSET(derive_device_type), AV_OPT_TYPE_STRING,
387  { .str = NULL }, 0, 0, FLAGS },
388  { "reverse", "Map in reverse (create and allocate in the sink)",
390  { .i64 = 0 }, 0, 1, FLAGS },
391 
392  { NULL }
393 };
394 
395 AVFILTER_DEFINE_CLASS(hwmap);
396 
397 static const AVFilterPad hwmap_inputs[] = {
398  {
399  .name = "default",
400  .type = AVMEDIA_TYPE_VIDEO,
401  .get_video_buffer = hwmap_get_buffer,
402  .filter_frame = hwmap_filter_frame,
403  },
404  { NULL }
405 };
406 
407 static const AVFilterPad hwmap_outputs[] = {
408  {
409  .name = "default",
410  .type = AVMEDIA_TYPE_VIDEO,
411  .config_props = hwmap_config_output,
412  },
413  { NULL }
414 };
415 
417  .name = "hwmap",
418  .description = NULL_IF_CONFIG_SMALL("Map hardware frames"),
419  .uninit = hwmap_uninit,
420  .priv_size = sizeof(HWMapContext),
421  .priv_class = &hwmap_class,
423  .inputs = hwmap_inputs,
424  .outputs = hwmap_outputs,
425  .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
426 };
#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:2419
This structure describes decoded (raw) audio or video data.
Definition: frame.h:201
AVOption.
Definition: opt.h:246
static int hwmap_filter_frame(AVFilterLink *link, AVFrame *input)
Definition: vf_hwmap.c:297
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:70
const char * desc
Definition: nvenc.c:60
int width
The allocated dimensions of the frames in this pool.
Definition: hwcontext.h:226
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:206
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
Definition: video.c:92
static av_cold void hwmap_uninit(AVFilterContext *avctx)
Definition: vf_hwmap.c:357
#define src
Definition: vp8dsp.c:254
The mapping must be readable.
Definition: hwcontext.h:501
AVBufferRef * hw_frames_ctx
For hwaccel-format frames, this should be a reference to the AVHWFramesContext describing the frame...
Definition: frame.h:538
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:1151
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:791
#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:150
AVOptions.
static int hwmap_query_formats(AVFilterContext *avctx)
Definition: vf_hwmap.c:40
static uint32_t reverse(uint32_t num, int bits)
Definition: speedhq.c:565
AVFILTER_DEFINE_CLASS(hwmap)
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
Definition: frame.h:294
static const AVOption hwmap_options[]
Definition: vf_hwmap.c:366
static const AVFilterPad hwmap_inputs[]
Definition: vf_hwmap.c:397
#define av_log(a,...)
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:259
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
The mapping must be direct.
Definition: hwcontext.h:517
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:163
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:179
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:364
int av_hwframe_ctx_init(AVBufferRef *ref)
Finalize the context before use.
Definition: hwcontext.c:323
#define fail()
Definition: checkasm.h:109
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:196
int ff_formats_ref(AVFilterFormats *f, AVFilterFormats **ref)
Add *ref as a new reference to formats.
Definition: formats.c:440
AVFormatContext * ctx
Definition: movenc.c:48
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:599
#define FLAGS
Definition: vf_hwmap.c:365
static const AVFilterPad outputs[]
Definition: af_afftfilt.c:389
int frames
Definition: movenc.c:65
int format
format of the frame, -1 if unknown or unset Values correspond to enum AVPixelFormat for video frames...
Definition: frame.h:274
static AVFrame * hwmap_get_buffer(AVFilterLink *inlink, int w, int h)
Definition: vf_hwmap.c:258
static const AVFilterPad inputs[]
Definition: af_afftfilt.c:379
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
GLint GLenum type
Definition: opengl_enc.c:105
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:121
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:407
AVFilterLink ** outputs
array of pointers to output links
Definition: avfilter.h:350
AVBufferRef * device_ref
A reference to the parent AVHWDeviceContext.
Definition: hwcontext.h:138
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:416
A reference to a data buffer.
Definition: buffer.h:81
static int query_formats(AVFilterContext *ctx)
Definition: aeval.c:244
if(ret< 0)
Definition: vf_mcdeint.c:279
int av_hwframe_map(AVFrame *dst, const AVFrame *src, int flags)
Map a hardware frame.
Definition: hwcontext.c:733
The mapped frame will be overwritten completely in subsequent operations, so the current frame data n...
Definition: hwcontext.h:511
AVBufferRef * av_hwframe_ctx_alloc(AVBufferRef *device_ref_in)
Allocate an AVHWFramesContext tied to a given device context.
Definition: hwcontext.c:237
AVBufferRef * av_buffer_ref(AVBufferRef *buf)
Create a new reference to an AVBuffer.
Definition: buffer.c:93
AVHWDeviceType
Definition: hwcontext.h:27
The mapping must be writeable.
Definition: hwcontext.h:505
An instance of a filter.
Definition: avfilter.h:338
int height
Definition: frame.h:259
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:2335
internal API functions
enum AVPixelFormat sw_format
The pixel format identifying the actual data layout of the hardware frames.
Definition: hwcontext.h:219
char * derive_device_type
Definition: vf_hwmap.c:36
mode
Use these values in ebur128_init (or'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:603