(API Change) Always use planar float audio output

Core API functions changed:
-----------------------------
EXPORT bool obs_reset_audio(struct audio_output_info *aoi);
EXPORT bool obs_get_audio_info(struct audio_output_info *aoi);

To:
-----------------------------
EXPORT bool obs_reset_audio(const struct obs_audio_info *oai);
EXPORT bool obs_get_audio_info(struct obs_audio_info *oai);

Core structure added:
-----------------------------
struct obs_audio_info {
	uint32_t            samples_per_sec;
	enum speaker_layout speakers;
	uint64_t            buffer_ms;
};

Non-interleaved (planar) floating point output is standard with audio
filtering, so to prevent audio filters from having to worry about
different audio format implementations and for the sake consistency
between user interfaces, make it so that audio is always set to
non-interleaved floating point output.
master
jp9000 2015-03-07 04:47:12 -08:00
parent 9b44b368b7
commit 9832a760b8
6 changed files with 59 additions and 57 deletions

View File

@ -283,16 +283,22 @@ static void volmeter_source_destroyed(void *vptr, calldata_t *calldata)
obs_volmeter_detach_source(volmeter);
}
static void volmeter_sum_and_max(float *data, size_t frames,
/* TODO: Separate for individual channels */
static void volmeter_sum_and_max(float *data[MAX_AV_PLANES], size_t frames,
float *sum, float *max)
{
float s = *sum;
float m = *max;
for (float *c = data; c < data + frames; ++c) {
const float pow = *c * *c;
s += pow;
m = (m > pow) ? m : pow;
for (size_t plane = 0; plane < MAX_AV_PLANES; plane++) {
if (!data[plane])
break;
for (float *c = data[plane]; c < data[plane] + frames; ++c) {
const float pow = *c * *c;
s += pow;
m = (m > pow) ? m : pow;
}
}
*sum = s;
@ -340,23 +346,29 @@ static bool volmeter_process_audio_data(obs_volmeter_t *volmeter,
{
bool updated = false;
size_t frames = 0;
size_t samples = 0;
size_t left = data->frames;
float *adata = (float *) data->data[0];
float *adata[MAX_AV_PLANES];
for (size_t i = 0; i < MAX_AV_PLANES; i++)
adata[i] = (float*)data->data[i];
while (left) {
frames = (volmeter->ival_frames + left >
volmeter->update_frames)
? volmeter->update_frames - volmeter->ival_frames
: left;
samples = frames * volmeter->channels;
volmeter_sum_and_max(adata, samples, &volmeter->ival_sum,
volmeter_sum_and_max(adata, frames, &volmeter->ival_sum,
&volmeter->ival_max);
volmeter->ival_frames += (unsigned int)frames;
left -= frames;
adata += samples;
for (size_t i = 0; i < MAX_AV_PLANES; i++) {
if (!adata[i])
break;
adata[i] += frames;
}
/* break if we did not reach the end of the interval */
if (volmeter->ival_frames != volmeter->update_frames)

View File

@ -1637,36 +1637,12 @@ static void downmix_to_mono_planar(struct obs_source *source, uint32_t frames)
}
}
static void downmix_to_mono_interleaved(struct obs_source *source,
uint32_t frames)
{
size_t channels = audio_output_get_channels(obs->audio.audio);
const float channels_i = 1.0f / (float)channels;
float *data = (float*)source->audio_data.data[0];
for (uint32_t frame = 0; frame < frames; frame++) {
size_t pos = frame * channels;
for (size_t channel = 1; channel < channels; channel++)
data[pos] += data[pos + channel];
}
for (uint32_t frame = 0; frame < frames; frame++)
data[frame * channels] *= channels_i;
for (uint32_t frame = 0; frame < frames; frame++) {
size_t pos = frame * channels;
for (size_t channel = 1; channel < channels; channel++)
data[pos + channel] = data[pos];
}
}
/* resamples/remixes new audio to the designated main audio output format */
static void process_audio(obs_source_t *source,
const struct obs_source_audio *audio)
{
uint32_t frames = audio->frames;
bool mono_output;
if (source->sample_info.samples_per_sec != audio->samples_per_sec ||
source->sample_info.format != audio->format ||
@ -1693,12 +1669,10 @@ static void process_audio(obs_source_t *source,
audio->timestamp);
}
if ((source->flags & OBS_SOURCE_FLAG_FORCE_MONO) != 0) {
if (is_audio_planar(source->sample_info.format))
downmix_to_mono_planar(source, frames);
else
downmix_to_mono_interleaved(source, frames);
}
mono_output = audio_output_get_channels(obs->audio.audio) == 1;
if (!mono_output && (source->flags & OBS_SOURCE_FLAG_FORCE_MONO) != 0)
downmix_to_mono_planar(source, frames);
}
void obs_source_output_audio(obs_source_t *source,

View File

@ -752,8 +752,10 @@ int obs_reset_video(struct obs_video_info *ovi)
return obs_init_video(ovi);
}
bool obs_reset_audio(struct audio_output_info *ai)
bool obs_reset_audio(const struct obs_audio_info *oai)
{
struct audio_output_info ai;
if (!obs) return false;
/* don't allow changing of audio settings if active. */
@ -761,18 +763,24 @@ bool obs_reset_audio(struct audio_output_info *ai)
return false;
obs_free_audio();
if(!ai)
if (!oai)
return true;
ai.name = "Audio";
ai.samples_per_sec = oai->samples_per_sec;
ai.format = AUDIO_FORMAT_FLOAT_PLANAR;
ai.speakers = oai->speakers;
ai.buffer_ms = oai->buffer_ms;
blog(LOG_INFO, "audio settings reset:\n"
"\tsamples per sec: %d\n"
"\tspeakers: %d\n"
"\tbuffering (ms): %d\n",
(int)ai->samples_per_sec,
(int)ai->speakers,
(int)ai->buffer_ms);
(int)ai.samples_per_sec,
(int)ai.speakers,
(int)ai.buffer_ms);
return obs_init_audio(ai);
return obs_init_audio(&ai);
}
bool obs_get_video_info(struct obs_video_info *ovi)
@ -803,17 +811,19 @@ bool obs_get_video_info(struct obs_video_info *ovi)
return true;
}
bool obs_get_audio_info(struct audio_output_info *aoi)
bool obs_get_audio_info(struct obs_audio_info *oai)
{
struct obs_core_audio *audio = &obs->audio;
const struct audio_output_info *info;
if (!obs || !audio->audio)
if (!obs || !oai || !audio->audio)
return false;
info = audio_output_get_info(audio->audio);
memcpy(aoi, info, sizeof(struct audio_output_info));
oai->samples_per_sec = info->samples_per_sec;
oai->speakers = info->speakers;
oai->buffer_ms = info->buffer_ms;
return true;
}

View File

@ -172,6 +172,15 @@ struct obs_video_info {
enum obs_scale_type scale_type; /**< How to scale if scaling */
};
/**
* Audio initialization structure
*/
struct obs_audio_info {
uint32_t samples_per_sec;
enum speaker_layout speakers;
uint64_t buffer_ms;
};
/**
* Sent to source filters via the filter_audio callback to allow filtering of
* audio data
@ -274,13 +283,13 @@ EXPORT int obs_reset_video(struct obs_video_info *ovi);
*
* @note Cannot reset base audio if an output is currently active.
*/
EXPORT bool obs_reset_audio(struct audio_output_info *ai);
EXPORT bool obs_reset_audio(const struct obs_audio_info *oai);
/** Gets the current video settings, returns false if no video */
EXPORT bool obs_get_video_info(struct obs_video_info *ovi);
/** Gets the current audio settings, returns false if no audio */
EXPORT bool obs_get_audio_info(struct audio_output_info *ai);
EXPORT bool obs_get_audio_info(struct obs_audio_info *oai);
/**
* Opens a plugin module directly from a specific path.

View File

@ -1539,10 +1539,7 @@ int OBSBasic::ResetVideo()
bool OBSBasic::ResetAudio()
{
struct audio_output_info ai;
ai.name = "Main Audio Track";
ai.format = AUDIO_FORMAT_FLOAT;
struct obs_audio_info ai;
ai.samples_per_sec = config_get_uint(basicConfig, "Audio",
"SampleRate");

View File

@ -287,7 +287,7 @@ static bool open_audio_codec(struct ffmpeg_data *data)
static bool create_audio_stream(struct ffmpeg_data *data)
{
AVCodecContext *context;
struct audio_output_info aoi;
struct obs_audio_info aoi;
if (!obs_get_audio_info(&aoi)) {
blog(LOG_WARNING, "No active audio");