encoder.cpp 36 KB

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