encoder.cpp 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384
  1. #include <util/darray.h>
  2. #include <util/dstr.hpp>
  3. #include <obs-module.h>
  4. #include <algorithm>
  5. #include <cstdlib>
  6. #include <initializer_list>
  7. #include <memory>
  8. #include <mutex>
  9. #include <vector>
  10. #ifndef _WIN32
  11. #include <AudioToolbox/AudioToolbox.h>
  12. #endif
  13. #define CA_LOG(level, format, ...) \
  14. blog(level, "[CoreAudio encoder]: " format, ##__VA_ARGS__)
  15. #define CA_LOG_ENCODER(format_name, encoder, level, format, ...) \
  16. blog(level, "[CoreAudio %s: '%s']: " format, \
  17. format_name, obs_encoder_get_name(encoder), \
  18. ##__VA_ARGS__)
  19. #define CA_BLOG(level, format, ...) \
  20. CA_LOG_ENCODER(ca->format_name, ca->encoder, level, format, \
  21. ##__VA_ARGS__)
  22. #define CA_CO_LOG(level, format, ...) \
  23. do { \
  24. if (ca) \
  25. CA_BLOG(level, format, ##__VA_ARGS__); \
  26. else \
  27. CA_LOG(level, format, ##__VA_ARGS__); \
  28. } while (false)
  29. #ifdef _WIN32
  30. #include "windows-imports.h"
  31. #endif
  32. using namespace std;
  33. namespace {
  34. struct asbd_builder {
  35. AudioStreamBasicDescription asbd;
  36. asbd_builder &sample_rate(Float64 rate)
  37. {
  38. asbd.mSampleRate = rate;
  39. return *this;
  40. }
  41. asbd_builder &format_id(UInt32 format)
  42. {
  43. asbd.mFormatID = format;
  44. return *this;
  45. }
  46. asbd_builder &format_flags(UInt32 flags)
  47. {
  48. asbd.mFormatFlags = flags;
  49. return *this;
  50. }
  51. asbd_builder &bytes_per_packet(UInt32 bytes)
  52. {
  53. asbd.mBytesPerPacket = bytes;
  54. return *this;
  55. }
  56. asbd_builder &frames_per_packet(UInt32 frames)
  57. {
  58. asbd.mFramesPerPacket = frames;
  59. return *this;
  60. }
  61. asbd_builder &bytes_per_frame(UInt32 bytes)
  62. {
  63. asbd.mBytesPerFrame = bytes;
  64. return *this;
  65. }
  66. asbd_builder &channels_per_frame(UInt32 channels)
  67. {
  68. asbd.mChannelsPerFrame = channels;
  69. return *this;
  70. }
  71. asbd_builder &bits_per_channel(UInt32 bits)
  72. {
  73. asbd.mBitsPerChannel = bits;
  74. return *this;
  75. }
  76. };
  77. struct ca_encoder {
  78. obs_encoder_t *encoder;
  79. const char *format_name;
  80. UInt32 format_id;
  81. const initializer_list<UInt32> *allowed_formats;
  82. AudioConverterRef converter;
  83. size_t output_buffer_size;
  84. vector<uint8_t> output_buffer;
  85. size_t out_frames_per_packet;
  86. size_t in_packets;
  87. size_t in_frame_size;
  88. size_t in_bytes_required;
  89. DARRAY(uint8_t) input_buffer;
  90. size_t bytes_read;
  91. uint64_t total_samples;
  92. uint64_t samples_per_second;
  93. vector<uint8_t> extra_data;
  94. size_t channels;
  95. ~ca_encoder()
  96. {
  97. if (converter)
  98. AudioConverterDispose(converter);
  99. da_free(input_buffer);
  100. }
  101. };
  102. typedef struct ca_encoder ca_encoder;
  103. }
  104. namespace std {
  105. #ifndef _WIN32
  106. template <>
  107. struct default_delete<remove_pointer<CFErrorRef>::type> {
  108. void operator()(remove_pointer<CFErrorRef>::type *err)
  109. {
  110. CFRelease(err);
  111. }
  112. };
  113. template <>
  114. struct default_delete<remove_pointer<CFStringRef>::type> {
  115. void operator()(remove_pointer<CFStringRef>::type *str)
  116. {
  117. CFRelease(str);
  118. }
  119. };
  120. #endif
  121. template <>
  122. struct default_delete<remove_pointer<AudioConverterRef>::type> {
  123. void operator()(AudioConverterRef converter)
  124. {
  125. AudioConverterDispose(converter);
  126. }
  127. };
  128. }
  129. template <typename T>
  130. using cf_ptr = unique_ptr<typename remove_pointer<T>::type>;
  131. #ifndef _MSC_VER
  132. __attribute__((__format__(__printf__, 3, 4)))
  133. #endif
  134. static void log_to_dstr(DStr &str, ca_encoder *ca, const char *fmt, ...)
  135. {
  136. dstr prev_str = *static_cast<dstr*>(str);
  137. va_list args;
  138. va_start(args, fmt);
  139. dstr_vcatf(str, fmt, args);
  140. va_end(args);
  141. if (str->array)
  142. return;
  143. char array[4096];
  144. va_start(args, fmt);
  145. vsnprintf(array, 4096, fmt, args);
  146. va_end(args);
  147. array[4095] = 0;
  148. if (!prev_str.array && !prev_str.len)
  149. CA_CO_LOG(LOG_ERROR, "Could not allocate buffer for logging:"
  150. "\n'%s'", array);
  151. else
  152. CA_CO_LOG(LOG_ERROR, "Could not allocate buffer for logging:"
  153. "\n'%s'\nPrevious log entries:\n%s",
  154. array, prev_str.array);
  155. bfree(prev_str.array);
  156. }
  157. static const char *flush_log(DStr &log)
  158. {
  159. if (!log->array || !log->len)
  160. return "";
  161. if (log->array[log->len - 1] == '\n') {
  162. log->array[log->len - 1] = 0; //Get rid of last newline
  163. log->len -= 1;
  164. }
  165. return log->array;
  166. }
  167. #define CA_CO_DLOG_(level, format) \
  168. CA_CO_LOG(level, format "%s%s", \
  169. log->array ? ":\n" : "", flush_log(log))
  170. #define CA_CO_DLOG(level, format, ...) \
  171. CA_CO_LOG(level, format "%s%s", ##__VA_ARGS__, \
  172. log->array ? ":\n" : "", flush_log(log))
  173. static const char *aac_get_name(void)
  174. {
  175. return obs_module_text("CoreAudioAAC");
  176. }
  177. static const char *code_to_str(OSStatus code)
  178. {
  179. switch (code) {
  180. #define HANDLE_CODE(c) case c: return #c
  181. HANDLE_CODE(kAudio_UnimplementedError);
  182. HANDLE_CODE(kAudio_FileNotFoundError);
  183. HANDLE_CODE(kAudio_FilePermissionError);
  184. HANDLE_CODE(kAudio_TooManyFilesOpenError);
  185. HANDLE_CODE(kAudio_BadFilePathError);
  186. HANDLE_CODE(kAudio_ParamError);
  187. HANDLE_CODE(kAudio_MemFullError);
  188. HANDLE_CODE(kAudioConverterErr_FormatNotSupported);
  189. HANDLE_CODE(kAudioConverterErr_OperationNotSupported);
  190. HANDLE_CODE(kAudioConverterErr_PropertyNotSupported);
  191. HANDLE_CODE(kAudioConverterErr_InvalidInputSize);
  192. HANDLE_CODE(kAudioConverterErr_InvalidOutputSize);
  193. HANDLE_CODE(kAudioConverterErr_UnspecifiedError);
  194. HANDLE_CODE(kAudioConverterErr_BadPropertySizeError);
  195. HANDLE_CODE(kAudioConverterErr_RequiresPacketDescriptionsError);
  196. HANDLE_CODE(kAudioConverterErr_InputSampleRateOutOfRange);
  197. HANDLE_CODE(kAudioConverterErr_OutputSampleRateOutOfRange);
  198. #undef HANDLE_CODE
  199. default: break;
  200. }
  201. return NULL;
  202. }
  203. static DStr osstatus_to_dstr(OSStatus code)
  204. {
  205. DStr result;
  206. #ifndef _WIN32
  207. cf_ptr<CFErrorRef> err{CFErrorCreate(kCFAllocatorDefault,
  208. kCFErrorDomainOSStatus, code, NULL)};
  209. cf_ptr<CFStringRef> str{CFErrorCopyDescription(err.get())};
  210. CFIndex length = CFStringGetLength(str.get());
  211. CFIndex max_size = CFStringGetMaximumSizeForEncoding(length,
  212. kCFStringEncodingUTF8);
  213. dstr_ensure_capacity(result, max_size);
  214. if (result->array && CFStringGetCString(str.get(), result->array,
  215. max_size, kCFStringEncodingUTF8)) {
  216. dstr_resize(result, strlen(result->array));
  217. return result;
  218. }
  219. #endif
  220. const char *code_str = code_to_str(code);
  221. dstr_printf(result, "%s%s%d%s",
  222. code_str ? code_str : "",
  223. code_str ? " (" : "",
  224. static_cast<int>(code),
  225. code_str ? ")" : "");
  226. return result;
  227. }
  228. static void log_osstatus(int log_level, ca_encoder *ca, const char *context,
  229. OSStatus code)
  230. {
  231. DStr str = osstatus_to_dstr(code);
  232. if (ca)
  233. CA_BLOG(log_level, "Error in %s: %s", context, str->array);
  234. else
  235. CA_LOG(log_level, "Error in %s: %s", context, str->array);
  236. }
  237. static const char *format_id_to_str(UInt32 format_id)
  238. {
  239. #define FORMAT_TO_STR(x) case x: return #x
  240. switch (format_id) {
  241. FORMAT_TO_STR(kAudioFormatLinearPCM);
  242. FORMAT_TO_STR(kAudioFormatAC3);
  243. FORMAT_TO_STR(kAudioFormat60958AC3);
  244. FORMAT_TO_STR(kAudioFormatAppleIMA4);
  245. FORMAT_TO_STR(kAudioFormatMPEG4AAC);
  246. FORMAT_TO_STR(kAudioFormatMPEG4CELP);
  247. FORMAT_TO_STR(kAudioFormatMPEG4HVXC);
  248. FORMAT_TO_STR(kAudioFormatMPEG4TwinVQ);
  249. FORMAT_TO_STR(kAudioFormatMACE3);
  250. FORMAT_TO_STR(kAudioFormatMACE6);
  251. FORMAT_TO_STR(kAudioFormatULaw);
  252. FORMAT_TO_STR(kAudioFormatALaw);
  253. FORMAT_TO_STR(kAudioFormatQDesign);
  254. FORMAT_TO_STR(kAudioFormatQDesign2);
  255. FORMAT_TO_STR(kAudioFormatQUALCOMM);
  256. FORMAT_TO_STR(kAudioFormatMPEGLayer1);
  257. FORMAT_TO_STR(kAudioFormatMPEGLayer2);
  258. FORMAT_TO_STR(kAudioFormatMPEGLayer3);
  259. FORMAT_TO_STR(kAudioFormatTimeCode);
  260. FORMAT_TO_STR(kAudioFormatMIDIStream);
  261. FORMAT_TO_STR(kAudioFormatParameterValueStream);
  262. FORMAT_TO_STR(kAudioFormatAppleLossless);
  263. FORMAT_TO_STR(kAudioFormatMPEG4AAC_HE);
  264. FORMAT_TO_STR(kAudioFormatMPEG4AAC_LD);
  265. FORMAT_TO_STR(kAudioFormatMPEG4AAC_ELD);
  266. FORMAT_TO_STR(kAudioFormatMPEG4AAC_ELD_SBR);
  267. FORMAT_TO_STR(kAudioFormatMPEG4AAC_HE_V2);
  268. FORMAT_TO_STR(kAudioFormatMPEG4AAC_Spatial);
  269. FORMAT_TO_STR(kAudioFormatAMR);
  270. FORMAT_TO_STR(kAudioFormatAudible);
  271. FORMAT_TO_STR(kAudioFormatiLBC);
  272. FORMAT_TO_STR(kAudioFormatDVIIntelIMA);
  273. FORMAT_TO_STR(kAudioFormatMicrosoftGSM);
  274. FORMAT_TO_STR(kAudioFormatAES3);
  275. }
  276. #undef FORMAT_TO_STR
  277. return "Unknown format";
  278. }
  279. static void aac_destroy(void *data)
  280. {
  281. ca_encoder *ca = static_cast<ca_encoder*>(data);
  282. delete ca;
  283. }
  284. template <typename Func>
  285. static bool query_converter_property_raw(DStr &log, ca_encoder *ca,
  286. AudioFormatPropertyID property,
  287. const char *get_property_info, const char *get_property,
  288. AudioConverterRef converter, Func &&func)
  289. {
  290. UInt32 size = 0;
  291. OSStatus code = AudioConverterGetPropertyInfo(converter, property,
  292. &size, nullptr);
  293. if (code) {
  294. log_to_dstr(log, ca, "%s: %s\n", get_property_info,
  295. osstatus_to_dstr(code)->array);
  296. return false;
  297. }
  298. if (!size) {
  299. log_to_dstr(log, ca, "%s returned 0 size\n", get_property_info);
  300. return false;
  301. }
  302. vector<uint8_t> buffer;
  303. try {
  304. buffer.resize(size);
  305. } catch (...) {
  306. log_to_dstr(log, ca, "Failed to allocate %u bytes for %s\n",
  307. static_cast<uint32_t>(size), get_property);
  308. return false;
  309. }
  310. code = AudioConverterGetProperty(converter, property, &size,
  311. buffer.data());
  312. if (code) {
  313. log_to_dstr(log, ca, "%s: %s\n", get_property,
  314. osstatus_to_dstr(code)->array);
  315. return false;
  316. }
  317. func(size, static_cast<void*>(buffer.data()));
  318. return true;
  319. }
  320. #define EXPAND_CONVERTER_NAMES(x) x, \
  321. "AudioConverterGetPropertyInfo(" #x ")", \
  322. "AudioConverterGetProperty(" #x ")"
  323. template <typename Func>
  324. static bool enumerate_bitrates(DStr &log, ca_encoder *ca,
  325. AudioConverterRef converter, Func &&func)
  326. {
  327. auto helper = [&](UInt32 size, void *data)
  328. {
  329. auto range = static_cast<AudioValueRange*>(data);
  330. size_t num_ranges = size / sizeof(AudioValueRange);
  331. for (size_t i = 0; i < num_ranges; i++)
  332. func(static_cast<UInt32>(range[i].mMinimum),
  333. static_cast<UInt32>(range[i].mMaximum));
  334. };
  335. return query_converter_property_raw(log, ca, EXPAND_CONVERTER_NAMES(
  336. kAudioConverterApplicableEncodeBitRates),
  337. converter, helper);
  338. }
  339. static bool bitrate_valid(DStr &log, ca_encoder *ca,
  340. AudioConverterRef converter, UInt32 bitrate)
  341. {
  342. bool valid = false;
  343. auto helper = [&](UInt32 min_, UInt32 max_)
  344. {
  345. if (min_ == bitrate || max_ == bitrate)
  346. valid = true;
  347. };
  348. enumerate_bitrates(log, ca, converter, helper);
  349. return valid;
  350. }
  351. static bool create_encoder(DStr &log, ca_encoder *ca,
  352. AudioStreamBasicDescription *in,
  353. AudioStreamBasicDescription *out,
  354. UInt32 format_id, UInt32 bitrate, UInt32 samplerate,
  355. UInt32 rate_control)
  356. {
  357. #define STATUS_CHECK(c) \
  358. code = c; \
  359. if (code) { \
  360. log_to_dstr(log, ca, #c " returned %s", \
  361. osstatus_to_dstr(code)->array); \
  362. return false; \
  363. }
  364. Float64 srate = samplerate ?
  365. (Float64)samplerate :
  366. (Float64)ca->samples_per_second;
  367. auto out_ = asbd_builder()
  368. .sample_rate(srate)
  369. .channels_per_frame((UInt32)ca->channels)
  370. .format_id(format_id)
  371. .asbd;
  372. UInt32 size = sizeof(*out);
  373. OSStatus code;
  374. STATUS_CHECK(AudioFormatGetProperty(kAudioFormatProperty_FormatInfo,
  375. 0, NULL, &size, &out_));
  376. *out = out_;
  377. STATUS_CHECK(AudioConverterNew(in, out, &ca->converter))
  378. STATUS_CHECK(AudioConverterSetProperty(ca->converter,
  379. kAudioCodecPropertyBitRateControlMode,
  380. sizeof(rate_control), &rate_control));
  381. if (!bitrate_valid(log, ca, ca->converter, bitrate)) {
  382. log_to_dstr(log, ca, "Encoder does not support bitrate %u "
  383. "for format %s (0x%x)\n",
  384. (uint32_t)bitrate, format_id_to_str(format_id),
  385. (uint32_t)format_id);
  386. return false;
  387. }
  388. ca->format_id = format_id;
  389. return true;
  390. #undef STATUS_CHECK
  391. }
  392. static const initializer_list<UInt32> aac_formats = {
  393. kAudioFormatMPEG4AAC_HE_V2,
  394. kAudioFormatMPEG4AAC_HE,
  395. kAudioFormatMPEG4AAC,
  396. };
  397. static const initializer_list<UInt32> aac_lc_formats = {
  398. kAudioFormatMPEG4AAC,
  399. };
  400. static void *aac_create(obs_data_t *settings, obs_encoder_t *encoder)
  401. {
  402. #define STATUS_CHECK(c) \
  403. code = c; \
  404. if (code) { \
  405. log_osstatus(LOG_ERROR, ca.get(), #c, code); \
  406. return nullptr; \
  407. }
  408. UInt32 bitrate = (UInt32)obs_data_get_int(settings, "bitrate") * 1000;
  409. if (!bitrate) {
  410. CA_LOG_ENCODER("AAC", encoder, LOG_ERROR,
  411. "Invalid bitrate specified");
  412. return NULL;
  413. }
  414. const enum audio_format format = AUDIO_FORMAT_FLOAT;
  415. if (is_audio_planar(format)) {
  416. CA_LOG_ENCODER("AAC", encoder, LOG_ERROR,
  417. "Got non-interleaved audio format %d", format);
  418. return NULL;
  419. }
  420. unique_ptr<ca_encoder> ca;
  421. try {
  422. ca.reset(new ca_encoder());
  423. } catch (...) {
  424. CA_LOG_ENCODER("AAC", encoder, LOG_ERROR,
  425. "Could not allocate encoder");
  426. return nullptr;
  427. }
  428. ca->encoder = encoder;
  429. ca->format_name = "AAC";
  430. audio_t *audio = obs_encoder_audio(encoder);
  431. const struct audio_output_info *aoi = audio_output_get_info(audio);
  432. ca->channels = audio_output_get_channels(audio);
  433. ca->samples_per_second = audio_output_get_sample_rate(audio);
  434. size_t bytes_per_frame = get_audio_size(format, aoi->speakers, 1);
  435. size_t bits_per_channel = get_audio_bytes_per_channel(format) * 8;
  436. auto in = asbd_builder()
  437. .sample_rate((Float64)ca->samples_per_second)
  438. .channels_per_frame((UInt32)ca->channels)
  439. .bytes_per_frame((UInt32)bytes_per_frame)
  440. .frames_per_packet(1)
  441. .bytes_per_packet((UInt32)(1 * bytes_per_frame))
  442. .bits_per_channel((UInt32)bits_per_channel)
  443. .format_id(kAudioFormatLinearPCM)
  444. .format_flags(kAudioFormatFlagsNativeEndian |
  445. kAudioFormatFlagIsPacked |
  446. kAudioFormatFlagIsFloat |
  447. 0)
  448. .asbd;
  449. AudioStreamBasicDescription out;
  450. UInt32 rate_control = kAudioCodecBitRateControlMode_Constant;
  451. if (obs_data_get_bool(settings, "allow he-aac")) {
  452. ca->allowed_formats = &aac_formats;
  453. } else {
  454. ca->allowed_formats = &aac_lc_formats;
  455. }
  456. auto samplerate =
  457. static_cast<UInt32>(obs_data_get_int(settings, "samplerate"));
  458. DStr log;
  459. bool encoder_created = false;
  460. for (UInt32 format_id : *ca->allowed_formats) {
  461. log_to_dstr(log, ca.get(), "Trying format %s (0x%x)\n",
  462. format_id_to_str(format_id),
  463. (uint32_t)format_id);
  464. if (!create_encoder(log, ca.get(), &in, &out, format_id,
  465. bitrate, samplerate, rate_control))
  466. continue;
  467. encoder_created = true;
  468. break;
  469. }
  470. if (!encoder_created) {
  471. CA_CO_DLOG(LOG_ERROR, "Could not create encoder for "
  472. "selected format%s",
  473. ca->allowed_formats->size() == 1 ? "" : "s");
  474. return nullptr;
  475. }
  476. if (log->len)
  477. CA_CO_DLOG_(LOG_DEBUG, "Encoder created");
  478. OSStatus code;
  479. UInt32 converter_quality = kAudioConverterQuality_Max;
  480. STATUS_CHECK(AudioConverterSetProperty(ca->converter,
  481. kAudioConverterCodecQuality,
  482. sizeof(converter_quality), &converter_quality));
  483. STATUS_CHECK(AudioConverterSetProperty(ca->converter,
  484. kAudioConverterEncodeBitRate,
  485. sizeof(bitrate), &bitrate));
  486. UInt32 size = sizeof(in);
  487. STATUS_CHECK(AudioConverterGetProperty(ca->converter,
  488. kAudioConverterCurrentInputStreamDescription,
  489. &size, &in));
  490. size = sizeof(out);
  491. STATUS_CHECK(AudioConverterGetProperty(ca->converter,
  492. kAudioConverterCurrentOutputStreamDescription,
  493. &size, &out));
  494. ca->in_frame_size = in.mBytesPerFrame;
  495. ca->in_packets = out.mFramesPerPacket / in.mFramesPerPacket;
  496. ca->in_bytes_required = ca->in_packets * ca->in_frame_size;
  497. ca->out_frames_per_packet = out.mFramesPerPacket;
  498. da_init(ca->input_buffer);
  499. ca->output_buffer_size = out.mBytesPerPacket;
  500. if (out.mBytesPerPacket == 0) {
  501. UInt32 max_packet_size = 0;
  502. size = sizeof(max_packet_size);
  503. code = AudioConverterGetProperty(ca->converter,
  504. kAudioConverterPropertyMaximumOutputPacketSize,
  505. &size, &max_packet_size);
  506. if (code) {
  507. log_osstatus(LOG_WARNING, ca.get(),
  508. "AudioConverterGetProperty(PacketSz)",
  509. code);
  510. ca->output_buffer_size = 32768;
  511. } else {
  512. ca->output_buffer_size = max_packet_size;
  513. }
  514. }
  515. try {
  516. ca->output_buffer.resize(ca->output_buffer_size);
  517. } catch (...) {
  518. CA_BLOG(LOG_ERROR, "Failed to allocate output buffer");
  519. return nullptr;
  520. }
  521. const char *format_name =
  522. out.mFormatID == kAudioFormatMPEG4AAC_HE_V2 ? "HE-AAC v2" :
  523. out.mFormatID == kAudioFormatMPEG4AAC_HE ? "HE-AAC" : "AAC";
  524. CA_BLOG(LOG_INFO, "settings:\n"
  525. "\tmode: %s\n"
  526. "\tbitrate: %u\n"
  527. "\tsample rate: %llu\n"
  528. "\tcbr: %s\n"
  529. "\toutput buffer: %lu",
  530. format_name, (unsigned int)bitrate / 1000,
  531. ca->samples_per_second,
  532. rate_control == kAudioCodecBitRateControlMode_Constant ?
  533. "on" : "off",
  534. (unsigned long)ca->output_buffer_size);
  535. return ca.release();
  536. #undef STATUS_CHECK
  537. }
  538. static OSStatus complex_input_data_proc(AudioConverterRef inAudioConverter,
  539. UInt32 *ioNumberDataPackets, AudioBufferList *ioData,
  540. AudioStreamPacketDescription **outDataPacketDescription,
  541. void *inUserData)
  542. {
  543. UNUSED_PARAMETER(inAudioConverter);
  544. UNUSED_PARAMETER(outDataPacketDescription);
  545. ca_encoder *ca = static_cast<ca_encoder*>(inUserData);
  546. if (ca->bytes_read) {
  547. da_erase_range(ca->input_buffer, 0, ca->bytes_read);
  548. ca->bytes_read = 0;
  549. }
  550. if (ca->input_buffer.num < ca->in_bytes_required) {
  551. *ioNumberDataPackets = 0;
  552. ioData->mBuffers[0].mData = NULL;
  553. return 1;
  554. }
  555. *ioNumberDataPackets =
  556. (UInt32)(ca->in_bytes_required / ca->in_frame_size);
  557. ioData->mNumberBuffers = 1;
  558. ioData->mBuffers[0].mData = ca->input_buffer.array;
  559. ioData->mBuffers[0].mNumberChannels = (UInt32)ca->channels;
  560. ioData->mBuffers[0].mDataByteSize = (UInt32)ca->in_bytes_required;
  561. ca->bytes_read += ca->in_packets * ca->in_frame_size;
  562. return 0;
  563. }
  564. #ifdef _MSC_VER
  565. // disable warning that recommends if ((foo = bar > 0) == false) over
  566. // if (!(foo = bar > 0))
  567. #pragma warning(push)
  568. #pragma warning(disable: 4706)
  569. #endif
  570. static bool aac_encode(void *data, struct encoder_frame *frame,
  571. struct encoder_packet *packet, bool *received_packet)
  572. {
  573. ca_encoder *ca = static_cast<ca_encoder*>(data);
  574. da_push_back_array(ca->input_buffer, frame->data[0],
  575. frame->linesize[0]);
  576. if ((ca->input_buffer.num - ca->bytes_read) < ca->in_bytes_required)
  577. return true;
  578. UInt32 packets = 1;
  579. AudioBufferList buffer_list = { 0 };
  580. buffer_list.mNumberBuffers = 1;
  581. buffer_list.mBuffers[0].mNumberChannels = (UInt32)ca->channels;
  582. buffer_list.mBuffers[0].mDataByteSize = (UInt32)ca->output_buffer_size;
  583. buffer_list.mBuffers[0].mData = ca->output_buffer.data();
  584. AudioStreamPacketDescription out_desc = { 0 };
  585. OSStatus code = AudioConverterFillComplexBuffer(ca->converter,
  586. complex_input_data_proc, ca, &packets,
  587. &buffer_list, &out_desc);
  588. if (code && code != 1) {
  589. log_osstatus(LOG_ERROR, ca, "AudioConverterFillComplexBuffer",
  590. code);
  591. return false;
  592. }
  593. if (!(*received_packet = packets > 0))
  594. return true;
  595. packet->pts = ca->total_samples;
  596. packet->dts = ca->total_samples;
  597. packet->timebase_num = 1;
  598. packet->timebase_den = (uint32_t)ca->samples_per_second;
  599. packet->type = OBS_ENCODER_AUDIO;
  600. packet->size = out_desc.mDataByteSize;
  601. packet->data =
  602. (uint8_t*)buffer_list.mBuffers[0].mData + out_desc.mStartOffset;
  603. ca->total_samples += ca->bytes_read / ca->in_frame_size;
  604. return true;
  605. }
  606. #ifdef _MSC_VER
  607. #pragma warning(pop)
  608. #endif
  609. static void aac_audio_info(void *data, struct audio_convert_info *info)
  610. {
  611. UNUSED_PARAMETER(data);
  612. info->format = AUDIO_FORMAT_FLOAT;
  613. }
  614. static size_t aac_frame_size(void *data)
  615. {
  616. ca_encoder *ca = static_cast<ca_encoder*>(data);
  617. return ca->out_frames_per_packet;
  618. }
  619. /* The following code was extracted from encca_aac.c in HandBrake's libhb */
  620. #define MP4ESDescrTag 0x03
  621. #define MP4DecConfigDescrTag 0x04
  622. #define MP4DecSpecificDescrTag 0x05
  623. // based off of mov_mp4_read_descr_len from mov.c in ffmpeg's libavformat
  624. static int read_descr_len(uint8_t **buffer)
  625. {
  626. int len = 0;
  627. int count = 4;
  628. while (count--)
  629. {
  630. int c = *(*buffer)++;
  631. len = (len << 7) | (c & 0x7f);
  632. if (!(c & 0x80))
  633. break;
  634. }
  635. return len;
  636. }
  637. // based off of mov_mp4_read_descr from mov.c in ffmpeg's libavformat
  638. static int read_descr(uint8_t **buffer, int *tag)
  639. {
  640. *tag = *(*buffer)++;
  641. return read_descr_len(buffer);
  642. }
  643. // based off of mov_read_esds from mov.c in ffmpeg's libavformat
  644. static void read_esds_desc_ext(uint8_t* desc_ext, vector<uint8_t> &buffer,
  645. bool version_flags)
  646. {
  647. uint8_t *esds = desc_ext;
  648. int tag, len;
  649. if (version_flags)
  650. esds += 4; // version + flags
  651. read_descr(&esds, &tag);
  652. esds += 2; // ID
  653. if (tag == MP4ESDescrTag)
  654. esds++; // priority
  655. read_descr(&esds, &tag);
  656. if (tag == MP4DecConfigDescrTag) {
  657. esds++; // object type id
  658. esds++; // stream type
  659. esds += 3; // buffer size db
  660. esds += 4; // max bitrate
  661. esds += 4; // average bitrate
  662. len = read_descr(&esds, &tag);
  663. if (tag == MP4DecSpecificDescrTag)
  664. try {
  665. buffer.assign(esds, esds + len);
  666. } catch (...) {
  667. //leave buffer empty
  668. }
  669. }
  670. }
  671. /* extracted code ends here */
  672. static void query_extra_data(ca_encoder *ca)
  673. {
  674. UInt32 size = 0;
  675. OSStatus code;
  676. code = AudioConverterGetPropertyInfo(ca->converter,
  677. kAudioConverterCompressionMagicCookie,
  678. &size, NULL);
  679. if (code) {
  680. log_osstatus(LOG_ERROR, ca,
  681. "AudioConverterGetPropertyInfo(magic_cookie)",
  682. code);
  683. return;
  684. }
  685. if (!size) {
  686. CA_BLOG(LOG_WARNING, "Got 0 data size info for magic_cookie");
  687. return;
  688. }
  689. vector<uint8_t> extra_data;
  690. try {
  691. extra_data.resize(size);
  692. } catch (...) {
  693. CA_BLOG(LOG_WARNING, "Could not allocate extra data buffer");
  694. return;
  695. }
  696. code = AudioConverterGetProperty(ca->converter,
  697. kAudioConverterCompressionMagicCookie,
  698. &size, extra_data.data());
  699. if (code) {
  700. log_osstatus(LOG_ERROR, ca,
  701. "AudioConverterGetProperty(magic_cookie)",
  702. code);
  703. return;
  704. }
  705. if (!size) {
  706. CA_BLOG(LOG_WARNING, "Got 0 data size for magic_cookie");
  707. return;
  708. }
  709. read_esds_desc_ext(extra_data.data(), ca->extra_data, false);
  710. }
  711. static bool aac_extra_data(void *data, uint8_t **extra_data, size_t *size)
  712. {
  713. ca_encoder *ca = static_cast<ca_encoder*>(data);
  714. if (!ca->extra_data.size())
  715. query_extra_data(ca);
  716. if (!ca->extra_data.size())
  717. return false;
  718. *extra_data = ca->extra_data.data();
  719. *size = ca->extra_data.size();
  720. return true;
  721. }
  722. static asbd_builder fill_common_asbd_fields(asbd_builder builder,
  723. bool in=false)
  724. {
  725. UInt32 bytes_per_frame = 8;
  726. UInt32 channels = 2;
  727. UInt32 bits_per_channel = bytes_per_frame / channels * 8;
  728. builder.channels_per_frame(channels);
  729. if (in) {
  730. builder
  731. .bytes_per_frame(bytes_per_frame)
  732. .frames_per_packet(1)
  733. .bytes_per_packet(1 * bytes_per_frame)
  734. .bits_per_channel(bits_per_channel);
  735. }
  736. return builder;
  737. }
  738. static AudioStreamBasicDescription get_default_in_asbd()
  739. {
  740. return fill_common_asbd_fields(asbd_builder(), true)
  741. .sample_rate(44100)
  742. .format_id(kAudioFormatLinearPCM)
  743. .format_flags(kAudioFormatFlagsNativeEndian |
  744. kAudioFormatFlagIsPacked |
  745. kAudioFormatFlagIsFloat |
  746. 0)
  747. .asbd;
  748. }
  749. static asbd_builder get_default_out_asbd_builder()
  750. {
  751. return fill_common_asbd_fields(asbd_builder())
  752. .sample_rate(44100);
  753. }
  754. static cf_ptr<AudioConverterRef> get_converter(DStr &log, ca_encoder *ca,
  755. AudioStreamBasicDescription out,
  756. AudioStreamBasicDescription in = get_default_in_asbd())
  757. {
  758. UInt32 size = sizeof(out);
  759. OSStatus code;
  760. #define STATUS_CHECK(x) \
  761. code = x; \
  762. if (code) { \
  763. log_to_dstr(log, ca, "%s: %s\n", #x, \
  764. osstatus_to_dstr(code)->array); \
  765. return nullptr; \
  766. }
  767. STATUS_CHECK(AudioFormatGetProperty(kAudioFormatProperty_FormatInfo,
  768. 0, NULL, &size, &out));
  769. AudioConverterRef converter;
  770. STATUS_CHECK(AudioConverterNew(&in, &out, &converter));
  771. return cf_ptr<AudioConverterRef>{converter};
  772. #undef STATUS_CHECK
  773. }
  774. static bool find_best_match(DStr &log, ca_encoder *ca, UInt32 bitrate,
  775. UInt32 &best_match)
  776. {
  777. UInt32 actual_bitrate = bitrate * 1000;
  778. bool found_match = false;
  779. auto handle_bitrate = [&](UInt32 candidate)
  780. {
  781. if (abs(static_cast<intmax_t>(actual_bitrate - candidate)) <
  782. abs(static_cast<intmax_t>(actual_bitrate - best_match))) {
  783. log_to_dstr(log, ca, "Found new best match %u\n",
  784. static_cast<uint32_t>(candidate));
  785. found_match = true;
  786. best_match = candidate;
  787. }
  788. };
  789. auto helper = [&](UInt32 min_, UInt32 max_)
  790. {
  791. handle_bitrate(min_);
  792. if (min_ == max_)
  793. return;
  794. log_to_dstr(log, ca, "Got actual bit rate range: %u<->%u\n",
  795. static_cast<uint32_t>(min_),
  796. static_cast<uint32_t>(max_));
  797. handle_bitrate(max_);
  798. };
  799. for (UInt32 format_id : aac_formats) {
  800. log_to_dstr(log, ca, "Trying %s (0x%x)\n",
  801. format_id_to_str(format_id), format_id);
  802. auto out = get_default_out_asbd_builder()
  803. .format_id(format_id)
  804. .asbd;
  805. auto converter = get_converter(log, ca, out);
  806. if (converter)
  807. enumerate_bitrates(log, ca, converter.get(),
  808. helper);
  809. else
  810. log_to_dstr(log, ca, "Could not get converter\n");
  811. }
  812. best_match /= 1000;
  813. return found_match;
  814. }
  815. static UInt32 find_matching_bitrate(UInt32 bitrate)
  816. {
  817. static UInt32 match = bitrate;
  818. static once_flag once;
  819. call_once(once, [&]()
  820. {
  821. DStr log;
  822. ca_encoder *ca = nullptr;
  823. if (!find_best_match(log, ca, bitrate, match)) {
  824. CA_CO_DLOG(LOG_ERROR, "No matching bitrates found for "
  825. "target bitrate %u",
  826. static_cast<uint32_t>(bitrate));
  827. match = bitrate;
  828. return;
  829. }
  830. if (match != bitrate) {
  831. CA_CO_DLOG(LOG_INFO, "Default bitrate (%u) isn't "
  832. "supported, returning %u as closest match",
  833. static_cast<uint32_t>(bitrate),
  834. static_cast<uint32_t>(match));
  835. return;
  836. }
  837. if (log->len)
  838. CA_CO_DLOG(LOG_DEBUG, "Default bitrate matching log "
  839. "for bitrate %u",
  840. static_cast<uint32_t>(bitrate));
  841. });
  842. return match;
  843. }
  844. static void aac_defaults(obs_data_t *settings)
  845. {
  846. obs_data_set_default_int(settings, "samplerate", 0); //match input
  847. obs_data_set_default_int(settings, "bitrate",
  848. find_matching_bitrate(128));
  849. obs_data_set_default_bool(settings, "allow he-aac", true);
  850. }
  851. template <typename Func>
  852. static bool query_property_raw(DStr &log, ca_encoder *ca,
  853. AudioFormatPropertyID property,
  854. const char *get_property_info, const char *get_property,
  855. AudioStreamBasicDescription &desc, Func &&func)
  856. {
  857. UInt32 size = 0;
  858. OSStatus code = AudioFormatGetPropertyInfo(property,
  859. sizeof(AudioStreamBasicDescription), &desc, &size);
  860. if (code) {
  861. log_to_dstr(log, ca, "%s: %s\n", get_property_info,
  862. osstatus_to_dstr(code)->array);
  863. return false;
  864. }
  865. if (!size) {
  866. log_to_dstr(log, ca, "%s returned 0 size\n", get_property_info);
  867. return false;
  868. }
  869. vector<uint8_t> buffer;
  870. try {
  871. buffer.resize(size);
  872. } catch (...) {
  873. log_to_dstr(log, ca, "Failed to allocate %u bytes for %s\n",
  874. static_cast<uint32_t>(size), get_property);
  875. return false;
  876. }
  877. code = AudioFormatGetProperty(property,
  878. sizeof(AudioStreamBasicDescription), &desc, &size,
  879. buffer.data());
  880. if (code) {
  881. log_to_dstr(log, ca, "%s: %s\n", get_property,
  882. osstatus_to_dstr(code)->array);
  883. return false;
  884. }
  885. func(size, static_cast<void*>(buffer.data()));
  886. return true;
  887. }
  888. #define EXPAND_PROPERTY_NAMES(x) x, \
  889. "AudioFormatGetPropertyInfo(" #x ")", \
  890. "AudioFormatGetProperty(" #x ")"
  891. template <typename Func>
  892. static bool enumerate_samplerates(DStr &log, ca_encoder *ca,
  893. AudioStreamBasicDescription &desc, Func &&func)
  894. {
  895. auto helper = [&](UInt32 size, void *data)
  896. {
  897. auto range = static_cast<AudioValueRange*>(data);
  898. size_t num_ranges = size / sizeof(AudioValueRange);
  899. for (size_t i = 0; i < num_ranges; i++)
  900. func(range[i]);
  901. };
  902. return query_property_raw(log, ca, EXPAND_PROPERTY_NAMES(
  903. kAudioFormatProperty_AvailableEncodeSampleRates),
  904. desc, helper);
  905. }
  906. #if 0
  907. // Unused because it returns bitrates that aren't actually usable, i.e.
  908. // Available bitrates vs Applicable bitrates
  909. template <typename Func>
  910. static bool enumerate_bitrates(DStr &log, ca_encoder *ca,
  911. AudioStreamBasicDescription &desc, Func &&func)
  912. {
  913. auto helper = [&](UInt32 size, void *data)
  914. {
  915. auto range = static_cast<AudioValueRange*>(data);
  916. size_t num_ranges = size / sizeof(AudioValueRange);
  917. for (size_t i = 0; i < num_ranges; i++)
  918. func(range[i]);
  919. };
  920. return query_property_raw(log, ca, EXPAND_PROPERTY_NAMES(
  921. kAudioFormatProperty_AvailableEncodeBitRates),
  922. desc, helper);
  923. }
  924. #endif
  925. static vector<UInt32> get_samplerates(DStr &log, ca_encoder *ca)
  926. {
  927. vector<UInt32> samplerates;
  928. auto handle_samplerate = [&](UInt32 rate)
  929. {
  930. if (find(begin(samplerates), end(samplerates), rate) ==
  931. end(samplerates)) {
  932. log_to_dstr(log, ca, "Adding sample rate %u\n",
  933. static_cast<uint32_t>(rate));
  934. samplerates.push_back(rate);
  935. } else {
  936. log_to_dstr(log, ca, "Sample rate %u already added\n",
  937. static_cast<uint32_t>(rate));
  938. }
  939. };
  940. auto helper = [&](const AudioValueRange &range)
  941. {
  942. auto min_ = static_cast<UInt32>(range.mMinimum);
  943. auto max_ = static_cast<UInt32>(range.mMaximum);
  944. handle_samplerate(min_);
  945. if (min_ == max_)
  946. return;
  947. log_to_dstr(log, ca, "Got actual sample rate range: %u<->%u\n",
  948. static_cast<uint32_t>(min_),
  949. static_cast<uint32_t>(max_));
  950. handle_samplerate(max_);
  951. };
  952. for (UInt32 format : (ca ? *ca->allowed_formats : aac_formats)) {
  953. log_to_dstr(log, ca, "Trying %s (0x%x)\n",
  954. format_id_to_str(format),
  955. static_cast<uint32_t>(format));
  956. auto asbd = asbd_builder()
  957. .format_id(format)
  958. .asbd;
  959. enumerate_samplerates(log, ca, asbd, helper);
  960. }
  961. return samplerates;
  962. }
  963. static void add_samplerates(obs_property_t *prop, ca_encoder *ca)
  964. {
  965. obs_property_list_add_int(prop,
  966. obs_module_text("UseInputSampleRate"), 0);
  967. DStr log;
  968. auto samplerates = get_samplerates(log, ca);
  969. if (!samplerates.size()) {
  970. CA_CO_DLOG_(LOG_ERROR, "Couldn't find available sample rates");
  971. return;
  972. }
  973. if (log->len)
  974. CA_CO_DLOG_(LOG_DEBUG, "Sample rate enumeration log");
  975. sort(begin(samplerates), end(samplerates));
  976. DStr buffer;
  977. for (UInt32 samplerate : samplerates) {
  978. dstr_printf(buffer, "%d", static_cast<uint32_t>(samplerate));
  979. obs_property_list_add_int(prop, buffer->array, samplerate);
  980. }
  981. }
  982. static vector<UInt32> get_bitrates(DStr &log, ca_encoder *ca,
  983. Float64 samplerate)
  984. {
  985. vector<UInt32> bitrates;
  986. auto handle_bitrate = [&](UInt32 bitrate)
  987. {
  988. if (find(begin(bitrates), end(bitrates), bitrate) ==
  989. end(bitrates)) {
  990. log_to_dstr(log, ca, "Adding bitrate %u\n",
  991. static_cast<uint32_t>(bitrate));
  992. bitrates.push_back(bitrate);
  993. } else {
  994. log_to_dstr(log, ca, "Bitrate %u already added\n",
  995. static_cast<uint32_t>(bitrate));
  996. }
  997. };
  998. auto helper = [&](UInt32 min_, UInt32 max_)
  999. {
  1000. handle_bitrate(min_);
  1001. if (min_ == max_)
  1002. return;
  1003. log_to_dstr(log, ca, "Got actual bitrate range: %u<->%u\n",
  1004. static_cast<uint32_t>(min_),
  1005. static_cast<uint32_t>(max_));
  1006. handle_bitrate(max_);
  1007. };
  1008. for (UInt32 format_id : (ca ? *ca->allowed_formats : aac_formats)) {
  1009. log_to_dstr(log, ca, "Trying %s (0x%x) at %g hz\n",
  1010. format_id_to_str(format_id),
  1011. static_cast<uint32_t>(format_id),
  1012. samplerate);
  1013. auto out = get_default_out_asbd_builder()
  1014. .format_id(format_id)
  1015. .sample_rate(samplerate)
  1016. .asbd;
  1017. auto converter = get_converter(log, ca, out);
  1018. if (converter)
  1019. enumerate_bitrates(log, ca, converter.get(), helper);
  1020. }
  1021. return bitrates;
  1022. }
  1023. static void add_bitrates(obs_property_t *prop, ca_encoder *ca,
  1024. Float64 samplerate=44100., UInt32 *selected=nullptr)
  1025. {
  1026. obs_property_list_clear(prop);
  1027. DStr log;
  1028. auto bitrates = get_bitrates(log, ca, samplerate);
  1029. if (!bitrates.size()) {
  1030. CA_CO_DLOG_(LOG_ERROR, "Couldn't find available bitrates");
  1031. return;
  1032. }
  1033. if (log->len)
  1034. CA_CO_DLOG_(LOG_DEBUG, "Bitrate enumeration log");
  1035. bool selected_in_range = true;
  1036. if (selected) {
  1037. selected_in_range = find(begin(bitrates), end(bitrates),
  1038. *selected * 1000) != end(bitrates);
  1039. if (!selected_in_range)
  1040. bitrates.push_back(*selected * 1000);
  1041. }
  1042. sort(begin(bitrates), end(bitrates));
  1043. DStr buffer;
  1044. for (UInt32 bitrate : bitrates) {
  1045. dstr_printf(buffer, "%u", (uint32_t)bitrate / 1000);
  1046. size_t idx = obs_property_list_add_int(prop, buffer->array,
  1047. bitrate / 1000);
  1048. if (selected_in_range || bitrate / 1000 != *selected)
  1049. continue;
  1050. obs_property_list_item_disable(prop, idx, true);
  1051. }
  1052. }
  1053. static bool samplerate_updated(obs_properties_t *props, obs_property_t *prop,
  1054. obs_data_t *settings)
  1055. {
  1056. auto samplerate =
  1057. static_cast<UInt32>(obs_data_get_int(settings, "samplerate"));
  1058. if (!samplerate)
  1059. samplerate = 44100;
  1060. prop = obs_properties_get(props, "bitrate");
  1061. if (prop) {
  1062. auto bitrate = static_cast<UInt32>(
  1063. obs_data_get_int(settings, "bitrate"));
  1064. add_bitrates(prop, nullptr, samplerate, &bitrate);
  1065. return true;
  1066. }
  1067. return false;
  1068. }
  1069. static obs_properties_t *aac_properties(void *data)
  1070. {
  1071. ca_encoder *ca = static_cast<ca_encoder*>(data);
  1072. obs_properties_t *props = obs_properties_create();
  1073. obs_property_t *p = obs_properties_add_list(props, "samplerate",
  1074. obs_module_text("OutputSamplerate"),
  1075. OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
  1076. add_samplerates(p, ca);
  1077. obs_property_set_modified_callback(p, samplerate_updated);
  1078. p = obs_properties_add_list(props, "bitrate",
  1079. obs_module_text("Bitrate"),
  1080. OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
  1081. add_bitrates(p, ca);
  1082. obs_properties_add_bool(props, "allow he-aac",
  1083. obs_module_text("AllowHEAAC"));
  1084. return props;
  1085. }
  1086. OBS_DECLARE_MODULE()
  1087. OBS_MODULE_USE_DEFAULT_LOCALE("coreaudio-encoder", "en-US")
  1088. bool obs_module_load(void)
  1089. {
  1090. #ifdef _WIN32
  1091. if (!load_core_audio()) {
  1092. CA_LOG(LOG_WARNING, "Couldn't load CoreAudio AAC encoder");
  1093. return true;
  1094. }
  1095. CA_LOG(LOG_INFO, "Adding CoreAudio AAC encoder");
  1096. #endif
  1097. struct obs_encoder_info aac_info{};
  1098. aac_info.id = "CoreAudio_AAC";
  1099. aac_info.type = OBS_ENCODER_AUDIO;
  1100. aac_info.codec = "AAC";
  1101. aac_info.get_name = aac_get_name;
  1102. aac_info.destroy = aac_destroy;
  1103. aac_info.create = aac_create;
  1104. aac_info.encode = aac_encode;
  1105. aac_info.get_frame_size = aac_frame_size;
  1106. aac_info.get_audio_info = aac_audio_info;
  1107. aac_info.get_extra_data = aac_extra_data;
  1108. aac_info.get_defaults = aac_defaults;
  1109. aac_info.get_properties = aac_properties;
  1110. obs_register_encoder(&aac_info);
  1111. return true;
  1112. }
  1113. #ifdef _WIN32
  1114. void obs_module_unload(void)
  1115. {
  1116. unload_core_audio();
  1117. }
  1118. #endif