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
1313
1414 API changes, most recent first:
1515
16+2016-xx-xx - xxxxxxx - lavfi 6.3.0 - avfilter.h
17+ Add AVFilterContext.hw_device_ctx.
18+
1619 2016-xx-xx - xxxxxxx - lavu 55.9.0 - hwcontext_vaapi.h
1720 Add new installed header with VAAPI-specific hwcontext definitions.
1821
libavfilter/Makefile+2−0
@@ -56,6 +56,8 @@ OBJS-$(CONFIG_FREI0R_FILTER) += vf_frei0r.o · 55 unmodified lines
5656 OBJS-$(CONFIG_GRADFUN_FILTER) += vf_gradfun.o
5757 OBJS-$(CONFIG_HFLIP_FILTER) += vf_hflip.o
5858 OBJS-$(CONFIG_HQDN3D_FILTER) += vf_hqdn3d.o
59+OBJS-$(CONFIG_HWDOWNLOAD_FILTER) += vf_hwdownload.o
60+OBJS-$(CONFIG_HWUPLOAD_FILTER) += vf_hwupload.o
5961 OBJS-$(CONFIG_HWUPLOAD_CUDA_FILTER) += vf_hwupload_cuda.o
6062 OBJS-$(CONFIG_INTERLACE_FILTER) += vf_interlace.o
6163 OBJS-$(CONFIG_LUT_FILTER) += vf_lut.o
libavfilter/allfilters.c+2−0
@@ -82,6 +82,8 @@ void avfilter_register_all(void) · 81 unmodified lines
8282 REGISTER_FILTER(GRADFUN, gradfun, vf);
8383 REGISTER_FILTER(HFLIP, hflip, vf);
8484 REGISTER_FILTER(HQDN3D, hqdn3d, vf);
85+ REGISTER_FILTER(HWDOWNLOAD, hwdownload, vf);
86+ REGISTER_FILTER(HWUPLOAD, hwupload, vf);
8587 REGISTER_FILTER(HWUPLOAD_CUDA, hwupload_cuda, vf);
8688 REGISTER_FILTER(INTERLACE, interlace, vf);
8789 REGISTER_FILTER(LUT, lut, vf);
libavfilter/avfilter.c+2−0
@@ -525,6 +525,8 @@ void avfilter_free(AVFilterContext *filter) · 524 unmodified lines
525525 if (filter->filter->priv_class)
526526 av_opt_free(filter->priv);
527527
528+ av_buffer_unref(&filter->hw_device_ctx);
529+
528530 av_freep(&filter->name);
529531 av_freep(&filter->input_pads);
530532 av_freep(&filter->output_pads);
libavfilter/avfilter.h+9−0
@@ -300,6 +300,15 @@ struct AVFilterContext { · 299 unmodified lines
300300 * An opaque struct for libavfilter internal use.
301301 */
302302 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;
303312 };
304313
305314 /**
libavfilter/version.h+1−1
@@ -30,7 +30,7 @@ · 29 unmodified lines
3030 #include "libavutil/version.h"
3131
3232 #define LIBAVFILTER_VERSION_MAJOR 6
33−#define LIBAVFILTER_VERSION_MINOR 2
33+#define LIBAVFILTER_VERSION_MINOR 3
3434 #define LIBAVFILTER_VERSION_MICRO 0
3535
3636 #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+
32+typedef struct HWDownloadContext {
33+ const AVClass *class;
34+
35+ AVBufferRef *hwframes_ref;
36+ AVHWFramesContext *hwframes;
37+} HWDownloadContext;
38+
39+static 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+
64+static 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+
86+static 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+
124+static 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+
164+fail:
165+ av_frame_free(&input);
166+ av_frame_free(&output);
167+ return err;
168+}
169+
170+static av_cold void hwdownload_uninit(AVFilterContext *avctx)
171+{
172+ HWDownloadContext *ctx = avctx->priv;
173+
174+ av_buffer_unref(&ctx->hwframes_ref);
175+}
176+
177+static 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+
184+static 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+
194+static const AVFilterPad hwdownload_outputs[] = {
195+ {
196+ .name = "default",
197+ .type = AVMEDIA_TYPE_VIDEO,
198+ .config_props = hwdownload_config_output,
199+ },
200+ { NULL }
201+};
202+
203+AVFilter 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+
31+typedef 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+
41+static 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+
92+fail:
93+ av_buffer_unref(&ctx->hwdevice_ref);
94+ av_hwframe_constraints_free(&constraints);
95+ return err;
96+}
97+
98+static 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+
148+fail:
149+ av_buffer_unref(&ctx->hwframes_ref);
150+ return err;
151+}
152+
153+static 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+
193+fail:
194+ av_frame_free(&input);
195+ av_frame_free(&output);
196+ return err;
197+}
198+
199+static 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+
207+static 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+
214+static const AVFilterPad hwupload_inputs[] = {
215+ {
216+ .name = "default",
217+ .type = AVMEDIA_TYPE_VIDEO,
218+ .filter_frame = hwupload_filter_frame,
219+ },
220+ { NULL }
221+};
222+
223+static const AVFilterPad hwupload_outputs[] = {
224+ {
225+ .name = "default",
226+ .type = AVMEDIA_TYPE_VIDEO,
227+ .config_props = hwupload_config_output,
228+ },
229+ { NULL }
230+};
231+
232+AVFilter 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