summaryrefslogtreecommitdiff
path: root/src/codec
diff options
context:
space:
mode:
Diffstat (limited to 'src/codec')
-rw-r--r--src/codec/ffmpeg/decoder.c99
-rw-r--r--src/codec/ffmpeg/decoder.h5
2 files changed, 75 insertions, 29 deletions
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;
};