From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by master.gitmailbox.com (Postfix) with ESMTP id 2517B47CE5 for ; Wed, 18 Oct 2023 16:55:52 +0000 (UTC) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 5688A68C94E; Wed, 18 Oct 2023 19:55:39 +0300 (EEST) Received: from out203-205-251-53.mail.qq.com (out203-205-251-53.mail.qq.com [203.205.251.53]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 3561468CA86 for ; Wed, 18 Oct 2023 19:55:30 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=foxmail.com; s=s201512; t=1697648120; bh=ATLwNzBhUMaZra4W0RKjV8G3BrY0bv8RgKbXljYnqK0=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=aBi2w1a6IPkRYcs90KX4z7YRD0aLYssR8V8f1AkP+xu/ZeaYCLCqDTlaTGRT1Blpm 6Pl06rhaKV4u3nTKsLRxkIiM9XPui3+Bw1+ShhI/dfUIIP+ZSdJZsDO/K2jekPyNqk hCwAfUY7TBhkvJcgvnsCaWq4CDGeAPDeBR8lsGiU= Received: from localhost.localdomain ([113.118.106.95]) by newxmesmtplogicsvrszb9-0.qq.com (NewEsmtp) with SMTP id DD2B24AA; Thu, 19 Oct 2023 00:55:18 +0800 X-QQ-mid: xmsmtpt1697648119t221nwh1n Message-ID: X-QQ-XMAILINFO: M0msBj/q2J/mK9ZaKgqG3FOBo3rZjVXOaezzpGFu0YPd624JIHtuxq7pZQaXy4 OSdlyid4fa9IWhn4ZhZizbO26T0ad/kA/oHxbrtGH6DAU2amwgU25ip22rxAMTPzjbLmaTrM49DC NUQIrJjUJazQrdSOquMp070Tuz7yZULVTHKI/PZZKfI5y+zMVNtDj1OQpI5C7eyRtoCHlHBQ/FCj cRQKyJtz5GrCNbjp+P9Aa6XGPHeE8Wgeuz8+U1pkA/Ltf+JQVgjYAsVqaYHk5wbk4ceEC9q6fK11 K5aJIOkGtNlwwJ7pvgvXE0V2ltIC58bs6bCjd42s0iMuq9+JzsAZ/xbp9ZIlmDnpg6q9IFVv6LxI TB6I0PD4rqk7RVzfSvKJnnETtfWmohsFDBoBcVGQfDQFbZ6pq4lPWSYLOpHKkJt4icOuCJDx26ZW TV9B013oH8nYL3esmjjgdBxnknxLVONkwrTDMXvHp9/e3rE7Ml2azfE0eusCa5M/GM46XdclklsS 7Mn5egAYJyiDprJZMy7s8wYhwicbb4sV4gxXhyOOXUzKJ54P8ekeWdhUDg3NmZPGJbGKCUNV28mK yoXe9cCZ1jeoRFv0/e4UR25KvP4CZ29YU3Wqqawv0fm5KvYmhU4urqkxc571nH9BATpwGM7qwgkS R2glJXwsYcfGfYqHEMypl84hOzTjs9rTFLH19a8a92MlsDB+S078dBDOOxmpetLB1DCnKbnoghPI FVL8BDXEZYenZaz7dVF043HN0RBWrBANLYRIzA4hYFkaWw0K6QuKuSLWdbr2DFCN020+iee3o1qD IBq1YtFYUmSaGvJMrmZY6Dpp7IC3LKkrPZHPSz72/QlSCRSdVOjhji0duOI8BteEGmLEvVYfTKXi SzDT1s0HvtV/aaTycDpJ6F/+p75MmaDYSO9gg4U+rXA1XVg2HimSKfskSojhr30GZwv3koHW9rgl SQ+TGOYf7JK7lGdyleqaUnJlzJAo+Fu1hDkbqmM06E82W0DOvuNb7xsi72sVKpZLwjq2ehLXk= X-QQ-XMRINFO: NS+P29fieYNw95Bth2bWPxk= From: Zhao Zhili To: ffmpeg-devel@ffmpeg.org Date: Thu, 19 Oct 2023 00:55:16 +0800 X-OQ-MSGID: <20231018165516.275945-2-quinkblack@foxmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231018165516.275945-1-quinkblack@foxmail.com> References: <20231018165516.275945-1-quinkblack@foxmail.com> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v2 2/2] fftools/ffplay: add hwaccel decoding support X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: Zhao Zhili Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Archived-At: List-Archive: List-Post: From: Zhao Zhili --- fftools/ffplay.c | 30 ++++++++++ fftools/ffplay_renderer.c | 117 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+) diff --git a/fftools/ffplay.c b/fftools/ffplay.c index 305d72d8b8..0f9584b57e 100644 --- a/fftools/ffplay.c +++ b/fftools/ffplay.c @@ -352,6 +352,7 @@ static int autorotate = 1; static int find_stream_info = 1; static int filter_nbthreads = 0; static int enable_vulkan = 0; +static const char *hwaccel = NULL; /* current context */ static int is_full_screen; @@ -2557,6 +2558,24 @@ static int audio_open(void *opaque, AVChannelLayout *wanted_channel_layout, int return spec.size; } +static int create_hwaccel(AVBufferRef **device_ctx) +{ + enum AVHWDeviceType type; + int ret; + + *device_ctx = NULL; + + if (!hwaccel) + return 0; + + type = av_hwdevice_find_type_by_name(hwaccel); + if (type == AV_HWDEVICE_TYPE_NONE) + return AVERROR(ENOTSUP); + + ret = av_hwdevice_ctx_create(device_ctx, type, NULL, NULL, 0); + return ret; +} + /* open a given stream. Return 0 if OK */ static int stream_component_open(VideoState *is, int stream_index) { @@ -2624,6 +2643,12 @@ static int stream_component_open(VideoState *is, int stream_index) av_dict_set(&opts, "flags", "+copy_opaque", AV_DICT_MULTIKEY); + if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) { + ret = create_hwaccel(&avctx->hw_device_ctx); + if (ret < 0) + goto fail; + } + if ((ret = avcodec_open2(avctx, codec, &opts)) < 0) { goto fail; } @@ -3625,6 +3650,7 @@ static const OptionDef options[] = { "read and decode the streams to fill missing information with heuristics" }, { "filter_threads", HAS_ARG | OPT_INT | OPT_EXPERT, { &filter_nbthreads }, "number of filter threads per graph" }, { "enable_vulkan", OPT_BOOL, { &enable_vulkan }, "enable vulkan render" }, + { "hwaccel", HAS_ARG | OPT_STRING | OPT_EXPERT, { &hwaccel }, "use HW accelerated decoding" }, { NULL, }, }; @@ -3739,6 +3765,10 @@ int main(int argc, char **argv) #ifdef SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, "0"); #endif + if (hwaccel && !enable_vulkan) { + av_log(NULL, AV_LOG_INFO, "Enable vulkan renderer to support hwaccel %s\n", hwaccel); + enable_vulkan = 1; + } if (enable_vulkan) { vk_renderer = vk_get_renderer(); if (vk_renderer) { diff --git a/fftools/ffplay_renderer.c b/fftools/ffplay_renderer.c index 796a964a7b..bf6ad7fbaf 100644 --- a/fftools/ffplay_renderer.c +++ b/fftools/ffplay_renderer.c @@ -50,6 +50,12 @@ typedef struct RendererContext { pl_tex tex[4]; pl_log vk_log; + + AVBufferRef *hw_device; + AVBufferRef *hw_frame; + int hw_failed; + + AVFrame *vk_frame; } RendererContext; static void vk_log_cb(void *log_priv, enum pl_log_level level, const char *msg) { @@ -133,6 +139,13 @@ static int create(VkRenderer *renderer, SDL_Window *window) ret = AVERROR_EXTERNAL; goto out; } + + ctx->vk_frame = av_frame_alloc(); + if (!ctx->vk_frame) { + ret = AVERROR(ENOMEM); + goto out; + } + ret = 0; out: @@ -140,6 +153,102 @@ out: return ret; } +static int create_hw(VkRenderer *renderer, AVFrame *frame) +{ + RendererContext *ctx = (RendererContext *)renderer; + AVHWFramesContext *src_hw_frame = (AVHWFramesContext *)frame->hw_frames_ctx->data; + AVBufferRef *src_dev = src_hw_frame->device_ref; + int ret; + + if (ctx->hw_failed) + return ctx->hw_failed; + + if (!ctx->hw_device) { + ret = av_hwdevice_ctx_create_derived(&ctx->hw_device, AV_HWDEVICE_TYPE_VULKAN, src_dev, 0); + if (ret < 0) { + av_log(renderer, AV_LOG_ERROR, "Derive hwaccel failed, %s\n", av_err2str(ret)); + ctx->hw_failed = ret; + return ret; + } + } + + if (!ctx->hw_frame) { + AVHWFramesContext *hw_frame; + + ctx->hw_frame = av_hwframe_ctx_alloc(ctx->hw_device); + if (!ctx->hw_frame) { + ctx->hw_failed = AVERROR(ENOMEM); + return AVERROR(ENOMEM); + } + + hw_frame = (AVHWFramesContext *)ctx->hw_frame->data; + hw_frame->format = AV_PIX_FMT_VULKAN; + hw_frame->sw_format = src_hw_frame->sw_format; + hw_frame->width = frame->width; + hw_frame->height = frame->height; + + ret = av_hwframe_ctx_init(ctx->hw_frame); + if (ret < 0) { + av_log(renderer, AV_LOG_ERROR, "Create hwframe context failed, %s\n", av_err2str(ret)); + ctx->hw_failed = ret; + return ret; + } + } + + return 0; +} + +static int transfer_frame(VkRenderer *renderer, AVFrame *frame) +{ + RendererContext *ctx = (RendererContext *)renderer; + int ret; + + if (!frame->hw_frames_ctx) + return 0; + + if (frame->format == AV_PIX_FMT_VULKAN) + return 0; + + ret = create_hw(renderer, frame); + if (ret < 0 && ret != AVERROR(ENOSYS)) + return ret; + + // Try map data first + av_frame_unref(ctx->vk_frame); + if (ctx->hw_frame) { + ctx->vk_frame->hw_frames_ctx = av_buffer_ref(ctx->hw_frame); + ctx->vk_frame->format = AV_PIX_FMT_VULKAN; + } + ret = av_hwframe_map(ctx->vk_frame, frame, AV_HWFRAME_MAP_READ); + if (!ret) { + goto out; + } + + if (ret != AVERROR(ENOSYS)) { + av_log(NULL, AV_LOG_FATAL, "Map data to vulkan failed: %s\n", av_err2str(ret)); + return ret; + } + + // Try transfer data + av_frame_unref(ctx->vk_frame); + if (ctx->hw_frame) + av_hwframe_get_buffer(ctx->hw_frame, ctx->vk_frame, 0); + ret = av_hwframe_transfer_data(ctx->vk_frame, frame, 0); + if (ret < 0) { + av_log(NULL, AV_LOG_FATAL, "Transfer data to vulkan failed: %s\n", av_err2str(ret)); + return ret; + } + +out: + ret = av_frame_copy_props(ctx->vk_frame, frame); + if (ret < 0) + return ret; + av_frame_unref(frame); + av_frame_move_ref(frame, ctx->vk_frame); + + return 0; +} + static int display(VkRenderer *renderer, AVFrame *frame) { struct pl_swapchain_frame swap_frame = {0}; @@ -148,6 +257,10 @@ static int display(VkRenderer *renderer, AVFrame *frame) RendererContext *ctx = (RendererContext *)renderer; int ret = 0; + ret = transfer_frame(renderer, frame); + if (ret < 0) + return ret; + if (!pl_map_avframe_ex(ctx->pl_vk->gpu, &pl_frame, pl_avframe_params( .frame = frame, .tex = ctx->tex))) { @@ -194,6 +307,10 @@ static void destroy(VkRenderer *renderer) PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR; RendererContext *ctx = (RendererContext *)renderer; + av_buffer_unref(&ctx->hw_frame); + av_buffer_unref(&ctx->hw_device); + av_frame_free(&ctx->vk_frame); + for (int i = 0; i < FF_ARRAY_ELEMS(ctx->tex); i++) pl_tex_destroy(ctx->pl_vk->gpu, &ctx->tex[i]); pl_renderer_destroy(&ctx->renderer); -- 2.34.1 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".