encoder.c 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638
  1. #include <obs-module.h>
  2. #include <util/darray.h>
  3. #include <util/platform.h>
  4. #include <obs-avc.h>
  5. #include <CoreFoundation/CoreFoundation.h>
  6. #include <VideoToolbox/VideoToolbox.h>
  7. #include <VideoToolbox/VTVideoEncoderList.h>
  8. #include <CoreMedia/CoreMedia.h>
  9. #include <util/apple/cfstring-utils.h>
  10. #include <assert.h>
  11. #define VT_LOG(level, format, ...) \
  12. blog(level, "[VideoToolbox encoder]: " format, ##__VA_ARGS__)
  13. #define VT_LOG_ENCODER(encoder, codec_type, level, format, ...) \
  14. blog(level, "[VideoToolbox %s: '%s']: " format, \
  15. obs_encoder_get_name(encoder), \
  16. codec_type_to_print_fmt(codec_type), ##__VA_ARGS__)
  17. #define VT_BLOG(level, format, ...) \
  18. VT_LOG_ENCODER(enc->encoder, enc->codec_type, level, format, \
  19. ##__VA_ARGS__)
  20. struct vt_encoder_type_data {
  21. const char *disp_name;
  22. const char *id;
  23. CMVideoCodecType codec_type;
  24. bool hardware_accelerated;
  25. };
  26. struct vt_prores_encoder_data {
  27. FourCharCode codec_type;
  28. CFStringRef encoder_id;
  29. };
  30. static DARRAY(struct vt_prores_encoder_data) vt_prores_hardware_encoder_list;
  31. static DARRAY(struct vt_prores_encoder_data) vt_prores_software_encoder_list;
  32. struct vt_encoder {
  33. obs_encoder_t *encoder;
  34. const char *vt_encoder_id;
  35. uint32_t width;
  36. uint32_t height;
  37. uint32_t keyint;
  38. uint32_t fps_num;
  39. uint32_t fps_den;
  40. const char *rate_control;
  41. uint32_t bitrate;
  42. float quality;
  43. bool limit_bitrate;
  44. uint32_t rc_max_bitrate;
  45. float rc_max_bitrate_window;
  46. const char *profile;
  47. CMVideoCodecType codec_type;
  48. bool bframes;
  49. int vt_pix_fmt;
  50. enum video_colorspace colorspace;
  51. VTCompressionSessionRef session;
  52. CMSimpleQueueRef queue;
  53. bool hw_enc;
  54. DARRAY(uint8_t) packet_data;
  55. DARRAY(uint8_t) extra_data;
  56. };
  57. static const char *codec_type_to_print_fmt(CMVideoCodecType codec_type)
  58. {
  59. switch (codec_type) {
  60. case kCMVideoCodecType_H264:
  61. return "h264";
  62. case kCMVideoCodecType_HEVC:
  63. return "hevc";
  64. case kCMVideoCodecType_AppleProRes4444XQ:
  65. return "ap4x";
  66. case kCMVideoCodecType_AppleProRes4444:
  67. return "ap4h";
  68. case kCMVideoCodecType_AppleProRes422Proxy:
  69. return "apco";
  70. case kCMVideoCodecType_AppleProRes422LT:
  71. return "apcs";
  72. case kCMVideoCodecType_AppleProRes422:
  73. return "apcn";
  74. case kCMVideoCodecType_AppleProRes422HQ:
  75. return "apch";
  76. default:
  77. return "";
  78. }
  79. }
  80. static void log_osstatus(int log_level, struct vt_encoder *enc,
  81. const char *context, OSStatus code)
  82. {
  83. char *c_str = NULL;
  84. CFErrorRef err = CFErrorCreate(kCFAllocatorDefault,
  85. kCFErrorDomainOSStatus, code, NULL);
  86. CFStringRef str = CFErrorCopyDescription(err);
  87. c_str = cfstr_copy_cstr(str, kCFStringEncodingUTF8);
  88. if (c_str) {
  89. if (enc)
  90. VT_BLOG(log_level, "Error in %s: %s", context, c_str);
  91. else
  92. VT_LOG(log_level, "Error in %s: %s", context, c_str);
  93. }
  94. bfree(c_str);
  95. CFRelease(str);
  96. CFRelease(err);
  97. }
  98. static CFStringRef obs_to_vt_profile(CMVideoCodecType codec_type,
  99. const char *profile,
  100. enum video_format format)
  101. {
  102. if (codec_type == kCMVideoCodecType_H264) {
  103. if (strcmp(profile, "baseline") == 0)
  104. return kVTProfileLevel_H264_Baseline_AutoLevel;
  105. else if (strcmp(profile, "main") == 0)
  106. return kVTProfileLevel_H264_Main_AutoLevel;
  107. else if (strcmp(profile, "high") == 0)
  108. return kVTProfileLevel_H264_High_AutoLevel;
  109. else
  110. return kVTProfileLevel_H264_Main_AutoLevel;
  111. #ifdef ENABLE_HEVC
  112. } else if (codec_type == kCMVideoCodecType_HEVC) {
  113. if (strcmp(profile, "main") == 0) {
  114. if (format == VIDEO_FORMAT_P010) {
  115. VT_LOG(LOG_WARNING, "Forcing main10 for P010");
  116. return kVTProfileLevel_HEVC_Main10_AutoLevel;
  117. } else {
  118. return kVTProfileLevel_HEVC_Main_AutoLevel;
  119. }
  120. }
  121. if (strcmp(profile, "main10") == 0)
  122. return kVTProfileLevel_HEVC_Main10_AutoLevel;
  123. #if __MAC_OS_X_VERSION_MAX_ALLOWED >= 120300 // macOS 12.3
  124. if (__builtin_available(macOS 12.3, *)) {
  125. if (strcmp(profile, "main42210") == 0)
  126. return kVTProfileLevel_HEVC_Main42210_AutoLevel;
  127. }
  128. #endif // macOS 12.3
  129. return kVTProfileLevel_HEVC_Main_AutoLevel;
  130. #endif // ENABLE_HEVC
  131. } else {
  132. return kVTProfileLevel_H264_Baseline_AutoLevel;
  133. }
  134. }
  135. static CFStringRef obs_to_vt_colorspace(enum video_colorspace cs)
  136. {
  137. switch (cs) {
  138. case VIDEO_CS_601:
  139. return kCVImageBufferYCbCrMatrix_ITU_R_601_4;
  140. case VIDEO_CS_2100_PQ:
  141. case VIDEO_CS_2100_HLG:
  142. return kCVImageBufferYCbCrMatrix_ITU_R_2020;
  143. default:
  144. return kCVImageBufferYCbCrMatrix_ITU_R_709_2;
  145. }
  146. }
  147. static CFStringRef obs_to_vt_primaries(enum video_colorspace cs)
  148. {
  149. switch (cs) {
  150. case VIDEO_CS_601:
  151. return kCVImageBufferColorPrimaries_SMPTE_C;
  152. case VIDEO_CS_2100_PQ:
  153. case VIDEO_CS_2100_HLG:
  154. return kCVImageBufferColorPrimaries_ITU_R_2020;
  155. default:
  156. return kCVImageBufferColorPrimaries_ITU_R_709_2;
  157. }
  158. }
  159. static CFStringRef obs_to_vt_transfer(enum video_colorspace cs)
  160. {
  161. switch (cs) {
  162. case VIDEO_CS_SRGB:
  163. return kCVImageBufferTransferFunction_sRGB;
  164. case VIDEO_CS_2100_PQ:
  165. return kCVImageBufferTransferFunction_SMPTE_ST_2084_PQ;
  166. case VIDEO_CS_2100_HLG:
  167. return kCVImageBufferTransferFunction_ITU_R_2100_HLG;
  168. default:
  169. return kCVImageBufferTransferFunction_ITU_R_709_2;
  170. }
  171. }
  172. /* Adapted from Chromium GenerateMasteringDisplayColorVolume */
  173. static CFDataRef obs_to_vt_masteringdisplay(uint32_t hdr_nominal_peak_level)
  174. {
  175. struct mastering_display_colour_volume {
  176. uint16_t display_primaries[3][2];
  177. uint16_t white_point[2];
  178. uint32_t max_display_mastering_luminance;
  179. uint32_t min_display_mastering_luminance;
  180. };
  181. static_assert(sizeof(struct mastering_display_colour_volume) == 24,
  182. "May need to adjust struct packing");
  183. struct mastering_display_colour_volume mdcv;
  184. mdcv.display_primaries[0][0] = __builtin_bswap16(13250);
  185. mdcv.display_primaries[0][1] = __builtin_bswap16(34500);
  186. mdcv.display_primaries[1][0] = __builtin_bswap16(7500);
  187. mdcv.display_primaries[1][1] = __builtin_bswap16(3000);
  188. mdcv.display_primaries[2][0] = __builtin_bswap16(34000);
  189. mdcv.display_primaries[2][1] = __builtin_bswap16(16000);
  190. mdcv.white_point[0] = __builtin_bswap16(15635);
  191. mdcv.white_point[1] = __builtin_bswap16(16450);
  192. mdcv.max_display_mastering_luminance =
  193. __builtin_bswap32(hdr_nominal_peak_level * 10000);
  194. mdcv.min_display_mastering_luminance = 0;
  195. UInt8 bytes[sizeof(struct mastering_display_colour_volume)];
  196. memcpy(bytes, &mdcv, sizeof(bytes));
  197. return CFDataCreate(NULL, bytes, sizeof(bytes));
  198. }
  199. /* Adapted from Chromium GenerateContentLightLevelInfo */
  200. static CFDataRef
  201. obs_to_vt_contentlightlevelinfo(uint16_t hdr_nominal_peak_level)
  202. {
  203. struct content_light_level_info {
  204. uint16_t max_content_light_level;
  205. uint16_t max_pic_average_light_level;
  206. };
  207. static_assert(sizeof(struct content_light_level_info) == 4,
  208. "May need to adjust struct packing");
  209. struct content_light_level_info clli;
  210. clli.max_content_light_level =
  211. __builtin_bswap16(hdr_nominal_peak_level);
  212. clli.max_pic_average_light_level =
  213. __builtin_bswap16(hdr_nominal_peak_level);
  214. UInt8 bytes[sizeof(struct content_light_level_info)];
  215. memcpy(bytes, &clli, sizeof(bytes));
  216. return CFDataCreate(NULL, bytes, sizeof(bytes));
  217. }
  218. #define STATUS_CHECK(c) \
  219. code = c; \
  220. if (code) { \
  221. log_osstatus(LOG_ERROR, enc, #c, code); \
  222. goto fail; \
  223. }
  224. #define SESSION_CHECK(x) \
  225. if ((code = (x)) != noErr) \
  226. return code;
  227. static OSStatus session_set_prop_float(VTCompressionSessionRef session,
  228. CFStringRef key, float val)
  229. {
  230. CFNumberRef n = CFNumberCreate(NULL, kCFNumberFloat32Type, &val);
  231. OSStatus code = VTSessionSetProperty(session, key, n);
  232. CFRelease(n);
  233. return code;
  234. }
  235. static OSStatus session_set_prop_int(VTCompressionSessionRef session,
  236. CFStringRef key, int32_t val)
  237. {
  238. CFNumberRef n = CFNumberCreate(NULL, kCFNumberSInt32Type, &val);
  239. OSStatus code = VTSessionSetProperty(session, key, n);
  240. CFRelease(n);
  241. return code;
  242. }
  243. static OSStatus session_set_prop_str(VTCompressionSessionRef session,
  244. CFStringRef key, char *val)
  245. {
  246. CFStringRef s = CFStringCreateWithFileSystemRepresentation(NULL, val);
  247. OSStatus code = VTSessionSetProperty(session, key, s);
  248. CFRelease(s);
  249. return code;
  250. }
  251. static OSStatus session_set_prop(VTCompressionSessionRef session,
  252. CFStringRef key, CFTypeRef val)
  253. {
  254. return VTSessionSetProperty(session, key, val);
  255. }
  256. static OSStatus session_set_bitrate(VTCompressionSessionRef session,
  257. const char *rate_control, int new_bitrate,
  258. float quality, bool limit_bitrate,
  259. int max_bitrate, float max_bitrate_window)
  260. {
  261. OSStatus code;
  262. bool can_limit_bitrate;
  263. CFStringRef compressionPropertyKey;
  264. if (strcmp(rate_control, "CBR") == 0) {
  265. compressionPropertyKey =
  266. kVTCompressionPropertyKey_AverageBitRate;
  267. can_limit_bitrate = true;
  268. if (__builtin_available(macOS 13.0, *)) {
  269. #if __MAC_OS_X_VERSION_MAX_ALLOWED >= 130000
  270. #ifdef __aarch64__
  271. if (true) {
  272. #else
  273. if (os_get_emulation_status() == true) {
  274. #endif
  275. compressionPropertyKey =
  276. kVTCompressionPropertyKey_ConstantBitRate;
  277. can_limit_bitrate = false;
  278. } else {
  279. VT_LOG(LOG_WARNING,
  280. "CBR support for VideoToolbox encoder requires Apple Silicon. "
  281. "Will use ABR instead.");
  282. }
  283. #else
  284. VT_LOG(LOG_WARNING,
  285. "CBR support for VideoToolbox not available in this build of OBS. "
  286. "Will use ABR instead.");
  287. #endif
  288. } else {
  289. VT_LOG(LOG_WARNING,
  290. "CBR support for VideoToolbox encoder requires macOS 13 or newer. "
  291. "Will use ABR instead.");
  292. }
  293. } else if (strcmp(rate_control, "ABR") == 0) {
  294. compressionPropertyKey =
  295. kVTCompressionPropertyKey_AverageBitRate;
  296. can_limit_bitrate = true;
  297. } else if (strcmp(rate_control, "CRF") == 0) {
  298. #ifdef __aarch64__
  299. if (true) {
  300. #else
  301. if (os_get_emulation_status() == true) {
  302. #endif
  303. compressionPropertyKey =
  304. kVTCompressionPropertyKey_Quality;
  305. SESSION_CHECK(session_set_prop_float(
  306. session, compressionPropertyKey, quality));
  307. } else {
  308. VT_LOG(LOG_WARNING,
  309. "CRF support for VideoToolbox encoder requires Apple Silicon. "
  310. "Will use ABR instead.");
  311. compressionPropertyKey =
  312. kVTCompressionPropertyKey_AverageBitRate;
  313. }
  314. can_limit_bitrate = true;
  315. } else {
  316. VT_LOG(LOG_ERROR,
  317. "Selected rate control method is not supported: %s",
  318. rate_control);
  319. return kVTParameterErr;
  320. }
  321. if (compressionPropertyKey != kVTCompressionPropertyKey_Quality) {
  322. SESSION_CHECK(session_set_prop_int(
  323. session, compressionPropertyKey, new_bitrate * 1000));
  324. }
  325. if (limit_bitrate && can_limit_bitrate) {
  326. int32_t cpb_size = max_bitrate * 125 * max_bitrate_window;
  327. CFNumberRef cf_cpb_size =
  328. CFNumberCreate(NULL, kCFNumberIntType, &cpb_size);
  329. CFNumberRef cf_cpb_window_s = CFNumberCreate(
  330. NULL, kCFNumberFloatType, &max_bitrate_window);
  331. CFMutableArrayRef rate_control = CFArrayCreateMutable(
  332. kCFAllocatorDefault, 2, &kCFTypeArrayCallBacks);
  333. CFArrayAppendValue(rate_control, cf_cpb_size);
  334. CFArrayAppendValue(rate_control, cf_cpb_window_s);
  335. code = session_set_prop(
  336. session, kVTCompressionPropertyKey_DataRateLimits,
  337. rate_control);
  338. CFRelease(cf_cpb_size);
  339. CFRelease(cf_cpb_window_s);
  340. CFRelease(rate_control);
  341. if (code == kVTPropertyNotSupportedErr) {
  342. log_osstatus(LOG_WARNING, NULL,
  343. "setting DataRateLimits on session", code);
  344. return noErr;
  345. }
  346. }
  347. return noErr;
  348. }
  349. static OSStatus session_set_colorspace(VTCompressionSessionRef session,
  350. enum video_colorspace cs)
  351. {
  352. OSStatus code;
  353. SESSION_CHECK(session_set_prop(session,
  354. kVTCompressionPropertyKey_ColorPrimaries,
  355. obs_to_vt_primaries(cs)));
  356. SESSION_CHECK(session_set_prop(
  357. session, kVTCompressionPropertyKey_TransferFunction,
  358. obs_to_vt_transfer(cs)));
  359. SESSION_CHECK(session_set_prop(session,
  360. kVTCompressionPropertyKey_YCbCrMatrix,
  361. obs_to_vt_colorspace(cs)));
  362. const bool pq = cs == VIDEO_CS_2100_PQ;
  363. const bool hlg = cs == VIDEO_CS_2100_HLG;
  364. if (pq || hlg) {
  365. const uint16_t hdr_nominal_peak_level =
  366. pq ? (uint16_t)obs_get_video_hdr_nominal_peak_level()
  367. : (hlg ? 1000 : 0);
  368. SESSION_CHECK(session_set_prop(
  369. session,
  370. kVTCompressionPropertyKey_MasteringDisplayColorVolume,
  371. obs_to_vt_masteringdisplay(hdr_nominal_peak_level)));
  372. SESSION_CHECK(session_set_prop(
  373. session,
  374. kVTCompressionPropertyKey_ContentLightLevelInfo,
  375. obs_to_vt_contentlightlevelinfo(
  376. hdr_nominal_peak_level)));
  377. }
  378. return noErr;
  379. }
  380. #undef SESSION_CHECK
  381. void sample_encoded_callback(void *data, void *source, OSStatus status,
  382. VTEncodeInfoFlags info_flags,
  383. CMSampleBufferRef buffer)
  384. {
  385. UNUSED_PARAMETER(status);
  386. UNUSED_PARAMETER(info_flags);
  387. CMSimpleQueueRef queue = data;
  388. CVPixelBufferRef pixbuf = source;
  389. if (buffer != NULL) {
  390. CFRetain(buffer);
  391. CMSimpleQueueEnqueue(queue, buffer);
  392. }
  393. CFRelease(pixbuf);
  394. }
  395. #define ENCODER_ID kVTVideoEncoderSpecification_EncoderID
  396. static inline CFMutableDictionaryRef
  397. create_encoder_spec(const char *vt_encoder_id)
  398. {
  399. CFMutableDictionaryRef encoder_spec = CFDictionaryCreateMutable(
  400. kCFAllocatorDefault, 3, &kCFTypeDictionaryKeyCallBacks,
  401. &kCFTypeDictionaryValueCallBacks);
  402. CFStringRef id =
  403. CFStringCreateWithFileSystemRepresentation(NULL, vt_encoder_id);
  404. CFDictionaryAddValue(encoder_spec, ENCODER_ID, id);
  405. CFRelease(id);
  406. return encoder_spec;
  407. }
  408. static inline CFMutableDictionaryRef
  409. create_prores_encoder_spec(CMVideoCodecType target_codec_type,
  410. bool hardware_accelerated)
  411. {
  412. CFStringRef encoder_id = NULL;
  413. size_t size = 0;
  414. struct vt_prores_encoder_data *encoder_list = NULL;
  415. if (hardware_accelerated) {
  416. size = vt_prores_hardware_encoder_list.num;
  417. encoder_list = vt_prores_hardware_encoder_list.array;
  418. } else {
  419. size = vt_prores_software_encoder_list.num;
  420. encoder_list = vt_prores_software_encoder_list.array;
  421. }
  422. for (size_t i = 0; i < size; ++i) {
  423. if (target_codec_type == encoder_list[i].codec_type) {
  424. encoder_id = encoder_list[i].encoder_id;
  425. }
  426. }
  427. CFMutableDictionaryRef encoder_spec = CFDictionaryCreateMutable(
  428. kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks,
  429. &kCFTypeDictionaryValueCallBacks);
  430. CFDictionaryAddValue(encoder_spec, ENCODER_ID, encoder_id);
  431. return encoder_spec;
  432. }
  433. #undef ENCODER_ID
  434. static inline CFMutableDictionaryRef create_pixbuf_spec(struct vt_encoder *enc)
  435. {
  436. CFMutableDictionaryRef pixbuf_spec = CFDictionaryCreateMutable(
  437. kCFAllocatorDefault, 3, &kCFTypeDictionaryKeyCallBacks,
  438. &kCFTypeDictionaryValueCallBacks);
  439. CFNumberRef n =
  440. CFNumberCreate(NULL, kCFNumberSInt32Type, &enc->vt_pix_fmt);
  441. CFDictionaryAddValue(pixbuf_spec, kCVPixelBufferPixelFormatTypeKey, n);
  442. CFRelease(n);
  443. n = CFNumberCreate(NULL, kCFNumberSInt32Type, &enc->width);
  444. CFDictionaryAddValue(pixbuf_spec, kCVPixelBufferWidthKey, n);
  445. CFRelease(n);
  446. n = CFNumberCreate(NULL, kCFNumberSInt32Type, &enc->height);
  447. CFDictionaryAddValue(pixbuf_spec, kCVPixelBufferHeightKey, n);
  448. CFRelease(n);
  449. return pixbuf_spec;
  450. }
  451. static bool create_encoder(struct vt_encoder *enc)
  452. {
  453. OSStatus code;
  454. VTCompressionSessionRef s;
  455. const char *codec_name = obs_encoder_get_codec(enc->encoder);
  456. CFDictionaryRef encoder_spec;
  457. if (strcmp(codec_name, "prores") == 0) {
  458. struct vt_encoder_type_data *type_data =
  459. (struct vt_encoder_type_data *)
  460. obs_encoder_get_type_data(enc->encoder);
  461. encoder_spec = create_prores_encoder_spec(
  462. enc->codec_type, type_data->hardware_accelerated);
  463. } else {
  464. encoder_spec = create_encoder_spec(enc->vt_encoder_id);
  465. }
  466. CFDictionaryRef pixbuf_spec = create_pixbuf_spec(enc);
  467. STATUS_CHECK(VTCompressionSessionCreate(
  468. kCFAllocatorDefault, enc->width, enc->height, enc->codec_type,
  469. encoder_spec, pixbuf_spec, NULL, &sample_encoded_callback,
  470. enc->queue, &s));
  471. CFRelease(encoder_spec);
  472. CFRelease(pixbuf_spec);
  473. CFBooleanRef b = NULL;
  474. code = VTSessionCopyProperty(
  475. s,
  476. kVTCompressionPropertyKey_UsingHardwareAcceleratedVideoEncoder,
  477. NULL, &b);
  478. if (code == noErr && (enc->hw_enc = CFBooleanGetValue(b)))
  479. VT_BLOG(LOG_INFO, "session created with hardware encoding");
  480. else
  481. enc->hw_enc = false;
  482. if (b != NULL)
  483. CFRelease(b);
  484. if (enc->codec_type == kCMVideoCodecType_H264 ||
  485. enc->codec_type == kCMVideoCodecType_HEVC) {
  486. // This can fail when using GPU hardware encoding
  487. code = session_set_prop_int(
  488. s,
  489. kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration,
  490. enc->keyint);
  491. if (code != noErr)
  492. log_osstatus(
  493. LOG_WARNING, enc,
  494. "setting kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration failed, "
  495. "keyframe interval might be incorrect",
  496. code);
  497. STATUS_CHECK(session_set_prop_int(
  498. s, kVTCompressionPropertyKey_MaxKeyFrameInterval,
  499. enc->keyint * ((float)enc->fps_num / enc->fps_den)));
  500. STATUS_CHECK(session_set_prop_float(
  501. s, kVTCompressionPropertyKey_ExpectedFrameRate,
  502. (float)enc->fps_num / enc->fps_den));
  503. STATUS_CHECK(session_set_prop(
  504. s, kVTCompressionPropertyKey_AllowFrameReordering,
  505. enc->bframes ? kCFBooleanTrue : kCFBooleanFalse));
  506. video_t *video = obs_encoder_video(enc->encoder);
  507. const struct video_output_info *voi =
  508. video_output_get_info(video);
  509. STATUS_CHECK(session_set_prop(
  510. s, kVTCompressionPropertyKey_ProfileLevel,
  511. obs_to_vt_profile(enc->codec_type, enc->profile,
  512. voi->format)));
  513. STATUS_CHECK(session_set_bitrate(
  514. s, enc->rate_control, enc->bitrate, enc->quality,
  515. enc->limit_bitrate, enc->rc_max_bitrate,
  516. enc->rc_max_bitrate_window));
  517. }
  518. // This can fail depending on hardware configuration
  519. code = session_set_prop(s, kVTCompressionPropertyKey_RealTime,
  520. kCFBooleanFalse);
  521. if (code != noErr)
  522. log_osstatus(
  523. LOG_WARNING, enc,
  524. "setting kVTCompressionPropertyKey_RealTime failed, "
  525. "frame delay might be increased",
  526. code);
  527. STATUS_CHECK(session_set_colorspace(s, enc->colorspace));
  528. STATUS_CHECK(VTCompressionSessionPrepareToEncodeFrames(s));
  529. enc->session = s;
  530. return true;
  531. fail:
  532. if (encoder_spec != NULL)
  533. CFRelease(encoder_spec);
  534. if (pixbuf_spec != NULL)
  535. CFRelease(pixbuf_spec);
  536. return false;
  537. }
  538. static void vt_destroy(void *data)
  539. {
  540. struct vt_encoder *enc = data;
  541. if (enc) {
  542. if (enc->session != NULL) {
  543. VTCompressionSessionInvalidate(enc->session);
  544. CFRelease(enc->session);
  545. }
  546. da_free(enc->packet_data);
  547. da_free(enc->extra_data);
  548. bfree(enc);
  549. }
  550. }
  551. static void dump_encoder_info(struct vt_encoder *enc)
  552. {
  553. VT_BLOG(LOG_INFO,
  554. "settings:\n"
  555. "\tvt_encoder_id %s\n"
  556. "\trate_control: %s\n"
  557. "\tbitrate: %d (kbps)\n"
  558. "\tquality: %f\n"
  559. "\tfps_num: %d\n"
  560. "\tfps_den: %d\n"
  561. "\twidth: %d\n"
  562. "\theight: %d\n"
  563. "\tkeyint: %d (s)\n"
  564. "\tlimit_bitrate: %s\n"
  565. "\trc_max_bitrate: %d (kbps)\n"
  566. "\trc_max_bitrate_window: %f (s)\n"
  567. "\thw_enc: %s\n"
  568. "\tprofile: %s\n"
  569. "\tcodec_type: %.4s\n",
  570. enc->vt_encoder_id, enc->rate_control, enc->bitrate,
  571. enc->quality, enc->fps_num, enc->fps_den, enc->width,
  572. enc->height, enc->keyint, enc->limit_bitrate ? "on" : "off",
  573. enc->rc_max_bitrate, enc->rc_max_bitrate_window,
  574. enc->hw_enc ? "on" : "off",
  575. (enc->profile != NULL && !!strlen(enc->profile)) ? enc->profile
  576. : "default",
  577. codec_type_to_print_fmt(enc->codec_type));
  578. }
  579. static bool set_video_format(struct vt_encoder *enc, enum video_format format,
  580. enum video_range_type range)
  581. {
  582. bool full_range = range == VIDEO_RANGE_FULL;
  583. switch (format) {
  584. case VIDEO_FORMAT_I420:
  585. enc->vt_pix_fmt =
  586. full_range
  587. ? kCVPixelFormatType_420YpCbCr8PlanarFullRange
  588. : kCVPixelFormatType_420YpCbCr8Planar;
  589. return true;
  590. case VIDEO_FORMAT_NV12:
  591. enc->vt_pix_fmt =
  592. full_range
  593. ? kCVPixelFormatType_420YpCbCr8BiPlanarFullRange
  594. : kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange;
  595. return true;
  596. case VIDEO_FORMAT_P010:
  597. if (enc->codec_type == kCMVideoCodecType_HEVC) {
  598. enc->vt_pix_fmt =
  599. full_range
  600. ? kCVPixelFormatType_420YpCbCr10BiPlanarFullRange
  601. : kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange;
  602. return true;
  603. }
  604. break;
  605. case VIDEO_FORMAT_P216:
  606. if (!full_range) {
  607. enc->vt_pix_fmt =
  608. kCVPixelFormatType_422YpCbCr16BiPlanarVideoRange;
  609. return true;
  610. }
  611. break;
  612. case VIDEO_FORMAT_P416:
  613. if (!full_range) {
  614. enc->vt_pix_fmt =
  615. kCVPixelFormatType_444YpCbCr16BiPlanarVideoRange;
  616. return true;
  617. }
  618. break;
  619. default:
  620. return false;
  621. }
  622. return false;
  623. }
  624. static bool update_params(struct vt_encoder *enc, obs_data_t *settings)
  625. {
  626. video_t *video = obs_encoder_video(enc->encoder);
  627. const struct video_output_info *voi = video_output_get_info(video);
  628. const char *codec = obs_encoder_get_codec(enc->encoder);
  629. if (strcmp(codec, "h264") == 0) {
  630. enc->codec_type = kCMVideoCodecType_H264;
  631. obs_data_set_int(settings, "codec_type", enc->codec_type);
  632. #ifdef ENABLE_HEVC
  633. } else if (strcmp(codec, "hevc") == 0) {
  634. enc->codec_type = kCMVideoCodecType_HEVC;
  635. obs_data_set_int(settings, "codec_type", enc->codec_type);
  636. #endif
  637. } else {
  638. enc->codec_type = (CMVideoCodecType)obs_data_get_int(
  639. settings, "codec_type");
  640. }
  641. if (!set_video_format(enc, voi->format, voi->range)) {
  642. obs_encoder_set_last_error(
  643. enc->encoder,
  644. obs_module_text("ColorFormatUnsupported"));
  645. VT_BLOG(LOG_WARNING, "Unsupported color format selected");
  646. return false;
  647. }
  648. enc->colorspace = voi->colorspace;
  649. enc->width = obs_encoder_get_width(enc->encoder);
  650. enc->height = obs_encoder_get_height(enc->encoder);
  651. enc->fps_num = voi->fps_num;
  652. enc->fps_den = voi->fps_den;
  653. enc->keyint = (uint32_t)obs_data_get_int(settings, "keyint_sec");
  654. enc->rate_control = obs_data_get_string(settings, "rate_control");
  655. enc->bitrate = (uint32_t)obs_data_get_int(settings, "bitrate");
  656. enc->quality = ((float)obs_data_get_int(settings, "quality")) / 100;
  657. enc->profile = obs_data_get_string(settings, "profile");
  658. enc->limit_bitrate = obs_data_get_bool(settings, "limit_bitrate");
  659. enc->rc_max_bitrate = obs_data_get_int(settings, "max_bitrate");
  660. enc->rc_max_bitrate_window =
  661. obs_data_get_double(settings, "max_bitrate_window");
  662. enc->bframes = obs_data_get_bool(settings, "bframes");
  663. return true;
  664. }
  665. static bool vt_update(void *data, obs_data_t *settings)
  666. {
  667. struct vt_encoder *enc = data;
  668. uint32_t old_bitrate = enc->bitrate;
  669. bool old_limit_bitrate = enc->limit_bitrate;
  670. update_params(enc, settings);
  671. if (old_bitrate == enc->bitrate &&
  672. old_limit_bitrate == enc->limit_bitrate)
  673. return true;
  674. OSStatus code = session_set_bitrate(enc->session, enc->rate_control,
  675. enc->bitrate, enc->quality,
  676. enc->limit_bitrate,
  677. enc->rc_max_bitrate,
  678. enc->rc_max_bitrate_window);
  679. if (code != noErr)
  680. VT_BLOG(LOG_WARNING, "Failed to set bitrate to session");
  681. dump_encoder_info(enc);
  682. return true;
  683. }
  684. static void *vt_create(obs_data_t *settings, obs_encoder_t *encoder)
  685. {
  686. struct vt_encoder *enc = bzalloc(sizeof(struct vt_encoder));
  687. OSStatus code;
  688. enc->encoder = encoder;
  689. enc->vt_encoder_id = obs_encoder_get_id(encoder);
  690. if (!update_params(enc, settings))
  691. goto fail;
  692. STATUS_CHECK(CMSimpleQueueCreate(NULL, 100, &enc->queue));
  693. if (!create_encoder(enc))
  694. goto fail;
  695. dump_encoder_info(enc);
  696. return enc;
  697. fail:
  698. vt_destroy(enc);
  699. return NULL;
  700. }
  701. static const uint8_t annexb_startcode[4] = {0, 0, 0, 1};
  702. static void packet_put(struct darray *packet, const uint8_t *buf, size_t size)
  703. {
  704. darray_push_back_array(sizeof(uint8_t), packet, buf, size);
  705. }
  706. static void packet_put_startcode(struct darray *packet, int size)
  707. {
  708. assert(size == 3 || size == 4);
  709. packet_put(packet, &annexb_startcode[4 - size], size);
  710. }
  711. static bool handle_prores_packet(struct vt_encoder *enc,
  712. CMSampleBufferRef buffer)
  713. {
  714. OSStatus err = 0;
  715. size_t block_size = 0;
  716. uint8_t *block_buf = NULL;
  717. CMBlockBufferRef block = CMSampleBufferGetDataBuffer(buffer);
  718. if (block == NULL) {
  719. VT_BLOG(LOG_ERROR,
  720. "Failed to get block buffer for ProRes frame.");
  721. return false;
  722. }
  723. err = CMBlockBufferGetDataPointer(block, 0, NULL, &block_size,
  724. (char **)&block_buf);
  725. if (err != 0) {
  726. VT_BLOG(LOG_ERROR,
  727. "Failed to get data buffer pointer for ProRes frame.");
  728. return false;
  729. }
  730. packet_put(&enc->packet_data.da, block_buf, block_size);
  731. return true;
  732. }
  733. static void convert_block_nals_to_annexb(struct vt_encoder *enc,
  734. struct darray *packet,
  735. CMBlockBufferRef block,
  736. int nal_length_bytes)
  737. {
  738. size_t block_size;
  739. uint8_t *block_buf;
  740. CMBlockBufferGetDataPointer(block, 0, NULL, &block_size,
  741. (char **)&block_buf);
  742. size_t bytes_remaining = block_size;
  743. while (bytes_remaining > 0) {
  744. uint32_t nal_size;
  745. if (nal_length_bytes == 1)
  746. nal_size = block_buf[0];
  747. else if (nal_length_bytes == 2)
  748. nal_size = CFSwapInt16BigToHost(
  749. ((uint16_t *)block_buf)[0]);
  750. else if (nal_length_bytes == 4)
  751. nal_size = CFSwapInt32BigToHost(
  752. ((uint32_t *)block_buf)[0]);
  753. else
  754. return;
  755. bytes_remaining -= nal_length_bytes;
  756. block_buf += nal_length_bytes;
  757. if (bytes_remaining < nal_size) {
  758. VT_BLOG(LOG_ERROR, "invalid nal block");
  759. return;
  760. }
  761. packet_put_startcode(packet, 3);
  762. packet_put(packet, block_buf, nal_size);
  763. bytes_remaining -= nal_size;
  764. block_buf += nal_size;
  765. }
  766. }
  767. static bool handle_keyframe(struct vt_encoder *enc,
  768. CMFormatDescriptionRef format_desc,
  769. size_t param_count, struct darray *packet,
  770. struct darray *extra_data)
  771. {
  772. OSStatus code;
  773. const uint8_t *param;
  774. size_t param_size;
  775. for (size_t i = 0; i < param_count; i++) {
  776. if (enc->codec_type == kCMVideoCodecType_H264) {
  777. code = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(
  778. format_desc, i, &param, &param_size, NULL,
  779. NULL);
  780. #ifdef ENABLE_HEVC
  781. } else if (enc->codec_type == kCMVideoCodecType_HEVC) {
  782. code = CMVideoFormatDescriptionGetHEVCParameterSetAtIndex(
  783. format_desc, i, &param, &param_size, NULL,
  784. NULL);
  785. #endif
  786. }
  787. if (code != noErr) {
  788. log_osstatus(LOG_ERROR, enc,
  789. "getting NAL parameter "
  790. "at index",
  791. code);
  792. return false;
  793. }
  794. packet_put_startcode(packet, 4);
  795. packet_put(packet, param, param_size);
  796. }
  797. // if we were passed an extra_data array, fill it with
  798. // SPS, PPS, etc.
  799. if (extra_data != NULL)
  800. packet_put(extra_data, packet->array, packet->num);
  801. return true;
  802. }
  803. static bool convert_sample_to_annexb(struct vt_encoder *enc,
  804. struct darray *packet,
  805. struct darray *extra_data,
  806. CMSampleBufferRef buffer, bool keyframe)
  807. {
  808. OSStatus code;
  809. CMFormatDescriptionRef format_desc =
  810. CMSampleBufferGetFormatDescription(buffer);
  811. size_t param_count;
  812. int nal_length_bytes;
  813. if (enc->codec_type == kCMVideoCodecType_H264) {
  814. code = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(
  815. format_desc, 0, NULL, NULL, &param_count,
  816. &nal_length_bytes);
  817. #ifdef ENABLE_HEVC
  818. } else if (enc->codec_type == kCMVideoCodecType_HEVC) {
  819. code = CMVideoFormatDescriptionGetHEVCParameterSetAtIndex(
  820. format_desc, 0, NULL, NULL, &param_count,
  821. &nal_length_bytes);
  822. #endif
  823. }
  824. // it is not clear what errors this function can return
  825. // so we check the two most reasonable
  826. if (code == kCMFormatDescriptionBridgeError_InvalidParameter ||
  827. code == kCMFormatDescriptionError_InvalidParameter) {
  828. VT_BLOG(LOG_WARNING, "assuming 2 parameter sets "
  829. "and 4 byte NAL length header");
  830. param_count = 2;
  831. nal_length_bytes = 4;
  832. } else if (code != noErr) {
  833. log_osstatus(LOG_ERROR, enc,
  834. "getting parameter count from sample", code);
  835. return false;
  836. }
  837. if (keyframe &&
  838. !handle_keyframe(enc, format_desc, param_count, packet, extra_data))
  839. return false;
  840. CMBlockBufferRef block = CMSampleBufferGetDataBuffer(buffer);
  841. convert_block_nals_to_annexb(enc, packet, block, nal_length_bytes);
  842. return true;
  843. }
  844. static bool is_sample_keyframe(CMSampleBufferRef buffer)
  845. {
  846. CFArrayRef attachments =
  847. CMSampleBufferGetSampleAttachmentsArray(buffer, false);
  848. if (attachments != NULL) {
  849. CFDictionaryRef attachment;
  850. CFBooleanRef has_dependencies;
  851. attachment =
  852. (CFDictionaryRef)CFArrayGetValueAtIndex(attachments, 0);
  853. has_dependencies = (CFBooleanRef)CFDictionaryGetValue(
  854. attachment, kCMSampleAttachmentKey_DependsOnOthers);
  855. return has_dependencies == kCFBooleanFalse;
  856. }
  857. return false;
  858. }
  859. static bool parse_sample(struct vt_encoder *enc, CMSampleBufferRef buffer,
  860. struct encoder_packet *packet, CMTime off)
  861. {
  862. CMTime pts = CMSampleBufferGetPresentationTimeStamp(buffer);
  863. CMTime dts = CMSampleBufferGetDecodeTimeStamp(buffer);
  864. if (CMTIME_IS_INVALID(dts))
  865. dts = pts;
  866. // imitate x264's negative dts when bframes might have pts < dts
  867. else if (enc->bframes)
  868. dts = CMTimeSubtract(dts, off);
  869. pts = CMTimeMultiply(pts, enc->fps_num);
  870. dts = CMTimeMultiply(dts, enc->fps_num);
  871. const bool is_avc = enc->codec_type == kCMVideoCodecType_H264;
  872. const bool has_annexb = is_avc ||
  873. (enc->codec_type == kCMVideoCodecType_HEVC);
  874. // All ProRes frames are "keyframes"
  875. const bool keyframe = !has_annexb || is_sample_keyframe(buffer);
  876. da_resize(enc->packet_data, 0);
  877. // If we are still looking for extra data
  878. struct darray *extra_data = NULL;
  879. if (enc->extra_data.num == 0)
  880. extra_data = &enc->extra_data.da;
  881. if (has_annexb) {
  882. if (!convert_sample_to_annexb(enc, &enc->packet_data.da,
  883. extra_data, buffer, keyframe))
  884. goto fail;
  885. } else {
  886. if (!handle_prores_packet(enc, buffer))
  887. goto fail;
  888. }
  889. packet->type = OBS_ENCODER_VIDEO;
  890. packet->pts = (int64_t)(CMTimeGetSeconds(pts));
  891. packet->dts = (int64_t)(CMTimeGetSeconds(dts));
  892. packet->data = enc->packet_data.array;
  893. packet->size = enc->packet_data.num;
  894. packet->keyframe = keyframe;
  895. if (is_avc) {
  896. // VideoToolbox produces packets with priority lower than the RTMP code
  897. // expects, which causes it to be unable to recover from frame drops.
  898. // Fix this by manually adjusting the priority.
  899. uint8_t *start = enc->packet_data.array;
  900. uint8_t *end = start + enc->packet_data.num;
  901. start = (uint8_t *)obs_avc_find_startcode(start, end);
  902. while (true) {
  903. while (start < end && !*(start++))
  904. ;
  905. if (start == end)
  906. break;
  907. const int type = start[0] & 0x1F;
  908. if (type == OBS_NAL_SLICE_IDR ||
  909. type == OBS_NAL_SLICE) {
  910. uint8_t prev_type = (start[0] >> 5) & 0x3;
  911. start[0] &= ~(3 << 5);
  912. if (type == OBS_NAL_SLICE_IDR)
  913. start[0] |= OBS_NAL_PRIORITY_HIGHEST
  914. << 5;
  915. else if (type == OBS_NAL_SLICE &&
  916. prev_type !=
  917. OBS_NAL_PRIORITY_DISPOSABLE)
  918. start[0] |= OBS_NAL_PRIORITY_HIGH << 5;
  919. else
  920. start[0] |= prev_type << 5;
  921. }
  922. start = (uint8_t *)obs_avc_find_startcode(start, end);
  923. }
  924. }
  925. CFRelease(buffer);
  926. return true;
  927. fail:
  928. CFRelease(buffer);
  929. return false;
  930. }
  931. bool get_cached_pixel_buffer(struct vt_encoder *enc, CVPixelBufferRef *buf)
  932. {
  933. OSStatus code;
  934. CVPixelBufferPoolRef pool =
  935. VTCompressionSessionGetPixelBufferPool(enc->session);
  936. if (!pool)
  937. return kCVReturnError;
  938. CVPixelBufferRef pixbuf;
  939. STATUS_CHECK(CVPixelBufferPoolCreatePixelBuffer(NULL, pool, &pixbuf));
  940. // Why aren't these already set on the pixel buffer?
  941. // I would have expected pixel buffers from the session's
  942. // pool to have the correct color space stuff set
  943. const enum video_colorspace cs = enc->colorspace;
  944. CVBufferSetAttachment(pixbuf, kCVImageBufferYCbCrMatrixKey,
  945. obs_to_vt_colorspace(cs),
  946. kCVAttachmentMode_ShouldPropagate);
  947. CVBufferSetAttachment(pixbuf, kCVImageBufferColorPrimariesKey,
  948. obs_to_vt_primaries(cs),
  949. kCVAttachmentMode_ShouldPropagate);
  950. CVBufferSetAttachment(pixbuf, kCVImageBufferTransferFunctionKey,
  951. obs_to_vt_transfer(cs),
  952. kCVAttachmentMode_ShouldPropagate);
  953. const bool pq = cs == VIDEO_CS_2100_PQ;
  954. const bool hlg = cs == VIDEO_CS_2100_HLG;
  955. if (pq || hlg) {
  956. const uint16_t hdr_nominal_peak_level =
  957. pq ? (uint16_t)obs_get_video_hdr_nominal_peak_level()
  958. : (hlg ? 1000 : 0);
  959. CVBufferSetAttachment(
  960. pixbuf, kCVImageBufferMasteringDisplayColorVolumeKey,
  961. obs_to_vt_masteringdisplay(hdr_nominal_peak_level),
  962. kCVAttachmentMode_ShouldPropagate);
  963. CVBufferSetAttachment(
  964. pixbuf, kCVImageBufferContentLightLevelInfoKey,
  965. obs_to_vt_contentlightlevelinfo(hdr_nominal_peak_level),
  966. kCVAttachmentMode_ShouldPropagate);
  967. }
  968. *buf = pixbuf;
  969. return true;
  970. fail:
  971. return false;
  972. }
  973. static bool vt_encode(void *data, struct encoder_frame *frame,
  974. struct encoder_packet *packet, bool *received_packet)
  975. {
  976. struct vt_encoder *enc = data;
  977. OSStatus code;
  978. CMTime dur = CMTimeMake(enc->fps_den, enc->fps_num);
  979. CMTime off = CMTimeMultiply(dur, 2);
  980. CMTime pts = CMTimeMake(frame->pts, enc->fps_num);
  981. CVPixelBufferRef pixbuf = NULL;
  982. if (!get_cached_pixel_buffer(enc, &pixbuf)) {
  983. VT_BLOG(LOG_ERROR, "Unable to create pixel buffer");
  984. goto fail;
  985. }
  986. STATUS_CHECK(CVPixelBufferLockBaseAddress(pixbuf, 0));
  987. for (int i = 0; i < MAX_AV_PLANES; i++) {
  988. if (frame->data[i] == NULL)
  989. break;
  990. uint8_t *p = (uint8_t *)CVPixelBufferGetBaseAddressOfPlane(
  991. pixbuf, i);
  992. uint8_t *f = frame->data[i];
  993. size_t plane_linesize =
  994. CVPixelBufferGetBytesPerRowOfPlane(pixbuf, i);
  995. size_t plane_height = CVPixelBufferGetHeightOfPlane(pixbuf, i);
  996. for (size_t j = 0; j < plane_height; j++) {
  997. memcpy(p, f, frame->linesize[i]);
  998. p += plane_linesize;
  999. f += frame->linesize[i];
  1000. }
  1001. }
  1002. STATUS_CHECK(CVPixelBufferUnlockBaseAddress(pixbuf, 0));
  1003. STATUS_CHECK(VTCompressionSessionEncodeFrame(enc->session, pixbuf, pts,
  1004. dur, NULL, pixbuf, NULL));
  1005. CMSampleBufferRef buffer =
  1006. (CMSampleBufferRef)CMSimpleQueueDequeue(enc->queue);
  1007. // No samples waiting in the queue
  1008. if (buffer == NULL)
  1009. return true;
  1010. *received_packet = true;
  1011. return parse_sample(enc, buffer, packet, off);
  1012. fail:
  1013. return false;
  1014. }
  1015. #undef STATUS_CHECK
  1016. #undef CFNUM_INT
  1017. static bool vt_extra_data(void *data, uint8_t **extra_data, size_t *size)
  1018. {
  1019. struct vt_encoder *enc = (struct vt_encoder *)data;
  1020. *extra_data = enc->extra_data.array;
  1021. *size = enc->extra_data.num;
  1022. return true;
  1023. }
  1024. static const char *vt_getname(void *data)
  1025. {
  1026. struct vt_encoder_type_data *type_data = data;
  1027. if (strcmp("Apple H.264 (HW)", type_data->disp_name) == 0) {
  1028. return obs_module_text("VTH264EncHW");
  1029. } else if (strcmp("Apple H.264 (SW)", type_data->disp_name) == 0) {
  1030. return obs_module_text("VTH264EncSW");
  1031. #ifdef ENABLE_HEVC
  1032. } else if (strcmp("Apple HEVC (HW)", type_data->disp_name) == 0) {
  1033. return obs_module_text("VTHEVCEncHW");
  1034. } else if (strcmp("Apple HEVC (AVE)", type_data->disp_name) == 0) {
  1035. return obs_module_text("VTHEVCEncT2");
  1036. } else if (strcmp("Apple HEVC (SW)", type_data->disp_name) == 0) {
  1037. return obs_module_text("VTHEVCEncSW");
  1038. #endif
  1039. } else if (strncmp("AppleProResHW", type_data->disp_name, 13) == 0) {
  1040. return obs_module_text("VTProResEncHW");
  1041. } else if (strncmp("Apple ProRes", type_data->disp_name, 12) == 0) {
  1042. return obs_module_text("VTProResEncSW");
  1043. }
  1044. return type_data->disp_name;
  1045. }
  1046. #define TEXT_BITRATE obs_module_text("Bitrate")
  1047. #define TEXT_QUALITY obs_module_text("Quality")
  1048. #define TEXT_USE_MAX_BITRATE obs_module_text("UseMaxBitrate")
  1049. #define TEXT_MAX_BITRATE obs_module_text("MaxBitrate")
  1050. #define TEXT_MAX_BITRATE_WINDOW obs_module_text("MaxBitrateWindow")
  1051. #define TEXT_KEYINT_SEC obs_module_text("KeyframeIntervalSec")
  1052. #define TEXT_PROFILE obs_module_text("Profile")
  1053. #define TEXT_BFRAMES obs_module_text("UseBFrames")
  1054. #define TEXT_RATE_CONTROL obs_module_text("RateControl")
  1055. #define TEXT_PRORES_CODEC obs_module_text("ProResCodec")
  1056. static bool rate_control_limit_bitrate_modified(obs_properties_t *ppts,
  1057. obs_property_t *p,
  1058. obs_data_t *settings)
  1059. {
  1060. bool has_bitrate = true;
  1061. bool can_limit_bitrate = true;
  1062. bool use_limit_bitrate = obs_data_get_bool(settings, "limit_bitrate");
  1063. const char *rate_control =
  1064. obs_data_get_string(settings, "rate_control");
  1065. if (strcmp(rate_control, "CBR") == 0) {
  1066. can_limit_bitrate = false;
  1067. has_bitrate = true;
  1068. } else if (strcmp(rate_control, "CRF") == 0) {
  1069. can_limit_bitrate = true;
  1070. has_bitrate = false;
  1071. } else if (strcmp(rate_control, "ABR") == 0) {
  1072. can_limit_bitrate = true;
  1073. has_bitrate = true;
  1074. }
  1075. p = obs_properties_get(ppts, "limit_bitrate");
  1076. obs_property_set_visible(p, can_limit_bitrate);
  1077. p = obs_properties_get(ppts, "max_bitrate");
  1078. obs_property_set_visible(p, can_limit_bitrate && use_limit_bitrate);
  1079. p = obs_properties_get(ppts, "max_bitrate_window");
  1080. obs_property_set_visible(p, can_limit_bitrate && use_limit_bitrate);
  1081. p = obs_properties_get(ppts, "bitrate");
  1082. obs_property_set_visible(p, has_bitrate);
  1083. p = obs_properties_get(ppts, "quality");
  1084. obs_property_set_visible(p, !has_bitrate);
  1085. return true;
  1086. }
  1087. static obs_properties_t *vt_properties_h26x(void *unused, void *data)
  1088. {
  1089. UNUSED_PARAMETER(unused);
  1090. struct vt_encoder_type_data *type_data = data;
  1091. obs_properties_t *props = obs_properties_create();
  1092. obs_property_t *p;
  1093. p = obs_properties_add_list(props, "rate_control", TEXT_RATE_CONTROL,
  1094. OBS_COMBO_TYPE_LIST,
  1095. OBS_COMBO_FORMAT_STRING);
  1096. if (__builtin_available(macOS 13.0, *))
  1097. if (type_data->hardware_accelerated
  1098. #ifndef __aarch64__
  1099. && (os_get_emulation_status() == true)
  1100. #endif
  1101. )
  1102. obs_property_list_add_string(p, "CBR", "CBR");
  1103. obs_property_list_add_string(p, "ABR", "ABR");
  1104. if (type_data->hardware_accelerated
  1105. #ifndef __aarch64__
  1106. && (os_get_emulation_status() == true)
  1107. #endif
  1108. )
  1109. obs_property_list_add_string(p, "CRF", "CRF");
  1110. obs_property_set_modified_callback(p,
  1111. rate_control_limit_bitrate_modified);
  1112. p = obs_properties_add_int(props, "bitrate", TEXT_BITRATE, 50, 10000000,
  1113. 50);
  1114. obs_property_int_set_suffix(p, " Kbps");
  1115. obs_properties_add_int_slider(props, "quality", TEXT_QUALITY, 0, 100,
  1116. 1);
  1117. p = obs_properties_add_bool(props, "limit_bitrate",
  1118. TEXT_USE_MAX_BITRATE);
  1119. obs_property_set_modified_callback(p,
  1120. rate_control_limit_bitrate_modified);
  1121. p = obs_properties_add_int(props, "max_bitrate", TEXT_MAX_BITRATE, 50,
  1122. 10000000, 50);
  1123. obs_property_int_set_suffix(p, " Kbps");
  1124. p = obs_properties_add_float(props, "max_bitrate_window",
  1125. TEXT_MAX_BITRATE_WINDOW, 0.10f, 10.0f,
  1126. 0.25f);
  1127. obs_property_float_set_suffix(p, " s");
  1128. p = obs_properties_add_int(props, "keyint_sec", TEXT_KEYINT_SEC, 0, 20,
  1129. 1);
  1130. obs_property_int_set_suffix(p, " s");
  1131. p = obs_properties_add_list(props, "profile", TEXT_PROFILE,
  1132. OBS_COMBO_TYPE_LIST,
  1133. OBS_COMBO_FORMAT_STRING);
  1134. if (type_data->codec_type == kCMVideoCodecType_H264) {
  1135. obs_property_list_add_string(p, "baseline", "baseline");
  1136. obs_property_list_add_string(p, "main", "main");
  1137. obs_property_list_add_string(p, "high", "high");
  1138. #ifdef ENABLE_HEVC
  1139. } else if (type_data->codec_type == kCMVideoCodecType_HEVC) {
  1140. obs_property_list_add_string(p, "main", "main");
  1141. obs_property_list_add_string(p, "main10", "main10");
  1142. if (__builtin_available(macOS 12.3, *)) {
  1143. obs_property_list_add_string(p, "main 4:2:2 10",
  1144. "main42210");
  1145. }
  1146. #endif
  1147. }
  1148. obs_properties_add_bool(props, "bframes", TEXT_BFRAMES);
  1149. return props;
  1150. }
  1151. static obs_properties_t *vt_properties_prores(void *unused, void *data)
  1152. {
  1153. UNUSED_PARAMETER(unused);
  1154. struct vt_encoder_type_data *type_data = data;
  1155. obs_properties_t *props = obs_properties_create();
  1156. obs_property_t *p;
  1157. p = obs_properties_add_list(props, "codec_type", TEXT_PRORES_CODEC,
  1158. OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
  1159. uint32_t codec_availability_flags = 0;
  1160. size_t size = 0;
  1161. struct vt_prores_encoder_data *encoder_list = NULL;
  1162. if (type_data->hardware_accelerated) {
  1163. size = vt_prores_hardware_encoder_list.num;
  1164. encoder_list = vt_prores_hardware_encoder_list.array;
  1165. } else {
  1166. size = vt_prores_software_encoder_list.num;
  1167. encoder_list = vt_prores_software_encoder_list.array;
  1168. }
  1169. for (size_t i = 0; i < size; ++i) {
  1170. switch (encoder_list[i].codec_type) {
  1171. case kCMVideoCodecType_AppleProRes4444XQ:
  1172. codec_availability_flags |= (1 << 0);
  1173. break;
  1174. case kCMVideoCodecType_AppleProRes4444:
  1175. codec_availability_flags |= (1 << 1);
  1176. break;
  1177. case kCMVideoCodecType_AppleProRes422Proxy:
  1178. codec_availability_flags |= (1 << 2);
  1179. break;
  1180. case kCMVideoCodecType_AppleProRes422LT:
  1181. codec_availability_flags |= (1 << 3);
  1182. break;
  1183. case kCMVideoCodecType_AppleProRes422:
  1184. codec_availability_flags |= (1 << 4);
  1185. break;
  1186. case kCMVideoCodecType_AppleProRes422HQ:
  1187. codec_availability_flags |= (1 << 5);
  1188. break;
  1189. }
  1190. }
  1191. if (codec_availability_flags & (1 << 0))
  1192. obs_property_list_add_int(p, obs_module_text("ProRes4444XQ"),
  1193. kCMVideoCodecType_AppleProRes4444XQ);
  1194. if (codec_availability_flags & (1 << 1))
  1195. obs_property_list_add_int(p, obs_module_text("ProRes4444"),
  1196. kCMVideoCodecType_AppleProRes4444);
  1197. if (codec_availability_flags & (1 << 2))
  1198. obs_property_list_add_int(
  1199. p, obs_module_text("ProRes422Proxy"),
  1200. kCMVideoCodecType_AppleProRes422Proxy);
  1201. if (codec_availability_flags & (1 << 3))
  1202. obs_property_list_add_int(p, obs_module_text("ProRes422LT"),
  1203. kCMVideoCodecType_AppleProRes422LT);
  1204. if (codec_availability_flags & (1 << 4))
  1205. obs_property_list_add_int(p, obs_module_text("ProRes422"),
  1206. kCMVideoCodecType_AppleProRes422);
  1207. if (codec_availability_flags & (1 << 5))
  1208. obs_property_list_add_int(p, obs_module_text("ProRes422HQ"),
  1209. kCMVideoCodecType_AppleProRes422HQ);
  1210. return props;
  1211. }
  1212. static void vt_defaults(obs_data_t *settings, void *data)
  1213. {
  1214. struct vt_encoder_type_data *type_data = data;
  1215. obs_data_set_default_string(settings, "rate_control", "ABR");
  1216. if (__builtin_available(macOS 13.0, *))
  1217. if (type_data->hardware_accelerated
  1218. #ifndef __aarch64__
  1219. && (os_get_emulation_status() == true)
  1220. #endif
  1221. )
  1222. obs_data_set_default_string(settings, "rate_control",
  1223. "CBR");
  1224. obs_data_set_default_int(settings, "bitrate", 2500);
  1225. obs_data_set_default_int(settings, "quality", 60);
  1226. obs_data_set_default_bool(settings, "limit_bitrate", false);
  1227. obs_data_set_default_int(settings, "max_bitrate", 2500);
  1228. obs_data_set_default_double(settings, "max_bitrate_window", 1.5f);
  1229. obs_data_set_default_int(settings, "keyint_sec", 0);
  1230. obs_data_set_default_string(
  1231. settings, "profile",
  1232. type_data->codec_type == kCMVideoCodecType_H264 ? "high"
  1233. : "main");
  1234. obs_data_set_default_int(settings, "codec_type",
  1235. kCMVideoCodecType_AppleProRes422);
  1236. obs_data_set_default_bool(settings, "bframes", true);
  1237. }
  1238. static void vt_free_type_data(void *data)
  1239. {
  1240. struct vt_encoder_type_data *type_data = data;
  1241. bfree((char *)type_data->disp_name);
  1242. bfree((char *)type_data->id);
  1243. bfree(type_data);
  1244. }
  1245. static inline void
  1246. vt_add_prores_encoder_data_to_list(CFDictionaryRef encoder_dict,
  1247. FourCharCode codec_type)
  1248. {
  1249. struct vt_prores_encoder_data *encoder_data = NULL;
  1250. CFBooleanRef hardware_accelerated = CFDictionaryGetValue(
  1251. encoder_dict, kVTVideoEncoderList_IsHardwareAccelerated);
  1252. if (hardware_accelerated == kCFBooleanTrue)
  1253. encoder_data =
  1254. da_push_back_new(vt_prores_hardware_encoder_list);
  1255. else
  1256. encoder_data =
  1257. da_push_back_new(vt_prores_software_encoder_list);
  1258. encoder_data->encoder_id = CFDictionaryGetValue(
  1259. encoder_dict, kVTVideoEncoderList_EncoderID);
  1260. encoder_data->codec_type = codec_type;
  1261. }
  1262. static CFComparisonResult
  1263. compare_encoder_list(const void *left_val, const void *right_val, void *unused)
  1264. {
  1265. UNUSED_PARAMETER(unused);
  1266. CFDictionaryRef left = (CFDictionaryRef)left_val;
  1267. CFDictionaryRef right = (CFDictionaryRef)right_val;
  1268. CFNumberRef left_codec_num =
  1269. CFDictionaryGetValue(left, kVTVideoEncoderList_CodecType);
  1270. CFNumberRef right_codec_num =
  1271. CFDictionaryGetValue(right, kVTVideoEncoderList_CodecType);
  1272. CFComparisonResult result =
  1273. CFNumberCompare(left_codec_num, right_codec_num, NULL);
  1274. if (result != kCFCompareEqualTo)
  1275. return result;
  1276. CFBooleanRef left_hardware_accel = CFDictionaryGetValue(
  1277. left, kVTVideoEncoderList_IsHardwareAccelerated);
  1278. CFBooleanRef right_hardware_accel = CFDictionaryGetValue(
  1279. right, kVTVideoEncoderList_IsHardwareAccelerated);
  1280. if (left_hardware_accel == right_hardware_accel)
  1281. return kCFCompareEqualTo;
  1282. else if (left_hardware_accel == kCFBooleanTrue)
  1283. return kCFCompareGreaterThan;
  1284. else
  1285. return kCFCompareLessThan;
  1286. }
  1287. OBS_DECLARE_MODULE()
  1288. OBS_MODULE_USE_DEFAULT_LOCALE("mac-videotoolbox", "en-US")
  1289. dispatch_group_t encoder_list_dispatch_group;
  1290. CFArrayRef encoder_list_const;
  1291. bool obs_module_load(void)
  1292. {
  1293. dispatch_queue_t queue =
  1294. dispatch_queue_create("Encoder list load queue", NULL);
  1295. encoder_list_dispatch_group = dispatch_group_create();
  1296. dispatch_group_async(encoder_list_dispatch_group, queue, ^{
  1297. VTCopyVideoEncoderList(NULL, &encoder_list_const);
  1298. });
  1299. // The group dispatch keeps a reference until it's finished
  1300. dispatch_release(queue);
  1301. return true;
  1302. }
  1303. void obs_module_post_load(void)
  1304. {
  1305. struct obs_encoder_info info = {
  1306. .type = OBS_ENCODER_VIDEO,
  1307. .get_name = vt_getname,
  1308. .create = vt_create,
  1309. .destroy = vt_destroy,
  1310. .encode = vt_encode,
  1311. .update = vt_update,
  1312. .get_defaults2 = vt_defaults,
  1313. .get_extra_data = vt_extra_data,
  1314. .free_type_data = vt_free_type_data,
  1315. .caps = OBS_ENCODER_CAP_DYN_BITRATE,
  1316. };
  1317. da_init(vt_prores_hardware_encoder_list);
  1318. da_init(vt_prores_software_encoder_list);
  1319. dispatch_group_wait(encoder_list_dispatch_group, DISPATCH_TIME_FOREVER);
  1320. dispatch_release(encoder_list_dispatch_group);
  1321. CFIndex size = CFArrayGetCount(encoder_list_const);
  1322. CFMutableArrayRef encoder_list = CFArrayCreateMutableCopy(
  1323. kCFAllocatorDefault, size, encoder_list_const);
  1324. CFRelease(encoder_list_const);
  1325. CFArraySortValues(encoder_list, CFRangeMake(0, size),
  1326. &compare_encoder_list, NULL);
  1327. for (CFIndex i = 0; i < size; i++) {
  1328. CFDictionaryRef encoder_dict =
  1329. CFArrayGetValueAtIndex(encoder_list, i);
  1330. #define VT_DICTSTR(key, name) \
  1331. CFStringRef name##_ref = CFDictionaryGetValue(encoder_dict, key); \
  1332. CFIndex name##_len = \
  1333. CFStringGetMaximumSizeOfFileSystemRepresentation(name##_ref); \
  1334. char *name = bzalloc(name##_len + 1); \
  1335. CFStringGetFileSystemRepresentation(name##_ref, name, name##_len);
  1336. CMVideoCodecType codec_type = 0;
  1337. {
  1338. CFNumberRef codec_type_num = CFDictionaryGetValue(
  1339. encoder_dict, kVTVideoEncoderList_CodecType);
  1340. CFNumberGetValue(codec_type_num, kCFNumberSInt32Type,
  1341. &codec_type);
  1342. }
  1343. switch (codec_type) {
  1344. case kCMVideoCodecType_H264:
  1345. info.get_properties2 = vt_properties_h26x;
  1346. info.codec = "h264";
  1347. break;
  1348. #ifdef ENABLE_HEVC
  1349. case kCMVideoCodecType_HEVC:
  1350. info.get_properties2 = vt_properties_h26x;
  1351. info.codec = "hevc";
  1352. break;
  1353. #endif
  1354. // 422 is used as a marker for all ProRes types,
  1355. // since the type is stored as a profile
  1356. case kCMVideoCodecType_AppleProRes422:
  1357. info.get_properties2 = vt_properties_prores;
  1358. info.codec = "prores";
  1359. vt_add_prores_encoder_data_to_list(encoder_dict,
  1360. codec_type);
  1361. break;
  1362. case kCMVideoCodecType_AppleProRes4444XQ:
  1363. case kCMVideoCodecType_AppleProRes4444:
  1364. case kCMVideoCodecType_AppleProRes422Proxy:
  1365. case kCMVideoCodecType_AppleProRes422LT:
  1366. case kCMVideoCodecType_AppleProRes422HQ:
  1367. vt_add_prores_encoder_data_to_list(encoder_dict,
  1368. codec_type);
  1369. continue;
  1370. default:
  1371. continue;
  1372. }
  1373. VT_DICTSTR(kVTVideoEncoderList_EncoderID, id);
  1374. VT_DICTSTR(kVTVideoEncoderList_DisplayName, disp_name);
  1375. CFBooleanRef hardware_ref = CFDictionaryGetValue(
  1376. encoder_dict,
  1377. kVTVideoEncoderList_IsHardwareAccelerated);
  1378. bool hardware_accelerated =
  1379. (hardware_ref) ? CFBooleanGetValue(hardware_ref)
  1380. : false;
  1381. info.id = id;
  1382. struct vt_encoder_type_data *type_data =
  1383. bzalloc(sizeof(struct vt_encoder_type_data));
  1384. type_data->disp_name = disp_name;
  1385. type_data->id = id;
  1386. type_data->codec_type = codec_type;
  1387. type_data->hardware_accelerated = hardware_accelerated;
  1388. info.type_data = type_data;
  1389. obs_register_encoder(&info);
  1390. #undef VT_DICTSTR
  1391. }
  1392. CFRelease(encoder_list);
  1393. VT_LOG(LOG_INFO, "Added VideoToolbox encoders");
  1394. }
  1395. void obs_module_unload(void)
  1396. {
  1397. da_free(vt_prores_hardware_encoder_list);
  1398. da_free(vt_prores_software_encoder_list);
  1399. }