From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from ffbox0-bg.ffmpeg.org (ffbox0-bg.ffmpeg.org [79.124.17.100]) by master.gitmailbox.com (Postfix) with ESMTPS id 8E13C4D6BC for ; Tue, 25 Nov 2025 13:03:58 +0000 (UTC) Authentication-Results: ffbox; dkim=fail (body hash mismatch (got b'pWW7LSnEntrB8rU0SGzSEHcqqqsDbkuAxCVFN2JQz6A=', expected b'FGkiAv93MGbaJN3KtXzym58LhgH6/AQ2Xmfi5hoxLR4=')) header.d=ffmpeg.org header.i=@ffmpeg.org header.a=rsa-sha256 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ffmpeg.org; i=@ffmpeg.org; q=dns/txt; s=mail; t=1764075818; h=mime-version : to : date : message-id : reply-to : subject : list-id : list-archive : list-archive : list-help : list-owner : list-post : list-subscribe : list-unsubscribe : from : cc : content-type : content-transfer-encoding : from; bh=pWW7LSnEntrB8rU0SGzSEHcqqqsDbkuAxCVFN2JQz6A=; b=xggMnQElyISP/YdQkWxfjLDlwrx5ZZydIoYjH8A/6FvOiHJscEbvRdRUhCp/+itgGWmDE syFSIbU5tfAXfpZ7lPLAhydJA0fBSo84LZxbdv8SYDBdwj9LSSOH6WbtJuk38bxLlvWt6iS ds7qZIRqmlIA6tprWwcR9bo8Xkw1+la+9Xe1gF1URAwt0hCr85c5UKrE9hs3KXwKwTmUILr jV8aGpxo/UthRWXcxtH1fFPZlbblZyS97QgGm6SIbKHGdJwaK2r+nS2g1/nKyAhC+G2dEMY 1fPXQrLagHz+tjL+IME1c3goy3wXDYWH8lJnNKJKV6bBtbLjYw6MMlJEDUmg== Received: from [172.19.0.3] (unknown [172.19.0.3]) by ffbox0-bg.ffmpeg.org (Postfix) with ESMTP id 8D2F4690164; Tue, 25 Nov 2025 15:03:38 +0200 (EET) ARC-Seal: i=1; cv=none; a=rsa-sha256; d=ffmpeg.org; s=arc; t=1764075801; b=CVL6pByUXSsC+XrBuJCVjPPpfZq/q1YbDLRBswgE5+vN44VU8JDVJu9LBmVwDGQK0w+TS Q7+ZvAibdmLZNBV4HXSC2TRN2ey7z2C0XJu4aIWj7XyLRcoLR72mDbAevP3qNqIkzFyeb7v 0UmSP3U05fV6XVCvR2O7uCkoyA6j+I4Ucik4N730t57A5OM7bvT1vmfMZIfTkB9GpMW0UD8 tGc5jMZzFhMcZH5oqxlDL1z+rSLxMsSbtquHypYfYIzdrjCt+8pwxXhJ1fZHj+TdNlhgE7H Ay99yJxwa/Iy3ZDmHjG88rhqhzZlzElh6zH0fpb95bSIu9GxtmulnlcVbgzQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=ffmpeg.org; s=arc; t=1764075801; h=from : sender : reply-to : subject : date : message-id : to : cc : mime-version : content-type : content-transfer-encoding : content-id : content-description : resent-date : resent-from : resent-sender : resent-to : resent-cc : resent-message-id : in-reply-to : references : list-id : list-help : list-unsubscribe : list-subscribe : list-post : list-owner : list-archive; bh=n9W3fjOEiVXyM9TYNvZyaHcEX0fNerCeK9tiP7L8nN4=; b=fh7ItBI1N6XDBGSNuFuiUdHZK5JSL+OXmO3ESE0uAmMsZLUKKLfYYcKmWJikWnx1loxR4 gq5eDldpxU17zIJAOLEXCsU4j70BqJUG/Lw7lhxG4z2fM0LLY9GKTJykJoDl5jTCnhYqAeE zFS1C/FOwoQ3zq/f0jqFpVBdEuQJUmyv4zc43RFm4v9OT9DEuCpZFeqC4RbOcks86URe850 zJXEmLBf/LqGzwq/F9dHSUnEesJa/1gGJ32+ur4H68TI8eJdMpiHRBPbBSKknBYV54CMhA1 1C/iq7r+DQlAn/UOFowIaVq8VC9XMuNIuT4cc+DXSeOYfcK2Fk9i5Xczz6rA== ARC-Authentication-Results: i=1; ffmpeg.org; dkim=pass header.d=ffmpeg.org header.i=@ffmpeg.org; arc=none; dmarc=pass header.from=ffmpeg.org policy.dmarc=quarantine Authentication-Results: ffmpeg.org; dkim=pass header.d=ffmpeg.org header.i=@ffmpeg.org; arc=none (Message is not ARC signed); dmarc=pass (Used From Domain Record) header.from=ffmpeg.org policy.dmarc=quarantine DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ffmpeg.org; i=@ffmpeg.org; q=dns/txt; s=mail; t=1764075793; h=content-type : mime-version : content-transfer-encoding : from : to : reply-to : subject : date : from; bh=FGkiAv93MGbaJN3KtXzym58LhgH6/AQ2Xmfi5hoxLR4=; b=RI88IdKNO82sj77aT24279pgkNZKJAnp362tatNFriCICA4q/wLaxJq0YkWEYTKT60WQw F7+06fc6yU6R2CFUiq6b1SU1j5NmFSXK57Xege+JH48+MVrNlD9/hnHODXOhExQCiGDrW68 V99zRMUwxhLqloP91BuxhmcAO4/VhnKl3yLfbNPL/tyTuil5k4wBvKy/kT1akdFk7WFZtRH dB27kHs42ZEIY5MeuQFba5fuEx0bww4srfMKheHThnOfhsE4/E/ptyANXLwLCSl0GVI1IDM 9/GYEoN8NpPAgOdErQF8VEaxnHmddm/a7g/Edeeq/nLKO32yIkahAf0unXOg== Received: from 55ca25703178 (code.ffmpeg.org [188.245.149.3]) by ffbox0-bg.ffmpeg.org (Postfix) with ESMTPS id 2268768FDAA for ; Tue, 25 Nov 2025 15:03:13 +0200 (EET) MIME-Version: 1.0 To: ffmpeg-devel@ffmpeg.org Date: Tue, 25 Nov 2025 13:03:12 -0000 Message-ID: <176407579329.39.13638719004517318908@2cb04c0e5124> Message-ID-Hash: 2IQCDEEIDUI3E2JGVTP26EKAEPTP7PPK X-Message-ID-Hash: 2IQCDEEIDUI3E2JGVTP26EKAEPTP7PPK X-MailFrom: code@ffmpeg.org X-Mailman-Rule-Hits: nonmember-moderation X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; header-match-ffmpeg-devel.ffmpeg.org-0; header-match-ffmpeg-devel.ffmpeg.org-1; header-match-ffmpeg-devel.ffmpeg.org-2; header-match-ffmpeg-devel.ffmpeg.org-3; emergency; member-moderation X-Mailman-Version: 3.3.10 Precedence: list Reply-To: FFmpeg development discussions and patches Subject: [FFmpeg-devel] [PATCH] avfilter: Add vsrc_amf - AMF based screen capture (PR #21015) List-Id: FFmpeg development discussions and patches Archived-At: Archived-At: List-Archive: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: ArazIusubov via ffmpeg-devel Cc: ArazIusubov Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Archived-At: List-Archive: List-Post: PR #21015 opened by ArazIusubov URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21015 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21015.patch This patch adds screen capture support via AMF vsrc_amf: ffmpeg -y \ -filter_complex "vsrc_amf=framerate=90:capture_mode=keep_framerate" \ -c:v hevc_amf \ -frames:v 300 \ output_grab.mp4 >>From 643aedbd843281a7de4ef43597e86e11ca83e26c Mon Sep 17 00:00:00 2001 From: Dmitrii Ovchinnikov Date: Tue, 25 Nov 2025 13:36:34 +0100 Subject: [PATCH] avfilter: Add vsrc_amf - AMF based screen capture This patch adds screen capture support via AMF vsrc_amf: ffmpeg -y \ -filter_complex "vsrc_amf=framerate=90:capture_mode=keep_framerate" \ -c:v hevc_amf \ -frames:v 300 \ output_grab.mp4 --- configure | 1 + libavfilter/Makefile | 1 + libavfilter/allfilters.c | 1 + libavfilter/version.h | 2 +- libavfilter/vsrc_amf.c | 348 ++++++++++++++++++++++++++++++++++++++ libavutil/hwcontext_amf.c | 1 + 6 files changed, 353 insertions(+), 1 deletion(-) create mode 100644 libavfilter/vsrc_amf.c diff --git a/configure b/configure index 99734e9d03..83dfe919df 100755 --- a/configure +++ b/configure @@ -3560,6 +3560,7 @@ vp9_vaapi_encoder_select="vaapi_encode" vp9_qsv_encoder_deps="libmfx MFX_CODEC_VP9" vp9_qsv_encoder_select="qsvenc" vp9_v4l2m2m_decoder_deps="v4l2_m2m vp9_v4l2_m2m" +amf_capture_filter_deps="amf" vvc_qsv_decoder_select="vvc_mp4toannexb_bsf qsvdec" # parsers diff --git a/libavfilter/Makefile b/libavfilter/Makefile index d56a458e45..5e70197dd8 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -630,6 +630,7 @@ OBJS-$(CONFIG_SMPTEHDBARS_FILTER) += vsrc_testsrc.o OBJS-$(CONFIG_COLOR_VULKAN_FILTER) += vsrc_testsrc_vulkan.o vulkan.o vulkan_filter.o OBJS-$(CONFIG_TESTSRC_FILTER) += vsrc_testsrc.o OBJS-$(CONFIG_TESTSRC2_FILTER) += vsrc_testsrc.o +OBJS-$(CONFIG_AMF_CAPTURE_FILTER) += vsrc_amf.o OBJS-$(CONFIG_YUVTESTSRC_FILTER) += vsrc_testsrc.o OBJS-$(CONFIG_ZONEPLATE_FILTER) += vsrc_testsrc.o diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c index 0a3e782fe9..8f2a04fc6d 100644 --- a/libavfilter/allfilters.c +++ b/libavfilter/allfilters.c @@ -564,6 +564,7 @@ extern const FFFilter ff_vf_drawbox_vaapi; extern const FFFilter ff_vsrc_allrgb; extern const FFFilter ff_vsrc_allyuv; +extern const FFFilter ff_vsrc_amf_capture; extern const FFFilter ff_vsrc_cellauto; extern const FFFilter ff_vsrc_color; extern const FFFilter ff_vsrc_color_vulkan; diff --git a/libavfilter/version.h b/libavfilter/version.h index 77f38cb9b4..268525b39a 100644 --- a/libavfilter/version.h +++ b/libavfilter/version.h @@ -31,7 +31,7 @@ #include "version_major.h" -#define LIBAVFILTER_VERSION_MINOR 9 +#define LIBAVFILTER_VERSION_MINOR 10 #define LIBAVFILTER_VERSION_MICRO 100 diff --git a/libavfilter/vsrc_amf.c b/libavfilter/vsrc_amf.c new file mode 100644 index 0000000000..a2d660633b --- /dev/null +++ b/libavfilter/vsrc_amf.c @@ -0,0 +1,348 @@ +/* + * 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/pixdesc.h" +#include "libavutil/mem.h" +#include "libavutil/opt.h" +#include "libavutil/time.h" +#include "libavutil/avstring.h" +#include "libavutil/avassert.h" +#include "libavutil/hwcontext.h" +#include "libavutil/hwcontext_amf.h" +#include "libavutil/hwcontext_amf_internal.h" +#include "compat/w32dlfcn.h" +#include "avfilter.h" +#include "filters.h" +#include "video.h" + +#include +#include +#include +#include + +typedef struct AMFGrabContext { + AVClass *avclass; + + int monitor_index; + AVRational framerate; + int capture_mode; + + AVBufferRef *device_ctx_ref; + + AMFComponent *capture; + amf_bool eof; + AMF_SURFACE_FORMAT format; +} AMFGrabContext; + +#define OFFSET(x) offsetof(AMFGrabContext, x) +#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM + +static const AVOption amf_capture_options[] = { + { "monitor_index", "Index of display monitor to capture", OFFSET(monitor_index), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 8, FLAGS }, + { "framerate", "Capture framerate", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = "60"}, 0, INT_MAX, FLAGS }, + + { "capture_mode", "Capture synchronization mode", OFFSET(capture_mode), AV_OPT_TYPE_INT, {.i64 = AMF_DISPLAYCAPTURE_MODE_KEEP_FRAMERATE}, 0, 2, FLAGS, "mode" }, + { "keep_framerate", "Capture component maintains the frame rate", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_DISPLAYCAPTURE_MODE_KEEP_FRAMERATE}, 0, 0, FLAGS, "mode" }, + { "wait_for_present", "Capture component waits for flip (present) event", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_DISPLAYCAPTURE_MODE_WAIT_FOR_PRESENT}, 0, 0, FLAGS, "mode" }, + { "get_current", "Returns current visible surface immediately", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_DISPLAYCAPTURE_MODE_GET_CURRENT_SURFACE}, 0, 0, FLAGS, "mode" }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(amf_capture); + +static void amf_release_surface(void *opaque, uint8_t *data) +{ + int ref = 0; + if(!!data){ + AMFSurface *surface = (AMFSurface*)(data); + ref = surface->pVtbl->Release(surface); + } +} + +static av_cold void amf_uninit(AVFilterContext *avctx) +{ + AMFGrabContext *ctx = avctx->priv; + + if (ctx->capture) { + ctx->capture->pVtbl->Drain(ctx->capture); + ctx->capture->pVtbl->Terminate(ctx->capture); + ctx->capture->pVtbl->Release(ctx->capture); + ctx->capture = NULL; + } + + av_buffer_unref(&ctx->device_ctx_ref); +} + +static av_cold int amf_init(AVFilterContext *avctx) +{ + AMFGrabContext *ctx = avctx->priv; + + ctx->eof = 0; + av_log(avctx, AV_LOG_VERBOSE, "Initializing AMF screen capture\n"); + + return 0; +} + +static int amf_init_vsrc(AVFilterLink *outlink) +{ + FilterLink *link = ff_filter_link(outlink); + AVFilterContext *avctx = outlink->src; + AMFGrabContext *ctx = avctx->priv; + AVHWDeviceContext *hw_device_ctx = (AVHWDeviceContext*)ctx->device_ctx_ref->data; + AVAMFDeviceContext *amf_device_ctx = (AVAMFDeviceContext*)hw_device_ctx->hwctx; + AMF_RESULT res; + AMFRate framerate; + AMFVariantStruct var = {0}; + AMFSize resolution = {0}; + + res = amf_device_ctx->factory->pVtbl->CreateComponent(amf_device_ctx->factory, + amf_device_ctx->context, + AMFDisplayCapture, + &ctx->capture); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_FILTER_NOT_FOUND, "CreateComponent(%ls) failed with error %d\n", AMFDisplayCapture, res); + + AMF_ASSIGN_PROPERTY_INT64(res, ctx->capture, AMF_DISPLAYCAPTURE_MONITOR_INDEX, ctx->monitor_index); + if (res != AMF_OK) { + av_log(avctx, AV_LOG_ERROR, "Failed to set monitor index: %d\n", res); + return AVERROR_EXTERNAL; + } + + if (ctx->framerate.num > 0 && ctx->framerate.den > 0) + framerate = AMFConstructRate(ctx->framerate.num, ctx->framerate.den); + else + framerate = AMFConstructRate(30, 1); + + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->capture, AMF_DISPLAYCAPTURE_DUPLICATEOUTPUT, true); + if (res != AMF_OK) { + av_log(avctx, AV_LOG_ERROR, "Failed to set AMF_DISPLAYCAPTURE_DUPLICATEOUTPUT: %d\n", res); + return AVERROR_EXTERNAL; + } + + AMF_ASSIGN_PROPERTY_RATE(res, ctx->capture, AMF_DISPLAYCAPTURE_FRAMERATE, framerate); + if (res != AMF_OK) { + av_log(avctx, AV_LOG_ERROR, "Failed to set framerate: %d\n", res); + return AVERROR_EXTERNAL; + } + + AMF_ASSIGN_PROPERTY_INT64(res, ctx->capture, AMF_DISPLAYCAPTURE_MODE, ctx->capture_mode); + if (res != AMF_OK) { + av_log(avctx, AV_LOG_WARNING, "Failed to set capture mode: %d\n", res); + } + + res = ctx->capture->pVtbl->Init(ctx->capture, AMF_SURFACE_UNKNOWN, 0, 0); + if (res != AMF_OK) { + av_log(avctx, AV_LOG_ERROR, "Failed to initialize capture component: %d\n", res); + return AVERROR_EXTERNAL; + } + + res = ctx->capture->pVtbl->GetProperty(ctx->capture, AMF_DISPLAYCAPTURE_RESOLUTION, &var); + if (res == AMF_OK && var.type == AMF_VARIANT_SIZE) { + resolution = var.sizeValue; + outlink->w = resolution.width; + outlink->h = resolution.height; + + av_log(avctx, AV_LOG_INFO, "Capture resolution: %dx%d\n", + outlink->w, outlink->h); + } else { + av_log(avctx, AV_LOG_WARNING, "Failed to get resolution, using defaults\n"); + outlink->w = 1920; + outlink->h = 1080; + } + + res = ctx->capture->pVtbl->GetProperty(ctx->capture, AMF_DISPLAYCAPTURE_FORMAT, &var); + if (res == AMF_OK && var.type == AMF_VARIANT_INT64) { + ctx->format = (AMF_SURFACE_FORMAT)var.int64Value; + av_log(avctx, AV_LOG_INFO, "Capture format: %d\n", ctx->format); + } else { + ctx->format = AMF_SURFACE_BGRA; + av_log(avctx, AV_LOG_WARNING, "Failed to get format, assuming BGRA\n"); + } + + + outlink->time_base = (AVRational){framerate.den, framerate.num}; + link->frame_rate = (AVRational){framerate.num, framerate.den}; + AMFVariantClear(&var); + return 0; +} + +static int amf_config_props(AVFilterLink *outlink) +{ + FilterLink *link = ff_filter_link(outlink); + AVFilterContext *avctx = outlink->src; + AMFGrabContext *ctx = avctx->priv; + AVHWDeviceContext *device_ctx; + int ret; + + av_buffer_unref(&ctx->device_ctx_ref); + + if (avctx->hw_device_ctx) { + device_ctx = (AVHWDeviceContext*)avctx->hw_device_ctx->data; + if (device_ctx->type == AV_HWDEVICE_TYPE_AMF) + { + ctx->device_ctx_ref = av_buffer_ref(avctx->hw_device_ctx); + } else { + ret = av_hwdevice_ctx_create_derived(&ctx->device_ctx_ref, AV_HWDEVICE_TYPE_AMF, avctx->hw_device_ctx, 0); + AMF_GOTO_FAIL_IF_FALSE(avctx, ret == 0, ret, "Failed to create derived AMF device context: %s\n", av_err2str(ret)); + } + } else { + ret = av_hwdevice_ctx_create(&ctx->device_ctx_ref, AV_HWDEVICE_TYPE_AMF, NULL, NULL, 0); + AMF_GOTO_FAIL_IF_FALSE(avctx, ret == 0, ret, "Failed to create hardware device context (AMF) : %s\n", av_err2str(ret)); + } + if ((ret = amf_init_vsrc(outlink)) == 0) { + AVHWDeviceContext *device_ctx = (AVHWDeviceContext*)ctx->device_ctx_ref->data; + if (device_ctx->type == AV_HWDEVICE_TYPE_AMF) { + AVHWFramesContext *frames_ctx; + link->hw_frames_ctx = av_hwframe_ctx_alloc(ctx->device_ctx_ref); + AMF_GOTO_FAIL_IF_FALSE(avctx, !!link->hw_frames_ctx, AVERROR(ENOMEM), "av_hwframe_ctx_alloc failed\n"); + + frames_ctx = (AVHWFramesContext*)link->hw_frames_ctx->data; + frames_ctx->format = AV_PIX_FMT_AMF_SURFACE; + frames_ctx->sw_format = av_amf_to_av_format(ctx->format); + frames_ctx->initial_pool_size = 28; + frames_ctx->width = outlink->w; + frames_ctx->height = outlink->h; + + ret = av_hwframe_ctx_init(link->hw_frames_ctx); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to initialize hardware frames context: %s\n", + av_err2str(ret)); + + return ret; + } + + if (!link->hw_frames_ctx) + return AVERROR(ENOMEM); + } + return 0; + } +fail: + amf_uninit(avctx); + return ret; +} + +static int amf_capture_frame(AVFilterLink *outlink) +{ + AVFilterContext *avctx = outlink->src; + AMFGrabContext *ctx = avctx->priv; + AMFSurface *surface = NULL; + AVFrame *frame = NULL; + AMF_RESULT res; + AMFData *data_out = NULL; + FilterLink *fl = ff_filter_link(outlink); + int format_amf; + int i; + int ret; + AMFPlane *plane; + + if (ctx->eof) + return AVERROR_EOF; + + res = ctx->capture->pVtbl->QueryOutput(ctx->capture, &data_out); + + if (res == AMF_REPEAT) { + av_log(0, AV_LOG_DEBUG, "AMF capture returned res = AMF_REPEAT\n"); + return AVERROR(EAGAIN); + } + + if (res == AMF_EOF) { + ctx->eof = 1; + av_log(avctx, AV_LOG_DEBUG, "Capture reached EOF\n"); + return AVERROR_EOF; + } + + if (res != AMF_OK || !data_out) { + if (res != AMF_OK) + av_log(avctx, AV_LOG_WARNING, "QueryOutput failed: %d\n", res); + + return AVERROR(EAGAIN); + } + + AMFGuid guid = IID_AMFSurface(); + data_out->pVtbl->QueryInterface(data_out, &guid, (void**)&surface); + data_out->pVtbl->Release(data_out); + + frame = av_frame_alloc(); + if (!frame) { + surface->pVtbl->Release(surface); + return AVERROR(ENOMEM); + } + frame->format = outlink->format; + frame->width = outlink->w; + frame->height = outlink->h; + frame->sample_aspect_ratio = (AVRational){1, 1}; + + amf_pts pts = surface->pVtbl->GetPts(surface); + frame->pts = av_rescale_q(pts, AMF_TIME_BASE_Q, outlink->time_base); + + if (fl->hw_frames_ctx) { + frame->format = AV_PIX_FMT_AMF_SURFACE; + frame->data[0] = (uint8_t*)surface; + frame->buf[0] = av_buffer_create((uint8_t*)surface, sizeof(surface), + amf_release_surface, NULL, 0); + frame->hw_frames_ctx = av_buffer_ref(fl->hw_frames_ctx); + if (!frame->buf[0]) { + av_frame_free(&frame); + surface->pVtbl->Release(surface); + return AVERROR(ENOMEM); + } + } else { + ret = surface->pVtbl->Convert(surface, AMF_MEMORY_HOST); + AMF_RETURN_IF_FALSE(avctx, ret == AMF_OK, AVERROR_UNKNOWN, "Convert(amf::AMF_MEMORY_HOST) failed with error %d\n", ret); + + for (i = 0; i < surface->pVtbl->GetPlanesCount(surface); i++) { + plane = surface->pVtbl->GetPlaneAt(surface, i); + frame->data[i] = plane->pVtbl->GetNative(plane); + frame->linesize[i] = plane->pVtbl->GetHPitch(plane); + } + + frame->buf[0] = av_buffer_create((uint8_t *)surface, sizeof(surface), + amf_release_surface, (void*)avctx, + AV_BUFFER_FLAG_READONLY); + AMF_RETURN_IF_FALSE(avctx, !!frame->buf[0], AVERROR(ENOMEM), "av_buffer_create for amf surface failed."); + + format_amf = surface->pVtbl->GetFormat(surface); + frame->format = av_amf_to_av_format(format_amf); + } + + return ff_filter_frame(outlink, frame); +} + +static const AVFilterPad amf_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .request_frame = amf_capture_frame, + .config_props = amf_config_props, + }, +}; + +const FFFilter ff_vsrc_amf_capture = { + .p.name = "vsrc_amf", + .p.description = NULL_IF_CONFIG_SMALL("AMD AMF screen capture"), + .p.priv_class = &amf_capture_class, + .p.inputs = NULL, + .p.flags = AVFILTER_FLAG_HWDEVICE, + .priv_size = sizeof(AMFGrabContext), + .init = amf_init, + .uninit = amf_uninit, + FILTER_OUTPUTS(amf_outputs), + FILTER_SINGLE_PIXFMT(AV_PIX_FMT_AMF_SURFACE), + .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, +}; \ No newline at end of file diff --git a/libavutil/hwcontext_amf.c b/libavutil/hwcontext_amf.c index c754dc4ee5..57bf08bc65 100644 --- a/libavutil/hwcontext_amf.c +++ b/libavutil/hwcontext_amf.c @@ -155,6 +155,7 @@ static const enum AVPixelFormat supported_formats[] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_BGRA, AV_PIX_FMT_RGBA, + AV_PIX_FMT_BGR0, AV_PIX_FMT_P010, #if CONFIG_D3D11VA AV_PIX_FMT_D3D11, -- 2.49.1 _______________________________________________ ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org