diff options
Diffstat (limited to 'src')
48 files changed, 607 insertions, 647 deletions
diff --git a/src/codec/codec.h b/src/codec/codec.h index 14727d3..16e408c 100644 --- a/src/codec/codec.h +++ b/src/codec/codec.h @@ -35,8 +35,8 @@ enum { enum { CAMU_STREAM_UNKNOWN = AVMEDIA_TYPE_UNKNOWN, - CAMU_STREAM_AUDIO = AVMEDIA_TYPE_AUDIO, // 1 CAMU_STREAM_VIDEO = AVMEDIA_TYPE_VIDEO, // 0 + CAMU_STREAM_AUDIO = AVMEDIA_TYPE_AUDIO, // 1 CAMU_STREAM_SUBTITLE = AVMEDIA_TYPE_SUBTITLE, CAMU_STREAM_ATTACHMENT = AVMEDIA_TYPE_ATTACHMENT }; @@ -77,12 +77,13 @@ enum { CAMU_SEEK_SIZE = 0x10000 }; +// Using values from FFmpeg for potentially less confusing errors. enum { CAMU_STREAM_UNKNOWN = -1, - CAMU_STREAM_AUDIO, - CAMU_STREAM_VIDEO, - CAMU_STREAM_SUBTITLE, - CAMU_STREAM_ATTACHMENT + CAMU_STREAM_VIDEO = 0, + CAMU_STREAM_AUDIO = 1, + CAMU_STREAM_SUBTITLE = 3, + CAMU_STREAM_ATTACHMENT = 4 }; enum { @@ -126,7 +127,11 @@ struct camu_audio_format { s32 format; s32 sample_rate; #ifdef CAMU_HAVE_FFMPEG +#ifndef CAMU_OLD_FFMPEG AVChannelLayout channel_layout; +#else + u64 channel_layout; +#endif #endif s32 channel_count; }; @@ -239,17 +244,49 @@ static inline bool camu_resampler_format_matches(struct camu_resampler_format *f return fmt->in.format == fmt->req.format && fmt->in.sample_rate == fmt->req.sample_rate #ifdef CAMU_HAVE_FFMPEG +#ifndef CAMU_OLD_FFMPEG && av_channel_layout_compare(&fmt->in.channel_layout, &fmt->req.channel_layout) == 0 +#else + && fmt->in.channel_layout == fmt->req.channel_layout +#endif #endif && fmt->in.channel_count == fmt->req.channel_count; } +#ifndef CAMU_OLD_FFMPEG +#define AV_CODECPAR_CHANNEL_LAYOUT(codecpar) ((codecpar)->ch_layout) +#define AV_CODECPAR_CHANNELS(codecpar) ((codecpar)->ch_layout.nb_channels) +static inline void camu_default_channel_layout(AVChannelLayout *ch_layout, s32 channels) +{ + av_channel_layout_default(ch_layout, channels); +} +static inline void camu_copy_channel_layout(AVChannelLayout *dest, AVChannelLayout *src) +{ + av_channel_layout_copy(dest, src); +} +#else +#define AV_CODECPAR_CHANNEL_LAYOUT(codecpar) ((codecpar)->channel_layout) +#define AV_CODECPAR_CHANNELS(codecpar) ((codecpar)->channels) +static inline void camu_default_channel_layout(u64 *channel_layout, s32 channels) +{ + *channel_layout = av_get_default_channel_layout(channels); +} +static inline void camu_copy_channel_layout(u64 *dest, u64 *src) +{ + *dest = *src; +} +#endif + static inline void camu_audio_format_copy(struct camu_audio_format *dest, struct camu_audio_format *src) { dest->format = src->format; dest->sample_rate = src->sample_rate; #ifdef CAMU_HAVE_FFMPEG +#ifndef CAMU_OLD_FFMPEG av_channel_layout_copy(&dest->channel_layout, &src->channel_layout); +#else + dest->channel_layout = src->channel_layout; +#endif #endif dest->channel_count = src->channel_count; } diff --git a/src/codec/ffmpeg/avio.c b/src/codec/ffmpeg/avio.c index 154152e..86130d8 100644 --- a/src/codec/ffmpeg/avio.c +++ b/src/codec/ffmpeg/avio.c @@ -2,20 +2,20 @@ #include "../../cache/handle.h" -s32 camu_avio_read(void *data, u8 *buf, s32 count) +s32 camu_avio_read(void *opaque, u8 *buf, s32 count) { - struct cch_handle *handle = (struct cch_handle *)data; + struct cch_handle *handle = (struct cch_handle *)opaque; return cch_handle_read(handle, buf, count); } -s32 camu_avio_write(void *data, const u8 *buf, s32 count) +s32 camu_avio_write(void *opaque, u8 *buf, s32 count) { - struct cch_handle *handle = (struct cch_handle *)data; + struct cch_handle *handle = (struct cch_handle *)opaque; return cch_handle_write(handle, buf, count); } -s64 camu_avio_seek(void *data, s64 offset, s32 whence) +s64 camu_avio_seek(void *opaque, s64 offset, s32 whence) { - struct cch_handle *handle = (struct cch_handle *)data; + struct cch_handle *handle = (struct cch_handle *)opaque; return (s64)cch_handle_seek(handle, offset, whence); } diff --git a/src/codec/ffmpeg/avio.h b/src/codec/ffmpeg/avio.h index 04aeeb4..bb67c58 100644 --- a/src/codec/ffmpeg/avio.h +++ b/src/codec/ffmpeg/avio.h @@ -2,5 +2,6 @@ #include <al/types.h> -s32 camu_avio_read(void *data, u8 *buf, s32 buf_size); -s64 camu_avio_seek(void *data, s64 offset, s32 whence); +s32 camu_avio_read(void *opaque, u8 *buf, s32 buf_size); +s32 camu_avio_write(void *opaque, u8 *buf, s32 count); +s64 camu_avio_seek(void *opaque, s64 offset, s32 whence); diff --git a/src/codec/ffmpeg/common.c b/src/codec/ffmpeg/common.c index 259ba90..5226df6 100644 --- a/src/codec/ffmpeg/common.c +++ b/src/codec/ffmpeg/common.c @@ -2,6 +2,7 @@ #include <al/log.h> #include <al/lib.h> #include <libavutil/log.h> +#include <libavformat/avformat.h> #include "common.h" @@ -55,5 +56,8 @@ 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 + av_register_all(); +#endif camu_ff_set_log_callback(av_log_callback); } diff --git a/src/codec/ffmpeg/decoder.c b/src/codec/ffmpeg/decoder.c index c22d1c1..e097e0c 100644 --- a/src/codec/ffmpeg/decoder.c +++ b/src/codec/ffmpeg/decoder.c @@ -10,11 +10,11 @@ #endif #ifdef CAMU_FF_DECODER_HWACCEL -#if defined CAMU_RENDERER_VULKAN +#if defined STELA_API_VULKAN static const char *hwdevces[] = { "vulkan" }; #elif defined NAUNET_ON_WINDOWS static const char *hwdevces[] = { "d3d11va" }; -#elif defined CAMU_RENDERER_OPENGL +#elif defined STELA_API_OPENGL static const char *hwdevces[] = { "vaapi" }; #endif diff --git a/src/codec/ffmpeg/decoder.h b/src/codec/ffmpeg/decoder.h index ab60ef3..4797060 100644 --- a/src/codec/ffmpeg/decoder.h +++ b/src/codec/ffmpeg/decoder.h @@ -4,8 +4,8 @@ #include "../codec.h" -#ifndef CAMU_SINK_NO_VIDEO -//#define CAMU_FF_DECODER_HWACCEL +#ifdef CAMU_USE_HWACCEL +#define CAMU_FF_DECODER_HWACCEL #endif struct camu_ff_decoder { diff --git a/src/codec/ffmpeg/demuxer.c b/src/codec/ffmpeg/demuxer.c index bf2039f..a5821a2 100644 --- a/src/codec/ffmpeg/demuxer.c +++ b/src/codec/ffmpeg/demuxer.c @@ -88,6 +88,13 @@ static bool ff_demuxer_init(struct camu_demuxer *demux, struct cch_handle *handl for (u32 i = 0; i < av->format_context->nb_streams; i++) { AVStream *stream = av->format_context->streams[i]; enum AVMediaType type = stream->codecpar->codec_type; +#ifdef CAMU_OLD_FFMPEG + // This is probably not correct. + if (stream->codecpar->channel_layout == 0) { + stream->codecpar->channel_layout = AV_CH_LAYOUT_STEREO; + stream->codecpar->channels = 2; + } +#endif u64 duration = 0; if (type == AVMEDIA_TYPE_AUDIO || type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_SUBTITLE) { // Try to detect attached images. diff --git a/src/codec/ffmpeg/encoder.c b/src/codec/ffmpeg/encoder.c index 50e80e4..5d90785 100644 --- a/src/codec/ffmpeg/encoder.c +++ b/src/codec/ffmpeg/encoder.c @@ -32,7 +32,7 @@ bool camu_ff_encoder_init(struct camu_ff_encoder *enc, char *encoder_name, char } enc->codec_context->sample_rate = 48000; - av_channel_layout_default(&enc->codec_context->ch_layout, CHANNELS); + camu_default_channel_layout(&AV_CODECPAR_CHANNEL_LAYOUT(enc->codec_context), CHANNELS); enc->codec_context->sample_fmt = AV_SAMPLE_FMT_FLT; enc->codec_context->bit_rate = bitrate; enc->codec_context->frame_size = SAMPLES_PER_FRAME; @@ -62,19 +62,20 @@ bool camu_ff_encoder_init(struct camu_ff_encoder *enc, char *encoder_name, char av_dict_free(&opts); AVCodecContext *out_codec = enc->codec_context; + AVFrame *frame = av_frame_alloc(); + frame->format = out_codec->sample_fmt; + frame->sample_rate = out_codec->sample_rate; + camu_copy_channel_layout(&AV_CODECPAR_CHANNEL_LAYOUT(frame), &AV_CODECPAR_CHANNEL_LAYOUT(out_codec)); + av_samples_alloc(frame->data, NULL, AV_CODECPAR_CHANNELS(out_codec), SAMPLES_PER_FRAME, frame->format, 1); + frame->nb_samples = SAMPLES_PER_FRAME; + frame->pts = 0; - enc->fmt.req.format = out_codec->sample_fmt; - enc->fmt.req.sample_rate = out_codec->sample_rate; - av_channel_layout_copy(&enc->fmt.req.channel_layout, &out_codec->ch_layout); - enc->fmt.req.channel_count = out_codec->ch_layout.nb_channels; + enc->fmt.format = frame->format; + enc->fmt.sample_rate = frame->sample_rate; + camu_copy_channel_layout(&enc->fmt.channel_layout, &AV_CODECPAR_CHANNEL_LAYOUT(frame)); + enc->fmt.channel_count = AV_CODECPAR_CHANNELS(frame); - enc->frame = av_frame_alloc(); - enc->frame->format = enc->fmt.req.format; - enc->frame->sample_rate = enc->fmt.req.sample_rate; - av_channel_layout_copy(&enc->frame->ch_layout, &enc->fmt.req.channel_layout); - av_samples_alloc(enc->frame->data, NULL, enc->frame->ch_layout.nb_channels, SAMPLES_PER_FRAME, enc->frame->format, 1); - enc->frame->nb_samples = SAMPLES_PER_FRAME; - enc->frame->pts = 0; + enc->frame = frame; return true; err: diff --git a/src/codec/ffmpeg/encoder.h b/src/codec/ffmpeg/encoder.h index 5f7d06f..3ace4d8 100644 --- a/src/codec/ffmpeg/encoder.h +++ b/src/codec/ffmpeg/encoder.h @@ -9,7 +9,7 @@ struct camu_ff_encoder { AVCodecContext *codec_context; const AVOutputFormat *output_format; - struct camu_resampler_format fmt; + struct camu_audio_format fmt; AVFrame *frame; void (*callback)(void *, AVPacket *); diff --git a/src/codec/ffmpeg/meson.build b/src/codec/ffmpeg/meson.build index eb68fad..56a75b2 100644 --- a/src/codec/ffmpeg/meson.build +++ b/src/codec/ffmpeg/meson.build @@ -3,6 +3,9 @@ ffmpeg_src = [ '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 = [ @@ -16,8 +19,7 @@ ffmpeg_client_src = [ ffmpeg_src, 'decoder.c', 'resampler.c', - 'scaler.c', - 'encoder.c' + 'scaler.c' ] ffmpeg_client_deps = [] @@ -38,7 +40,12 @@ libavcodec = dependency('libavcodec', 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()) - ffmpeg_proj = subproject('ffmpeg', required: false) + if get_option('win32-compat') + ffmpeg_proj = subproject('ffmpeg-compat', required: false) + ffmpeg_args += ['-DCAMU_OLD_FFMPEG'] + else + ffmpeg_proj = subproject('ffmpeg', required: false) + endif if ffmpeg_proj.found() libavutil = ffmpeg_proj.get_variable('avutil') libavformat = ffmpeg_proj.get_variable('avformat') @@ -48,9 +55,12 @@ if not (libavutil.found() and libavformat.found() and libavcodec.found() and lib 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 in the FFmpeg build. + # We explicitly enable zlib and maybe bzlib in the FFmpeg build. ffmpeg_deps += [dependency('zlib')] - if is_windows + if not get_option('sink-only') + ffmpeg_deps += [dependency('bzip2')] + 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 diff --git a/src/codec/ffmpeg/packet_ext.c b/src/codec/ffmpeg/packet_ext.c index acf5bbd..a1a6a5e 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 LIBAVCODEC_VERSION_INT >= 60 +#if !defined CAMU_OLD_FFMPEG && LIBAVCODEC_VERSION_INT >= 60 NNWT_PACKET_WRITE_TYPE(packet, AVRational, codecpar->framerate); #endif NNWT_PACKET_WRITE_TYPE(packet, enum AVFieldOrder, codecpar->field_order); @@ -26,6 +26,7 @@ void nn_packet_write_av_codec_parameters(struct nn_packet *packet, AVCodecParame NNWT_PACKET_WRITE_TYPE(packet, enum AVColorSpace, codecpar->color_space); NNWT_PACKET_WRITE_TYPE(packet, enum AVChromaLocation, codecpar->chroma_location); NNWT_PACKET_WRITE_TYPE(packet, s32, codecpar->video_delay); +#ifndef CAMU_OLD_FFMPEG // Incomplete. NNWT_PACKET_WRITE_TYPE(packet, enum AVChannelOrder, codecpar->ch_layout.order); if (codecpar->ch_layout.order == AV_CHANNEL_ORDER_NATIVE) { @@ -33,6 +34,10 @@ void nn_packet_write_av_codec_parameters(struct nn_packet *packet, AVCodecParame } else { NNWT_PACKET_WRITE_TYPE(packet, s32, codecpar->ch_layout.nb_channels); } +#else + NNWT_PACKET_WRITE_TYPE(packet, u64, codecpar->channel_layout); + NNWT_PACKET_WRITE_TYPE(packet, s32, codecpar->channels); +#endif NNWT_PACKET_WRITE_TYPE(packet, s32, codecpar->sample_rate); NNWT_PACKET_WRITE_TYPE(packet, s32, codecpar->block_align); NNWT_PACKET_WRITE_TYPE(packet, s32, codecpar->frame_size); @@ -98,7 +103,9 @@ void nn_packet_write_av_packet(struct nn_packet *packet, AVPacket *pkt) } NNWT_PACKET_WRITE_TYPE(packet, s64, pkt->duration); NNWT_PACKET_WRITE_TYPE(packet, s64, pkt->pos); +#ifndef CAMU_OLD_FFMPEG NNWT_PACKET_WRITE_TYPE(packet, AVRational, pkt->time_base); +#endif } void nn_packet_read_av_codec_parameters(struct nn_packet *packet, AVCodecParameters *codecpar) @@ -120,7 +127,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 LIBAVCODEC_VERSION_INT >= 60 +#if !defined CAMU_OLD_FFMPEG && LIBAVCODEC_VERSION_INT >= 60 NNWT_PACKET_READ_TYPE(packet, AVRational, codecpar->framerate); #endif NNWT_PACKET_READ_TYPE(packet, enum AVFieldOrder, codecpar->field_order); @@ -130,6 +137,7 @@ void nn_packet_read_av_codec_parameters(struct nn_packet *packet, AVCodecParamet NNWT_PACKET_READ_TYPE(packet, enum AVColorSpace, codecpar->color_space); NNWT_PACKET_READ_TYPE(packet, enum AVChromaLocation, codecpar->chroma_location); NNWT_PACKET_READ_TYPE(packet, s32, codecpar->video_delay); +#ifndef CAMU_OLD_FFMPEG enum AVChannelOrder order; NNWT_PACKET_READ_TYPE(packet, enum AVChannelOrder, order); if (order == AV_CHANNEL_ORDER_NATIVE) { @@ -141,6 +149,10 @@ void nn_packet_read_av_codec_parameters(struct nn_packet *packet, AVCodecParamet NNWT_PACKET_READ_TYPE(packet, s32, nb_channels); av_channel_layout_default(&codecpar->ch_layout, nb_channels); } +#else + NNWT_PACKET_READ_TYPE(packet, u64, codecpar->channel_layout); + NNWT_PACKET_READ_TYPE(packet, s32, codecpar->channels); +#endif NNWT_PACKET_READ_TYPE(packet, s32, codecpar->sample_rate); NNWT_PACKET_READ_TYPE(packet, s32, codecpar->block_align); NNWT_PACKET_READ_TYPE(packet, s32, codecpar->frame_size); @@ -214,5 +226,7 @@ void nn_packet_read_av_packet(struct nn_packet *packet, AVPacket *pkt) } NNWT_PACKET_READ_TYPE(packet, s64, pkt->duration); NNWT_PACKET_READ_TYPE(packet, s64, pkt->pos); +#ifndef CAMU_OLD_FFMPEG NNWT_PACKET_READ_TYPE(packet, AVRational, pkt->time_base); +#endif } diff --git a/src/codec/ffmpeg/packet_ext.h b/src/codec/ffmpeg/packet_ext.h index fab9b36..540cdcb 100644 --- a/src/codec/ffmpeg/packet_ext.h +++ b/src/codec/ffmpeg/packet_ext.h @@ -1,8 +1,7 @@ #pragma once #include <nnwt/packet.h> -#include <libavcodec/packet.h> -#include <libavcodec/codec_par.h> +#include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libavutil/dict.h> diff --git a/src/codec/ffmpeg/resampler.c b/src/codec/ffmpeg/resampler.c index eacc75b..48cca8e 100644 --- a/src/codec/ffmpeg/resampler.c +++ b/src/codec/ffmpeg/resampler.c @@ -12,26 +12,35 @@ static bool ff_resampler_init(struct camu_resampler *resamp, struct camu_resampl camu_audio_format_copy(&av->fmt, &fmt->req); - s32 ret = swr_alloc_set_opts2(&av->resample_context, - &fmt->req.channel_layout, fmt->req.format, fmt->req.sample_rate, - &fmt->in.channel_layout, fmt->in.format, fmt->in.sample_rate, 0, NULL); - if (ret != 0) { - log_error("Failed to configure resampler context."); - return false; - } + SwrContext *swr = swr_alloc(); + +#ifndef CAMU_OLD_FFMPEG + av_opt_set_chlayout(swr, "in_chlayout", &fmt->in.channel_layout, 0); + av_opt_set_chlayout(swr, "out_chlayout", &fmt->req.channel_layout, 0); +#else + av_opt_set_channel_layout(swr, "in_channel_layout", fmt->in.channel_layout, 0); + av_opt_set_channel_layout(swr, "out_channel_layout", fmt->req.channel_layout, 0); +#endif + av_opt_set_int(swr, "in_sample_rate", fmt->in.sample_rate, 0); + av_opt_set_int(swr, "out_sample_rate", fmt->req.sample_rate, 0); + av_opt_set_sample_fmt(swr, "in_sample_fmt", fmt->in.format, 0); + av_opt_set_sample_fmt(swr, "out_sample_fmt", fmt->req.format, 0); #ifdef CAMU_HAVE_SOXR // Slower but more accurate resampler. - av_opt_set_int(av->resample_context, "resampler", SWR_ENGINE_SOXR, 0); + av_opt_set_int(swr, "resampler", SWR_ENGINE_SOXR, 0); log_info("Using SoX resampler."); #endif - if (swr_init(av->resample_context) != 0) { - swr_free(&av->resample_context); - log_error("Failed to init resampler context."); + s32 ret = swr_init(swr); + if (ret != 0) { + swr_free(&swr); + log_error("Failed to init resampler context (%s).", av_err2str(ret)); return false; } + av->resample_context = swr; + return true; } @@ -44,7 +53,7 @@ static inline void alloc_sample_data(struct camu_ff_resampler *av, s32 sample_co { if (av->sample_count >= sample_count) return; free_sample_data(av); - s32 nb_channels = av->fmt.channel_layout.nb_channels; + s32 nb_channels = av->fmt.channel_count; av_samples_alloc(av->data, NULL, nb_channels, sample_count, av->fmt.format, 32); av->sample_count = sample_count; } diff --git a/src/fruits/cmc/meson.build b/src/fruits/cmc/meson.build index 864af8a..de6d335 100644 --- a/src/fruits/cmc/meson.build +++ b/src/fruits/cmc/meson.build @@ -19,7 +19,7 @@ if use_tui cmc_deps += [notcurses, notcurses_core, codecs_client] endif -if is_windows and meson.is_cross_build() +if is_windows and not is_msvc cmc_args += ['-static', '-static-libgcc', '-static-libstdc++', '-municode', '-mwindows'] endif diff --git a/src/fruits/cmc/ui/util/waveform.c b/src/fruits/cmc/ui/util/waveform.c index 535f219..b114a5e 100644 --- a/src/fruits/cmc/ui/util/waveform.c +++ b/src/fruits/cmc/ui/util/waveform.c @@ -5,7 +5,7 @@ #define WITHIN_RMS(low, high, rms) \ ((low >= 0 && low <= rms) || (high < 0 && high >= -rms) || (low < 0 && high > 0 && rms > 0)) -#define OUTPUT_WAVEFORM_PNG +//#define OUTPUT_WAVEFORM_PNG //#define WAVEFORM_REFERENCE_MODE #ifdef OUTPUT_WAVEFORM_PNG #include <nnwt/file.h> diff --git a/src/fruits/cmsrv/meson.build b/src/fruits/cmsrv/meson.build index dce3d94..b12d00d 100644 --- a/src/fruits/cmsrv/meson.build +++ b/src/fruits/cmsrv/meson.build @@ -8,7 +8,7 @@ if use_tui cmsrv_deps += [notcurses_core] endif -if is_windows and meson.is_cross_build() +if is_windows and not is_msvc cmsrv_args += ['-static', '-static-libgcc', '-static-libstdc++', '-municode', '-mwindows'] endif diff --git a/src/fruits/cmv/cmv.c b/src/fruits/cmv/cmv.c index 70a0b28..28dcbb5 100644 --- a/src/fruits/cmv/cmv.c +++ b/src/fruits/cmv/cmv.c @@ -3,14 +3,16 @@ #include <nnwt/event_loop.h> #include <nnwt/thread.h> -#include "../../util/color_palette.h" -#include "../../codec/ffmpeg/common.h" #include "../../libsink/desktop.h" #include "../../server/common.h" #ifndef CAMU_SINK_ONLY #include "../../server/server.h" #endif #include "../../server/common.h" +#include "../../util/color_palette.h" +#ifdef CAMU_HAVE_FFMPEG +#include "../../codec/ffmpeg/common.h" +#endif #include "../common.h" @@ -95,7 +97,11 @@ static bool parse_exe_name_params(str *exe_name, str *addr, struct lia_prefs *pr return true; def: +#ifdef CAMU_HAVE_SUBTITLES prefs->enabled_mask = CAMU_MASK_AUDIO | CAMU_MASK_VIDEO | CAMU_MASK_SUBTITLE; +#else + prefs->enabled_mask = CAMU_MASK_AUDIO | CAMU_MASK_VIDEO; +#endif prefs->audio_lang = CAMU_LANG_JAPANESE; prefs->subtitle_lang = CAMU_LANG_ENGLISH; @@ -175,8 +181,10 @@ s32 window_system_main(u32 argc, str *argv, void *extra) c.desktop.exit_callback = exit_callback; c.desktop.userdata = &c; } -#endif str *name = local ? &al_str_c("local") : &al_str_c("desktop"); +#else + str *name = &al_str_c("desktop"); +#endif if (!camu_desktop_connect(&c.desktop, name, &c.loop, type, &addr, CAMU_PORT)) { return EXIT_FAILURE; } diff --git a/src/fruits/cmv/meson.build b/src/fruits/cmv/meson.build index 870345e..bfd2182 100644 --- a/src/fruits/cmv/meson.build +++ b/src/fruits/cmv/meson.build @@ -14,7 +14,7 @@ if use_tui endif cmv_link_args = [] -if is_windows and meson.is_cross_build() +if is_windows and not is_msvc cmv_link_args += ['-static', '-static-libgcc', '-static-libstdc++', '-municode', '-mwindows'] endif diff --git a/src/fruits/droid/ctv/gradle/libs.versions.toml b/src/fruits/droid/ctv/gradle/libs.versions.toml index 4a8d0bc..95dfb43 100644 --- a/src/fruits/droid/ctv/gradle/libs.versions.toml +++ b/src/fruits/droid/ctv/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -agp = "8.9.1" +agp = "8.10.0" [libraries] diff --git a/src/liana/client.c b/src/liana/client.c index 164a4d1..626a752 100644 --- a/src/liana/client.c +++ b/src/liana/client.c @@ -27,7 +27,12 @@ static void data_packet_callback(void *userdata, struct nn_packet_stream *stream static s32 stream_compare(const void *a, const void *b) { - return (s32)((struct camu_codec_stream *)a)->type - (s32)((struct camu_codec_stream *)b)->type; + struct camu_codec_stream *aa = (struct camu_codec_stream *)a; + struct camu_codec_stream *bb = (struct camu_codec_stream *)b; + if (aa->type == bb->type) { + return aa->index - bb->index; + } + return aa->type - bb->type; } static void collect_streams(struct lia_client *client, struct nn_packet *packet) @@ -49,7 +54,7 @@ static void collect_streams(struct lia_client *client, struct nn_packet *packet) fmt->sample_rate = nn_packet_read_s32(packet); fmt->channel_count = nn_packet_read_s32(packet); #ifdef CAMU_HAVE_FFMPEG - av_channel_layout_default(&fmt->channel_layout, fmt->channel_count); + camu_default_channel_layout(&fmt->channel_layout, fmt->channel_count); #endif } else if (type == CAMU_STREAM_VIDEO) { struct camu_video_format *fmt = &stream.video.fmt; @@ -80,8 +85,8 @@ static void collect_streams(struct lia_client *client, struct nn_packet *packet) struct camu_audio_format *fmt = &stream.audio.fmt; fmt->format = codecpar->format; fmt->sample_rate = codecpar->sample_rate; - av_channel_layout_copy(&fmt->channel_layout, &codecpar->ch_layout); - fmt->channel_count = codecpar->ch_layout.nb_channels; + camu_copy_channel_layout(&fmt->channel_layout, &AV_CODECPAR_CHANNEL_LAYOUT(codecpar)); + fmt->channel_count = AV_CODECPAR_CHANNELS(codecpar); break; } case CAMU_STREAM_VIDEO: { diff --git a/src/liana/handlers/codec_client.c b/src/liana/handlers/codec_client.c index fd2569b..38b5d3b 100644 --- a/src/liana/handlers/codec_client.c +++ b/src/liana/handlers/codec_client.c @@ -132,9 +132,9 @@ static bool codec_client_handle_packet(struct lia_client_handler *handler, struc #endif break; } +#endif default: al_assert_and_return(false); -#endif } // Restore packet rindex in case we resue it. diff --git a/src/liana/handlers/codec_server.c b/src/liana/handlers/codec_server.c index de2c927..3b7d31e 100644 --- a/src/liana/handlers/codec_server.c +++ b/src/liana/handlers/codec_server.c @@ -149,7 +149,7 @@ static void codec_server_write_packet(struct lia_server_handler *handler, struct nn_packet_write_u8(packet, LIANA_PACKET_EOF); #ifdef LIANA_SERVER_LOOP codec->pts_offset += codec->demux->get_duration(codec->demux); - codec->demux->seek(codec->demux, 0); + codec->demux->seek(codec->demux, 0, false); #endif } else { nn_packet_write_u8(packet, LIANA_PACKET_ERROR); diff --git a/src/liana/process.c b/src/liana/process.c index 0a6d6b6..a8b57d0 100644 --- a/src/liana/process.c +++ b/src/liana/process.c @@ -65,10 +65,10 @@ bool lia_prepare_visual_data(struct cch_handle *handle, struct lia_visual_data * fmt.req.format = CAMU_SAMPLE_FORMAT_S16; fmt.in.sample_rate = codecpar->sample_rate; fmt.req.sample_rate = codecpar->sample_rate; - av_channel_layout_copy(&fmt.in.channel_layout, &codecpar->ch_layout); - av_channel_layout_copy(&fmt.req.channel_layout, &codecpar->ch_layout); - fmt.in.channel_count = codecpar->ch_layout.nb_channels; - fmt.req.channel_count = codecpar->ch_layout.nb_channels; + camu_copy_channel_layout(&fmt.in.channel_layout, &AV_CODECPAR_CHANNEL_LAYOUT(codecpar)); + camu_copy_channel_layout(&fmt.req.channel_layout, &AV_CODECPAR_CHANNEL_LAYOUT(codecpar)); + fmt.in.channel_count = AV_CODECPAR_CHANNELS(codecpar); + fmt.req.channel_count = AV_CODECPAR_CHANNELS(codecpar); struct raw_samples_data raw; raw.resampler = resampler; diff --git a/src/liana/vcr.c b/src/liana/vcr.c index 4500681..78c2b9c 100644 --- a/src/liana/vcr.c +++ b/src/liana/vcr.c @@ -126,9 +126,11 @@ static nn_thread_result NNWT_THREADCALL vcr_track_thread(void *userdata) continue; } - index++; // Count of packets consumed. + index++; // Count of packets consumed, also increment for WHOLE_FILE mode. +#ifndef VCR_BUFFER_WHOLE_FILE nn_packet_stream_return_packets(vcr->data, al_array_offset(track->cache.cache, 0), index); al_array_remove_range(track->cache.cache, 0, index); +#endif nn_packet_cache_unlock(&track->cache); @@ -153,7 +155,9 @@ static nn_thread_result NNWT_THREADCALL vcr_track_thread(void *userdata) if (corked) { // The cache is already unlocked here. +#ifndef VCR_BUFFER_WHOLE_FILE index = 0; +#endif } else { #ifndef VCR_BUFFER_WHOLE_FILE al_assert(index == packets); diff --git a/src/libsink/desktop.c b/src/libsink/desktop.c index 2bbe906..a2d02c9 100644 --- a/src/libsink/desktop.c +++ b/src/libsink/desktop.c @@ -8,8 +8,8 @@ #else #include "../mixer/audio_miniaudio.h" #endif -#if defined CAMU_RENDERER_TIGER -#include "../render/renderer_tiger.h" +#if defined CAMU_RENDERER_MOMO +#include "../render/renderer_momo.h" #elif defined CAMU_RENDERER_LIBPLACEBO #include "../render/renderer_libplacebo.h" #endif @@ -111,8 +111,9 @@ static u8 sink_callback(void *userdata, u8 op, u8 type, void *opaque) } static char status[64]; -static void log_playback_pos(struct camu_sink *sink) +static void log_sink_status(struct camu_desktop *c) { + struct camu_sink *sink = &c->sink; struct camu_sink_entry *current = camu_sink_get_current(sink); if (!current) { camu_sink_return_current(sink); @@ -140,10 +141,10 @@ static void log_playback_pos(struct camu_sink *sink) offset += al_snprintf(status + offset, sizeof(status) - offset, "]"); status[offset] = '\0'; - log_info("%s", status); + log_info("%s, window size: %ux%u", status, c->scr.width, c->scr.height); return; notplaying: - log_info("Not playing."); + log_info("Not playing, window size: %ux%u", c->scr.width, c->scr.height); } static void screen_callback(void *userdata, u8 op, void *opaque) @@ -175,7 +176,7 @@ static void screen_callback(void *userdata, u8 op, void *opaque) camu_sink_shuffle(&c->sink); break; case CAMU_SCREEN_STATUS: - log_playback_pos(&c->sink); + log_sink_status(c); break; #ifdef CAMU_SCREEN_DEBUG_KEY case CAMU_SCREEN_DEBUG: @@ -199,8 +200,8 @@ bool camu_desktop_open(struct camu_desktop *c, const char *window_name) if (!camu_screen_init(&c->scr) || !camu_screen_create_window(&c->scr, window_name)) { return false; } -#if defined CAMU_RENDERER_TIGER - c->renderer = camu_renderer_tiger_create(); +#if defined CAMU_RENDERER_MOMO + c->renderer = camu_renderer_momo_create(); #elif defined CAMU_RENDERER_LIBPLACEBO c->renderer = camu_renderer_lp_create(); #endif diff --git a/src/libsink/sink.c b/src/libsink/sink.c index 07bb604..56be556 100644 --- a/src/libsink/sink.c +++ b/src/libsink/sink.c @@ -468,18 +468,17 @@ static void mixer_callback(void *userdata, u8 op) struct camu_sink *sink = (struct camu_sink *)userdata; if (op == CAMU_MIXER_EMPTY) { log_info("Mixer empty."); -#ifndef LIANA_LIST_SCUFFED_LOOP // We need to sync with do_add_entry() because the order of // the START/STOP's in the queue matters. nn_mutex_lock(&sink->lock); - queue_cmd(sink, (struct camu_sink_cmd){ - .op = STOP, - .value.i = CAMU_SINK_AUDIO - }); + // This feels a bit too loose. + if (!(sink->current && AUDIO_STATE(sink->current) == BUFFER_ADDED)) { + queue_cmd(sink, (struct camu_sink_cmd){ + .op = STOP, + .value.i = CAMU_SINK_AUDIO + }); + } nn_mutex_unlock(&sink->lock); -#else - (void)sink; -#endif } } @@ -1526,11 +1525,15 @@ static struct nn_rpc_command commands[] = { { .op = CAMU_SINK_SEEK, .callback = seek_command_callback, .userdata = NULL } }; +// @TODO: Send sink id from list. static void identify_callback(void *userdata, struct nn_rpc_connection *conn, struct nn_packet *packet) { struct camu_sink *sink = (struct camu_sink *)userdata; - (void)sink; - // @TODO: Send sink id from list. + if (sink->type == NNWT_SOCKET_UNIX) { + log_info("Sink connected to %.*s.", al_str_x(&sink->addr)); + } else { + log_info("Sink connected to %.*s:%hu.", al_str_x(&sink->addr), sink->port); + } nn_packet_stream_return_packet(conn->stream, packet); } diff --git a/src/mixer/audio_miniaudio.c b/src/mixer/audio_miniaudio.c index 7e31abf..a0db3f3 100644 --- a/src/mixer/audio_miniaudio.c +++ b/src/mixer/audio_miniaudio.c @@ -27,6 +27,9 @@ static ma_backend backends[] = { #ifdef MA_ENABLE_WASAPI ma_backend_wasapi, #endif +#ifdef MA_ENABLE_DSOUND + ma_backend_dsound, +#endif #ifdef MA_ENABLE_AAUDIO ma_backend_aaudio, #endif @@ -142,7 +145,7 @@ static void audio_miniaudio_pick_format(struct camu_audio *audio, struct camu_re fmt->req.sample_rate = ma->device.playback.internalSampleRate; u32 channels = ma->device.playback.channels; #ifdef CAMU_HAVE_FFMPEG - av_channel_layout_default(&fmt->req.channel_layout, channels); + camu_default_channel_layout(&fmt->req.channel_layout, channels); #endif fmt->req.channel_count = channels; } @@ -162,7 +165,7 @@ static void data_callback(ma_device *device, void *output, const void *input, u3 #define DEFAULT_PERIOD_SIZE_IN_MILLISECONDS 8 #else #define DEFAULT_PERIODS 3 -#define DEFAULT_PERIOD_SIZE_IN_MILLISECONDS 48 +#define DEFAULT_PERIOD_SIZE_IN_MILLISECONDS 64 #endif static bool audio_miniaudio_configure_stream(struct camu_audio *audio, void *opaque) diff --git a/src/mixer/audio_null.c b/src/mixer/audio_null.c index a6eeea3..2fa5ddb 100644 --- a/src/mixer/audio_null.c +++ b/src/mixer/audio_null.c @@ -15,7 +15,7 @@ static void audio_null_pick_format(struct camu_audio *audio, struct camu_resampl fmt->req.format = fmt->in.format; fmt->req.channel_count = fmt->in.channel_count; #ifdef CAMU_HAVE_FFMPEG - av_channel_layout_default(&fmt->req.channel_layout, fmt->in.channel_count); + camu_default_channel_layout(&fmt->req.channel_layout, fmt->in.channel_count); #endif fmt->req.sample_rate = fmt->in.sample_rate; } diff --git a/src/mixer/meson.build b/src/mixer/meson.build index c09f779..e4840c1 100644 --- a/src/mixer/meson.build +++ b/src/mixer/meson.build @@ -22,7 +22,11 @@ if use_miniaudio mixer_deps += [libpulse, alsa] mixer_args += ['-DMA_ENABLE_ALSA', '-DMA_ENABLE_PULSEAUDIO', '-DMA_NO_RUNTIME_LINKING'] elif is_windows - mixer_args += ['-DMA_ENABLE_WASAPI'] + if get_option('win32-compat') + mixer_args += ['-DMA_ENABLE_DSOUND'] + else + mixer_args += ['-DMA_ENABLE_WASAPI'] + endif elif is_android mixer_args += ['-DMA_ENABLE_AAUDIO'] endif diff --git a/src/render/meson.build b/src/render/meson.build index 98b86ec..7e3e394 100644 --- a/src/render/meson.build +++ b/src/render/meson.build @@ -2,23 +2,20 @@ render_src = [] render_deps = [] render_args = [] -if get_option('renderer') == 'tiger' - render_src += ['renderer_tiger.c', 'queue_tiger.c'] - linmath_h = subproject('linmath.h').get_variable('linmath_h') - render_deps += [linmath_h] - libm = compiler.find_library('m', required: false) - if libm.found() - render_deps += [libm] - endif - render_args += ['-DCAMU_RENDERER_TIGER'] +if get_option('renderer') == 'momo' + render_src += ['renderer_momo.c', 'queue_momo.c'] + subdir('momo') + render_deps += [momo] + render_args += ['-DCAMU_RENDERER_MOMO'] elif get_option('renderer') == 'libplacebo' libplacebo_opts = ['warning_level=2', 'demos=false', 'tests=false', 'bench=false', 'fuzz=false', 'glslang=disabled', 'gl-proc-addr=disabled', 'vk-proc-addr=disabled', - 'lcms=disabled', - 'dovi=disabled', - 'libdovi=disabled' + 'lcms=auto', + 'dovi=auto', + 'libdovi=auto', + 'xxhash=auto' ] if get_option('renderer-api') == 'vulkan' or get_option('renderer-api') == 'dx11' @@ -27,12 +24,19 @@ elif get_option('renderer') == 'libplacebo' render_deps += [shaderc] else shaderc_opts = cmake.subproject_options() + shaderc_opts.set_override_option('warning_level', '0') # Doesn't work. reltype = is_minsize ? 'MinSizeRel' : 'Release' shaderc_opts.add_cmake_defines({ 'CMAKE_BUILD_TYPE': is_debug ? 'Debug' : reltype }) shaderc_opts.add_cmake_defines({ 'SHADERC_SKIP_INSTALL': true }) shaderc_opts.add_cmake_defines({ 'SHADERC_SKIP_TESTS': true }) shaderc_opts.add_cmake_defines({ 'SHADERC_SKIP_EXAMPLES': true }) shaderc_opts.add_cmake_defines({ 'SHADERC_SKIP_COPYRIGHT_CHECK': true }) + shaderc_opts.add_cmake_defines({ 'ENABLE_GLSLANG_BINARIES': false }) + shaderc_opts.add_cmake_defines({ 'ENABLE_SPVREMAPPER': false }) + shaderc_opts.add_cmake_defines({ 'ENABLE_HLSL': false }) + spirv_optimizer = true + shaderc_opts.add_cmake_defines({ 'ENABLE_OPT': spirv_optimizer }) + shaderc_opts.add_cmake_defines({ 'ENABLE_EXCEPTIONS_ON_MSVC': false }) shaderc_proj = cmake.subproject('shaderc', options: shaderc_opts) shaderc = shaderc_proj.dependency('shaderc') meson.override_dependency('shaderc', shaderc) @@ -43,20 +47,31 @@ elif get_option('renderer') == 'libplacebo' shaderc_proj.dependency('OSDependent'), shaderc_proj.dependency('GenericCodeGen'), shaderc_proj.dependency('SPIRV'), - shaderc_proj.dependency('SPIRV-Tools-opt'), shaderc_proj.dependency('SPIRV-Tools-static') ] + if spirv_optimizer + render_deps += [ + shaderc_proj.dependency('SPIRV-Tools-opt'), + ] + endif endif #glslang = dependency('glslang', required: false, allow_fallback: false) #if glslang.found() # render_deps += [glslang] #else + # #spirv_tools_opts = cmake.subproject_options() + # #spirv_tools_opts.set_override_option('warning_level', '0') + # #reltype = is_minsize ? 'MinSizeRel' : 'Release' + # #spirv_tools_opts.add_cmake_defines({ 'CMAKE_BUILD_TYPE': is_debug ? 'Debug' : reltype }) + # #spirv_tools_proj = cmake.subproject('SPIRV-Tools', options: spirv_tools_opts) # glslang_opts = cmake.subproject_options() + # glslang_opts.set_override_option('warning_level', '0') # reltype = is_minsize ? 'MinSizeRel' : 'Release' # glslang_opts.add_cmake_defines({ 'CMAKE_BUILD_TYPE': is_debug ? 'Debug' : reltype }) + # #glslang_opts.add_cmake_defines({ 'ALLOW_EXTERNAL_SPIRV_TOOLS': true }) # glslang_opts.add_cmake_defines({ 'ENABLE_OPT': '0' }) # glslang_proj = cmake.subproject('glslang', options: glslang_opts) - # message('CMake targets:\n - ' + '\n - '.join(glslang_proj.target_list())) + # #message('CMake targets:\n - ' + '\n - '.join(glslang_proj.target_list())) # glslang = glslang_proj.dependency('glslang') # spirv = glslang_proj.dependency('SPIRV') # glslang_default_resource_limits = glslang_proj.dependency('glslang-default-resource-limits') @@ -118,22 +133,27 @@ if get_option('subtitles').enabled() default_options: [ 'doc=disabled', 'nls=disabled', - 'tests=disabled', 'tools=disabled', 'cache-build=disabled' ]) + else + libass_opts += ['directwrite=enabled'] endif # libass(e46aede):meson.build:84 # fontconfig(72b9a48):meson.build:28 freetype = dependency('freetype2', version: '>=9.17.3', default_options: [ - 'harfbuzz=disabled' + 'warning_level=0', + 'harfbuzz=disabled', + 'png=disabled' ]) # libass(e46aede):meson.build:90 fribidi = dependency('fribidi', version: '>=0.19.1', default_options: [ + 'warning_level=0', + 'c_args=-Wno-stringop-overflow', # This doesn't work. 'docs=false', 'tests=false', 'bin=false' @@ -143,7 +163,6 @@ if get_option('subtitles').enabled() version: '>=2.0.0', default_options: [ 'freetype=disabled', - 'tests=disabled', 'introspection=disabled', 'docs=disabled', 'utilities=disabled', diff --git a/src/render/momo/meson.build b/src/render/momo/meson.build new file mode 100644 index 0000000..092293a --- /dev/null +++ b/src/render/momo/meson.build @@ -0,0 +1,12 @@ +momo_src = ['momo.c'] +momo_deps = [] +momo_args = [] + +libm = compiler.find_library('m', required: false) +if libm.found() + momo_deps += [libm] +endif +linmath_h = subproject('linmath.h').get_variable('linmath_h') +momo_deps += [linmath_h] + +momo = declare_dependency(sources: momo_src, dependencies: momo_deps, compile_args: momo_args) diff --git a/src/render/momo/momo.c b/src/render/momo/momo.c new file mode 100644 index 0000000..5239efd --- /dev/null +++ b/src/render/momo/momo.c @@ -0,0 +1,35 @@ +#define AL_LOG_SECTION "momo" +#include <al/log.h> + +#include "momo.h" + +bool MOMO_Init(MOMO_Renderer *mmr, +#ifdef STELA_API_OPENGL + bool (*MakeCurrent)(void *), + void (*ReleaseCurrent)(void *), + void (*SwapBuffers)(void *), +#endif + void *Private) +{ + mmr->Private = Private; +#ifdef STELA_API_OPENGL + mmr->GL.MakeCurrent = MakeCurrent; + mmr->GL.ReleaseCurrent = ReleaseCurrent; + mmr->GL.SwapBuffers = SwapBuffers; + mmr->GL.MakeCurrent(mmr->Private); + const char *gl_version = (const char *)glGetString(GL_VERSION); + if (gl_version) { + log_info("GL context version: %s.", gl_version); + } else { + log_warn("Somehow failed to retrive GL_VERSION."); + } +#endif + return true; +} + +void MOMO_Render(MOMO_Renderer *mmr) +{ +#ifdef STELA_API_OPENGL + mmr->GL.SwapBuffers(mmr->Private); +#endif +} diff --git a/src/render/momo/momo.h b/src/render/momo/momo.h new file mode 100644 index 0000000..76686ba --- /dev/null +++ b/src/render/momo/momo.h @@ -0,0 +1,25 @@ +#pragma once + +#include <al/types.h> + +#ifdef STELA_API_OPENGL +#include <stl/gl.h> +#endif + +typedef struct { + struct { + bool (*MakeCurrent)(void *); + void (*ReleaseCurrent)(void *); + void (*SwapBuffers)(void *); + } GL; + void *Private; +} MOMO_Renderer; + +bool MOMO_Init(MOMO_Renderer *mmr, +#ifdef STELA_API_OPENGL + bool (*MakeCurrent)(void *), + void (*ReleaseCurrent)(void *), + void (*SwapBuffers)(void *), +#endif + void *Private); +void MOMO_Render(MOMO_Renderer *mmr); diff --git a/src/render/queue_libplacebo.c b/src/render/queue_libplacebo.c index 7fe9258..5932944 100644 --- a/src/render/queue_libplacebo.c +++ b/src/render/queue_libplacebo.c @@ -30,6 +30,7 @@ static bool queue_lp_configure_subtitles(struct camu_frame_queue *queue, u32 wid ass_set_frame_size(lq->ass_renderer, width, height); ass_set_storage_size(lq->ass_renderer, width, height); ass_set_fonts(lq->ass_renderer, NULL, NULL, ASS_FONTPROVIDER_AUTODETECT, NULL, 0); + ass_set_hinting(lq->ass_renderer, ASS_HINTING_NONE); AVCodecParameters *codecpar = stream->av.stream->codecpar; ass_process_codec_private(lq->ass_track, (const char *)codecpar->extradata, codecpar->extradata_size); diff --git a/src/render/queue_momo.c b/src/render/queue_momo.c new file mode 100644 index 0000000..8e8d7e3 --- /dev/null +++ b/src/render/queue_momo.c @@ -0,0 +1,68 @@ +#include "queue_momo.h" + +static void queue_momo_push(struct camu_frame_queue *queue, struct camu_codec_frame *frame, f64 pts) +{ + struct camu_frame_queue_momo *mq = (struct camu_frame_queue_momo *)queue; + (void)mq; + (void)pts; + camu_codec_frame_discard(frame); +} + +#ifdef CAMU_HAVE_FFMPEG +static void queue_momo_push_av_frame(struct camu_frame_queue *queue, AVFrame *frame, f64 pts) +{ + struct camu_frame_queue_momo *mq = (struct camu_frame_queue_momo *)queue; + (void)mq; + (void)pts; + av_frame_free(&frame); +} +#endif + +static void queue_momo_flush(struct camu_frame_queue *queue) +{ + (void)queue; +} + +static s32 queue_momo_count(struct camu_frame_queue *queue) +{ + struct camu_frame_queue_momo *mq = (struct camu_frame_queue_momo *)queue; + (void)mq; + return 1; +} + +static u8 queue_momo_read(struct camu_frame_queue *queue, f64 pts, void *out) +{ + struct camu_frame_queue_momo *mq = (struct camu_frame_queue_momo *)queue; + (void)mq; + (void)pts; + (void)out; + return CAMU_QUEUE_OK; +} + +static void queue_momo_reset(struct camu_frame_queue *queue) +{ + struct camu_frame_queue_momo *tq = (struct camu_frame_queue_momo *)queue; + (void)tq; +} + +static void queue_momo_free(struct camu_frame_queue **queue) +{ + struct camu_frame_queue_momo *mq = (struct camu_frame_queue_momo *)*queue; + al_free(mq); + *queue = NULL; +} + +struct camu_frame_queue *camu_frame_queue_momo_create(void) +{ + struct camu_frame_queue_momo *mq = al_alloc_object(struct camu_frame_queue_momo); + mq->q.push = queue_momo_push; +#ifdef CAMU_HAVE_FFMPEG + mq->q.push_av_frame = queue_momo_push_av_frame; +#endif + mq->q.flush = queue_momo_flush; + mq->q.count = queue_momo_count; + mq->q.read = queue_momo_read; + mq->q.reset = queue_momo_reset; + mq->q.free = queue_momo_free; + return (struct camu_frame_queue *)mq; +} diff --git a/src/render/queue_momo.h b/src/render/queue_momo.h new file mode 100644 index 0000000..c4bf5d1 --- /dev/null +++ b/src/render/queue_momo.h @@ -0,0 +1,9 @@ +#pragma once + +#include "../buffer/frame_queue.h" + +struct camu_frame_queue_momo { + struct camu_frame_queue q; +}; + +struct camu_frame_queue *camu_frame_queue_momo_create(void); diff --git a/src/render/queue_tiger.c b/src/render/queue_tiger.c deleted file mode 100644 index df072d2..0000000 --- a/src/render/queue_tiger.c +++ /dev/null @@ -1,130 +0,0 @@ -#include <al/lib.h> -#include <stl/gl.h> - -#include "queue_tiger.h" - -#define GL_UNPACK_ROW_LENGTH 0x0CF2 - -static void upload_texture(struct camu_frame_queue_tiger *tq, u8 *data, u32 width, u32 height, s32 format, s32 linesize) -{ - glGenTextures(1, &tq->texture_id); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, tq->texture_id); - //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); - //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - //if (frame->flags & CAMU_FRAME_DEVICE_ALLOCATED) { - // glBindBuffer(GL_PIXEL_UNPACK_BUFFER, tq->tr->texture_buffer); - //} - glPixelStorei(GL_UNPACK_ROW_LENGTH, linesize); - glPixelStorei(GL_UNPACK_ALIGNMENT, 0); - switch (format) { - case CAMU_PIXEL_FORMAT_RGBA: - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, - 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - break; - case CAMU_PIXEL_FORMAT_RGB: - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, - 0, GL_RGB, GL_UNSIGNED_BYTE, data); - break; - default: - al_assert(false); - } - //glGenerateMipmap(GL_TEXTURE_2D); -} - -static void queue_tiger_push(struct camu_frame_queue *queue, struct camu_codec_frame *frame, f64 pts) -{ - struct camu_frame_queue_tiger *tq = (struct camu_frame_queue_tiger *)queue; - (void)pts; - tq->queued_frame = frame; -} - -#ifdef CAMU_HAVE_FFMPEG -static void queue_tiger_push_av_frame(struct camu_frame_queue *queue, AVFrame *frame, f64 pts) -{ - struct camu_frame_queue_tiger *tq = (struct camu_frame_queue_tiger *)queue; - (void)pts; - tq->queued_av_frame = frame; -} -#endif - -static void queue_tiger_flush(struct camu_frame_queue *queue) -{ - (void)queue; -} - -static s32 queue_tiger_count(struct camu_frame_queue *queue) -{ - struct camu_frame_queue_tiger *tq = (struct camu_frame_queue_tiger *)queue; - (void)tq; - return 1; -} - -static u8 queue_tiger_read(struct camu_frame_queue *queue, f64 pts, void *out) -{ - struct camu_frame_queue_tiger *tq = (struct camu_frame_queue_tiger *)queue; - (void)pts; - if (tq->queued_frame) { - struct camu_codec_frame *frame = tq->queued_frame; - s32 linesize = frame->video.width; - upload_texture(tq, frame->data, frame->video.width, frame->video.height, frame->format, linesize); - camu_codec_frame_discard(frame); - tq->queued_frame = NULL; - tq->uploaded = true; - } -#ifdef CAMU_HAVE_FFMPEG - if (tq->queued_av_frame) { - AVFrame *frame = tq->queued_av_frame; - s32 linesize = frame->linesize[0]; - switch (frame->format) { - case CAMU_PIXEL_FORMAT_RGBA: - linesize /= 4; - break; - case CAMU_PIXEL_FORMAT_RGB: - linesize /= 3; - break; - } - upload_texture(tq, frame->data[0], frame->width, frame->height, frame->format, linesize); - av_frame_free(&frame); - tq->queued_av_frame = NULL; - tq->uploaded = true; - } -#endif - if (!tq->uploaded) return CAMU_QUEUE_MORE; - *((GLuint *)out) = tq->texture_id; - return CAMU_QUEUE_OK; -} - -static void queue_tiger_reset(struct camu_frame_queue *queue) -{ - struct camu_frame_queue_tiger *tq = (struct camu_frame_queue_tiger *)queue; - (void)tq; -} - -static void queue_tiger_free(struct camu_frame_queue **queue) -{ - struct camu_frame_queue_tiger *tq = (struct camu_frame_queue_tiger *)*queue; - glDeleteTextures(1, &tq->texture_id); - al_free(tq); - *queue = NULL; -} - -struct camu_frame_queue *camu_frame_queue_tiger_create(void) -{ - struct camu_frame_queue_tiger *tq = al_alloc_object(struct camu_frame_queue_tiger); - tq->queued_frame = NULL; - tq->queued_av_frame = NULL; - tq->uploaded = false; - tq->q.push = queue_tiger_push; -#ifdef CAMU_HAVE_FFMPEG - tq->q.push_av_frame = queue_tiger_push_av_frame; -#endif - tq->q.flush = queue_tiger_flush; - tq->q.count = queue_tiger_count; - tq->q.read = queue_tiger_read; - tq->q.reset = queue_tiger_reset; - tq->q.free = queue_tiger_free; - return (struct camu_frame_queue *)tq; -} diff --git a/src/render/queue_tiger.h b/src/render/queue_tiger.h deleted file mode 100644 index af0e229..0000000 --- a/src/render/queue_tiger.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include <stl/gl.h> - -#include "../buffer/frame_queue.h" - -struct camu_frame_queue_tiger { - struct camu_frame_queue q; - GLuint texture_id; - struct camu_renderer_tiger *tr; - struct camu_codec_frame *queued_frame; -#ifdef CAMU_HAVE_FFMPEG - struct AVFrame *queued_av_frame; -#endif - bool uploaded; -}; - -struct camu_frame_queue *camu_frame_queue_tiger_create(void); diff --git a/src/render/renderer.h b/src/render/renderer.h index 1e6ffc0..d2590b1 100644 --- a/src/render/renderer.h +++ b/src/render/renderer.h @@ -7,14 +7,9 @@ #endif #if defined STELA_API_OPENGL -#define CAMU_RENDERER_OPENGL #ifdef STELA_USE_EGL #include <stl/egl.h> #endif -#elif defined STELA_API_VULKAN -#define CAMU_RENDERER_VULKAN -#elif defined STELA_API_DX11 -#define CAMU_RENDERER_DX11 #endif #include "../codec/codec.h" @@ -24,28 +19,32 @@ enum { CAMU_SCALING_NEAREST }; +enum { + CAMU_BACKGROUND_DEFAULT = 0, + CAMU_BACKGROUND_TRANSPARENT +}; + struct camu_frame_queue; struct camu_screen; struct camu_renderer { bool (*create_renderer)( struct camu_renderer *, u32 *, u32 *, -#if defined CAMU_RENDERER_VULKAN +#if defined STELA_API_VULKAN VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL (*get_vk_proc_address)(VkInstance, const char *), VkResult (*vk_create_surface)(void *, VkInstance, VkSurfaceKHR *), const char *const *(*vk_get_extensions)(u32 *), -#elif defined CAMU_RENDERER_DX11 +#elif defined STELA_API_DX11 HWND win32_window, -#elif defined CAMU_RENDERER_OPENGL +#elif defined STELA_API_OPENGL #ifdef STELA_USE_EGL EGLDisplay display, EGLContext context, #endif - void (*get_gl_proc_address(char const *procname))(void), + void (*get_gl_proc_address(char const *))(void), bool (*gl_load_loader)(void *), bool (*gl_make_current)(void *), void (*gl_release_current)(void *), void (*gl_swap_buffers)(void *), -#elif defined CAMU_RENDERER_DX11 #endif void *priv); struct camu_frame_queue *(*create_queue)(struct camu_renderer *); @@ -54,6 +53,7 @@ struct camu_renderer { void (*resize)(struct camu_renderer *, u32 *, u32 *); void (*set_fullscreen)(struct camu_renderer *, bool); void (*set_scaling)(struct camu_renderer *, u8); + void (*set_background)(struct camu_renderer *, u8); void (*render)(struct camu_renderer *, struct camu_screen *, bool); #ifdef CAMU_HAVE_FFMPEG s32 (*get_buffer2)(struct AVCodecContext *s, AVFrame *frame, s32 flags); diff --git a/src/render/renderer_libplacebo.c b/src/render/renderer_libplacebo.c index a2105d6..bfe8c47 100644 --- a/src/render/renderer_libplacebo.c +++ b/src/render/renderer_libplacebo.c @@ -9,7 +9,7 @@ #include "../screen/screen.h" #include "../util/color_palette.h" -#ifdef CAMU_RENDERER_DX11 +#ifdef STELA_API_DX11 #include <nnwt/windows.h> #define COBJMACROS #include <libplacebo/d3d11.h> @@ -42,7 +42,7 @@ static void renderer_lp_resize(struct camu_renderer *renderer, u32 *width, u32 * } } -#ifdef CAMU_RENDERER_DX11 +#ifdef STELA_API_DX11 static void renderer_lp_set_fullscreen(struct camu_renderer *renderer, bool fullscreen) { struct camu_renderer_lp *lr = (struct camu_renderer_lp *)renderer; @@ -69,6 +69,21 @@ static void renderer_lp_set_scaling(struct camu_renderer *renderer, u8 mode) } } +static void renderer_lp_set_background(struct camu_renderer *renderer, u8 mode) +{ + struct camu_renderer_lp *lr = (struct camu_renderer_lp *)renderer; + switch (mode) { + case CAMU_BACKGROUND_DEFAULT: + clear_color[3] = 1.f; + lr->params.background = PL_CLEAR_TILES; + break; + case CAMU_BACKGROUND_TRANSPARENT: + clear_color[3] = 0.f; + lr->params.background = PL_CLEAR_SKIP; + break; + } +} + static void log_callback(void *userdata, enum pl_log_level level, const char *message) { (void)userdata; @@ -79,19 +94,34 @@ static void log_callback(void *userdata, enum pl_log_level level, const char *me } } +#ifdef CAMU_HAVE_SUBTITLES +// level = 0(FATAL)-7(VERBOSE). +static void ass_log_callback(s32 level, const char *fmt, va_list args, void *userdata) +{ + (void)userdata; + if (level <= 1) { + al_logv(AL_LOG_ERROR, "ass", fmt, args); + } else { +#ifdef AL_DEBUG + al_logv(AL_LOG_DEBUG, "ass", fmt, args); +#endif + } +} +#endif + static bool renderer_lp_create_renderer(struct camu_renderer *renderer, u32 *width, u32 *height, -#if defined CAMU_RENDERER_VULKAN +#if defined STELA_API_VULKAN VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL (*get_vk_proc_address)(VkInstance, const char *), VkResult (*vk_create_surface)(void *, VkInstance, VkSurfaceKHR *), const char *const *(*vk_get_extensions)(u32 *), -#elif defined CAMU_RENDERER_DX11 +#elif defined STELA_API_DX11 HWND win32_window, -#elif defined CAMU_RENDERER_OPENGL +#elif defined STELA_API_OPENGL #ifdef STELA_USE_EGL EGLDisplay display, EGLContext context, #endif - void (*get_gl_proc_address(char const *procname))(void), + void (*get_gl_proc_address(char const *))(void), bool (*gl_load_loader)(void *), bool (*gl_make_current)(void *), void (*gl_release_current)(void *), @@ -111,13 +141,18 @@ static bool renderer_lp_create_renderer(struct camu_renderer *renderer, u32 *wid clear_color[2] = 255.f; */ +//#define LIBPLACEBO_LOG_TRACE lr->logger = pl_log_create(PL_API_VER, pl_log_params( .log_cb = log_callback, .log_priv = NULL, +#ifdef LIBPLACEBO_LOG_TRACE + .log_level = PL_LOG_TRACE +#else .log_level = PL_LOG_INFO +#endif )); -#if defined CAMU_RENDERER_VULKAN +#if defined STELA_API_VULKAN VkResult err; u32 num; @@ -153,6 +188,7 @@ static bool renderer_lp_create_renderer(struct camu_renderer *renderer, u32 *wid lr->swapchain = pl_vulkan_create_swapchain(lr->vk, pl_vulkan_swapchain_params( .surface = lr->surface, .present_mode = VK_PRESENT_MODE_FIFO_KHR + //.present_mode = VK_PRESENT_MODE_IMMEDIATE_KHR )); if (!lr->swapchain) { log_error("Failed to create vulkan swapchain."); @@ -162,7 +198,7 @@ static bool renderer_lp_create_renderer(struct camu_renderer *renderer, u32 *wid lr->gpu = lr->vk->gpu; log_info("Using Vulkan."); -#elif defined CAMU_RENDERER_DX11 +#elif defined STELA_API_DX11 (void)priv; lr->d3d11 = pl_d3d11_create(lr->logger, pl_d3d11_params( .debug = false @@ -183,7 +219,7 @@ static bool renderer_lp_create_renderer(struct camu_renderer *renderer, u32 *wid lr->gpu = lr->d3d11->gpu; log_info("Using DirectX 11."); -#elif defined CAMU_RENDERER_OPENGL +#elif defined STELA_API_OPENGL (void)gl_load_loader; lr->gl = pl_opengl_create(lr->logger, pl_opengl_params( .debug = false, @@ -230,8 +266,17 @@ static bool renderer_lp_create_renderer(struct camu_renderer *renderer, u32 *wid // Clear manually so we can draw multiple images per frame. lr->params.border = PL_CLEAR_SKIP; + lr->params.background = PL_CLEAR_TILES; + /* + lr->params.background_color[0] = clear_color[0]; + lr->params.background_color[1] = clear_color[1]; + lr->params.background_color[2] = clear_color[2]; + lr->params.background_transparency = clear_color[3]; + */ + // Prioritize a more consistent image. lr->params.correct_subpixel_offsets = true; + //lr->params.distort_params = pl_distort_params(.unscaled = false); #if 0 struct nn_file file; @@ -254,6 +299,7 @@ static bool renderer_lp_create_renderer(struct camu_renderer *renderer, u32 *wid #ifdef CAMU_HAVE_SUBTITLES lr->ass = ass_library_init(); + ass_set_message_cb(lr->ass, ass_log_callback, lr); #endif lr->last_render_tick = nn_get_tick(); @@ -339,7 +385,7 @@ static void renderer_lp_render(struct camu_renderer *renderer, struct camu_scree if (mix.frames) { // weighted is only set when read() returns QUEUE_OK. do_gpu_finish |= weighted; - // Terrible hack. Let's us distinguish single frames with the same dimensions. + // Terrible hack. Lets us distinguish single frames with the same dimensions. // Tied to a libplacebo patch to consider info_priv in the hash. // Also, add in reset_pts to account for buffer resets. This is a completely // broken "hash" of the f64 pts value but hopefully it works for now. @@ -413,8 +459,8 @@ void renderer_lp_free(struct camu_renderer **renderer) struct camu_renderer_lp *lr = (struct camu_renderer_lp *)*renderer; if (lr->renderer) pl_renderer_destroy(&lr->renderer); if (lr->swapchain) pl_swapchain_destroy(&lr->swapchain); -#if defined CAMU_RENDERER_VULKAN -#elif defined CAMU_RENDERER_OPENGL +#if defined STELA_API_VULKAN +#elif defined STELA_API_OPENGL if (lr->gl) pl_opengl_destroy(&lr->gl); #endif if (lr->logger) pl_log_destroy(&lr->logger); @@ -433,12 +479,13 @@ struct camu_renderer *camu_renderer_lp_create(void) lr->r.add_font = renderer_lp_add_font; lr->r.get_latency = renderer_lp_get_latency; lr->r.resize = renderer_lp_resize; -#ifdef CAMU_RENDERER_DX11 +#ifdef STELA_API_DX11 lr->r.set_fullscreen = renderer_lp_set_fullscreen; #else lr->r.set_fullscreen = NULL; #endif lr->r.set_scaling = renderer_lp_set_scaling; + lr->r.set_background = renderer_lp_set_background; lr->r.render = renderer_lp_render; lr->r.free = renderer_lp_free; return (struct camu_renderer *)lr; diff --git a/src/render/renderer_libplacebo.h b/src/render/renderer_libplacebo.h index 7b1cfa2..a0125ba 100644 --- a/src/render/renderer_libplacebo.h +++ b/src/render/renderer_libplacebo.h @@ -10,23 +10,23 @@ #include "renderer.h" -#if defined CAMU_RENDERER_VULKAN +#if defined STELA_API_VULKAN #include <libplacebo/vulkan.h> -#elif defined CAMU_RENDERER_DX11 +#elif defined STELA_API_DX11 #include <libplacebo/d3d11.h> -#elif defined CAMU_RENDERER_OPENGL +#elif defined STELA_API_OPENGL #include <libplacebo/opengl.h> #endif struct camu_renderer_lp { struct camu_renderer r; -#if defined CAMU_RENDERER_VULKAN +#if defined STELA_API_VULKAN VkSurfaceKHR surface; pl_vulkan vk; pl_vk_inst vk_inst; -#elif defined CAMU_RENDERER_DX11 +#elif defined STELA_API_DX11 pl_d3d11 d3d11; -#elif defined CAMU_RENDERER_OPENGL +#elif defined STELA_API_OPENGL pl_opengl gl; #endif pl_gpu gpu; diff --git a/src/render/renderer_momo.c b/src/render/renderer_momo.c new file mode 100644 index 0000000..9f217bf --- /dev/null +++ b/src/render/renderer_momo.c @@ -0,0 +1,97 @@ +#define AL_LOG_SECTION "renderer_momo" +#include <al/log.h> + +#include "renderer_momo.h" +#include "queue_momo.h" + +static void renderer_momo_resize(struct camu_renderer *renderer, u32 *width, u32 *height) +{ + struct camu_renderer_momo *mr = (struct camu_renderer_momo *)renderer; + (void)mr; + (void)width; + (void)height; +} + +static bool renderer_momo_create_renderer(struct camu_renderer *renderer, u32 *width, u32 *height, +#if defined STELA_API_OPENGL +#ifdef STELA_USE_EGL + EGLDisplay display, + EGLContext context, +#endif + void (*get_gl_proc_address(char const *))(void), + bool (*gl_load_loader)(void *), + bool (*gl_make_current)(void *), + void (*gl_release_current)(void *), + void (*gl_swap_buffers)(void *), +#endif + void *priv) +{ + struct camu_renderer_momo *mr = (struct camu_renderer_momo *)renderer; + (void)width; + (void)height; +#if defined STELA_API_OPENGL +#ifdef STELA_USE_EGL + (void)display; + (void)context; +#endif + (void)get_gl_proc_address; + (void)gl_load_loader; + MOMO_Init(&mr->mmr, gl_make_current, gl_release_current, gl_swap_buffers, priv); +#endif +#ifdef CAMU_HAVE_SUBTITLES + mr->ass = ass_library_init(); + // Just to keep these linked in the exe for platform testing. + ASS_Renderer *ar = ass_renderer_init(mr->ass); + ASS_Track *at = ass_new_track(mr->ass); + (void)at; + u32 w = *width, h = *height; + ass_set_frame_size(ar, w, h); + ass_set_storage_size(ar, w, h); + ass_set_fonts(ar, NULL, NULL, ASS_FONTPROVIDER_AUTODETECT, NULL, 0); + ass_set_hinting(ar, ASS_HINTING_NONE); +#endif + return true; +} + +static struct camu_frame_queue *renderer_momo_create_queue(struct camu_renderer *renderer) +{ + struct camu_renderer_momo *mr = (struct camu_renderer_momo *)renderer; + struct camu_frame_queue *q = camu_frame_queue_momo_create(); + struct camu_frame_queue_momo *mq = (struct camu_frame_queue_momo *)q; + (void)mr; + (void)mq; + return q; +} + +static u32 renderer_momo_get_latency(struct camu_renderer *renderer) +{ + (void)renderer; + return 0; +} + +static void renderer_momo_render(struct camu_renderer *renderer, struct camu_screen *scr, bool force) +{ + struct camu_renderer_momo *mr = (struct camu_renderer_momo *)renderer; + (void)scr; + (void)force; + MOMO_Render(&mr->mmr); +} + +static void renderer_momo_free(struct camu_renderer **renderer) +{ + struct camu_renderer_momo *mr = (struct camu_renderer_momo *)*renderer; + al_free(mr); + *renderer = NULL; +} + +struct camu_renderer *camu_renderer_momo_create(void) +{ + struct camu_renderer_momo *mr = al_alloc_object(struct camu_renderer_momo); + mr->r.create_renderer = renderer_momo_create_renderer; + mr->r.create_queue = renderer_momo_create_queue; + mr->r.get_latency = renderer_momo_get_latency; + mr->r.resize = renderer_momo_resize; + mr->r.render = renderer_momo_render; + mr->r.free = renderer_momo_free; + return (struct camu_renderer *)mr; +} diff --git a/src/render/renderer_momo.h b/src/render/renderer_momo.h new file mode 100644 index 0000000..3b9084b --- /dev/null +++ b/src/render/renderer_momo.h @@ -0,0 +1,19 @@ +#pragma once + +#ifdef CAMU_HAVE_SUBTITLES +#include <ass/ass.h> +#endif + +#include "momo/momo.h" + +#include "renderer.h" + +struct camu_renderer_momo { + struct camu_renderer r; + MOMO_Renderer mmr; +#ifdef CAMU_HAVE_SUBTITLES + ASS_Library *ass; +#endif +}; + +struct camu_renderer *camu_renderer_momo_create(void); diff --git a/src/render/renderer_tiger.c b/src/render/renderer_tiger.c deleted file mode 100644 index eb99e0c..0000000 --- a/src/render/renderer_tiger.c +++ /dev/null @@ -1,320 +0,0 @@ -#define AL_LOG_SECTION "renderer_tiger" -#include <al/log.h> -#include <al/lib.h> -#include <linmath.h> - -#include "../screen/view.h" -#include "../screen/screen.h" -#include "../util/color_palette.h" - -#include "renderer_tiger.h" -#include "queue_tiger.h" - -#ifdef CAMU_RENDERER_OPENGL -static const GLfloat default_vertices[] = { - 0.f, 0.f, 0.f, 0.f, 0.f, - 0.f, 1.f, 0.f, 0.f, 1.f, - 1.f, 0.f, 0.f, 1.f, 0.f, - 1.f, 0.f, 0.f, 1.f, 0.f, - 0.f, 1.f, 0.f, 0.f, 1.f, - 1.f, 1.f, 0.f, 1.f, 1.f -}; - -static GLfloat clear_color[4] = { 0.f, 0.f, 0.f, 1.f }; - -static const GLchar *default_vs = \ - "#version 100\n" \ - "attribute vec3 a_Position;\n" \ - "attribute vec2 a_TexCoord;\n" \ - "varying vec2 v_TexCoord;\n" \ - "uniform mat4 g_ModelViewProjectionMatrix;\n" \ - "void main() {\n" \ - " gl_Position = g_ModelViewProjectionMatrix * vec4(a_Position, 1.0);\n" \ - " v_TexCoord = a_TexCoord;\n" \ - "}"; - -static const GLchar *default_fs = \ - "#version 100\n" \ - "precision mediump float;\n" \ - "varying vec2 v_TexCoord;\n" \ - "uniform sampler2D g_Texture0;\n" \ - "void main() {\n" \ - " gl_FragColor = texture2D(g_Texture0, v_TexCoord);\n" \ - "}"; - -static bool compile(GLuint shader, const GLchar *source, GLchar *error) -{ - glShaderSource(shader, 1, &source, 0); - glCompileShader(shader); - - GLint status; - - glGetShaderiv(shader, GL_COMPILE_STATUS, &status); - - if (status == GL_FALSE) { - glGetShaderInfoLog(shader, 256, NULL, error); - return false; - } - - return true; -} - -static bool compile_shaders(struct camu_renderer_tiger *tr) -{ - tr->program = glCreateProgram(); - - GLchar error[256]; - - GLuint vs_shader = glCreateShader(GL_VERTEX_SHADER); - if (!compile(vs_shader, default_vs, error)) { - log_error("Failed to compile vertex shader (%.*s)", sizeof(error), error); - return false; - } - - GLuint fs_shader = glCreateShader(GL_FRAGMENT_SHADER); - if (!compile(fs_shader, default_fs, error)) { - log_error("Failed to compile fragment shader (%.*s)", sizeof(error), error); - return false; - } - - glAttachShader(tr->program, vs_shader); - glAttachShader(tr->program, fs_shader); - glLinkProgram(tr->program); - - return true; -} -#endif - -static void renderer_tiger_resize(struct camu_renderer *renderer, u32 *width, u32 *height) -{ - struct camu_renderer_tiger *tr = (struct camu_renderer_tiger *)renderer; - (void)tr; - (void)width; - (void)height; -} - -static bool renderer_tiger_create_renderer(struct camu_renderer *renderer, u32 *width, u32 *height, -#if defined CAMU_RENDERER_VULKAN - VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL (*get_vk_proc_address)(VkInstance, const char *), - void (*vk_create_surface)(void *, VkInstance, VkSurfaceKHR *), - const char *const *(*vk_get_extensions)(u32 *), -#elif defined CAMU_RENDERER_OPENGL -#ifdef STELA_USE_EGL - EGLDisplay display, - EGLContext context, -#endif - void (*get_gl_proc_address(char const *procname))(void), - bool (*gl_load_loader)(void *), - bool (*gl_make_current)(void *), - void (*gl_release_current)(void *), - void (*gl_swap_buffers)(void *), -#endif - void *priv) -{ - struct camu_renderer_tiger *tr = (struct camu_renderer_tiger *)renderer; - (void)width; - (void)height; -#ifdef CAMU_RENDERER_OPENGL - (void)display; - (void)context; - (void)get_gl_proc_address; - - tr->load_loader = gl_load_loader; - tr->make_current = gl_make_current; - tr->release_current = gl_release_current; - tr->swap_buffers = gl_swap_buffers; - tr->priv = priv; - - tr->make_current(tr->priv); - - if (!tr->load_loader(tr->priv)) { - return false; - } - - clear_color[0] = ((global_color_palette.colors[0] >> 16) & 0xff) / 255.f; - clear_color[1] = ((global_color_palette.colors[0] >> 8) & 0xff) / 255.f; - clear_color[2] = ((global_color_palette.colors[0]) & 0xff) / 255.f; - - glClearColor(clear_color[0], clear_color[1], clear_color[2], 1.f); - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - glGenBuffers(1, &tr->vbo); - glBindBuffer(GL_ARRAY_BUFFER, tr->vbo); - glBufferData(GL_ARRAY_BUFFER, sizeof(default_vertices), default_vertices, GL_STATIC_DRAW); - - if (!compile_shaders(tr)) return false; - - glUseProgram(tr->program); - - GLint pos = glGetAttribLocation(tr->program, "a_Position"); - glVertexAttribPointer(pos, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void *)0); - if (stl_gl_check_error()) { - log_error("glVertexAttribPointer returned error, use GLES context."); - al_assert_and_return(false); - } - glEnableVertexAttribArray(pos); - GLint texcoord = glGetAttribLocation(tr->program, "a_TexCoord"); - glVertexAttribPointer(texcoord, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void *)12); - glEnableVertexAttribArray(texcoord); - - //glGenBuffers(1, &tr->texture_buffer); -#endif - -#ifdef CAMU_HAVE_FFMPEG - tr->r.get_buffer2 = NULL; - tr->r.opaque = NULL; -#endif - - return true; -} - -static struct camu_frame_queue *renderer_tiger_create_queue(struct camu_renderer *renderer) -{ -#ifdef CAMU_RENDERER_OPENGL - struct camu_renderer_tiger *tr = (struct camu_renderer_tiger *)renderer; - struct camu_frame_queue *q = camu_frame_queue_tiger_create(); - struct camu_frame_queue_tiger *tq = (struct camu_frame_queue_tiger *)q; - tq->tr = tr; - return q; -#endif -} - -static u32 renderer_tiger_get_latency(struct camu_renderer *renderer) -{ - (void)renderer; - return 0; -} - -static void set_uniform(struct camu_renderer_tiger *tr, const GLchar *name, - u8 type, void *value) -{ -#ifdef CAMU_RENDERER_OPENGL - GLint loc = glGetUniformLocation(tr->program, name); - if (loc == -1) return; - - switch (type) - { - case TYPE_FLOAT: - glUniform1f(loc, *((GLfloat *)value)); - break; - case TYPE_SAMPLER2D: - glUniform1i(loc, (GLuint)(*((GLfloat *)value))); - break; - case TYPE_VEC2: - glUniform2fv(loc, 1, (GLfloat *)value); - break; - case TYPE_VEC3: - glUniform3fv(loc, 1, (GLfloat *)value); - break; - case TYPE_VEC4: - glUniform4fv(loc, 1, (GLfloat *)value); - break; - case TYPE_MAT4: - glUniformMatrix4fv(loc, 1, GL_FALSE, (GLfloat *)value); - break; - case TYPE_MAT3: - glUniformMatrix3fv(loc, 1, GL_FALSE, (GLfloat *)value); - break; - case TYPE_INVALID: - break; - } -#endif -} - -static void renderer_tiger_render(struct camu_renderer *renderer, struct camu_screen *scr, bool force) -{ -#ifdef CAMU_RENDERER_OPENGL - struct camu_renderer_tiger *tr = (struct camu_renderer_tiger *)renderer; - (void)force; - - tr->make_current(tr->priv); - - glClear(GL_COLOR_BUFFER_BIT); - - glUseProgram(tr->program); - glBindBuffer(GL_ARRAY_BUFFER, tr->vbo); - glActiveTexture(GL_TEXTURE0); - -#ifdef CAMU_SCREEN_THREADED - if (al_atomic_load(u8)(&scr->queued, AL_ATOMIC_RELAXED)) { - camu_screen_run_queue(scr); - } -#endif - - if (scr->videos.count > 0) { - struct camu_screen_video *video = &al_array_last(scr->videos); - - GLuint texture_id; - bool weighted; - if (camu_video_buffer_read(video->buf, &texture_id, &weighted)) { - glBindTexture(GL_TEXTURE_2D, texture_id); - - mat4x4 model; - mat4x4_identity(model); - mat4x4_ortho(model, 0.f, (f32)scr->width, (f32)scr->height, 0.f, -1.f, 1.f); - mat4x4_translate_in_place(model, (f32)video->view.x_offset, (f32)video->view.y_offset, 0.f); - mat4x4_scale_aniso(model, model, (f32)video->view.zoom, (f32)video->view.zoom, 1.f); - mat4x4_scale_aniso(model, model, (f32)video->view.width, (f32)video->view.height, 1.f); - set_uniform(tr, "g_ModelViewProjectionMatrix", TYPE_MAT4, model); - - GLuint texture0 = 0; - set_uniform(tr, "g_Texture0", TYPE_SAMPLER2D, &texture0); - - glViewport(0, 0, scr->width, scr->height); - glDrawArrays(GL_TRIANGLES, 0, 6); - } - } - - tr->swap_buffers(tr->priv); -#endif - - tr->release_current(tr->priv); -} - -/* -static void *renderer_tiger_get_device_ptr(struct camu_renderer *renderer, size_t length) -{ - (void)renderer; - (void)length; - return NULL; -#ifdef CAMU_RENDERER_OPENGL - //struct camu_renderer_tiger *tr = (struct camu_renderer_tiger *)renderer; - //glBindBuffer(GL_PIXEL_UNPACK_BUFFER, tr->texture_buffer); - //glBufferData(GL_PIXEL_UNPACK_BUFFER, length, NULL, GL_STREAM_DRAW); - //return glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, length, GL_MAP_WRITE_BIT); -#endif -} - -static void renderer_tiger_commit_device_ptr(struct camu_renderer *renderer) -{ - (void)renderer; -#ifdef CAMU_RENDERER_OPENGL - //struct camu_renderer_tiger *tr = (struct camu_renderer_tiger *)renderer; - //glBindBuffer(GL_PIXEL_UNPACK_BUFFER, tr->texture_buffer); - //glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); -#endif -} -*/ - -static void renderer_tiger_free(struct camu_renderer **renderer) -{ - struct camu_renderer_tiger *tr = (struct camu_renderer_tiger *)*renderer; - glDeleteProgram(tr->program); - glDeleteBuffers(1, &tr->vbo); - al_free(tr); - *renderer = NULL; -} - -struct camu_renderer *camu_renderer_tiger_create(void) -{ - struct camu_renderer_tiger *tr = al_alloc_object(struct camu_renderer_tiger); - tr->r.create_renderer = renderer_tiger_create_renderer; - tr->r.create_queue = renderer_tiger_create_queue; - tr->r.get_latency = renderer_tiger_get_latency; - tr->r.resize = renderer_tiger_resize; - tr->r.render = renderer_tiger_render; - tr->r.free = renderer_tiger_free; - return (struct camu_renderer *)tr; -} diff --git a/src/render/renderer_tiger.h b/src/render/renderer_tiger.h deleted file mode 100644 index 5891c20..0000000 --- a/src/render/renderer_tiger.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include <stl/gl.h> - -#include "renderer.h" - -enum { - TYPE_INVALID = 0, - TYPE_FLOAT, - TYPE_VEC4, - TYPE_VEC3, - TYPE_VEC2, - TYPE_MAT4, - TYPE_MAT3, - TYPE_SAMPLER2D -}; - -struct camu_renderer_tiger { - struct camu_renderer r; - GLuint vao; - GLuint vbo; - GLuint program; - GLuint texture_buffer; - bool (*load_loader)(void *); - bool (*make_current)(void *); - void (*release_current)(void *); - void (*swap_buffers)(void *); - void *priv; -}; - -struct camu_renderer *camu_renderer_tiger_create(void); diff --git a/src/screen/screen.c b/src/screen/screen.c index 23afa7e..0ff5eec 100644 --- a/src/screen/screen.c +++ b/src/screen/screen.c @@ -51,7 +51,7 @@ static void do_resize(struct camu_screen *scr, u32 width, u32 height) camu_view_calculate(&video->view, scr->width, scr->height); } // No buffers resize. - al_atomic_store(u32)(&scr->force_refresh, 1, AL_ATOMIC_RELAXED); + al_atomic_add(u32)(&scr->force_refresh, 1, AL_ATOMIC_RELAXED); } static void resize_callback(void *userdata, u32 width, u32 height) @@ -309,6 +309,18 @@ static bool key_callback(void *userdata, u8 state, u16 button) log_info("Scaling filters enabled."); } return true; + case STELA_KEY_C: + scr->transparent_background = !scr->transparent_background; + if (scr->transparent_background) { + scr->renderer->set_background(scr->renderer, CAMU_BACKGROUND_TRANSPARENT); + log_info("Background transparent."); + } else { + scr->renderer->set_background(scr->renderer, CAMU_BACKGROUND_DEFAULT); + log_info("Background solid."); + } + // Force refresh for if there's no video buffer. + al_atomic_add(u32)(&scr->force_refresh, 1, AL_ATOMIC_RELAXED); + return true; default: break; } @@ -402,6 +414,7 @@ bool camu_screen_create_window(struct camu_screen *scr, const char *name) scr->height = scr->window->height; scr->fullscreen = false; scr->scaling_disabled = false; + scr->transparent_background = false; #ifdef STELA_EVENT_BUFFER nn_thread_create(&scr->thread, event_thread, scr); #endif @@ -412,13 +425,13 @@ bool camu_screen_create_renderer(struct camu_screen *scr, struct camu_renderer * { scr->renderer = renderer; return renderer->create_renderer(renderer, &scr->width, &scr->height, -#if defined CAMU_RENDERER_VULKAN +#if defined STELA_API_VULKAN scr->window->get_vk_proc_address, scr->window->vk_create_surface, scr->window->vk_get_extensions, -#elif defined CAMU_RENDERER_DX11 +#elif defined STELA_API_DX11 scr->window->win32_window, -#elif defined CAMU_RENDERER_OPENGL +#elif defined STELA_API_OPENGL #ifdef STELA_USE_EGL scr->window->egl_display, scr->window->egl_context, @@ -587,14 +600,14 @@ void camu_screen_set_state(struct camu_screen *scr, s32 state) if (al_atomic_load(s32)(&scr->state, AL_ATOMIC_ACQUIRE) != CAMU_SCREEN_STOPPED) { al_atomic_store(s32)(&scr->state, state, AL_ATOMIC_RELEASE); if (state == CAMU_SCREEN_PAUSED) { - al_atomic_store(u32)(&scr->force_refresh, 1, AL_ATOMIC_RELAXED); + al_atomic_add(u32)(&scr->force_refresh, 1, AL_ATOMIC_RELAXED); } } } void camu_screen_force_refresh(struct camu_screen *scr) { - al_atomic_store(u32)(&scr->force_refresh, 1, AL_ATOMIC_RELAXED); + al_atomic_add(u32)(&scr->force_refresh, 1, AL_ATOMIC_RELAXED); camu_screen_wake(scr); } @@ -622,13 +635,15 @@ bool camu_screen_tick(struct camu_screen *scr, bool *force) { s32 state = al_atomic_load(s32)(&scr->state, AL_ATOMIC_RELAXED); al_assert(state != CAMU_SCREEN_STOPPED); - bool paused = state == CAMU_SCREEN_PAUSED; - bool do_render = camu_screen_poll(scr, paused) || !paused; u32 force_refresh = al_atomic_load(u32)(&scr->force_refresh, AL_ATOMIC_ACQUIRE); + bool paused = state == CAMU_SCREEN_PAUSED && force_refresh == 0; + bool do_render = camu_screen_poll(scr, paused) || !paused; + // Should be AL_ATOMIC_ACQ_REL. + force_refresh = al_atomic_load(u32)(&scr->force_refresh, AL_ATOMIC_ACQUIRE); do_render |= force_refresh > 0; *force = force_refresh > 0; if (force_refresh > 0) { - al_atomic_store(u32)(&scr->force_refresh, 0, AL_ATOMIC_RELEASE); + al_atomic_sub(u32)(&scr->force_refresh, 1, AL_ATOMIC_RELEASE); } return do_render; } diff --git a/src/screen/screen.h b/src/screen/screen.h index 4ba07c2..afd2dee 100644 --- a/src/screen/screen.h +++ b/src/screen/screen.h @@ -64,6 +64,7 @@ struct camu_screen { u32 height; bool fullscreen; bool scaling_disabled; + bool transparent_background; u64 last_click_ts; f64 last_mouse_y; f64 last_mouse_x; diff --git a/src/server/server.c b/src/server/server.c index 6f8da78..ec99921 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -616,6 +616,7 @@ static u8 parse_resource_type(str *line) return CAMU_RESOURCE_HTTP; #else if (0) { + (void)line; #endif #if CACHE_HAVE_CDIO } else if (al_str_cmp(line, &al_str_c("cdda://"), 0, 7) == 0) { @@ -812,7 +813,7 @@ static void connection_closed_callback(void *userdata, struct nn_rpc_connection struct camu_server_sink *sink; al_array_foreach(server->sinks, i, sink) { if (sink->conn == conn) { - log_info("Sink removed."); + log_info("Sink \"%.*s\" removed.", al_str_x(&sink->name)); struct lia_list *list; al_array_foreach(server->lists, j, list) { lia_list_remove_sink(list, sink); |