Support opus flt and fltp

This commit is contained in:
dec05eba 2023-03-04 16:02:48 +01:00
parent c956cd4be3
commit 8ca1ac70e8
3 changed files with 46 additions and 23 deletions

View File

@ -37,7 +37,8 @@ struct MergedAudioInputs {
typedef enum { typedef enum {
S16, S16,
S32 S32,
F32
} AudioFormat; } AudioFormat;
/* /*

View File

@ -235,11 +235,37 @@ static AVCodecID audio_codec_get_id(AudioCodec audio_codec) {
return AV_CODEC_ID_AAC; return AV_CODEC_ID_AAC;
} }
static AVSampleFormat audio_codec_get_sample_format(AudioCodec audio_codec) { static AVSampleFormat audio_codec_get_sample_format(AudioCodec audio_codec, const AVCodec *codec) {
switch(audio_codec) { switch(audio_codec) {
case AudioCodec::AAC: return AV_SAMPLE_FMT_FLTP; case AudioCodec::AAC: {
case AudioCodec::OPUS: return AV_SAMPLE_FMT_S16; return AV_SAMPLE_FMT_FLTP;
case AudioCodec::FLAC: return AV_SAMPLE_FMT_S32; }
case AudioCodec::OPUS: {
bool supports_s16 = false;
bool supports_flt = false;
for(size_t i = 0; codec->sample_fmts && codec->sample_fmts[i] != -1; ++i) {
if(codec->sample_fmts[i] == AV_SAMPLE_FMT_S16) {
supports_s16 = true;
} else if(codec->sample_fmts[i] == AV_SAMPLE_FMT_FLT) {
supports_flt = true;
}
}
if(!supports_s16 && !supports_flt) {
fprintf(stderr, "Warning: opus audio codec is chosen but your ffmpeg version does not support s16/flt sample format and performance might be slightly worse. You can either rebuild ffmpeg with libopus instead of the built-in opus, use the flatpak version of gpu screen recorder or record with flac audio codec instead (-ac flac). Falling back to fltp audio sample format instead.\n");
}
if(supports_s16)
return AV_SAMPLE_FMT_S16;
else if(supports_flt)
return AV_SAMPLE_FMT_FLT;
else
return AV_SAMPLE_FMT_FLTP;
}
case AudioCodec::FLAC: {
return AV_SAMPLE_FMT_S32;
}
} }
assert(false); assert(false);
return AV_SAMPLE_FMT_FLTP; return AV_SAMPLE_FMT_FLTP;
@ -255,20 +281,21 @@ static int64_t audio_codec_get_get_bitrate(AudioCodec audio_codec) {
return 96000; return 96000;
} }
static AudioFormat audio_codec_get_audio_format(AudioCodec audio_codec) { static AudioFormat audio_codec_context_get_audio_format(const AVCodecContext *audio_codec_context) {
switch(audio_codec) { switch(audio_codec_context->sample_fmt) {
case AudioCodec::AAC: return S32; case AV_SAMPLE_FMT_FLT: return F32;
case AudioCodec::OPUS: return S16; case AV_SAMPLE_FMT_FLTP: return S32;
case AudioCodec::FLAC: return S32; case AV_SAMPLE_FMT_S16: return S16;
case AV_SAMPLE_FMT_S32: return S32;
default: return S16;
} }
assert(false);
return S32;
} }
static AVSampleFormat audio_format_to_sample_format(const AudioFormat audio_format) { static AVSampleFormat audio_format_to_sample_format(const AudioFormat audio_format) {
switch(audio_format) { switch(audio_format) {
case S16: return AV_SAMPLE_FMT_S16; case S16: return AV_SAMPLE_FMT_S16;
case S32: return AV_SAMPLE_FMT_S32; case S32: return AV_SAMPLE_FMT_S32;
case F32: return AV_SAMPLE_FMT_FLT;
} }
assert(false); assert(false);
return AV_SAMPLE_FMT_S16; return AV_SAMPLE_FMT_S16;
@ -281,16 +308,11 @@ static AVCodecContext* create_audio_codec_context(int fps, AudioCodec audio_code
exit(1); exit(1);
} }
fprintf(stderr, "Audio codec: %s, supported sample formats:\n", audio_codec_get_name(audio_codec));
for(size_t i = 0; codec->sample_fmts && codec->sample_fmts[i] != -1; ++i) {
fprintf(stderr, " %zu: %s\n", i, av_get_sample_fmt_name(codec->sample_fmts[i]));
}
AVCodecContext *codec_context = avcodec_alloc_context3(codec); AVCodecContext *codec_context = avcodec_alloc_context3(codec);
assert(codec->type == AVMEDIA_TYPE_AUDIO); assert(codec->type == AVMEDIA_TYPE_AUDIO);
codec_context->codec_id = codec->id; codec_context->codec_id = codec->id;
codec_context->sample_fmt = audio_codec_get_sample_format(audio_codec); codec_context->sample_fmt = audio_codec_get_sample_format(audio_codec, codec);
codec_context->bit_rate = audio_codec_get_get_bitrate(audio_codec); codec_context->bit_rate = audio_codec_get_get_bitrate(audio_codec);
codec_context->sample_rate = 48000; codec_context->sample_rate = 48000;
if(audio_codec == AudioCodec::AAC) if(audio_codec == AudioCodec::AAC)
@ -1055,8 +1077,6 @@ int main(int argc, char **argv) {
usage(); usage();
} }
const AudioFormat audio_format = audio_codec_get_audio_format(audio_codec);
const Arg &audio_input_arg = args["-a"]; const Arg &audio_input_arg = args["-a"];
const std::vector<AudioInput> audio_inputs = get_pulseaudio_inputs(); const std::vector<AudioInput> audio_inputs = get_pulseaudio_inputs();
std::vector<MergedAudioInputs> requested_audio_inputs; std::vector<MergedAudioInputs> requested_audio_inputs;
@ -1482,7 +1502,7 @@ int main(int argc, char **argv) {
audio_device.sound_device.handle = NULL; audio_device.sound_device.handle = NULL;
audio_device.sound_device.frames = 0; audio_device.sound_device.frames = 0;
} else { } else {
if(sound_device_get_by_name(&audio_device.sound_device, audio_input.name.c_str(), audio_input.description.c_str(), num_channels, audio_codec_context->frame_size, audio_format) != 0) { if(sound_device_get_by_name(&audio_device.sound_device, audio_input.name.c_str(), audio_input.description.c_str(), num_channels, audio_codec_context->frame_size, audio_codec_context_get_audio_format(audio_codec_context)) != 0) {
fprintf(stderr, "Error: failed to get \"%s\" sound device\n", audio_input.name.c_str()); fprintf(stderr, "Error: failed to get \"%s\" sound device\n", audio_input.name.c_str());
exit(1); exit(1);
} }
@ -1560,8 +1580,8 @@ int main(int argc, char **argv) {
for(AudioTrack &audio_track : audio_tracks) { for(AudioTrack &audio_track : audio_tracks) {
for(AudioDevice &audio_device : audio_track.audio_devices) { for(AudioDevice &audio_device : audio_track.audio_devices) {
audio_device.thread = std::thread([record_start_time, replay_buffer_size_secs, &frame_data_queue, &frames_erased, &audio_track, empty_audio, &audio_device, &audio_filter_mutex, &write_output_mutex, audio_format](AVFormatContext *av_format_context) mutable { audio_device.thread = std::thread([record_start_time, replay_buffer_size_secs, &frame_data_queue, &frames_erased, &audio_track, empty_audio, &audio_device, &audio_filter_mutex, &write_output_mutex](AVFormatContext *av_format_context) mutable {
const AVSampleFormat sound_device_sample_format = audio_format_to_sample_format(audio_format); const AVSampleFormat sound_device_sample_format = audio_format_to_sample_format(audio_codec_context_get_audio_format(audio_track.codec_context));
const bool needs_audio_conversion = audio_track.codec_context->sample_fmt != sound_device_sample_format; const bool needs_audio_conversion = audio_track.codec_context->sample_fmt != sound_device_sample_format;
SwrContext *swr = nullptr; SwrContext *swr = nullptr;
if(needs_audio_conversion) { if(needs_audio_conversion) {

View File

@ -231,6 +231,7 @@ static pa_sample_format_t audio_format_to_pulse_audio_format(AudioFormat audio_f
switch(audio_format) { switch(audio_format) {
case S16: return PA_SAMPLE_S16LE; case S16: return PA_SAMPLE_S16LE;
case S32: return PA_SAMPLE_S32LE; case S32: return PA_SAMPLE_S32LE;
case F32: return PA_SAMPLE_FLOAT32LE;
} }
assert(false); assert(false);
return PA_SAMPLE_S16LE; return PA_SAMPLE_S16LE;
@ -240,6 +241,7 @@ static int audio_format_to_get_bytes_per_sample(AudioFormat audio_format) {
switch(audio_format) { switch(audio_format) {
case S16: return 2; case S16: return 2;
case S32: return 4; case S32: return 4;
case F32: return 4;
} }
assert(false); assert(false);
return 2; return 2;