libobs: Add multi-track support to non-encoded outputs

master
jp9000 2018-10-04 20:04:40 -07:00
parent 8b98568bbc
commit b8a3ae1b10
6 changed files with 119 additions and 17 deletions

View File

@ -117,6 +117,18 @@ Output Definition Structure (obs_output_info)
This is called when the output recieves raw audio data. Only applies
to outputs that are not encoded.
**This callback must be used with single-track raw outputs.**
:param frames: The raw audio frames
.. member:: void (*obs_output_info.raw_audio2)(void *data, size_t idx, struct audio_data *frames)
This is called when the output recieves raw audio data. Only applies
to outputs that are not encoded.
**This callback must be used with multi-track raw outputs.**
:param idx: The audio track index
:param frames: The raw audio frames
.. member:: void (*obs_output_info.encoded_packet)(void *data, struct encoder_packet *packet)
@ -472,7 +484,19 @@ General Output Functions
.. function:: void obs_output_set_mixer(obs_output_t *output, size_t mixer_idx)
size_t obs_output_get_mixer(const obs_output_t *output)
Sets/gets the current audio mixer for non-encoded outputs.
Sets/gets the current audio mixer for non-encoded outputs. For
multi-track outputs, this would be the equivalent of setting the mask
only for the specified mixer index.
---------------------
.. function:: void obs_output_set_mixers(obs_output_t *output, size_t mixers)
size_t obs_output_get_mixers(const obs_output_t *output)
Sets/gets the current audio mixers (via mask) for non-encoded
multi-track outputs. If used with single-track outputs, the
single-track output will use either the first set mixer track in the
bitmask, or the first track if none is set in the bitmask.
---------------------

View File

@ -863,7 +863,7 @@ struct obs_output {
obs_encoder_t *video_encoder;
obs_encoder_t *audio_encoders[MAX_AUDIO_MIXES];
obs_service_t *service;
size_t mixer_idx;
size_t mixer_mask;
uint32_t scaled_width;
uint32_t scaled_height;

View File

@ -675,9 +675,15 @@ void obs_register_output_s(const struct obs_output_info *info, size_t size)
CHECK_REQUIRED_VAL_(info, raw_video,
obs_register_output);
if (info->flags & OBS_OUTPUT_AUDIO)
CHECK_REQUIRED_VAL_(info, raw_audio,
obs_register_output);
if (info->flags & OBS_OUTPUT_AUDIO) {
if (info->flags & OBS_OUTPUT_MULTI_TRACK) {
CHECK_REQUIRED_VAL_(info, raw_audio2,
obs_register_output);
} else {
CHECK_REQUIRED_VAL_(info, raw_audio,
obs_register_output);
}
}
}
#undef CHECK_REQUIRED_VAL_

View File

