From: Zhao Zhili <quinkblack@foxmail.com> To: ffmpeg-devel@ffmpeg.org Cc: Zhao Zhili <zhilizhao@tencent.com> Subject: [FFmpeg-devel] [PATCH v2 2/2] fftools/ffplay: add hwaccel decoding support Date: Thu, 19 Oct 2023 00:55:16 +0800 Message-ID: <tencent_5B85E615D0BE66C8A7C6AA92530DDC43CB06@qq.com> (raw) In-Reply-To: <20231018165516.275945-1-quinkblack@foxmail.com> From: Zhao Zhili <zhilizhao@tencent.com> --- 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".
next parent reply other threads:[~2023-10-18 16:55 UTC|newest] Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top [not found] <20231018165516.275945-1-quinkblack@foxmail.com> 2023-10-18 16:55 ` Zhao Zhili [this message] 2023-10-18 17:05 ` Zhao Zhili [not found] ` <tencent_C04DA1CF8A5540A716B8A2162D4D26207507@qq.com-Nh2k2V1----9> 2023-10-19 1:31 ` Lynne 2023-10-19 1:41 ` Zhao Zhili 2023-10-19 3:31 ` Lynne 2023-10-19 3:51 ` Zhao Zhili
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=tencent_5B85E615D0BE66C8A7C6AA92530DDC43CB06@qq.com \ --to=quinkblack@foxmail.com \ --cc=ffmpeg-devel@ffmpeg.org \ --cc=zhilizhao@tencent.com \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel This inbox may be cloned and mirrored by anyone: git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git # If you have public-inbox 1.1+ installed, you may # initialize and index your mirror using the following commands: public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \ ffmpegdev@gitmailbox.com public-inbox-index ffmpegdev Example config snippet for mirrors. AGPL code for this site: git clone https://public-inbox.org/public-inbox.git