From ce955da36daa278d5b331b3c97e228e733a5125e Mon Sep 17 00:00:00 2001 From: Andrew Opalach Date: Mon, 8 Sep 2025 13:54:36 -0400 Subject: Major FFmpeg build improvements - Make build more compatible with a traditional linux environment. Signed-off-by: Andrew Opalach --- src/codec/codec.h | 2 + src/codec/ffmpeg/common.c | 16 +++-- src/codec/ffmpeg/decoder.c | 17 +++-- src/codec/ffmpeg/decoder.h | 2 +- src/codec/ffmpeg/demuxer.c | 12 +++- src/codec/ffmpeg/meson.build | 157 ++++++++++++++++++++---------------------- src/codec/ffmpeg/packet_ext.c | 8 ++- 7 files changed, 115 insertions(+), 99 deletions(-) (limited to 'src/codec') diff --git a/src/codec/codec.h b/src/codec/codec.h index 701ef16..9820316 100644 --- a/src/codec/codec.h +++ b/src/codec/codec.h @@ -56,8 +56,10 @@ enum { CAMU_SAMPLE_FORMAT_S32P = AV_SAMPLE_FMT_S32P, CAMU_SAMPLE_FORMAT_FLTP = AV_SAMPLE_FMT_FLTP, CAMU_SAMPLE_FORMAT_DBLP = AV_SAMPLE_FMT_DBLP, +#ifndef CAMU_OLD_FFMPEG CAMU_SAMPLE_FORMAT_S64 = AV_SAMPLE_FMT_S64, CAMU_SAMPLE_FORMAT_S64P = AV_SAMPLE_FMT_S64P +#endif }; enum { diff --git a/src/codec/ffmpeg/common.c b/src/codec/ffmpeg/common.c index 5226df6..e697a00 100644 --- a/src/codec/ffmpeg/common.c +++ b/src/codec/ffmpeg/common.c @@ -1,4 +1,5 @@ #define AL_LOG_SECTION "ff" +//#define AL_LOG_ENABLE_TRACE #include #include #include @@ -27,10 +28,6 @@ static void av_log_callback(void *userdata, s32 level, const char *fmt, va_list { (void)userdata; - if (level >= AV_LOG_DEBUG) { - return; - } - char *offset = log_context.buf + log_context.pos; s32 ret = al_vsnprintf(offset, AV_LOG_MAX_CHUNK, fmt, args); al_assert(ret > 0); @@ -41,8 +38,10 @@ static void av_log_callback(void *userdata, s32 level, const char *fmt, va_list if ((log_context.pos > 0 && *(offset - 1) == '\n') || log_context.pos >= AV_LOG_MAX_CHUNK) { if (level < AV_LOG_WARNING) { log_info(log_context.buf); - } else { + } else if (level < AL_LOG_DEBUG) { log_debug(log_context.buf); + } else { + log_trace(log_context.buf); } log_context.pos = 0; } @@ -55,9 +54,14 @@ void camu_ff_set_log_callback(void (*callback)(void *, s32, const char *, va_lis void camu_ff_common_init(void) { - log_info("Using FFmpeg version "FFMPEG_VERSION"."); + #ifdef CAMU_OLD_FFMPEG + log_info("Using FFmpeg version "FFMPEG_VERSION" (old)."); + AL_IGNORE_WARNING("-Wdeprecated-declarations") av_register_all(); + AL_IGNORE_WARNING_END +#else + log_info("Using FFmpeg version "FFMPEG_VERSION"."); #endif camu_ff_set_log_callback(av_log_callback); } diff --git a/src/codec/ffmpeg/decoder.c b/src/codec/ffmpeg/decoder.c index 7be21a2..47bab44 100644 --- a/src/codec/ffmpeg/decoder.c +++ b/src/codec/ffmpeg/decoder.c @@ -5,17 +5,20 @@ #include "decoder.h" -#if !defined CAMU_SINK_NO_VIDEO && defined CAMU_FF_DECODER_HWACCEL +#ifdef CAMU_FF_DECODER_HWACCEL #include "../../render/renderer.h" static const char *hwdevces[] = { -#if defined STELA_API_VULKAN +#ifdef CAMU_HAVE_VULKAN_DECODE "vulkan", -#else -#if defined NAUNET_ON_WINDOWS - "d3d11va", -#else +#endif +#ifdef CAMU_HAVE_VAAPI "vaapi", #endif +#ifdef CAMU_HAVE_D3D11VA + "d3d11va", +#endif +#ifdef CAMU_HAVE_DXVA2 + "dxva2", #endif }; #endif @@ -179,6 +182,8 @@ static bool get_hwdevice_config(struct camu_ff_decoder *av, const AVCodec *codec return true; } } + const char *hwdevice_name = av_hwdevice_get_type_name(hw_device_type); + log_warn("No hw_config for device type %s (type: %d).", hwdevice_name, hw_device_type); return false; } diff --git a/src/codec/ffmpeg/decoder.h b/src/codec/ffmpeg/decoder.h index 85b88dc..ff513b9 100644 --- a/src/codec/ffmpeg/decoder.h +++ b/src/codec/ffmpeg/decoder.h @@ -4,7 +4,7 @@ #include "../codec.h" -#ifdef CAMU_USE_HWACCEL +#if defined CAMU_TRY_HWACCEL && !defined CAMU_SINK_NO_VIDEO #define CAMU_FF_DECODER_HWACCEL #endif diff --git a/src/codec/ffmpeg/demuxer.c b/src/codec/ffmpeg/demuxer.c index f05cfa9..a8f1df7 100644 --- a/src/codec/ffmpeg/demuxer.c +++ b/src/codec/ffmpeg/demuxer.c @@ -1,4 +1,5 @@ #define AL_LOG_SECTION "ff_demuxer" +//#define AL_LOG_ENABLE_TRACE #include #include @@ -9,7 +10,12 @@ static void close_internal(struct camu_ff_demuxer *av) { if (av->io_context) { av_free(av->io_context->buffer); +#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57, 80, 100) avio_context_free(&av->io_context); +#else + av_free(av->io_context); + av->io_context = NULL; +#endif } if (av->format_context) { avformat_flush(av->format_context); @@ -126,9 +132,13 @@ static bool ff_demuxer_init(struct camu_demuxer *demux, struct cch_handle *handl })); } +#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(60, 30, 100) av_format_inject_global_side_data(av->format_context); +#endif - //av_dump_format(av->format_context, 0, "", 0); +#ifdef AL_LOG_ENABLE_TRACE + av_dump_format(av->format_context, 0, "", 0); +#endif av->eof = false; diff --git a/src/codec/ffmpeg/meson.build b/src/codec/ffmpeg/meson.build index 56a75b2..6482426 100644 --- a/src/codec/ffmpeg/meson.build +++ b/src/codec/ffmpeg/meson.build @@ -1,97 +1,88 @@ -ffmpeg_src = [ - 'common.c', - 'packet_ext.c', -] +ffmpeg_src = ['common.c', 'packet_ext.c'] ffmpeg_args = ['-DCAMU_HAVE_FFMPEG'] -if get_option('codec-hwaccel').enabled() - ffmpeg_args += ['-DCAMU_USE_HWACCEL'] -endif -ffmpeg_deps = [] - -ffmpeg_server_src = [ - ffmpeg_src, - 'demuxer.c', - 'avio.c' -] -ffmpeg_server_deps = [] - -ffmpeg_client_src = [ - ffmpeg_src, - 'decoder.c', - 'resampler.c', - 'scaler.c' -] -ffmpeg_client_deps = [] +ffmpeg_server_src = [ffmpeg_src, 'demuxer.c', 'avio.c'] server_transcode = not get_option('sink-only') if server_transcode - ffmpeg_server_src += [ - 'decoder.c', - 'resampler.c', - 'scaler.c', - 'encoder.c' - ] + ffmpeg_server_src += ['decoder.c', 'resampler.c', 'scaler.c', 'encoder.c'] endif +ffmpeg_server_deps = [] + +ffmpeg_client_src = [ffmpeg_src, 'decoder.c', 'resampler.c', 'scaler.c'] +ffmpeg_client_deps = [] -libavutil = dependency('libavutil', required: false) -libavformat = dependency('libavformat', required: false) -libavcodec = dependency('libavcodec', required: false) -#libavdevice = dependency('libavdevice', required: false) -libswresample = dependency('libswresample', required: false) -libswscale = dependency('libswscale', required: false) -if not (libavutil.found() and libavformat.found() and libavcodec.found() and libswresample.found() and libswscale.found()) - if get_option('win32-compat') - ffmpeg_proj = subproject('ffmpeg-compat', required: false) - ffmpeg_args += ['-DCAMU_OLD_FFMPEG'] +ffmpeg_force_fallback = false +foreach dep: ['ffmpeg', 'libavutil', 'libavformat', 'libavcodec', 'libavdevice', 'libswresample', 'libswscale'] + if dep in get_option('force_fallback_for') + ffmpeg_force_fallback = true + break + endif +endforeach +ffmpeg_version_option = get_option('codec-ffmpeg-version') +# Check for FFmpeg version in the environment. +if not ffmpeg_force_fallback + libavutil_version_map = { '54': '2', '55': '3', '56': '4', '57': '5', '58': '6', '59': '7', '60': '8' } + libavutil_version_rev = { '2': '54', '3': '55', '4': '56', '5': '57', '6': '58', '7': '59', '8': '60' } + if ffmpeg_version_option != 'system' + ffmpeg_version_int = ffmpeg_version_option.to_int() + # Overriding a found dependency will error but overriding a found dependency of the wrong version is allowed. + libavutil_version_request = ['>=' + libavutil_version_rev[(ffmpeg_version_int).to_string()] + '.0.0'] + if ffmpeg_version_int < 8 + libavutil_version_request += ['<' + libavutil_version_rev[(ffmpeg_version_int + 1).to_string()] + '.0.0'] + endif + libavutil = dependency('libavutil', required: false, allow_fallback: false, version: libavutil_version_request) else - ffmpeg_proj = subproject('ffmpeg', required: false) + libavutil = dependency('libavutil', required: false, allow_fallback: false) endif - if ffmpeg_proj.found() - libavutil = ffmpeg_proj.get_variable('avutil') - libavformat = ffmpeg_proj.get_variable('avformat') - libavcodec = ffmpeg_proj.get_variable('avcodec') - #libavdevice = ffmpeg_proj.get_variable('avdevice') - libswresample = ffmpeg_proj.get_variable('swresample') - libswscale = ffmpeg_proj.get_variable('swscale') - # Only used to set include dirs for FFmpeg. - ffmpeg_deps += [ffmpeg_proj.get_variable('ffmpeg_include')] - # We explicitly enable zlib and maybe bzlib in the FFmpeg build. - ffmpeg_deps += [dependency('zlib')] - if not get_option('sink-only') - ffmpeg_deps += [dependency('bzip2')] + if libavutil.found() + ffmpeg_version_string = run_command('sh', join_paths(meson.current_source_dir(), 'version.sh'), check: true).stdout().strip() + if ffmpeg_version_string == '(unknown)' + ffmpeg_version_string = libavutil_version_map[libavutil.version().split('.')[0]] + '.x' endif - if is_windows and not get_option('win32-compat') - # Extra static dependencies for Windows. - ffmpeg_client_deps += [compiler.find_library('bcrypt')] - elif is_android - # Android MediaCodec HW decoding. - ffmpeg_client_deps += [compiler.find_library('mediandk')] + ffmpeg_args += ['-DFFMPEG_VERSION="' + ffmpeg_version_string + '"'] + if get_option('codec-hwaccels').length() > 0 + hwaccel_map = { + 'vulkan': '-DCAMU_HAVE_VULKAN_DECODE', + 'vaapi': '-DCAMU_HAVE_VAAPI', + 'd3d11va': '-DCAMU_HAVE_D3D11VA', + 'dxva2': '-DCAMU_HAVE_DXVA2', + 'mediacodec': '-DCAMU_HAVE_MEDIACODEC', + } + foreach hwaccel: get_option('codec-hwaccels') + if hwaccel in hwaccel_map + ffmpeg_args += hwaccel_map[hwaccel] + endif + endforeach + ffmpeg_args += ['-DCAMU_TRY_HWACCEL'] endif - ffmpeg_version_string = ffmpeg_proj.get_variable('ffmpeg_version_string') + elif ffmpeg_version_option == 'system' + error('System FFmpeg requested but not found. Add \'--force-fallback-for=ffmpeg\' or \'-Dcodec-ffmpeg-version=[8,7,6,...]\'.') endif -else - ffmpeg_version_string = run_command('sh', join_paths(meson.current_source_dir(), 'version.sh'), check: true).stdout().strip() endif - -if libavutil.found() and libavformat.found() and libavcodec.found() and libswresample.found() and libswscale.found() - # This is probably meaningless compared to libav* versions, it's just something I wanted. - ffmpeg_args += ['-DFFMPEG_VERSION="' + ffmpeg_version_string + '"'] - ffmpeg_server_deps += [libavutil, libavformat, libavcodec] - if server_transcode - ffmpeg_server_deps += [libswresample, libswscale] - endif - ffmpeg_client_deps += [libavutil, libavformat, libavcodec, libswresample, libswscale] - soxr = compiler.find_library('soxr', required: false) - if soxr.found() - ffmpeg_client_deps += [soxr] - ffmpeg_args += ['-DCAMU_HAVE_SOXR'] +# Fallback if requested or necessary. +if ffmpeg_force_fallback or not libavutil.found() + if ffmpeg_version_option == 'system' + ffmpeg_version_option = '8' # Default to current latest. endif - codec_server_deps += [ - declare_dependency(sources: ffmpeg_server_src, - dependencies: [ffmpeg_deps, ffmpeg_server_deps], compile_args: ffmpeg_args) - ] - codec_client_deps += [ - declare_dependency(sources: ffmpeg_client_src, - dependencies: [ffmpeg_deps, ffmpeg_client_deps], compile_args: ffmpeg_args) - ] + subproject('ffmpeg' + ffmpeg_version_option) # Override libav dependencies. +endif + +libavutil = dependency('libavutil') +libavutil_version = libavutil.version().split('.')[0].to_int() +if libavutil_version <= 54 + error('FFmpeg version 2.x and lower currently unsupported.') +elif libavutil_version <= 56 + ffmpeg_args += ['-DCAMU_OLD_FFMPEG'] +endif +libavformat = dependency('libavformat') +libavcodec = dependency('libavcodec') +libavdevice = dependency('libavdevice') +libswresample = dependency('libswresample') +libswscale = dependency('libswscale') +ffmpeg_server_deps += [libavutil, libavformat, libavcodec] +if server_transcode + ffmpeg_server_deps += [libswresample, libswscale] endif +ffmpeg_client_deps += [libavutil, libavformat, libavcodec, libswresample, libswscale] +codec_server_deps += [declare_dependency(sources: ffmpeg_server_src, dependencies: ffmpeg_server_deps, compile_args: ffmpeg_args)] +codec_client_deps += [declare_dependency(sources: ffmpeg_client_src, dependencies: ffmpeg_client_deps, compile_args: ffmpeg_args)] diff --git a/src/codec/ffmpeg/packet_ext.c b/src/codec/ffmpeg/packet_ext.c index 7dcda88..6b66dd1 100644 --- a/src/codec/ffmpeg/packet_ext.c +++ b/src/codec/ffmpeg/packet_ext.c @@ -16,7 +16,7 @@ void nn_packet_write_av_codec_parameters(struct nn_packet *packet, AVCodecParame NNWT_PACKET_WRITE_TYPE(packet, s32, codecpar->width); NNWT_PACKET_WRITE_TYPE(packet, s32, codecpar->height); NNWT_PACKET_WRITE_TYPE(packet, AVRational, codecpar->sample_aspect_ratio); -#if !defined CAMU_OLD_FFMPEG && LIBAVCODEC_VERSION_INT >= 60 +#if !defined CAMU_OLD_FFMPEG && LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(60, 11, 100) NNWT_PACKET_WRITE_TYPE(packet, AVRational, codecpar->framerate); #endif NNWT_PACKET_WRITE_TYPE(packet, enum AVFieldOrder, codecpar->field_order); @@ -108,6 +108,10 @@ void nn_packet_write_av_packet(struct nn_packet *packet, AVPacket *pkt) #endif } +// @TODO: coded_side_data +// https://github.com/FFmpeg/FFmpeg/blob/f62d8789116fef8d8cd7f20062b16ccd93f7ce23/doc/APIchanges#L537 +// https://ffmpeg.org/doxygen/8.0/structAVCodecParameters.html#ad54da9241deabb3601e6e0e8fa832c19 +// #if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(60, 30, 100) void nn_packet_read_av_codec_parameters(struct nn_packet *packet, AVCodecParameters *codecpar) { NNWT_PACKET_READ_TYPE(packet, enum AVMediaType, codecpar->codec_type); @@ -127,7 +131,7 @@ void nn_packet_read_av_codec_parameters(struct nn_packet *packet, AVCodecParamet NNWT_PACKET_READ_TYPE(packet, s32, codecpar->width); NNWT_PACKET_READ_TYPE(packet, s32, codecpar->height); NNWT_PACKET_READ_TYPE(packet, AVRational, codecpar->sample_aspect_ratio); -#if !defined CAMU_OLD_FFMPEG && LIBAVCODEC_VERSION_INT >= 60 +#if !defined CAMU_OLD_FFMPEG && LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(60, 11, 100) NNWT_PACKET_READ_TYPE(packet, AVRational, codecpar->framerate); #endif NNWT_PACKET_READ_TYPE(packet, enum AVFieldOrder, codecpar->field_order); -- cgit v1.2.3-101-g0448