2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * The Original Code is Copyright (C) 2012 Blender Foundation.
19 * All rights reserved.
21 * Contributor(s): Blender Foundation,
24 * ***** END GPL LICENSE BLOCK *****
27 /** \file blender/blenkernel/intern/seqmodifier.c
34 #include "MEM_guardedalloc.h"
36 #include "BLI_listbase.h"
37 #include "BLI_path_util.h"
38 #include "BLI_string.h"
39 #include "BLI_utildefines.h"
42 #include "BLF_translation.h"
44 #include "DNA_sequence_types.h"
46 #include "BKE_colortools.h"
47 #include "BKE_sequencer.h"
49 #include "IMB_imbuf.h"
50 #include "IMB_imbuf_types.h"
52 static SequenceModifierTypeInfo *modifiersTypes[NUM_SEQUENCE_MODIFIER_TYPES];
53 static bool modifierTypesInit = false;
55 /*********************** Modifiers *************************/
57 typedef void (*modifier_apply_threaded_cb) (int width, int height, unsigned char *rect, float *rect_float,
58 unsigned char *mask_rect, float *mask_rect_float, void *data_v);
60 typedef struct ModifierInitData {
65 modifier_apply_threaded_cb apply_callback;
68 typedef struct ModifierThread {
71 unsigned char *rect, *mask_rect;
72 float *rect_float, *mask_rect_float;
76 modifier_apply_threaded_cb apply_callback;
80 static ImBuf *modifier_mask_get(SequenceModifierData *smd, const SeqRenderData *context, int cfra, int fra_offset, bool make_float)
82 return BKE_sequencer_render_mask_input(context, smd->mask_input_type, smd->mask_sequence, smd->mask_id, cfra, fra_offset, make_float);
85 static void modifier_init_handle(void *handle_v, int start_line, int tot_line, void *init_data_v)
87 ModifierThread *handle = (ModifierThread *) handle_v;
88 ModifierInitData *init_data = (ModifierInitData *) init_data_v;
89 ImBuf *ibuf = init_data->ibuf;
90 ImBuf *mask = init_data->mask;
92 int offset = 4 * start_line * ibuf->x;
94 memset(handle, 0, sizeof(ModifierThread));
96 handle->width = ibuf->x;
97 handle->height = tot_line;
98 handle->apply_callback = init_data->apply_callback;
99 handle->user_data = init_data->user_data;
102 handle->rect = (unsigned char *) ibuf->rect + offset;
104 if (ibuf->rect_float)
105 handle->rect_float = ibuf->rect_float + offset;
109 handle->mask_rect = (unsigned char *) mask->rect + offset;
111 if (mask->rect_float)
112 handle->mask_rect_float = mask->rect_float + offset;
115 handle->mask_rect = NULL;
116 handle->mask_rect_float = NULL;
120 static void *modifier_do_thread(void *thread_data_v)
122 ModifierThread *td = (ModifierThread *) thread_data_v;
124 td->apply_callback(td->width, td->height, td->rect, td->rect_float, td->mask_rect, td->mask_rect_float, td->user_data);
129 static void modifier_apply_threaded(ImBuf *ibuf, ImBuf *mask, modifier_apply_threaded_cb apply_callback, void *user_data)
131 ModifierInitData init_data;
133 init_data.ibuf = ibuf;
134 init_data.mask = mask;
135 init_data.user_data = user_data;
137 init_data.apply_callback = apply_callback;
139 IMB_processor_apply_threaded(ibuf->y, sizeof(ModifierThread), &init_data,
140 modifier_init_handle, modifier_do_thread);
143 /* **** Color Balance Modifier **** */
145 static void colorBalance_init_data(SequenceModifierData *smd)
147 ColorBalanceModifierData *cbmd = (ColorBalanceModifierData *) smd;
150 cbmd->color_multiply = 1.0f;
152 for (c = 0; c < 3; c++) {
153 cbmd->color_balance.lift[c] = 1.0f;
154 cbmd->color_balance.gamma[c] = 1.0f;
155 cbmd->color_balance.gain[c] = 1.0f;
159 static void colorBalance_apply(SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
161 ColorBalanceModifierData *cbmd = (ColorBalanceModifierData *) smd;
163 BKE_sequencer_color_balance_apply(&cbmd->color_balance, ibuf, cbmd->color_multiply, false, mask);
166 static SequenceModifierTypeInfo seqModifier_ColorBalance = {
167 CTX_N_(BLF_I18NCONTEXT_ID_SEQUENCE, "Color Balance"), /* name */
168 "ColorBalanceModifierData", /* struct_name */
169 sizeof(ColorBalanceModifierData), /* struct_size */
170 colorBalance_init_data, /* init_data */
171 NULL, /* free_data */
172 NULL, /* copy_data */
173 colorBalance_apply /* apply */
176 /* **** Curves Modifier **** */
178 static void curves_init_data(SequenceModifierData *smd)
180 CurvesModifierData *cmd = (CurvesModifierData *) smd;
182 curvemapping_set_defaults(&cmd->curve_mapping, 4, 0.0f, 0.0f, 1.0f, 1.0f);
185 static void curves_free_data(SequenceModifierData *smd)
187 CurvesModifierData *cmd = (CurvesModifierData *) smd;
189 curvemapping_free_data(&cmd->curve_mapping);
192 static void curves_copy_data(SequenceModifierData *target, SequenceModifierData *smd)
194 CurvesModifierData *cmd = (CurvesModifierData *) smd;
195 CurvesModifierData *cmd_target = (CurvesModifierData *) target;
197 curvemapping_copy_data(&cmd_target->curve_mapping, &cmd->curve_mapping);
200 static void curves_apply_threaded(int width, int height, unsigned char *rect, float *rect_float,
201 unsigned char *mask_rect, float *mask_rect_float, void *data_v)
203 CurveMapping *curve_mapping = (CurveMapping *) data_v;
206 for (y = 0; y < height; y++) {
207 for (x = 0; x < width; x++) {
208 int pixel_index = (y * width + x) * 4;
211 float *pixel = rect_float + pixel_index;
214 curvemapping_evaluate_premulRGBF(curve_mapping, result, pixel);
216 if (mask_rect_float) {
217 const float *m = mask_rect_float + pixel_index;
219 pixel[0] = pixel[0] * (1.0f - m[0]) + result[0] * m[0];
220 pixel[1] = pixel[1] * (1.0f - m[1]) + result[1] * m[1];
221 pixel[2] = pixel[2] * (1.0f - m[2]) + result[2] * m[2];
224 pixel[0] = result[0];
225 pixel[1] = result[1];
226 pixel[2] = result[2];
230 unsigned char *pixel = rect + pixel_index;
231 float result[3], tempc[4];
233 straight_uchar_to_premul_float(tempc, pixel);
235 curvemapping_evaluate_premulRGBF(curve_mapping, result, tempc);
240 rgb_uchar_to_float(t, mask_rect + pixel_index);
242 tempc[0] = tempc[0] * (1.0f - t[0]) + result[0] * t[0];
243 tempc[1] = tempc[1] * (1.0f - t[1]) + result[1] * t[1];
244 tempc[2] = tempc[2] * (1.0f - t[2]) + result[2] * t[2];
247 tempc[0] = result[0];
248 tempc[1] = result[1];
249 tempc[2] = result[2];
252 premul_float_to_straight_uchar(pixel, tempc);
258 static void curves_apply(struct SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
260 CurvesModifierData *cmd = (CurvesModifierData *) smd;
262 float black[3] = {0.0f, 0.0f, 0.0f};
263 float white[3] = {1.0f, 1.0f, 1.0f};
265 curvemapping_initialize(&cmd->curve_mapping);
267 curvemapping_premultiply(&cmd->curve_mapping, 0);
268 curvemapping_set_black_white(&cmd->curve_mapping, black, white);
270 modifier_apply_threaded(ibuf, mask, curves_apply_threaded, &cmd->curve_mapping);
272 curvemapping_premultiply(&cmd->curve_mapping, 1);
275 static SequenceModifierTypeInfo seqModifier_Curves = {
276 CTX_N_(BLF_I18NCONTEXT_ID_SEQUENCE, "Curves"), /* name */
277 "CurvesModifierData", /* struct_name */
278 sizeof(CurvesModifierData), /* struct_size */
279 curves_init_data, /* init_data */
280 curves_free_data, /* free_data */
281 curves_copy_data, /* copy_data */
282 curves_apply /* apply */
285 /* **** Hue Correct Modifier **** */
287 static void hue_correct_init_data(SequenceModifierData *smd)
289 HueCorrectModifierData *hcmd = (HueCorrectModifierData *) smd;
292 curvemapping_set_defaults(&hcmd->curve_mapping, 1, 0.0f, 0.0f, 1.0f, 1.0f);
293 hcmd->curve_mapping.preset = CURVE_PRESET_MID9;
295 for (c = 0; c < 3; c++) {
296 CurveMap *cuma = &hcmd->curve_mapping.cm[c];
298 curvemap_reset(cuma, &hcmd->curve_mapping.clipr, hcmd->curve_mapping.preset, CURVEMAP_SLOPE_POSITIVE);
301 /* default to showing Saturation */
302 hcmd->curve_mapping.cur = 1;
305 static void hue_correct_free_data(SequenceModifierData *smd)
307 HueCorrectModifierData *hcmd = (HueCorrectModifierData *) smd;
309 curvemapping_free_data(&hcmd->curve_mapping);
312 static void hue_correct_copy_data(SequenceModifierData *target, SequenceModifierData *smd)
314 HueCorrectModifierData *hcmd = (HueCorrectModifierData *) smd;
315 HueCorrectModifierData *hcmd_target = (HueCorrectModifierData *) target;
317 curvemapping_copy_data(&hcmd_target->curve_mapping, &hcmd->curve_mapping);
320 static void hue_correct_apply_threaded(int width, int height, unsigned char *rect, float *rect_float,
321 unsigned char *mask_rect, float *mask_rect_float, void *data_v)
323 CurveMapping *curve_mapping = (CurveMapping *) data_v;
326 for (y = 0; y < height; y++) {
327 for (x = 0; x < width; x++) {
328 int pixel_index = (y * width + x) * 4;
329 float pixel[3], result[3], mask[3] = {1.0f, 1.0f, 1.0f};
333 copy_v3_v3(pixel, rect_float + pixel_index);
335 rgb_uchar_to_float(pixel, rect + pixel_index);
337 rgb_to_hsv(pixel[0], pixel[1], pixel[2], hsv, hsv + 1, hsv + 2);
339 /* adjust hue, scaling returned default 0.5 up to 1 */
340 f = curvemapping_evaluateF(curve_mapping, 0, hsv[0]);
343 /* adjust saturation, scaling returned default 0.5 up to 1 */
344 f = curvemapping_evaluateF(curve_mapping, 1, hsv[0]);
345 hsv[1] *= (f * 2.0f);
347 /* adjust value, scaling returned default 0.5 up to 1 */
348 f = curvemapping_evaluateF(curve_mapping, 2, hsv[0]);
351 hsv[0] = hsv[0] - floorf(hsv[0]); /* mod 1.0 */
352 CLAMP(hsv[1], 0.0f, 1.0f);
354 /* convert back to rgb */
355 hsv_to_rgb(hsv[0], hsv[1], hsv[2], result, result + 1, result + 2);
358 copy_v3_v3(mask, mask_rect_float + pixel_index);
360 rgb_uchar_to_float(mask, mask_rect + pixel_index);
362 result[0] = pixel[0] * (1.0f - mask[0]) + result[0] * mask[0];
363 result[1] = pixel[1] * (1.0f - mask[1]) + result[1] * mask[1];
364 result[2] = pixel[2] * (1.0f - mask[2]) + result[2] * mask[2];
367 copy_v3_v3(rect_float + pixel_index, result);
369 rgb_float_to_uchar(rect + pixel_index, result);
374 static void hue_correct_apply(struct SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
376 HueCorrectModifierData *hcmd = (HueCorrectModifierData *) smd;
378 curvemapping_initialize(&hcmd->curve_mapping);
380 modifier_apply_threaded(ibuf, mask, hue_correct_apply_threaded, &hcmd->curve_mapping);
383 static SequenceModifierTypeInfo seqModifier_HueCorrect = {
384 CTX_N_(BLF_I18NCONTEXT_ID_SEQUENCE, "Hue Correct"), /* name */
385 "HueCorrectModifierData", /* struct_name */
386 sizeof(HueCorrectModifierData), /* struct_size */
387 hue_correct_init_data, /* init_data */
388 hue_correct_free_data, /* free_data */
389 hue_correct_copy_data, /* copy_data */
390 hue_correct_apply /* apply */
393 /* **** Bright/Contrast Modifier **** */
395 typedef struct BrightContrastThreadData {
398 } BrightContrastThreadData;
400 static void brightcontrast_apply_threaded(int width, int height, unsigned char *rect, float *rect_float,
401 unsigned char *mask_rect, float *mask_rect_float, void *data_v)
403 BrightContrastThreadData *data = (BrightContrastThreadData *) data_v;
409 float brightness = data->bright / 100.0f;
410 float contrast = data->contrast;
411 float delta = contrast / 200.0f;
413 a = 1.0f - delta * 2.0f;
415 * The algorithm is by Werner D. Streidt
416 * (http://visca.com/ffactory/archives/5-99/msg00021.html)
417 * Extracted of OpenCV demhist.c
421 b = a * (brightness - delta);
425 b = a * (brightness + delta);
428 for (y = 0; y < height; y++) {
429 for (x = 0; x < width; x++) {
430 int pixel_index = (y * width + x) * 4;
433 unsigned char *pixel = rect + pixel_index;
435 for (c = 0; c < 3; c++) {
436 i = (float) pixel[c] / 255.0f;
440 unsigned char *m = mask_rect + pixel_index;
441 float t = (float) m[c] / 255.0f;
443 v = (float) pixel[c] / 255.0f * (1.0f - t) + v * t;
446 pixel[c] = FTOCHAR(v);
449 else if (rect_float) {
450 float *pixel = rect_float + pixel_index;
452 for (c = 0; c < 3; c++) {
456 if (mask_rect_float) {
457 const float *m = mask_rect_float + pixel_index;
459 pixel[c] = pixel[c] * (1.0f - m[c]) + v * m[c];
469 static void brightcontrast_apply(struct SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
471 BrightContrastModifierData *bcmd = (BrightContrastModifierData *) smd;
472 BrightContrastThreadData data;
474 data.bright = bcmd->bright;
475 data.contrast = bcmd->contrast;
477 modifier_apply_threaded(ibuf, mask, brightcontrast_apply_threaded, &data);
480 static SequenceModifierTypeInfo seqModifier_BrightContrast = {
481 CTX_N_(BLF_I18NCONTEXT_ID_SEQUENCE, "Bright/Contrast"), /* name */
482 "BrightContrastModifierData", /* struct_name */
483 sizeof(BrightContrastModifierData), /* struct_size */
484 NULL, /* init_data */
485 NULL, /* free_data */
486 NULL, /* copy_data */
487 brightcontrast_apply /* apply */
490 /* **** Mask Modifier **** */
492 static void maskmodifier_apply_threaded(int width, int height, unsigned char *rect, float *rect_float,
493 unsigned char *mask_rect, float *mask_rect_float, void *UNUSED(data_v))
497 if (rect && !mask_rect)
500 if (rect_float && !mask_rect_float)
503 for (y = 0; y < height; y++) {
504 for (x = 0; x < width; x++) {
505 int pixel_index = (y * width + x) * 4;
508 unsigned char *pixel = rect + pixel_index;
509 unsigned char *mask_pixel = mask_rect + pixel_index;
510 unsigned char mask = min_iii(mask_pixel[0], mask_pixel[1], mask_pixel[2]);
512 /* byte buffer is straight, so only affect on alpha itself,
513 * this is the only way to alpha-over byte strip after
514 * applying mask modifier.
516 pixel[3] = (float)(pixel[3] * mask) / 255.0f;
518 else if (rect_float) {
520 float *pixel = rect_float + pixel_index;
521 const float *mask_pixel = mask_rect_float + pixel_index;
522 float mask = min_fff(mask_pixel[0], mask_pixel[1], mask_pixel[2]);
524 /* float buffers are premultiplied, so need to premul color
525 * as well to make it easy to alpha-over masted strip.
527 for (c = 0; c < 4; c++)
528 pixel[c] = pixel[c] * mask;
534 static void maskmodifier_apply(struct SequenceModifierData *UNUSED(smd), ImBuf *ibuf, ImBuf *mask)
536 // SequencerMaskModifierData *bcmd = (SequencerMaskModifierData *)smd;
538 modifier_apply_threaded(ibuf, mask, maskmodifier_apply_threaded, NULL);
541 static SequenceModifierTypeInfo seqModifier_Mask = {
542 CTX_N_(BLF_I18NCONTEXT_ID_SEQUENCE, "Mask"), /* name */
543 "SequencerMaskModifierData", /* struct_name */
544 sizeof(SequencerMaskModifierData), /* struct_size */
545 NULL, /* init_data */
546 NULL, /* free_data */
547 NULL, /* copy_data */
548 maskmodifier_apply /* apply */
551 /*********************** Modifier functions *************************/
553 static void sequence_modifier_type_info_init(void)
555 #define INIT_TYPE(typeName) (modifiersTypes[seqModifierType_##typeName] = &seqModifier_##typeName)
557 INIT_TYPE(ColorBalance);
559 INIT_TYPE(HueCorrect);
560 INIT_TYPE(BrightContrast);
566 SequenceModifierTypeInfo *BKE_sequence_modifier_type_info_get(int type)
568 if (!modifierTypesInit) {
569 sequence_modifier_type_info_init();
570 modifierTypesInit = true;
573 return modifiersTypes[type];
576 SequenceModifierData *BKE_sequence_modifier_new(Sequence *seq, const char *name, int type)
578 SequenceModifierData *smd;
579 SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(type);
581 smd = MEM_callocN(smti->struct_size, "sequence modifier");
584 smd->flag |= SEQUENCE_MODIFIER_EXPANDED;
586 if (!name || !name[0])
587 BLI_strncpy(smd->name, smti->name, sizeof(smd->name));
589 BLI_strncpy(smd->name, name, sizeof(smd->name));
591 BLI_addtail(&seq->modifiers, smd);
593 BKE_sequence_modifier_unique_name(seq, smd);
596 smti->init_data(smd);
601 bool BKE_sequence_modifier_remove(Sequence *seq, SequenceModifierData *smd)
603 if (BLI_findindex(&seq->modifiers, smd) == -1)
606 BLI_remlink(&seq->modifiers, smd);
607 BKE_sequence_modifier_free(smd);
612 void BKE_sequence_modifier_clear(Sequence *seq)
614 SequenceModifierData *smd, *smd_next;
616 for (smd = seq->modifiers.first; smd; smd = smd_next) {
617 smd_next = smd->next;
618 BKE_sequence_modifier_free(smd);
621 BLI_listbase_clear(&seq->modifiers);
624 void BKE_sequence_modifier_free(SequenceModifierData *smd)
626 SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
628 if (smti && smti->free_data) {
629 smti->free_data(smd);
635 void BKE_sequence_modifier_unique_name(Sequence *seq, SequenceModifierData *smd)
637 SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
639 BLI_uniquename(&seq->modifiers, smd, CTX_DATA_(BLF_I18NCONTEXT_ID_SEQUENCE, smti->name), '.',
640 offsetof(SequenceModifierData, name), sizeof(smd->name));
643 SequenceModifierData *BKE_sequence_modifier_find_by_name(Sequence *seq, const char *name)
645 return BLI_findstring(&(seq->modifiers), name, offsetof(SequenceModifierData, name));
648 ImBuf *BKE_sequence_modifier_apply_stack(const SeqRenderData *context, Sequence *seq, ImBuf *ibuf, int cfra)
650 SequenceModifierData *smd;
651 ImBuf *processed_ibuf = ibuf;
653 if (seq->modifiers.first && (seq->flag & SEQ_USE_LINEAR_MODIFIERS)) {
654 processed_ibuf = IMB_dupImBuf(ibuf);
655 BKE_sequencer_imbuf_from_sequencer_space(context->scene, processed_ibuf);
658 for (smd = seq->modifiers.first; smd; smd = smd->next) {
659 SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
661 /* could happen if modifier is being removed or not exists in current version of blender */
665 /* modifier is muted, do nothing */
666 if (smd->flag & SEQUENCE_MODIFIER_MUTE)
670 ImBuf *mask = modifier_mask_get(smd, context, cfra, seq->start, ibuf->rect_float != NULL);
672 if (processed_ibuf == ibuf)
673 processed_ibuf = IMB_dupImBuf(ibuf);
675 smti->apply(smd, processed_ibuf, mask);
682 if (seq->modifiers.first && (seq->flag & SEQ_USE_LINEAR_MODIFIERS)) {
683 BKE_sequencer_imbuf_to_sequencer_space(context->scene, processed_ibuf, false);
686 return processed_ibuf;
689 void BKE_sequence_modifier_list_copy(Sequence *seqn, Sequence *seq)
691 SequenceModifierData *smd;
693 for (smd = seq->modifiers.first; smd; smd = smd->next) {
694 SequenceModifierData *smdn;
695 SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
697 smdn = MEM_dupallocN(smd);
699 if (smti && smti->copy_data)
700 smti->copy_data(smdn, smd);
702 smdn->next = smdn->prev = NULL;
703 BLI_addtail(&seqn->modifiers, smdn);
707 int BKE_sequence_supports_modifiers(Sequence *seq)
709 return !ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD);