diff --git a/Changelog b/Changelog
index cd8be931ef..777cca679a 100644
--- a/Changelog
+++ b/Changelog
@@ -22,6 +22,7 @@ version <next>:
 - MODS demuxer
 - PhotoCD decoder
 - MCA demuxer
+- http video filter, send raw frames to remote url for postprocessing
 
 
 version 4.3:
diff --git a/configure b/configure
index ae8c6e61c8..f5131d4669 100755
--- a/configure
+++ b/configure
@@ -325,6 +325,7 @@ External library support:
   --enable-vulkan          enable Vulkan code [no]
   --disable-xlib           disable xlib [autodetect]
   --disable-zlib           disable zlib [autodetect]
+  --enable-libcurl         enable http filter that send raw frames to remote server
 
   The following libraries provide various hardware acceleration features:
   --disable-amf            disable AMF video encoding code [autodetect]
@@ -1827,6 +1828,7 @@ EXTERNAL_LIBRARY_LIST="
     opengl
     pocketsphinx
     vapoursynth
+    libcurl
 "
 
 HWACCEL_AUTODETECT_LIBRARY_LIST="
@@ -3650,6 +3652,7 @@ vpp_qsv_filter_select="qsvvpp"
 xfade_opencl_filter_deps="opencl"
 yadif_cuda_filter_deps="ffnvcodec"
 yadif_cuda_filter_deps_any="cuda_nvcc cuda_llvm"
+http_filter_deps="libcurl"
 
 # examples
 avio_list_dir_deps="avformat avutil"
