obs-libfdk.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. #include <obs-module.h>
  2. #ifdef DEBUG
  3. #ifndef _DEBUG
  4. #define _DEBUG
  5. #endif
  6. #undef DEBUG
  7. #endif
  8. #include <fdk-aac/aacenc_lib.h>
  9. static const char *libfdk_get_error(AACENC_ERROR err)
  10. {
  11. switch (err) {
  12. case AACENC_OK:
  13. return "No error";
  14. case AACENC_INVALID_HANDLE:
  15. return "Invalid handle";
  16. case AACENC_MEMORY_ERROR:
  17. return "Memory allocation error";
  18. case AACENC_UNSUPPORTED_PARAMETER:
  19. return "Unsupported parameter";
  20. case AACENC_INVALID_CONFIG:
  21. return "Invalid config";
  22. case AACENC_INIT_ERROR:
  23. return "Initialization error";
  24. case AACENC_INIT_AAC_ERROR:
  25. return "AAC library initialization error";
  26. case AACENC_INIT_SBR_ERROR:
  27. return "SBR library initialization error";
  28. case AACENC_INIT_TP_ERROR:
  29. return "Transport library initialization error";
  30. case AACENC_INIT_META_ERROR:
  31. return "Metadata library initialization error";
  32. case AACENC_ENCODE_ERROR:
  33. return "Encoding error";
  34. case AACENC_ENCODE_EOF:
  35. return "End of file";
  36. default:
  37. return "Unknown error";
  38. }
  39. }
  40. typedef struct libfdk_encoder {
  41. obs_encoder_t *encoder;
  42. int channels, sample_rate;
  43. HANDLE_AACENCODER fdkhandle;
  44. AACENC_InfoStruct info;
  45. uint64_t total_samples;
  46. int frame_size_bytes;
  47. uint8_t *packet_buffer;
  48. int packet_buffer_size;
  49. } libfdk_encoder_t;
  50. static const char *libfdk_getname(void *unused)
  51. {
  52. UNUSED_PARAMETER(unused);
  53. return obs_module_text("LibFDK");
  54. }
  55. static obs_properties_t *libfdk_properties(void *unused)
  56. {
  57. UNUSED_PARAMETER(unused);
  58. obs_properties_t *props = obs_properties_create();
  59. obs_properties_add_int(props, "bitrate", obs_module_text("Bitrate"), 32,
  60. 1024, 32);
  61. obs_properties_add_bool(props, "afterburner",
  62. obs_module_text("Afterburner"));
  63. return props;
  64. }
  65. static void libfdk_defaults(obs_data_t *settings)
  66. {
  67. obs_data_set_default_int(settings, "bitrate", 128);
  68. obs_data_set_default_bool(settings, "afterburner", true);
  69. }
  70. #define CHECK_LIBFDK(r) \
  71. if ((err = (r)) != AACENC_OK) { \
  72. blog(LOG_ERROR, #r " failed: %s", libfdk_get_error(err)); \
  73. goto fail; \
  74. }
  75. static void *libfdk_create(obs_data_t *settings, obs_encoder_t *encoder)
  76. {
  77. bool hasFdkHandle = false;
  78. libfdk_encoder_t *enc = 0;
  79. int bitrate = (int)obs_data_get_int(settings, "bitrate") * 1000;
  80. int afterburner = obs_data_get_bool(settings, "afterburner") ? 1 : 0;
  81. audio_t *audio = obs_encoder_audio(encoder);
  82. int mode = 0;
  83. AACENC_ERROR err;
  84. if (!bitrate) {
  85. blog(LOG_ERROR, "Invalid bitrate");
  86. return NULL;
  87. }
  88. enc = bzalloc(sizeof(libfdk_encoder_t));
  89. enc->encoder = encoder;
  90. enc->channels = (int)audio_output_get_channels(audio);
  91. enc->sample_rate = audio_output_get_sample_rate(audio);
  92. switch (enc->channels) {
  93. case 1:
  94. mode = MODE_1;
  95. break;
  96. case 2:
  97. mode = MODE_2;
  98. break;
  99. case 3:
  100. mode = MODE_1_2;
  101. break;
  102. case 4:
  103. mode = MODE_1_2_1;
  104. break;
  105. case 5:
  106. mode = MODE_1_2_2;
  107. break;
  108. case 6:
  109. mode = MODE_1_2_2_1;
  110. break;
  111. /* lib_fdk-aac > 1.3 required for 7.1 surround;
  112. * uncomment if available on linux build
  113. */
  114. #ifndef __linux__
  115. case 8:
  116. mode = MODE_7_1_REAR_SURROUND;
  117. break;
  118. #endif
  119. default:
  120. blog(LOG_ERROR, "Invalid channel count");
  121. goto fail;
  122. }
  123. CHECK_LIBFDK(aacEncOpen(&enc->fdkhandle, 0, enc->channels));
  124. hasFdkHandle = true;
  125. CHECK_LIBFDK(aacEncoder_SetParam(enc->fdkhandle, AACENC_AOT,
  126. 2)); // MPEG-4 AAC-LC
  127. CHECK_LIBFDK(aacEncoder_SetParam(enc->fdkhandle, AACENC_SAMPLERATE,
  128. enc->sample_rate));
  129. CHECK_LIBFDK(
  130. aacEncoder_SetParam(enc->fdkhandle, AACENC_CHANNELMODE, mode));
  131. CHECK_LIBFDK(
  132. aacEncoder_SetParam(enc->fdkhandle, AACENC_CHANNELORDER, 1));
  133. CHECK_LIBFDK(
  134. aacEncoder_SetParam(enc->fdkhandle, AACENC_BITRATEMODE, 0));
  135. CHECK_LIBFDK(
  136. aacEncoder_SetParam(enc->fdkhandle, AACENC_BITRATE, bitrate));
  137. CHECK_LIBFDK(aacEncoder_SetParam(enc->fdkhandle, AACENC_TRANSMUX, 0));
  138. CHECK_LIBFDK(aacEncoder_SetParam(enc->fdkhandle, AACENC_AFTERBURNER,
  139. afterburner));
  140. CHECK_LIBFDK(aacEncEncode(enc->fdkhandle, NULL, NULL, NULL, NULL));
  141. CHECK_LIBFDK(aacEncInfo(enc->fdkhandle, &enc->info));
  142. enc->frame_size_bytes = enc->info.frameLength * 2 * enc->channels;
  143. enc->packet_buffer_size = enc->channels * 768;
  144. if (enc->packet_buffer_size < 8192)
  145. enc->packet_buffer_size = 8192;
  146. enc->packet_buffer = bmalloc(enc->packet_buffer_size);
  147. blog(LOG_INFO, "libfdk_aac encoder created");
  148. blog(LOG_INFO, "libfdk_aac bitrate: %d, channels: %d", bitrate / 1000,
  149. enc->channels);
  150. return enc;
  151. fail:
  152. if (hasFdkHandle)
  153. aacEncClose(&enc->fdkhandle);
  154. if (enc->packet_buffer)
  155. bfree(enc->packet_buffer);
  156. if (enc)
  157. bfree(enc);
  158. blog(LOG_WARNING, "libfdk_aac encoder creation failed");
  159. return 0;
  160. }
  161. static void libfdk_destroy(void *data)
  162. {
  163. libfdk_encoder_t *enc = data;
  164. aacEncClose(&enc->fdkhandle);
  165. bfree(enc->packet_buffer);
  166. bfree(enc);
  167. blog(LOG_INFO, "libfdk_aac encoder destroyed");
  168. }
  169. static bool libfdk_encode(void *data, struct encoder_frame *frame,
  170. struct encoder_packet *packet, bool *received_packet)
  171. {
  172. libfdk_encoder_t *enc = data;
  173. AACENC_BufDesc in_buf = {0};
  174. AACENC_BufDesc out_buf = {0};
  175. AACENC_InArgs in_args = {0};
  176. AACENC_OutArgs out_args = {0};
  177. int in_identifier = IN_AUDIO_DATA;
  178. int in_size, in_elem_size;
  179. int out_identifier = OUT_BITSTREAM_DATA;
  180. int out_size, out_elem_size;
  181. void *in_ptr;
  182. void *out_ptr;
  183. AACENC_ERROR err;
  184. int64_t encoderDelay;
  185. in_ptr = frame->data[0];
  186. in_size = enc->frame_size_bytes;
  187. in_elem_size = 2;
  188. in_args.numInSamples = enc->info.frameLength * enc->channels;
  189. in_buf.numBufs = 1;
  190. in_buf.bufs = &in_ptr;
  191. in_buf.bufferIdentifiers = &in_identifier;
  192. in_buf.bufSizes = &in_size;
  193. in_buf.bufElSizes = &in_elem_size;
  194. out_ptr = enc->packet_buffer;
  195. out_size = enc->packet_buffer_size;
  196. out_elem_size = 1;
  197. out_buf.numBufs = 1;
  198. out_buf.bufs = &out_ptr;
  199. out_buf.bufferIdentifiers = &out_identifier;
  200. out_buf.bufSizes = &out_size;
  201. out_buf.bufElSizes = &out_elem_size;
  202. if ((err = aacEncEncode(enc->fdkhandle, &in_buf, &out_buf, &in_args,
  203. &out_args)) != AACENC_OK) {
  204. blog(LOG_ERROR, "Failed to encode frame: %s",
  205. libfdk_get_error(err));
  206. return false;
  207. }
  208. enc->total_samples += enc->info.frameLength;
  209. if (out_args.numOutBytes == 0) {
  210. *received_packet = false;
  211. return true;
  212. }
  213. *received_packet = true;
  214. #if (AACENCODER_LIB_VL0 >= 4)
  215. encoderDelay = enc->info.nDelay;
  216. #else
  217. encoderDelay = enc->info.encoderDelay;
  218. #endif
  219. packet->pts = enc->total_samples - encoderDelay;
  220. packet->dts = enc->total_samples - encoderDelay;
  221. packet->data = enc->packet_buffer;
  222. packet->size = out_args.numOutBytes;
  223. packet->type = OBS_ENCODER_AUDIO;
  224. packet->timebase_num = 1;
  225. packet->timebase_den = enc->sample_rate;
  226. return true;
  227. }
  228. static bool libfdk_extra_data(void *data, uint8_t **extra_data, size_t *size)
  229. {
  230. libfdk_encoder_t *enc = data;
  231. *size = enc->info.confSize;
  232. *extra_data = enc->info.confBuf;
  233. return true;
  234. }
  235. static void libfdk_audio_info(void *data, struct audio_convert_info *info)
  236. {
  237. UNUSED_PARAMETER(data);
  238. info->format = AUDIO_FORMAT_16BIT;
  239. }
  240. static size_t libfdk_frame_size(void *data)
  241. {
  242. libfdk_encoder_t *enc = data;
  243. return enc->info.frameLength;
  244. }
  245. struct obs_encoder_info obs_libfdk_encoder = {
  246. .id = "libfdk_aac",
  247. .type = OBS_ENCODER_AUDIO,
  248. .codec = "AAC",
  249. .get_name = libfdk_getname,
  250. .create = libfdk_create,
  251. .destroy = libfdk_destroy,
  252. .encode = libfdk_encode,
  253. .get_frame_size = libfdk_frame_size,
  254. .get_defaults = libfdk_defaults,
  255. .get_properties = libfdk_properties,
  256. .get_extra_data = libfdk_extra_data,
  257. .get_audio_info = libfdk_audio_info,
  258. };
  259. bool obs_module_load(void)
  260. {
  261. obs_register_encoder(&obs_libfdk_encoder);
  262. return true;
  263. }
  264. OBS_DECLARE_MODULE()
  265. OBS_MODULE_USE_DEFAULT_LOCALE("obs-libfdk", "en-US")