| @@ -30,6 +30,7 @@ · 29 unmodified lines |
| 30 | typedef enum AnalyzeMode { | 30 | typedef enum AnalyzeMode { |
| 31 | MANUAL, | 31 | MANUAL, |
| 32 | AVERAGE, | 32 | AVERAGE, |
| | 33 | MINMAX, |
| 33 | NB_ANALYZE | 34 | NB_ANALYZE |
| 34 | } AnalyzeMode; | 35 | } AnalyzeMode; |
| 35 | | 36 | |
| @@ -48,7 +49,7 @@ typedef struct ColorCorrectContext { · 12 unmodified lines |
| 48 | int planeheight[4]; | 49 | int planeheight[4]; |
| 49 | int planewidth[4]; | 50 | int planewidth[4]; |
| 50 | | 51 | |
| 51 | float (*analyzeret)[2]; | 52 | float (*analyzeret)[4]; |
| 52 | | 53 | |
| 53 | int (*do_analyze)(AVFilterContext *s, void *arg, | 54 | int (*do_analyze)(AVFilterContext *s, void *arg, |
| 54 | int jobnr, int nb_jobs); | 55 | int jobnr, int nb_jobs); |
| @@ -81,8 +82,8 @@ static int average_slice8(AVFilterContext *ctx, void *arg, int jobnr, int nb_job · 26 unmodified lines |
| 81 | vptr += vlinesize; | 82 | vptr += vlinesize; |
| 82 | } | 83 | } |
| 83 | | 84 | |
| 84 | s->analyzeret[jobnr][0] = imax * sum_u / (float)((slice_end - slice_start) * width) - 0.5f; | 85 | s->analyzeret[jobnr][0] = s->analyzeret[jobnr][2] = imax * sum_u / (float)((slice_end - slice_start) * width) - 0.5f; |
| 85 | s->analyzeret[jobnr][1] = imax * sum_v / (float)((slice_end - slice_start) * width) - 0.5f; | 86 | s->analyzeret[jobnr][1] = s->analyzeret[jobnr][3] = imax * sum_v / (float)((slice_end - slice_start) * width) - 0.5f; |
| 86 | | 87 | |
| 87 | return 0; | 88 | return 0; |
| 88 | } | 89 | } |
| @@ -112,8 +113,80 @@ static int average_slice16(AVFilterContext *ctx, void *arg, int jobnr, int nb_jo · 23 unmodified lines |
| 112 | vptr += vlinesize; | 113 | vptr += vlinesize; |
| 113 | } | 114 | } |
| 114 | | 115 | |
| 115 | s->analyzeret[jobnr][0] = imax * sum_u / (float)((slice_end - slice_start) * width) - 0.5f; | 116 | s->analyzeret[jobnr][0] = s->analyzeret[jobnr][2] = imax * sum_u / (float)((slice_end - slice_start) * width) - 0.5f; |
| 116 | s->analyzeret[jobnr][1] = imax * sum_v / (float)((slice_end - slice_start) * width) - 0.5f; | 117 | s->analyzeret[jobnr][1] = s->analyzeret[jobnr][3] = imax * sum_v / (float)((slice_end - slice_start) * width) - 0.5f; |
| | 118 | |
| | 119 | return 0; |
| | 120 | } |
| | 121 | |
| | 122 | static int minmax_slice8(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) |
| | 123 | { |
| | 124 | ColorCorrectContext *s = ctx->priv; |
| | 125 | AVFrame *frame = arg; |
| | 126 | const float imax = s->imax; |
| | 127 | const int width = s->planewidth[1]; |
| | 128 | const int height = s->planeheight[1]; |
| | 129 | const int slice_start = (height * jobnr) / nb_jobs; |
| | 130 | const int slice_end = (height * (jobnr + 1)) / nb_jobs; |
| | 131 | const int ulinesize = frame->linesize[1]; |
| | 132 | const int vlinesize = frame->linesize[2]; |
| | 133 | const uint8_t *uptr = (const uint8_t *)frame->data[1] + slice_start * ulinesize; |
| | 134 | const uint8_t *vptr = (const uint8_t *)frame->data[2] + slice_start * vlinesize; |
| | 135 | int min_u = 255, min_v = 255; |
| | 136 | int max_u = 0, max_v = 0; |
| | 137 | |
| | 138 | for (int y = slice_start; y < slice_end; y++) { |
| | 139 | for (int x = 0; x < width; x++) { |
| | 140 | min_u = FFMIN(min_u, uptr[x]); |
| | 141 | min_v = FFMIN(min_v, vptr[x]); |
| | 142 | max_u = FFMAX(max_u, uptr[x]); |
| | 143 | max_v = FFMAX(max_v, vptr[x]); |
| | 144 | } |
| | 145 | |
| | 146 | uptr += ulinesize; |
| | 147 | vptr += vlinesize; |
| | 148 | } |
| | 149 | |
| | 150 | s->analyzeret[jobnr][0] = imax * min_u - 0.5f; |
| | 151 | s->analyzeret[jobnr][1] = imax * min_v - 0.5f; |
| | 152 | s->analyzeret[jobnr][2] = imax * max_u - 0.5f; |
| | 153 | s->analyzeret[jobnr][3] = imax * max_v - 0.5f; |
| | 154 | |
| | 155 | return 0; |
| | 156 | } |
| | 157 | |
| | 158 | static int minmax_slice16(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) |
| | 159 | { |
| | 160 | ColorCorrectContext *s = ctx->priv; |
| | 161 | AVFrame *frame = arg; |
| | 162 | const float imax = s->imax; |
| | 163 | const int width = s->planewidth[1]; |
| | 164 | const int height = s->planeheight[1]; |
| | 165 | const int slice_start = (height * jobnr) / nb_jobs; |
| | 166 | const int slice_end = (height * (jobnr + 1)) / nb_jobs; |
| | 167 | const int ulinesize = frame->linesize[1] / 2; |
| | 168 | const int vlinesize = frame->linesize[2] / 2; |
| | 169 | const uint16_t *uptr = (const uint16_t *)frame->data[1] + slice_start * ulinesize; |
| | 170 | const uint16_t *vptr = (const uint16_t *)frame->data[2] + slice_start * vlinesize; |
| | 171 | int min_u = INT_MAX, min_v = INT_MAX; |
| | 172 | int max_u = INT_MIN, max_v = INT_MIN; |
| | 173 | |
| | 174 | for (int y = slice_start; y < slice_end; y++) { |
| | 175 | for (int x = 0; x < width; x++) { |
| | 176 | min_u = FFMIN(min_u, uptr[x]); |
| | 177 | min_v = FFMIN(min_v, vptr[x]); |
| | 178 | max_u = FFMAX(max_u, uptr[x]); |
| | 179 | max_v = FFMAX(max_v, vptr[x]); |
| | 180 | } |
| | 181 | |
| | 182 | uptr += ulinesize; |
| | 183 | vptr += vlinesize; |
| | 184 | } |
| | 185 | |
| | 186 | s->analyzeret[jobnr][0] = imax * min_u - 0.5f; |
| | 187 | s->analyzeret[jobnr][1] = imax * min_v - 0.5f; |
| | 188 | s->analyzeret[jobnr][2] = imax * max_u - 0.5f; |
| | 189 | s->analyzeret[jobnr][3] = imax * max_v - 0.5f; |
| 117 | | 190 | |
| 118 | return 0; | 191 | return 0; |
| 119 | } | 192 | } |
| @@ -215,20 +288,26 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) · 95 unmodified lines |
| 215 | const int nb_threads = FFMIN(s->planeheight[1], ff_filter_get_nb_threads(ctx)); | 288 | const int nb_threads = FFMIN(s->planeheight[1], ff_filter_get_nb_threads(ctx)); |
| 216 | | 289 | |
| 217 | if (s->analyze) { | 290 | if (s->analyze) { |
| 218 | float bl = 0.f, rl = 0.f; | 291 | float bl = 0.f, rl = 0.f, bh = 0.f, rh = 0.f; |
| 219 | | 292 | |
| 220 | ff_filter_execute(ctx, s->do_analyze, frame, NULL, nb_threads); | 293 | ff_filter_execute(ctx, s->do_analyze, frame, NULL, nb_threads); |
| 221 | | 294 | |
| 222 | for (int i = 0; i < nb_threads; i++) { | 295 | for (int i = 0; i < nb_threads; i++) { |
| 223 | bl += s->analyzeret[i][0]; | 296 | bl += s->analyzeret[i][0]; |
| 224 | rl += s->analyzeret[i][0]; | 297 | rl += s->analyzeret[i][1]; |
| | 298 | bh += s->analyzeret[i][2]; |
| | 299 | rh += s->analyzeret[i][3]; |
| 225 | } | 300 | } |
| 226 | | 301 | |
| 227 | bl /= nb_threads; | 302 | bl /= nb_threads; |
| 228 | rl /= nb_threads; | 303 | rl /= nb_threads; |
| | 304 | bh /= nb_threads; |
| | 305 | rh /= nb_threads; |
| 229 | | 306 | |
| 230 | s->bl = -bl; | 307 | s->bl = -bl; |
| 231 | s->rl = -rl; | 308 | s->rl = -rl; |
| | 309 | s->bh = -bh; |
| | 310 | s->rh = -rh; |
| 232 | } | 311 | } |
| 233 | | 312 | |
| 234 | ff_filter_execute(ctx, s->do_slice, frame, NULL, nb_threads); | 313 | ff_filter_execute(ctx, s->do_slice, frame, NULL, nb_threads); |
| @@ -278,6 +357,9 @@ static av_cold int config_input(AVFilterLink *inlink) · 43 unmodified lines |
| 278 | case AVERAGE: | 357 | case AVERAGE: |
| 279 | s->do_analyze = s->depth <= 8 ? average_slice8 : average_slice16; | 358 | s->do_analyze = s->depth <= 8 ? average_slice8 : average_slice16; |
| 280 | break; | 359 | break; |
| | 360 | case MINMAX: |
| | 361 | s->do_analyze = s->depth <= 8 ? minmax_slice8 : minmax_slice16; |
| | 362 | break; |
| 281 | default: | 363 | default: |
| 282 | return AVERROR_BUG; | 364 | return AVERROR_BUG; |
| 283 | } | 365 | } |
| @@ -327,9 +409,10 @@ static const AVOption colorcorrect_options[] = { · 43 unmodified lines |
| 327 | { "rh", "set the red highlight spot", OFFSET(rh), AV_OPT_TYPE_FLOAT, {.dbl=0}, -1, 1, VF }, | 409 | { "rh", "set the red highlight spot", OFFSET(rh), AV_OPT_TYPE_FLOAT, {.dbl=0}, -1, 1, VF }, |
| 328 | { "bh", "set the blue highlight spot", OFFSET(bh), AV_OPT_TYPE_FLOAT, {.dbl=0}, -1, 1, VF }, | 410 | { "bh", "set the blue highlight spot", OFFSET(bh), AV_OPT_TYPE_FLOAT, {.dbl=0}, -1, 1, VF }, |
| 329 | { "saturation", "set the amount of saturation", OFFSET(saturation), AV_OPT_TYPE_FLOAT, {.dbl=1}, -3, 3, VF }, | 411 | { "saturation", "set the amount of saturation", OFFSET(saturation), AV_OPT_TYPE_FLOAT, {.dbl=1}, -3, 3, VF }, |
| 330 | { "analyze", "set the analyze mode", OFFSET(analyze), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_ANALYZE, VF, "analyze" }, | 412 | { "analyze", "set the analyze mode", OFFSET(analyze), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_ANALYZE-1, VF, "analyze" }, |
| 331 | { "manual", "manually set options", 0, AV_OPT_TYPE_CONST, {.i64=MANUAL}, 0, 0, VF, "analyze" }, | 413 | { "manual", "manually set options", 0, AV_OPT_TYPE_CONST, {.i64=MANUAL}, 0, 0, VF, "analyze" }, |
| 332 | { "average", "use average pixels", 0, AV_OPT_TYPE_CONST, {.i64=AVERAGE}, 0, 0, VF, "analyze" }, | 414 | { "average", "use average pixels", 0, AV_OPT_TYPE_CONST, {.i64=AVERAGE}, 0, 0, VF, "analyze" }, |
| | 415 | { "minmax", "use minmax pixels", 0, AV_OPT_TYPE_CONST, {.i64=MINMAX}, 0, 0, VF, "analyze" }, |
| 333 | { NULL } | 416 | { NULL } |
| 334 | }; | 417 | }; |
| 335 | | 418 | |