Unified · Split
| @@ -13,6 +13,9 @@ libavutil: 2015-08-28 · 12 unmodified lines | |||
| 13 | 13 | ||
| 14 | API changes, most recent first: | 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 | 2016-xx-xx - xxxxxxx - lavu 55.9.0 - hwcontext_vaapi.h | 19 | 2016-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 | ||
| @@ -56,6 +56,8 @@ OBJS-$(CONFIG_FREI0R_FILTER) += vf_frei0r.o · 55 unmodified lines | |||
| 56 | OBJS-$(CONFIG_GRADFUN_FILTER) += vf_gradfun.o | 56 | OBJS-$(CONFIG_GRADFUN_FILTER) += vf_gradfun.o |
| 57 | OBJS-$(CONFIG_HFLIP_FILTER) += vf_hflip.o | 57 | OBJS-$(CONFIG_HFLIP_FILTER) += vf_hflip.o |
| 58 | OBJS-$(CONFIG_HQDN3D_FILTER) += vf_hqdn3d.o | 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 | OBJS-$(CONFIG_HWUPLOAD_CUDA_FILTER) += vf_hwupload_cuda.o | 61 | OBJS-$(CONFIG_HWUPLOAD_CUDA_FILTER) += vf_hwupload_cuda.o |
| 60 | OBJS-$(CONFIG_INTERLACE_FILTER) += vf_interlace.o | 62 | OBJS-$(CONFIG_INTERLACE_FILTER) += vf_interlace.o |
| 61 | OBJS-$(CONFIG_LUT_FILTER) += vf_lut.o | 63 | OBJS-$(CONFIG_LUT_FILTER) += vf_lut.o |
| @@ -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); |
| @@ -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); |
| @@ -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 | /** |
| @@ -30,7 +30,7 @@ · 29 unmodified lines | |||
| 30 | #include "libavutil/version.h" | 30 | #include "libavutil/version.h" |
| 31 | 31 | ||
| 32 | #define LIBAVFILTER_VERSION_MAJOR 6 | 32 | #define LIBAVFILTER_VERSION_MAJOR 6 |
| 33 | #define LIBAVFILTER_VERSION_MINOR 2 | 33 | #define LIBAVFILTER_VERSION_MINOR 3 |
| 34 | #define LIBAVFILTER_VERSION_MICRO 0 | 34 | #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, \ |
| @@ -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 | }; | ||