encoder.c 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012
  1. #include <obs-module.h>
  2. #include <util/darray.h>
  3. #include <CoreFoundation/CoreFoundation.h>
  4. #include <VideoToolbox/VideoToolbox.h>
  5. #include <VideoToolbox/VTVideoEncoderList.h>
  6. #include <CoreMedia/CoreMedia.h>
  7. #include <util/apple/cfstring-utils.h>
  8. #include <assert.h>
  9. #define VT_LOG(level, format, ...) \
  10. blog(level, "[VideoToolbox encoder]: " format, ##__VA_ARGS__)
  11. #define VT_LOG_ENCODER(encoder, level, format, ...) \
  12. blog(level, "[VideoToolbox %s: 'h264']: " format, \
  13. obs_encoder_get_name(encoder), \
  14. ##__VA_ARGS__)
  15. #define VT_BLOG(level, format, ...) \
  16. VT_LOG_ENCODER(enc->encoder, level, format, \
  17. ##__VA_ARGS__)
  18. // Clipped from NSApplication as it is in a ObjC header
  19. extern const double NSAppKitVersionNumber;
  20. #define NSAppKitVersionNumber10_8 1187
  21. #define APPLE_H264_ENC_ID_HW "com.apple.videotoolbox.videoencoder.h264.gva"
  22. #define APPLE_H264_ENC_ID_SW "com.apple.videotoolbox.videoencoder.h264"
  23. // Get around missing symbol on 10.8 during compilation
  24. enum {
  25. kCMFormatDescriptionBridgeError_InvalidParameter_ = -12712,
  26. };
  27. static bool is_appkit10_9_or_greater()
  28. {
  29. return floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_8;
  30. }
  31. static DARRAY(struct vt_encoder {
  32. const char *name;
  33. const char *disp_name;
  34. const char *id;
  35. const char *codec_name;
  36. }) vt_encoders;
  37. struct vt_h264_encoder
  38. {
  39. obs_encoder_t *encoder;
  40. const char *vt_encoder_id;
  41. uint32_t width;
  42. uint32_t height;
  43. uint32_t keyint;
  44. uint32_t fps_num;
  45. uint32_t fps_den;
  46. uint32_t bitrate;
  47. bool limit_bitrate;
  48. uint32_t rc_max_bitrate;
  49. float rc_max_bitrate_window;
  50. const char *profile;
  51. bool bframes;
  52. enum video_format obs_pix_fmt;
  53. int vt_pix_fmt;
  54. enum video_colorspace colorspace;
  55. bool fullrange;
  56. VTCompressionSessionRef session;
  57. CMSimpleQueueRef queue;
  58. bool hw_enc;
  59. DARRAY(uint8_t) packet_data;
  60. DARRAY(uint8_t) extra_data;
  61. };
  62. static void log_osstatus(int log_level, struct vt_h264_encoder *enc,
  63. const char *context, OSStatus code)
  64. {
  65. char *c_str = NULL;
  66. CFErrorRef err = CFErrorCreate(kCFAllocatorDefault,
  67. kCFErrorDomainOSStatus, code, NULL);
  68. CFStringRef str = CFErrorCopyDescription(err);
  69. c_str = cfstr_copy_cstr(str, kCFStringEncodingUTF8);
  70. if (c_str) {
  71. if (enc)
  72. VT_BLOG(log_level, "Error in %s: %s", context, c_str);
  73. else
  74. VT_LOG(log_level, "Error in %s: %s", context, c_str);
  75. }
  76. bfree(c_str);
  77. CFRelease(str);
  78. CFRelease(err);
  79. }
  80. static CFStringRef obs_to_vt_profile(const char *profile)
  81. {
  82. if (strcmp(profile, "baseline") == 0)
  83. return kVTProfileLevel_H264_Baseline_AutoLevel;
  84. else if (strcmp(profile, "main") == 0)
  85. return kVTProfileLevel_H264_Main_AutoLevel;
  86. else if (strcmp(profile, "high") == 0)
  87. return kVTProfileLevel_H264_High_AutoLevel;
  88. else
  89. return kVTProfileLevel_H264_Main_AutoLevel;
  90. }
  91. static CFStringRef obs_to_vt_colorspace(enum video_colorspace cs)
  92. {
  93. if (cs == VIDEO_CS_709)
  94. return kCVImageBufferYCbCrMatrix_ITU_R_709_2;
  95. else if (cs == VIDEO_CS_601)
  96. return kCVImageBufferYCbCrMatrix_ITU_R_601_4;
  97. return NULL;
  98. }
  99. #define STATUS_CHECK(c) \
  100. code = c; \
  101. if (code) { \
  102. log_osstatus(LOG_ERROR, enc, #c, code); \
  103. goto fail; \
  104. }
  105. #define SESSION_CHECK(x) if ((code = (x)) != noErr) return code;
  106. static OSStatus session_set_prop_int(VTCompressionSessionRef session,
  107. CFStringRef key, int32_t val)
  108. {
  109. CFNumberRef n = CFNumberCreate(NULL, kCFNumberSInt32Type, &val);
  110. OSStatus code = VTSessionSetProperty(session, key, n);
  111. CFRelease(n);
  112. return code;
  113. }
  114. static OSStatus session_set_prop_str(VTCompressionSessionRef session,
  115. CFStringRef key, char *val)
  116. {
  117. CFStringRef s = CFStringCreateWithFileSystemRepresentation(NULL, val);
  118. OSStatus code = VTSessionSetProperty(session, key, s);
  119. CFRelease(s);
  120. return code;
  121. }
  122. static OSStatus session_set_prop(VTCompressionSessionRef session,
  123. CFStringRef key, CFTypeRef val)
  124. {
  125. return VTSessionSetProperty(session, key, val);
  126. }
  127. static OSStatus session_set_bitrate(VTCompressionSessionRef session,
  128. int new_bitrate, bool limit_bitrate, int max_bitrate,
  129. float max_bitrate_window)
  130. {
  131. OSStatus code;
  132. SESSION_CHECK(session_set_prop_int(session,
  133. kVTCompressionPropertyKey_AverageBitRate,
  134. new_bitrate * 1000));
  135. if (limit_bitrate) {
  136. int32_t cpb_size = max_bitrate * 125 * max_bitrate_window;
  137. CFNumberRef cf_cpb_size = CFNumberCreate(NULL,
  138. kCFNumberIntType, &cpb_size);
  139. CFNumberRef cf_cpb_window_s = CFNumberCreate(NULL,
  140. kCFNumberFloatType, &max_bitrate_window);
  141. CFMutableArrayRef rate_control = CFArrayCreateMutable(
  142. kCFAllocatorDefault, 2,
  143. &kCFTypeArrayCallBacks);
  144. CFArrayAppendValue(rate_control, cf_cpb_size);
  145. CFArrayAppendValue(rate_control, cf_cpb_window_s);
  146. code = session_set_prop(session,
  147. kVTCompressionPropertyKey_DataRateLimits,
  148. rate_control);
  149. CFRelease(cf_cpb_size);
  150. CFRelease(cf_cpb_window_s);
  151. CFRelease(rate_control);
  152. if (code == kVTPropertyNotSupportedErr) {
  153. log_osstatus(LOG_WARNING, NULL,
  154. "setting DataRateLimits on session", code);
  155. return noErr;
  156. }
  157. }
  158. return noErr;
  159. }
  160. static OSStatus session_set_colorspace(VTCompressionSessionRef session,
  161. enum video_colorspace cs)
  162. {
  163. CFStringRef matrix = obs_to_vt_colorspace(cs);
  164. OSStatus code;
  165. if (matrix != NULL) {
  166. SESSION_CHECK(session_set_prop(session,
  167. kVTCompressionPropertyKey_ColorPrimaries,
  168. kCVImageBufferColorPrimaries_ITU_R_709_2));
  169. SESSION_CHECK(session_set_prop(session,
  170. kVTCompressionPropertyKey_TransferFunction,
  171. kCVImageBufferTransferFunction_ITU_R_709_2));
  172. SESSION_CHECK(session_set_prop(session,
  173. kVTCompressionPropertyKey_YCbCrMatrix,
  174. matrix));
  175. }
  176. return noErr;
  177. }
  178. #undef SESSION_CHECK
  179. void sample_encoded_callback(void *data, void *source, OSStatus status,
  180. VTEncodeInfoFlags info_flags, CMSampleBufferRef buffer)
  181. {
  182. UNUSED_PARAMETER(status);
  183. UNUSED_PARAMETER(info_flags);
  184. CMSimpleQueueRef queue = data;
  185. CVPixelBufferRef pixbuf = source;
  186. if (buffer != NULL) {
  187. CFRetain(buffer);
  188. CMSimpleQueueEnqueue(queue, buffer);
  189. }
  190. CFRelease(pixbuf);
  191. }
  192. #define ENCODER_ID \
  193. kVTVideoEncoderSpecification_EncoderID
  194. #define ENABLE_HW_ACCEL \
  195. kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder
  196. #define REQUIRE_HW_ACCEL \
  197. kVTVideoEncoderSpecification_RequireHardwareAcceleratedVideoEncoder
  198. static inline CFMutableDictionaryRef create_encoder_spec(
  199. const char *vt_encoder_id)
  200. {
  201. CFMutableDictionaryRef encoder_spec = CFDictionaryCreateMutable(
  202. kCFAllocatorDefault,
  203. 3,
  204. &kCFTypeDictionaryKeyCallBacks,
  205. &kCFTypeDictionaryValueCallBacks);
  206. CFStringRef id = CFStringCreateWithFileSystemRepresentation(
  207. NULL, vt_encoder_id);
  208. CFDictionaryAddValue(encoder_spec, ENCODER_ID, id);
  209. CFRelease(id);
  210. CFDictionaryAddValue(encoder_spec, ENABLE_HW_ACCEL, kCFBooleanTrue);
  211. CFDictionaryAddValue(encoder_spec, REQUIRE_HW_ACCEL, kCFBooleanFalse);
  212. return encoder_spec;
  213. }
  214. #undef ENCODER_ID
  215. #undef REQUIRE_HW_ACCEL
  216. #undef ENABLE_HW_ACCEL
  217. static inline CFMutableDictionaryRef create_pixbuf_spec(
  218. struct vt_h264_encoder *enc)
  219. {
  220. CFMutableDictionaryRef pixbuf_spec = CFDictionaryCreateMutable(
  221. kCFAllocatorDefault,
  222. 3,
  223. &kCFTypeDictionaryKeyCallBacks,
  224. &kCFTypeDictionaryValueCallBacks);
  225. CFNumberRef n = CFNumberCreate(NULL, kCFNumberSInt32Type,
  226. &enc->vt_pix_fmt);
  227. CFDictionaryAddValue(pixbuf_spec, kCVPixelBufferPixelFormatTypeKey, n);
  228. CFRelease(n);
  229. n = CFNumberCreate(NULL, kCFNumberSInt32Type, &enc->width);
  230. CFDictionaryAddValue(pixbuf_spec, kCVPixelBufferWidthKey, n);
  231. CFRelease(n);
  232. n = CFNumberCreate(NULL, kCFNumberSInt32Type, &enc->height);
  233. CFDictionaryAddValue(pixbuf_spec, kCVPixelBufferHeightKey, n);
  234. CFRelease(n);
  235. return pixbuf_spec;
  236. }
  237. static bool create_encoder(struct vt_h264_encoder *enc)
  238. {
  239. OSStatus code;
  240. VTCompressionSessionRef s;
  241. CFDictionaryRef encoder_spec = create_encoder_spec(enc->vt_encoder_id);
  242. CFDictionaryRef pixbuf_spec = create_pixbuf_spec(enc);
  243. STATUS_CHECK(VTCompressionSessionCreate(
  244. kCFAllocatorDefault,
  245. enc->width,
  246. enc->height,
  247. kCMVideoCodecType_H264,
  248. encoder_spec,
  249. pixbuf_spec,
  250. NULL,
  251. &sample_encoded_callback,
  252. enc->queue,
  253. &s));
  254. CFRelease(encoder_spec);
  255. CFRelease(pixbuf_spec);
  256. CFBooleanRef b = NULL;
  257. code = VTSessionCopyProperty(s,
  258. kVTCompressionPropertyKey_UsingHardwareAcceleratedVideoEncoder,
  259. NULL, &b);
  260. if (code == noErr && (enc->hw_enc = CFBooleanGetValue(b)))
  261. VT_BLOG(LOG_INFO, "session created with hardware encoding");
  262. else
  263. enc->hw_enc = false;
  264. if (b != NULL)
  265. CFRelease(b);
  266. STATUS_CHECK(session_set_prop_int(s,
  267. kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration,
  268. enc->keyint));
  269. STATUS_CHECK(session_set_prop_int(s,
  270. kVTCompressionPropertyKey_MaxKeyFrameInterval,
  271. enc->keyint * ((float)enc->fps_num/enc->fps_den)));
  272. STATUS_CHECK(session_set_prop_int(s,
  273. kVTCompressionPropertyKey_ExpectedFrameRate,
  274. ceil((float)enc->fps_num/ enc->fps_den)));
  275. STATUS_CHECK(session_set_prop(s,
  276. kVTCompressionPropertyKey_AllowFrameReordering,
  277. enc->bframes ? kCFBooleanTrue : kCFBooleanFalse));
  278. // This can fail depending on hardware configuration
  279. code = session_set_prop(s, kVTCompressionPropertyKey_RealTime,
  280. kCFBooleanTrue);
  281. if (code != noErr)
  282. log_osstatus(LOG_WARNING, enc,
  283. "setting "
  284. "kVTCompressionPropertyKey_RealTime, "
  285. "frame delay might be increased",
  286. code);
  287. STATUS_CHECK(session_set_prop(s,
  288. kVTCompressionPropertyKey_ProfileLevel,
  289. obs_to_vt_profile(enc->profile)));
  290. STATUS_CHECK(session_set_bitrate(s, enc->bitrate, enc->limit_bitrate,
  291. enc->rc_max_bitrate, enc->rc_max_bitrate_window));
  292. STATUS_CHECK(session_set_colorspace(s, enc->colorspace));
  293. STATUS_CHECK(VTCompressionSessionPrepareToEncodeFrames(s));
  294. enc->session = s;
  295. return true;
  296. fail:
  297. if (encoder_spec != NULL)
  298. CFRelease(encoder_spec);
  299. if (pixbuf_spec != NULL)
  300. CFRelease(pixbuf_spec);
  301. return false;
  302. }
  303. static void vt_h264_destroy(void *data)
  304. {
  305. struct vt_h264_encoder *enc = data;
  306. if (enc) {
  307. if (enc->session != NULL) {
  308. VTCompressionSessionInvalidate(enc->session);
  309. CFRelease(enc->session);
  310. }
  311. da_free(enc->packet_data);
  312. da_free(enc->extra_data);
  313. bfree(enc);
  314. }
  315. }
  316. static void dump_encoder_info(struct vt_h264_encoder *enc)
  317. {
  318. VT_BLOG(LOG_INFO, "settings:\n"
  319. "\tvt_encoder_id %s\n"
  320. "\tbitrate: %d (kbps)\n"
  321. "\tfps_num: %d\n"
  322. "\tfps_den: %d\n"
  323. "\twidth: %d\n"
  324. "\theight: %d\n"
  325. "\tkeyint: %d (s)\n"
  326. "\tlimit_bitrate: %s\n"
  327. "\trc_max_bitrate: %d (kbps)\n"
  328. "\trc_max_bitrate_window: %f (s)\n"
  329. "\thw_enc: %s\n"
  330. "\tprofile: %s\n",
  331. enc->vt_encoder_id,
  332. enc->bitrate,
  333. enc->fps_num,
  334. enc->fps_den,
  335. enc->width,
  336. enc->height,
  337. enc->keyint,
  338. enc->limit_bitrate ? "on" : "off",
  339. enc->rc_max_bitrate,
  340. enc->rc_max_bitrate_window,
  341. enc->hw_enc ? "on" : "off",
  342. (enc->profile != NULL && !!strlen(enc->profile))
  343. ? enc->profile : "default");
  344. }
  345. static void vt_h264_video_info(void *data, struct video_scale_info *info)
  346. {
  347. struct vt_h264_encoder *enc = data;
  348. if (info->format == VIDEO_FORMAT_I420) {
  349. enc->obs_pix_fmt = info->format;
  350. enc->vt_pix_fmt = enc->fullrange ?
  351. kCVPixelFormatType_420YpCbCr8PlanarFullRange
  352. : kCVPixelFormatType_420YpCbCr8Planar;
  353. return;
  354. }
  355. if (info->format == VIDEO_FORMAT_I444)
  356. VT_BLOG(LOG_WARNING, "I444 color format not supported");
  357. // Anything else, return default
  358. enc->obs_pix_fmt = VIDEO_FORMAT_NV12;
  359. enc->vt_pix_fmt = enc->fullrange ?
  360. kCVPixelFormatType_420YpCbCr8BiPlanarFullRange
  361. : kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange;
  362. info->format = enc->obs_pix_fmt;
  363. }
  364. static void update_params(struct vt_h264_encoder *enc, obs_data_t *settings)
  365. {
  366. video_t *video = obs_encoder_video(enc->encoder);
  367. const struct video_output_info *voi = video_output_get_info(video);
  368. struct video_scale_info info = { .format = voi->format };
  369. enc->fullrange = voi->range == VIDEO_RANGE_FULL;
  370. // also sets the enc->vt_pix_fmt
  371. vt_h264_video_info(enc, &info);
  372. enc->colorspace = voi->colorspace;
  373. enc->width = obs_encoder_get_width(enc->encoder);
  374. enc->height = obs_encoder_get_height(enc->encoder);
  375. enc->fps_num = voi->fps_num;
  376. enc->fps_den = voi->fps_den;
  377. enc->keyint = (uint32_t)obs_data_get_int(settings, "keyint_sec");
  378. enc->bitrate = (uint32_t)obs_data_get_int(settings, "bitrate");
  379. enc->profile = obs_data_get_string(settings, "profile");
  380. enc->limit_bitrate = obs_data_get_bool(settings, "limit_bitrate");
  381. enc->rc_max_bitrate = obs_data_get_int(settings, "max_bitrate");
  382. enc->rc_max_bitrate_window = obs_data_get_double(settings,
  383. "max_bitrate_window");
  384. enc->bframes = obs_data_get_bool(settings, "bframes");
  385. }
  386. static bool vt_h264_update(void *data, obs_data_t *settings)
  387. {
  388. struct vt_h264_encoder *enc = data;
  389. uint32_t old_bitrate = enc->bitrate;
  390. bool old_limit_bitrate = enc->limit_bitrate;
  391. update_params(enc, settings);
  392. if (old_bitrate == enc->bitrate &&
  393. old_limit_bitrate == enc->limit_bitrate)
  394. return true;
  395. OSStatus code = session_set_bitrate(enc->session,
  396. enc->bitrate, enc->limit_bitrate, enc->rc_max_bitrate,
  397. enc->rc_max_bitrate_window);
  398. if (code != noErr)
  399. VT_BLOG(LOG_WARNING,
  400. "failed to set bitrate to session");
  401. CFNumberRef n;
  402. VTSessionCopyProperty(enc->session,
  403. kVTCompressionPropertyKey_AverageBitRate, NULL,
  404. &n);
  405. uint32_t session_bitrate;
  406. CFNumberGetValue(n, kCFNumberIntType, &session_bitrate);
  407. CFRelease(n);
  408. if (session_bitrate == old_bitrate) {
  409. VT_BLOG(LOG_WARNING, "failed to update current session "
  410. " bitrate from %d->%d",
  411. old_bitrate, enc->bitrate);
  412. }
  413. dump_encoder_info(enc);
  414. return true;
  415. }
  416. static void *vt_h264_create(obs_data_t *settings,
  417. obs_encoder_t *encoder, const char *vt_encoder_id)
  418. {
  419. struct vt_h264_encoder *enc = bzalloc(sizeof(struct vt_h264_encoder));
  420. OSStatus code;
  421. enc->encoder = encoder;
  422. enc->vt_encoder_id = vt_encoder_id;
  423. update_params(enc, settings);
  424. STATUS_CHECK(CMSimpleQueueCreate(NULL, 100, &enc->queue));
  425. if (!create_encoder(enc))
  426. goto fail;
  427. dump_encoder_info(enc);
  428. return enc;
  429. fail:
  430. vt_h264_destroy(enc);
  431. return NULL;
  432. }
  433. static void *vt_h264_create_hw(obs_data_t *settings, obs_encoder_t *encoder)
  434. {
  435. return vt_h264_create(settings, encoder, APPLE_H264_ENC_ID_HW);
  436. }
  437. static void *vt_h264_create_sw(obs_data_t *settings, obs_encoder_t *encoder)
  438. {
  439. return vt_h264_create(settings, encoder, APPLE_H264_ENC_ID_SW);
  440. }
  441. static const uint8_t annexb_startcode[4] = {0, 0, 0, 1};
  442. static void packet_put(struct darray *packet, const uint8_t *buf, size_t size)
  443. {
  444. darray_push_back_array(sizeof(uint8_t), packet, buf, size);
  445. }
  446. static void packet_put_startcode(struct darray *packet, int size)
  447. {
  448. assert(size == 3 || size == 4);
  449. packet_put(packet, &annexb_startcode[4 - size], size);
  450. }
  451. static void convert_block_nals_to_annexb(struct vt_h264_encoder *enc,
  452. struct darray *packet, CMBlockBufferRef block,
  453. int nal_length_bytes)
  454. {
  455. size_t block_size;
  456. uint8_t *block_buf;
  457. CMBlockBufferGetDataPointer(block, 0, NULL, &block_size,
  458. (char **)&block_buf);
  459. size_t bytes_remaining = block_size;
  460. while(bytes_remaining > 0) {
  461. uint32_t nal_size;
  462. if (nal_length_bytes == 1)
  463. nal_size = block_buf[0];
  464. else if (nal_length_bytes == 2)
  465. nal_size = CFSwapInt16BigToHost(
  466. ((uint16_t *)block_buf)[0]);
  467. else if (nal_length_bytes == 4)
  468. nal_size = CFSwapInt32BigToHost(
  469. ((uint32_t *)block_buf)[0]);
  470. else
  471. return;
  472. bytes_remaining -= nal_length_bytes;
  473. block_buf += nal_length_bytes;
  474. if (bytes_remaining < nal_size) {
  475. VT_BLOG(LOG_ERROR, "invalid nal block");
  476. return;
  477. }
  478. packet_put_startcode(packet, 3);
  479. packet_put(packet, block_buf, nal_size);
  480. bytes_remaining -= nal_size;
  481. block_buf += nal_size;
  482. }
  483. }
  484. static bool handle_keyframe(struct vt_h264_encoder *enc,
  485. CMFormatDescriptionRef format_desc, size_t param_count,
  486. struct darray *packet, struct darray *extra_data)
  487. {
  488. OSStatus code;
  489. const uint8_t *param;
  490. size_t param_size;
  491. for(size_t i = 0; i < param_count; i++) {
  492. code = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(
  493. format_desc, i, &param, &param_size,
  494. NULL, NULL);
  495. if (code != noErr) {
  496. log_osstatus(LOG_ERROR, enc,
  497. "getting NAL parameter "
  498. "at index", code);
  499. return false;
  500. }
  501. packet_put_startcode(packet, 4);
  502. packet_put(packet, param, param_size);
  503. }
  504. // if we were passed an extra_data array, fill it with
  505. // SPS, PPS, etc.
  506. if (extra_data != NULL)
  507. packet_put(extra_data, packet->array, packet->num);
  508. return true;
  509. }
  510. static bool convert_sample_to_annexb(struct vt_h264_encoder *enc,
  511. struct darray *packet, struct darray *extra_data,
  512. CMSampleBufferRef buffer, bool keyframe)
  513. {
  514. OSStatus code;
  515. CMFormatDescriptionRef format_desc =
  516. CMSampleBufferGetFormatDescription(buffer);
  517. size_t param_count;
  518. int nal_length_bytes;
  519. code = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(format_desc,
  520. 0, NULL, NULL, &param_count, &nal_length_bytes);
  521. // it is not clear what errors this function can return
  522. // so we check the two most reasonable
  523. if (code == kCMFormatDescriptionBridgeError_InvalidParameter_ ||
  524. code == kCMFormatDescriptionError_InvalidParameter) {
  525. VT_BLOG(LOG_WARNING, "assuming 2 parameter sets "
  526. "and 4 byte NAL length header");
  527. param_count = 2;
  528. nal_length_bytes = 4;
  529. } else if (code != noErr) {
  530. log_osstatus(LOG_ERROR, enc,
  531. "getting parameter count from sample",
  532. code);
  533. return false;
  534. }
  535. if (keyframe && !handle_keyframe(enc, format_desc, param_count,
  536. packet, extra_data))
  537. return false;
  538. CMBlockBufferRef block = CMSampleBufferGetDataBuffer(buffer);
  539. convert_block_nals_to_annexb(enc, packet, block, nal_length_bytes);
  540. return true;
  541. }
  542. static bool is_sample_keyframe(CMSampleBufferRef buffer)
  543. {
  544. CFArrayRef attachments = CMSampleBufferGetSampleAttachmentsArray(
  545. buffer, false);
  546. if(attachments != NULL) {
  547. CFDictionaryRef attachment;
  548. CFBooleanRef has_dependencies;
  549. attachment = (CFDictionaryRef)CFArrayGetValueAtIndex(
  550. attachments, 0);
  551. has_dependencies = (CFBooleanRef)CFDictionaryGetValue(
  552. attachment, kCMSampleAttachmentKey_DependsOnOthers);
  553. return has_dependencies == kCFBooleanFalse;
  554. }
  555. return false;
  556. }
  557. static bool parse_sample(struct vt_h264_encoder *enc, CMSampleBufferRef buffer,
  558. struct encoder_packet *packet, CMTime off)
  559. {
  560. CMTime pts = CMSampleBufferGetPresentationTimeStamp(buffer);
  561. CMTime dts = CMSampleBufferGetDecodeTimeStamp(buffer);
  562. pts = CMTimeMultiplyByFloat64(pts,
  563. ((Float64)enc->fps_num/enc->fps_den));
  564. dts = CMTimeMultiplyByFloat64(dts,
  565. ((Float64)enc->fps_num/enc->fps_den));
  566. // imitate x264's negative dts when bframes might have pts < dts
  567. if (enc->bframes)
  568. dts = CMTimeSubtract(dts, off);
  569. bool keyframe = is_sample_keyframe(buffer);
  570. da_resize(enc->packet_data, 0);
  571. // If we are still looking for extra data
  572. struct darray *extra_data = NULL;
  573. if (enc->extra_data.num == 0)
  574. extra_data = &enc->extra_data.da;
  575. if (!convert_sample_to_annexb(enc, &enc->packet_data.da, extra_data,
  576. buffer, keyframe))
  577. goto fail;
  578. packet->type = OBS_ENCODER_VIDEO;
  579. packet->pts = (int64_t)(CMTimeGetSeconds(pts));
  580. packet->dts = (int64_t)(CMTimeGetSeconds(dts));
  581. packet->data = enc->packet_data.array;
  582. packet->size = enc->packet_data.num;
  583. packet->keyframe = keyframe;
  584. CFRelease(buffer);
  585. return true;
  586. fail:
  587. CFRelease(buffer);
  588. return false;
  589. }
  590. bool get_cached_pixel_buffer(struct vt_h264_encoder *enc,
  591. CVPixelBufferRef *buf)
  592. {
  593. OSStatus code;
  594. CVPixelBufferPoolRef pool =
  595. VTCompressionSessionGetPixelBufferPool(
  596. enc->session);
  597. if (!pool)
  598. return kCVReturnError;
  599. CVPixelBufferRef pixbuf;
  600. STATUS_CHECK(CVPixelBufferPoolCreatePixelBuffer(NULL, pool,
  601. &pixbuf));
  602. // Why aren't these already set on the pixel buffer?
  603. // I would have expected pixel buffers from the session's
  604. // pool to have the correct color space stuff set
  605. CFStringRef matrix = obs_to_vt_colorspace(enc->colorspace);
  606. CVBufferSetAttachment(pixbuf,
  607. kCVImageBufferYCbCrMatrixKey,
  608. matrix,
  609. kCVAttachmentMode_ShouldPropagate);
  610. CVBufferSetAttachment(pixbuf,
  611. kCVImageBufferColorPrimariesKey,
  612. kCVImageBufferColorPrimaries_ITU_R_709_2,
  613. kCVAttachmentMode_ShouldPropagate);
  614. CVBufferSetAttachment(pixbuf,
  615. kCVImageBufferTransferFunctionKey,
  616. kCVImageBufferTransferFunction_ITU_R_709_2,
  617. kCVAttachmentMode_ShouldPropagate);
  618. *buf = pixbuf;
  619. return true;
  620. fail:
  621. return false;
  622. }
  623. static bool vt_h264_encode(void *data, struct encoder_frame *frame,
  624. struct encoder_packet *packet, bool *received_packet)
  625. {
  626. struct vt_h264_encoder *enc = data;
  627. OSStatus code;
  628. CMTime dur = CMTimeMake(enc->fps_den, enc->fps_num);
  629. CMTime off = CMTimeMultiply(dur, 2);
  630. CMTime pts = CMTimeMultiply(dur, frame->pts);
  631. CVPixelBufferRef pixbuf = NULL;
  632. if (!get_cached_pixel_buffer(enc, &pixbuf)) {
  633. VT_BLOG(LOG_ERROR, "Unable to create pixel buffer");
  634. goto fail;
  635. }
  636. STATUS_CHECK(CVPixelBufferLockBaseAddress(pixbuf, 0));
  637. for(int i = 0; i < MAX_AV_PLANES; i++) {
  638. if (frame->data[i] == NULL)
  639. break;
  640. uint8_t *p = (uint8_t *)CVPixelBufferGetBaseAddressOfPlane(
  641. pixbuf, i);
  642. uint8_t *f = frame->data[i];
  643. size_t plane_linesize = CVPixelBufferGetBytesPerRowOfPlane(
  644. pixbuf, i);
  645. size_t plane_height = CVPixelBufferGetHeightOfPlane(pixbuf, i);
  646. for(size_t j = 0; j < plane_height; j++) {
  647. memcpy(p, f, frame->linesize[i]);
  648. p += plane_linesize;
  649. f += frame->linesize[i];
  650. }
  651. }
  652. STATUS_CHECK(CVPixelBufferUnlockBaseAddress(pixbuf, 0));
  653. STATUS_CHECK(VTCompressionSessionEncodeFrame(enc->session, pixbuf, pts,
  654. dur, NULL, pixbuf, NULL));
  655. CMSampleBufferRef buffer =
  656. (CMSampleBufferRef)CMSimpleQueueDequeue(enc->queue);
  657. // No samples waiting in the queue
  658. if (buffer == NULL)
  659. return true;
  660. *received_packet = true;
  661. return parse_sample(enc, buffer, packet, off);
  662. fail:
  663. return false;
  664. }
  665. #undef STATUS_CHECK
  666. #undef CFNUM_INT
  667. static bool vt_h264_extra_data(void *data, uint8_t **extra_data, size_t *size)
  668. {
  669. struct vt_h264_encoder *enc = (struct vt_h264_encoder *)data;
  670. *extra_data = enc->extra_data.array;
  671. *size = enc->extra_data.num;
  672. return true;
  673. }
  674. static const char *vt_h264_getname_hw(void *unused)
  675. {
  676. UNUSED_PARAMETER(unused);
  677. return obs_module_text("VTH264EncHW");
  678. }
  679. static const char *vt_h264_getname_sw(void *unused)
  680. {
  681. UNUSED_PARAMETER(unused);
  682. return obs_module_text("VTH264EncSW");
  683. }
  684. #define TEXT_VT_ENCODER obs_module_text("VTEncoder")
  685. #define TEXT_BITRATE obs_module_text("Bitrate")
  686. #define TEXT_USE_MAX_BITRATE obs_module_text("UseMaxBitrate")
  687. #define TEXT_MAX_BITRATE obs_module_text("MaxBitrate")
  688. #define TEXT_MAX_BITRATE_WINDOW obs_module_text("MaxBitrateWindow")
  689. #define TEXT_KEYINT_SEC obs_module_text("KeyframeIntervalSec")
  690. #define TEXT_PROFILE obs_module_text("Profile")
  691. #define TEXT_NONE obs_module_text("None")
  692. #define TEXT_DEFAULT obs_module_text("DefaultEncoder")
  693. #define TEXT_BFRAMES obs_module_text("UseBFrames")
  694. static bool limit_bitrate_modified(obs_properties_t *ppts, obs_property_t *p,
  695. obs_data_t *settings)
  696. {
  697. bool use_max_bitrate = obs_data_get_bool(settings, "limit_bitrate");
  698. p = obs_properties_get(ppts, "max_bitrate");
  699. obs_property_set_visible(p, use_max_bitrate);
  700. p = obs_properties_get(ppts, "max_bitrate_window");
  701. obs_property_set_visible(p, use_max_bitrate);
  702. return true;
  703. }
  704. static obs_properties_t *vt_h264_properties(void *unused)
  705. {
  706. UNUSED_PARAMETER(unused);
  707. obs_properties_t *props = obs_properties_create();
  708. obs_property_t *p;
  709. obs_properties_add_int(props, "bitrate", TEXT_BITRATE, 50, 10000000, 1);
  710. p = obs_properties_add_bool(props, "limit_bitrate",
  711. TEXT_USE_MAX_BITRATE);
  712. obs_property_set_modified_callback(p, limit_bitrate_modified);
  713. obs_properties_add_int(props, "max_bitrate", TEXT_MAX_BITRATE, 50,
  714. 10000000, 1);
  715. obs_properties_add_float(props, "max_bitrate_window",
  716. TEXT_MAX_BITRATE_WINDOW, 0.10f, 10.0f, 0.25f);
  717. obs_properties_add_int(props, "keyint_sec", TEXT_KEYINT_SEC, 0, 20, 1);
  718. p = obs_properties_add_list(props, "profile", TEXT_PROFILE,
  719. OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
  720. obs_property_list_add_string(p, TEXT_NONE, "");
  721. obs_property_list_add_string(p, "baseline", "baseline");
  722. obs_property_list_add_string(p, "main", "main");
  723. obs_property_list_add_string(p, "high", "high");
  724. obs_properties_add_bool(props, "bframes", TEXT_BFRAMES);
  725. return props;
  726. }
  727. static void vt_h264_defaults(obs_data_t *settings)
  728. {
  729. obs_data_set_default_int(settings, "bitrate", 2500);
  730. obs_data_set_default_bool(settings, "limit_bitrate", false);
  731. obs_data_set_default_int(settings, "max_bitrate", 2500);
  732. obs_data_set_default_double(settings, "max_bitrate_window", 1.5f);
  733. obs_data_set_default_int(settings, "keyint_sec", 0);
  734. obs_data_set_default_string(settings, "profile", "");
  735. obs_data_set_default_bool(settings, "bframes", true);
  736. }
  737. OBS_DECLARE_MODULE()
  738. OBS_MODULE_USE_DEFAULT_LOCALE("mac-h264", "en-US")
  739. void encoder_list_create()
  740. {
  741. CFArrayRef encoder_list;
  742. VTCopyVideoEncoderList(NULL, &encoder_list);
  743. CFIndex size = CFArrayGetCount(encoder_list);
  744. for(CFIndex i = 0; i < size; i++) {
  745. CFDictionaryRef encoder_dict =
  746. CFArrayGetValueAtIndex(encoder_list, i);
  747. #define VT_DICTSTR(key, name) \
  748. CFStringRef name ## _ref = CFDictionaryGetValue(encoder_dict, key); \
  749. CFIndex name ## _len = CFStringGetLength(name ## _ref); \
  750. char * name = bzalloc(name ## _len + 1); \
  751. CFStringGetFileSystemRepresentation(name ## _ref, name, name ## _len);
  752. VT_DICTSTR(kVTVideoEncoderList_CodecName, codec_name);
  753. if (strcmp("H.264", codec_name) != 0) {
  754. bfree(codec_name);
  755. continue;
  756. }
  757. VT_DICTSTR(kVTVideoEncoderList_EncoderName, name);
  758. VT_DICTSTR(kVTVideoEncoderList_EncoderID, id);
  759. VT_DICTSTR(kVTVideoEncoderList_DisplayName, disp_name);
  760. struct vt_encoder enc = {
  761. .name = name,
  762. .id = id,
  763. .disp_name = disp_name,
  764. .codec_name = codec_name
  765. };
  766. da_push_back(vt_encoders, &enc);
  767. #undef VT_DICTSTR
  768. }
  769. }
  770. void encoder_list_destroy()
  771. {
  772. for(size_t i = 0; i < vt_encoders.num; i++) {
  773. bfree((char *)vt_encoders.array[i].name);
  774. bfree((char *)vt_encoders.array[i].id);
  775. bfree((char *)vt_encoders.array[i].codec_name);
  776. bfree((char *)vt_encoders.array[i].disp_name);
  777. }
  778. da_free(vt_encoders);
  779. }
  780. void register_encoders()
  781. {
  782. struct obs_encoder_info info = {
  783. .type = OBS_ENCODER_VIDEO,
  784. .codec = "h264",
  785. .destroy = vt_h264_destroy,
  786. .encode = vt_h264_encode,
  787. .update = vt_h264_update,
  788. .get_properties = vt_h264_properties,
  789. .get_defaults = vt_h264_defaults,
  790. .get_video_info = vt_h264_video_info,
  791. .get_extra_data = vt_h264_extra_data
  792. };
  793. for(size_t i = 0; i < vt_encoders.num; i++) {
  794. if (strcmp(vt_encoders.array[i].id,
  795. APPLE_H264_ENC_ID_HW) == 0) {
  796. info.id = "vt_h264_hw";
  797. info.get_name = vt_h264_getname_hw;
  798. info.create = vt_h264_create_hw;
  799. obs_register_encoder(&info);
  800. } else if (strcmp(vt_encoders.array[i].id,
  801. APPLE_H264_ENC_ID_SW) == 0) {
  802. info.id = "vt_h264_sw";
  803. info.get_name = vt_h264_getname_sw;
  804. info.create = vt_h264_create_sw;
  805. obs_register_encoder(&info);
  806. }
  807. }
  808. }
  809. bool obs_module_load(void)
  810. {
  811. if (!is_appkit10_9_or_greater()) {
  812. VT_LOG(LOG_WARNING, "Not adding VideoToolbox H264 encoder; "
  813. "AppKit must be version 10.9 or greater");
  814. return false;
  815. }
  816. encoder_list_create();
  817. register_encoders();
  818. VT_LOG(LOG_INFO, "Adding VideoToolbox H264 encoders");
  819. return true;
  820. }
  821. void obs_module_unload(void)
  822. {
  823. encoder_list_destroy();
  824. }