Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
F
ffmpeg.wasm-core
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Linshizhi
ffmpeg.wasm-core
Commits
c4cda4eb
Commit
c4cda4eb
authored
Aug 23, 2018
by
Paul B Mahol
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
avfilter: add lut1d filter
parent
037b3bd1
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
483 additions
and
1 deletion
+483
-1
Changelog
Changelog
+1
-0
filters.texi
doc/filters.texi
+31
-0
Makefile
libavfilter/Makefile
+1
-0
allfilters.c
libavfilter/allfilters.c
+1
-0
version.h
libavfilter/version.h
+1
-1
vf_lut3d.c
libavfilter/vf_lut3d.c
+448
-0
No files found.
Changelog
View file @
c4cda4eb
...
...
@@ -21,6 +21,7 @@ version <next>:
- Brooktree ProSumer video decoder
- MatchWare Screen Capture Codec decoder
- WinCam Motion Video decoder
- 1D LUT filter (lut1d)
version 4.0:
...
...
doc/filters.texi
View file @
c4cda4eb
...
...
@@ -10962,6 +10962,37 @@ Set maximal size in number of frames. Default is 0.
Set first frame of loop. Default is 0.
@end table
@section lut1d
Apply a 1D LUT to an input video.
The filter accepts the following options:
@table @option
@item file
Set the 1D LUT file name.
Currently supported formats:
@table @samp
@item cube
Iridas
@end table
@item interp
Select interpolation mode.
Available values are:
@table @samp
@item nearest
Use values from the nearest defined point.
@item linear
Interpolate values using the linear interpolation.
@item cubic
Interpolate values using the cubic interpolation.
@end table
@end table
@anchor{lut3d}
@section lut3d
...
...
libavfilter/Makefile
View file @
c4cda4eb
...
...
@@ -258,6 +258,7 @@ OBJS-$(CONFIG_LIBVMAF_FILTER) += vf_libvmaf.o framesync.o
OBJS-$(CONFIG_LIMITER_FILTER)
+=
vf_limiter.o
OBJS-$(CONFIG_LOOP_FILTER)
+=
f_loop.o
OBJS-$(CONFIG_LUMAKEY_FILTER)
+=
vf_lumakey.o
OBJS-$(CONFIG_LUT1D_FILTER)
+=
vf_lut3d.o
OBJS-$(CONFIG_LUT_FILTER)
+=
vf_lut.o
OBJS-$(CONFIG_LUT2_FILTER)
+=
vf_lut2.o
framesync.o
OBJS-$(CONFIG_LUT3D_FILTER)
+=
vf_lut3d.o
...
...
libavfilter/allfilters.c
View file @
c4cda4eb
...
...
@@ -246,6 +246,7 @@ extern AVFilter ff_vf_limiter;
extern
AVFilter
ff_vf_loop
;
extern
AVFilter
ff_vf_lumakey
;
extern
AVFilter
ff_vf_lut
;
extern
AVFilter
ff_vf_lut1d
;
extern
AVFilter
ff_vf_lut2
;
extern
AVFilter
ff_vf_lut3d
;
extern
AVFilter
ff_vf_lutrgb
;
...
...
libavfilter/version.h
View file @
c4cda4eb
...
...
@@ -30,7 +30,7 @@
#include "libavutil/version.h"
#define LIBAVFILTER_VERSION_MAJOR 7
#define LIBAVFILTER_VERSION_MINOR 2
6
#define LIBAVFILTER_VERSION_MINOR 2
7
#define LIBAVFILTER_VERSION_MICRO 100
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
...
...
libavfilter/vf_lut3d.c
View file @
c4cda4eb
/*
* Copyright (c) 2013 Clément Bœsch
* Copyright (c) 2018 Paul B Mahol
*
* This file is part of FFmpeg.
*
...
...
@@ -975,3 +976,450 @@ AVFilter ff_vf_haldclut = {
.
flags
=
AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL
|
AVFILTER_FLAG_SLICE_THREADS
,
};
#endif
#if CONFIG_LUT1D_FILTER
enum
interp_1d_mode
{
INTERPOLATE_1D_NEAREST
,
INTERPOLATE_1D_LINEAR
,
INTERPOLATE_1D_CUBIC
,
NB_INTERP_1D_MODE
};
#define MAX_1D_LEVEL 65536
typedef
struct
LUT1DContext
{
const
AVClass
*
class
;
char
*
file
;
int
interpolation
;
///<interp_1d_mode
uint8_t
rgba_map
[
4
];
int
step
;
float
lut
[
3
][
MAX_1D_LEVEL
];
int
lutsize
;
avfilter_action_func
*
interp
;
}
LUT1DContext
;
#undef OFFSET
#define OFFSET(x) offsetof(LUT1DContext, x)
static
void
set_identity_matrix_1d
(
LUT1DContext
*
lut1d
,
int
size
)
{
const
float
c
=
1
.
/
(
size
-
1
);
int
i
;
lut1d
->
lutsize
=
size
;
for
(
i
=
0
;
i
<
size
;
i
++
)
{
lut1d
->
lut
[
0
][
i
]
=
i
*
c
;
lut1d
->
lut
[
1
][
i
]
=
i
*
c
;
lut1d
->
lut
[
2
][
i
]
=
i
*
c
;
}
}
static
int
parse_cube_1d
(
AVFilterContext
*
ctx
,
FILE
*
f
)
{
LUT1DContext
*
lut1d
=
ctx
->
priv
;
char
line
[
MAX_LINE_SIZE
];
float
min
[
3
]
=
{
0
.
0
,
0
.
0
,
0
.
0
};
float
max
[
3
]
=
{
1
.
0
,
1
.
0
,
1
.
0
};
while
(
fgets
(
line
,
sizeof
(
line
),
f
))
{
if
(
!
strncmp
(
line
,
"LUT_1D_SIZE "
,
12
))
{
const
int
size
=
strtol
(
line
+
12
,
NULL
,
0
);
int
i
;
if
(
size
<
2
||
size
>
MAX_1D_LEVEL
)
{
av_log
(
ctx
,
AV_LOG_ERROR
,
"Too large or invalid 1D LUT size
\n
"
);
return
AVERROR
(
EINVAL
);
}
lut1d
->
lutsize
=
size
;
for
(
i
=
0
;
i
<
size
;
i
++
)
{
do
{
try_again:
NEXT_LINE
(
0
);
if
(
!
strncmp
(
line
,
"DOMAIN_"
,
7
))
{
float
*
vals
=
NULL
;
if
(
!
strncmp
(
line
+
7
,
"MIN "
,
4
))
vals
=
min
;
else
if
(
!
strncmp
(
line
+
7
,
"MAX "
,
4
))
vals
=
max
;
if
(
!
vals
)
return
AVERROR_INVALIDDATA
;
sscanf
(
line
+
11
,
"%f %f %f"
,
vals
,
vals
+
1
,
vals
+
2
);
av_log
(
ctx
,
AV_LOG_DEBUG
,
"min: %f %f %f | max: %f %f %f
\n
"
,
min
[
0
],
min
[
1
],
min
[
2
],
max
[
0
],
max
[
1
],
max
[
2
]);
goto
try_again
;
}
else
if
(
!
strncmp
(
line
,
"LUT_1D_INPUT_RANGE "
,
19
))
{
sscanf
(
line
+
19
,
"%f %f"
,
min
,
max
);
min
[
1
]
=
min
[
2
]
=
min
[
0
];
max
[
1
]
=
max
[
2
]
=
max
[
0
];
goto
try_again
;
}
}
while
(
skip_line
(
line
));
if
(
sscanf
(
line
,
"%f %f %f"
,
&
lut1d
->
lut
[
0
][
i
],
&
lut1d
->
lut
[
1
][
i
],
&
lut1d
->
lut
[
2
][
i
])
!=
3
)
return
AVERROR_INVALIDDATA
;
lut1d
->
lut
[
0
][
i
]
*=
max
[
0
]
-
min
[
0
];
lut1d
->
lut
[
1
][
i
]
*=
max
[
1
]
-
min
[
1
];
lut1d
->
lut
[
2
][
i
]
*=
max
[
2
]
-
min
[
2
];
}
break
;
}
}
return
0
;
}
static
const
AVOption
lut1d_options
[]
=
{
{
"file"
,
"set 1D LUT file name"
,
OFFSET
(
file
),
AV_OPT_TYPE_STRING
,
{.
str
=
NULL
},
.
flags
=
FLAGS
},
{
"interp"
,
"select interpolation mode"
,
OFFSET
(
interpolation
),
AV_OPT_TYPE_INT
,
{.
i64
=
INTERPOLATE_1D_LINEAR
},
0
,
NB_INTERP_1D_MODE
-
1
,
FLAGS
,
"interp_mode"
},
{
"nearest"
,
"use values from the nearest defined points"
,
0
,
AV_OPT_TYPE_CONST
,
{.
i64
=
INTERPOLATE_1D_NEAREST
},
INT_MIN
,
INT_MAX
,
FLAGS
,
"interp_mode"
},
{
"linear"
,
"use values from the linear interpolation"
,
0
,
AV_OPT_TYPE_CONST
,
{.
i64
=
INTERPOLATE_1D_LINEAR
},
INT_MIN
,
INT_MAX
,
FLAGS
,
"interp_mode"
},
{
"cubic"
,
"use values from the cubic interpolation"
,
0
,
AV_OPT_TYPE_CONST
,
{.
i64
=
INTERPOLATE_1D_CUBIC
},
INT_MIN
,
INT_MAX
,
FLAGS
,
"interp_mode"
},
{
NULL
}
};
AVFILTER_DEFINE_CLASS
(
lut1d
);
static
inline
float
interp_1d_nearest
(
const
LUT1DContext
*
lut1d
,
int
idx
,
const
float
s
)
{
return
lut1d
->
lut
[
idx
][
NEAR
(
s
)];
}
#define NEXT1D(x) (FFMIN((int)(x) + 1, lut1d->lutsize - 1))
static
inline
float
interp_1d_linear
(
const
LUT1DContext
*
lut1d
,
int
idx
,
const
float
s
)
{
const
int
prev
=
PREV
(
s
);
const
int
next
=
NEXT1D
(
s
);
const
float
d
=
s
-
prev
;
const
float
p
=
lut1d
->
lut
[
idx
][
prev
];
const
float
n
=
lut1d
->
lut
[
idx
][
next
];
return
lerpf
(
p
,
n
,
d
);
}
static
inline
float
interp_1d_cubic
(
const
LUT1DContext
*
lut1d
,
int
idx
,
const
float
s
)
{
const
int
prev
=
PREV
(
s
);
const
int
next
=
NEXT1D
(
s
);
const
float
mu
=
s
-
prev
;
float
a0
,
a1
,
a2
,
a3
,
mu2
;
float
y0
=
lut1d
->
lut
[
idx
][
FFMAX
(
prev
-
1
,
0
)];
float
y1
=
lut1d
->
lut
[
idx
][
prev
];
float
y2
=
lut1d
->
lut
[
idx
][
next
];
float
y3
=
lut1d
->
lut
[
idx
][
FFMIN
(
next
+
1
,
lut1d
->
lutsize
-
1
)];
mu2
=
mu
*
mu
;
a0
=
y3
-
y2
-
y0
+
y1
;
a1
=
y0
-
y1
-
a0
;
a2
=
y2
-
y0
;
a3
=
y1
;
return
a0
*
mu
*
mu2
+
a1
*
mu2
+
a2
*
mu
+
a3
;
}
#define DEFINE_INTERP_FUNC_PLANAR_1D(name, nbits, depth) \
static int interp_1d_##nbits##_##name##_p##depth(AVFilterContext *ctx, \
void *arg, int jobnr, \
int nb_jobs) \
{ \
int x, y; \
const LUT1DContext *lut1d = ctx->priv; \
const ThreadData *td = arg; \
const AVFrame *in = td->in; \
const AVFrame *out = td->out; \
const int direct = out == in; \
const int slice_start = (in->height * jobnr ) / nb_jobs; \
const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
uint8_t *grow = out->data[0] + slice_start * out->linesize[0]; \
uint8_t *brow = out->data[1] + slice_start * out->linesize[1]; \
uint8_t *rrow = out->data[2] + slice_start * out->linesize[2]; \
uint8_t *arow = out->data[3] + slice_start * out->linesize[3]; \
const uint8_t *srcgrow = in->data[0] + slice_start * in->linesize[0]; \
const uint8_t *srcbrow = in->data[1] + slice_start * in->linesize[1]; \
const uint8_t *srcrrow = in->data[2] + slice_start * in->linesize[2]; \
const uint8_t *srcarow = in->data[3] + slice_start * in->linesize[3]; \
const float factor = (1 << depth) - 1; \
const float scale = (1. / factor) * (lut1d->lutsize - 1); \
\
for (y = slice_start; y < slice_end; y++) { \
uint##nbits##_t *dstg = (uint##nbits##_t *)grow; \
uint##nbits##_t *dstb = (uint##nbits##_t *)brow; \
uint##nbits##_t *dstr = (uint##nbits##_t *)rrow; \
uint##nbits##_t *dsta = (uint##nbits##_t *)arow; \
const uint##nbits##_t *srcg = (const uint##nbits##_t *)srcgrow; \
const uint##nbits##_t *srcb = (const uint##nbits##_t *)srcbrow; \
const uint##nbits##_t *srcr = (const uint##nbits##_t *)srcrrow; \
const uint##nbits##_t *srca = (const uint##nbits##_t *)srcarow; \
for (x = 0; x < in->width; x++) { \
float r = srcr[x] * scale; \
float g = srcg[x] * scale; \
float b = srcb[x] * scale; \
r = interp_1d_##name(lut1d, 0, r); \
g = interp_1d_##name(lut1d, 1, g); \
b = interp_1d_##name(lut1d, 2, b); \
dstr[x] = av_clip_uintp2(r * factor, depth); \
dstg[x] = av_clip_uintp2(g * factor, depth); \
dstb[x] = av_clip_uintp2(b * factor, depth); \
if (!direct && in->linesize[3]) \
dsta[x] = srca[x]; \
} \
grow += out->linesize[0]; \
brow += out->linesize[1]; \
rrow += out->linesize[2]; \
arow += out->linesize[3]; \
srcgrow += in->linesize[0]; \
srcbrow += in->linesize[1]; \
srcrrow += in->linesize[2]; \
srcarow += in->linesize[3]; \
} \
return 0; \
}
DEFINE_INTERP_FUNC_PLANAR_1D
(
nearest
,
8
,
8
)
DEFINE_INTERP_FUNC_PLANAR_1D
(
linear
,
8
,
8
)
DEFINE_INTERP_FUNC_PLANAR_1D
(
cubic
,
8
,
8
)
DEFINE_INTERP_FUNC_PLANAR_1D
(
nearest
,
16
,
9
)
DEFINE_INTERP_FUNC_PLANAR_1D
(
linear
,
16
,
9
)
DEFINE_INTERP_FUNC_PLANAR_1D
(
cubic
,
16
,
9
)
DEFINE_INTERP_FUNC_PLANAR_1D
(
nearest
,
16
,
10
)
DEFINE_INTERP_FUNC_PLANAR_1D
(
linear
,
16
,
10
)
DEFINE_INTERP_FUNC_PLANAR_1D
(
cubic
,
16
,
10
)
DEFINE_INTERP_FUNC_PLANAR_1D
(
nearest
,
16
,
12
)
DEFINE_INTERP_FUNC_PLANAR_1D
(
linear
,
16
,
12
)
DEFINE_INTERP_FUNC_PLANAR_1D
(
cubic
,
16
,
12
)
DEFINE_INTERP_FUNC_PLANAR_1D
(
nearest
,
16
,
14
)
DEFINE_INTERP_FUNC_PLANAR_1D
(
linear
,
16
,
14
)
DEFINE_INTERP_FUNC_PLANAR_1D
(
cubic
,
16
,
14
)
DEFINE_INTERP_FUNC_PLANAR_1D
(
nearest
,
16
,
16
)
DEFINE_INTERP_FUNC_PLANAR_1D
(
linear
,
16
,
16
)
DEFINE_INTERP_FUNC_PLANAR_1D
(
cubic
,
16
,
16
)
#define DEFINE_INTERP_FUNC_1D(name, nbits) \
static int interp_1d_##nbits##_##name(AVFilterContext *ctx, void *arg, \
int jobnr, int nb_jobs) \
{ \
int x, y; \
const LUT1DContext *lut1d = ctx->priv; \
const ThreadData *td = arg; \
const AVFrame *in = td->in; \
const AVFrame *out = td->out; \
const int direct = out == in; \
const int step = lut1d->step; \
const uint8_t r = lut1d->rgba_map[R]; \
const uint8_t g = lut1d->rgba_map[G]; \
const uint8_t b = lut1d->rgba_map[B]; \
const uint8_t a = lut1d->rgba_map[A]; \
const int slice_start = (in->height * jobnr ) / nb_jobs; \
const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
uint8_t *dstrow = out->data[0] + slice_start * out->linesize[0]; \
const uint8_t *srcrow = in ->data[0] + slice_start * in ->linesize[0]; \
const float factor = (1 << nbits) - 1; \
const float scale = (1. / factor) * (lut1d->lutsize - 1); \
\
for (y = slice_start; y < slice_end; y++) { \
uint##nbits##_t *dst = (uint##nbits##_t *)dstrow; \
const uint##nbits##_t *src = (const uint##nbits##_t *)srcrow; \
for (x = 0; x < in->width * step; x += step) { \
float rr = src[x + r] * scale; \
float gg = src[x + g] * scale; \
float bb = src[x + b] * scale; \
rr = interp_1d_##name(lut1d, 0, rr); \
gg = interp_1d_##name(lut1d, 1, gg); \
bb = interp_1d_##name(lut1d, 2, bb); \
dst[x + r] = av_clip_uint##nbits(rr * factor); \
dst[x + g] = av_clip_uint##nbits(gg * factor); \
dst[x + b] = av_clip_uint##nbits(bb * factor); \
if (!direct && step == 4) \
dst[x + a] = src[x + a]; \
} \
dstrow += out->linesize[0]; \
srcrow += in ->linesize[0]; \
} \
return 0; \
}
DEFINE_INTERP_FUNC_1D
(
nearest
,
8
)
DEFINE_INTERP_FUNC_1D
(
linear
,
8
)
DEFINE_INTERP_FUNC_1D
(
cubic
,
8
)
DEFINE_INTERP_FUNC_1D
(
nearest
,
16
)
DEFINE_INTERP_FUNC_1D
(
linear
,
16
)
DEFINE_INTERP_FUNC_1D
(
cubic
,
16
)
static
int
config_input_1d
(
AVFilterLink
*
inlink
)
{
int
depth
,
is16bit
=
0
,
planar
=
0
;
LUT1DContext
*
lut1d
=
inlink
->
dst
->
priv
;
const
AVPixFmtDescriptor
*
desc
=
av_pix_fmt_desc_get
(
inlink
->
format
);
depth
=
desc
->
comp
[
0
].
depth
;
switch
(
inlink
->
format
)
{
case
AV_PIX_FMT_RGB48
:
case
AV_PIX_FMT_BGR48
:
case
AV_PIX_FMT_RGBA64
:
case
AV_PIX_FMT_BGRA64
:
is16bit
=
1
;
break
;
case
AV_PIX_FMT_GBRP9
:
case
AV_PIX_FMT_GBRP10
:
case
AV_PIX_FMT_GBRP12
:
case
AV_PIX_FMT_GBRP14
:
case
AV_PIX_FMT_GBRP16
:
case
AV_PIX_FMT_GBRAP10
:
case
AV_PIX_FMT_GBRAP12
:
case
AV_PIX_FMT_GBRAP16
:
is16bit
=
1
;
case
AV_PIX_FMT_GBRP
:
case
AV_PIX_FMT_GBRAP
:
planar
=
1
;
break
;
}
ff_fill_rgba_map
(
lut1d
->
rgba_map
,
inlink
->
format
);
lut1d
->
step
=
av_get_padded_bits_per_pixel
(
desc
)
>>
(
3
+
is16bit
);
#define SET_FUNC_1D(name) do { \
if (planar) { \
switch (depth) { \
case 8: lut1d->interp = interp_1d_8_##name##_p8; break; \
case 9: lut1d->interp = interp_1d_16_##name##_p9; break; \
case 10: lut1d->interp = interp_1d_16_##name##_p10; break; \
case 12: lut1d->interp = interp_1d_16_##name##_p12; break; \
case 14: lut1d->interp = interp_1d_16_##name##_p14; break; \
case 16: lut1d->interp = interp_1d_16_##name##_p16; break; \
} \
} else if (is16bit) { lut1d->interp = interp_1d_16_##name; \
} else { lut1d->interp = interp_1d_8_##name; } \
} while (0)
switch
(
lut1d
->
interpolation
)
{
case
INTERPOLATE_1D_NEAREST
:
SET_FUNC_1D
(
nearest
);
break
;
case
INTERPOLATE_1D_LINEAR
:
SET_FUNC_1D
(
linear
);
break
;
case
INTERPOLATE_1D_CUBIC
:
SET_FUNC_1D
(
cubic
);
break
;
default
:
av_assert0
(
0
);
}
return
0
;
}
static
av_cold
int
lut1d_init
(
AVFilterContext
*
ctx
)
{
int
ret
;
FILE
*
f
;
const
char
*
ext
;
LUT1DContext
*
lut1d
=
ctx
->
priv
;
if
(
!
lut1d
->
file
)
{
set_identity_matrix_1d
(
lut1d
,
32
);
return
0
;
}
f
=
fopen
(
lut1d
->
file
,
"r"
);
if
(
!
f
)
{
ret
=
AVERROR
(
errno
);
av_log
(
ctx
,
AV_LOG_ERROR
,
"%s: %s
\n
"
,
lut1d
->
file
,
av_err2str
(
ret
));
return
ret
;
}
ext
=
strrchr
(
lut1d
->
file
,
'.'
);
if
(
!
ext
)
{
av_log
(
ctx
,
AV_LOG_ERROR
,
"Unable to guess the format from the extension
\n
"
);
ret
=
AVERROR_INVALIDDATA
;
goto
end
;
}
ext
++
;
if
(
!
av_strcasecmp
(
ext
,
"cube"
)
||
!
av_strcasecmp
(
ext
,
"1dlut"
))
{
ret
=
parse_cube_1d
(
ctx
,
f
);
}
else
{
av_log
(
ctx
,
AV_LOG_ERROR
,
"Unrecognized '.%s' file type
\n
"
,
ext
);
ret
=
AVERROR
(
EINVAL
);
}
if
(
!
ret
&&
!
lut1d
->
lutsize
)
{
av_log
(
ctx
,
AV_LOG_ERROR
,
"1D LUT is empty
\n
"
);
ret
=
AVERROR_INVALIDDATA
;
}
end
:
fclose
(
f
);
return
ret
;
}
static
AVFrame
*
apply_1d_lut
(
AVFilterLink
*
inlink
,
AVFrame
*
in
)
{
AVFilterContext
*
ctx
=
inlink
->
dst
;
LUT1DContext
*
lut1d
=
ctx
->
priv
;
AVFilterLink
*
outlink
=
inlink
->
dst
->
outputs
[
0
];
AVFrame
*
out
;
ThreadData
td
;
if
(
av_frame_is_writable
(
in
))
{
out
=
in
;
}
else
{
out
=
ff_get_video_buffer
(
outlink
,
outlink
->
w
,
outlink
->
h
);
if
(
!
out
)
{
av_frame_free
(
&
in
);
return
NULL
;
}
av_frame_copy_props
(
out
,
in
);
}
td
.
in
=
in
;
td
.
out
=
out
;
ctx
->
internal
->
execute
(
ctx
,
lut1d
->
interp
,
&
td
,
NULL
,
FFMIN
(
outlink
->
h
,
ff_filter_get_nb_threads
(
ctx
)));
if
(
out
!=
in
)
av_frame_free
(
&
in
);
return
out
;
}
static
int
filter_frame_1d
(
AVFilterLink
*
inlink
,
AVFrame
*
in
)
{
AVFilterLink
*
outlink
=
inlink
->
dst
->
outputs
[
0
];
AVFrame
*
out
=
apply_1d_lut
(
inlink
,
in
);
if
(
!
out
)
return
AVERROR
(
ENOMEM
);
return
ff_filter_frame
(
outlink
,
out
);
}
static
const
AVFilterPad
lut1d_inputs
[]
=
{
{
.
name
=
"default"
,
.
type
=
AVMEDIA_TYPE_VIDEO
,
.
filter_frame
=
filter_frame_1d
,
.
config_props
=
config_input_1d
,
},
{
NULL
}
};
static
const
AVFilterPad
lut1d_outputs
[]
=
{
{
.
name
=
"default"
,
.
type
=
AVMEDIA_TYPE_VIDEO
,
},
{
NULL
}
};
AVFilter
ff_vf_lut1d
=
{
.
name
=
"lut1d"
,
.
description
=
NULL_IF_CONFIG_SMALL
(
"Adjust colors using a 1D LUT."
),
.
priv_size
=
sizeof
(
LUT1DContext
),
.
init
=
lut1d_init
,
.
query_formats
=
query_formats
,
.
inputs
=
lut1d_inputs
,
.
outputs
=
lut1d_outputs
,
.
priv_class
=
&
lut1d_class
,
.
flags
=
AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC
|
AVFILTER_FLAG_SLICE_THREADS
,
};
#endif
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment