== Sequencer ==
authorPeter Schlaile <peter@schlaile.de>
Sat, 2 Feb 2008 23:28:50 +0000 (23:28 +0000)
committerPeter Schlaile <peter@schlaile.de>
Sat, 2 Feb 2008 23:28:50 +0000 (23:28 +0000)
New feature: color balance aka 3-way-color-correction aka lift/gamma/gain
on input (folded into byte -> float conversion, so _very_ fast in that case).
Interface is inspired from Rebel CC (but not as complete yet, you can't
choose white and black points right now).

Bugfix: clamp color seperated wave form display correctly.

source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/makesdna/DNA_sequence_types.h
source/blender/src/buttons_scene.c
source/blender/src/editseq.c
source/blender/src/seqscopes.c
source/blender/src/sequence.c

index a382fa17fa5eb3307275f8feb670eeaa65fa9be0..a05683dfd10fcfbdd933b4e3729616b8dd0270b4 100644 (file)
@@ -3468,6 +3468,12 @@ static void direct_link_scene(FileData *fd, Scene *sce)
                                } else {
                                        seq->strip->proxy = 0;
                                }
+                               if (seq->flag & SEQ_USE_COLOR_BALANCE) {
+                                       seq->strip->color_balance = newdataadr(
+                                               fd, seq->strip->color_balance);
+                               } else {
+                                       seq->strip->color_balance = 0;
+                               }
                        }
                }
                END_SEQ
index 8bcc2497dbd0d8c7c17639ac166144f547e026f6..6ff39d471dfe53c4d44cc601ba69b016d8840fea 100644 (file)
@@ -1505,6 +1505,9 @@ static void write_scenes(WriteData *wd, ListBase *scebase)
                                        if(seq->flag & SEQ_USE_PROXY && strip->proxy) {
                                                writestruct(wd, DATA, "StripProxy", 1, strip->proxy);
                                        }
+                                       if(seq->flag & SEQ_USE_COLOR_BALANCE && strip->color_balance) {
+                                               writestruct(wd, DATA, "StripColorBalance", 1, strip->color_balance);
+                                       }
                                        if(seq->type==SEQ_IMAGE)
                                                writestruct(wd, DATA, "StripElem", strip->len, strip->stripdata);
                                        else if(seq->type==SEQ_MOVIE || seq->type==SEQ_RAM_SOUND || seq->type == SEQ_HD_SOUND)
index 6798e726ce802ac206a5c92ffed21daf1ae9f15b..5e32476b4e0688f6a38ba7c54d4bbb6da719c82b 100644 (file)
@@ -69,6 +69,15 @@ typedef struct StripTransform {
        int yofs;
 } StripTransform;
 
