encoder.cpp 36 KB

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