Merge commit '07a844f32ebb78503981df017fa3ebfedb75fe1c'
authorDerek Buitenhuis <derek.buitenhuis@gmail.com>
Thu, 14 Apr 2016 12:59:45 +0000 (13:59 +0100)
committerDerek Buitenhuis <derek.buitenhuis@gmail.com>
Thu, 14 Apr 2016 12:59:45 +0000 (13:59 +0100)
* commit '07a844f32ebb78503981df017fa3ebfedb75fe1c':
  lavfi: generic hardware surface upload and download filters

Merged-by: Derek Buitenhuis <derek.buitenhuis@gmail.com>
1  2 
doc/APIchanges
libavfilter/Makefile
libavfilter/allfilters.c
libavfilter/avfilter.c
libavfilter/avfilter.h
libavfilter/version.h
libavfilter/vf_hwdownload.c
libavfilter/vf_hwupload.c

diff --cc doc/APIchanges
@@@ -15,114 -13,63 +15,117 @@@ libavutil:     2015-08-2
  
  API changes, most recent first:
  
 -2016-xx-xx - xxxxxxx - lavfi 6.3.0 - avfilter.h
++2016-xx-xx - xxxxxxx - lavfi 6.42.0 - avfilter.h
+   Add AVFilterContext.hw_device_ctx.
 -2016-xx-xx - xxxxxxx - lavu 55.9.0 - hwcontext_vaapi.h
 +2016-xx-xx - xxxxxxx - lavu 55.22.0 - hwcontext_vaapi.h
    Add new installed header with VAAPI-specific hwcontext definitions.
  
 -2016-xx-xx - xxxxxxx - lavu 55.8.0 - pixfmt.h
 -  Deprecate all AV_PIX_FMT_VAAPI_* formats.
 -  Replaced by AV_PIX_FMT_VAAPI.
 -
 -2016-xx-xx - xxxxxxx - lavu 55.7.0 - hwcontext.h
 +2016-xx-xx - xxxxxxx - lavu 55.21.0 - hwcontext.h
    Add AVHWFramesConstraints and associated API.
  
 -2016-02-23 - 9200514 - lavf 57.5.0 - avformat.h
 +2016-04-11 - xxxxxxx - lavf 57.33.0 - avformat.h
    Add AVStream.codecpar, deprecate AVStream.codec.
  
 -2016-xx-xx - lavc 57.14.0 - avcodec.h
 -  998e1b8 - Add AVCodecParameters and its related API.
 -  a806834 - Add av_get_audio_frame_duration2().
 +2016-04-02 - xxxxxxx - lavu 55.20.100 - base64.h
 +  Add AV_BASE64_DECODE_SIZE(x) macro.
 +
 +2016-xx-xx - lavc 57.33.0 - avcodec.h
 +  xxxxxxx - Add AVCodecParameters and its related API.
 +  xxxxxxx - Add av_get_audio_frame_duration2().
 +
 +2016-03-11 - xxxxxxx - lavf/lavc 57.28.101
 +  Add requirement to bitstream filtering API that returned packets with
 +  size == 0 and side_data_elems == 0 are to be skipped by the caller.
 +
 +2016-XX-XX - xxxxxxx - lavf 57.28.100
 +  Add protocol blacklisting API
 +
 +2016-02-28 - xxxxxxx - lavc 57.27.101
 +  Validate AVFrame returned by get_buffer2 to have required
 +  planes not NULL and unused planes set to NULL as crashes
 +  and buffer overflow are possible with certain streams if
 +  that is not the case.
 +
 +2016-xx-xx - xxxxxxx - lavc 57.27.100 - avcodec.h
 +  "flags2" decoding option now allows the flag "ass_ro_flush_noop" preventing
 +  the reset of the ASS ReadOrder field on flush. This affects the content of
 +  AVSubtitles.rects[N]->ass when "sub_text_format" is set to "ass" (see
 +  previous entry).
 +
 +2016-xx-xx - xxxxxxx - lavc 57.26.100 - avcodec.h
 +  Add a "sub_text_format" subtitles decoding option allowing the values "ass"
 +  (recommended) and "ass_with_timings" (not recommended, deprecated, default).
 +  The default value for this option will change to "ass" at the next major
 +  libavcodec version bump.
 +
 +  The current default is "ass_with_timings" for compatibility. This means that
 +  all subtitles text decoders currently still output ASS with timings printed
 +  as strings in the AVSubtitles.rects[N]->ass fields.
 +
 +  Setting "sub_text_format" to "ass" allows a better timing accuracy (ASS
 +  timing is limited to a 1/100 time base, so this is relevant for any subtitles
 +  format needing a bigger one), ease timing adjustments, and prevents the need
 +  of removing the timing from the decoded string yourself. This form is also
 +  known as "the Matroska form". The timing information (start time, duration)
 +  can be found in the AVSubtitles fields.
 +
 +2016-xx-xx - lavc 57.25.0 - avcodec.h
 +  Add AVCodecContext.hw_frames_ctx.
  
 -2016-02-22 - ec4c483 - lavf 57.4.0 - avformat.h
 -  Add AVFormatContext.protocol_whitelist and protocol_blacklist.
 -  Add 'protocol_whitelist' and 'protocol_blacklist' private options for
 -  avio_open2().
 +2016-xx-xx - lavfi 6.36.0 - avfilter.h
 +  xxxxxxx avfilter.h - Add AVFilterLink.hw_frames_ctx.
 +  xxxxxxx buffersrc.h - Add AVBufferSrcParameters and functions for handling it.
  
 -2016-02-14 - 7b3214d0 - lavc 57.13.0 - avcodec.h
 -  Add AVCodecContext.hw_frames_ctx.
 +2016-02-xx - xxxxxxx - lavc 57.25.100
 +  Add AV_PKT_DATA_MPEGTS_STREAM_ID for exporting the MPEGTS stream ID.
  
 -2016-02-14 - lavfi 6.2.0 - avfilter.h
 -  b3dd30d avfilter.h - Add AVFilterLink.hw_frames_ctx.
 -          buffersrc.h - Add AVBufferSrcParameters and functions for handling it.
 +2016-xx-xx - lavu 55.18.100
 +  xxxxxxx audio_fifo.h - Add av_audio_fifo_peek_at().
  
 -2016-02-14 - lavu 55.6.0
 -  721a4ef buffer.h - Add av_buffer_pool_init2().
 -  89923e4 hwcontext.h - Add a new installed header hwcontext.h with a new API
 +2016-xx-xx - lavu 55.18.0
 +  xxxxxxx buffer.h - Add av_buffer_pool_init2().
 +  xxxxxxx hwcontext.h - Add a new installed header hwcontext.h with a new API
                          for handling hwaccel frames.
 -  ad884d1 hwcontext_cuda.h - Add a new installed header hwcontext_cuda.h with
 +  xxxxxxx hwcontext_cuda.h - Add a new installed header hwcontext_cuda.h with
                               CUDA-specific hwcontext definitions.
 -  a001ce3 hwcontext_vdpau.h - Add a new installed header hwcontext_vdpau.h with
 +  xxxxxxx hwcontext_vdpau.h - Add a new installed header hwcontext_vdpau.h with
                                VDPAU-specific hwcontext definitions.
 -  7bc780c pixfmt.h - Add AV_PIX_FMT_CUDA.
 +  xxxxxxx pixfmt.h - Add AV_PIX_FMT_CUDA.
  
 -2016-01-24 - 9f61abc - lavf 57.3.0 - avformat.h
 +-------- 8< --------- FFmpeg 3.0 was cut here -------- 8< ---------
 +
 +2016-02-10 - bc9a596 / 9f61abc - lavf 57.25.100 / 57.3.0 - avformat.h
    Add AVFormatContext.opaque, io_open and io_close, allowing custom IO
 -  for muxers and demuxers that open additional files.
  
 -2015-12-12 - 2c68113 - lavc 57.12.0 - avcodec.h
 +2016-02-01 - 1dba837 - lavf 57.24.100 - avformat.h, avio.h
 +  Add protocol_whitelist to AVFormatContext, AVIOContext
 +
 +2016-01-31 - 66e9d2f - lavu 55.17.100 - frame.h
 +  Add AV_FRAME_DATA_GOP_TIMECODE for exporting MPEG1/2 GOP timecodes.
 +
 +2016-01-01 - 5e8b053 / 2c68113 - lavc 57.21.100 / 57.12.0 - avcodec.h
    Add AVCodecDescriptor.profiles and avcodec_profile_name().
  
 -2015-12-06 - lavc 57.11.0 - avcodec.h dirac.h
 -  31c51f7 - Add av_packet_add_side_data().
 -  84adab3 - Add AVCodecContext.coded_side_data.
 -  f0b769c - Add AVCPBProperties API.
 -  e02de9d - Add a new public header dirac.h containing
 +2015-12-28 - 1f9139b - lavf 57.21.100 - avformat.h
 +  Add automatic bitstream filtering; add av_apply_bitstream_filters()
 +
 +2015-12-22 - 39a09e9 - lavfi 6.21.101 - avfilter.h
 +  Deprecate avfilter_link_set_closed().
 +  Applications are not supposed to mess with links,
 +  they should close the sinks.
 +
 +2015-12-17 - lavc 57.18.100 / 57.11.0 - avcodec.h dirac.h
 +  xxxxxxx - Add av_packet_add_side_data().
 +  xxxxxxx - Add AVCodecContext.coded_side_data.
 +  xxxxxxx - Add AVCPBProperties API.
 +  xxxxxxx - Add a new public header dirac.h containing
              av_dirac_parse_sequence_header()
  
 -2015-11-20 - 462a54e - lavc 57.9.1 - avcodec.h
 +2015-12-11 - 676a93f - lavf 57.20.100 - avformat.h
 +  Add av_program_add_stream_index()
 +
 +2015-11-29 - 93fb4a4 - lavc 57.16.101 - avcodec.h
    Deprecate rtp_callback without replacement, i.e. it won't be possible to
    get image slices before the full frame is encoded any more. The libavformat
    rtpenc muxer can still be used for RFC-2190 packetization.
