2012-03-10 03:04:19 +00:00
/*
* ColorMatrix v2 .2 for Avisynth 2.5 . x
*
* Copyright ( C ) 2006 - 2007 Kevin Stone
*
* ColorMatrix 1. x is Copyright ( C ) Wilbert Dijkhof
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation ; either version 2 of the License , or ( at your
* option ) any later version .
*
* This program is distributed in the hope that it will be useful , but
* OUT ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public
* License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software Foundation ,
2014-02-22 10:17:56 +00:00
* Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
2012-03-10 03:04:19 +00:00
*/
/**
* @ file
* ColorMatrix 2.0 is based on the original ColorMatrix filter by Wilbert
* Dijkhof . It adds the ability to convert between any of : Rec .709 , FCC ,
* Rec .601 , and SMPTE 240 M . It also makes pre and post clipping optional ,
* adds an option to use scaled or non - scaled coefficients , and more . . .
*/
# include <float.h>
# include "avfilter.h"
2012-06-16 09:47:46 +00:00
# include "formats.h"
2012-11-29 01:04:45 +00:00
# include "internal.h"
2012-06-16 09:47:46 +00:00
# include "video.h"
2013-03-24 12:40:57 +00:00
# include "libavutil/opt.h"
2012-03-10 03:04:19 +00:00
# include "libavutil/pixdesc.h"
# include "libavutil/avstring.h"
2014-06-24 19:40:57 +00:00
# define NS(n) ((n) < 0 ? (int)((n)*65536.0-0.5+DBL_EPSILON) : (int)((n)*65536.0+0.5))
2012-03-10 03:04:19 +00:00
# define CB(n) av_clip_uint8(n)
2016-03-25 22:31:36 +00:00
static const double yuv_coeff_luma [ 5 ] [ 3 ] = {
2016-03-26 10:53:36 +00:00
{ + 0.7152 , + 0.0722 , + 0.2126 } , // Rec.709 (0)
{ + 0.5900 , + 0.1100 , + 0.3000 } , // FCC (1)
{ + 0.5870 , + 0.1140 , + 0.2990 } , // Rec.601 (ITU-R BT.470-2/SMPTE 170M) (2)
{ + 0.7010 , + 0.0870 , + 0.2120 } , // SMPTE 240M (3)
2016-03-25 22:31:36 +00:00
{ + 0.6780 , + 0.0593 , + 0.2627 } , // Rec.2020 (4)
2012-03-10 03:04:19 +00:00
} ;
2013-03-24 12:40:57 +00:00
enum ColorMode {
COLOR_MODE_NONE = - 1 ,
COLOR_MODE_BT709 ,
COLOR_MODE_FCC ,
COLOR_MODE_BT601 ,
COLOR_MODE_SMPTE240M ,
2016-03-25 22:31:36 +00:00
COLOR_MODE_BT2020 ,
2013-03-24 12:40:57 +00:00
COLOR_MODE_COUNT
} ;
2017-05-12 18:00:49 +00:00
typedef struct ColorMatrixContext {
2013-03-24 12:40:57 +00:00
const AVClass * class ;
2016-03-25 22:31:36 +00:00
int yuv_convert [ 25 ] [ 3 ] [ 3 ] ;
2012-03-10 03:04:19 +00:00
int interlaced ;
2015-03-07 01:44:04 +00:00
int source , dest ; ///< ColorMode
2013-03-24 12:40:57 +00:00
int mode ;
2012-03-10 03:04:19 +00:00
int hsub , vsub ;
} ColorMatrixContext ;
2015-03-10 05:01:47 +00:00
typedef struct ThreadData {
AVFrame * dst ;
const AVFrame * src ;
int c2 ;
int c3 ;
int c4 ;
int c5 ;
int c6 ;
int c7 ;
} ThreadData ;
2013-03-24 12:40:57 +00:00
# define OFFSET(x) offsetof(ColorMatrixContext, x)
# define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
static const AVOption colormatrix_options [ ] = {
{ " src " , " set source color matrix " , OFFSET ( source ) , AV_OPT_TYPE_INT , { . i64 = COLOR_MODE_NONE } , COLOR_MODE_NONE , COLOR_MODE_COUNT - 1 , . flags = FLAGS , . unit = " color_mode " } ,
{ " dst " , " set destination color matrix " , OFFSET ( dest ) , AV_OPT_TYPE_INT , { . i64 = COLOR_MODE_NONE } , COLOR_MODE_NONE , COLOR_MODE_COUNT - 1 , . flags = FLAGS , . unit = " color_mode " } ,
{ " bt709 " , " set BT.709 colorspace " , 0 , AV_OPT_TYPE_CONST , { . i64 = COLOR_MODE_BT709 } , . flags = FLAGS , . unit = " color_mode " } ,
{ " fcc " , " set FCC colorspace " , 0 , AV_OPT_TYPE_CONST , { . i64 = COLOR_MODE_FCC } , . flags = FLAGS , . unit = " color_mode " } ,
{ " bt601 " , " set BT.601 colorspace " , 0 , AV_OPT_TYPE_CONST , { . i64 = COLOR_MODE_BT601 } , . flags = FLAGS , . unit = " color_mode " } ,
2015-02-24 18:05:41 +00:00
{ " bt470 " , " set BT.470 colorspace " , 0 , AV_OPT_TYPE_CONST , { . i64 = COLOR_MODE_BT601 } , . flags = FLAGS , . unit = " color_mode " } ,
2015-09-02 13:05:29 +00:00
{ " bt470bg " , " set BT.470 colorspace " , 0 , AV_OPT_TYPE_CONST , { . i64 = COLOR_MODE_BT601 } , . flags = FLAGS , . unit = " color_mode " } ,
2015-02-24 18:05:41 +00:00
{ " smpte170m " , " set SMTPE-170M colorspace " , 0 , AV_OPT_TYPE_CONST , { . i64 = COLOR_MODE_BT601 } , . flags = FLAGS , . unit = " color_mode " } ,
2013-03-24 12:40:57 +00:00
{ " smpte240m " , " set SMPTE-240M colorspace " , 0 , AV_OPT_TYPE_CONST , { . i64 = COLOR_MODE_SMPTE240M } , . flags = FLAGS , . unit = " color_mode " } ,
2016-03-25 22:31:36 +00:00
{ " bt2020 " , " set BT.2020 colorspace " , 0 , AV_OPT_TYPE_CONST , { . i64 = COLOR_MODE_BT2020 } , . flags = FLAGS , . unit = " color_mode " } ,
2013-03-24 12:40:57 +00:00
{ NULL }
} ;
AVFILTER_DEFINE_CLASS ( colormatrix ) ;
2012-03-10 03:04:19 +00:00
# define ma m[0][0]
# define mb m[0][1]
# define mc m[0][2]
# define md m[1][0]
# define me m[1][1]
# define mf m[1][2]
# define mg m[2][0]
# define mh m[2][1]
# define mi m[2][2]
# define ima im[0][0]
# define imb im[0][1]
# define imc im[0][2]
# define imd im[1][0]
# define ime im[1][1]
# define imf im[1][2]
# define img im[2][0]
# define imh im[2][1]
# define imi im[2][2]
2016-03-26 10:53:36 +00:00
static void inverse3x3 ( double im [ 3 ] [ 3 ] , double m [ 3 ] [ 3 ] )
2012-03-10 03:04:19 +00:00
{
double det = ma * ( me * mi - mf * mh ) - mb * ( md * mi - mf * mg ) + mc * ( md * mh - me * mg ) ;
det = 1.0 / det ;
ima = det * ( me * mi - mf * mh ) ;
imb = det * ( mc * mh - mb * mi ) ;
imc = det * ( mb * mf - mc * me ) ;
imd = det * ( mf * mg - md * mi ) ;
ime = det * ( ma * mi - mc * mg ) ;
imf = det * ( mc * md - ma * mf ) ;
img = det * ( md * mh - me * mg ) ;
imh = det * ( mb * mg - ma * mh ) ;
imi = det * ( ma * me - mb * md ) ;
}
2016-03-26 10:53:36 +00:00
static void solve_coefficients ( double cm [ 3 ] [ 3 ] , double rgb [ 3 ] [ 3 ] , double yuv [ 3 ] [ 3 ] )
2012-03-10 03:04:19 +00:00
{
int i , j ;
for ( i = 0 ; i < 3 ; i + + )
for ( j = 0 ; j < 3 ; j + + )
cm [ i ] [ j ] = yuv [ i ] [ 0 ] * rgb [ 0 ] [ j ] + yuv [ i ] [ 1 ] * rgb [ 1 ] [ j ] + yuv [ i ] [ 2 ] * rgb [ 2 ] [ j ] ;
}
static void calc_coefficients ( AVFilterContext * ctx )
{
ColorMatrixContext * color = ctx - > priv ;
2016-03-25 22:31:36 +00:00
double yuv_coeff [ 5 ] [ 3 ] [ 3 ] ;
double rgb_coeffd [ 5 ] [ 3 ] [ 3 ] ;
double yuv_convertd [ 25 ] [ 3 ] [ 3 ] ;
2016-03-26 10:53:36 +00:00
double bscale , rscale ;
2012-03-10 03:04:19 +00:00
int v = 0 ;
int i , j , k ;
2016-03-25 22:31:36 +00:00
for ( i = 0 ; i < 5 ; i + + ) {
2016-03-26 10:53:36 +00:00
yuv_coeff [ i ] [ 0 ] [ 0 ] = yuv_coeff_luma [ i ] [ 0 ] ;
yuv_coeff [ i ] [ 0 ] [ 1 ] = yuv_coeff_luma [ i ] [ 1 ] ;
yuv_coeff [ i ] [ 0 ] [ 2 ] = yuv_coeff_luma [ i ] [ 2 ] ;
bscale = 0.5 / ( yuv_coeff [ i ] [ 0 ] [ 1 ] - 1.0 ) ;
rscale = 0.5 / ( yuv_coeff [ i ] [ 0 ] [ 2 ] - 1.0 ) ;
yuv_coeff [ i ] [ 1 ] [ 0 ] = bscale * yuv_coeff [ i ] [ 0 ] [ 0 ] ;
yuv_coeff [ i ] [ 1 ] [ 1 ] = 0.5 ;
yuv_coeff [ i ] [ 1 ] [ 2 ] = bscale * yuv_coeff [ i ] [ 0 ] [ 2 ] ;
yuv_coeff [ i ] [ 2 ] [ 0 ] = rscale * yuv_coeff [ i ] [ 0 ] [ 0 ] ;
yuv_coeff [ i ] [ 2 ] [ 1 ] = rscale * yuv_coeff [ i ] [ 0 ] [ 1 ] ;
yuv_coeff [ i ] [ 2 ] [ 2 ] = 0.5 ;
}
2016-03-25 22:31:36 +00:00
for ( i = 0 ; i < 5 ; i + + )
2012-03-10 03:04:19 +00:00
inverse3x3 ( rgb_coeffd [ i ] , yuv_coeff [ i ] ) ;
2016-03-25 22:31:36 +00:00
for ( i = 0 ; i < 5 ; i + + ) {
for ( j = 0 ; j < 5 ; j + + ) {
2012-03-10 03:04:19 +00:00
solve_coefficients ( yuv_convertd [ v ] , rgb_coeffd [ i ] , yuv_coeff [ j ] ) ;
for ( k = 0 ; k < 3 ; k + + ) {
color - > yuv_convert [ v ] [ k ] [ 0 ] = NS ( yuv_convertd [ v ] [ k ] [ 0 ] ) ;
color - > yuv_convert [ v ] [ k ] [ 1 ] = NS ( yuv_convertd [ v ] [ k ] [ 1 ] ) ;
color - > yuv_convert [ v ] [ k ] [ 2 ] = NS ( yuv_convertd [ v ] [ k ] [ 2 ] ) ;
}
if ( color - > yuv_convert [ v ] [ 0 ] [ 0 ] ! = 65536 | | color - > yuv_convert [ v ] [ 1 ] [ 0 ] ! = 0 | |
color - > yuv_convert [ v ] [ 2 ] [ 0 ] ! = 0 ) {
av_log ( ctx , AV_LOG_ERROR , " error calculating conversion coefficients \n " ) ;
}
v + + ;
}
}
}
2016-03-25 22:31:36 +00:00
static const char * const color_modes [ ] = { " bt709 " , " fcc " , " bt601 " , " smpte240m " , " bt2020 " } ;
2012-03-10 03:04:19 +00:00
2013-04-12 09:13:33 +00:00
static av_cold int init ( AVFilterContext * ctx )
2012-03-10 03:04:19 +00:00
{
ColorMatrixContext * color = ctx - > priv ;
2014-01-08 17:40:23 +00:00
if ( color - > dest = = COLOR_MODE_NONE ) {
av_log ( ctx , AV_LOG_ERROR , " Unspecified destination color space \n " ) ;
2012-03-10 03:04:19 +00:00
return AVERROR ( EINVAL ) ;
}
if ( color - > source = = color - > dest ) {
2013-03-24 12:46:15 +00:00
av_log ( ctx , AV_LOG_ERROR , " Source and destination color space must not be identical \n " ) ;
2012-03-10 03:04:19 +00:00
return AVERROR ( EINVAL ) ;
}
2015-06-05 20:05:18 +00:00
calc_coefficients ( ctx ) ;
2012-03-10 03:04:19 +00:00
return 0 ;
}
2015-03-10 05:01:47 +00:00
static int process_slice_uyvy422 ( AVFilterContext * ctx , void * arg , int jobnr , int nb_jobs )
2012-03-10 03:04:19 +00:00
{
2015-03-10 05:01:47 +00:00
const ThreadData * td = arg ;
const AVFrame * src = td - > src ;
AVFrame * dst = td - > dst ;
2013-03-10 00:30:30 +00:00
const int height = src - > height ;
const int width = src - > width * 2 ;
2015-03-10 05:01:47 +00:00
const int src_pitch = src - > linesize [ 0 ] ;
2012-03-10 03:04:19 +00:00
const int dst_pitch = dst - > linesize [ 0 ] ;
2015-03-10 05:01:47 +00:00
const int slice_start = ( height * jobnr ) / nb_jobs ;
const int slice_end = ( height * ( jobnr + 1 ) ) / nb_jobs ;
const unsigned char * srcp = src - > data [ 0 ] + slice_start * src_pitch ;
unsigned char * dstp = dst - > data [ 0 ] + slice_start * dst_pitch ;
const int c2 = td - > c2 ;
const int c3 = td - > c3 ;
const int c4 = td - > c4 ;
const int c5 = td - > c5 ;
const int c6 = td - > c6 ;
const int c7 = td - > c7 ;
2012-03-10 03:04:19 +00:00
int x , y ;
2015-03-10 05:01:47 +00:00
for ( y = slice_start ; y < slice_end ; y + + ) {
2012-03-10 03:04:19 +00:00
for ( x = 0 ; x < width ; x + = 4 ) {
const int u = srcp [ x + 0 ] - 128 ;
const int v = srcp [ x + 2 ] - 128 ;
const int uvval = c2 * u + c3 * v + 1081344 ;
dstp [ x + 0 ] = CB ( ( c4 * u + c5 * v + 8421376 ) > > 16 ) ;
dstp [ x + 1 ] = CB ( ( 65536 * ( srcp [ x + 1 ] - 16 ) + uvval ) > > 16 ) ;
dstp [ x + 2 ] = CB ( ( c6 * u + c7 * v + 8421376 ) > > 16 ) ;
dstp [ x + 3 ] = CB ( ( 65536 * ( srcp [ x + 3 ] - 16 ) + uvval ) > > 16 ) ;
}
srcp + = src_pitch ;
dstp + = dst_pitch ;
}
2015-03-10 05:01:47 +00:00
return 0 ;
2012-03-10 03:04:19 +00:00
}
2015-07-06 14:07:52 +00:00
static int process_slice_yuv444p ( AVFilterContext * ctx , void * arg , int jobnr , int nb_jobs )
{
const ThreadData * td = arg ;
const AVFrame * src = td - > src ;
AVFrame * dst = td - > dst ;
const int height = src - > height ;
const int width = src - > width ;
const int slice_start = ( height * jobnr ) / nb_jobs ;
const int slice_end = ( height * ( jobnr + 1 ) ) / nb_jobs ;
const int src_pitchY = src - > linesize [ 0 ] ;
const int src_pitchUV = src - > linesize [ 1 ] ;
const unsigned char * srcpU = src - > data [ 1 ] + slice_start * src_pitchUV ;
const unsigned char * srcpV = src - > data [ 2 ] + slice_start * src_pitchUV ;
const unsigned char * srcpY = src - > data [ 0 ] + slice_start * src_pitchY ;
const int dst_pitchY = dst - > linesize [ 0 ] ;
const int dst_pitchUV = dst - > linesize [ 1 ] ;
unsigned char * dstpU = dst - > data [ 1 ] + slice_start * dst_pitchUV ;
unsigned char * dstpV = dst - > data [ 2 ] + slice_start * dst_pitchUV ;
unsigned char * dstpY = dst - > data [ 0 ] + slice_start * dst_pitchY ;
const int c2 = td - > c2 ;
const int c3 = td - > c3 ;
const int c4 = td - > c4 ;
const int c5 = td - > c5 ;
const int c6 = td - > c6 ;
const int c7 = td - > c7 ;
int x , y ;
for ( y = slice_start ; y < slice_end ; y + + ) {
for ( x = 0 ; x < width ; x + + ) {
const int u = srcpU [ x ] - 128 ;
const int v = srcpV [ x ] - 128 ;
const int uvval = c2 * u + c3 * v + 1081344 ;
dstpY [ x ] = CB ( ( 65536 * ( srcpY [ x ] - 16 ) + uvval ) > > 16 ) ;
dstpU [ x ] = CB ( ( c4 * u + c5 * v + 8421376 ) > > 16 ) ;
dstpV [ x ] = CB ( ( c6 * u + c7 * v + 8421376 ) > > 16 ) ;
}
srcpY + = src_pitchY ;
dstpY + = dst_pitchY ;
srcpU + = src_pitchUV ;
srcpV + = src_pitchUV ;
dstpU + = dst_pitchUV ;
dstpV + = dst_pitchUV ;
}
return 0 ;
}
2015-03-10 05:01:47 +00:00
static int process_slice_yuv422p ( AVFilterContext * ctx , void * arg , int jobnr , int nb_jobs )
2012-03-10 03:04:19 +00:00
{
2015-03-10 05:01:47 +00:00
const ThreadData * td = arg ;
const AVFrame * src = td - > src ;
AVFrame * dst = td - > dst ;
2013-03-10 00:30:30 +00:00
const int height = src - > height ;
const int width = src - > width ;
2015-03-10 05:01:47 +00:00
const int slice_start = ( height * jobnr ) / nb_jobs ;
const int slice_end = ( height * ( jobnr + 1 ) ) / nb_jobs ;
const int src_pitchY = src - > linesize [ 0 ] ;
const int src_pitchUV = src - > linesize [ 1 ] ;
const unsigned char * srcpU = src - > data [ 1 ] + slice_start * src_pitchUV ;
const unsigned char * srcpV = src - > data [ 2 ] + slice_start * src_pitchUV ;
const unsigned char * srcpY = src - > data [ 0 ] + slice_start * src_pitchY ;
2012-03-10 03:04:19 +00:00
const int dst_pitchY = dst - > linesize [ 0 ] ;
const int dst_pitchUV = dst - > linesize [ 1 ] ;
2015-03-10 05:01:47 +00:00
unsigned char * dstpU = dst - > data [ 1 ] + slice_start * dst_pitchUV ;
unsigned char * dstpV = dst - > data [ 2 ] + slice_start * dst_pitchUV ;
unsigned char * dstpY = dst - > data [ 0 ] + slice_start * dst_pitchY ;
const int c2 = td - > c2 ;
const int c3 = td - > c3 ;
const int c4 = td - > c4 ;
const int c5 = td - > c5 ;
const int c6 = td - > c6 ;
const int c7 = td - > c7 ;
2012-03-10 03:04:19 +00:00
int x , y ;
2015-03-10 05:01:47 +00:00
for ( y = slice_start ; y < slice_end ; y + + ) {
2012-03-10 03:04:19 +00:00
for ( x = 0 ; x < width ; x + = 2 ) {
const int u = srcpU [ x > > 1 ] - 128 ;
const int v = srcpV [ x > > 1 ] - 128 ;
const int uvval = c2 * u + c3 * v + 1081344 ;
dstpY [ x + 0 ] = CB ( ( 65536 * ( srcpY [ x + 0 ] - 16 ) + uvval ) > > 16 ) ;
dstpY [ x + 1 ] = CB ( ( 65536 * ( srcpY [ x + 1 ] - 16 ) + uvval ) > > 16 ) ;
dstpU [ x > > 1 ] = CB ( ( c4 * u + c5 * v + 8421376 ) > > 16 ) ;
dstpV [ x > > 1 ] = CB ( ( c6 * u + c7 * v + 8421376 ) > > 16 ) ;
}
srcpY + = src_pitchY ;
dstpY + = dst_pitchY ;
srcpU + = src_pitchUV ;
srcpV + = src_pitchUV ;
dstpU + = dst_pitchUV ;
dstpV + = dst_pitchUV ;
}
2015-03-10 05:01:47 +00:00
return 0 ;
2012-03-10 03:04:19 +00:00
}
2015-03-10 05:01:47 +00:00
static int process_slice_yuv420p ( AVFilterContext * ctx , void * arg , int jobnr , int nb_jobs )
2012-03-10 03:04:19 +00:00
{
2015-03-10 05:01:47 +00:00
const ThreadData * td = arg ;
const AVFrame * src = td - > src ;
AVFrame * dst = td - > dst ;
2015-03-18 22:58:30 +00:00
const int height = FFALIGN ( src - > height , 2 ) > > 1 ;
2013-03-10 00:30:30 +00:00
const int width = src - > width ;
2015-03-18 22:58:30 +00:00
const int slice_start = ( ( height * jobnr ) / nb_jobs ) < < 1 ;
const int slice_end = ( ( height * ( jobnr + 1 ) ) / nb_jobs ) < < 1 ;
2015-03-10 05:01:47 +00:00
const int src_pitchY = src - > linesize [ 0 ] ;
const int src_pitchUV = src - > linesize [ 1 ] ;
2012-03-10 03:04:19 +00:00
const int dst_pitchY = dst - > linesize [ 0 ] ;
const int dst_pitchUV = dst - > linesize [ 1 ] ;
2015-03-10 05:01:47 +00:00
const unsigned char * srcpY = src - > data [ 0 ] + src_pitchY * slice_start ;
const unsigned char * srcpU = src - > data [ 1 ] + src_pitchUV * ( slice_start > > 1 ) ;
const unsigned char * srcpV = src - > data [ 2 ] + src_pitchUV * ( slice_start > > 1 ) ;
const unsigned char * srcpN = src - > data [ 0 ] + src_pitchY * ( slice_start + 1 ) ;
unsigned char * dstpU = dst - > data [ 1 ] + dst_pitchUV * ( slice_start > > 1 ) ;
unsigned char * dstpV = dst - > data [ 2 ] + dst_pitchUV * ( slice_start > > 1 ) ;
unsigned char * dstpY = dst - > data [ 0 ] + dst_pitchY * slice_start ;
unsigned char * dstpN = dst - > data [ 0 ] + dst_pitchY * ( slice_start + 1 ) ;
const int c2 = td - > c2 ;
const int c3 = td - > c3 ;
const int c4 = td - > c4 ;
const int c5 = td - > c5 ;
const int c6 = td - > c6 ;
const int c7 = td - > c7 ;
2012-03-10 03:04:19 +00:00
int x , y ;
2015-03-10 05:01:47 +00:00
for ( y = slice_start ; y < slice_end ; y + = 2 ) {
2012-03-10 03:04:19 +00:00
for ( x = 0 ; x < width ; x + = 2 ) {
const int u = srcpU [ x > > 1 ] - 128 ;
const int v = srcpV [ x > > 1 ] - 128 ;
const int uvval = c2 * u + c3 * v + 1081344 ;
dstpY [ x + 0 ] = CB ( ( 65536 * ( srcpY [ x + 0 ] - 16 ) + uvval ) > > 16 ) ;
dstpY [ x + 1 ] = CB ( ( 65536 * ( srcpY [ x + 1 ] - 16 ) + uvval ) > > 16 ) ;
dstpN [ x + 0 ] = CB ( ( 65536 * ( srcpN [ x + 0 ] - 16 ) + uvval ) > > 16 ) ;
dstpN [ x + 1 ] = CB ( ( 65536 * ( srcpN [ x + 1 ] - 16 ) + uvval ) > > 16 ) ;
dstpU [ x > > 1 ] = CB ( ( c4 * u + c5 * v + 8421376 ) > > 16 ) ;
dstpV [ x > > 1 ] = CB ( ( c6 * u + c7 * v + 8421376 ) > > 16 ) ;
}
srcpY + = src_pitchY < < 1 ;
dstpY + = dst_pitchY < < 1 ;
srcpN + = src_pitchY < < 1 ;
dstpN + = dst_pitchY < < 1 ;
srcpU + = src_pitchUV ;
srcpV + = src_pitchUV ;
dstpU + = dst_pitchUV ;
dstpV + = dst_pitchUV ;
}
2015-03-10 05:01:47 +00:00
return 0 ;
2012-03-10 03:04:19 +00:00
}
static int config_input ( AVFilterLink * inlink )
{
AVFilterContext * ctx = inlink - > dst ;
ColorMatrixContext * color = ctx - > priv ;
2012-10-20 04:43:48 +00:00
const AVPixFmtDescriptor * pix_desc = av_pix_fmt_desc_get ( inlink - > format ) ;
2012-03-10 03:04:19 +00:00
color - > hsub = pix_desc - > log2_chroma_w ;
color - > vsub = pix_desc - > log2_chroma_h ;
2013-03-24 12:40:57 +00:00
av_log ( ctx , AV_LOG_VERBOSE , " %s -> %s \n " ,
color_modes [ color - > source ] , color_modes [ color - > dest ] ) ;
2012-03-10 03:04:19 +00:00
return 0 ;
}
static int query_formats ( AVFilterContext * ctx )
{
2012-10-08 18:54:00 +00:00
static const enum AVPixelFormat pix_fmts [ ] = {
2015-07-06 14:07:52 +00:00
AV_PIX_FMT_YUV444P ,
2012-10-08 18:54:00 +00:00
AV_PIX_FMT_YUV422P ,
AV_PIX_FMT_YUV420P ,
AV_PIX_FMT_UYVY422 ,
AV_PIX_FMT_NONE
2012-03-10 03:04:19 +00:00
} ;
2015-03-15 13:20:34 +00:00
AVFilterFormats * fmts_list = ff_make_format_list ( pix_fmts ) ;
if ( ! fmts_list )
return AVERROR ( ENOMEM ) ;
return ff_set_common_formats ( ctx , fmts_list ) ;
2012-03-10 03:04:19 +00:00
}
2013-03-10 00:30:30 +00:00
static int filter_frame ( AVFilterLink * link , AVFrame * in )
2012-03-10 03:04:19 +00:00
{
2012-07-21 19:35:05 +00:00
AVFilterContext * ctx = link - > dst ;
ColorMatrixContext * color = ctx - > priv ;
2012-11-29 01:04:45 +00:00
AVFilterLink * outlink = ctx - > outputs [ 0 ] ;
2013-03-10 00:30:30 +00:00
AVFrame * out ;
2015-03-10 05:01:47 +00:00
ThreadData td = { 0 } ;
2012-03-10 03:04:19 +00:00
2013-03-10 00:30:30 +00:00
out = ff_get_video_buffer ( outlink , outlink - > w , outlink - > h ) ;
2012-11-29 01:04:45 +00:00
if ( ! out ) {
2013-03-10 00:30:30 +00:00
av_frame_free ( & in ) ;
2012-11-29 01:04:45 +00:00
return AVERROR ( ENOMEM ) ;
}
2013-03-10 00:30:30 +00:00
av_frame_copy_props ( out , in ) ;
2012-03-10 03:04:19 +00:00
2014-01-08 17:40:23 +00:00
if ( color - > source = = COLOR_MODE_NONE ) {
2017-04-22 08:57:18 +00:00
enum AVColorSpace cs = in - > colorspace ;
2014-01-08 17:40:23 +00:00
enum ColorMode source ;
switch ( cs ) {
case AVCOL_SPC_BT709 : source = COLOR_MODE_BT709 ; break ;
case AVCOL_SPC_FCC : source = COLOR_MODE_FCC ; break ;
case AVCOL_SPC_SMPTE240M : source = COLOR_MODE_SMPTE240M ; break ;
case AVCOL_SPC_BT470BG : source = COLOR_MODE_BT601 ; break ;
2015-02-24 18:05:41 +00:00
case AVCOL_SPC_SMPTE170M : source = COLOR_MODE_BT601 ; break ;
2016-03-25 22:31:36 +00:00
case AVCOL_SPC_BT2020_NCL : source = COLOR_MODE_BT2020 ; break ;
case AVCOL_SPC_BT2020_CL : source = COLOR_MODE_BT2020 ; break ;
2014-01-08 17:40:23 +00:00
default :
av_log ( ctx , AV_LOG_ERROR , " Input frame does not specify a supported colorspace, and none has been specified as source either \n " ) ;
2014-04-07 23:25:00 +00:00
av_frame_free ( & out ) ;
2014-01-08 17:40:23 +00:00
return AVERROR ( EINVAL ) ;
}
2016-03-25 22:31:36 +00:00
color - > mode = source * 5 + color - > dest ;
2014-01-08 17:40:23 +00:00
} else
2016-03-25 22:31:36 +00:00
color - > mode = color - > source * 5 + color - > dest ;
2014-01-08 17:40:23 +00:00
2014-01-28 19:49:38 +00:00
switch ( color - > dest ) {
2017-04-22 08:57:18 +00:00
case COLOR_MODE_BT709 : out - > colorspace = AVCOL_SPC_BT709 ; break ;
case COLOR_MODE_FCC : out - > colorspace = AVCOL_SPC_FCC ; break ;
case COLOR_MODE_SMPTE240M : out - > colorspace = AVCOL_SPC_SMPTE240M ; break ;
case COLOR_MODE_BT601 : out - > colorspace = AVCOL_SPC_BT470BG ; break ;
case COLOR_MODE_BT2020 : out - > colorspace = AVCOL_SPC_BT2020_NCL ; break ;
2014-01-28 19:49:38 +00:00
}
2015-03-10 05:01:47 +00:00
td . src = in ;
td . dst = out ;
td . c2 = color - > yuv_convert [ color - > mode ] [ 0 ] [ 1 ] ;
td . c3 = color - > yuv_convert [ color - > mode ] [ 0 ] [ 2 ] ;
td . c4 = color - > yuv_convert [ color - > mode ] [ 1 ] [ 1 ] ;
td . c5 = color - > yuv_convert [ color - > mode ] [ 1 ] [ 2 ] ;
td . c6 = color - > yuv_convert [ color - > mode ] [ 2 ] [ 1 ] ;
td . c7 = color - > yuv_convert [ color - > mode ] [ 2 ] [ 2 ] ;
2015-07-06 14:07:52 +00:00
if ( in - > format = = AV_PIX_FMT_YUV444P )
ctx - > internal - > execute ( ctx , process_slice_yuv444p , & td , NULL ,
2016-08-27 20:44:42 +00:00
FFMIN ( in - > height , ff_filter_get_nb_threads ( ctx ) ) ) ;
2015-07-06 14:07:52 +00:00
else if ( in - > format = = AV_PIX_FMT_YUV422P )
2015-03-10 05:01:47 +00:00
ctx - > internal - > execute ( ctx , process_slice_yuv422p , & td , NULL ,
2016-08-27 20:44:42 +00:00
FFMIN ( in - > height , ff_filter_get_nb_threads ( ctx ) ) ) ;
2012-11-29 01:04:45 +00:00
else if ( in - > format = = AV_PIX_FMT_YUV420P )
2015-03-10 05:01:47 +00:00
ctx - > internal - > execute ( ctx , process_slice_yuv420p , & td , NULL ,
2016-08-27 20:44:42 +00:00
FFMIN ( in - > height / 2 , ff_filter_get_nb_threads ( ctx ) ) ) ;
2012-03-10 03:04:19 +00:00
else
2015-03-10 05:01:47 +00:00
ctx - > internal - > execute ( ctx , process_slice_uyvy422 , & td , NULL ,
2016-08-27 20:44:42 +00:00
FFMIN ( in - > height , ff_filter_get_nb_threads ( ctx ) ) ) ;
2012-03-10 03:04:19 +00:00
2013-03-10 00:30:30 +00:00
av_frame_free ( & in ) ;
2012-11-29 01:04:45 +00:00
return ff_filter_frame ( outlink , out ) ;
2012-03-10 03:04:19 +00:00
}
2012-11-28 19:01:59 +00:00
static const AVFilterPad colormatrix_inputs [ ] = {
{
2013-09-07 12:13:50 +00:00
. name = " default " ,
. type = AVMEDIA_TYPE_VIDEO ,
. config_props = config_input ,
. filter_frame = filter_frame ,
2012-11-28 19:01:59 +00:00
} ,
{ NULL }
} ;
static const AVFilterPad colormatrix_outputs [ ] = {
{
. name = " default " ,
. type = AVMEDIA_TYPE_VIDEO ,
} ,
{ NULL }
} ;
2021-04-19 16:33:56 +00:00
const AVFilter ff_vf_colormatrix = {
2012-03-10 03:04:19 +00:00
. name = " colormatrix " ,
2013-03-24 12:40:57 +00:00
. description = NULL_IF_CONFIG_SMALL ( " Convert color matrix. " ) ,
2012-03-10 03:04:19 +00:00
. priv_size = sizeof ( ColorMatrixContext ) ,
. init = init ,
. query_formats = query_formats ,
2012-11-28 19:01:59 +00:00
. inputs = colormatrix_inputs ,
. outputs = colormatrix_outputs ,
2013-03-24 12:40:57 +00:00
. priv_class = & colormatrix_class ,
2015-03-10 05:01:47 +00:00
. flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS ,
2012-03-10 03:04:19 +00:00
} ;