@ -544,19 +544,46 @@ audio_t *obs_output_audio(const obs_output_t *output)
output->audio : NULL;
}
static inline size_t get_first_mixer(const obs_output_t *output)
{
for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) {
if ((((size_t)1 << i) & output->mixer_mask) != 0) {
return i;
}
}
return 0;
}
void obs_output_set_mixer(obs_output_t *output, size_t mixer_idx)
{
if (!obs_output_valid(output, "obs_output_set_mixer"))
return;
if (!active(output))
output->mixer_idx = mixer_idx;
output->mixer_mask = (size_t)1 << mixer_idx;
}
size_t obs_output_get_mixer(const obs_output_t *output)
{
return obs_output_valid(output, "obs_output_get_mixer") ?
output->mixer_idx : 0;
if (!obs_output_valid(output, "obs_output_get_mixer"))
return 0;
return get_first_mixer(output);
}
void obs_output_set_mixers(obs_output_t *output, size_t mixers)
{
if (!obs_output_valid(output, "obs_output_set_mixers"))
return;
output->mixer_mask = mixers;
}
size_t obs_output_get_mixers(const obs_output_t *output)
{
return obs_output_valid(output, "obs_output_get_mixers") ?
output->mixer_mask : 0;
}
void obs_output_remove_encoder(struct obs_output *output,
@ -1476,6 +1503,7 @@ static void default_raw_video_callback(void *param, struct video_data *frame)
output->total_frames++;
}
static void default_raw_audio_callback(void *param, size_t mix_idx,
struct audio_data *frames)
{
@ -1483,9 +1511,10 @@ static void default_raw_audio_callback(void *param, size_t mix_idx,
if (!data_active(output))
return;
output->info.raw_audio(output->context.data, frames);
UNUSED_PARAMETER(mix_idx);
if (output->info.raw_audio2)
output->info.raw_audio2(output->context.data, mix_idx, frames);
else
output->info.raw_audio(output->context.data, frames);
}
static inline void start_audio_encoders(struct obs_output *output,
@ -1499,6 +1528,25 @@ static inline void start_audio_encoders(struct obs_output *output,
}
}
static inline void start_raw_audio(obs_output_t *output)
{
if (output->info.raw_audio2) {
for (int idx = 0; idx < MAX_AUDIO_MIXES; idx++) {
if ((output->mixer_mask & ((size_t)1 << idx)) != 0) {
audio_output_connect(output->audio, idx,
get_audio_conversion(output),
default_raw_audio_callback,
output);
}
}
} else {
audio_output_connect(output->audio, get_first_mixer(output),
get_audio_conversion(output),
default_raw_audio_callback,
output);
}
}
static void reset_packet_data(obs_output_t *output)
{
output->received_audio = false;
@ -1557,9 +1605,7 @@ static void hook_data_capture(struct obs_output *output, bool encoded,
get_video_conversion(output),
default_raw_video_callback, output);
if (has_audio)
audio_output_connect(output->audio, output->mixer_idx,
get_audio_conversion(output),
default_raw_audio_callback, output);
start_raw_audio(output);
}
}
@ -1786,6 +1832,25 @@ static inline void stop_audio_encoders(obs_output_t *output,
}
}
static inline void stop_raw_audio(obs_output_t *output)
{
if (output->info.raw_audio2) {
for (int idx = 0; idx < MAX_AUDIO_MIXES; idx++) {
if ((output->mixer_mask & ((size_t)1 << idx)) != 0) {
audio_output_disconnect(output->audio,
idx,
default_raw_audio_callback,
output);
}
}
} else {
audio_output_disconnect(output->audio,
get_first_mixer(output),
default_raw_audio_callback,
output);
}
}
static void *end_data_capture_thread(void *data)
{
bool encoded, has_video, has_audio, has_service;
@ -1812,9 +1877,7 @@ static void *end_data_capture_thread(void *data)
stop_raw_video(output->video,
default_raw_video_callback, output);
if (has_audio)
audio_output_disconnect(output->audio,
output->mixer_idx,
default_raw_audio_callback, output);
stop_raw_audio(output);
}
if (has_service)

View File

@ -71,6 +71,9 @@ struct obs_output_info {
/* only used with encoded outputs, separated with semicolon */
const char *encoded_video_codecs;
const char *encoded_audio_codecs;
/* raw audio callback for multi track outputs */
void (*raw_audio2)(void *data, size_t idx, struct audio_data *frames);
};
EXPORT void obs_register_output_s(const struct obs_output_info *info,

View File

@ -1632,6 +1632,12 @@ EXPORT void obs_output_set_mixer(obs_output_t *output, size_t mixer_idx);
/** Gets the current audio mixer for non-encoded outputs */
EXPORT size_t obs_output_get_mixer(const obs_output_t *output);
/** Sets the current audio mixes (mask) for a non-encoded multi-track output */
EXPORT void obs_output_set_mixers(obs_output_t *output, size_t mixers);
/** Gets the current audio mixes (mask) for a non-encoded multi-track output */
EXPORT size_t obs_output_get_mixers(const obs_output_t *output);
/**
* Sets the current video encoder associated with this output,
* required for encoded outputs