@@@ -169,30 -52,14 +169,32 @@@ OBJS-$(CONFIG_FIND_RECT_FILTER
  OBJS-$(CONFIG_FORMAT_FILTER)                 += vf_format.o
  OBJS-$(CONFIG_FPS_FILTER)                    += vf_fps.o
  OBJS-$(CONFIG_FRAMEPACK_FILTER)              += vf_framepack.o
 +OBJS-$(CONFIG_FRAMERATE_FILTER)              += vf_framerate.o
 +OBJS-$(CONFIG_FRAMESTEP_FILTER)              += vf_framestep.o
  OBJS-$(CONFIG_FREI0R_FILTER)                 += vf_frei0r.o
 +OBJS-$(CONFIG_FSPP_FILTER)                   += vf_fspp.o
 +OBJS-$(CONFIG_GEQ_FILTER)                    += vf_geq.o
  OBJS-$(CONFIG_GRADFUN_FILTER)                += vf_gradfun.o
 +OBJS-$(CONFIG_HALDCLUT_FILTER)               += vf_lut3d.o dualinput.o framesync.o
  OBJS-$(CONFIG_HFLIP_FILTER)                  += vf_hflip.o
 +OBJS-$(CONFIG_HISTEQ_FILTER)                 += vf_histeq.o
 +OBJS-$(CONFIG_HISTOGRAM_FILTER)              += vf_histogram.o
  OBJS-$(CONFIG_HQDN3D_FILTER)                 += vf_hqdn3d.o
 +OBJS-$(CONFIG_HQX_FILTER)                    += vf_hqx.o
+ OBJS-$(CONFIG_HWDOWNLOAD_FILTER)             += vf_hwdownload.o
+ OBJS-$(CONFIG_HWUPLOAD_FILTER)               += vf_hwupload.o
  OBJS-$(CONFIG_HWUPLOAD_CUDA_FILTER)          += vf_hwupload_cuda.o
 +OBJS-$(CONFIG_HSTACK_FILTER)                 += vf_stack.o framesync.o
 +OBJS-$(CONFIG_HUE_FILTER)                    += vf_hue.o
 +OBJS-$(CONFIG_IDET_FILTER)                   += vf_idet.o
 +OBJS-$(CONFIG_IL_FILTER)                     += vf_il.o
 +OBJS-$(CONFIG_INFLATE_FILTER)                += vf_neighbor.o
  OBJS-$(CONFIG_INTERLACE_FILTER)              += vf_interlace.o
 +OBJS-$(CONFIG_INTERLEAVE_FILTER)             += f_interleave.o
 +OBJS-$(CONFIG_KERNDEINT_FILTER)              += vf_kerndeint.o
 +OBJS-$(CONFIG_LENSCORRECTION_FILTER)         += vf_lenscorrection.o
 +OBJS-$(CONFIG_LOOP_FILTER)                   += f_loop.o
 +OBJS-$(CONFIG_LUT3D_FILTER)                  += vf_lut3d.o
  OBJS-$(CONFIG_LUT_FILTER)                    += vf_lut.o
  OBJS-$(CONFIG_LUTRGB_FILTER)                 += vf_lut.o
  OBJS-$(CONFIG_LUTYUV_FILTER)                 += vf_lut.o
@@@ -190,30 -78,14 +190,32 @@@ void avfilter_register_all(void
      REGISTER_FILTER(FORMAT,         format,         vf);
      REGISTER_FILTER(FPS,            fps,            vf);
      REGISTER_FILTER(FRAMEPACK,      framepack,      vf);
 +    REGISTER_FILTER(FRAMERATE,      framerate,      vf);
 +    REGISTER_FILTER(FRAMESTEP,      framestep,      vf);
      REGISTER_FILTER(FREI0R,         frei0r,         vf);
 +    REGISTER_FILTER(FSPP,           fspp,           vf);
 +    REGISTER_FILTER(GEQ,            geq,            vf);
      REGISTER_FILTER(GRADFUN,        gradfun,        vf);
 +    REGISTER_FILTER(HALDCLUT,       haldclut,       vf);
      REGISTER_FILTER(HFLIP,          hflip,          vf);
 +    REGISTER_FILTER(HISTEQ,         histeq,         vf);
 +    REGISTER_FILTER(HISTOGRAM,      histogram,      vf);
      REGISTER_FILTER(HQDN3D,         hqdn3d,         vf);
 +    REGISTER_FILTER(HQX,            hqx,            vf);
+     REGISTER_FILTER(HWDOWNLOAD,     hwdownload,     vf);
+     REGISTER_FILTER(HWUPLOAD,       hwupload,       vf);
      REGISTER_FILTER(HWUPLOAD_CUDA,  hwupload_cuda,  vf);
 +    REGISTER_FILTER(HSTACK,         hstack,         vf);
 +    REGISTER_FILTER(HUE,            hue,            vf);
 +    REGISTER_FILTER(IDET,           idet,           vf);
 +    REGISTER_FILTER(IL,             il,             vf);
 +    REGISTER_FILTER(INFLATE,        inflate,        vf);
      REGISTER_FILTER(INTERLACE,      interlace,      vf);
 +    REGISTER_FILTER(INTERLEAVE,     interleave,     vf);
 +    REGISTER_FILTER(KERNDEINT,      kerndeint,      vf);
 +    REGISTER_FILTER(LENSCORRECTION, lenscorrection, vf);
 +    REGISTER_FILTER(LOOP,           loop,           vf);
 +    REGISTER_FILTER(LUT3D,          lut3d,          vf);
      REGISTER_FILTER(LUT,            lut,            vf);
      REGISTER_FILTER(LUTRGB,         lutrgb,         vf);
      REGISTER_FILTER(LUTYUV,         lutyuv,         vf);
Simple merge
@@@ -344,12 -301,14 +344,21 @@@ struct AVFilterContext 
       */
      AVFilterInternal *internal;
  
+     /**
+      * For filters which will create hardware frames, sets the device the
+      * filter should create them in.  All other filters will ignore this field:
+      * in particular, a filter which consumes or processes hardware frames will
+      * instead use the hw_frames_ctx field in AVFilterLink to carry the
+      * hardware context information.
+      */
+     AVBufferRef *hw_device_ctx;
++
 +    struct AVFilterCommand *command_queue;
 +
 +    char *enable_str;               ///< enable expression string
 +    void *enable;                   ///< parsed expression (AVExpr*)
 +    double *var_values;             ///< variable values for the enable expression
 +    int is_disabled;                ///< the enabled state from the last expression evaluation
  };
  
  /**
@@@ -29,9 -29,9 +29,9 @@@
  
  #include "libavutil/version.h"
  
 -#define LIBAVFILTER_VERSION_MAJOR  6
 -#define LIBAVFILTER_VERSION_MINOR  3
 -#define LIBAVFILTER_VERSION_MICRO  0
 +#define LIBAVFILTER_VERSION_MAJOR   6
- #define LIBAVFILTER_VERSION_MINOR  41
- #define LIBAVFILTER_VERSION_MICRO 101
++#define LIBAVFILTER_VERSION_MINOR  42
++#define LIBAVFILTER_VERSION_MICRO 100
  
  #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
                                                 LIBAVFILTER_VERSION_MINOR, \
index 0000000,0ba1d98..2dcc9fa
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,212 +1,212 @@@
 - * This file is part of Libav.
+ /*
 - * Libav is free software; you can redistribute it and/or
++ * This file is part of FFmpeg.
+  *
 - * Libav is distributed in the hope that it will be useful,
++ * FFmpeg is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU Lesser General Public
+  * License as published by the Free Software Foundation; either
+  * version 2.1 of the License, or (at your option) any later version.
+  *
 - * License along with Libav; if not, write to the Free Software
++ * FFmpeg is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  * Lesser General Public License for more details.
+  *
+  * You should have received a copy of the GNU Lesser General Public
++ * License along with FFmpeg; if not, write to the Free Software
+  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+  */
+ #include "libavutil/avassert.h"
+ #include "libavutil/buffer.h"
+ #include "libavutil/hwcontext.h"
+ #include "libavutil/log.h"
+ #include "libavutil/mem.h"
+ #include "libavutil/opt.h"
+ #include "libavutil/pixdesc.h"
+ #include "avfilter.h"
+ #include "formats.h"
+ #include "internal.h"
+ #include "video.h"
+ typedef struct HWDownloadContext {
+     const AVClass *class;
+     AVBufferRef       *hwframes_ref;
+     AVHWFramesContext *hwframes;
+ } HWDownloadContext;
+ static int hwdownload_query_formats(AVFilterContext *avctx)
+ {
+     AVFilterFormats  *infmts = NULL;
+     AVFilterFormats *outfmts = NULL;
+     const AVPixFmtDescriptor *desc;
+     int err;
+     for (desc = av_pix_fmt_desc_next(NULL); desc;
+          desc = av_pix_fmt_desc_next(desc)) {
+         if (desc->flags & AV_PIX_FMT_FLAG_HWACCEL)
+             err = ff_add_format(&infmts,  av_pix_fmt_desc_get_id(desc));
+         else
+             err = ff_add_format(&outfmts, av_pix_fmt_desc_get_id(desc));
+         if (err) {
+             ff_formats_unref(&infmts);
+             ff_formats_unref(&outfmts);
+             return err;
+         }
+     }
+     ff_formats_ref(infmts,  &avctx->inputs[0]->out_formats);
+     ff_formats_ref(outfmts, &avctx->outputs[0]->in_formats);
+     return 0;
+ }
+ static int hwdownload_config_input(AVFilterLink *inlink)
+ {
+     AVFilterContext *avctx = inlink->dst;
+     HWDownloadContext *ctx = avctx->priv;
+     av_buffer_unref(&ctx->hwframes_ref);
+     if (!inlink->hw_frames_ctx) {
+         av_log(ctx, AV_LOG_ERROR, "The input must have a hardware frame "
+                "reference.\n");
+         return AVERROR(EINVAL);
+     }
+     ctx->hwframes_ref = av_buffer_ref(inlink->hw_frames_ctx);
+     if (!ctx->hwframes_ref)
+         return AVERROR(ENOMEM);
+     ctx->hwframes = (AVHWFramesContext*)ctx->hwframes_ref->data;
+     return 0;
+ }
+ static int hwdownload_config_output(AVFilterLink *outlink)
+ {
+     AVFilterContext *avctx = outlink->src;
+     AVFilterLink *inlink   = avctx->inputs[0];
+     HWDownloadContext *ctx = avctx->priv;
+     enum AVPixelFormat *formats;
+     int err, i, found;
+     if (!ctx->hwframes_ref)
+         return AVERROR(EINVAL);
+     err = av_hwframe_transfer_get_formats(ctx->hwframes_ref,
+                                           AV_HWFRAME_TRANSFER_DIRECTION_FROM,
+                                           &formats, 0);
+     if (err < 0)
+         return err;
+     found = 0;
+     for (i = 0; formats[i] != AV_PIX_FMT_NONE; i++) {
+         if (formats[i] == outlink->format) {
+             found = 1;
+             break;
+         }
+     }
+     av_freep(&formats);
+     if (!found) {
+         av_log(ctx, AV_LOG_ERROR, "Invalid output format %s for hwframe "
+                "download.\n", av_get_pix_fmt_name(outlink->format));
+         return AVERROR(EINVAL);
+     }
+     outlink->w = inlink->w;
+     outlink->h = inlink->h;
+     return 0;
+ }
+ static int hwdownload_filter_frame(AVFilterLink *link, AVFrame *input)
+ {
+     AVFilterContext *avctx = link->dst;
+     AVFilterLink  *outlink = avctx->outputs[0];
+     HWDownloadContext *ctx = avctx->priv;
+     AVFrame *output = NULL;
+     int err;
+     if (!ctx->hwframes_ref || !input->hw_frames_ctx) {
+         av_log(ctx, AV_LOG_ERROR, "Input frames must have hardware context.\n");
+         err = AVERROR(EINVAL);
+         goto fail;
+     }
+     if ((void*)ctx->hwframes != input->hw_frames_ctx->data) {
+         av_log(ctx, AV_LOG_ERROR, "Input frame is not the in the configured "
+                "hwframe context.\n");
+         err = AVERROR(EINVAL);
+         goto fail;
+     }
+     output = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+     if (!output) {
+         err = AVERROR(ENOMEM);
+         goto fail;
+     }
+     err = av_hwframe_transfer_data(output, input, 0);
+     if (err < 0) {
+         av_log(ctx, AV_LOG_ERROR, "Failed to download frame: %d.\n", err);
+         goto fail;
+     }
+     err = av_frame_copy_props(output, input);
+     if (err < 0)
+         goto fail;
+     av_frame_free(&input);
+     return ff_filter_frame(avctx->outputs[0], output);
+ fail:
+     av_frame_free(&input);
+     av_frame_free(&output);
+     return err;
+ }
+ static av_cold void hwdownload_uninit(AVFilterContext *avctx)
+ {
+     HWDownloadContext *ctx = avctx->priv;
+     av_buffer_unref(&ctx->hwframes_ref);
+ }
+ static const AVClass hwdownload_class = {
+     .class_name = "hwdownload",
+     .item_name  = av_default_item_name,
+     .option     = NULL,
+     .version    = LIBAVUTIL_VERSION_INT,
+ };
+ static const AVFilterPad hwdownload_inputs[] = {
+     {
+         .name         = "default",
+         .type         = AVMEDIA_TYPE_VIDEO,
+         .config_props = hwdownload_config_input,
+         .filter_frame = hwdownload_filter_frame,
+     },
+     { NULL }
+ };
+ static const AVFilterPad hwdownload_outputs[] = {
+     {
+         .name         = "default",
+         .type         = AVMEDIA_TYPE_VIDEO,
+         .config_props = hwdownload_config_output,
+     },
+     { NULL }
+ };
+ AVFilter ff_vf_hwdownload = {
+     .name          = "hwdownload",
+     .description   = NULL_IF_CONFIG_SMALL("Download a hardware frame to a normal frame"),
+     .uninit        = hwdownload_uninit,
+     .query_formats = hwdownload_query_formats,
+     .priv_size     = sizeof(HWDownloadContext),
+     .priv_class    = &hwdownload_class,
+     .inputs        = hwdownload_inputs,
+     .outputs       = hwdownload_outputs,
+ };
index 0000000,c438d5a..08af2dd
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,241 +1,241 @@@
 - * This file is part of Libav.
+ /*
 - * Libav is free software; you can redistribute it and/or
++ * This file is part of FFmpeg.
+  *
 - * Libav is distributed in the hope that it will be useful,
++ * FFmpeg is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU Lesser General Public
+  * License as published by the Free Software Foundation; either
+  * version 2.1 of the License, or (at your option) any later version.
+  *
 - * License along with Libav; if not, write to the Free Software
++ * FFmpeg is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  * Lesser General Public License for more details.
+  *
+  * You should have received a copy of the GNU Lesser General Public
++ * License along with FFmpeg; if not, write to the Free Software
+  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+  */
+ #include "libavutil/buffer.h"
+ #include "libavutil/hwcontext.h"
+ #include "libavutil/hwcontext_internal.h"
+ #include "libavutil/log.h"
+ #include "libavutil/pixdesc.h"
+ #include "libavutil/opt.h"
+ #include "avfilter.h"
+ #include "formats.h"
+ #include "internal.h"
+ #include "video.h"
+ typedef struct HWUploadContext {
+     const AVClass *class;
+     AVBufferRef       *hwdevice_ref;
+     AVHWDeviceContext *hwdevice;
+     AVBufferRef       *hwframes_ref;
+     AVHWFramesContext *hwframes;
+ } HWUploadContext;
+ static int hwupload_query_formats(AVFilterContext *avctx)
+ {
+     HWUploadContext *ctx = avctx->priv;
+     AVHWFramesConstraints *constraints = NULL;
+     const enum AVPixelFormat *input_pix_fmts, *output_pix_fmts;
+     AVFilterFormats *input_formats = NULL;
+     int err, i;
+     if (!avctx->hw_device_ctx) {
+         av_log(ctx, AV_LOG_ERROR, "A hardware device reference is required "
+                "to upload frames to.\n");
+         return AVERROR(EINVAL);
+     }
+     ctx->hwdevice_ref = av_buffer_ref(avctx->hw_device_ctx);
+     if (!ctx->hwdevice_ref)
+         return AVERROR(ENOMEM);
+     ctx->hwdevice = (AVHWDeviceContext*)ctx->hwdevice_ref->data;
+     constraints = av_hwdevice_get_hwframe_constraints(ctx->hwdevice_ref, NULL);
+     if (!constraints) {
+         err = AVERROR(EINVAL);
+         goto fail;
+     }
+     input_pix_fmts  = constraints->valid_sw_formats;
+     output_pix_fmts = constraints->valid_hw_formats;
+     input_formats = ff_make_format_list(output_pix_fmts);
+     if (!input_formats) {
+         err = AVERROR(ENOMEM);
+         goto fail;
+     }
+     if (input_pix_fmts) {
+         for (i = 0; input_pix_fmts[i] != AV_PIX_FMT_NONE; i++) {
+             err = ff_add_format(&input_formats, input_pix_fmts[i]);
+             if (err < 0) {
+                 ff_formats_unref(&input_formats);
+                 goto fail;
+             }
+         }
+     }
+     ff_formats_ref(input_formats, &avctx->inputs[0]->out_formats);
+     ff_formats_ref(ff_make_format_list(output_pix_fmts),
+                    &avctx->outputs[0]->in_formats);
+     av_hwframe_constraints_free(&constraints);
+     return 0;
+ fail:
+     av_buffer_unref(&ctx->hwdevice_ref);
+     av_hwframe_constraints_free(&constraints);
+     return err;
+ }
+ static int hwupload_config_output(AVFilterLink *outlink)
+ {
+     AVFilterContext *avctx = outlink->src;
+     AVFilterLink   *inlink = avctx->inputs[0];
+     HWUploadContext   *ctx = avctx->priv;
+     int err;
+     av_buffer_unref(&ctx->hwframes_ref);
+     if (inlink->format == outlink->format) {
+         // The input is already a hardware format, so we just want to
+         // pass through the input frames in their own hardware context.
+         if (!inlink->hw_frames_ctx) {
+             av_log(ctx, AV_LOG_ERROR, "No input hwframe context.\n");
+             return AVERROR(EINVAL);
+         }
+         outlink->hw_frames_ctx = av_buffer_ref(inlink->hw_frames_ctx);
+         if (!outlink->hw_frames_ctx)
+             return AVERROR(ENOMEM);
+         return 0;
+     }
+     ctx->hwframes_ref = av_hwframe_ctx_alloc(ctx->hwdevice_ref);
+     if (!ctx->hwframes_ref)
+         return AVERROR(ENOMEM);
+     ctx->hwframes = (AVHWFramesContext*)ctx->hwframes_ref->data;
+     av_log(ctx, AV_LOG_DEBUG, "Surface format is %s.\n",
+            av_get_pix_fmt_name(inlink->format));
+     ctx->hwframes->format    = outlink->format;
+     ctx->hwframes->sw_format = inlink->format;
+     ctx->hwframes->width     = inlink->w;
+     ctx->hwframes->height    = inlink->h;
+     err = av_hwframe_ctx_init(ctx->hwframes_ref);
+     if (err < 0)
+         goto fail;
+     outlink->hw_frames_ctx = av_buffer_ref(ctx->hwframes_ref);
+     if (!outlink->hw_frames_ctx) {
+         err = AVERROR(ENOMEM);
+         goto fail;
+     }
+     return 0;
+ fail:
+     av_buffer_unref(&ctx->hwframes_ref);
+     return err;
+ }
+ static int hwupload_filter_frame(AVFilterLink *link, AVFrame *input)
+ {
+     AVFilterContext *avctx = link->dst;
+     AVFilterLink  *outlink = avctx->outputs[0];
+     HWUploadContext   *ctx = avctx->priv;
+     AVFrame *output = NULL;
+     int err;
+     if (input->format == outlink->format)
+         return ff_filter_frame(outlink, input);
+     output = av_frame_alloc();
+     if (!output) {
+         err = AVERROR(ENOMEM);
+         goto fail;
+     }
+     err = av_hwframe_get_buffer(ctx->hwframes_ref, output, 0);
+     if (err < 0) {
+         av_log(ctx, AV_LOG_ERROR, "Failed to allocate frame to upload to.\n");
+         goto fail;
+     }
+     output->width  = input->width;
+     output->height = input->height;
+     err = av_hwframe_transfer_data(output, input, 0);
+     if (err < 0) {
+         av_log(ctx, AV_LOG_ERROR, "Failed to upload frame: %d.\n", err);
+         goto fail;
+     }
+     err = av_frame_copy_props(output, input);
+     if (err < 0)
+         goto fail;
+     av_frame_free(&input);
+     return ff_filter_frame(outlink, output);
+ fail:
+     av_frame_free(&input);
+     av_frame_free(&output);
+     return err;
+ }
+ static av_cold void hwupload_uninit(AVFilterContext *avctx)
+ {
+     HWUploadContext *ctx = avctx->priv;
+     av_buffer_unref(&ctx->hwframes_ref);
+     av_buffer_unref(&ctx->hwdevice_ref);
+ }
+ static const AVClass hwupload_class = {
+     .class_name = "hwupload",
+     .item_name  = av_default_item_name,
+     .option     = NULL,
+     .version    = LIBAVUTIL_VERSION_INT,
+ };
+ static const AVFilterPad hwupload_inputs[] = {
+     {
+         .name         = "default",
+         .type         = AVMEDIA_TYPE_VIDEO,
+         .filter_frame = hwupload_filter_frame,
+     },
+     { NULL }
+ };
+ static const AVFilterPad hwupload_outputs[] = {
+     {
+         .name         = "default",
+         .type         = AVMEDIA_TYPE_VIDEO,
+         .config_props = hwupload_config_output,
+     },
+     { NULL }
+ };
+ AVFilter ff_vf_hwupload = {
+     .name          = "hwupload",
+     .description   = NULL_IF_CONFIG_SMALL("Upload a normal frame to a hardware frame"),
+     .uninit        = hwupload_uninit,
+     .query_formats = hwupload_query_formats,
+     .priv_size     = sizeof(HWUploadContext),
+     .priv_class    = &hwupload_class,
+     .inputs        = hwupload_inputs,
+     .outputs       = hwupload_outputs,
+ };