You've already forked FFmpeg
mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-11-23 21:54:53 +02:00
avfilter: add gfxcapture, Windows.Graphics.Capture based window/monitor capture
This commit is contained in:
@@ -4,6 +4,7 @@ releases are sorted from youngest to oldest.
|
||||
version <next>:
|
||||
- ffprobe -codec option
|
||||
- EXIF Metadata Parsing
|
||||
- gfxcapture: Windows.Graphics.Capture based window/monitor capture
|
||||
|
||||
|
||||
version 8.0:
|
||||
|
||||
8
configure
vendored
8
configure
vendored
@@ -2516,6 +2516,8 @@ TOOLCHAIN_FEATURES="
|
||||
TYPES_LIST="
|
||||
DPI_AWARENESS_CONTEXT
|
||||
IDXGIOutput5
|
||||
__x_ABI_CWindows_CGraphics_CCapture_CIGraphicsCaptureSession5
|
||||
IDirect3DDxgiInterfaceAccess
|
||||
kCMVideoCodecType_HEVC
|
||||
kCMVideoCodecType_HEVCWithAlpha
|
||||
kCMVideoCodecType_VP9
|
||||
@@ -3412,6 +3414,8 @@ pad_cuda_filter_deps_any="cuda_nvcc cuda_llvm"
|
||||
sharpen_npp_filter_deps="ffnvcodec libnpp"
|
||||
|
||||
ddagrab_filter_deps="d3d11va IDXGIOutput1 DXGI_OUTDUPL_FRAME_INFO"
|
||||
gfxcapture_filter_deps="cxx17 threads d3d11va IGraphicsCaptureItemInterop __x_ABI_CWindows_CGraphics_CCapture_CIGraphicsCaptureSession3"
|
||||
gfxcapture_filter_extralibs="-lstdc++"
|
||||
scale_d3d11_filter_deps="d3d11va"
|
||||
|
||||
amf_deps_any="libdl LoadLibrary"
|
||||
@@ -6940,6 +6944,10 @@ check_type "windows.h" "DPI_AWARENESS_CONTEXT" -D_WIN32_WINNT=0x0A00
|
||||
check_type "windows.h security.h schnlsp.h" SecPkgContext_KeyingMaterialInfo -DSECURITY_WIN32
|
||||
check_type "d3d9.h dxva2api.h" DXVA2_ConfigPictureDecode -D_WIN32_WINNT=0x0602
|
||||
check_func_headers mfapi.h MFCreateAlignedMemoryBuffer -lmfplat
|
||||
check_type "windows.h windows.graphics.capture.h" __x_ABI_CWindows_CGraphics_CCapture_CIGraphicsCaptureSession3 -D_WIN32_WINNT=0x0A00 -DWINDOWS_FOUNDATION_UNIVERSALAPICONTRACT_VERSION=0x130000 -DCOBJMACROS
|
||||
check_type "windows.h windows.graphics.capture.h" __x_ABI_CWindows_CGraphics_CCapture_CIGraphicsCaptureSession5 -D_WIN32_WINNT=0x0A00 -DWINDOWS_FOUNDATION_UNIVERSALAPICONTRACT_VERSION=0x130000 -DCOBJMACROS
|
||||
check_type "windows.h windows.graphics.capture.interop.h" IGraphicsCaptureItemInterop -D_WIN32_WINNT=0x0A00 -DWINDOWS_FOUNDATION_UNIVERSALAPICONTRACT_VERSION=0x130000 -DCOBJMACROS
|
||||
check_type "windows.h windows.graphics.directx.direct3d11.interop.h" IDirect3DDxgiInterfaceAccess -D_WIN32_WINNT=0x0A00 -DWINDOWS_FOUNDATION_UNIVERSALAPICONTRACT_VERSION=0x130000 -DCOBJMACROS
|
||||
|
||||
check_type "vdpau/vdpau.h" "VdpPictureInfoHEVC"
|
||||
check_type "vdpau/vdpau.h" "VdpPictureInfoVP9"
|
||||
|
||||
159
doc/filters.texi
159
doc/filters.texi
@@ -29614,6 +29614,165 @@ ddagrab=video_size=800x600:offset_x=100:offset_y=100
|
||||
@end example
|
||||
|
||||
|
||||
@section gfxcapture
|
||||
|
||||
Capture windows or monitors using Windows.Graphics.Capture API.
|
||||
|
||||
This source provides low overhead capture of application windows or entire monitors.
|
||||
The filter outputs hardware frames in @code{d3d11} format; use @code{hwdownload,format=}
|
||||
if system memory frames are required.
|
||||
|
||||
The window to be captured can be selected via regular expressions on its title,
|
||||
class name or backing executable name, by explicit native handles, or by monitor
|
||||
index or explicit native handle. A window must match all provided expressions to be
|
||||
selected. The first matching window will be picked, in whatever order Windows
|
||||
returns them.
|
||||
|
||||
Explicit handles (@option{hwnd}, @option{hmonitor}) override pattern or index
|
||||
based selection. If neither handles nor a monitor index are given, the first
|
||||
window matching the provided regular expressions is captured.
|
||||
|
||||
This source does NOT hold a stable FPS. It returns frames at whatever rate the compositor
|
||||
provides them, only capped by the @option{max_framerate}.
|
||||
If you need a stable rate, you need to add an fps filter to drop/duplicate frames as needed.
|
||||
|
||||
If the capture source disappears mid-capture (window closed, monitor disconnected), the filter will return EOF.
|
||||
|
||||
This source accepts the following options:
|
||||
@table @option
|
||||
@item window_title
|
||||
ECMAScript regular expression matched against the window title. Supports a
|
||||
PCRE style @code{(?i)} prefix for case-insensitive matching.
|
||||
|
||||
@item window_class
|
||||
As @option{window_title}, but matched against the window class name.
|
||||
|
||||
@item window_exe
|
||||
As @option{window_title}, but matched against the executable file name of the
|
||||
window's process.
|
||||
|
||||
@item monitor_idx
|
||||
Zero-based index of the monitor to capture.
|
||||
|
||||
Can also be set to @code{window} to capture the monitor the selected window
|
||||
is displayed on at filter initialization time.
|
||||
|
||||
@item hwnd
|
||||
Explicit native window handle (HWND).
|
||||
|
||||
@item hmonitor
|
||||
Explicit native monitor handle (HMONITOR).
|
||||
|
||||
@item capture_cursor
|
||||
Capture the mouse cursor. Enabled by default.
|
||||
|
||||
@item capture_border
|
||||
Capture the full area of the window, including its window decorarions/border.
|
||||
Disabled by default.
|
||||
|
||||
@item display_border
|
||||
Draw a yellow highlight border around the captured window. Disabled by default.
|
||||
|
||||
@item max_framerate
|
||||
Maximum capture frame rate. Accepts a video rate (e.g. @code{30}, @code{60/1},
|
||||
@code{24000/1001}). The default is @code{60} FPS.
|
||||
The actual rate is the rate at which the compositor renders the window/monitor,
|
||||
capped by this option.
|
||||
|
||||
@item width
|
||||
Force the output canvas width. If zero (default) the initial captured source
|
||||
width is used. If a negative number is provided, the width will be rounded
|
||||
down to the next multiple of that number.
|
||||
|
||||
See @option{resize_mode}.
|
||||
|
||||
@item height
|
||||
Force the output canvas height. If zero (default) the initial captured source
|
||||
height is used. If a negative number is provided, the height will be rounded
|
||||
down to the next multiple of that number.
|
||||
|
||||
See @option{resize_mode}.
|
||||
|
||||
@item crop_left
|
||||
Crop this many pixels from the left side of the captured frames.
|
||||
|
||||
@item crop_top
|
||||
Crop this many pixels from the left side of the captured frames.
|
||||
|
||||
@item crop_right
|
||||
Crop this many pixels from the left side of the captured frames.
|
||||
|
||||
@item crop_bottom
|
||||
Crop this many pixels from the left side of the captured frames.
|
||||
|
||||
@item premultiplied
|
||||
If set to 1, return frames with premultiplied alpha. Default is 0 (straight
|
||||
alpha).
|
||||
|
||||
@item resize_mode
|
||||
Defines how the captured content is fitted into the output canvas size.
|
||||
Possible values:
|
||||
@table @samp
|
||||
@item crop
|
||||
Crop (or pad with black) to the canvas size. (default)
|
||||
@item scale
|
||||
Scale the source to fill the canvas, potentially altering aspect ratio.
|
||||
@item scale_aspect
|
||||
Scale the source to fit inside the canvas while preserving aspect ratio.
|
||||
Remaining area is filled with black.
|
||||
@end table
|
||||
|
||||
@item scale_mode
|
||||
Scaling algorithm used when resizing is required.
|
||||
|
||||
Possible values:
|
||||
@table @samp
|
||||
@item point
|
||||
Nearest neighbour (pixelated) scaling.
|
||||
@item bilinear
|
||||
Bilinear filtering. (default)
|
||||
@item bicubic
|
||||
Bicubic filtering. Potentially more blurry, but fewer scaling artifacts depending on contents.
|
||||
@end table
|
||||
|
||||
@item output_fmt
|
||||
Desired output pixel format inside the D3D11 hardware frames.
|
||||
|
||||
Possible values:
|
||||
@table @samp
|
||||
@item bgra
|
||||
@item 8bit
|
||||
8 bit BGRA output (default)
|
||||
@item x2bgr10
|
||||
@item 10bit
|
||||
10 bit BGR output
|
||||
@item rgbaf16
|
||||
@item 16bit
|
||||
16bit float RGBA output
|
||||
@end table
|
||||
|
||||
@end table
|
||||
|
||||
@subsection Examples
|
||||
@itemize
|
||||
@item Capture a window by title (case-insensitive) at a maximum of 60 fps:
|
||||
@example
|
||||
ffmpeg -filter_complex gfxcapture=window_text='(?i)My Application':max_framerate=60,hwdownload,format=bgra,format=yuv420p -c:v libx264 -crf 15 capture.mp4
|
||||
@end example
|
||||
|
||||
@item Capture monitor 1 at native refresh, 10bit color depth, scale to 1920x1080 preserving aspect:
|
||||
@example
|
||||
ffmpeg -filter_complex gfxcapture=monitor_idx=1:width=1920:height=1080:resize_mode=scale_aspect:output_fmt=10bit -c:v hevc_nvenc -cq 15 capture.mp4
|
||||
@end example
|
||||
|
||||
@item Capture a window by executable name, draw border, force point scaling, fixed 60 fps:
|
||||
@example
|
||||
ffmpeg -filter_complex gfxcapture=window_exe='^firefox.exe$':display_border=1:scale_mode=point,fps=60 -rc qvbr -qvbr_quality_level 15 -c:v h264_amf capture.mp4
|
||||
@end example
|
||||
|
||||
@end itemize
|
||||
|
||||
|
||||
@section gradients
|
||||
Generate several gradients.
|
||||
|
||||
|
||||
@@ -609,6 +609,7 @@ OBJS-$(CONFIG_COLORSPECTRUM_FILTER) += vsrc_testsrc.o
|
||||
OBJS-$(CONFIG_COREIMAGESRC_FILTER) += vf_coreimage.o
|
||||
OBJS-$(CONFIG_DDAGRAB_FILTER) += vsrc_ddagrab.o
|
||||
OBJS-$(CONFIG_FREI0R_SRC_FILTER) += vf_frei0r.o
|
||||
OBJS-$(CONFIG_GFXCAPTURE_FILTER) += vsrc_gfxcapture.o vsrc_gfxcapture_winrt.o
|
||||
OBJS-$(CONFIG_GRADIENTS_FILTER) += vsrc_gradients.o
|
||||
OBJS-$(CONFIG_HALDCLUTSRC_FILTER) += vsrc_testsrc.o
|
||||
OBJS-$(CONFIG_LIFE_FILTER) += vsrc_life.o
|
||||
|
||||
@@ -571,6 +571,7 @@ extern const FFFilter ff_vsrc_colorspectrum;
|
||||
extern const FFFilter ff_vsrc_coreimagesrc;
|
||||
extern const FFFilter ff_vsrc_ddagrab;
|
||||
extern const FFFilter ff_vsrc_frei0r_src;
|
||||
extern const FFFilter ff_vsrc_gfxcapture;
|
||||
extern const FFFilter ff_vsrc_gradients;
|
||||
extern const FFFilter ff_vsrc_haldclutsrc;
|
||||
extern const FFFilter ff_vsrc_life;
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
#include "version_major.h"
|
||||
|
||||
#define LIBAVFILTER_VERSION_MINOR 8
|
||||
#define LIBAVFILTER_VERSION_MINOR 9
|
||||
#define LIBAVFILTER_VERSION_MICRO 100
|
||||
|
||||
|
||||
|
||||
102
libavfilter/vsrc_gfxcapture.c
Normal file
102
libavfilter/vsrc_gfxcapture.c
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "libavutil/internal.h"
|
||||
#include "libavutil/opt.h"
|
||||
#include "avfilter.h"
|
||||
#include "filters.h"
|
||||
|
||||
#include "vsrc_gfxcapture.h"
|
||||
|
||||
#define OFFSET(x) offsetof(GfxCaptureContext, x)
|
||||
#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
|
||||
static const AVOption gfxcapture_options[] = {
|
||||
{ "window_title", "ECMAScript regular expression to match against the window title. "
|
||||
"Supports PCRE style (?i) prefix for case-insensitivity.",
|
||||
OFFSET(window_text), AV_OPT_TYPE_STRING, { .str = NULL }, 0, INT_MAX, FLAGS },
|
||||
{ "window_class", "as window_title, but against the window class",
|
||||
OFFSET(window_class), AV_OPT_TYPE_STRING, { .str = NULL }, 0, INT_MAX, FLAGS },
|
||||
{ "window_exe", "as window_title, but against the windows executable name",
|
||||
OFFSET(window_exe), AV_OPT_TYPE_STRING, { .str = NULL }, 0, INT_MAX, FLAGS },
|
||||
{ "monitor_idx", "index of the monitor to capture", OFFSET(monitor_idx), AV_OPT_TYPE_INT, { .i64 = GFX_MONITOR_IDX_DEFAULT }, GFX_MONITOR_IDX_DEFAULT, INT_MAX, FLAGS, .unit = "monitor_idx" },
|
||||
{ "window", "derive from selected window", 0, AV_OPT_TYPE_CONST, { .i64 = GFX_MONITOR_IDX_WINDOW }, 0, 0, FLAGS, .unit = "monitor_idx" },
|
||||
{ "capture_cursor", "capture mouse cursor", OFFSET(capture_cursor), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, FLAGS },
|
||||
{ "capture_border", "capture full window border", OFFSET(capture_border), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS },
|
||||
{ "display_border", "display yellow border around captured window",
|
||||
OFFSET(display_border), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS },
|
||||
{ "max_framerate", "set maximum capture frame rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, { .str = "60" }, 0.001, 1000, FLAGS },
|
||||
{ "hwnd", "pre-existing HWND handle", OFFSET(user_hwnd), AV_OPT_TYPE_UINT64, { .i64 = 0 }, 0, UINT64_MAX, FLAGS },
|
||||
{ "hmonitor", "pre-existing HMONITOR handle", OFFSET(user_hmonitor), AV_OPT_TYPE_UINT64, { .i64 = 0 }, 0, UINT64_MAX, FLAGS },
|
||||
{ "width", "force width of the output frames, negative values round down the width to the nearest multiple of that number",
|
||||
OFFSET(canvas_width), AV_OPT_TYPE_INT, { .i64 = 0 }, INT_MIN, INT_MAX, FLAGS },
|
||||
{ "height", "force height of the output frames, negative values round down the height to the nearest multiple of that number",
|
||||
OFFSET(canvas_height), AV_OPT_TYPE_INT, { .i64 = 0 }, INT_MIN, INT_MAX, FLAGS },
|
||||
{ "crop_left", "number of pixels to crop from the left of the captured area",
|
||||
OFFSET(crop_left), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS },
|
||||
{ "crop_top", "number of pixels to crop from the top of the captured area",
|
||||
OFFSET(crop_top), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS },
|
||||
{ "crop_right", "number of pixels to crop from the right of the captured area",
|
||||
OFFSET(crop_right), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS },
|
||||
{ "crop_bottom", "number of pixels to crop from the bottom of the captured area",
|
||||
OFFSET(crop_bottom), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS },
|
||||
{ "premultiplied", "return premultiplied alpha frames", OFFSET(premult_alpha), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS },
|
||||
{ "resize_mode", "capture source resize behavior", OFFSET(resize_mode), AV_OPT_TYPE_INT, { .i64 = GFX_RESIZE_CROP }, 0, GFX_RESIZE_NB - 1, FLAGS, .unit = "resize_mode" },
|
||||
{ "crop", "crop or add black bars into frame", 0, AV_OPT_TYPE_CONST, { .i64 = GFX_RESIZE_CROP }, 0, 0, FLAGS, .unit = "resize_mode" },
|
||||
{ "scale", "scale source to fit initial size", 0, AV_OPT_TYPE_CONST, { .i64 = GFX_RESIZE_SCALE }, 0, 0, FLAGS, .unit = "resize_mode" },
|
||||
{ "scale_aspect", "scale source to fit initial size while preserving aspect ratio",
|
||||
0, AV_OPT_TYPE_CONST, { .i64 = GFX_RESIZE_SCALE_ASPECT }, 0, 0, FLAGS, .unit = "resize_mode" },
|
||||
{ "scale_mode", "scaling algorithm", OFFSET(scale_mode), AV_OPT_TYPE_INT, { .i64 = GFX_SCALE_BILINEAR }, 0, GFX_SCALE_NB - 1, FLAGS, .unit = "scale_mode" },
|
||||
{ "point", "use point scaling", 0, AV_OPT_TYPE_CONST, { .i64 = GFX_SCALE_POINT }, 0, 0, FLAGS, .unit = "scale_mode" },
|
||||
{ "bilinear", "use bilinear scaling", 0, AV_OPT_TYPE_CONST, { .i64 = GFX_SCALE_BILINEAR }, 0, 0, FLAGS, .unit = "scale_mode" },
|
||||
{ "bicubic", "use bicubic scaling", 0, AV_OPT_TYPE_CONST, { .i64 = GFX_SCALE_BICUBIC }, 0, 0, FLAGS, .unit = "scale_mode" },
|
||||
{ "output_fmt", "desired output format", OFFSET(out_fmt), AV_OPT_TYPE_INT, { .i64 = AV_PIX_FMT_BGRA }, 0, INT_MAX, FLAGS, .unit = "output_fmt" },
|
||||
{ "8bit", "output default 8 Bit format", 0, AV_OPT_TYPE_CONST, { .i64 = AV_PIX_FMT_BGRA }, 0, 0, FLAGS, .unit = "output_fmt" },
|
||||
{ "bgra", "output 8 Bit BGRA", 0, AV_OPT_TYPE_CONST, { .i64 = AV_PIX_FMT_BGRA }, 0, 0, FLAGS, .unit = "output_fmt" },
|
||||
{ "10bit", "output default 10 Bit format", 0, AV_OPT_TYPE_CONST, { .i64 = AV_PIX_FMT_X2BGR10 }, 0, 0, FLAGS, .unit = "output_fmt" },
|
||||
{ "x2bgr10", "output 10 Bit X2BGR10", 0, AV_OPT_TYPE_CONST, { .i64 = AV_PIX_FMT_X2BGR10 }, 0, 0, FLAGS, .unit = "output_fmt" },
|
||||
{ "16bit", "output default 16 Bit format", 0, AV_OPT_TYPE_CONST, { .i64 = AV_PIX_FMT_RGBAF16 }, 0, 0, FLAGS, .unit = "output_fmt" },
|
||||
{ "rgbaf16", "output 16 Bit RGBAF16", 0, AV_OPT_TYPE_CONST, { .i64 = AV_PIX_FMT_RGBAF16 }, 0, 0, FLAGS, .unit = "output_fmt" },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
AVFILTER_DEFINE_CLASS(gfxcapture);
|
||||
|
||||
static const AVFilterPad gfxcapture_outputs[] = {
|
||||
{
|
||||
.name = "default",
|
||||
.type = AVMEDIA_TYPE_VIDEO,
|
||||
.config_props = ff_gfxcapture_config_props,
|
||||
},
|
||||
};
|
||||
|
||||
const FFFilter ff_vsrc_gfxcapture = {
|
||||
.p.name = "gfxcapture",
|
||||
.p.description = NULL_IF_CONFIG_SMALL("Capture graphics/screen content as a video source"),
|
||||
.p.priv_class = &gfxcapture_class,
|
||||
.p.inputs = NULL,
|
||||
.p.flags = AVFILTER_FLAG_HWDEVICE,
|
||||
.priv_size = sizeof(GfxCaptureContext),
|
||||
.init = ff_gfxcapture_init,
|
||||
.uninit = ff_gfxcapture_uninit,
|
||||
FILTER_OUTPUTS(gfxcapture_outputs),
|
||||
FILTER_SINGLE_PIXFMT(AV_PIX_FMT_D3D11),
|
||||
.flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
|
||||
.activate = ff_gfxcapture_activate,
|
||||
};
|
||||
81
libavfilter/vsrc_gfxcapture.h
Normal file
81
libavfilter/vsrc_gfxcapture.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef AVFILTER_VSRC_GFXCAPTURE_H
|
||||
#define AVFILTER_VSRC_GFXCAPTURE_H
|
||||
|
||||
typedef struct GfxCaptureContextCpp GfxCaptureContextCpp;
|
||||
|
||||
enum GfxResizeMode {
|
||||
GFX_RESIZE_CROP = 0,
|
||||
GFX_RESIZE_SCALE,
|
||||
GFX_RESIZE_SCALE_ASPECT,
|
||||
GFX_RESIZE_NB
|
||||
};
|
||||
|
||||
enum GfxScaleMode {
|
||||
GFX_SCALE_POINT = 0,
|
||||
GFX_SCALE_BILINEAR,
|
||||
GFX_SCALE_BICUBIC,
|
||||
GFX_SCALE_NB
|
||||
};
|
||||
|
||||
enum GfxMonitorIdx {
|
||||
GFX_MONITOR_IDX_WINDOW = -1,
|
||||
GFX_MONITOR_IDX_DEFAULT = -2
|
||||
};
|
||||
|
||||
typedef struct GfxCaptureContext {
|
||||
const AVClass *avclass;
|
||||
|
||||
GfxCaptureContextCpp *ctx;
|
||||
|
||||
const char *window_text;
|
||||
const char *window_class;
|
||||
const char *window_exe;
|
||||
int monitor_idx;
|
||||
|
||||
uint64_t user_hwnd;
|
||||
uint64_t user_hmonitor;
|
||||
|
||||
int capture_cursor;
|
||||
int capture_border;
|
||||
int display_border;
|
||||
AVRational frame_rate;
|
||||
int canvas_width, canvas_height;
|
||||
int crop_left, crop_top, crop_right, crop_bottom;
|
||||
int out_fmt;
|
||||
int resize_mode;
|
||||
int scale_mode;
|
||||
int premult_alpha;
|
||||
} GfxCaptureContext;
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define NOEXCEPT noexcept
|
||||
#else
|
||||
#define NOEXCEPT
|
||||
#endif
|
||||
|
||||
av_cold int ff_gfxcapture_init(AVFilterContext *avctx) NOEXCEPT;
|
||||
av_cold void ff_gfxcapture_uninit(AVFilterContext *avctx) NOEXCEPT;
|
||||
int ff_gfxcapture_activate(AVFilterContext *avctx) NOEXCEPT;
|
||||
int ff_gfxcapture_config_props(AVFilterLink *outlink) NOEXCEPT;
|
||||
|
||||
#undef NOEXCEPT
|
||||
|
||||
#endif /* AVFILTER_VSRC_GFXCAPTURE_H */
|
||||
126
libavfilter/vsrc_gfxcapture_shader.h
Normal file
126
libavfilter/vsrc_gfxcapture_shader.h
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef AVFILTER_VSRC_GFXCAPTURE_SHADER_H
|
||||
#define AVFILTER_VSRC_GFXCAPTURE_SHADER_H
|
||||
|
||||
#define HLSL_SHADER(shader) #shader
|
||||
|
||||
static const char render_shader_src[] = HLSL_SHADER(
|
||||
struct VSOut {
|
||||
float4 pos : SV_Position;
|
||||
float2 uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
cbuffer cb : register(b0) {
|
||||
float2 tS;
|
||||
float2 dS;
|
||||
float2 uvMin;
|
||||
float2 uvMax;
|
||||
uint to_unpremult;
|
||||
uint to_srgb;
|
||||
uint2 pad;
|
||||
};
|
||||
|
||||
Texture2D t0 : register(t0);
|
||||
SamplerState s0 : register(s0);
|
||||
|
||||
VSOut main_vs(uint id : SV_VertexID) {
|
||||
VSOut o;
|
||||
o.pos = float4(id == 2 ? 3.0 : -1.0, id == 1 ? 3.0 : -1.0, 0, 1);
|
||||
o.uv = lerp(uvMin, uvMax, float2((o.pos.x + 1) * 0.5, 1 - (o.pos.y + 1) * 0.5));
|
||||
return o;
|
||||
}
|
||||
|
||||
float4 cubic(float v) {
|
||||
float4 n = float4(1.0, 2.0, 3.0, 4.0) - v;
|
||||
float4 s = n * n * n;
|
||||
float x = s.x;
|
||||
float y = s.y - 4.0 * s.x;
|
||||
float z = s.z - 4.0 * s.y + 6.0 * s.x;
|
||||
float w = 6.0 - x - y - z;
|
||||
return float4(x, y, z, w) * (1.0 / 6.0);
|
||||
}
|
||||
|
||||
float4 texBicubic(Texture2D t, SamplerState ss, float2 uv) {
|
||||
float2 itS = 1.0 / tS;
|
||||
|
||||
float2 tc = uv * tS - 0.5;
|
||||
float2 fxy = frac(tc);
|
||||
tc -= fxy;
|
||||
|
||||
float4 xc = cubic(fxy.x);
|
||||
float4 yc = cubic(fxy.y);
|
||||
|
||||
float4 s = float4(xc.xz + xc.yw, yc.xz + yc.yw);
|
||||
float4 o = tc.xxyy + (float2(-0.5, 1.5)).xyxy + float4(xc.yw, yc.yw) / s;
|
||||
o *= itS.xxyy;
|
||||
|
||||
float4 s0 = t.Sample(ss, o.xz);
|
||||
float4 s1 = t.Sample(ss, o.yz);
|
||||
float4 s2 = t.Sample(ss, o.xw);
|
||||
float4 s3 = t.Sample(ss, o.yw);
|
||||
|
||||
float sx = s.x / (s.x + s.y);
|
||||
float sy = s.z / (s.z + s.w);
|
||||
|
||||
return lerp(lerp(s3, s2, sx), lerp(s1, s0, sx), sy);
|
||||
}
|
||||
|
||||
float4 unpremultiply(float4 c) {
|
||||
if (c.a < 1e-6)
|
||||
return float4(0.0, 0.0, 0.0, 0.0);
|
||||
return float4(c.rgb / c.a, c.a);
|
||||
}
|
||||
|
||||
float4 premultiply(float4 c) {
|
||||
return float4(c.rgb * c.a, c.a);
|
||||
}
|
||||
|
||||
float3 linear_to_srgb(float3 c) {
|
||||
c = max(c, 0.0);
|
||||
float3 lo = 12.92 * c;
|
||||
float3 hi = 1.055 * pow(c, 1.0 / 2.4) - 0.055;
|
||||
return saturate(lerp(hi, lo, step(c, 0.0031308)));
|
||||
}
|
||||
|
||||
float4 fix_color(float4 c) {
|
||||
if (to_unpremult || to_srgb)
|
||||
c = unpremultiply(c);
|
||||
if (to_srgb) {
|
||||
c.rgb = linear_to_srgb(c.rgb);
|
||||
if (!to_unpremult)
|
||||
c = premultiply(c);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
float4 main_ps(VSOut i) : SV_Target {
|
||||
return fix_color(t0.Sample(s0, i.uv));
|
||||
}
|
||||
|
||||
float4 main_ps_bicubic(VSOut i) : SV_Target {
|
||||
if (all(tS == dS))
|
||||
return main_ps(i);
|
||||
return fix_color(texBicubic(t0, s0, i.uv));
|
||||
}
|
||||
);
|
||||
|
||||
#undef HLSL_SHADER
|
||||
|
||||
#endif /* AVFILTER_VSRC_GFXCAPTURE_SHADER_H */
|
||||
1551
libavfilter/vsrc_gfxcapture_winrt.cpp
Normal file
1551
libavfilter/vsrc_gfxcapture_winrt.cpp
Normal file
File diff suppressed because it is too large
Load Diff
189
libavfilter/vsrc_gfxcapture_winrt.h
Normal file
189
libavfilter/vsrc_gfxcapture_winrt.h
Normal file
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef AVFILTER_VSRC_GFXCAPTURE_WINRT_H
|
||||
#define AVFILTER_VSRC_GFXCAPTURE_WINRT_H
|
||||
|
||||
// Forward-declare IDirect3DDxgiInterfaceAccess if headers too old
|
||||
#if !HAVE_IDIRECT3DDXGIINTERFACEACCESS
|
||||
namespace Windows::Graphics::DirectX::Direct3D11 {
|
||||
MIDL_INTERFACE("A9B3D012-3DF2-4EE3-B8D1-8695F457D3C1")
|
||||
IDirect3DDxgiInterfaceAccess : public IUnknown
|
||||
{
|
||||
public:
|
||||
IFACEMETHOD(GetInterface)(REFIID iid, _COM_Outptr_ void** p) = 0;
|
||||
};
|
||||
}
|
||||
#ifdef __MINGW32__
|
||||
__CRT_UUID_DECL(Windows::Graphics::DirectX::Direct3D11::IDirect3DDxgiInterfaceAccess,
|
||||
0xa9b3d012, 0x3df2, 0x4ee3, 0xb8, 0xd1, 0x86, 0x95, 0xf4, 0x57, 0xd3, 0xc1)
|
||||
#endif
|
||||
#endif /* !HAVE_IDIRECT3DDXGIINTERFACEACCESS */
|
||||
|
||||
// Forward-declare IGraphicsCaptureSession5 if headers too old
|
||||
#if !HAVE___X_ABI_CWINDOWS_CGRAPHICS_CCAPTURE_CIGRAPHICSCAPTURESESSION5
|
||||
namespace ABI::Windows ::Graphics::Capture {
|
||||
MIDL_INTERFACE("67C0EA62-1F85-5061-925A-239BE0AC09CB")
|
||||
IGraphicsCaptureSession5 : public IInspectable
|
||||
{
|
||||
public:
|
||||
IFACEMETHOD(get_MinUpdateInterval)(ABI::Windows::Foundation::TimeSpan* value) = 0;
|
||||
IFACEMETHOD(put_MinUpdateInterval)(ABI::Windows::Foundation::TimeSpan value) = 0;
|
||||
};
|
||||
}
|
||||
#ifdef __MINGW32__
|
||||
__CRT_UUID_DECL(ABI::Windows ::Graphics::Capture::IGraphicsCaptureSession5,
|
||||
0x67c0ea62, 0x1f85, 0x5061, 0x92, 0x5a, 0x23, 0x9b, 0xe0, 0xac, 0x09, 0xcb)
|
||||
#endif
|
||||
#endif /* !HAVE___X_ABI_CWINDOWS_CGRAPHICS_CCAPTURE_CIGRAPHICSCAPTURESESSION5 */
|
||||
|
||||
/****************************************************
|
||||
* Helper class to implement refcounted COM objects *
|
||||
****************************************************/
|
||||
template<typename... Interfaces>
|
||||
struct FFComObject : Interfaces...
|
||||
{
|
||||
virtual ~FFComObject() = default;
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) override
|
||||
{
|
||||
if (!ppvObject)
|
||||
return E_POINTER;
|
||||
|
||||
if (query_all<Interfaces...>(riid, ppvObject))
|
||||
{
|
||||
AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
*ppvObject = nullptr;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
ULONG STDMETHODCALLTYPE AddRef() override
|
||||
{
|
||||
return ++ref_count;
|
||||
}
|
||||
|
||||
ULONG STDMETHODCALLTYPE Release() override
|
||||
{
|
||||
ULONG rc = --ref_count;
|
||||
if (rc == 0)
|
||||
delete this;
|
||||
return rc;
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename Iface, typename... IFaces>
|
||||
bool query_all(REFIID riid, void** ppvObject)
|
||||
{
|
||||
if (riid == __uuidof(Iface)) {
|
||||
*ppvObject = static_cast<Iface*>(this);
|
||||
return true;
|
||||
}
|
||||
if constexpr (sizeof...(IFaces)) {
|
||||
return query_all<IFaces...>(riid, ppvObject);
|
||||
} else if (riid == __uuidof(IUnknown)) {
|
||||
*ppvObject = static_cast<IUnknown*>(static_cast<Iface*>(this));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::atomic<ULONG> ref_count { 1 };
|
||||
};
|
||||
|
||||
/*******************************************
|
||||
* Helper to implement COM/WinRT callbacks *
|
||||
*******************************************/
|
||||
template<class Iface, typename F, typename... Args>
|
||||
struct FFTypedCBHandler : FFComObject<Iface, IAgileObject>
|
||||
{
|
||||
using Func = std::decay_t<F>;
|
||||
|
||||
explicit FFTypedCBHandler(F&& f) : cb_func(std::forward<F>(f)) {}
|
||||
|
||||
std::invoke_result_t<Func&, Args...> STDMETHODCALLTYPE Invoke(Args... args) override
|
||||
{
|
||||
if constexpr (std::is_same_v<std::invoke_result_t<Func&, Args...>, HRESULT>) {
|
||||
return cb_func(std::forward<Args>(args)...);
|
||||
} else {
|
||||
cb_func(std::forward<Args>(args)...);
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Func cb_func;
|
||||
};
|
||||
|
||||
template<class Iface, typename... Args, typename F>
|
||||
static Microsoft::WRL::ComPtr<Iface> create_cb_handler(F&& cb_func)
|
||||
{
|
||||
return Microsoft::WRL::ComPtr<Iface>(
|
||||
new FFTypedCBHandler<Iface, F, Args...>(std::forward<F>(cb_func))
|
||||
);
|
||||
}
|
||||
|
||||
/******************************************
|
||||
* Helpers to implement C style callbacks *
|
||||
******************************************/
|
||||
template <typename Ret, typename... Args>
|
||||
struct Win32Callback {
|
||||
std::function<Ret(Args...)> fn;
|
||||
static Ret CALLBACK thunk(Args... args, LPARAM lparam) {
|
||||
auto self = reinterpret_cast<Win32Callback*>(lparam);
|
||||
return self->fn(std::forward<Args>(args)...);
|
||||
}
|
||||
decltype(&Win32Callback::thunk) proc = &Win32Callback::thunk;
|
||||
LPARAM lparam = 0;
|
||||
};
|
||||
|
||||
template <typename Ret, typename... Args>
|
||||
auto make_win32_callback(const std::function<Ret(Args...)> &&fn) {
|
||||
using T = Win32Callback<Ret, Args...>;
|
||||
auto res = std::make_unique<T>(T{ std::forward<decltype(fn)>(fn) });
|
||||
res->lparam = reinterpret_cast<LPARAM>(res.get());
|
||||
return res;
|
||||
}
|
||||
#define make_win32_callback(...) make_win32_callback(std::function(__VA_ARGS__))
|
||||
|
||||
/*****************************
|
||||
* Small convenience helpers *
|
||||
*****************************/
|
||||
struct HMODULEDeleter {
|
||||
typedef HMODULE pointer;
|
||||
void operator()(HMODULE handle) const {
|
||||
if (handle)
|
||||
FreeLibrary(handle);
|
||||
}
|
||||
};
|
||||
typedef std::unique_ptr<HMODULE, HMODULEDeleter> hmodule_ptr_t;
|
||||
|
||||
struct HANDLEDeleter {
|
||||
typedef HANDLE pointer;
|
||||
void operator()(HANDLE handle) const {
|
||||
if (handle && handle != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(handle);
|
||||
}
|
||||
};
|
||||
typedef std::unique_ptr<HANDLE, HANDLEDeleter> handle_ptr_t;
|
||||
|
||||
#define HLSL(shader) #shader
|
||||
|
||||
#endif /* AVFILTER_VSRC_GFXCAPTURE_WINRT_H */
|
||||
Reference in New Issue
Block a user