encoder.cpp 36 KB

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