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 4849847C6E for ; Sun, 15 Oct 2023 13:05:40 +0000 (UTC) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 34B2168C78E; Sun, 15 Oct 2023 16:05:38 +0300 (EEST) Received: from out162-62-57-210.mail.qq.com (out162-62-57-210.mail.qq.com [162.62.57.210]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 3955F68BF45 for ; Sun, 15 Oct 2023 16:05:30 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=foxmail.com; s=s201512; t=1697375121; bh=VVBk4xZFKNFyW+rHkw/BB2bfReNIIIrk3KAb/j9wknU=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=wUAl/sdnQabKbkM4bZ9nfEnwNLkyXF07na/C5Pjp6PQu6VjDKAA8JsC2kB+tddCTR C1Wd50g6mO/DGUdoh7ug6WAWds8rJYVqyzR7/yhBXzLn/vwxu/FEeFsakxwE6SXifm gbeFCT/D2w0ElOFnp88EnluWE4c5dD6BV7kOa7pI= Received: from localhost.localdomain ([121.35.185.85]) by newxmesmtplogicsvrszc2-0.qq.com (NewEsmtp) with SMTP id 152A04B8; Sun, 15 Oct 2023 21:05:18 +0800 X-QQ-mid: xmsmtpt1697375120tj9yqil98 Message-ID: X-QQ-XMAILINFO: M/NR0wiIuy70pgZa/WcfiCMgmy/5rdmNACIqg9KR0pgNykZKlm089Khw79ziys 3Tp+QFaHrAFD2R0Ps64pmrVR4Ah9v5nPNvQGlihrS4tgttqfPCbIZu/OTQc5TGvN2CxalEtlmDNR g9Re6yoiiSjsIqoOsrnMUCsKBdIZazas213rYTCWFzJNEUZzCFO9IHhyF9D2ChdETqYdaPdj4HkG nR7vIqt8cnu11p203LBK+/OMj3KMXFnzb1oid0aDSnYW+0Ywt4gFVSb2e/73ap2aYJk/H4LKQ+C9 dyy6Y4IDzP/Gfd4dndttU+0TcW8a5kkMDfPV3vAMOElbdBizxXq7f61DSgj6jPWtxkqLsqgKuft5 MZ7rXe/OtCdQyGzzne27EmEnO4w51O1gwqIyLVORIJ8qNL9oOj+Cd8kzZtJ7+oJZ4qDDbx6kdWfC WNirUwYz1RT7wAsEFeouMV6bLPvR3bRtq19bGuh78D3HQZNc2mCNvzq+sT3I6/MKjEfPYTatgcac HJQkdniULhH7sbEAt+lsW/+c6okY7YgUDMMD2/dzBDmy8DpUoJwlox3CxrpEbzwbvjV7WwgY1yd2 gkta8zbH0gXassW+UPQ24GwuqOnecbYUbukP1KphzEmG2b3koMyA2sz6kqZ/Ed6ZqRQ6E/JNHydu B0r/kJH0o4thQDdiapYAkepoEppkuL/fHZDWE7NoipD7jQxYCSey3t/TWQvSzHRvL4q63mmvw4/v kyeDUHc8ps3BJOzZ5cTiVAVGYOSifGT7Bjlay8Gy+0hycoCSbDtDAOQhA3GoCOlwIfLjx6TGjGG2 HY6mepnTU/gExx1pPhFSGnmVC7tP9MuFp2ygAgIjlkWdRNeLYjC60olh2CDulYNdzEb5GNa/1r/3 HEioKa4kEtklhnu/dZuMyGvzq8itkmhsL7rO/aKcb+Vn+scFtKTCHvW2Jq0MqqhekiFQT7wV3/Qq 14SrYoKrQMTZEqhqVG12mdssMTdgTEYsTjnqJQJutqMkyNRqD2l+PaNhVAQzt8 X-QQ-XMRINFO: Nq+8W0+stu50PRdwbJxPCL0= From: Zhao Zhili To: ffmpeg-devel@ffmpeg.org Date: Sun, 15 Oct 2023 21:05:15 +0800 X-OQ-MSGID: <20231015130515.8445-3-quinkblack@foxmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231015130515.8445-1-quinkblack@foxmail.com> References: <20231015130515.8445-1-quinkblack@foxmail.com> MIME-Version: 1.0 Subject: [FFmpeg-devel] [RFC PATCH 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 | 31 ++++++++++ fftools/ffplay_renderer.c | 120 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 151 insertions(+) diff --git a/fftools/ffplay.c b/fftools/ffplay.c index 3ae9c47509..bd88fed8d6 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,29 @@ 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; + + if (!vk_renderer) { + av_log(NULL, AV_LOG_WARNING, "hwaccel only works with -enable_vulkan\n"); + 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 +2648,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; } @@ -3623,6 +3653,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, }, }; diff --git a/fftools/ffplay_renderer.c b/fftools/ffplay_renderer.c index b03729c064..10de78c32b 100644 --- a/fftools/ffplay_renderer.c +++ b/fftools/ffplay_renderer.c @@ -48,6 +48,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) { @@ -131,6 +137,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: @@ -138,12 +151,115 @@ 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) { + if (ret != AVERROR(ENOSYS)) + return ret; + // Fallback to slow path + goto try_transfer; + } + + // Try map data first + av_frame_unref(ctx->vk_frame); + ctx->vk_frame->hw_frames_ctx = av_buffer_ref(ctx->hw_frame); + 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: + // 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}; struct pl_frame pl_frame = {0}; struct pl_frame target = {0}; RendererContext *ctx = (RendererContext *)renderer; + int ret; + + ret = transfer_frame(renderer, frame); + if (ret < 0) + return ret; if (!pl_swapchain_start_frame(ctx->swapchain, &swap_frame)) { av_log(NULL, AV_LOG_ERROR, "start frame failed\n"); @@ -179,6 +295,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".