encoder.cpp 34 KB

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