@@ -6367,6 +6370,7 @@ enabled libmysofa         && { check_pkg_config libmysofa libmysofa mysofa.h mys
 enabled libnpp            && { check_lib libnpp npp.h nppGetLibVersion -lnppig -lnppicc -lnppc -lnppidei ||
                                check_lib libnpp npp.h nppGetLibVersion -lnppi -lnppc -lnppidei ||
                                die "ERROR: libnpp not found"; }
+enabled libcurl           && require "libcurl >= 7.68.0" curl/curl.h curl_easy_init -lcurl
 enabled libopencore_amrnb && require libopencore_amrnb opencore-amrnb/interf_dec.h Decoder_Interface_init -lopencore-amrnb
 enabled libopencore_amrwb && require libopencore_amrwb opencore-amrwb/dec_if.h D_IF_init -lopencore-amrwb
 enabled libopencv         && { check_headers opencv2/core/core_c.h &&
diff --git a/doc/filters.texi b/doc/filters.texi
index cbb16f22b2..660ef8b4d9 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -12078,6 +12078,34 @@ For example, to horizontally flip the input video with @command{ffmpeg}:
 ffmpeg -i in.avi -vf "hflip" out.avi
 @end example
 
+@anchor{http}
+@section http
+
+Send raw frame data to the remote server for postprocessing and await response as new frame in same format and size. To enable filter configure ffmpeg with @code{./configure --enable-libcurl}.
+
+The filter accepts the following options:
+
+@table @option
+@item url
+Specify remote server url location.
+
+@item content_type
+Specify content-type header in request header, default to "application/octet-stream".
+@end table
+
+Simple demo http server for postprocessing frames can be found here: @url{https://github.com/devalexqt/simple_ffmpeg_http_filter_server}
+
+@subsection Examples
+@itemize
+
+@item
+Send raw frames to "http://localhost:3000/frame?param=abc"
+
+@example
+ffmpeg -i input.mp4 -vf format=rgb24,http=url="http\\\://localhost\\\:3000/frame?param=abc":content_type=application/octet-stream -t 10 out.mp4
+@end example
+@end itemize
+
 @section histeq
 This filter applies a global color histogram equalization on a
 per-frame basis.
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index e6d3c283da..38eb1f4204 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -467,6 +467,7 @@ OBJS-$(CONFIG_YAEPBLUR_FILTER)               += vf_yaepblur.o
 OBJS-$(CONFIG_ZMQ_FILTER)                    += f_zmq.o
 OBJS-$(CONFIG_ZOOMPAN_FILTER)                += vf_zoompan.o
 OBJS-$(CONFIG_ZSCALE_FILTER)                 += vf_zscale.o
+OBJS-$(CONFIG_HTTP_FILTER)                   += vf_http.o
 
 OBJS-$(CONFIG_ALLRGB_FILTER)                 += vsrc_testsrc.o
 OBJS-$(CONFIG_ALLYUV_FILTER)                 += vsrc_testsrc.o
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index fa91e608e4..8626fbc331 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -445,6 +445,7 @@ extern AVFilter ff_vf_yaepblur;
 extern AVFilter ff_vf_zmq;
 extern AVFilter ff_vf_zoompan;
 extern AVFilter ff_vf_zscale;
+extern AVFilter ff_vf_http;
 
 extern AVFilter ff_vsrc_allrgb;
 extern AVFilter ff_vsrc_allyuv;
diff --git a/libavfilter/version.h b/libavfilter/version.h
index 308fbe07c3..b8ba489da7 100644
--- a/libavfilter/version.h
+++ b/libavfilter/version.h
@@ -30,7 +30,7 @@
 #include "libavutil/version.h"
 
 #define LIBAVFILTER_VERSION_MAJOR   7
-#define LIBAVFILTER_VERSION_MINOR  87
+#define LIBAVFILTER_VERSION_MINOR  88
 #define LIBAVFILTER_VERSION_MICRO 100
 
 
diff --git a/libavfilter/vf_http.c b/libavfilter/vf_http.c
new file mode 100644
index 0000000000..f4290ca254
--- /dev/null
+++ b/libavfilter/vf_http.c
@@ -0,0 +1,221 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * 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.
+ *
+ * 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
+ */
+
+/**
+ * @file
+ * http video filter
+ */
+
+#include "libavutil/avassert.h"
+#include "libavutil/opt.h"
+#include "libavutil/internal.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/avstring.h"
+#include "avfilter.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.h"
+#include "stdio.h"
+#include "curl/curl.h"
+
+struct MemoryStruct {
+  uint8_t *memory;
+  size_t size;
+};
+
+typedef struct HttpContext {
+    const AVClass *class;
+    char *url;
+    char *content_type;
+    CURL *curl;
+    struct curl_slist *headers;
+} HttpContext;
+
+#define OFFSET(x) offsetof(HttpContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+
+static const AVOption http_options[] = {
+    { "url", "set remote url address", OFFSET(url), AV_OPT_TYPE_STRING, {.str=NULL}, FLAGS },
+    { "content_type", "set 'Content-Type' request header", OFFSET(content_type), AV_OPT_TYPE_STRING, {.str="application/octet-stream"}, FLAGS },
+    { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(http);
+
+static av_cold int init(AVFilterContext *ctx)
+{
+    HttpContext *http = ctx->priv;
+    http->curl = curl_easy_init();
+
+    /* check if remote server url is valid formated */
+    CURLU *url= curl_url();
+    CURLUcode result;
+
+    /* parse a full URL */ 
+    result = curl_url_set(url, CURLUPART_URL, http->url, 0);
+    if(result){
+        av_log(NULL, AV_LOG_ERROR, "http filter failed: invalid input url!\n");
+    return AVERROR(EINVAL); 
+    }
+
+    /* set request headers */
+    http->headers=NULL;
+    http->headers = curl_slist_append(http->headers, av_asprintf("Content-Type: %s",http->content_type));
+    http->headers = curl_slist_append(http->headers, "Expect:");
+    curl_easy_setopt(http->curl, CURLOPT_HTTPHEADER, http->headers);
+    curl_easy_setopt(http->curl, CURLOPT_FOLLOWLOCATION, 1L);
+
+    curl_url_cleanup(url);
+    return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+    HttpContext *http = ctx->priv;
+    
+    curl_easy_cleanup(http->curl);
+    curl_slist_free_all(http->headers);
+    curl_global_cleanup();
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+    const HttpContext *http = ctx->priv;
+    return ff_default_query_formats(ctx);
+}
+
+static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
+{
+    size_t realsize = size * nmemb;
+    struct MemoryStruct *mem = (struct MemoryStruct *)userp;
+ 
+    char *ptr = realloc(mem->memory, mem->size + realsize + 1);
+    if(!ptr) {
+      /* out of memory! */ 
+      return AVERROR(ENOMEM); 
+    }
+ 
+    mem->memory = ptr;
+    memcpy(&(mem->memory[mem->size]), contents, realsize);
+    mem->size += realsize;
+    mem->memory[mem->size] = 0;
+ 
+  return realsize;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+    AVFilterContext *ctx = inlink->dst;
+    AVFilterLink *outlink = ctx->outputs[0];
+    HttpContext *http = inlink->dst->priv;
+    AVFrame *out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+    if (!out) {
+       av_frame_free(&in);
+       return AVERROR(ENOMEM); 
+    }
+    av_frame_copy_props(out, in);
+
+    CURL *curl=http->curl;
+    CURLU *url= curl_url();
+    CURLcode res;
+    struct MemoryStruct chunk;
+       chunk.memory = av_malloc(1);
+       chunk.size = 0;    
+
+    /* create buffer and copy input frame */
+    int buff_size=av_image_get_buffer_size(in->format, in->width, in->height, 1);
+    uint8_t *buffer=av_malloc(buff_size);    
+    av_image_copy_to_buffer(buffer, buff_size, in->data, in->linesize, in->format, in->width, in->height, 1);
+
+    /* update url query */
+    CURLUcode result;
+    const char *url_params=av_asprintf("width=%d&height=%d&format=%d&size=%d&pts=%ld",in->width, in->height, in->format, buff_size, in->pts);
+    curl_url_set(url, CURLUPART_URL, http->url, 0);
+    result = curl_url_set(url, CURLUPART_QUERY, url_params, CURLU_APPENDQUERY);
+    if(result){
+        av_log(NULL, AV_LOG_ERROR, "http filter failed: failed to setup url query params!\n");
+    return AVERROR(EINVAL); 
+    }
+
+    /* specify the POST data */ 
+    curl_easy_setopt(http->curl, CURLOPT_CURLU,url);
+    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, buffer);
+    curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, buff_size);
+
+    /* send all data to this function  */ 
+    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
+        
+    /* we pass our 'chunk' struct to the callback function */ 
+    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
+    curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");
+
+    /* Perform the request, res will get the return code */ 
+    res = curl_easy_perform(curl);
+
+    /* Check for errors */ 
+    if(res != CURLE_OK){
+        av_log(NULL, AV_LOG_ERROR, "http filter failed: %s\n", curl_easy_strerror(res));
+        av_frame_free(&in);
+        av_frame_free(&out);
+        free(buffer);
+    return AVERROR(EINVAL);
+    }
+    else{
+        if(chunk.size!=buff_size){
+           av_log(NULL, AV_LOG_ERROR, "http filter failed: size of the input and received frames must be equal!\n");
+        return AVERROR(EINVAL);
+        }
+        /* fill frame data from received buffer */
+        av_image_fill_arrays(out->data, out->linesize, chunk.memory, out->format, out->width, out->height, 1);
+    }
+       
+        /* cleanup */ 
+        curl_url_cleanup(url);
+        av_free(buffer);
+        av_frame_free(&in);
+    return ff_filter_frame(outlink, out);
+} 
+
+static const AVFilterPad avfilter_vf_http_inputs[] = {
+    {
+        .name = "default",
+        .type = AVMEDIA_TYPE_VIDEO,
+        .filter_frame = filter_frame,        
+    },
+    { NULL }
+};
+
+static const AVFilterPad avfilter_vf_http_outputs[] = {
+    {
+        .name = "default",
+        .type = AVMEDIA_TYPE_VIDEO,
+    },
+    { NULL }
+};
+
+AVFilter ff_vf_http = {
+    .name          = "http",
+    .description   = NULL_IF_CONFIG_SMALL("Send raw frame data to the remote server for postprocessing and await response as new frame in same format and size."),
+    .priv_size     = sizeof(HttpContext),
+    .init          = init,
+    .uninit        = uninit,
+    .query_formats = query_formats,
+    .inputs        = avfilter_vf_http_inputs,
+    .outputs       = avfilter_vf_http_outputs,
+    .priv_class    = &http_class,
+};
