History

lavfi: generic hardware surface upload and download filters

Mark Thompson committed 10 years ago

Commit 07a844f1 parent 551c6778 files · +472 −1Browse files

Unified · Split

8 files
  1. doc/APIchanges +3 −0
  2. libavfilter/Makefile +2 −0
  3. libavfilter/allfilters.c +2 −0
  4. libavfilter/avfilter.c +2 −0
  5. libavfilter/avfilter.h +9 −0
  6. libavfilter/version.h +1 −1
  7. libavfilter/vf_hwdownload.c +212 −0
  8. libavfilter/vf_hwupload.c +241 −0
doc/APIchanges+3−0
@@ -13,6 +13,9 @@ libavutil: 2015-08-28 · 12 unmodified lines
13 13
14API changes, most recent first:14API changes, most recent first:
15 15
162016-xx-xx - xxxxxxx - lavfi 6.3.0 - avfilter.h
17 Add AVFilterContext.hw_device_ctx.
18
162016-xx-xx - xxxxxxx - lavu 55.9.0 - hwcontext_vaapi.h192016-xx-xx - xxxxxxx - lavu 55.9.0 - hwcontext_vaapi.h
17 Add new installed header with VAAPI-specific hwcontext definitions.20 Add new installed header with VAAPI-specific hwcontext definitions.
18 21
libavfilter/Makefile+2−0
@@ -56,6 +56,8 @@ OBJS-$(CONFIG_FREI0R_FILTER) += vf_frei0r.o · 55 unmodified lines
56OBJS-$(CONFIG_GRADFUN_FILTER) += vf_gradfun.o56OBJS-$(CONFIG_GRADFUN_FILTER) += vf_gradfun.o
57OBJS-$(CONFIG_HFLIP_FILTER) += vf_hflip.o57OBJS-$(CONFIG_HFLIP_FILTER) += vf_hflip.o
58OBJS-$(CONFIG_HQDN3D_FILTER) += vf_hqdn3d.o58OBJS-$(CONFIG_HQDN3D_FILTER) += vf_hqdn3d.o
59OBJS-$(CONFIG_HWDOWNLOAD_FILTER) += vf_hwdownload.o
60OBJS-$(CONFIG_HWUPLOAD_FILTER) += vf_hwupload.o
59OBJS-$(CONFIG_HWUPLOAD_CUDA_FILTER) += vf_hwupload_cuda.o61OBJS-$(CONFIG_HWUPLOAD_CUDA_FILTER) += vf_hwupload_cuda.o
60OBJS-$(CONFIG_INTERLACE_FILTER) += vf_interlace.o62OBJS-$(CONFIG_INTERLACE_FILTER) += vf_interlace.o
61OBJS-$(CONFIG_LUT_FILTER) += vf_lut.o63OBJS-$(CONFIG_LUT_FILTER) += vf_lut.o
libavfilter/allfilters.c+2−0
@@ -82,6 +82,8 @@ void avfilter_register_all(void) · 81 unmodified lines
82 REGISTER_FILTER(GRADFUN, gradfun, vf);82 REGISTER_FILTER(GRADFUN, gradfun, vf);
83 REGISTER_FILTER(HFLIP, hflip, vf);83 REGISTER_FILTER(HFLIP, hflip, vf);
84 REGISTER_FILTER(HQDN3D, hqdn3d, vf);84 REGISTER_FILTER(HQDN3D, hqdn3d, vf);
85 REGISTER_FILTER(HWDOWNLOAD, hwdownload, vf);
86 REGISTER_FILTER(HWUPLOAD, hwupload, vf);
85 REGISTER_FILTER(HWUPLOAD_CUDA, hwupload_cuda, vf);87 REGISTER_FILTER(HWUPLOAD_CUDA, hwupload_cuda, vf);
86 REGISTER_FILTER(INTERLACE, interlace, vf);88 REGISTER_FILTER(INTERLACE, interlace, vf);
87 REGISTER_FILTER(LUT, lut, vf);89 REGISTER_FILTER(LUT, lut, vf);
libavfilter/avfilter.c+2−0
@@ -525,6 +525,8 @@ void avfilter_free(AVFilterContext *filter) · 524 unmodified lines
525 if (filter->filter->priv_class)525 if (filter->filter->priv_class)
526 av_opt_free(filter->priv);526 av_opt_free(filter->priv);
527 527
528 av_buffer_unref(&filter->hw_device_ctx);
529
528 av_freep(&filter->name);530 av_freep(&filter->name);
529 av_freep(&filter->input_pads);531 av_freep(&filter->input_pads);
530 av_freep(&filter->output_pads);532 av_freep(&filter->output_pads);
libavfilter/avfilter.h+9−0
@@ -300,6 +300,15 @@ struct AVFilterContext { · 299 unmodified lines
300 * An opaque struct for libavfilter internal use.300 * An opaque struct for libavfilter internal use.
301 */301 */
302 AVFilterInternal *internal;302 AVFilterInternal *internal;
303
304 /**
305 * For filters which will create hardware frames, sets the device the
306 * filter should create them in. All other filters will ignore this field:
307 * in particular, a filter which consumes or processes hardware frames will
308 * instead use the hw_frames_ctx field in AVFilterLink to carry the
309 * hardware context information.
310 */
311 AVBufferRef *hw_device_ctx;
303};312};
304 313
305/**314/**
libavfilter/version.h+1−1
@@ -30,7 +30,7 @@ · 29 unmodified lines
30#include "libavutil/version.h"30#include "libavutil/version.h"
31 31
32#define LIBAVFILTER_VERSION_MAJOR 632#define LIBAVFILTER_VERSION_MAJOR 6
33#define LIBAVFILTER_VERSION_MINOR 233#define LIBAVFILTER_VERSION_MINOR 3
34#define LIBAVFILTER_VERSION_MICRO 034#define LIBAVFILTER_VERSION_MICRO 0
35 35
36#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \36#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
libavfilter/vf_hwdownload.c+212−0
@@ -0,0 +1,212 @@
1/*
2 * This file is part of Libav.
3 *
4 * Libav 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 * Libav 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 Libav; 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/avassert.h"
20#include "libavutil/buffer.h"
21#include "libavutil/hwcontext.h"
22#include "libavutil/log.h"
23#include "libavutil/mem.h"
24#include "libavutil/opt.h"
25#include "libavutil/pixdesc.h"
26
27#include "avfilter.h"
28#include "formats.h"
29#include "internal.h"
30#include "video.h"
31
32typedef struct HWDownloadContext {
33 const AVClass *class;
34
35 AVBufferRef *hwframes_ref;
36 AVHWFramesContext *hwframes;
37} HWDownloadContext;
38
39static int hwdownload_query_formats(AVFilterContext *avctx)
40{
41 AVFilterFormats *infmts = NULL;
42 AVFilterFormats *outfmts = NULL;
43 const AVPixFmtDescriptor *desc;
44 int err;
45
46 for (desc = av_pix_fmt_desc_next(NULL); desc;
47 desc = av_pix_fmt_desc_next(desc)) {
48 if (desc->flags & AV_PIX_FMT_FLAG_HWACCEL)
49 err = ff_add_format(&infmts, av_pix_fmt_desc_get_id(desc));
50 else
51 err = ff_add_format(&outfmts, av_pix_fmt_desc_get_id(desc));
52 if (err) {
53 ff_formats_unref(&infmts);
54 ff_formats_unref(&outfmts);
55 return err;
56 }
57 }
58
59 ff_formats_ref(infmts, &avctx->inputs[0]->out_formats);
60 ff_formats_ref(outfmts, &avctx->outputs[0]->in_formats);
61 return 0;
62}
63
64static int hwdownload_config_input(AVFilterLink *inlink)
65{
66 AVFilterContext *avctx = inlink->dst;
67 HWDownloadContext *ctx = avctx->priv;
68
69 av_buffer_unref(&ctx->hwframes_ref);
70
71 if (!inlink->hw_frames_ctx) {
72 av_log(ctx, AV_LOG_ERROR, "The input must have a hardware frame "
73 "reference.\n");
74 return AVERROR(EINVAL);
75 }
76
77 ctx->hwframes_ref = av_buffer_ref(inlink->hw_frames_ctx);
78 if (!ctx->hwframes_ref)
79 return AVERROR(ENOMEM);
80
81 ctx->hwframes = (AVHWFramesContext*)ctx->hwframes_ref->data;
82
83 return 0;
84}
85
86static int hwdownload_config_output(AVFilterLink *outlink)
87{
88 AVFilterContext *avctx = outlink->src;
89 AVFilterLink *inlink = avctx->inputs[0];
90 HWDownloadContext *ctx = avctx->priv;
91 enum AVPixelFormat *formats;
92 int err, i, found;
93
94 if (!ctx->hwframes_ref)
95 return AVERROR(EINVAL);
96
97 err = av_hwframe_transfer_get_formats(ctx->hwframes_ref,
98 AV_HWFRAME_TRANSFER_DIRECTION_FROM,
99 &formats, 0);
100 if (err < 0)
101 return err;
102
103 found = 0;
104 for (i = 0; formats[i] != AV_PIX_FMT_NONE; i++) {
105 if (formats[i] == outlink->format) {
106 found = 1;
107 break;
108 }
109 }
110 av_freep(&formats);
111
112 if (!found) {
113 av_log(ctx, AV_LOG_ERROR, "Invalid output format %s for hwframe "
114 "download.\n", av_get_pix_fmt_name(outlink->format));
115 return AVERROR(EINVAL);
116 }
117
118 outlink->w = inlink->w;
119 outlink->h = inlink->h;
120
121 return 0;
122}
123
124static int hwdownload_filter_frame(AVFilterLink *link, AVFrame *input)
125{
126 AVFilterContext *avctx = link->dst;
127 AVFilterLink *outlink = avctx->outputs[0];
128 HWDownloadContext *ctx = avctx->priv;
129 AVFrame *output = NULL;
130 int err;
131
132 if (!ctx->hwframes_ref || !input->hw_frames_ctx) {
133 av_log(ctx, AV_LOG_ERROR, "Input frames must have hardware context.\n");
134 err = AVERROR(EINVAL);
135 goto fail;
136 }
137 if ((void*)ctx->hwframes != input->hw_frames_ctx->data) {
138 av_log(ctx, AV_LOG_ERROR, "Input frame is not the in the configured "
139 "hwframe context.\n");
140 err = AVERROR(EINVAL);
141 goto fail;
142 }
143
144 output = ff_get_video_buffer(outlink, outlink->w, outlink->h);
145 if (!output) {
146 err = AVERROR(ENOMEM);
147 goto fail;
148 }
149
150 err = av_hwframe_transfer_data(output, input, 0);
151 if (err < 0) {
152 av_log(ctx, AV_LOG_ERROR, "Failed to download frame: %d.\n", err);
153 goto fail;
154 }
155
156 err = av_frame_copy_props(output, input);
157 if (err < 0)
158 goto fail;
159
160 av_frame_free(&input);
161
162 return ff_filter_frame(avctx->outputs[0], output);
163
164fail:
165 av_frame_free(&input);
166 av_frame_free(&output);
167 return err;
168}
169
170static av_cold void hwdownload_uninit(AVFilterContext *avctx)
171{
172 HWDownloadContext *ctx = avctx->priv;
173
174 av_buffer_unref(&ctx->hwframes_ref);
175}
176
177static const AVClass hwdownload_class = {
178 .class_name = "hwdownload",
179 .item_name = av_default_item_name,
180 .option = NULL,
181 .version = LIBAVUTIL_VERSION_INT,
182};
183
184static const AVFilterPad hwdownload_inputs[] = {
185 {
186 .name = "default",
187 .type = AVMEDIA_TYPE_VIDEO,
188 .config_props = hwdownload_config_input,
189 .filter_frame = hwdownload_filter_frame,
190 },
191 { NULL }
192};
193
194static const AVFilterPad hwdownload_outputs[] = {
195 {
196 .name = "default",
197 .type = AVMEDIA_TYPE_VIDEO,
198 .config_props = hwdownload_config_output,
199 },
200 { NULL }
201};
202
203AVFilter ff_vf_hwdownload = {
204 .name = "hwdownload",
205 .description = NULL_IF_CONFIG_SMALL("Download a hardware frame to a normal frame"),
206 .uninit = hwdownload_uninit,
207 .query_formats = hwdownload_query_formats,
208 .priv_size = sizeof(HWDownloadContext),
209 .priv_class = &hwdownload_class,
210 .inputs = hwdownload_inputs,
211 .outputs = hwdownload_outputs,
212};
libavfilter/vf_hwupload.c+241−0
@@ -0,0 +1,241 @@
1/*
2 * This file is part of Libav.
3 *
4 * Libav 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 * Libav 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 Libav; 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/hwcontext_internal.h"
22#include "libavutil/log.h"
23#include "libavutil/pixdesc.h"
24#include "libavutil/opt.h"
25
26#include "avfilter.h"
27#include "formats.h"
28#include "internal.h"
29#include "video.h"
30
31typedef struct HWUploadContext {
32 const AVClass *class;
33
34 AVBufferRef *hwdevice_ref;
35 AVHWDeviceContext *hwdevice;
36
37 AVBufferRef *hwframes_ref;
38 AVHWFramesContext *hwframes;
39} HWUploadContext;
40
41static int hwupload_query_formats(AVFilterContext *avctx)
42{
43 HWUploadContext *ctx = avctx->priv;
44 AVHWFramesConstraints *constraints = NULL;
45 const enum AVPixelFormat *input_pix_fmts, *output_pix_fmts;
46 AVFilterFormats *input_formats = NULL;
47 int err, i;
48
49 if (!avctx->hw_device_ctx) {
50 av_log(ctx, AV_LOG_ERROR, "A hardware device reference is required "
51 "to upload frames to.\n");
52 return AVERROR(EINVAL);
53 }
54
55 ctx->hwdevice_ref = av_buffer_ref(avctx->hw_device_ctx);
56 if (!ctx->hwdevice_ref)
57 return AVERROR(ENOMEM);
58 ctx->hwdevice = (AVHWDeviceContext*)ctx->hwdevice_ref->data;
59
60 constraints = av_hwdevice_get_hwframe_constraints(ctx->hwdevice_ref, NULL);
61 if (!constraints) {
62 err = AVERROR(EINVAL);
63 goto fail;
64 }
65
66 input_pix_fmts = constraints->valid_sw_formats;
67 output_pix_fmts = constraints->valid_hw_formats;
68
69 input_formats = ff_make_format_list(output_pix_fmts);
70 if (!input_formats) {
71 err = AVERROR(ENOMEM);
72 goto fail;
73 }
74 if (input_pix_fmts) {
75 for (i = 0; input_pix_fmts[i] != AV_PIX_FMT_NONE; i++) {
76 err = ff_add_format(&input_formats, input_pix_fmts[i]);
77 if (err < 0) {
78 ff_formats_unref(&input_formats);
79 goto fail;
80 }
81 }
82 }
83
84 ff_formats_ref(input_formats, &avctx->inputs[0]->out_formats);
85
86 ff_formats_ref(ff_make_format_list(output_pix_fmts),
87 &avctx->outputs[0]->in_formats);
88
89 av_hwframe_constraints_free(&constraints);
90 return 0;
91
92fail:
93 av_buffer_unref(&ctx->hwdevice_ref);
94 av_hwframe_constraints_free(&constraints);
95 return err;
96}
97
98static int hwupload_config_output(AVFilterLink *outlink)
99{
100 AVFilterContext *avctx = outlink->src;
101 AVFilterLink *inlink = avctx->inputs[0];
102 HWUploadContext *ctx = avctx->priv;
103 int err;
104
105 av_buffer_unref(&ctx->hwframes_ref);
106
107 if (inlink->format == outlink->format) {
108 // The input is already a hardware format, so we just want to
109 // pass through the input frames in their own hardware context.
110 if (!inlink->hw_frames_ctx) {
111 av_log(ctx, AV_LOG_ERROR, "No input hwframe context.\n");
112 return AVERROR(EINVAL);
113 }
114
115 outlink->hw_frames_ctx = av_buffer_ref(inlink->hw_frames_ctx);
116 if (!outlink->hw_frames_ctx)
117 return AVERROR(ENOMEM);
118
119 return 0;
120 }
121
122 ctx->hwframes_ref = av_hwframe_ctx_alloc(ctx->hwdevice_ref);
123 if (!ctx->hwframes_ref)
124 return AVERROR(ENOMEM);
125
126 ctx->hwframes = (AVHWFramesContext*)ctx->hwframes_ref->data;
127
128 av_log(ctx, AV_LOG_DEBUG, "Surface format is %s.\n",
129 av_get_pix_fmt_name(inlink->format));
130
131 ctx->hwframes->format = outlink->format;
132 ctx->hwframes->sw_format = inlink->format;
133 ctx->hwframes->width = inlink->w;
134 ctx->hwframes->height = inlink->h;
135
136 err = av_hwframe_ctx_init(ctx->hwframes_ref);
137 if (err < 0)
138 goto fail;
139
140 outlink->hw_frames_ctx = av_buffer_ref(ctx->hwframes_ref);
141 if (!outlink->hw_frames_ctx) {
142 err = AVERROR(ENOMEM);
143 goto fail;
144 }
145
146 return 0;
147
148fail:
149 av_buffer_unref(&ctx->hwframes_ref);
150 return err;
151}
152
153static int hwupload_filter_frame(AVFilterLink *link, AVFrame *input)
154{
155 AVFilterContext *avctx = link->dst;
156 AVFilterLink *outlink = avctx->outputs[0];
157 HWUploadContext *ctx = avctx->priv;
158 AVFrame *output = NULL;
159 int err;
160
161 if (input->format == outlink->format)
162 return ff_filter_frame(outlink, input);
163
164 output = av_frame_alloc();
165 if (!output) {
166 err = AVERROR(ENOMEM);
167 goto fail;
168 }
169
170 err = av_hwframe_get_buffer(ctx->hwframes_ref, output, 0);
171 if (err < 0) {
172 av_log(ctx, AV_LOG_ERROR, "Failed to allocate frame to upload to.\n");
173 goto fail;
174 }
175
176 output->width = input->width;
177 output->height = input->height;
178
179 err = av_hwframe_transfer_data(output, input, 0);
180 if (err < 0) {
181 av_log(ctx, AV_LOG_ERROR, "Failed to upload frame: %d.\n", err);
182 goto fail;
183 }
184
185 err = av_frame_copy_props(output, input);
186 if (err < 0)
187 goto fail;
188
189 av_frame_free(&input);
190
191 return ff_filter_frame(outlink, output);
192
193fail:
194 av_frame_free(&input);
195 av_frame_free(&output);
196 return err;
197}
198
199static av_cold void hwupload_uninit(AVFilterContext *avctx)
200{
201 HWUploadContext *ctx = avctx->priv;
202
203 av_buffer_unref(&ctx->hwframes_ref);
204 av_buffer_unref(&ctx->hwdevice_ref);
205}
206
207static const AVClass hwupload_class = {
208 .class_name = "hwupload",
209 .item_name = av_default_item_name,
210 .option = NULL,
211 .version = LIBAVUTIL_VERSION_INT,
212};
213
214static const AVFilterPad hwupload_inputs[] = {
215 {
216 .name = "default",
217 .type = AVMEDIA_TYPE_VIDEO,
218 .filter_frame = hwupload_filter_frame,
219 },
220 { NULL }
221};
222
223static const AVFilterPad hwupload_outputs[] = {
224 {
225 .name = "default",
226 .type = AVMEDIA_TYPE_VIDEO,
227 .config_props = hwupload_config_output,
228 },
229 { NULL }
230};
231
232AVFilter ff_vf_hwupload = {
233 .name = "hwupload",
234 .description = NULL_IF_CONFIG_SMALL("Upload a normal frame to a hardware frame"),
235 .uninit = hwupload_uninit,
236 .query_formats = hwupload_query_formats,
237 .priv_size = sizeof(HWUploadContext),
238 .priv_class = &hwupload_class,
239 .inputs = hwupload_inputs,
240 .outputs = hwupload_outputs,
241};

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t