@@ -3529,6 +3529,7 @@ fbdev_outdev_deps="linux_fb_h"
gdigrab_indev_deps="CreateDIBSection"
gdigrab_indev_extralibs="-lgdi32"
gdigrab_indev_select="bmp_decoder"
+dxgigrab_indev_extralibs="-ldxgi -ld3d11"
iec61883_indev_deps="libiec61883"
iec61883_indev_select="dv_demuxer"
jack_indev_deps="libjack"
@@ -30,6 +30,7 @@ OBJS-$(CONFIG_FBDEV_INDEV) += fbdev_dec.o \
OBJS-$(CONFIG_FBDEV_OUTDEV) += fbdev_enc.o \
fbdev_common.o
OBJS-$(CONFIG_GDIGRAB_INDEV) += gdigrab.o
+OBJS-$(CONFIG_DXGIGRAB_INDEV) += windows_capture.o dxgigrab.o dxgigrab_c.o
OBJS-$(CONFIG_IEC61883_INDEV) += iec61883.o
OBJS-$(CONFIG_JACK_INDEV) += jack.o timefilter.o
OBJS-$(CONFIG_KMSGRAB_INDEV) += kmsgrab.o
@@ -72,5 +73,8 @@ SKIPHEADERS-$(CONFIG_V4L2_INDEV) += v4l2-common.h
SKIPHEADERS-$(CONFIG_V4L2_OUTDEV) += v4l2-common.h
SKIPHEADERS-$(CONFIG_ALSA) += alsa.h
SKIPHEADERS-$(CONFIG_SNDIO) += sndio.h
+SKIPHEADERS-$(CONFIG_DXGIGRAB_INDEV) += dxgigrab.h \
+ windows_capture.h \
+ dxgigrab_c.h
TESTPROGS-$(CONFIG_JACK_INDEV) += timefilter
@@ -35,6 +35,7 @@ extern const AVInputFormat ff_dshow_demuxer;
extern const AVInputFormat ff_fbdev_demuxer;
extern const AVOutputFormat ff_fbdev_muxer;
extern const AVInputFormat ff_gdigrab_demuxer;
+extern const AVInputFormat ff_dxgigrab_demuxer;
extern const AVInputFormat ff_iec61883_demuxer;
extern const AVInputFormat ff_jack_demuxer;
extern const AVInputFormat ff_kmsgrab_demuxer;
new file mode 100644
@@ -0,0 +1,59 @@
+/*
+ * 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
+ */
+
+#pragma once
+
+#include <winrt/Windows.UI.Composition.h>
+#include <windows.ui.composition.interop.h>
+#include <d2d1_1.h>
+
+inline auto
+CreateD3DDevice(
+ D3D_DRIVER_TYPE const type,
+ winrt::com_ptr<ID3D11Device>& device)
+{
+ WINRT_ASSERT(!device);
+
+ UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
+
+ return D3D11CreateDevice(
+ nullptr,
+ type,
+ nullptr,
+ flags,
+ nullptr, 0,
+ D3D11_SDK_VERSION,
+ device.put(),
+ nullptr,
+ nullptr);
+}
+
+inline auto
+CreateD3DDevice()
+{
+ winrt::com_ptr<ID3D11Device> device;
+ HRESULT hr = CreateD3DDevice(D3D_DRIVER_TYPE_HARDWARE, device);
+
+ if (DXGI_ERROR_UNSUPPORTED == hr)
+ {
+ hr = CreateD3DDevice(D3D_DRIVER_TYPE_WARP, device);
+ }
+
+ winrt::check_hresult(hr);
+ return device;
+}
new file mode 100644
@@ -0,0 +1,51 @@
+/*
+ * 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
+ */
+
+#pragma once
+#include <winrt/windows.graphics.directx.direct3d11.h>
+
+extern "C"
+{
+ HRESULT __stdcall CreateDirect3D11DeviceFromDXGIDevice(::IDXGIDevice* dxgiDevice,
+ ::IInspectable** graphicsDevice);
+
+ HRESULT __stdcall CreateDirect3D11SurfaceFromDXGISurface(::IDXGISurface* dgxiSurface,
+ ::IInspectable** graphicsSurface);
+}
+
+struct __declspec(uuid("A9B3D012-3DF2-4EE3-B8D1-8695F457D3C1"))
+ IDirect3DDxgiInterfaceAccess : ::IUnknown
+{
+ virtual HRESULT __stdcall GetInterface(GUID const& id, void** object) = 0;
+};
+
+inline auto CreateDirect3DDevice(IDXGIDevice* dxgi_device)
+{
+ winrt::com_ptr<::IInspectable> d3d_device;
+ winrt::check_hresult(CreateDirect3D11DeviceFromDXGIDevice(dxgi_device, d3d_device.put()));
+ return d3d_device.as<winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice>();
+}
+
+template <typename T>
+auto GetDXGIInterfaceFromObject(winrt::Windows::Foundation::IInspectable const& object)
+{
+ auto access = object.as<IDirect3DDxgiInterfaceAccess>();
+ winrt::com_ptr<T> result;
+ winrt::check_hresult(access->GetInterface(winrt::guid_of<T>(), result.put_void()));
+ return result;
+}
new file mode 100644
@@ -0,0 +1,225 @@
+/*
+ * DXGI video grab interface
+ *
+ * This file is part of FFmpeg.
+ *
+ * Copyright (C) 2022 Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com>
+ *
+ * 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
+ * DXGI frame device demuxer
+ * @author Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com>
+ */
+
+#include "dxgigrab.h"
+
+#include <dwmapi.h>
+#include <sstream>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include <libavutil/parseutils.h>
+#ifdef __cplusplus
+}
+#endif
+
+static BOOL CALLBACK enumMonitor(HMONITOR handle, HDC hdc, LPRECT rect,
+ LPARAM lParam)
+{
+ MonitorData* monitorData = reinterpret_cast<MonitorData*>(lParam);
+
+ if (monitorData->curId == 0 || monitorData->desiredId == monitorData->curId) {
+ monitorData->rect = *rect;
+ monitorData->id = monitorData->curId;
+
+ monitorData->hmnt = handle;
+ }
+
+ return (monitorData->desiredId > monitorData->curId++);
+}
+
+int dxgigrab_read_header(AVFormatContext *s1)
+{
+ struct dxgigrab *s = static_cast<dxgigrab*>(s1->priv_data);
+ if (!s->internal_struct)
+ s->internal_struct = new dxgigrab_internal();
+ struct dxgigrab_internal* x_internal = static_cast<dxgigrab_internal*>(s->internal_struct);
+ MonitorData monitorData;
+ monitorData.rect.top = 0;
+ monitorData.rect.left = 0;
+ monitorData.rect.bottom = 0;
+ monitorData.rect.right = 0;
+ std::string handle;
+ AVStream *st = NULL;
+
+ if (!strncmp(s1->url, "hwnd=", 5)) {
+ if (!s->hwnd) {
+ handle = s1->url + 5;
+ try {
+ s->hwnd = reinterpret_cast<HWND>(std::stoull(handle, nullptr, 16));
+ } catch (...) {}
+ if (!s->hwnd) {
+ av_log(s1, AV_LOG_ERROR,
+ "Can't find window from handle '%s', aborting.\n", handle.c_str());
+ return AVERROR_EXTERNAL;
+ }
+ }
+ } else {
+ s->hwnd = NULL;
+ char *display_number = av_strdup(s1->url);
+ if (!sscanf(s1->url, "%[^+]+%d,%d ", display_number, &s->offset_x, &s->offset_y)) {
+ av_log(s1, AV_LOG_ERROR,
+ "Please use \"<screenNumber>+<X,Y> <WidthxHeight>\" or \"hwnd=<windowHandle>\" to specify your target.\n");
+ return AVERROR_EXTERNAL;
+ }
+ if (s->offset_x || s->offset_y) {
+ av_log(s1,
+ AV_LOG_ERROR,
+ "This device does not support partial screen sharing.\n");
+ return AVERROR_PATCHWELCOME;
+ }
+ monitorData.desiredId = std::stoi(display_number);
+ av_freep(&display_number);
+ try {
+ LPARAM lParam = reinterpret_cast<LPARAM>(&monitorData);
+ EnumDisplayMonitors(NULL, NULL, enumMonitor, lParam);
+ } catch (...) {
+ }
+ }
+
+ s->hmnt = monitorData.hmnt;
+ s->rect = monitorData.rect;
+
+ if (!s->hmnt && !s->hwnd) {
+ av_log(s1, AV_LOG_ERROR,
+ "Please use \"<screenNumber>+<X,Y> <WidthxHeight>\" or \"hwnd=<windowHandle>\" to "
+ "specify your target.\n");
+ return AVERROR_EXTERNAL;
+ }
+
+ bool openWindow = true;
+ if (!s1->nb_streams) {
+ st = avformat_new_stream(s1, NULL);
+ } else {
+ openWindow = false;
+ st = s1->streams[0];
+ }
+ if (!st) {
+ return AVERROR(ENOMEM);
+ }
+
+ std::lock_guard lk(x_internal->mtx);
+ if (openWindow) {
+ auto d3dDevice = CreateD3DDevice();
+ auto dxgiDevice = d3dDevice.as<IDXGIDevice>();
+ auto m_device = CreateDirect3DDevice(dxgiDevice.get());
+
+ auto activation_factory = winrt::get_activation_factory<winrt::Windows::Graphics::Capture::GraphicsCaptureItem>();
+ auto interop_factory = activation_factory.as<IGraphicsCaptureItemInterop>();
+ winrt::Windows::Graphics::Capture::GraphicsCaptureItem windowItem = { nullptr };
+
+ try {
+ if (s->hwnd) {
+ winrt::check_hresult(interop_factory
+ ->CreateForWindow(s->hwnd, // we should have create for display too
+ winrt::guid_of<ABI::Windows::Graphics::Capture::IGraphicsCaptureItem>(),
+ reinterpret_cast<void**>(winrt::put_abi(windowItem))));
+ } else if (s->hmnt) {
+ winrt::check_hresult(interop_factory
+ ->CreateForMonitor(s->hmnt, // we should have create for display too
+ winrt::guid_of<ABI::Windows::Graphics::Capture::IGraphicsCaptureItem>(),
+ reinterpret_cast<void**>(winrt::put_abi(windowItem))));
+ }
+ } catch (winrt::hresult_error &err) {
+ av_log(s, AV_LOG_ERROR, "CreateForWindow failed: %s\n", err.message().c_str());
+ return AVERROR_EXTERNAL;
+ } catch (...) {
+ av_log(s, AV_LOG_ERROR, "CreateForWindow failed\n");
+ return AVERROR_EXTERNAL;
+ }
+ av_log(s, AV_LOG_ERROR, "CreateForWindow success\n");
+
+ x_internal->m_capture.reset(new WindowsCapture(m_device, windowItem, monitorData));
+ x_internal->m_capture->StartCapture();
+ x_internal->m_capture->checkNewFrameArrived();
+ x_internal->m_capture->window = handle;
+ x_internal->windowHandle = handle;
+ }
+
+ s->time_base = av_inv_q(s->framerate);
+
+ avpriv_set_pts_info(st, 64, 1, 1000000);
+
+ s->width = x_internal->m_capture->m_DeviceSize.Width;
+ s->height = x_internal->m_capture->m_DeviceSize.Height;
+
+ x_internal->m_capture->screen.first = monitorData.hmnt;
+ x_internal->m_capture->screen.second = monitorData.rect;
+
+ s->time_frame = av_gettime_relative();
+
+ st->avg_frame_rate = av_inv_q(s->time_base);
+
+ auto frame_size_bits = (int64_t)s->width * s->height * 4 * 8;
+ if (frame_size_bits / 8 + AV_INPUT_BUFFER_PADDING_SIZE > INT_MAX) {
+ av_log(s, AV_LOG_ERROR, "Captured area is too large\n");
+ return AVERROR_PATCHWELCOME;
+ }
+ s->frame_size = frame_size_bits / 8;
+
+ st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
+ st->codecpar->codec_id = AV_CODEC_ID_RAWVIDEO;
+ st->codecpar->width = s->width;
+ st->codecpar->height = s->height;
+ st->codecpar->format = AV_PIX_FMT_RGBA;
+ st->codecpar->bit_rate = av_rescale(frame_size_bits, st->avg_frame_rate.num, st->avg_frame_rate.den);
+
+ return 0;
+}
+
+int dxgigrab_read_packet(AVFormatContext *s1, AVPacket *pkt)
+{
+ struct dxgigrab *s = static_cast<dxgigrab*>(s1->priv_data);
+ struct dxgigrab_internal *x_internal = static_cast<dxgigrab_internal*>(s->internal_struct);
+ std::lock_guard lk(x_internal->mtx);
+ int ret = 0;
+ int64_t pts = av_gettime();
+
+ if (!x_internal->m_capture)
+ return 0; // If m_capture not available, return empty frame
+ ret = x_internal->m_capture->GetPkt(pkt);
+ if (ret < 0)
+ return ret;
+ pkt->dts = pkt->pts = pts;
+
+ return ret;
+}
+
+int dxgigrab_read_close(AVFormatContext *s1)
+{
+ struct dxgigrab* s = static_cast<dxgigrab*>(s1->priv_data);
+ struct dxgigrab_internal* x_internal = static_cast<dxgigrab_internal*>(s->internal_struct);
+ std::lock_guard lk(x_internal->mtx);
+
+ if (!x_internal->m_capture)
+ return 0; // If m_capture not available, no need to close it
+ x_internal->m_capture->Close();
+
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,83 @@
+/*
+ * DXGI video grab interface
+ *
+ * This file is part of FFmpeg.
+ *
+ * Copyright (C) 2022 Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com>
+ *
+ * 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
+ * DXGI frame device demuxer
+ * @author Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com>
+ */
+
+#ifndef AVDEVICE_DXGI_H
+#define AVDEVICE_DXGI_H
+
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include "dxgigrab_c.h"
+#ifdef __cplusplus
+}
+#endif
+
+#include <Unknwn.h>
+#include <inspectable.h>
+
+// WinRT
+#include <winrt/Windows.Foundation.h>
+#include <winrt/Windows.System.h>
+#include <winrt/Windows.UI.h>
+#include <winrt/Windows.UI.Composition.h>
+#include <winrt/Windows.UI.Composition.Desktop.h>
+#include <winrt/Windows.UI.Popups.h>
+#include <winrt/Windows.Graphics.Capture.h>
+#include <winrt/Windows.Graphics.DirectX.h>
+#include <winrt/Windows.Graphics.DirectX.Direct3d11.h>
+#include <windows.graphics.capture.interop.h>
+#include <windows.graphics.capture.h>
+
+#include <windows.ui.composition.interop.h>
+#include <DispatcherQueue.h>
+
+// STL
+#include <atomic>
+#include <memory>
+#include <mutex>
+
+// D3D
+#include <d3d11_4.h>
+#include <dxgi1_6.h>
+#include <d2d1_3.h>
+#include <wincodec.h>
+
+// Internal
+#include "d3dHelpers.h"
+#include "direct3d11.interop.h"
+#include "windows_capture.h"
+
+struct dxgigrab_internal {
+ std::unique_ptr<WindowsCapture> m_capture{ nullptr };
+ std::string windowHandle;
+ std::mutex mtx;
+};
+
+#endif /* AVDEVICE_DXGI_H */
new file mode 100644
@@ -0,0 +1,59 @@
+/*
+ * DXGI video grab interface
+ *
+ * This file is part of FFmpeg.
+ *
+ * Copyright (C) 2022 Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com>
+ *
+ * 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
+ * DXGI frame device demuxer
+ * @author Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com>
+ */
+
+#include "dxgigrab_c.h"
+
+#define OFFSET(x) offsetof(struct dxgigrab, x)
+#define DEC AV_OPT_FLAG_DECODING_PARAM
+static const AVOption options[] = {
+ { "framerate", "set video frame rate", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = "ntsc"}, 0, INT_MAX, DEC },
+ { "video_size", "set video frame size", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, DEC },
+ { "offset_x", "capture area x offset", OFFSET(offset_x), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC },
+ { "offset_y", "capture area y offset", OFFSET(offset_y), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC },
+ { NULL },
+};
+
+static const AVClass dxgigrab_class = {
+ .class_name = "DXGIgrab indev",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT,
+};
+
+/** dxgi grabber device demuxer declaration */
+AVInputFormat ff_dxgigrab_demuxer = {
+ .name = "dxgigrab",
+ .long_name = NULL_IF_CONFIG_SMALL("DXGI API Windows frame grabber"),
+ .priv_data_size = sizeof(struct dxgigrab),
+ .read_header = dxgigrab_read_header,
+ .read_packet = dxgigrab_read_packet,
+ .read_close = dxgigrab_read_close,
+ .flags = AVFMT_NOFILE,
+ .priv_class = &dxgigrab_class,
+};
new file mode 100644
@@ -0,0 +1,98 @@
+/*
+ * DXGI video grab interface
+ *
+ * This file is part of FFmpeg.
+ *
+ * Copyright (C) 2022 Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com>
+ *
+ * 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
+ * DXGI frame device demuxer
+ * @author Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com>
+ */
+
+#ifndef AVDEVICE_DXGI_C_H
+#define AVDEVICE_DXGI_C_H
+
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "libavformat/internal.h"
+#include "config.h"
+#include "libavutil/opt.h"
+#include "libavutil/time.h"
+
+#include <windows.h>
+
+/**
+ * DXGI Device Demuxer context
+ */
+struct dxgigrab {
+ const AVClass *avclass; /**< Class for private options */
+
+ int frame_size; /**< Size in bytes of the frame pixel data */
+ AVRational time_base; /**< Time base */
+ int64_t time_frame; /**< Current time */
+
+ AVRational framerate; /**< Capture framerate (private option) */
+ int width; /**< Width of the grab frame (private option) */
+ int height; /**< Height of the grab frame (private option) */
+ int offset_x; /**< Capture x offset (private option) */
+ int offset_y; /**< Capture y offset (private option) */
+
+ HWND hwnd; /**< Handle of the Window for the grab */
+ HMONITOR hmnt; /**< Handle of the Screen for the grab */
+ RECT rect; /**< Rect of the Screen for the grab */
+
+ void* internal_struct;
+};
+
+/**
+ * Initializes the dxgi grab device demuxer (public device demuxer API).
+ *
+ * @param s1 Context from avformat core
+ * @return AVERROR_IO error, 0 success
+ */
+int dxgigrab_read_header(AVFormatContext *s1);
+
+/**
+ * Grabs a frame from dxgi (public device demuxer API).
+ *
+ * @param s1 Context from avformat core
+ * @param pkt Packet holding the grabbed frame
+ * @return frame size in bytes
+ */
+int dxgigrab_read_packet(AVFormatContext *s1, AVPacket *pkt);
+
+
+/**
+ * Closes dxgi frame grabber (public device demuxer API).
+ *
+ * @param s1 Context from avformat core
+ * @return 0 success, !0 failure
+ */
+int dxgigrab_read_close(AVFormatContext *s1);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVDEVICE_DXGI_C_H */
new file mode 100644
@@ -0,0 +1,184 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * Copyright (C) 2022 Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com>
+ *
+ * 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
+ */
+
+/**
+ * @author Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com>
+ */
+
+#include "dxgigrab.h"
+
+#include <d3d11.h>
+
+using namespace winrt;
+using namespace Windows;
+using namespace Windows::Foundation;
+using namespace Windows::System;
+using namespace Windows::Graphics;
+using namespace Windows::Graphics::Capture;
+using namespace Windows::Graphics::DirectX;
+using namespace Windows::Graphics::DirectX::Direct3D11;
+using namespace Windows::Foundation::Numerics;
+using namespace Windows::UI;
+using namespace Windows::UI::Composition;
+
+WindowsCapture::WindowsCapture(
+ IDirect3DDevice const& device,
+ GraphicsCaptureItem const& item,
+ MonitorData& monitorData)
+{
+ m_item = item;
+ m_device = device;
+
+ m_d3dDevice = GetDXGIInterfaceFromObject<ID3D11Device>(m_device);
+ m_d3dDevice->GetImmediateContext(m_d3dContext.put());
+ screen.first = monitorData.hmnt;
+ screen.second = monitorData.rect;
+
+ m_DeviceSize = m_item.Size();
+
+ // Create framepool, define pixel format (DXGI_FORMAT_B8G8R8A8_UNORM), and frame size.
+ m_framePool = Direct3D11CaptureFramePool::Create(
+ m_device,
+ DirectXPixelFormat::R8G8B8A8UIntNormalized,
+ 2,
+ m_DeviceSize);
+ m_session = m_framePool.CreateCaptureSession(m_item);
+ auto sup = m_session.IsSupported();
+}
+
+// Start sending capture frames
+void
+WindowsCapture::StartCapture()
+{
+ std::lock_guard<std::mutex> lk(mtx_);
+ running_ = true;
+ m_session.StartCapture();
+}
+
+// Process captured frames
+void
+WindowsCapture::Close()
+{
+ std::lock_guard<std::mutex> lk(mtx_);
+ running_ = false;
+ if (texture) {
+ texture->Release();
+ }
+ m_framePool.Close();
+ m_session.Close();
+ m_d3dContext->ClearState();
+ m_d3dContext->Flush();
+ m_d3dDevice->Release();
+
+ texture = nullptr;
+ m_framePool = nullptr;
+ m_session = nullptr;
+ m_item = nullptr;
+}
+
+bool
+WindowsCapture::checkNewFrameArrived()
+{
+ std::lock_guard<std::mutex> lk(mtx_);
+ if (!running_)
+ return false;
+ auto shouldResize = false;
+
+ auto frame = m_framePool.TryGetNextFrame();
+ if (!frame)
+ return false;
+
+ auto frameSurface = GetDXGIInterfaceFromObject<ID3D11Texture2D>(frame.Surface());
+
+ D3D11_TEXTURE2D_DESC desc;
+ frameSurface->GetDesc(&desc);
+ auto frameContentSize = frame.ContentSize();
+ if (desc.Width <= 0 || desc.Height <= 0)
+ return false;
+
+ shouldResize = frameContentSize.Width != m_DeviceSize.Width || frameContentSize.Height != m_DeviceSize.Height;
+
+ if (shouldResize) {
+ m_DeviceSize.Width = frameContentSize.Width;
+ m_DeviceSize.Height = frameContentSize.Height;
+ m_framePool.Recreate(m_device, DirectXPixelFormat::R8G8B8A8UIntNormalized, 2, m_DeviceSize);
+ return false;
+ }
+
+ texDesc.Width = desc.Width;
+ texDesc.Height = desc.Height;
+ texDesc.MipLevels = desc.MipLevels;
+ texDesc.ArraySize = desc.ArraySize;
+ texDesc.Format = desc.Format;
+ texDesc.SampleDesc = desc.SampleDesc;
+ texDesc.Usage = D3D11_USAGE_STAGING;
+ texDesc.BindFlags = 0;
+ texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
+ texDesc.MiscFlags = 0;
+
+ m_d3dDevice->CreateTexture2D(&texDesc, nullptr, &texture);
+
+ // copy the texture to a staging resource
+ m_d3dContext->CopyResource(texture, frameSurface.get());
+
+ return true;
+}
+
+int
+WindowsCapture::GetPkt(AVPacket *pkt)
+{
+ if (!checkNewFrameArrived() || !running_ || !texture)
+ return 0;
+ std::lock_guard<std::mutex> lk(mtx_);
+
+ // now, map the staging resource TO CPU
+ D3D11_MAPPED_SUBRESOURCE mapInfo;
+ m_d3dContext->Map(
+ texture,
+ 0,
+ D3D11_MAP_READ,
+ 0,
+ &mapInfo);
+
+ m_d3dContext->Unmap(texture, 0);
+
+ auto ret = av_new_packet(pkt, mapInfo.DepthPitch);
+ if (ret < 0) {
+ if (mapInfo.DepthPitch) {
+ av_packet_unref(pkt);
+ }
+ texture->Release();
+ texture = nullptr;
+ return ret;
+ }
+
+ auto idx = 0;
+ for (auto y = 0; y < m_DeviceSize.Height; y++) {
+ for (auto x = 0; x < m_DeviceSize.Width * 4; x++) {
+ pkt->data[idx] = static_cast<uint8_t*>(mapInfo.pData)[y * mapInfo.RowPitch + x];
+ idx++;
+ }
+ }
+
+ texture->Release();
+ texture = nullptr;
+
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,82 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * Copyright (C) 2022 Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com>
+ *
+ * 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
+ */
+
+/**
+ * @author Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com>
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include <libavutil/hwcontext_d3d11va.h>
+#ifdef __cplusplus
+}
+#endif
+
+#include <mutex>
+#include <memory>
+
+#include <windows.h>
+
+struct MonitorData {
+ HMONITOR hmnt = NULL;
+ RECT rect;
+ int id = 0;
+ int curId = 0;
+ int desiredId = 0;
+};
+
+class WindowsCapture
+{
+public:
+ WindowsCapture(
+ winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice const& device,
+ winrt::Windows::Graphics::Capture::GraphicsCaptureItem const& item,
+ MonitorData& monitorData);
+ ~WindowsCapture() { Close(); }
+
+ void StartCapture();
+
+ int GetPkt(AVPacket *pkt);
+
+ void Close();
+ std::string window;
+
+ bool checkNewFrameArrived();
+ winrt::Windows::Graphics::SizeInt32 m_DeviceSize;
+ std::pair<bool, RECT> screen;
+
+private:
+ winrt::Windows::Graphics::Capture::GraphicsCaptureItem m_item{ nullptr };
+ winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool m_framePool{ nullptr };
+ winrt::Windows::Graphics::Capture::GraphicsCaptureSession m_session{ nullptr };
+
+ winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice m_device {nullptr};
+ winrt::com_ptr<ID3D11Device> m_d3dDevice{nullptr};
+ winrt::com_ptr<ID3D11DeviceContext> m_d3dContext {nullptr};
+
+ D3D11_TEXTURE2D_DESC texDesc;
+ ID3D11Texture2D *texture {nullptr};
+
+ std::mutex mtx_;
+ bool running_;
+};