From 30094a5919cc2e9e81fb1ef03ee7f949bfe4cdf0 Mon Sep 17 00:00:00 2001 From: jp9000 Date: Mon, 17 Feb 2014 20:23:20 -0700 Subject: [PATCH] Implement auto output resampling (if requested) If there are for example more than one audio outputs and they have different sample rates or channels and such, this will allow automatic conversion of that audio to the request formats/channels/rates (but only if requested). --- libobs/media-io/audio-io.c | 74 ++++++++++++++++++++++++-- plugins/obs-ffmpeg/obs-ffmpeg-output.c | 2 +- 2 files changed, 71 insertions(+), 5 deletions(-) diff --git a/libobs/media-io/audio-io.c b/libobs/media-io/audio-io.c index f6a5e3713..400b36600 100644 --- a/libobs/media-io/audio-io.c +++ b/libobs/media-io/audio-io.c @@ -24,6 +24,7 @@ #include "../util/platform.h" #include "audio-io.h" +#include "audio-resampler.h" /* #define DEBUG_AUDIO */ @@ -31,10 +32,17 @@ struct audio_input { struct audio_convert_info conversion; + audio_resampler_t resampler; + void (*callback)(void *param, const struct audio_data *data); void *param; }; +static inline audio_input_free(struct audio_input *input) +{ + audio_resampler_destroy(input->resampler); +} + struct audio_line { char *name; @@ -313,6 +321,31 @@ static inline bool mix_audio_line(struct audio_output *audio, return true; } +static bool resample_audio_output(struct audio_input *input, + struct audio_data *data) +{ + bool success = true; + + if (input->resampler) { + uint8_t *output[MAX_AV_PLANES]; + uint32_t frames; + uint64_t offset; + + memset(output, 0, sizeof(output)); + + success = audio_resampler_resample(input->resampler, + output, &frames, &offset, + data->data, data->frames); + + for (size_t i = 0; i < MAX_AV_PLANES; i++) + data->data[i] = output[i]; + data->frames = frames; + data->timestamp -= offset; + } + + return success; +} + static inline void do_audio_output(struct audio_output *audio, uint64_t timestamp, uint32_t frames) { @@ -323,12 +356,15 @@ static inline void do_audio_output(struct audio_output *audio, data.timestamp = timestamp; data.volume = 1.0f; - /* TODO: conversion */ pthread_mutex_lock(&audio->input_mutex); + for (size_t i = 0; i < audio->inputs.num; i++) { struct audio_input *input = audio->inputs.array+i; - input->callback(input->param, &data); + + if (resample_audio_output(input, &data)) + input->callback(input->param, &data); } + pthread_mutex_unlock(&audio->input_mutex); } @@ -429,6 +465,30 @@ static size_t audio_get_input_idx(audio_t video, return DARRAY_INVALID; } +static inline void audio_input_init(struct audio_input *input, + struct audio_output *audio) +{ + if (input->conversion.format != audio->info.format || + input->conversion.samples_per_sec != audio->info.samples_per_sec || + input->conversion.speakers != audio->info.speakers) { + struct resample_info from = { + .format = audio->info.format, + .samples_per_sec = audio->info.samples_per_sec, + .speakers = audio->info.speakers + }; + + struct resample_info to = { + .format = input->conversion.format, + .samples_per_sec = input->conversion.samples_per_sec, + .speakers = input->conversion.speakers + }; + + input->resampler = audio_resampler_create(&to, &from); + } else { + input->resampler = NULL; + } +} + void audio_output_connect(audio_t audio, struct audio_convert_info *conversion, void (*callback)(void *param, const struct audio_data *data), @@ -441,7 +501,6 @@ void audio_output_connect(audio_t audio, input.callback = callback; input.param = param; - /* TODO: conversion */ if (conversion) { input.conversion = *conversion; } else { @@ -451,6 +510,7 @@ void audio_output_connect(audio_t audio, audio->info.samples_per_sec; } + audio_input_init(&input, audio); da_push_back(audio->inputs, &input); } @@ -464,8 +524,10 @@ void audio_output_disconnect(audio_t audio, pthread_mutex_lock(&audio->input_mutex); size_t idx = audio_get_input_idx(audio, callback, param); - if (idx != DARRAY_INVALID) + if (idx != DARRAY_INVALID) { + audio_input_free(audio->inputs.array+idx); da_erase(audio->inputs, idx); + } pthread_mutex_unlock(&audio->input_mutex); } @@ -536,9 +598,13 @@ void audio_output_close(audio_t audio) line = next; } + for (size_t i = 0; i < audio->inputs.num; i++) + audio_input_free(audio->inputs.array+i); + for (size_t i = 0; i < MAX_AV_PLANES; i++) da_free(audio->mix_buffers[i]); + da_free(audio->inputs); event_destroy(&audio->stop_event); pthread_mutex_destroy(&audio->line_mutex); bfree(audio); diff --git a/plugins/obs-ffmpeg/obs-ffmpeg-output.c b/plugins/obs-ffmpeg/obs-ffmpeg-output.c index 8ad83a7b4..85e4594f9 100644 --- a/plugins/obs-ffmpeg/obs-ffmpeg-output.c +++ b/plugins/obs-ffmpeg/obs-ffmpeg-output.c @@ -576,7 +576,7 @@ static bool ffmpeg_output_start(void *data) struct audio_convert_info aci; aci.samples_per_sec = SPS_TODO; - aci.format = AUDIO_FORMAT_FLOAT; + aci.format = AUDIO_FORMAT_FLOAT_PLANAR; aci.speakers = SPEAKERS_STEREO; struct video_convert_info vci;