luma-key-filter.c 5.6 KB

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