diff --git a/plugins/obs-ffmpeg/data/locale/en-US.ini b/plugins/obs-ffmpeg/data/locale/en-US.ini index 6e7d15903..a88fab8cd 100644 --- a/plugins/obs-ffmpeg/data/locale/en-US.ini +++ b/plugins/obs-ffmpeg/data/locale/en-US.ini @@ -1,6 +1,9 @@ FFmpegOutput="FFmpeg Output" FFmpegAAC="FFmpeg AAC" FFmpegOpus="FFmpeg Opus" +FFmpegALAC="FFmpeg ALAC (24-bit)" +FFmpegPCM16Bit="FFmpeg PCM (16-bit)" +FFmpegPCM24Bit="FFmpeg PCM (24-bit)" FFmpegOpts="FFmpeg Options" FFmpegOpts.ToolTip.Source="Allows you to set FFmpeg options. This only accepts options in the option=value format.\nMultiple options can be set by separating them with a space.\nExample: rtsp_transport=tcp rtsp_flags=prefer_tcp" Bitrate="Bitrate" diff --git a/plugins/obs-ffmpeg/obs-ffmpeg-audio-encoders.c b/plugins/obs-ffmpeg/obs-ffmpeg-audio-encoders.c index 80920dcf9..bd6f8a149 100644 --- a/plugins/obs-ffmpeg/obs-ffmpeg-audio-encoders.c +++ b/plugins/obs-ffmpeg/obs-ffmpeg-audio-encoders.c @@ -95,6 +95,24 @@ static const char *opus_getname(void *unused) return obs_module_text("FFmpegOpus"); } +static const char *pcm_getname(void *unused) +{ + UNUSED_PARAMETER(unused); + return obs_module_text("FFmpegPCM16Bit"); +} + +static const char *pcm24_getname(void *unused) +{ + UNUSED_PARAMETER(unused); + return obs_module_text("FFmpegPCM24Bit"); +} + +static const char *alac_getname(void *unused) +{ + UNUSED_PARAMETER(unused); + return obs_module_text("FFmpegALAC"); +} + static void enc_destroy(void *data) { struct enc_encoder *enc = data; @@ -207,9 +225,17 @@ static void *enc_create(obs_data_t *settings, obs_encoder_t *encoder, goto fail; } - if (!bitrate) { + const AVCodecDescriptor *codec_desc = + avcodec_descriptor_get(enc->codec->id); + + if (!codec_desc) { + warn("Failed to get codec descriptor"); + goto fail; + } + + if (!bitrate && !(codec_desc->props & AV_CODEC_PROP_LOSSLESS)) { warn("Invalid bitrate specified"); - return NULL; + goto fail; } enc->context = avcodec_alloc_context3(enc->codec); @@ -218,7 +244,12 @@ static void *enc_create(obs_data_t *settings, obs_encoder_t *encoder, goto fail; } - enc->context->bit_rate = bitrate * 1000; + if (codec_desc->props & AV_CODEC_PROP_LOSSLESS) + // Set by encoder on init, not known at this time + enc->context->bit_rate = -1; + else + enc->context->bit_rate = bitrate * 1000; + const struct audio_output_info *aoi; aoi = audio_output_get_info(audio); @@ -300,6 +331,21 @@ static void *opus_create(obs_data_t *settings, obs_encoder_t *encoder) return enc_create(settings, encoder, "libopus", "opus"); } +static void *pcm_create(obs_data_t *settings, obs_encoder_t *encoder) +{ + return enc_create(settings, encoder, "pcm_s16le", NULL); +} + +static void *pcm24_create(obs_data_t *settings, obs_encoder_t *encoder) +{ + return enc_create(settings, encoder, "pcm_s24le", NULL); +} + +static void *alac_create(obs_data_t *settings, obs_encoder_t *encoder) +{ + return enc_create(settings, encoder, "alac", NULL); +} + static bool do_encode(struct enc_encoder *enc, struct encoder_packet *packet, bool *received_packet) { @@ -453,3 +499,48 @@ struct obs_encoder_info opus_encoder_info = { .get_extra_data = enc_extra_data, .get_audio_info = enc_audio_info, }; + +struct obs_encoder_info pcm_encoder_info = { + .id = "ffmpeg_pcm_s16le", + .type = OBS_ENCODER_AUDIO, + .codec = "pcm_s16le", + .get_name = pcm_getname, + .create = pcm_create, + .destroy = enc_destroy, + .encode = enc_encode, + .get_frame_size = enc_frame_size, + .get_defaults = enc_defaults, + .get_properties = enc_properties, + .get_extra_data = enc_extra_data, + .get_audio_info = enc_audio_info, +}; + +struct obs_encoder_info pcm24_encoder_info = { + .id = "ffmpeg_pcm_s24le", + .type = OBS_ENCODER_AUDIO, + .codec = "pcm_s24le", + .get_name = pcm24_getname, + .create = pcm24_create, + .destroy = enc_destroy, + .encode = enc_encode, + .get_frame_size = enc_frame_size, + .get_defaults = enc_defaults, + .get_properties = enc_properties, + .get_extra_data = enc_extra_data, + .get_audio_info = enc_audio_info, +}; + +struct obs_encoder_info alac_encoder_info = { + .id = "ffmpeg_alac", + .type = OBS_ENCODER_AUDIO, + .codec = "alac", + .get_name = alac_getname, + .create = alac_create, + .destroy = enc_destroy, + .encode = enc_encode, + .get_frame_size = enc_frame_size, + .get_defaults = enc_defaults, + .get_properties = enc_properties, + .get_extra_data = enc_extra_data, + .get_audio_info = enc_audio_info, +}; diff --git a/plugins/obs-ffmpeg/obs-ffmpeg.c b/plugins/obs-ffmpeg/obs-ffmpeg.c index d32146cf9..906f46df8 100644 --- a/plugins/obs-ffmpeg/obs-ffmpeg.c +++ b/plugins/obs-ffmpeg/obs-ffmpeg.c @@ -36,6 +36,9 @@ extern struct obs_output_info replay_buffer; extern struct obs_output_info ffmpeg_hls_muxer; extern struct obs_encoder_info aac_encoder_info; extern struct obs_encoder_info opus_encoder_info; +extern struct obs_encoder_info pcm_encoder_info; +extern struct obs_encoder_info pcm24_encoder_info; +extern struct obs_encoder_info alac_encoder_info; extern struct obs_encoder_info h264_nvenc_encoder_info; #ifdef ENABLE_HEVC extern struct obs_encoder_info hevc_nvenc_encoder_info; @@ -387,6 +390,9 @@ bool obs_module_load(void) register_encoder_if_available(&svt_av1_encoder_info, "libsvtav1"); register_encoder_if_available(&aom_av1_encoder_info, "libaom-av1"); obs_register_encoder(&opus_encoder_info); + obs_register_encoder(&pcm_encoder_info); + obs_register_encoder(&pcm24_encoder_info); + obs_register_encoder(&alac_encoder_info); #ifndef __APPLE__ bool h264 = false; bool hevc = false;