... | ... |
@@ -5750,6 +5750,8 @@ options. In this case, the unset component(s) will fallback on this |
5750 | 5750 |
@option{all} setting. |
5751 | 5751 |
@item psfile |
5752 | 5752 |
Specify a Photoshop curves file (@code{.acv}) to import the settings from. |
5753 |
+@item plot |
|
5754 |
+Save Gnuplot script of the curves in specified file. |
|
5753 | 5755 |
@end table |
5754 | 5756 |
|
5755 | 5757 |
To avoid some filtergraph syntax conflicts, each key points list need to be |
... | ... |
@@ -5796,6 +5798,14 @@ Use a Photoshop preset and redefine the points of the green component: |
5796 | 5796 |
@example |
5797 | 5797 |
curves=psfile='MyCurvesPresets/purple.acv':green='0/0 0.45/0.53 1/1' |
5798 | 5798 |
@end example |
5799 |
+ |
|
5800 |
+@item |
|
5801 |
+Check out the curves of the @code{cross_process} profile using @command{ffmpeg} |
|
5802 |
+and @command{gnuplot}: |
|
5803 |
+@example |
|
5804 |
+ffmpeg -f lavfi -i color -vf curves=cross_process:plot=/tmp/curves.plt -frames:v 1 -f null - |
|
5805 |
+gnuplot -p /tmp/curves.plt |
|
5806 |
+@end example |
|
5799 | 5807 |
@end itemize |
5800 | 5808 |
|
5801 | 5809 |
@section datascope |
... | ... |
@@ -67,6 +67,7 @@ typedef struct { |
67 | 67 |
char *psfile; |
68 | 68 |
uint8_t rgba_map[4]; |
69 | 69 |
int step; |
70 |
+ char *plot_filename; |
|
70 | 71 |
} CurvesContext; |
71 | 72 |
|
72 | 73 |
typedef struct ThreadData { |
... | ... |
@@ -98,6 +99,7 @@ static const AVOption curves_options[] = { |
98 | 98 |
{ "b", "set blue points coordinates", OFFSET(comp_points_str[2]), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS }, |
99 | 99 |
{ "all", "set points coordinates for all components", OFFSET(comp_points_str_all), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS }, |
100 | 100 |
{ "psfile", "set Photoshop curves file name", OFFSET(psfile), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS }, |
101 |
+ { "plot", "save Gnuplot script of the curves in specified file", OFFSET(plot_filename), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS }, |
|
101 | 102 |
{ NULL } |
102 | 103 |
}; |
103 | 104 |
|
... | ... |
@@ -377,6 +379,65 @@ end: |
377 | 377 |
return ret; |
378 | 378 |
} |
379 | 379 |
|
380 |
+static int dump_curves(const char *fname, uint8_t graph[NB_COMP + 1][256], |
|
381 |
+ struct keypoint *comp_points[NB_COMP + 1]) |
|
382 |
+{ |
|
383 |
+ int i; |
|
384 |
+ AVBPrint buf; |
|
385 |
+ static const char * const colors[] = { "red", "green", "blue", "#404040", }; |
|
386 |
+ FILE *f = av_fopen_utf8(fname, "w"); |
|
387 |
+ |
|
388 |
+ av_assert0(FF_ARRAY_ELEMS(colors) == NB_COMP + 1); |
|
389 |
+ |
|
390 |
+ if (!f) { |
|
391 |
+ int ret = AVERROR(errno); |
|
392 |
+ av_log(NULL, AV_LOG_ERROR, "Cannot open file '%s' for writing: %s\n", |
|
393 |
+ fname, av_err2str(ret)); |
|
394 |
+ return ret; |
|
395 |
+ } |
|
396 |
+ |
|
397 |
+ av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); |
|
398 |
+ |
|
399 |
+ av_bprintf(&buf, "set xtics 0.1\n"); |
|
400 |
+ av_bprintf(&buf, "set ytics 0.1\n"); |
|
401 |
+ av_bprintf(&buf, "set size square\n"); |
|
402 |
+ av_bprintf(&buf, "set grid\n"); |
|
403 |
+ |
|
404 |
+ for (i = 0; i < FF_ARRAY_ELEMS(colors); i++) { |
|
405 |
+ av_bprintf(&buf, "%s'-' using 1:2 with lines lc '%s' title ''", |
|
406 |
+ i ? ", " : "plot ", colors[i]); |
|
407 |
+ if (comp_points[i]) |
|
408 |
+ av_bprintf(&buf, ", '-' using 1:2 with points pointtype 3 lc '%s' title ''", |
|
409 |
+ colors[i]); |
|
410 |
+ } |
|
411 |
+ av_bprintf(&buf, "\n"); |
|
412 |
+ |
|
413 |
+ for (i = 0; i < FF_ARRAY_ELEMS(colors); i++) { |
|
414 |
+ int x; |
|
415 |
+ |
|
416 |
+ /* plot generated values */ |
|
417 |
+ for (x = 0; x < 256; x++) |
|
418 |
+ av_bprintf(&buf, "%f %f\n", x/255., graph[i][x]/255.); |
|
419 |
+ av_bprintf(&buf, "e\n"); |
|
420 |
+ |
|
421 |
+ /* plot user knots */ |
|
422 |
+ if (comp_points[i]) { |
|
423 |
+ const struct keypoint *point = comp_points[i]; |
|
424 |
+ |
|
425 |
+ while (point) { |
|
426 |
+ av_bprintf(&buf, "%f %f\n", point->x, point->y); |
|
427 |
+ point = point->next; |
|
428 |
+ } |
|
429 |
+ av_bprintf(&buf, "e\n"); |
|
430 |
+ } |
|
431 |
+ } |
|
432 |
+ |
|
433 |
+ fwrite(buf.str, 1, buf.len, f); |
|
434 |
+ fclose(f); |
|
435 |
+ av_bprint_finalize(&buf, NULL); |
|
436 |
+ return 0; |
|
437 |
+} |
|
438 |
+ |
|
380 | 439 |
static av_cold int init(AVFilterContext *ctx) |
381 | 440 |
{ |
382 | 441 |
int i, j, ret; |
... | ... |
@@ -448,6 +509,9 @@ static av_cold int init(AVFilterContext *ctx) |
448 | 448 |
} |
449 | 449 |
} |
450 | 450 |
|
451 |
+ if (curves->plot_filename) |
|
452 |
+ dump_curves(curves->plot_filename, curves->graph, comp_points); |
|
453 |
+ |
|
451 | 454 |
for (i = 0; i < NB_COMP + 1; i++) { |
452 | 455 |
struct keypoint *point = comp_points[i]; |
453 | 456 |
while (point) { |