jp9000 f53df7da64 clang-format: Apply formatting
Code submissions have continually suffered from formatting
inconsistencies that constantly have to be addressed.  Using
clang-format simplifies this by making code formatting more consistent,
and allows automation of the code formatting so that maintainers can
focus more on the code itself instead of code formatting.
2019-06-23 23:49:10 -07:00

329 lines
7.6 KiB
C

#include <obs-module.h>
#ifdef DEBUG
#ifndef _DEBUG
#define _DEBUG
#endif
#undef DEBUG
#endif
#include <fdk-aac/aacenc_lib.h>
static const char *libfdk_get_error(AACENC_ERROR err)
{
switch (err) {
case AACENC_OK:
return "No error";
case AACENC_INVALID_HANDLE:
return "Invalid handle";
case AACENC_MEMORY_ERROR:
return "Memory allocation error";
case AACENC_UNSUPPORTED_PARAMETER:
return "Unsupported parameter";
case AACENC_INVALID_CONFIG:
return "Invalid config";
case AACENC_INIT_ERROR:
return "Initialization error";
case AACENC_INIT_AAC_ERROR:
return "AAC library initialization error";
case AACENC_INIT_SBR_ERROR:
return "SBR library initialization error";
case AACENC_INIT_TP_ERROR:
return "Transport library initialization error";
case AACENC_INIT_META_ERROR:
return "Metadata library initialization error";
case AACENC_ENCODE_ERROR:
return "Encoding error";
case AACENC_ENCODE_EOF:
return "End of file";
default:
return "Unknown error";
}
}
typedef struct libfdk_encoder {
obs_encoder_t *encoder;
int channels, sample_rate;
HANDLE_AACENCODER fdkhandle;
AACENC_InfoStruct info;
uint64_t total_samples;
int frame_size_bytes;
uint8_t *packet_buffer;
int packet_buffer_size;
} libfdk_encoder_t;
static const char *libfdk_getname(void *unused)
{
UNUSED_PARAMETER(unused);
return obs_module_text("LibFDK");
}
static obs_properties_t *libfdk_properties(void *unused)
{
UNUSED_PARAMETER(unused);
obs_properties_t *props = obs_properties_create();
obs_properties_add_int(props, "bitrate", obs_module_text("Bitrate"), 32,
1024, 32);
obs_properties_add_bool(props, "afterburner",
obs_module_text("Afterburner"));
return props;
}
static void libfdk_defaults(obs_data_t *settings)
{
obs_data_set_default_int(settings, "bitrate", 128);
obs_data_set_default_bool(settings, "afterburner", true);
}
#define CHECK_LIBFDK(r) \
if ((err = (r)) != AACENC_OK) { \
blog(LOG_ERROR, #r " failed: %s", libfdk_get_error(err)); \
goto fail; \
}
static void *libfdk_create(obs_data_t *settings, obs_encoder_t *encoder)
{
bool hasFdkHandle = false;
libfdk_encoder_t *enc = 0;
int bitrate = (int)obs_data_get_int(settings, "bitrate") * 1000;
int afterburner = obs_data_get_bool(settings, "afterburner") ? 1 : 0;
audio_t *audio = obs_encoder_audio(encoder);
int mode = 0;
AACENC_ERROR err;
if (!bitrate) {
blog(LOG_ERROR, "Invalid bitrate");
return NULL;
}
enc = bzalloc(sizeof(libfdk_encoder_t));
enc->encoder = encoder;
enc->channels = (int)audio_output_get_channels(audio);
enc->sample_rate = audio_output_get_sample_rate(audio);
switch (enc->channels) {
case 1:
mode = MODE_1;
break;
case 2:
mode = MODE_2;
break;
case 3:
mode = MODE_1_2;
break;
case 4:
mode = MODE_1_2_1;
break;
case 5:
mode = MODE_1_2_2;
break;
case 6:
mode = MODE_1_2_2_1;
break;
/* lib_fdk-aac > 1.3 required for 7.1 surround;
* uncomment if available on linux build
*/
#ifndef __linux__
case 8:
mode = MODE_7_1_REAR_SURROUND;
break;
#endif
default:
blog(LOG_ERROR, "Invalid channel count");
goto fail;
}
CHECK_LIBFDK(aacEncOpen(&enc->fdkhandle, 0, enc->channels));
hasFdkHandle = true;
CHECK_LIBFDK(aacEncoder_SetParam(enc->fdkhandle, AACENC_AOT,
2)); // MPEG-4 AAC-LC
CHECK_LIBFDK(aacEncoder_SetParam(enc->fdkhandle, AACENC_SAMPLERATE,
enc->sample_rate));
CHECK_LIBFDK(
aacEncoder_SetParam(enc->fdkhandle, AACENC_CHANNELMODE, mode));
CHECK_LIBFDK(
aacEncoder_SetParam(enc->fdkhandle, AACENC_CHANNELORDER, 1));
CHECK_LIBFDK(
aacEncoder_SetParam(enc->fdkhandle, AACENC_BITRATEMODE, 0));
CHECK_LIBFDK(
aacEncoder_SetParam(enc->fdkhandle, AACENC_BITRATE, bitrate));
CHECK_LIBFDK(aacEncoder_SetParam(enc->fdkhandle, AACENC_TRANSMUX, 0));
CHECK_LIBFDK(aacEncoder_SetParam(enc->fdkhandle, AACENC_AFTERBURNER,
afterburner));
CHECK_LIBFDK(aacEncEncode(enc->fdkhandle, NULL, NULL, NULL, NULL));
CHECK_LIBFDK(aacEncInfo(enc->fdkhandle, &enc->info));
enc->frame_size_bytes = enc->info.frameLength * 2 * enc->channels;
enc->packet_buffer_size = enc->channels * 768;
if (enc->packet_buffer_size < 8192)
enc->packet_buffer_size = 8192;
enc->packet_buffer = bmalloc(enc->packet_buffer_size);
blog(LOG_INFO, "libfdk_aac encoder created");
blog(LOG_INFO, "libfdk_aac bitrate: %d, channels: %d", bitrate / 1000,
enc->channels);
return enc;
fail:
if (hasFdkHandle)
aacEncClose(&enc->fdkhandle);
if (enc->packet_buffer)
bfree(enc->packet_buffer);
if (enc)
bfree(enc);
blog(LOG_WARNING, "libfdk_aac encoder creation failed");
return 0;
}
static void libfdk_destroy(void *data)
{
libfdk_encoder_t *enc = data;
aacEncClose(&enc->fdkhandle);
bfree(enc->packet_buffer);
bfree(enc);
blog(LOG_INFO, "libfdk_aac encoder destroyed");
}
static bool libfdk_encode(void *data, struct encoder_frame *frame,
struct encoder_packet *packet, bool *received_packet)
{
libfdk_encoder_t *enc = data;
AACENC_BufDesc in_buf = {0};
AACENC_BufDesc out_buf = {0};
AACENC_InArgs in_args = {0};
AACENC_OutArgs out_args = {0};
int in_identifier = IN_AUDIO_DATA;
int in_size, in_elem_size;
int out_identifier = OUT_BITSTREAM_DATA;
int out_size, out_elem_size;
void *in_ptr;
void *out_ptr;
AACENC_ERROR err;
int64_t encoderDelay;
in_ptr = frame->data[0];
in_size = enc->frame_size_bytes;
in_elem_size = 2;
in_args.numInSamples = enc->info.frameLength * enc->channels;
in_buf.numBufs = 1;
in_buf.bufs = &in_ptr;
in_buf.bufferIdentifiers = &in_identifier;
in_buf.bufSizes = &in_size;
in_buf.bufElSizes = &in_elem_size;
out_ptr = enc->packet_buffer;
out_size = enc->packet_buffer_size;
out_elem_size = 1;
out_buf.numBufs = 1;
out_buf.bufs = &out_ptr;
out_buf.bufferIdentifiers = &out_identifier;
out_buf.bufSizes = &out_size;
out_buf.bufElSizes = &out_elem_size;
if ((err = aacEncEncode(enc->fdkhandle, &in_buf, &out_buf, &in_args,
&out_args)) != AACENC_OK) {
blog(LOG_ERROR, "Failed to encode frame: %s",
libfdk_get_error(err));
return false;
}
enc->total_samples += enc->info.frameLength;
if (out_args.numOutBytes == 0) {
*received_packet = false;
return true;
}
*received_packet = true;
#if (AACENCODER_LIB_VL0 >= 4)
encoderDelay = enc->info.nDelay;
#else
encoderDelay = enc->info.encoderDelay;
#endif
packet->pts = enc->total_samples - encoderDelay;
packet->dts = enc->total_samples - encoderDelay;
packet->data = enc->packet_buffer;
packet->size = out_args.numOutBytes;
packet->type = OBS_ENCODER_AUDIO;
packet->timebase_num = 1;
packet->timebase_den = enc->sample_rate;
return true;
}
static bool libfdk_extra_data(void *data, uint8_t **extra_data, size_t *size)
{
libfdk_encoder_t *enc = data;
*size = enc->info.confSize;
*extra_data = enc->info.confBuf;
return true;
}
static void libfdk_audio_info(void *data, struct audio_convert_info *info)
{
UNUSED_PARAMETER(data);
info->format = AUDIO_FORMAT_16BIT;
}
static size_t libfdk_frame_size(void *data)
{
libfdk_encoder_t *enc = data;
return enc->info.frameLength;
}
struct obs_encoder_info obs_libfdk_encoder = {
.id = "libfdk_aac",
.type = OBS_ENCODER_AUDIO,
.codec = "AAC",
.get_name = libfdk_getname,
.create = libfdk_create,
.destroy = libfdk_destroy,
.encode = libfdk_encode,
.get_frame_size = libfdk_frame_size,
.get_defaults = libfdk_defaults,
.get_properties = libfdk_properties,
.get_extra_data = libfdk_extra_data,
.get_audio_info = libfdk_audio_info,
};
bool obs_module_load(void)
{
obs_register_encoder(&obs_libfdk_encoder);
return true;
}
OBS_DECLARE_MODULE()
OBS_MODULE_USE_DEFAULT_LOCALE("obs-libfdk", "en-US")