Unified · Split
| @@ -13,6 +13,9 @@ libavutil: 2015-08-28 · 12 unmodified lines | ||
| 13 | 13 | |
| 14 | 14 | API changes, most recent first: |
| 15 | 15 | |
| 16 | +2016-xx-xx - xxxxxxx - lavfi 6.3.0 - avfilter.h | |
| 17 | + Add AVFilterContext.hw_device_ctx. | |
| 18 | + | |
| 16 | 19 | 2016-xx-xx - xxxxxxx - lavu 55.9.0 - hwcontext_vaapi.h |
| 17 | 20 | Add new installed header with VAAPI-specific hwcontext definitions. |
| 18 | 21 | |
| @@ -56,6 +56,8 @@ OBJS-$(CONFIG_FREI0R_FILTER) += vf_frei0r.o · 55 unmodified lines | ||
| 56 | 56 | OBJS-$(CONFIG_GRADFUN_FILTER) += vf_gradfun.o |
| 57 | 57 | OBJS-$(CONFIG_HFLIP_FILTER) += vf_hflip.o |
| 58 | 58 | OBJS-$(CONFIG_HQDN3D_FILTER) += vf_hqdn3d.o |
| 59 | +OBJS-$(CONFIG_HWDOWNLOAD_FILTER) += vf_hwdownload.o | |
| 60 | +OBJS-$(CONFIG_HWUPLOAD_FILTER) += vf_hwupload.o | |
| 59 | 61 | OBJS-$(CONFIG_HWUPLOAD_CUDA_FILTER) += vf_hwupload_cuda.o |
| 60 | 62 | OBJS-$(CONFIG_INTERLACE_FILTER) += vf_interlace.o |
| 61 | 63 | OBJS-$(CONFIG_LUT_FILTER) += vf_lut.o |
| @@ -82,6 +82,8 @@ void avfilter_register_all(void) · 81 unmodified lines | ||
| 82 | 82 | REGISTER_FILTER(GRADFUN, gradfun, vf); |
| 83 | 83 | REGISTER_FILTER(HFLIP, hflip, vf); |
| 84 | 84 | REGISTER_FILTER(HQDN3D, hqdn3d, vf); |
| 85 | + REGISTER_FILTER(HWDOWNLOAD, hwdownload, vf); | |
| 86 | + REGISTER_FILTER(HWUPLOAD, hwupload, vf); | |
| 85 | 87 | REGISTER_FILTER(HWUPLOAD_CUDA, hwupload_cuda, vf); |
| 86 | 88 | REGISTER_FILTER(INTERLACE, interlace, vf); |
| 87 | 89 | REGISTER_FILTER(LUT, lut, vf); |
| @@ -525,6 +525,8 @@ void avfilter_free(AVFilterContext *filter) · 524 unmodified lines | ||
| 525 | 525 | if (filter->filter->priv_class) |
| 526 | 526 | av_opt_free(filter->priv); |
| 527 | 527 | |
| 528 | + av_buffer_unref(&filter->hw_device_ctx); | |
| 529 | + | |
| 528 | 530 | av_freep(&filter->name); |
| 529 | 531 | av_freep(&filter->input_pads); |
| 530 | 532 | av_freep(&filter->output_pads); |
| @@ -300,6 +300,15 @@ struct AVFilterContext { · 299 unmodified lines | ||
| 300 | 300 | * An opaque struct for libavfilter internal use. |
| 301 | 301 | */ |
| 302 | 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 | /** |
| @@ -30,7 +30,7 @@ · 29 unmodified lines | ||
| 30 | 30 | #include "libavutil/version.h" |
| 31 | 31 | |
| 32 | 32 | #define LIBAVFILTER_VERSION_MAJOR 6 |
| 33 | −#define LIBAVFILTER_VERSION_MINOR 2 | |
| 33 | +#define LIBAVFILTER_VERSION_MINOR 3 | |
| 34 | 34 | #define LIBAVFILTER_VERSION_MICRO 0 |
| 35 | 35 | |
| 36 | 36 | #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \ |
| @@ -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 | +}; | |
| @@ -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 | +}; | |