1 /*
2 * Copyright (c) 2012-2019 Paul B Mahol
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
31
33 const AVClass *
class;
///< AVClass context for log and options purpose
63
64 #define OFFSET(x) offsetof(HistogramContext, x)
65 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
66
67 #define COMMON_OPTIONS \
68 { "display_mode", "set display mode", OFFSET(display_mode), AV_OPT_TYPE_INT, {.i64=2}, 0, 2, FLAGS, "display_mode"}, \
69 { "d", "set display mode", OFFSET(display_mode), AV_OPT_TYPE_INT, {.i64=2}, 0, 2, FLAGS, "display_mode"}, \
70 { "overlay", NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "display_mode" }, \
71 { "parade", NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "display_mode" }, \
72 { "stack", NULL, 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "display_mode" }, \
73 { "levels_mode", "set levels mode", OFFSET(levels_mode), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS, "levels_mode"}, \
74 { "m", "set levels mode", OFFSET(levels_mode), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS, "levels_mode"}, \
75 { "linear", NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "levels_mode" }, \
76 { "logarithmic", NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "levels_mode" }, \
77 { "components", "set color components to display", OFFSET(components), AV_OPT_TYPE_INT, {.i64=7}, 1, 15, FLAGS}, \
78 { "c", "set color components to display", OFFSET(components), AV_OPT_TYPE_INT, {.i64=7}, 1, 15, FLAGS},
79
101 };
102
104
122 };
123
127 };
128
132 };
133
137 };
138
142 };
143
147 };
148
152 };
153
157 };
158
162 };
163
165 {
171
172 if (!
ctx->inputs[0]->incfg.formats ||
173 !
ctx->inputs[0]->incfg.formats->nb_formats) {
175 }
176
177 if (!
ctx->inputs[0]->outcfg.formats)
180 avff =
ctx->inputs[0]->incfg.formats;
189 }
190
207 else
211
212 return 0;
213 }
214
227
229 {
232
234 s->ncomp =
s->desc->nb_components;
235 s->histogram_size = 1 <<
s->desc->comp[0].depth;
236 s->mult =
s->histogram_size / 256;
237
248 s->start[0] =
s->start[1] =
s->start[2] =
s->start[3] = 0;
249 memcpy(
s->envelope_color,
s->envelope_rgba, 4);
251 break;
252 default:
256 s->start[0] =
s->start[3] = 0;
257 s->start[1] =
s->start[2] =
s->histogram_size / 2;
258 s->envelope_color[0] =
RGB_TO_Y_BT709(
s->envelope_rgba[0],
s->envelope_rgba[1],
s->envelope_rgba[2]);
259 s->envelope_color[1] =
RGB_TO_U_BT709(
s->envelope_rgba[0],
s->envelope_rgba[1],
s->envelope_rgba[2], 0);
260 s->envelope_color[2] =
RGB_TO_V_BT709(
s->envelope_rgba[0],
s->envelope_rgba[1],
s->envelope_rgba[2], 0);
261 s->envelope_color[3] =
s->envelope_rgba[3];
262 }
263
264 for (
int i = 1;
i < 4;
i++) {
265 memcpy(
s->fg_color[
i],
s->fg_color[0], 4);
266 memcpy(
s->bg_color[
i],
s->bg_color[0], 4);
267 }
268
269 if (
s->display_mode) {
270 if (
s->colors_mode == 1) {
271 for (
int i = 0;
i < 4;
i++)
272 for (int j = 0; j < 4; j++)
273 FFSWAP(uint8_t,
s->fg_color[
i][j],
s->bg_color[
i][j]);
274 }
else if (
s->colors_mode == 2) {
275 for (
int i = 0;
i < 4;
i++)
277 }
else if (
s->colors_mode == 3) {
278 for (
int i = 0;
i < 4;
i++)
279 for (int j = 0; j < 4; j++)
280 FFSWAP(uint8_t,
s->fg_color[
i][j],
s->bg_color[
i][j]);
281 for (
int i = 0;
i < 4;
i++)
283 }
else if (
s->colors_mode == 4) {
288 } else {
292 }
293 }
else if (
s->colors_mode == 5) {
294 for (
int i = 0;
i < 4;
i++)
295 for (int j = 0; j < 4; j++)
296 FFSWAP(uint8_t,
s->fg_color[
i][j],
s->bg_color[
i][j]);
301 } else {
305 }
306 }
else if (
s->colors_mode == 6) {
307 for (
int i = 0;
i < 4;
i++)
313 } else {
317 }
318 }
else if (
s->colors_mode == 7) {
319 for (
int i = 0;
i < 4;
i++)
320 for (int j = 0; j < 4; j++)
321 FFSWAP(uint8_t,
s->fg_color[
i][j],
s->bg_color[
i][j]);
326 } else {
330 }
331 }
else if (
s->colors_mode == 8) {
336 } else {
340 }
341 }
else if (
s->colors_mode == 9) {
342 for (
int i = 0;
i < 4;
i++)
348 } else {
352 }
353 }
354 }
355
356 for (
int i = 0;
i < 4;
i++) {
357 s->fg_color[
i][3] =
s->fgopacity * 255;
358 s->bg_color[
i][3] =
s->bgopacity * 255;
359 }
360
362 s->planeheight[0] =
s->planeheight[3] =
inlink->h;
364 s->planewidth[0] =
s->planewidth[3] =
inlink->w;
365
366 return 0;
367 }
368
370 {
374
375 if (!strcmp(
ctx->filter->name,
"thistogram"))
377
378 for (
i = 0;
i <
s->ncomp;
i++) {
379 if ((1 <<
i) &
s->components)
380 ncomp++;
381 }
382
385 s->width =
ctx->inputs[0]->w;
386 outlink->
w =
s->width *
FFMAX(ncomp * (
s->display_mode == 1), 1);
387 outlink->
h =
s->histogram_size *
FFMAX(ncomp * (
s->display_mode == 2), 1);
388 } else {
389 outlink->
w =
s->histogram_size *
FFMAX(ncomp * (
s->display_mode == 1), 1);
390 outlink->
h = (
s->level_height +
s->scale_height) *
FFMAX(ncomp * (
s->display_mode == 2), 1);
391 }
392
394 s->dncomp =
s->odesc->nb_components;
396
397 return 0;
398 }
399
401 {
407
408 if (!
s->thistogram || !
out) {
413 }
415
416 for (k = 0; k < 4 &&
out->data[k]; k++) {
417 const int is_chroma = (k == 1 || k == 2);
418 const int dst_h =
AV_CEIL_RSHIFT(outlink->
h, (is_chroma ?
s->odesc->log2_chroma_h : 0));
419 const int dst_w =
AV_CEIL_RSHIFT(outlink->
w, (is_chroma ?
s->odesc->log2_chroma_w : 0));
420
421 if (
s->histogram_size <= 256) {
422 for (
i = 0;
i < dst_h ;
i++)
423 memset(
out->data[
s->odesc->comp[k].plane] +
424 i *
out->linesize[
s->odesc->comp[k].plane],
425 s->bg_color[0][k], dst_w);
426 } else {
427 const int mult =
s->mult;
428
429 for (
i = 0;
i < dst_h ;
i++)
430 for (j = 0; j < dst_w; j++)
432 i *
out->linesize[
s->odesc->comp[k].plane] + j * 2,
433 s->bg_color[0][k] *
mult);
434 }
435 }
436 }
437
438 for (m = 0, k = 0; k <
s->ncomp; k++) {
439 const int p =
s->desc->comp[k].plane;
440 const int max_value =
s->histogram_size - 1 -
s->start[p];
441 const int height =
s->planeheight[p];
442 const int width =
s->planewidth[p];
443 const int mid =
s->mid;
444 double max_hval_log;
445 unsigned max_hval = 0;
446 int starty, startx;
447
448 if (!((1 << k) &
s->components))
449 continue;
451 starty = m *
s->histogram_size * (
s->display_mode == 2);
452 startx = m++ *
s->width * (
s->display_mode == 1);
453 } else {
454 startx = m *
s->histogram_size * (
s->display_mode == 1);
455 starty = m++ * (
s->level_height +
s->scale_height) * (
s->display_mode == 2);
456 }
457
458 if (
s->histogram_size <= 256) {
461 for (j = 0; j <
width; j++)
462 s->histogram[
src[j]]++;
463 }
464 } else {
466 const uint16_t *
src = (
const uint16_t *)(in->
data[p] +
i * in->
linesize[p]);
467 for (j = 0; j <
width; j++)
468 s->histogram[
src[j]]++;
469 }
470 }
471
472 for (
i = 0;
i <
s->histogram_size;
i++)
473 max_hval =
FFMAX(max_hval,
s->histogram[
i]);
474 max_hval_log =
log2(max_hval + 1);
475
477 const int bpp = 1 + (
s->histogram_size > 256);
478 int minh =
s->histogram_size - 1, maxh = 0;
479
481 s->x_pos =
out->width - 1;
482 for (j = 0; j < outlink->
h; j++) {
483 memmove(
out->data[p] + j *
out->linesize[p] ,
484 out->data[p] + j *
out->linesize[p] + bpp,
485 (outlink->
w - 1) * bpp);
486 }
487 }
else if (
s->slide == 3) {
489 for (j = 0; j < outlink->
h; j++) {
490 memmove(
out->data[p] + j *
out->linesize[p] + bpp,
491 out->data[p] + j *
out->linesize[p],
492 (outlink->
w - 1) * bpp);
493 }
494 }
495
496 for (
int i = 0;
i <
s->histogram_size;
i++) {
497 int idx =
s->histogram_size -
i - 1;
499
500 if (
s->envelope &&
s->histogram[idx]) {
503 }
504
506 value +=
lrint(max_value * (
log2(
s->histogram[idx] + 1) / max_hval_log));
507 else
508 value +=
lrint(max_value *
s->histogram[idx] / (
float)max_hval);
509
510 if (
s->histogram_size <= 256) {
511 s->out->data[p][(
i + starty) *
s->out->linesize[p] + startx +
s->x_pos] =
value;
512 } else {
513 AV_WN16(
s->out->data[p] + (
i + starty) *
s->out->linesize[p] + startx * 2 +
s->x_pos * 2,
value);
514 }
515 }
516
518 if (
s->histogram_size <= 256) {
519 s->out->data[0][(minh + starty) *
s->out->linesize[p] + startx +
s->x_pos] =
s->envelope_color[0];
520 s->out->data[0][(maxh + starty) *
s->out->linesize[p] + startx +
s->x_pos] =
s->envelope_color[0];
521 if (
s->dncomp >= 3) {
522 s->out->data[1][(minh + starty) *
s->out->linesize[p] + startx +
s->x_pos] =
s->envelope_color[1];
523 s->out->data[2][(minh + starty) *
s->out->linesize[p] + startx +
s->x_pos] =
s->envelope_color[2];
524 s->out->data[1][(maxh + starty) *
s->out->linesize[p] + startx +
s->x_pos] =
s->envelope_color[1];
525 s->out->data[2][(maxh + starty) *
s->out->linesize[p] + startx +
s->x_pos] =
s->envelope_color[2];
526 }
527 } else {
528 const int mult =
s->mult;
529
530 AV_WN16(
s->out->data[0] + (minh + starty) *
s->out->linesize[p] + startx * 2 +
s->x_pos * 2,
s->envelope_color[0] *
mult);
531 AV_WN16(
s->out->data[0] + (maxh + starty) *
s->out->linesize[p] + startx * 2 +
s->x_pos * 2,
s->envelope_color[0] *
mult);
532 if (
s->dncomp >= 3) {
533 AV_WN16(
s->out->data[1] + (minh + starty) *
s->out->linesize[p] + startx * 2 +
s->x_pos * 2,
s->envelope_color[1] *
mult);
534 AV_WN16(
s->out->data[2] + (minh + starty) *
s->out->linesize[p] + startx * 2 +
s->x_pos * 2,
s->envelope_color[2] *
mult);
535 AV_WN16(
s->out->data[1] + (maxh + starty) *
s->out->linesize[p] + startx * 2 +
s->x_pos * 2,
s->envelope_color[1] *
mult);
536 AV_WN16(
s->out->data[2] + (maxh + starty) *
s->out->linesize[p] + startx * 2 +
s->x_pos * 2,
s->envelope_color[2] *
mult);
537 }
538 }
539 }
540 } else {
541 for (
i = 0;
i <
s->histogram_size;
i++) {
542 int col_height;
543
545 col_height =
lrint(
s->level_height * (1. - (
log2(
s->histogram[
i] + 1) / max_hval_log)));
546 else
547 col_height =
s->level_height - (
s->histogram[
i] * (int64_t)
s->level_height + max_hval - 1) / max_hval;
548
549 if (
s->histogram_size <= 256) {
550 for (j =
s->level_height - 1; j >= col_height; j--) {
551 if (
s->display_mode) {
552 for (l = 0; l <
s->dncomp; l++)
553 out->data[l][(j + starty) *
out->linesize[l] + startx +
i] =
s->fg_color[p][l];
554 } else {
555 out->data[p][(j + starty) *
out->linesize[p] + startx +
i] = 255;
556 }
557 }
558 if (
s->display_mode) {
559 for (j = col_height - 1; j >= 0; j--) {
560 for (l = 0; l <
s->dncomp; l++)
561 out->data[l][(j + starty) *
out->linesize[l] + startx +
i] =
s->bg_color[p][l];
562 }
563 }
564 for (j =
s->level_height +
s->scale_height - 1; j >=
s->level_height; j--)
565 for (l = 0; l <
s->dncomp; l++)
566 out->data[l][(j + starty) *
out->linesize[l] + startx +
i] = p == l ?
i : mid;
567 } else {
568 const int mult =
s->mult;
569
570 for (j =
s->level_height - 1; j >= col_height; j--) {
571 if (
s->display_mode) {
572 for (l = 0; l <
s->dncomp; l++)
573 AV_WN16(
out->data[l] + (j + starty) *
out->linesize[l] + startx * 2 +
i * 2,
s->fg_color[p][l] *
mult);
574 } else {
575 AV_WN16(
out->data[p] + (j + starty) *
out->linesize[p] + startx * 2 +
i * 2, 255 *
mult);
576 }
577 }
578 if (
s->display_mode) {
579 for (j = col_height - 1; j >= 0; j--) {
580 for (l = 0; l <
s->dncomp; l++)
581 AV_WN16(
out->data[l] + (j + starty) *
out->linesize[l] + startx * 2 +
i * 2,
s->bg_color[p][l] *
mult);
582 }
583 }
584 for (j =
s->level_height +
s->scale_height - 1; j >=
s->level_height; j--)
585 for (l = 0; l <
s->dncomp; l++)
586 AV_WN16(
out->data[l] + (j + starty) *
out->linesize[l] + startx * 2 +
i * 2, p == l ?
i : mid *
mult);
587 }
588 }
589 }
590
591 memset(
s->histogram, 0,
s->histogram_size *
sizeof(
unsigned));
592 }
593
597 if (
s->x_pos >=
s->width) {
599 if (
s->thistogram && (
s->slide == 4 ||
s->slide == 0)) {
601 goto end;
602 }
603 }
else if (
s->thistogram &&
s->slide == 4) {
604 return 0;
605 }
606
609
610 if (!clone)
613 }
614 end:
616 }
617
619 {
624 },
625 };
626
628 {
632 },
633 };
634
635 #if CONFIG_HISTOGRAM_FILTER
636
644 .priv_class = &histogram_class,
645 };
646
647 #endif /* CONFIG_HISTOGRAM_FILTER */
648
649 #if CONFIG_THISTOGRAM_FILTER
650
652 {
654
656 }
657
658 static const AVOption thistogram_options[] = {
675 };
676
678
680 .
name =
"thistogram",
687 .priv_class = &thistogram_class,
688 };
689
690 #endif /* CONFIG_THISTOGRAM_FILTER */