Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
Michael Niedermayer authored on 2013/04/23 22:46:51... | ... |
@@ -35,10 +35,11 @@ |
35 | 35 |
typedef struct { |
36 | 36 |
const AVClass *class; |
37 | 37 |
AVExpr *e[4]; ///< expressions for each plane |
38 |
- char *expr_str[4]; ///< expression strings for each plane |
|
38 |
+ char *expr_str[4+3]; ///< expression strings for each plane |
|
39 | 39 |
AVFrame *picref; ///< current input buffer |
40 | 40 |
int hsub, vsub; ///< chroma subsampling |
41 | 41 |
int planes; ///< number of planes |
42 |
+ int is_rgb; |
|
42 | 43 |
} GEQContext; |
43 | 44 |
|
44 | 45 |
#define OFFSET(x) offsetof(GEQContext, x) |
... | ... |
@@ -49,6 +50,10 @@ static const AVOption geq_options[] = { |
49 | 49 |
{ "cb_expr", "set chroma blue expression", OFFSET(expr_str[1]), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS }, |
50 | 50 |
{ "cr_expr", "set chroma red expression", OFFSET(expr_str[2]), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS }, |
51 | 51 |
{ "alpha_expr", "set alpha expression", OFFSET(expr_str[3]), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS }, |
52 |
+ |
|
53 |
+ { "r", "set red expression", OFFSET(expr_str[6]), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS }, |
|
54 |
+ { "g", "set green expression", OFFSET(expr_str[4]), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS }, |
|
55 |
+ { "b", "set blue expression", OFFSET(expr_str[5]), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS }, |
|
52 | 56 |
{NULL}, |
53 | 57 |
}; |
54 | 58 |
|
... | ... |
@@ -92,8 +97,15 @@ static av_cold int geq_init(AVFilterContext *ctx) |
92 | 92 |
GEQContext *geq = ctx->priv; |
93 | 93 |
int plane, ret = 0; |
94 | 94 |
|
95 |
- if (!geq->expr_str[0]) { |
|
96 |
- av_log(ctx, AV_LOG_ERROR, "Luminance expression is mandatory\n"); |
|
95 |
+ if (!geq->expr_str[0] && !geq->expr_str[4] && !geq->expr_str[5] && !geq->expr_str[6]) { |
|
96 |
+ av_log(ctx, AV_LOG_ERROR, "A luminance or RGB expression is mandatory\n"); |
|
97 |
+ ret = AVERROR(EINVAL); |
|
98 |
+ goto end; |
|
99 |
+ } |
|
100 |
+ geq->is_rgb = !geq->expr_str[0]; |
|
101 |
+ |
|
102 |
+ if ((geq->expr_str[0] || geq->expr_str[1] || geq->expr_str[2]) && (geq->expr_str[4] || geq->expr_str[5] || geq->expr_str[6])) { |
|
103 |
+ av_log(ctx, AV_LOG_ERROR, "Either YCbCr or RGB but not both must be specified\n"); |
|
97 | 104 |
ret = AVERROR(EINVAL); |
98 | 105 |
goto end; |
99 | 106 |
} |
... | ... |
@@ -110,18 +122,29 @@ static av_cold int geq_init(AVFilterContext *ctx) |
110 | 110 |
|
111 | 111 |
if (!geq->expr_str[3]) |
112 | 112 |
geq->expr_str[3] = av_strdup("255"); |
113 |
- |
|
114 |
- if (!geq->expr_str[1] || !geq->expr_str[2] || !geq->expr_str[3]) { |
|
113 |
+ if (!geq->expr_str[4]) |
|
114 |
+ geq->expr_str[4] = av_strdup("g(X,Y)"); |
|
115 |
+ if (!geq->expr_str[5]) |
|
116 |
+ geq->expr_str[5] = av_strdup("b(X,Y)"); |
|
117 |
+ if (!geq->expr_str[6]) |
|
118 |
+ geq->expr_str[6] = av_strdup("r(X,Y)"); |
|
119 |
+ |
|
120 |
+ if (geq->is_rgb ? |
|
121 |
+ (!geq->expr_str[4] || !geq->expr_str[5] || !geq->expr_str[6]) |
|
122 |
+ : |
|
123 |
+ (!geq->expr_str[1] || !geq->expr_str[2] || !geq->expr_str[3])) { |
|
115 | 124 |
ret = AVERROR(ENOMEM); |
116 | 125 |
goto end; |
117 | 126 |
} |
118 | 127 |
|
119 | 128 |
for (plane = 0; plane < 4; plane++) { |
120 | 129 |
static double (*p[])(void *, double, double) = { lum, cb, cr, alpha }; |
121 |
- static const char *const func2_names[] = { "lum", "cb", "cr", "alpha", "p", NULL }; |
|
130 |
+ static const char *const func2_yuv_names[] = { "lum", "cb", "cr", "alpha", "p", NULL }; |
|
131 |
+ static const char *const func2_rgb_names[] = { "g", "b", "r", "alpha", "p", NULL }; |
|
132 |
+ const char *const *func2_names = geq->is_rgb ? func2_rgb_names : func2_yuv_names; |
|
122 | 133 |
double (*func2[])(void *, double, double) = { lum, cb, cr, alpha, p[plane], NULL }; |
123 | 134 |
|
124 |
- ret = av_expr_parse(&geq->e[plane], geq->expr_str[plane], var_names, |
|
135 |
+ ret = av_expr_parse(&geq->e[plane], geq->expr_str[plane < 3 && geq->is_rgb ? plane+4 : plane], var_names, |
|
125 | 136 |
NULL, NULL, func2_names, func2, 0, ctx); |
126 | 137 |
if (ret < 0) |
127 | 138 |
break; |
... | ... |
@@ -133,14 +156,22 @@ end: |
133 | 133 |
|
134 | 134 |
static int geq_query_formats(AVFilterContext *ctx) |
135 | 135 |
{ |
136 |
- static const enum PixelFormat pix_fmts[] = { |
|
136 |
+ GEQContext *geq = ctx->priv; |
|
137 |
+ static const enum PixelFormat yuv_pix_fmts[] = { |
|
137 | 138 |
AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P, |
138 | 139 |
AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV440P, |
139 | 140 |
AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA420P, |
140 | 141 |
AV_PIX_FMT_GRAY8, |
141 | 142 |
AV_PIX_FMT_NONE |
142 | 143 |
}; |
143 |
- ff_set_common_formats(ctx, ff_make_format_list(pix_fmts)); |
|
144 |
+ static const enum PixelFormat rgb_pix_fmts[] = { |
|
145 |
+ AV_PIX_FMT_GBRP, |
|
146 |
+ AV_PIX_FMT_NONE |
|
147 |
+ }; |
|
148 |
+ if (geq->is_rgb) { |
|
149 |
+ ff_set_common_formats(ctx, ff_make_format_list(rgb_pix_fmts)); |
|
150 |
+ } else |
|
151 |
+ ff_set_common_formats(ctx, ff_make_format_list(yuv_pix_fmts)); |
|
144 | 152 |
return 0; |
145 | 153 |
} |
146 | 154 |
|