From 474ccfd0534e03cfcde94fe0f94e3028ed65366a Mon Sep 17 00:00:00 2001 From: Andrew Opalach Date: Sun, 19 Jan 2025 10:49:22 -0500 Subject: Add DVD boilerplate - Work on FFmpeg hwframes context support - Raspberry Pi testing - Update color_palette Signed-off-by: Andrew Opalach --- src/codec/ffmpeg/decoder.c | 99 +++++++++++++++++++++++++++++++++------------- src/codec/ffmpeg/decoder.h | 5 ++- 2 files changed, 75 insertions(+), 29 deletions(-) (limited to 'src/codec/ffmpeg') diff --git a/src/codec/ffmpeg/decoder.c b/src/codec/ffmpeg/decoder.c index c2d95ce..b502e88 100644 --- a/src/codec/ffmpeg/decoder.c +++ b/src/codec/ffmpeg/decoder.c @@ -14,13 +14,53 @@ static s32 get_buffer2(AVCodecContext *context, AVFrame *pic, s32 flags) return ret; } +static s32 init_hwframe_context(struct camu_ff_decoder *av, AVCodecContext *context, AVBufferRef *hw_device_context) +{ + AVBufferRef *hw_frames_ref; + if (!(hw_frames_ref = av_hwframe_ctx_alloc(hw_device_context))) { + al_log_error("ff_decoder", "Failed to create hardware frame context."); + return -1; + } + + AVHWFramesContext *frames_ctx = (AVHWFramesContext *)(hw_frames_ref->data); + frames_ctx->format = av->hw_pix_fmt; + frames_ctx->sw_format = av->codec_context->sw_pix_fmt; + frames_ctx->width = av->codec_context->width; + frames_ctx->height = av->codec_context->height; + frames_ctx->initial_pool_size = 20; + + s32 ret = av_hwframe_ctx_init(hw_frames_ref); + if (ret < 0) { + al_log_error("ff_decoder", "Failed to initialize hardware frame context (%s).", av_err2str(ret)); + av_buffer_unref(&hw_frames_ref); + return ret; + } + + context->hw_frames_ctx = av_buffer_ref(hw_frames_ref); + + av_buffer_unref(&hw_frames_ref); + + return ret; +} + static enum AVPixelFormat get_hw_format(AVCodecContext *context, const enum AVPixelFormat *pix_fmts) { struct camu_ff_decoder *av = (struct camu_ff_decoder *)context->opaque; const enum AVPixelFormat *fmt = pix_fmts; for (; *fmt != AV_PIX_FMT_NONE; fmt++) { - if (*fmt == av->hw_pix_fmt) return *fmt; + if (*fmt == av->hw_pix_fmt) { + if (av->use_frames_context) { + av->hw_context = NULL; + s32 ret = av_hwdevice_ctx_create(&av->hw_context, AV_HWDEVICE_TYPE_VAAPI, NULL, NULL, 0); + if (ret < 0 || !av->hw_context) { + al_log_error("ff_decoder", "Failed to initialize VAAPI device (%s).", av_err2str(ret)); + break; + } + init_hwframe_context(av, av->codec_context, av->hw_context); + } + return *fmt; + } } al_log_error("ff_decoder", "Failed to get HW surface format."); @@ -29,14 +69,9 @@ static enum AVPixelFormat get_hw_format(AVCodecContext *context, const enum AVPi } #endif -static void close_internal(struct camu_ff_decoder *av) +static s32 init_hwdevice_context(struct camu_ff_decoder *av, AVCodecContext *context) { - if (av->codec_context) avcodec_free_context(&av->codec_context); -} - -static s32 init_hw_decoder(struct camu_ff_decoder *av, AVCodecContext *context, const enum AVHWDeviceType device_type) -{ - s32 ret = av_hwdevice_ctx_create(&av->hw_context, device_type, NULL, NULL, 0); + s32 ret = av_hwdevice_ctx_create(&av->hw_context, av->hw_device_type, NULL, NULL, 0); if (ret < 0) { al_log_error("ff_decoder", "Failed to create specified HW device."); return ret; @@ -44,11 +79,16 @@ static s32 init_hw_decoder(struct camu_ff_decoder *av, AVCodecContext *context, context->hw_device_ctx = av_buffer_ref(av->hw_context); - al_log_info("ff_decoder", "Using %s hardware decoding.", av_hwdevice_get_type_name(device_type)); + al_log_info("ff_decoder", "Using %s hardware decoding.", av_hwdevice_get_type_name(av->hw_device_type)); return ret; } +static void close_internal(struct camu_ff_decoder *av) +{ + if (av->codec_context) avcodec_free_context(&av->codec_context); +} + static bool ff_decoder_init(struct camu_decoder *dec, struct camu_renderer *renderer, struct camu_codec_stream *stream, void (*callback)(void *, struct camu_codec_frame *), void *userdata) { @@ -69,49 +109,51 @@ static bool ff_decoder_init(struct camu_decoder *dec, struct camu_renderer *rend goto err; } - enum AVHWDeviceType device_type = AV_HWDEVICE_TYPE_NONE; + av->hw_device_type = AV_HWDEVICE_TYPE_NONE; #ifdef CAMU_FF_DECODER_HWACCEL if (codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { -#ifdef _WIN32 +#ifdef _WIN32 // TEMP const char *hw_device = "vulkan"; #else const char *hw_device = "vaapi"; #endif - device_type = av_hwdevice_find_type_by_name(hw_device); - if (device_type == AV_HWDEVICE_TYPE_NONE) { + av->hw_device_type = av_hwdevice_find_type_by_name(hw_device); + if (av->hw_device_type == AV_HWDEVICE_TYPE_NONE) { al_log_info("ff_decoder", "Hardware device type \"%s\" not supported.", hw_device); al_log_info("ff_decoder", "Types available on this system:"); - while ((device_type = av_hwdevice_iterate_types(device_type)) != AV_HWDEVICE_TYPE_NONE) { - al_log_info("ff_decoder", "\t%s", av_hwdevice_get_type_name(device_type)); + while ((av->hw_device_type = av_hwdevice_iterate_types(av->hw_device_type)) != AV_HWDEVICE_TYPE_NONE) { + al_log_info("ff_decoder", "\t%s", av_hwdevice_get_type_name(av->hw_device_type)); } } } #endif - if (device_type != AV_HWDEVICE_TYPE_NONE) { - bool supports_frames_context = false; + if (av->hw_device_type != AV_HWDEVICE_TYPE_NONE) { + av->use_frames_context = false; for (s32 i = 0; ; i++) { const AVCodecHWConfig *config = avcodec_get_hw_config(codec, i); if (!config) { - if (supports_frames_context) { + if (av->use_frames_context) { al_log_warn("ff_decoder", "Selected hardware decoder (%s) only supports" "hardware frames for %s, which is unimplemented.", - av_hwdevice_get_type_name(device_type), codec->name); + av_hwdevice_get_type_name(av->hw_device_type), codec->name); } else { al_log_warn("ff_decoder", "Selected hardware decoder (%s) does not support %s.", - av_hwdevice_get_type_name(device_type), codec->name); + av_hwdevice_get_type_name(av->hw_device_type), codec->name); } - device_type = AV_HWDEVICE_TYPE_NONE; + av->hw_device_type = AV_HWDEVICE_TYPE_NONE; break; } if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX) { - supports_frames_context = true; + av->hw_pix_fmt = config->pix_fmt; + av->use_frames_context = true; } if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX) { - if (config->device_type == device_type) { + if (config->device_type == av->hw_device_type) { av->hw_pix_fmt = config->pix_fmt; + av->use_frames_context = false; break; } } @@ -134,7 +176,7 @@ static bool ff_decoder_init(struct camu_decoder *dec, struct camu_renderer *rend av->renderer = renderer; av->codec_context->opaque = av; av->codec_context->get_buffer2 = get_buffer2; - if (device_type != AV_HWDEVICE_TYPE_NONE) { + if (av->hw_device_type != AV_HWDEVICE_TYPE_NONE) { av->codec_context->get_format = get_hw_format; } } @@ -142,7 +184,7 @@ static bool ff_decoder_init(struct camu_decoder *dec, struct camu_renderer *rend (void)renderer; #endif - if (stream->duration > 0 && device_type == AV_HWDEVICE_TYPE_NONE) { + if (stream->duration > 0 && av->hw_device_type == AV_HWDEVICE_TYPE_NONE) { s32 cpus = 0; if (av->codec_context->codec_type == AVMEDIA_TYPE_VIDEO) { cpus = av_cpu_count(); @@ -154,8 +196,9 @@ static bool ff_decoder_init(struct camu_decoder *dec, struct camu_renderer *rend al_log_debug("ff_decoder", "Using %i threads for decoder.", cpus); } - if ((device_type != AV_HWDEVICE_TYPE_NONE) && - (init_hw_decoder(av, av->codec_context, device_type) < 0)) { + if ((av->hw_device_type != AV_HWDEVICE_TYPE_NONE) && + (init_hwdevice_context(av, av->codec_context) < 0)) { + av->hw_pix_fmt = AV_PIX_FMT_NONE; return false; } @@ -166,7 +209,7 @@ static bool ff_decoder_init(struct camu_decoder *dec, struct camu_renderer *rend const char *long_name = codec->long_name ? codec->long_name : codec->name; s64 kbps = codecpar->bit_rate > 0 ? codecpar->bit_rate / 1000L : 0L; - al_log_info("ff_decoder", "Codec: %s (%s) %ldkbps.", codec->name, long_name, kbps); + al_log_info("ff_decoder", "Codec: %s (%s) %lldkbps.", codec->name, long_name, kbps); av->callback = callback; av->userdata = userdata; diff --git a/src/codec/ffmpeg/decoder.h b/src/codec/ffmpeg/decoder.h index 8d707f3..827afd2 100644 --- a/src/codec/ffmpeg/decoder.h +++ b/src/codec/ffmpeg/decoder.h @@ -5,7 +5,8 @@ #include "../codec.h" -#if !(defined _WIN32 && defined CAMU_RENDERER_OPENGL) +// We need EGL for hwaccel on OpenGL. +#if !(defined CAMU_RENDERER_OPENGL && !defined STELA_USE_EGL) //#define CAMU_FF_DECODER_HWACCEL #endif @@ -15,6 +16,8 @@ struct camu_ff_decoder { struct camu_renderer *renderer; AVBufferRef *hw_context; enum AVPixelFormat hw_pix_fmt; + enum AVHWDeviceType hw_device_type; + bool use_frames_context; void (*callback)(void *, struct camu_codec_frame *); void *userdata; }; -- cgit v1.2.3-101-g0448