luma-key-filter.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. #include <obs-module.h>
  2. /* clang-format off */
  3. #define SETTING_SDR_ONLY_INFO "sdr_only_info"
  4. #define SETTING_LUMA_MAX "luma_max"
  5. #define SETTING_LUMA_MIN "luma_min"
  6. #define SETTING_LUMA_MAX_SMOOTH "luma_max_smooth"
  7. #define SETTING_LUMA_MIN_SMOOTH "luma_min_smooth"
  8. #define TEXT_SDR_ONLY_INFO obs_module_text("SdrOnlyInfo")
  9. #define TEXT_LUMA_MAX obs_module_text("Luma.LumaMax")
  10. #define TEXT_LUMA_MIN obs_module_text("Luma.LumaMin")
  11. #define TEXT_LUMA_MAX_SMOOTH obs_module_text("Luma.LumaMaxSmooth")
  12. #define TEXT_LUMA_MIN_SMOOTH obs_module_text("Luma.LumaMinSmooth")
  13. /* clang-format on */
  14. struct luma_key_filter_data {
  15. obs_source_t *context;
  16. gs_effect_t *effect;
  17. gs_eparam_t *luma_max_param;
  18. gs_eparam_t *luma_min_param;
  19. gs_eparam_t *luma_max_smooth_param;
  20. gs_eparam_t *luma_min_smooth_param;
  21. float luma_max;
  22. float luma_min;
  23. float luma_max_smooth;
  24. float luma_min_smooth;
  25. };
  26. static const char *luma_key_name(void *unused)
  27. {
  28. UNUSED_PARAMETER(unused);
  29. return obs_module_text("LumaKeyFilter");
  30. }
  31. static void luma_key_update(void *data, obs_data_t *settings)
  32. {
  33. struct luma_key_filter_data *filter = data;
  34. double lumaMax = obs_data_get_double(settings, SETTING_LUMA_MAX);
  35. double lumaMin = obs_data_get_double(settings, SETTING_LUMA_MIN);
  36. double lumaMaxSmooth =
  37. obs_data_get_double(settings, SETTING_LUMA_MAX_SMOOTH);
  38. double lumaMinSmooth =
  39. obs_data_get_double(settings, SETTING_LUMA_MIN_SMOOTH);
  40. filter->luma_max = (float)lumaMax;
  41. filter->luma_min = (float)lumaMin;
  42. filter->luma_max_smooth = (float)lumaMaxSmooth;
  43. filter->luma_min_smooth = (float)lumaMinSmooth;
  44. }
  45. static void luma_key_destroy(void *data)
  46. {
  47. struct luma_key_filter_data *filter = data;
  48. if (filter->effect) {
  49. obs_enter_graphics();
  50. gs_effect_destroy(filter->effect);
  51. obs_leave_graphics();
  52. }
  53. bfree(data);
  54. }
  55. static void *luma_key_create_internal(obs_data_t *settings,
  56. obs_source_t *context,
  57. const char *effect_name)
  58. {
  59. struct luma_key_filter_data *filter =
  60. bzalloc(sizeof(struct luma_key_filter_data));
  61. char *effect_path = obs_module_file(effect_name);
  62. filter->context = context;
  63. obs_enter_graphics();
  64. filter->effect = gs_effect_create_from_file(effect_path, NULL);
  65. if (filter->effect) {
  66. filter->luma_max_param =
  67. gs_effect_get_param_by_name(filter->effect, "lumaMax");
  68. filter->luma_min_param =
  69. gs_effect_get_param_by_name(filter->effect, "lumaMin");
  70. filter->luma_max_smooth_param = gs_effect_get_param_by_name(
  71. filter->effect, "lumaMaxSmooth");
  72. filter->luma_min_smooth_param = gs_effect_get_param_by_name(
  73. filter->effect, "lumaMinSmooth");
  74. }
  75. obs_leave_graphics();
  76. bfree(effect_path);
  77. if (!filter->effect) {
  78. luma_key_destroy(filter);
  79. return NULL;
  80. }
  81. luma_key_update(filter, settings);
  82. return filter;
  83. }
  84. static void *luma_key_create_v1(obs_data_t *settings, obs_source_t *context)
  85. {
  86. return luma_key_create_internal(settings, context,
  87. "luma_key_filter.effect");
  88. }
  89. static void *luma_key_create_v2(obs_data_t *settings, obs_source_t *context)
  90. {
  91. return luma_key_create_internal(settings, context,
  92. "luma_key_filter_v2.effect");
  93. }
  94. static void luma_key_render_internal(void *data, bool premultiplied)
  95. {
  96. struct luma_key_filter_data *filter = data;
  97. const enum gs_color_space preferred_spaces[] = {
  98. GS_CS_SRGB,
  99. GS_CS_SRGB_16F,
  100. GS_CS_709_EXTENDED,
  101. };
  102. const enum gs_color_space source_space = obs_source_get_color_space(
  103. obs_filter_get_target(filter->context),
  104. OBS_COUNTOF(preferred_spaces), preferred_spaces);
  105. if (source_space == GS_CS_709_EXTENDED) {
  106. obs_source_skip_video_filter(filter->context);
  107. } else {
  108. const enum gs_color_format format =
  109. gs_get_format_from_space(source_space);
  110. if (obs_source_process_filter_begin_with_color_space(
  111. filter->context, format, source_space,
  112. OBS_ALLOW_DIRECT_RENDERING)) {
  113. gs_effect_set_float(filter->luma_max_param,
  114. filter->luma_max);
  115. gs_effect_set_float(filter->luma_min_param,
  116. filter->luma_min);
  117. gs_effect_set_float(filter->luma_max_smooth_param,
  118. filter->luma_max_smooth);
  119. gs_effect_set_float(filter->luma_min_smooth_param,
  120. filter->luma_min_smooth);
  121. if (premultiplied) {
  122. gs_blend_state_push();
  123. gs_blend_function(GS_BLEND_ONE,
  124. GS_BLEND_INVSRCALPHA);
  125. }
  126. obs_source_process_filter_end(filter->context,
  127. filter->effect, 0, 0);
  128. if (premultiplied) {
  129. gs_blend_state_pop();
  130. }
  131. }
  132. }
  133. }
  134. static void luma_key_render_v1(void *data, gs_effect_t *effect)
  135. {
  136. UNUSED_PARAMETER(effect);
  137. luma_key_render_internal(data, false);
  138. }
  139. static void luma_key_render_v2(void *data, gs_effect_t *effect)
  140. {
  141. UNUSED_PARAMETER(effect);
  142. luma_key_render_internal(data, true);
  143. }
  144. static obs_properties_t *luma_key_properties(void *data)
  145. {
  146. obs_properties_t *props = obs_properties_create();
  147. obs_properties_add_text(props, SETTING_SDR_ONLY_INFO,
  148. TEXT_SDR_ONLY_INFO, OBS_TEXT_INFO);
  149. obs_properties_add_float_slider(props, SETTING_LUMA_MAX, TEXT_LUMA_MAX,
  150. 0, 1, 0.0001);
  151. obs_properties_add_float_slider(props, SETTING_LUMA_MAX_SMOOTH,
  152. TEXT_LUMA_MAX_SMOOTH, 0, 1, 0.0001);
  153. obs_properties_add_float_slider(props, SETTING_LUMA_MIN, TEXT_LUMA_MIN,
  154. 0, 1, 0.0001);
  155. obs_properties_add_float_slider(props, SETTING_LUMA_MIN_SMOOTH,
  156. TEXT_LUMA_MIN_SMOOTH, 0, 1, 0.0001);
  157. UNUSED_PARAMETER(data);
  158. return props;
  159. }
  160. static void luma_key_defaults(obs_data_t *settings)
  161. {
  162. obs_data_set_default_double(settings, SETTING_LUMA_MAX, 1.0);
  163. obs_data_set_default_double(settings, SETTING_LUMA_MIN, 0.0);
  164. obs_data_set_default_double(settings, SETTING_LUMA_MAX_SMOOTH, 0.0);
  165. obs_data_set_default_double(settings, SETTING_LUMA_MIN_SMOOTH, 0.0);
  166. }
  167. static enum gs_color_space
  168. luma_key_get_color_space(void *data, size_t count,
  169. const enum gs_color_space *preferred_spaces)
  170. {
  171. UNUSED_PARAMETER(count);
  172. UNUSED_PARAMETER(preferred_spaces);
  173. const enum gs_color_space potential_spaces[] = {
  174. GS_CS_SRGB,
  175. GS_CS_SRGB_16F,
  176. GS_CS_709_EXTENDED,
  177. };
  178. struct luma_key_filter_data *const filter = data;
  179. const enum gs_color_space source_space = obs_source_get_color_space(
  180. obs_filter_get_target(filter->context),
  181. OBS_COUNTOF(potential_spaces), potential_spaces);
  182. return source_space;
  183. }
  184. struct obs_source_info luma_key_filter = {
  185. .id = "luma_key_filter",
  186. .type = OBS_SOURCE_TYPE_FILTER,
  187. .output_flags = OBS_SOURCE_VIDEO | OBS_SOURCE_CAP_OBSOLETE,
  188. .get_name = luma_key_name,
  189. .create = luma_key_create_v1,
  190. .destroy = luma_key_destroy,
  191. .video_render = luma_key_render_v1,
  192. .update = luma_key_update,
  193. .get_properties = luma_key_properties,
  194. .get_defaults = luma_key_defaults,
  195. };
  196. struct obs_source_info luma_key_filter_v2 = {
  197. .id = "luma_key_filter",
  198. .version = 2,
  199. .type = OBS_SOURCE_TYPE_FILTER,
  200. .output_flags = OBS_SOURCE_VIDEO | OBS_SOURCE_SRGB,
  201. .get_name = luma_key_name,
  202. .create = luma_key_create_v2,
  203. .destroy = luma_key_destroy,
  204. .video_render = luma_key_render_v2,
  205. .update = luma_key_update,
  206. .get_properties = luma_key_properties,
  207. .get_defaults = luma_key_defaults,
  208. .video_get_color_space = luma_key_get_color_space,
  209. };