+typedef struct StripColorBalance {
+       float lift[3];
+       float gamma[3];
+       float gain[3];
+       int flag;
+       float exposure;
+       float saturation;
+} StripColorBalance;
+
 typedef struct StripProxy {
        char dir[160];
        int format;
@@ -86,6 +95,7 @@ typedef struct Strip {
        StripCrop *crop;
        StripTransform *transform;
        StripProxy *proxy;
+       StripColorBalance *color_balance;
        TStripElem *tstripdata;
        TStripElem *tstripdata_startstill;
        TStripElem *tstripdata_endstill;
@@ -248,7 +258,11 @@ typedef struct SpeedControlVars {
 #define SEQ_USE_PROXY                           32768
 #define SEQ_USE_TRANSFORM                       65536
 #define SEQ_USE_CROP                           131072
+#define SEQ_USE_COLOR_BALANCE                  262144
 
+#define SEQ_COLOR_BALANCE_INVERSE_GAIN 1
+#define SEQ_COLOR_BALANCE_INVERSE_GAMMA 2
+#define SEQ_COLOR_BALANCE_INVERSE_LIFT 4
 
 /* seq->type WATCH IT: SEQ_EFFECT BIT is used to determine if this is an effect strip!!! */
 #define SEQ_IMAGE              0
index 2470da279962319025458e1e051b76fafc0f5888..6eb26e4327456a5e68dc6386da1962197b36c51a 100644 (file)
@@ -889,50 +889,113 @@ static void seq_panel_filter_video()
 
 
        uiDefButBitI(block, TOG, SEQ_MAKE_PREMUL, 
-                    B_SEQ_BUT_RELOAD, "Convert to Premul", 
-                    10,110,150,19, &last_seq->flag, 
+                    B_SEQ_BUT_RELOAD, "Premul", 
+                    10,110,80,19, &last_seq->flag, 
                     0.0, 21.0, 100, 0, 
                     "Converts RGB values to become premultiplied with Alpha");
 
+       uiDefButBitI(block, TOG, SEQ_MAKE_FLOAT, 
+                    B_SEQ_BUT_RELOAD, "Float", 
+                    90,110,80,19, &last_seq->flag, 
+                    0.0, 21.0, 100, 0, 
+                    "Convert input to float data");
+
        uiDefButBitI(block, TOG, SEQ_FILTERY, 
                     B_SEQ_BUT_RELOAD, "FilterY",       
-                    10,90,75,19, &last_seq->flag, 
+                    170,110,80,19, &last_seq->flag, 
                     0.0, 21.0, 100, 0, 
                     "For video movies to remove fields");
 
-       uiDefButBitI(block, TOG, SEQ_MAKE_FLOAT, 
-                    B_SEQ_BUT_RELOAD, "Make Float",    
-                    85,90,75,19, &last_seq->flag, 
-                    0.0, 21.0, 100, 0, 
-                    "Convert input to float data");
-               
        uiDefButBitI(block, TOG, SEQ_FLIPX, 
                     B_SEQ_BUT_RELOAD, "FlipX", 
-                    10,70,75,19, &last_seq->flag, 
+                    10,90,80,19, &last_seq->flag, 
                     0.0, 21.0, 100, 0, 
                     "Flip on the X axis");
        uiDefButBitI(block, TOG, SEQ_FLIPY, 
                     B_SEQ_BUT_RELOAD, "FlipY", 
-                    85,70,75,19, &last_seq->flag, 
+                    90,90,80,19, &last_seq->flag, 
                     0.0, 21.0, 100, 0, 
                     "Flip on the Y axis");
-               
-       uiDefButF(block, NUM, B_SEQ_BUT_RELOAD, "Mul:",
-                 10,50,150,19, &last_seq->mul, 
-                 0.001, 5.0, 100, 0, 
-                 "Multiply colors");
 
        uiDefButBitI(block, TOG, SEQ_REVERSE_FRAMES,
-                    B_SEQ_BUT_RELOAD, "Reverse Frames", 
-                    10,30,150,19, &last_seq->flag, 
+                    B_SEQ_BUT_RELOAD, "Flip Time", 
+                    170,90,80,19, &last_seq->flag, 
                     0.0, 21.0, 100, 0, 
                     "Reverse frame order");
+               
+       uiDefButF(block, NUM, B_SEQ_BUT_RELOAD, "Mul:",
+                 10,70,120,19, &last_seq->mul, 
+                 0.001, 5.0, 0.1, 0, 
+                 "Multiply colors");
 
        uiDefButF(block, NUM, B_SEQ_BUT_RELOAD, "Strobe:",
-                 10,10,150,19, &last_seq->strobe, 
+                 130,70,120,19, &last_seq->strobe, 
                  1.0, 30.0, 100, 0, 
                  "Only display every nth frame");
 
+       uiDefButBitI(block, TOG, SEQ_USE_COLOR_BALANCE,
+                    B_SEQ_BUT_RELOAD, "Use Color Balance", 
+                    10,50,240,19, &last_seq->flag, 
+                    0.0, 21.0, 100, 0, 
+                    "Activate Color Balance "
+                    "(3-Way color correction) on input");
+
+
+       if (last_seq->flag & SEQ_USE_COLOR_BALANCE) {
+               if (!last_seq->strip->color_balance) {
+                       int c;
+                       StripColorBalance * cb 
+                               = last_seq->strip->color_balance 
+                               = MEM_callocN(
+                                       sizeof(struct StripColorBalance), 
+                                       "StripColorBalance");
+                       for (c = 0; c < 3; c++) {
+                               cb->lift[c] = 1.0;
+                               cb->gamma[c] = 1.0;
+                               cb->gain[c] = 1.0;
+                       }
+               }
+
+               uiDefBut(block, LABEL, 0, "Lift",
+                        10,30,80,19, 0, 0, 0, 0, 0, "");
+               uiDefBut(block, LABEL, 0, "Gamma",
+                        90,30,80,19, 0, 0, 0, 0, 0, "");
+               uiDefBut(block, LABEL, 0, "Gain",
+                        170,30,80,19, 0, 0, 0, 0, 0, "");
+
+               uiDefButF(block, COL, B_SEQ_BUT_RELOAD, "Lift",
+                         10,10,80,19, last_seq->strip->color_balance->lift, 
+                         0, 0, 0, 0, "Lift (shadows)");
+
+               uiDefButF(block, COL, B_SEQ_BUT_RELOAD, "Gamma",
+                         90,10,80,19, last_seq->strip->color_balance->gamma, 
+                         0, 0, 0, 0, "Gamma (midtones)");
+
+               uiDefButF(block, COL, B_SEQ_BUT_RELOAD, "Gain",
+                         170,10,80,19, last_seq->strip->color_balance->gain, 
+                         0, 0, 0, 0, "Gain (highlights)");
+
+               uiDefButBitI(block, TOG, SEQ_COLOR_BALANCE_INVERSE_LIFT,
+                            B_SEQ_BUT_RELOAD, "Inv Lift", 
+                            10,-10,80,19, 
+                            &last_seq->strip->color_balance->flag, 
+                            0.0, 21.0, 100, 0, 
+                            "Inverse Lift");
+               uiDefButBitI(block, TOG, SEQ_COLOR_BALANCE_INVERSE_GAMMA,
+                            B_SEQ_BUT_RELOAD, "Inv Gamma", 
+                            90,-10,80,19, 
+                            &last_seq->strip->color_balance->flag, 
+                            0.0, 21.0, 100, 0, 
+                            "Inverse Gamma");
+               uiDefButBitI(block, TOG, SEQ_COLOR_BALANCE_INVERSE_GAIN,
+                            B_SEQ_BUT_RELOAD, "Inv Gain", 
+                            170,-10,80,19, 
+                            &last_seq->strip->color_balance->flag, 
+                            0.0, 21.0, 100, 0, 
+                            "Inverse Gain");
+       }
+
+
        uiBlockEndAlign(block);
 
 }
index e5e5a960f0c016243516f03a0377bc81aa5ad86d..4995e106a305f0b4edfe062d78224070c9186137 100644 (file)
@@ -2190,6 +2190,11 @@ static Sequence *dupli_seq(Sequence *seq)
        if (seq->strip->proxy) {
                seqn->strip->proxy = MEM_dupallocN(seq->strip->proxy);
        }
+
+       if (seq->strip->color_balance) {
+               seqn->strip->color_balance 
+                       = MEM_dupallocN(seq->strip->color_balance);
+       }
        
        if(seq->type==SEQ_META) {
                seqn->strip->stripdata = 0;
index 84a92982ab553c2b2996795aef91706ea184e3b5..b7b1d2436f8dba28afc35a4a5ce02950a4bab07a 100644 (file)
@@ -323,7 +323,11 @@ static struct ImBuf *make_sep_waveform_view_from_ibuf_float(
                        float * rgb = src + 4 * (ibuf->x * y + x);
                        for (c = 0; c < 3; c++) {
                                unsigned char * p = tgt;
-                               p += 4 * (w * ((int) (rgb[c] * (h - 3)) + 1)
+                               float v = rgb[c];
+
+                               CLAMP(v, 0.0, 1.0);
+
+                               p += 4 * (w * ((int) (v * (h - 3)) + 1)
                                          + c * sw + x/3 + 1);
 
                                scope_put_pixel_single(wtable, p, c);
index 63e92feb07e7ae22a1204f7a8e0c3465e91625b1..a570cc66cf03730248b7f5e7d050e1109181329e 100644 (file)
@@ -127,6 +127,9 @@ void free_strip(Strip *strip)
        if (strip->proxy) {
                seq_proxy_free(strip->proxy);
        }
+       if (strip->color_balance) {
+               MEM_freeN(strip->color_balance);
+       }
 
        free_tstripdata(strip->len, strip->tstripdata);
        free_tstripdata(strip->endstill, strip->tstripdata_endstill);
@@ -1010,6 +1013,164 @@ void set_meta_stripdata(Sequence *seqm)
        }
 }
 
+static StripColorBalance calc_cb(StripColorBalance * cb_)
+{
+       StripColorBalance cb = *cb_;
+       int c;
+
+       if (cb.flag & SEQ_COLOR_BALANCE_INVERSE_LIFT) {
+               for (c = 0; c < 3; c++) {
+                       cb.lift[c] = 1.0 - cb.lift[c];
+               }
+       } else {
+               for (c = 0; c < 3; c++) {
+                       cb.lift[c] = -(1.0 - cb.lift[c]);
+               }
+       }
+       if (cb.flag & SEQ_COLOR_BALANCE_INVERSE_GAIN) {
+               for (c = 0; c < 3; c++) {
+                       if (cb.gain[c] != 0.0) {
+                               cb.gain[c] = 1.0/cb.gain[c];
+                       } else {
+                               cb.gain[c] = 1000000; /* should be enough :) */
+                       }
+               }
+       }
+
+       if (!(cb.flag & SEQ_COLOR_BALANCE_INVERSE_GAMMA)) {
+               for (c = 0; c < 3; c++) {
+                       if (cb.gain[c] != 0.0) {
+                               cb.gamma[c] = 1.0/cb.gamma[c];
+                       } else {
+                               cb.gamma[c] = 1000000; /* should be enough :) */
+                       }
+               }
+       }
+
+       return cb;
+}
+
+static void make_cb_table_byte(float lift, float gain, float gamma,
+                              unsigned char * table, float mul)
+{
+       int y;
+
+       for (y = 0; y < 256; y++) {
+               float v = 1.0 * y / 255;
+               v += lift; 
+               v *= gain;
+               v = pow(v, gamma);
+               v *= mul;
+               if ( v > 1.0) {
+                       v = 1.0;
+               } else if (v < 0.0) {
+                       v = 0.0;
+               }
+               table[y] = v * 255;
+       }
+
+}
+
+static void make_cb_table_float(float lift, float gain, float gamma,
+                               float * table, float mul)
+{
+       int y;
+
+       for (y = 0; y < 256; y++) {
+               float v = (float) y * 1.0 / 255.0;
+               v += lift;
+               v *= gain;
+               v = pow(v, gamma);
+               v *= mul;
+               table[y] = v;
+       }
+}
+
+static void color_balance_byte_byte(Sequence * seq, TStripElem* se,
+                                   float mul)
+{
+       unsigned char cb_tab[3][256];
+       int c;
+       unsigned char * p = (unsigned char*) se->ibuf->rect;
+       unsigned char * e = p + se->ibuf->x * 4 * se->ibuf->y;
+
+       StripColorBalance cb = calc_cb(seq->strip->color_balance);
+
+       for (c = 0; c < 3; c++) {
+               make_cb_table_byte(cb.lift[c], cb.gain[c], cb.gamma[c],
+                                  cb_tab[c], mul);
+       }
+
+       while (p < e) {
+               p[0] = cb_tab[0][p[0]];
+               p[1] = cb_tab[1][p[1]];
+               p[2] = cb_tab[2][p[2]];
+               
+               p += 4;
+       }
+}
+
+static void color_balance_byte_float(Sequence * seq, TStripElem* se,
+                                    float mul)
+{
+       float cb_tab[4][256];
+       int c,i;
+       unsigned char * p = (unsigned char*) se->ibuf->rect;
+       unsigned char * e = p + se->ibuf->x * 4 * se->ibuf->y;
+       float * o;
+
+       imb_addrectfloatImBuf(se->ibuf);
+
+       o = se->ibuf->rect_float;
+
+       StripColorBalance cb = calc_cb(seq->strip->color_balance);
+
+       for (c = 0; c < 3; c++) {
+               make_cb_table_float(cb.lift[c], cb.gain[c], cb.gamma[c],
+                                   cb_tab[c], mul);
+       }
+
+       for (i = 0; i < 256; i++) {
+               cb_tab[3][i] = ((float)i)*(1.0f/255.0f);
+       }
+
+       while (p < e) {
+               o[0] = cb_tab[0][p[0]];
+               o[1] = cb_tab[1][p[1]];
+               o[2] = cb_tab[2][p[2]];
+               o[3] = cb_tab[3][p[3]];
+
+               p += 4; o += 4;
+       }
+}
+
+static void color_balance_float_float(Sequence * seq, TStripElem* se,
+                                     float mul)
+{
+       float * p = se->ibuf->rect_float;
+       float * e = se->ibuf->rect_float + se->ibuf->x * 4* se->ibuf->y;
+       StripColorBalance cb = calc_cb(seq->strip->color_balance);
+
+       while (p < e) {
+               int c;
+               for (c = 0; c < 3; c++) {
+                       p[c] = pow((p[c] + cb.lift[c]) * cb.gain[c], 
+                                  cb.gamma[c]) * mul;
+               }
+       }
+}
+
+static void color_balance(Sequence * seq, TStripElem* se, float mul)
+{
+       if (se->ibuf->rect_float) {
+               color_balance_float_float(seq, se, mul);
+       } else if(seq->flag & SEQ_MAKE_FLOAT) {
+               color_balance_byte_float(seq, se, mul);
+       } else {
+               color_balance_byte_byte(seq, se, mul);
+       }
+}
+
 /*
   input preprocessing for SEQ_IMAGE, SEQ_MOVIE and SEQ_SCENE
 
@@ -1022,6 +1183,9 @@ void set_meta_stripdata(Sequence *seqm)
   - Crop and transform in image source coordinate space
   - Flip X + Flip Y (could be done afterwards, backward compatibility)
   - Promote image to float data (affects pipeline operations afterwards)
+  - Color balance (is most efficient in the byte -> float 
+    (future: half -> float should also work fine!)
+    case, if done on load, since we can use lookup tables)
   - Premultiply
 
 */
@@ -1092,13 +1256,6 @@ static void input_preprocess(Sequence * seq, TStripElem* se, int cfra)
                IMB_flipy(se->ibuf);
        }
 
-       if(seq->flag & SEQ_MAKE_FLOAT) {
-               if (!se->ibuf->rect_float) {
-                       IMB_float_from_rect(se->ibuf);
-                       imb_freerectImBuf(se->ibuf);
-               }
-       }
-
        if(seq->mul == 0.0) {
                seq->mul = 1.0;
        }
@@ -1113,6 +1270,20 @@ static void input_preprocess(Sequence * seq, TStripElem* se, int cfra)
                mul *= seq->blend_opacity / 100.0;
        }
 
+       if(seq->flag & SEQ_USE_COLOR_BALANCE && seq->strip->color_balance) {
+               color_balance(seq, se, mul);
+               mul = 1.0;
+       }
+
+       if(seq->flag & SEQ_MAKE_FLOAT) {
+               if (!se->ibuf->rect_float) {
+                       IMB_float_from_rect(se->ibuf);
+               }
+               if (se->ibuf->rect) {
+                       imb_freerectImBuf(se->ibuf);
+               }
+       }
+
        if(mul != 1.0) {
                multibuf(se->ibuf, mul);
        }