lavfi: new colorspace conversion filter.
The intent here is similar to colormatrix, but it's LGPLv2.1-or-later (instead of GPLv2.0) and supports gamma/chromaticity correction.
This commit is contained in:
parent
d7815df402
commit
2e2e08a35b
@ -23,6 +23,7 @@ version <next>:
|
||||
- aix demuxer
|
||||
- remap filter
|
||||
- hash and framehash muxers
|
||||
- colorspace filter
|
||||
|
||||
version 3.0:
|
||||
- Common Encryption (CENC) MP4 encoding and decoding support
|
||||
|
183
doc/filters.texi
183
doc/filters.texi
@ -4937,6 +4937,189 @@ For example to convert from BT.601 to SMPTE-240M, use the command:
|
||||
colormatrix=bt601:smpte240m
|
||||
@end example
|
||||
|
||||
@section colorspace
|
||||
|
||||
Convert colorspace, transfer characteristics or color primaries.
|
||||
|
||||
The filter accepts the following options:
|
||||
|
||||
@table @option
|
||||
@item all
|
||||
Specify all color properties at once.
|
||||
|
||||
The accepted values are:
|
||||
@table @samp
|
||||
@item bt470m
|
||||
BT.470M
|
||||
|
||||
@item bt470bg
|
||||
BT.470BG
|
||||
|
||||
@item bt601-6-525
|
||||
BT.601-6 525
|
||||
|
||||
@item bt601-6-625
|
||||
BT.601-6 625
|
||||
|
||||
@item bt709
|
||||
BT.709
|
||||
|
||||
@item smpte170m
|
||||
SMPTE-170M
|
||||
|
||||
@item smpte240m
|
||||
SMPTE-240M
|
||||
|
||||
@item bt2020
|
||||
BT.2020
|
||||
|
||||
@end table
|
||||
|
||||
@item space
|
||||
Specify output colorspace.
|
||||
|
||||
The accepted values are:
|
||||
@table @samp
|
||||
@item bt709
|
||||
BT.709
|
||||
|
||||
@item fcc
|
||||
FCC
|
||||
|
||||
@item bt470bg
|
||||
BT.470BG or BT.601-6 625
|
||||
|
||||
@item smpte170m
|
||||
SMPTE-170M or BT.601-6 525
|
||||
|
||||
@item smpte240m
|
||||
SMPTE-240M
|
||||
|
||||
@item bt2020ncl
|
||||
BT.2020 with non-constant luminance
|
||||
|
||||
@end table
|
||||
|
||||
@item trc
|
||||
Specify output transfer characteristics.
|
||||
|
||||
The accepted values are:
|
||||
@table @samp
|
||||
@item bt709
|
||||
BT.709
|
||||
|
||||
@item gamma22
|
||||
Constant gamma of 2.2
|
||||
|
||||
@item gamma28
|
||||
Constant gamma of 2.8
|
||||
|
||||
@item smpte170m
|
||||
SMPTE-170M, BT.601-6 625 or BT.601-6 525
|
||||
|
||||
@item smpte240m
|
||||
SMPTE-240M
|
||||
|
||||
@item bt2020-10
|
||||
BT.2020 for 10-bits content
|
||||
|
||||
@item bt2020-12
|
||||
BT.2020 for 12-bits content
|
||||
|
||||
@end table
|
||||
|
||||
@item prm
|
||||
Specify output color primaries.
|
||||
|
||||
The accepted values are:
|
||||
@table @samp
|
||||
@item bt709
|
||||
BT.709
|
||||
|
||||
@item bt470m
|
||||
BT.470M
|
||||
|
||||
@item bt470bg
|
||||
BT.470BG or BT.601-6 625
|
||||
|
||||
@item smpte170m
|
||||
SMPTE-170M or BT.601-6 525
|
||||
|
||||
@item smpte240m
|
||||
SMPTE-240M
|
||||
|
||||
@item bt2020
|
||||
BT.2020
|
||||
|
||||
@end table
|
||||
|
||||
@item rng
|
||||
Specify output color range.
|
||||
|
||||
The accepted values are:
|
||||
@table @samp
|
||||
@item mpeg
|
||||
MPEG (restricted) range
|
||||
|
||||
@item jpeg
|
||||
JPEG (full) range
|
||||
|
||||
@end table
|
||||
|
||||
@item format
|
||||
Specify output color format.
|
||||
|
||||
The accepted values are:
|
||||
@table @samp
|
||||
@item yuv420p
|
||||
YUV 4:2:0 planar 8-bits
|
||||
|
||||
@item yuv420p10
|
||||
YUV 4:2:0 planar 10-bits
|
||||
|
||||
@item yuv420p12
|
||||
YUV 4:2:0 planar 12-bits
|
||||
|
||||
@item yuv422p
|
||||
YUV 4:2:2 planar 8-bits
|
||||
|
||||
@item yuv422p10
|
||||
YUV 4:2:2 planar 10-bits
|
||||
|
||||
@item yuv422p12
|
||||
YUV 4:2:2 planar 12-bits
|
||||
|
||||
@item yuv444p
|
||||
YUV 4:4:4 planar 8-bits
|
||||
|
||||
@item yuv444p10
|
||||
YUV 4:4:4 planar 10-bits
|
||||
|
||||
@item yuv444p12
|
||||
YUV 4:4:4 planar 12-bits
|
||||
|
||||
@end table
|
||||
|
||||
@item fast
|
||||
Do a fast conversion, which skips gamma/primary correction. This will take
|
||||
significantly less CPU, but will be mathematically incorrect. To get output
|
||||
compatible with that produced by the colormatrix filter, use fast=1.
|
||||
@end table
|
||||
|
||||
The filter converts the transfer characteristics, color space and color
|
||||
primaries to the specified user values. The output value, if not specified,
|
||||
is set to a default value based on the "all" property. If that property is
|
||||
also not specified, the filter will log an error. The output color range and
|
||||
format default to the same value as the input color range and format. The
|
||||
input transfer characteristics, color space, color primaries and color range
|
||||
should be set on the input data. If any of these are missing, the filter will
|
||||
log an error and no conversion will take place.
|
||||
|
||||
For example to convert the input to SMPTE-240M, use the command:
|
||||
@example
|
||||
colorspace=smpte240m
|
||||
@end example
|
||||
|
||||
@section convolution
|
||||
|
||||
Apply convolution 3x3 or 5x5 filter.
|
||||
|
@ -131,6 +131,7 @@ OBJS-$(CONFIG_COLORCHANNELMIXER_FILTER) += vf_colorchannelmixer.o
|
||||
OBJS-$(CONFIG_COLORKEY_FILTER) += vf_colorkey.o
|
||||
OBJS-$(CONFIG_COLORLEVELS_FILTER) += vf_colorlevels.o
|
||||
OBJS-$(CONFIG_COLORMATRIX_FILTER) += vf_colormatrix.o
|
||||
OBJS-$(CONFIG_COLORSPACE_FILTER) += vf_colorspace.o colorspacedsp.o
|
||||
OBJS-$(CONFIG_CONVOLUTION_FILTER) += vf_convolution.o
|
||||
OBJS-$(CONFIG_COPY_FILTER) += vf_copy.o
|
||||
OBJS-$(CONFIG_COREIMAGE_FILTER) += vf_coreimage.o
|
||||
|
@ -152,6 +152,7 @@ void avfilter_register_all(void)
|
||||
REGISTER_FILTER(COLORKEY, colorkey, vf);
|
||||
REGISTER_FILTER(COLORLEVELS, colorlevels, vf);
|
||||
REGISTER_FILTER(COLORMATRIX, colormatrix, vf);
|
||||
REGISTER_FILTER(COLORSPACE, colorspace, vf);
|
||||
REGISTER_FILTER(CONVOLUTION, convolution, vf);
|
||||
REGISTER_FILTER(COPY, copy, vf);
|
||||
REGISTER_FILTER(COREIMAGE, coreimage, vf);
|
||||
|
131
libavfilter/colorspacedsp.c
Normal file
131
libavfilter/colorspacedsp.c
Normal file
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Ronald S. Bultje <rsbultje@gmail.com>
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "colorspacedsp.h"
|
||||
|
||||
#define SS_W 0
|
||||
#define SS_H 0
|
||||
|
||||
#define BIT_DEPTH 8
|
||||
#include "colorspacedsp_template.c"
|
||||
|
||||
#undef BIT_DEPTH
|
||||
#define BIT_DEPTH 10
|
||||
#include "colorspacedsp_template.c"
|
||||
|
||||
#undef BIT_DEPTH
|
||||
#define BIT_DEPTH 12
|
||||
#include "colorspacedsp_template.c"
|
||||
|
||||
#undef SS_W
|
||||
#undef SS_H
|
||||
|
||||
#define SS_W 1
|
||||
#define SS_H 0
|
||||
|
||||
#undef BIT_DEPTH
|
||||
#define BIT_DEPTH 8
|
||||
#include "colorspacedsp_template.c"
|
||||
|
||||
#undef BIT_DEPTH
|
||||
#define BIT_DEPTH 10
|
||||
#include "colorspacedsp_template.c"
|
||||
|
||||
#undef BIT_DEPTH
|
||||
#define BIT_DEPTH 12
|
||||
#include "colorspacedsp_template.c"
|
||||
|
||||
#undef SS_W
|
||||
#undef SS_H
|
||||
|
||||
#define SS_W 1
|
||||
#define SS_H 1
|
||||
|
||||
#undef BIT_DEPTH
|
||||
#define BIT_DEPTH 8
|
||||
#include "colorspacedsp_template.c"
|
||||
|
||||
#undef BIT_DEPTH
|
||||
#define BIT_DEPTH 10
|
||||
#include "colorspacedsp_template.c"
|
||||
|
||||
#undef BIT_DEPTH
|
||||
#define BIT_DEPTH 12
|
||||
#include "colorspacedsp_template.c"
|
||||
|
||||
static void multiply3x3_c(int16_t *buf[3], ptrdiff_t stride,
|
||||
int w, int h, const int16_t m[3][3][8])
|
||||
{
|
||||
int y, x;
|
||||
int16_t *buf0 = buf[0], *buf1 = buf[1], *buf2 = buf[2];
|
||||
|
||||
for (y = 0; y < h; y++) {
|
||||
for (x = 0; x < w; x++) {
|
||||
int v0 = buf0[x], v1 = buf1[x], v2 = buf2[x];
|
||||
|
||||
buf0[x] = av_clip_int16((m[0][0][0] * v0 + m[0][1][0] * v1 +
|
||||
m[0][2][0] * v2 + 8192) >> 14);
|
||||
buf1[x] = av_clip_int16((m[1][0][0] * v0 + m[1][1][0] * v1 +
|
||||
m[1][2][0] * v2 + 8192) >> 14);
|
||||
buf2[x] = av_clip_int16((m[2][0][0] * v0 + m[2][1][0] * v1 +
|
||||
m[2][2][0] * v2 + 8192) >> 14);
|
||||
}
|
||||
|
||||
buf0 += stride;
|
||||
buf1 += stride;
|
||||
buf2 += stride;
|
||||
}
|
||||
}
|
||||
|
||||
void ff_colorspacedsp_init(ColorSpaceDSPContext *dsp)
|
||||
{
|
||||
#define init_yuv2rgb_fn(idx, bit) \
|
||||
dsp->yuv2rgb[idx][0] = yuv2rgb_444p##bit##_c; \
|
||||
dsp->yuv2rgb[idx][1] = yuv2rgb_422p##bit##_c; \
|
||||
dsp->yuv2rgb[idx][2] = yuv2rgb_420p##bit##_c
|
||||
|
||||
init_yuv2rgb_fn(0, 8);
|
||||
init_yuv2rgb_fn(1, 10);
|
||||
init_yuv2rgb_fn(2, 12);
|
||||
|
||||
#define init_rgb2yuv_fn(idx, bit) \
|
||||
dsp->rgb2yuv[idx][0] = rgb2yuv_444p##bit##_c; \
|
||||
dsp->rgb2yuv[idx][1] = rgb2yuv_422p##bit##_c; \
|
||||
dsp->rgb2yuv[idx][2] = rgb2yuv_420p##bit##_c
|
||||
|
||||
init_rgb2yuv_fn(0, 8);
|
||||
init_rgb2yuv_fn(1, 10);
|
||||
init_rgb2yuv_fn(2, 12);
|
||||
|
||||
#define init_yuv2yuv_fn(idx1, idx2, bit1, bit2) \
|
||||
dsp->yuv2yuv[idx1][idx2][0] = yuv2yuv_444p##bit1##to##bit2##_c; \
|
||||
dsp->yuv2yuv[idx1][idx2][1] = yuv2yuv_422p##bit1##to##bit2##_c; \
|
||||
dsp->yuv2yuv[idx1][idx2][2] = yuv2yuv_420p##bit1##to##bit2##_c
|
||||
#define init_yuv2yuv_fns(idx1, bit1) \
|
||||
init_yuv2yuv_fn(idx1, 0, bit1, 8); \
|
||||
init_yuv2yuv_fn(idx1, 1, bit1, 10); \
|
||||
init_yuv2yuv_fn(idx1, 2, bit1, 12)
|
||||
|
||||
init_yuv2yuv_fns(0, 8);
|
||||
init_yuv2yuv_fns(1, 10);
|
||||
init_yuv2yuv_fns(2, 12);
|
||||
|
||||
dsp->multiply3x3 = multiply3x3_c;
|
||||
}
|
51
libavfilter/colorspacedsp.h
Normal file
51
libavfilter/colorspacedsp.h
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Ronald S. Bultje <rsbultje@gmail.com>
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVFILTER_COLORSPACEDSP_H
|
||||
#define AVFILTER_COLORSPACEDSP_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef void (*yuv2rgb_fn)(int16_t *rgb[3], ptrdiff_t rgb_stride,
|
||||
uint8_t *yuv[3], ptrdiff_t yuv_stride[3],
|
||||
int w, int h, const int16_t yuv2rgb_coeffs[3][3][8],
|
||||
const int16_t yuv_offset[8]);
|
||||
typedef void (*rgb2yuv_fn)(uint8_t *yuv[3], ptrdiff_t yuv_stride[3],
|
||||
int16_t *rgb[3], ptrdiff_t rgb_stride,
|
||||
int w, int h, const int16_t rgb2yuv_coeffs[3][3][8],
|
||||
const int16_t yuv_offset[8]);
|
||||
typedef void (*yuv2yuv_fn)(uint8_t *yuv_out[3], ptrdiff_t yuv_out_stride[3],
|
||||
uint8_t *yuv_in[3], ptrdiff_t yuv_in_stride[3],
|
||||
int w, int h, const int16_t yuv2yuv_coeffs[3][3][8],
|
||||
const int16_t yuv_offset[2][8]);
|
||||
|
||||
typedef struct ColorSpaceDSPContext {
|
||||
yuv2rgb_fn yuv2rgb[3 /* 0: 8bit, 1: 10bit, 2: 12bit */][3 /* 0: 444, 1: 422, 2: 420 */];
|
||||
rgb2yuv_fn rgb2yuv[3 /* 0: 8bit, 1: 10bit, 2: 12bit */][3 /* 0: 444, 1: 422, 2: 420 */];
|
||||
yuv2yuv_fn yuv2yuv[3 /* in_depth */][3 /* out_depth */][3 /* 0: 444, 1: 422, 2: 420 */];
|
||||
|
||||
void (*multiply3x3)(int16_t *data[3], ptrdiff_t stride,
|
||||
int w, int h, const int16_t m[3][3][8]);
|
||||
} ColorSpaceDSPContext;
|
||||
|
||||
void ff_colorspacedsp_init(ColorSpaceDSPContext *dsp);
|
||||
|
||||
#endif /* AVFILTER_COLORSPACEDSP_H */
|
214
libavfilter/colorspacedsp_template.c
Normal file
214
libavfilter/colorspacedsp_template.c
Normal file
@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Ronald S. Bultje <rsbultje@gmail.com>
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "libavutil/avassert.h"
|
||||
|
||||
#undef avg
|
||||
#undef ss
|
||||
|
||||
#if SS_W == 0
|
||||
#define ss 444
|
||||
#define avg(a,b,c,d) (a)
|
||||
#elif SS_H == 0
|
||||
#define ss 422
|
||||
#define avg(a,b,c,d) ((a + b + 1) >> 1)
|
||||
#else
|
||||
#define ss 420
|
||||
#define avg(a,b,c,d) ((a + b + c + d + 2) >> 2)
|
||||
#endif
|
||||
|
||||
#undef fn
|
||||
#undef fn2
|
||||
#undef fn3
|
||||
#define fn3(a,b,c) a##_##c##p##b##_c
|
||||
#define fn2(a,b,c) fn3(a,b,c)
|
||||
#define fn(a) fn2(a, BIT_DEPTH, ss)
|
||||
|
||||
#undef pixel
|
||||
#undef av_clip_pixel
|
||||
#if BIT_DEPTH == 8
|
||||
#define pixel uint8_t
|
||||
#define av_clip_pixel(x) av_clip_uint8(x)
|
||||
#else
|
||||
#define pixel uint16_t
|
||||
#define av_clip_pixel(x) av_clip_uintp2(x, BIT_DEPTH)
|
||||
#endif
|
||||
|
||||
static void fn(yuv2rgb)(int16_t *rgb[3], ptrdiff_t rgb_stride,
|
||||
uint8_t *_yuv[3], ptrdiff_t yuv_stride[3],
|
||||
int w, int h, const int16_t yuv2rgb_coeffs[3][3][8],
|
||||
const int16_t yuv_offset[8])
|
||||
{
|
||||
pixel **yuv = (pixel **) _yuv;
|
||||
const pixel *yuv0 = yuv[0], *yuv1 = yuv[1], *yuv2 = yuv[2];
|
||||
int16_t *rgb0 = rgb[0], *rgb1 = rgb[1], *rgb2 = rgb[2];
|
||||
int y, x;
|
||||
int cy = yuv2rgb_coeffs[0][0][0];
|
||||
int crv = yuv2rgb_coeffs[0][2][0];
|
||||
int cgu = yuv2rgb_coeffs[1][1][0];
|
||||
int cgv = yuv2rgb_coeffs[1][2][0];
|
||||
int cbu = yuv2rgb_coeffs[2][1][0];
|
||||
const int sh = BIT_DEPTH - 1, rnd = 1 << (sh - 1);
|
||||
const int uv_offset = 128 << (BIT_DEPTH - 8);
|
||||
|
||||
av_assert2(yuv2rgb_coeffs[0][1][0] == 0);
|
||||
av_assert2(yuv2rgb_coeffs[2][2][0] == 0);
|
||||
av_assert2(yuv2rgb_coeffs[1][0][0] == cy && yuv2rgb_coeffs[2][0][0] == cy);
|
||||
|
||||
w = AV_CEIL_RSHIFT(w, SS_W);
|
||||
h = AV_CEIL_RSHIFT(h, SS_H);
|
||||
for (y = 0; y < h; y++) {
|
||||
for (x = 0; x < w; x++) {
|
||||
int y00 = yuv0[x << SS_W] - yuv_offset[0];
|
||||
#if SS_W == 1
|
||||
int y01 = yuv0[2 * x + 1] - yuv_offset[0];
|
||||
#if SS_H == 1
|
||||
int y10 = yuv0[yuv_stride[0] / sizeof(pixel) + 2 * x] - yuv_offset[0];
|
||||
int y11 = yuv0[yuv_stride[0] / sizeof(pixel) + 2 * x + 1] - yuv_offset[0];
|
||||
#endif
|
||||
#endif
|
||||
int u = yuv1[x] - uv_offset, v = yuv2[x] - uv_offset;
|
||||
|
||||
rgb0[x << SS_W] = av_clip_int16((y00 * cy + crv * v + rnd) >> sh);
|
||||
#if SS_W == 1
|
||||
rgb0[2 * x + 1] = av_clip_int16((y01 * cy + crv * v + rnd) >> sh);
|
||||
#if SS_H == 1
|
||||
rgb0[2 * x + rgb_stride] = av_clip_int16((y10 * cy + crv * v + rnd) >> sh);
|
||||
rgb0[2 * x + rgb_stride + 1] = av_clip_int16((y11 * cy + crv * v + rnd) >> sh);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
rgb1[x << SS_W] = av_clip_int16((y00 * cy + cgu * u +
|
||||
cgv * v + rnd) >> sh);
|
||||
#if SS_W == 1
|
||||
rgb1[2 * x + 1] = av_clip_int16((y01 * cy + cgu * u +
|
||||
cgv * v + rnd) >> sh);
|
||||
#if SS_H == 1
|
||||
rgb1[2 * x + rgb_stride] = av_clip_int16((y10 * cy + cgu * u +
|
||||
cgv * v + rnd) >> sh);
|
||||
rgb1[2 * x + rgb_stride + 1] = av_clip_int16((y11 * cy + cgu * u +
|
||||
cgv * v + rnd) >> sh);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
rgb2[x << SS_W] = av_clip_int16((y00 * cy + cbu * u + rnd) >> sh);
|
||||
#if SS_W == 1
|
||||
rgb2[2 * x + 1] = av_clip_int16((y01 * cy + cbu * u + rnd) >> sh);
|
||||
#if SS_H == 1
|
||||
rgb2[2 * x + rgb_stride] = av_clip_int16((y10 * cy + cbu * u + rnd) >> sh);
|
||||
rgb2[2 * x + rgb_stride + 1] = av_clip_int16((y11 * cy + cbu * u + rnd) >> sh);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
yuv0 += (yuv_stride[0] * (1 << SS_H)) / sizeof(pixel);
|
||||
yuv1 += yuv_stride[1] / sizeof(pixel);
|
||||
yuv2 += yuv_stride[2] / sizeof(pixel);
|
||||
rgb0 += rgb_stride * (1 << SS_H);
|
||||
rgb1 += rgb_stride * (1 << SS_H);
|
||||
rgb2 += rgb_stride * (1 << SS_H);
|
||||
}
|
||||
}
|
||||
|
||||
static void fn(rgb2yuv)(uint8_t *_yuv[3], ptrdiff_t yuv_stride[3],
|
||||
int16_t *rgb[3], ptrdiff_t s,
|
||||
int w, int h, const int16_t rgb2yuv_coeffs[3][3][8],
|
||||
const int16_t yuv_offset[8])
|
||||
{
|
||||
pixel **yuv = (pixel **) _yuv;
|
||||
pixel *yuv0 = yuv[0], *yuv1 = yuv[1], *yuv2 = yuv[2];
|
||||
const int16_t *rgb0 = rgb[0], *rgb1 = rgb[1], *rgb2 = rgb[2];
|
||||
int y, x;
|
||||
const int sh = 29 - BIT_DEPTH;
|
||||
const int rnd = 1 << (sh - 1);
|
||||
int cry = rgb2yuv_coeffs[0][0][0];
|
||||
int cgy = rgb2yuv_coeffs[0][1][0];
|
||||
int cby = rgb2yuv_coeffs[0][2][0];
|
||||
int cru = rgb2yuv_coeffs[1][0][0];
|
||||
int cgu = rgb2yuv_coeffs[1][1][0];
|
||||
int cburv = rgb2yuv_coeffs[1][2][0];
|
||||
int cgv = rgb2yuv_coeffs[2][1][0];
|
||||
int cbv = rgb2yuv_coeffs[2][2][0];
|
||||
ptrdiff_t s0 = yuv_stride[0] / sizeof(pixel);
|
||||
const int uv_offset = 128 << (BIT_DEPTH - 8);
|
||||
|
||||
av_assert2(rgb2yuv_coeffs[1][2][0] == rgb2yuv_coeffs[2][0][0]);
|
||||
w = AV_CEIL_RSHIFT(w, SS_W);
|
||||
h = AV_CEIL_RSHIFT(h, SS_H);
|
||||
for (y = 0; y < h; y++) {
|
||||
for (x = 0; x < w; x++) {
|
||||
int r00 = rgb0[x << SS_W], g00 = rgb1[x << SS_W], b00 = rgb2[x << SS_W];
|
||||
#if SS_W == 1
|
||||
int r01 = rgb0[x * 2 + 1], g01 = rgb1[x * 2 + 1], b01 = rgb2[x * 2 + 1];
|
||||
#if SS_H == 1
|
||||
int r10 = rgb0[x * 2 + 0 + s], g10 = rgb1[x * 2 + 0 + s], b10 = rgb2[x * 2 + 0 + s];
|
||||
int r11 = rgb0[x * 2 + 1 + s], g11 = rgb1[x * 2 + 1 + s], b11 = rgb2[x * 2 + 1 + s];
|
||||
#endif
|
||||
#endif
|
||||
|
||||
yuv0[x << SS_W] = av_clip_pixel(yuv_offset[0] +
|
||||
((r00 * cry + g00 * cgy +
|
||||
b00 * cby + rnd) >> sh));
|
||||
#if SS_W == 1
|
||||
yuv0[x * 2 + 1] = av_clip_pixel(yuv_offset[0] +
|
||||
((r01 * cry + g01 * cgy +
|
||||
b01 * cby + rnd) >> sh));
|
||||
#if SS_H == 1
|
||||
yuv0[x * 2 + 0 + s0] = av_clip_pixel(yuv_offset[0] +
|
||||
((r10 * cry + g10 * cgy +
|
||||
b10 * cby + rnd) >> sh));
|
||||
yuv0[x * 2 + 1 + s0] = av_clip_pixel(yuv_offset[0] +
|
||||
((r11 * cry + g11 * cgy +
|
||||
b11 * cby + rnd) >> sh));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
yuv1[x] = av_clip_pixel(uv_offset +
|
||||
((avg(r00, r01, r10, r11) * cru +
|
||||
avg(g00, g01, g10, g11) * cgu +
|
||||
avg(b00, b01, b10, b11) * cburv + rnd) >> sh));
|
||||
yuv2[x] = av_clip_pixel(uv_offset +
|
||||
((avg(r00, r01, r10, r11) * cburv +
|
||||
avg(g00, g01, g10, g11) * cgv +
|
||||
avg(b00, b01, b10, b11) * cbv + rnd) >> sh));
|
||||
}
|
||||
|
||||
yuv0 += s0 * (1 << SS_H);
|
||||
yuv1 += yuv_stride[1] / sizeof(pixel);
|
||||
yuv2 += yuv_stride[2] / sizeof(pixel);
|
||||
rgb0 += s * (1 << SS_H);
|
||||
rgb1 += s * (1 << SS_H);
|
||||
rgb2 += s * (1 << SS_H);
|
||||
}
|
||||
}
|
||||
|
||||
#undef IN_BIT_DEPTH
|
||||
#undef OUT_BIT_DEPTH
|
||||
#define OUT_BIT_DEPTH BIT_DEPTH
|
||||
#define IN_BIT_DEPTH 8
|
||||
#include "colorspacedsp_yuv2yuv_template.c"
|
||||
|
||||
#undef IN_BIT_DEPTH
|
||||
#define IN_BIT_DEPTH 10
|
||||
#include "colorspacedsp_yuv2yuv_template.c"
|
||||
|
||||
#undef IN_BIT_DEPTH
|
||||
#define IN_BIT_DEPTH 12
|
||||
#include "colorspacedsp_yuv2yuv_template.c"
|
98
libavfilter/colorspacedsp_yuv2yuv_template.c
Normal file
98
libavfilter/colorspacedsp_yuv2yuv_template.c
Normal file
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Ronald S. Bultje <rsbultje@gmail.com>
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "libavutil/avassert.h"
|
||||
|
||||
#undef opixel
|
||||
#define opixel pixel
|
||||
|
||||
#undef ipixel
|
||||
#if IN_BIT_DEPTH == 8
|
||||
#define ipixel uint8_t
|
||||
#else
|
||||
#define ipixel uint16_t
|
||||
#endif
|
||||
|
||||
#undef fn
|
||||
#undef fn2
|
||||
#undef fn3
|
||||
#define fn3(a,b,c,d) a##_##d##p##b##to##c##_c
|
||||
#define fn2(a,b,c,d) fn3(a,b,c,d)
|
||||
#define fn(a) fn2(a, IN_BIT_DEPTH, OUT_BIT_DEPTH, ss)
|
||||
|
||||
static void fn(yuv2yuv)(uint8_t *_dst[3], ptrdiff_t dst_stride[3],
|
||||
uint8_t *_src[3], ptrdiff_t src_stride[3],
|
||||
int w, int h, const int16_t c[3][3][8],
|
||||
const int16_t yuv_offset[2][8])
|
||||
{
|
||||
opixel **dst = (opixel **) _dst;
|
||||
ipixel **src = (ipixel **) _src;
|
||||
const ipixel *src0 = src[0], *src1 = src[1], *src2 = src[2];
|
||||
opixel *dst0 = dst[0], *dst1 = dst[1], *dst2 = dst[2];
|
||||
int y, x;
|
||||
const int sh = 14 + IN_BIT_DEPTH - OUT_BIT_DEPTH;
|
||||
const int rnd = 1 << (sh - 1);
|
||||
int y_off_in = yuv_offset[0][0];
|
||||
int y_off_out = yuv_offset[1][0] << sh;
|
||||
const int uv_off_in = 128 << (IN_BIT_DEPTH - 8);
|
||||
const int uv_off_out = rnd + (128 << (OUT_BIT_DEPTH - 8 + sh));
|
||||
int cyy = c[0][0][0], cyu = c[0][1][0], cyv = c[0][2][0];
|
||||
int cuu = c[1][1][0], cuv = c[1][2][0], cvu = c[2][1][0], cvv = c[2][2][0];
|
||||
|
||||
av_assert2(c[1][0][0] == 0);
|
||||
av_assert2(c[2][0][0] == 0);
|
||||
w = AV_CEIL_RSHIFT(w, SS_W);
|
||||
h = AV_CEIL_RSHIFT(h, SS_H);
|
||||
for (y = 0; y < h; y++) {
|
||||
for (x = 0; x < w; x++) {
|
||||
int y00 = src0[x << SS_W] - y_off_in;
|
||||
#if SS_W == 1
|
||||
int y01 = src0[2 * x + 1] - y_off_in;
|
||||
#if SS_H == 1
|
||||
int y10 = src0[src_stride[0] / sizeof(ipixel) + 2 * x] - y_off_in;
|
||||
int y11 = src0[src_stride[0] / sizeof(ipixel) + 2 * x + 1] - y_off_in;
|
||||
#endif
|
||||
#endif
|
||||
int u = src1[x] - uv_off_in, v = src2[x] - uv_off_in;
|
||||
int uv_val = cyu * u + cyv * v + rnd + y_off_out;
|
||||
|
||||
dst0[x << SS_W] = av_clip_pixel((cyy * y00 + uv_val) >> sh);
|
||||
#if SS_W == 1
|
||||
dst0[x * 2 + 1] = av_clip_pixel((cyy * y01 + uv_val) >> sh);
|
||||
#if SS_H == 1
|
||||
dst0[x * 2 + 0 + dst_stride[0] / sizeof(opixel)] =
|
||||
av_clip_pixel((cyy * y10 + uv_val) >> sh);
|
||||
dst0[x * 2 + 1 + dst_stride[0] / sizeof(opixel)] =
|
||||
av_clip_pixel((cyy * y11 + uv_val) >> sh);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
dst1[x] = av_clip_pixel((u * cuu + v * cuv + uv_off_out) >> sh);
|
||||
dst2[x] = av_clip_pixel((u * cvu + v * cvv + uv_off_out) >> sh);
|
||||
}
|
||||
|
||||
dst0 += (dst_stride[0] * (1 << SS_H)) / sizeof(opixel);
|
||||
dst1 += dst_stride[1] / sizeof(opixel);
|
||||
dst2 += dst_stride[2] / sizeof(opixel);
|
||||
src0 += (src_stride[0] * (1 << SS_H)) / sizeof(ipixel);
|
||||
src1 += src_stride[1] / sizeof(ipixel);
|
||||
src2 += src_stride[2] / sizeof(ipixel);
|
||||
}
|
||||
}
|
1024
libavfilter/vf_colorspace.c
Normal file
1024
libavfilter/vf_colorspace.c
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user