diff options
Diffstat (limited to 'source/blender/blenkernel/intern/seqeffects.c')
-rw-r--r-- | source/blender/blenkernel/intern/seqeffects.c | 486 |
1 files changed, 339 insertions, 147 deletions
diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c index f375c2b1e4f..1b807adca4b 100644 --- a/source/blender/blenkernel/intern/seqeffects.c +++ b/source/blender/blenkernel/intern/seqeffects.c @@ -146,6 +146,11 @@ static ImBuf *prepare_effect_imbufs(const SeqRenderData *context, ImBuf *ibuf1, if (out->rect_float) IMB_colormanagement_assign_float_colorspace(out, scene->sequencer_colorspace_settings.name); + /* If effect only affecting a single channel, forward input's metadata to the output. */ + if (ibuf1 != NULL && ibuf1 == ibuf2 && ibuf2 == ibuf3) { + IMB_metadata_copy(out, ibuf1); + } + return out; } @@ -860,9 +865,10 @@ static void do_add_effect_byte(float facf0, float facf1, int x, int y, unsigned x = xo; while (x--) { - rt[0] = min_ii(cp1[0] + ((fac1 * cp2[0]) >> 8), 255); - rt[1] = min_ii(cp1[1] + ((fac1 * cp2[1]) >> 8), 255); - rt[2] = min_ii(cp1[2] + ((fac1 * cp2[2]) >> 8), 255); + const int m = fac1 * (int)cp2[3]; + rt[0] = min_ii(cp1[0] + ((m * cp2[0]) >> 16), 255); + rt[1] = min_ii(cp1[1] + ((m * cp2[1]) >> 16), 255); + rt[2] = min_ii(cp1[2] + ((m * cp2[2]) >> 16), 255); rt[3] = cp1[3]; cp1 += 4; cp2 += 4; rt += 4; @@ -874,9 +880,10 @@ static void do_add_effect_byte(float facf0, float facf1, int x, int y, unsigned x = xo; while (x--) { - rt[0] = min_ii(cp1[0] + ((fac3 * cp2[0]) >> 8), 255); - rt[1] = min_ii(cp1[1] + ((fac3 * cp2[1]) >> 8), 255); - rt[2] = min_ii(cp1[2] + ((fac3 * cp2[2]) >> 8), 255); + const int m = fac3 * (int)cp2[3]; + rt[0] = min_ii(cp1[0] + ((m * cp2[0]) >> 16), 255); + rt[1] = min_ii(cp1[1] + ((m * cp2[1]) >> 16), 255); + rt[2] = min_ii(cp1[2] + ((m * cp2[2]) >> 16), 255); rt[3] = cp1[3]; cp1 += 4; cp2 += 4; rt += 4; @@ -887,7 +894,7 @@ static void do_add_effect_byte(float facf0, float facf1, int x, int y, unsigned static void do_add_effect_float(float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out) { int xo; - float m, fac1, fac3; + float fac1, fac3; float *rt1, *rt2, *rt; xo = x; @@ -901,7 +908,7 @@ static void do_add_effect_float(float facf0, float facf1, int x, int y, float *r while (y--) { x = xo; while (x--) { - m = 1.0f - (rt1[3] * (1.0f - fac1)); + const float m = (1.0f - (rt1[3] * (1.0f - fac1))) * rt2[3]; rt[0] = rt1[0] + m * rt2[0]; rt[1] = rt1[1] + m * rt2[1]; rt[2] = rt1[2] + m * rt2[2]; @@ -916,7 +923,7 @@ static void do_add_effect_float(float facf0, float facf1, int x, int y, float *r x = xo; while (x--) { - m = 1.0f - (rt1[3] * (1.0f - fac3)); + const float m = (1.0f - (rt1[3] * (1.0f - fac3))) * rt2[3]; rt[0] = rt1[0] + m * rt2[0]; rt[1] = rt1[1] + m * rt2[1]; rt[2] = rt1[2] + m * rt2[2]; @@ -964,9 +971,10 @@ static void do_sub_effect_byte(float facf0, float facf1, int x, int y, unsigned while (y--) { x = xo; while (x--) { - rt[0] = max_ii(cp1[0] - ((fac1 * cp2[0]) >> 8), 0); - rt[1] = max_ii(cp1[1] - ((fac1 * cp2[1]) >> 8), 0); - rt[2] = max_ii(cp1[2] - ((fac1 * cp2[2]) >> 8), 0); + const int m = fac1 * (int)cp2[3]; + rt[0] = max_ii(cp1[0] - ((m * cp2[0]) >> 16), 0); + rt[1] = max_ii(cp1[1] - ((m * cp2[1]) >> 16), 0); + rt[2] = max_ii(cp1[2] - ((m * cp2[2]) >> 16), 0); rt[3] = cp1[3]; cp1 += 4; cp2 += 4; rt += 4; @@ -978,9 +986,10 @@ static void do_sub_effect_byte(float facf0, float facf1, int x, int y, unsigned x = xo; while (x--) { - rt[0] = max_ii(cp1[0] - ((fac3 * cp2[0]) >> 8), 0); - rt[1] = max_ii(cp1[1] - ((fac3 * cp2[1]) >> 8), 0); - rt[2] = max_ii(cp1[2] - ((fac3 * cp2[2]) >> 8), 0); + const int m = fac3 * (int)cp2[3]; + rt[0] = max_ii(cp1[0] - ((m * cp2[0]) >> 16), 0); + rt[1] = max_ii(cp1[1] - ((m * cp2[1]) >> 16), 0); + rt[2] = max_ii(cp1[2] - ((m * cp2[2]) >> 16), 0); rt[3] = cp1[3]; cp1 += 4; cp2 += 4; rt += 4; @@ -991,7 +1000,7 @@ static void do_sub_effect_byte(float facf0, float facf1, int x, int y, unsigned static void do_sub_effect_float(float UNUSED(facf0), float facf1, int x, int y, float *rect1, float *rect2, float *out) { int xo; - float m /*, fac1*/, fac3; + float /* fac1, */ fac3_inv; float *rt1, *rt2, *rt; xo = x; @@ -1001,12 +1010,12 @@ static void do_sub_effect_float(float UNUSED(facf0), float facf1, int x, int y, /* UNUSED */ // fac1 = facf0; - fac3 = facf1; + fac3_inv = 1.0f - facf1; while (y--) { x = xo; while (x--) { - m = 1.0f - (rt1[3] * (1 - fac3)); + const float m = (1.0f - (rt1[3] * fac3_inv)) * rt2[3]; rt[0] = max_ff(rt1[0] - m * rt2[0], 0.0f); rt[1] = max_ff(rt1[1] - m * rt2[1], 0.0f); rt[2] = max_ff(rt1[2] - m * rt2[2], 0.0f); @@ -1021,7 +1030,7 @@ static void do_sub_effect_float(float UNUSED(facf0), float facf1, int x, int y, x = xo; while (x--) { - m = 1.0f - (rt1[3] * (1 - fac3)); + const float m = (1.0f - (rt1[3] * fac3_inv)) * rt2[3]; rt[0] = max_ff(rt1[0] - m * rt2[0], 0.0f); rt[1] = max_ff(rt1[1] - m * rt2[1], 0.0f); rt[2] = max_ff(rt1[2] - m * rt2[2], 0.0f); @@ -1536,7 +1545,7 @@ static void init_wipe_effect(Sequence *seq) static int num_inputs_wipe(void) { - return 1; + return 2; } static void free_wipe_effect(Sequence *seq) @@ -2354,6 +2363,9 @@ static ImBuf *do_adjustment(const SeqRenderData *context, Sequence *seq, float c if (BKE_sequencer_input_have_to_preprocess(context, seq, cfra)) { out = IMB_dupImBuf(i); + if (out) { + IMB_metadata_copy(out, i); + } IMB_freeImBuf(i); } else { @@ -2663,36 +2675,81 @@ static float *make_gaussian_blur_kernel(float rad, int size) return gausstab; } -static void do_gaussian_blur_effect_byte(Sequence *seq, - int start_line, - int x, int y, - int frame_width, int frame_height, - unsigned char *rect, - unsigned char *out) +static void do_gaussian_blur_effect_byte_x(Sequence *seq, + int start_line, + int x, int y, + int frame_width, + int UNUSED(frame_height), + unsigned char *rect, + unsigned char *out) { #define INDEX(_x, _y) (((_y) * (x) + (_x)) * 4) GaussianBlurVars *data = seq->effectdata; const int size_x = (int) (data->size_x + 0.5f); - const int size_y = (int) (data->size_y + 0.5f); int i, j; /* Make gaussian weight tabke. */ - float *gausstab_x, *gausstab_y; + float *gausstab_x; gausstab_x = make_gaussian_blur_kernel(data->size_x, size_x); - if (data->size_x == data->size_y) { - gausstab_y = gausstab_x; - } - else { - gausstab_y = make_gaussian_blur_kernel(data->size_y, size_y); + + for (i = 0; i < y; ++i) { + for (j = 0; j < x; ++j) { + int out_index = INDEX(j, i); + float accum[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + float accum_weight = 0.0f; + + for (int current_x = j - size_x; + current_x <= j + size_x; + ++current_x) + { + if (current_x < 0 || current_x >= frame_width) { + /* Out of bounds. */ + continue; + } + int index = INDEX(current_x, i + start_line); + float weight = gausstab_x[current_x - j + size_x]; + accum[0] += rect[index] * weight; + accum[1] += rect[index + 1] * weight; + accum[2] += rect[index + 2] * weight; + accum[3] += rect[index + 3] * weight; + accum_weight += weight; + } + + float inv_accum_weight = 1.0f / accum_weight; + out[out_index + 0] = accum[0] * inv_accum_weight; + out[out_index + 1] = accum[1] * inv_accum_weight; + out[out_index + 2] = accum[2] * inv_accum_weight; + out[out_index + 3] = accum[3] * inv_accum_weight; + } } + MEM_freeN(gausstab_x); +#undef INDEX +} + +static void do_gaussian_blur_effect_byte_y(Sequence *seq, + int start_line, + int x, int y, + int UNUSED(frame_width), + int frame_height, + unsigned char *rect, + unsigned char *out) +{ +#define INDEX(_x, _y) (((_y) * (x) + (_x)) * 4) + GaussianBlurVars *data = seq->effectdata; + const int size_y = (int) (data->size_y + 0.5f); + int i, j; + + /* Make gaussian weight tabke. */ + float *gausstab_y; + gausstab_y = make_gaussian_blur_kernel(data->size_y, size_y); + for (i = 0; i < y; ++i) { for (j = 0; j < x; ++j) { int out_index = INDEX(j, i); - int current_x, current_y; float accum[4] = {0.0f, 0.0f, 0.0f, 0.0f}; float accum_weight = 0.0f; - for (current_y = i - size_y; + for (int current_y = i - size_y; current_y <= i + size_y; ++current_y) { @@ -2702,144 +2759,182 @@ static void do_gaussian_blur_effect_byte(Sequence *seq, /* Out of bounds. */ continue; } + int index = INDEX(j, current_y + start_line); + float weight = gausstab_y[current_y - i + size_y]; + accum[0] += rect[index] * weight; + accum[1] += rect[index + 1] * weight; + accum[2] += rect[index + 2] * weight; + accum[3] += rect[index + 3] * weight; + accum_weight += weight; + } + float inv_accum_weight = 1.0f / accum_weight; + out[out_index + 0] = accum[0] * inv_accum_weight; + out[out_index + 1] = accum[1] * inv_accum_weight; + out[out_index + 2] = accum[2] * inv_accum_weight; + out[out_index + 3] = accum[3] * inv_accum_weight; + } + } - for (current_x = j - size_x; - current_x <= j + size_x; - ++current_x) - { - float weight; - int index = INDEX(current_x, current_y + start_line); - if (current_x < 0 || current_x >= frame_width) { - /* Out of bounds. */ - continue; - } - BLI_assert(index >= 0); - BLI_assert(index < frame_width * frame_height * 4); - - if (size_x != 0 && size_y != 0) { - weight = gausstab_x[current_x - j + size_x] * - gausstab_y[current_y - i + size_y]; - } - else if (size_x == 0) { - weight = gausstab_y[current_y - i + size_y]; - } - else { - weight = gausstab_x[current_x - j + size_x]; - } - accum[0] += rect[index] * weight; - accum[1] += rect[index + 1] * weight; - accum[2] += rect[index + 2] * weight; - accum[3] += rect[index + 3] * weight; - accum_weight += weight; + MEM_freeN(gausstab_y); +#undef INDEX +} + +static void do_gaussian_blur_effect_float_x(Sequence *seq, + int start_line, + int x, int y, + int frame_width, + int UNUSED(frame_height), + float *rect, + float *out) +{ +#define INDEX(_x, _y) (((_y) * (x) + (_x)) * 4) + GaussianBlurVars *data = seq->effectdata; + const int size_x = (int) (data->size_x + 0.5f); + int i, j; + + /* Make gaussian weight tabke. */ + float *gausstab_x; + gausstab_x = make_gaussian_blur_kernel(data->size_x, size_x); + + for (i = 0; i < y; ++i) { + for (j = 0; j < x; ++j) { + int out_index = INDEX(j, i); + float accum[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + float accum_weight = 0.0f; + for (int current_x = j - size_x; + current_x <= j + size_x; + ++current_x) + { + if (current_x < 0 || current_x >= frame_width) { + /* Out of bounds. */ + continue; } + int index = INDEX(current_x, i + start_line); + float weight = gausstab_x[current_x - j + size_x]; + madd_v4_v4fl(accum, &rect[index], weight); + accum_weight += weight; } - out[out_index + 0] = accum[0] / accum_weight; - out[out_index + 1] = accum[1] / accum_weight; - out[out_index + 2] = accum[2] / accum_weight; - out[out_index + 3] = accum[3] / accum_weight; + mul_v4_v4fl(&out[out_index], accum, 1.0f / accum_weight); } } MEM_freeN(gausstab_x); - if (gausstab_x != gausstab_y) { - MEM_freeN(gausstab_y); - } #undef INDEX } -static void do_gaussian_blur_effect_float(Sequence *seq, - int start_line, - int x, int y, - int frame_width, int frame_height, - float *rect, - float *out) +static void do_gaussian_blur_effect_float_y(Sequence *seq, + int start_line, + int x, int y, + int UNUSED(frame_width), + int frame_height, + float *rect, + float *out) { #define INDEX(_x, _y) (((_y) * (x) + (_x)) * 4) GaussianBlurVars *data = seq->effectdata; - const int size_x = (int) (data->size_x + 0.5f); const int size_y = (int) (data->size_y + 0.5f); int i, j; /* Make gaussian weight tabke. */ - float *gausstab_x, *gausstab_y; - gausstab_x = make_gaussian_blur_kernel(data->size_x, size_x); - if (data->size_x == data->size_y) { - gausstab_y = gausstab_x; - } - else { - gausstab_y = make_gaussian_blur_kernel(data->size_y, size_y); - } + float *gausstab_y; + gausstab_y = make_gaussian_blur_kernel(data->size_y, size_y); for (i = 0; i < y; ++i) { for (j = 0; j < x; ++j) { int out_index = INDEX(j, i); - int current_x, current_y; float accum[4] = {0.0f, 0.0f, 0.0f, 0.0f}; float accum_weight = 0.0f; - for (current_y = i - size_y; + for (int current_y = i - size_y; current_y <= i + size_y; ++current_y) { - float weight; if (current_y < -start_line || current_y + start_line >= frame_height) { /* Out of bounds. */ continue; } - - for (current_x = j - size_x; - current_x <= j + size_x; - ++current_x) - { - int index = INDEX(current_x, current_y + start_line); - if (current_x < 0 || current_x >= frame_width) { - /* Out of bounds. */ - continue; - } - - if (size_x != 0 && size_y != 0) { - weight = gausstab_x[current_x - j + size_x] * - gausstab_y[current_y - i + size_y]; - } - else if (size_x == 0) { - weight = gausstab_y[current_y - i + size_y]; - } - else { - weight = gausstab_x[current_x - j + size_x]; - } - madd_v4_v4fl(accum, &rect[index], weight); - accum_weight += weight; - } + int index = INDEX(j, current_y + start_line); + float weight = gausstab_y[current_y - i + size_y]; + madd_v4_v4fl(accum, &rect[index], weight); + accum_weight += weight; } mul_v4_v4fl(&out[out_index], accum, 1.0f / accum_weight); } } - MEM_freeN(gausstab_x); - if (gausstab_x != gausstab_y) { - MEM_freeN(gausstab_y); - } + MEM_freeN(gausstab_y); #undef INDEX } -static void do_gaussian_blur_effect(const SeqRenderData *context, - Sequence *seq, - float UNUSED(cfra), - float UNUSED(facf0), - float UNUSED(facf1), - ImBuf *ibuf1, - ImBuf *ibuf2, - ImBuf *UNUSED(ibuf3), - int start_line, - int total_lines, - ImBuf *out) +static void do_gaussian_blur_effect_x_cb(const SeqRenderData *context, + Sequence *seq, + ImBuf *ibuf, + int start_line, + int total_lines, + ImBuf *out) +{ + if (out->rect_float) { + float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; + + slice_get_float_buffers(context, + ibuf, + NULL, + NULL, + out, + start_line, + &rect1, + &rect2, + NULL, + &rect_out); + + do_gaussian_blur_effect_float_x(seq, + start_line, + context->rectx, + total_lines, + context->rectx, + context->recty, + ibuf->rect_float, + rect_out); + } + else { + unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; + + slice_get_byte_buffers(context, + ibuf, + NULL, + NULL, + out, + start_line, + &rect1, + &rect2, + NULL, + &rect_out); + + do_gaussian_blur_effect_byte_x(seq, + start_line, + context->rectx, + total_lines, + context->rectx, + context->recty, + (unsigned char *) ibuf->rect, + rect_out); + } +} + +static void do_gaussian_blur_effect_y_cb(const SeqRenderData *context, + Sequence *seq, + ImBuf *ibuf, + int start_line, + int total_lines, + ImBuf *out) { if (out->rect_float) { float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; slice_get_float_buffers(context, - ibuf1, ibuf2, + ibuf, + NULL, NULL, out, start_line, @@ -2848,20 +2943,21 @@ static void do_gaussian_blur_effect(const SeqRenderData *context, NULL, &rect_out); - do_gaussian_blur_effect_float(seq, - start_line, - context->rectx, - total_lines, - context->rectx, - context->recty, - ibuf1->rect_float, - rect_out); + do_gaussian_blur_effect_float_y(seq, + start_line, + context->rectx, + total_lines, + context->rectx, + context->recty, + ibuf->rect_float, + rect_out); } else { unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; slice_get_byte_buffers(context, - ibuf1, ibuf2, + ibuf, + NULL, NULL, out, start_line, @@ -2870,17 +2966,114 @@ static void do_gaussian_blur_effect(const SeqRenderData *context, NULL, &rect_out); - do_gaussian_blur_effect_byte(seq, - start_line, - context->rectx, - total_lines, - context->rectx, - context->recty, - (unsigned char *) ibuf1->rect, - rect_out); + do_gaussian_blur_effect_byte_y(seq, + start_line, + context->rectx, + total_lines, + context->rectx, + context->recty, + (unsigned char *) ibuf->rect, + rect_out); } } +typedef struct RenderGaussianBlurEffectInitData { + const SeqRenderData *context; + Sequence *seq; + ImBuf *ibuf; + ImBuf *out; +} RenderGaussianBlurEffectInitData; + +typedef struct RenderGaussianBlurEffectThread { + const SeqRenderData *context; + Sequence *seq; + ImBuf *ibuf; + ImBuf *out; + int start_line, tot_line; +} RenderGaussianBlurEffectThread; + +static void render_effect_execute_init_handle(void *handle_v, + int start_line, + int tot_line, + void *init_data_v) +{ + RenderGaussianBlurEffectThread *handle = (RenderGaussianBlurEffectThread *) handle_v; + RenderGaussianBlurEffectInitData *init_data = (RenderGaussianBlurEffectInitData *) init_data_v; + + handle->context = init_data->context; + handle->seq = init_data->seq; + handle->ibuf = init_data->ibuf; + handle->out = init_data->out; + + handle->start_line = start_line; + handle->tot_line = tot_line; +} + +static void *render_effect_execute_do_x_thread(void *thread_data_v) +{ + RenderGaussianBlurEffectThread *thread_data = (RenderGaussianBlurEffectThread *) thread_data_v; + do_gaussian_blur_effect_x_cb(thread_data->context, + thread_data->seq, + thread_data->ibuf, + thread_data->start_line, + thread_data->tot_line, + thread_data->out); + return NULL; +} + +static void *render_effect_execute_do_y_thread(void *thread_data_v) +{ + RenderGaussianBlurEffectThread *thread_data = (RenderGaussianBlurEffectThread *) thread_data_v; + do_gaussian_blur_effect_y_cb(thread_data->context, + thread_data->seq, + thread_data->ibuf, + thread_data->start_line, + thread_data->tot_line, + thread_data->out); + + return NULL; +} + +static ImBuf *do_gaussian_blur_effect(const SeqRenderData *context, + Sequence *seq, + float UNUSED(cfra), + float UNUSED(facf0), + float UNUSED(facf1), + ImBuf *ibuf1, + ImBuf *UNUSED(ibuf2), + ImBuf *UNUSED(ibuf3)) +{ + ImBuf *out = prepare_effect_imbufs(context, ibuf1, NULL, NULL); + + RenderGaussianBlurEffectInitData init_data; + + init_data.context = context; + init_data.seq = seq; + init_data.ibuf = ibuf1; + init_data.out = out; + + IMB_processor_apply_threaded(out->y, + sizeof(RenderGaussianBlurEffectThread), + &init_data, + render_effect_execute_init_handle, + render_effect_execute_do_x_thread); + + ibuf1 = out; + init_data.ibuf = ibuf1; + out = prepare_effect_imbufs(context, ibuf1, NULL, NULL);; + init_data.out = out; + + IMB_processor_apply_threaded(out->y, + sizeof(RenderGaussianBlurEffectThread), + &init_data, + render_effect_execute_init_handle, + render_effect_execute_do_y_thread); + + IMB_freeImBuf(ibuf1); + + return out; +} + /*********************** text *************************/ static void init_text_effect(Sequence *seq) { @@ -3211,13 +3404,12 @@ static struct SeqEffectHandle get_sequence_effect_impl(int seq_type) rval.execute = do_adjustment; break; case SEQ_TYPE_GAUSSIAN_BLUR: - rval.multithreaded = true; rval.init = init_gaussian_blur_effect; rval.num_inputs = num_inputs_gaussian_blur; rval.free = free_gaussian_blur_effect; rval.copy = copy_gaussian_blur_effect; rval.early_out = early_out_gaussian_blur; - rval.execute_slice = do_gaussian_blur_effect; + rval.execute = do_gaussian_blur_effect; break; case SEQ_TYPE_TEXT: rval.num_inputs = num_inputs_text; |