@ -26,11 +26,15 @@ enum { RED = 0, GREEN, BLUE, ALPHA };
int ff_fill_rgba_map ( uint8_t * rgba_map , enum PixelFormat pix_fmt )
{
switch ( pix_fmt ) {
case PIX_FMT_0RGB :
case PIX_FMT_ARGB : rgba_map [ ALPHA ] = 0 ; rgba_map [ RED ] = 1 ; rgba_map [ GREEN ] = 2 ; rgba_map [ BLUE ] = 3 ; break ;
case PIX_FMT_0BGR :
case PIX_FMT_ABGR : rgba_map [ ALPHA ] = 0 ; rgba_map [ BLUE ] = 1 ; rgba_map [ GREEN ] = 2 ; rgba_map [ RED ] = 3 ; break ;
case PIX_FMT_RGB0 :
case PIX_FMT_RGBA :
case PIX_FMT_RGB24 : rgba_map [ RED ] = 0 ; rgba_map [ GREEN ] = 1 ; rgba_map [ BLUE ] = 2 ; rgba_map [ ALPHA ] = 3 ; break ;
case PIX_FMT_BGRA :
case PIX_FMT_BGR0 :
case PIX_FMT_BGR24 : rgba_map [ BLUE ] = 0 ; rgba_map [ GREEN ] = 1 ; rgba_map [ RED ] = 2 ; rgba_map [ ALPHA ] = 3 ; break ;
default : /* unsupported */
return AVERROR ( EINVAL ) ;
@ -120,3 +124,189 @@ void ff_copy_rectangle(uint8_t *dst[4], int dst_linesize[4],
}
}
}
int ff_draw_init ( FFDrawContext * draw , enum PixelFormat format , unsigned flags )
{
const AVPixFmtDescriptor * desc = & av_pix_fmt_descriptors [ format ] ;
const AVComponentDescriptor * c ;
unsigned i , nb_planes = 0 ;
int pixelstep [ MAX_PLANES ] = { 0 } ;
if ( desc - > flags & ~ ( PIX_FMT_PLANAR | PIX_FMT_RGB ) )
return AVERROR ( ENOSYS ) ;
for ( i = 0 ; i < desc - > nb_components ; i + + ) {
c = & desc - > comp [ i ] ;
/* for now, only 8-bits formats */
if ( c - > depth_minus1 ! = 8 - 1 )
return AVERROR ( ENOSYS ) ;
if ( c - > plane > = MAX_PLANES )
return AVERROR ( ENOSYS ) ;
/* strange interleaving */
if ( pixelstep [ c - > plane ] ! = 0 & &
pixelstep [ c - > plane ] ! = c - > step_minus1 + 1 )
return AVERROR ( ENOSYS ) ;
pixelstep [ c - > plane ] = c - > step_minus1 + 1 ;
nb_planes = FFMAX ( nb_planes , c - > plane + 1 ) ;
}
if ( ( desc - > log2_chroma_w | | desc - > log2_chroma_h ) & & nb_planes < 3 )
return AVERROR ( ENOSYS ) ; /* exclude NV12 and NV21 */
memset ( draw , 0 , sizeof ( * draw ) ) ;
draw - > desc = desc ;
draw - > format = format ;
draw - > nb_planes = nb_planes ;
memcpy ( draw - > pixelstep , pixelstep , sizeof ( draw - > pixelstep ) ) ;
if ( nb_planes > = 3 & & ! ( desc - > flags & PIX_FMT_RGB ) ) {
draw - > hsub [ 1 ] = draw - > hsub [ 2 ] = draw - > hsub_max = desc - > log2_chroma_w ;
draw - > vsub [ 1 ] = draw - > vsub [ 2 ] = draw - > vsub_max = desc - > log2_chroma_h ;
}
return 0 ;
}
void ff_draw_color ( FFDrawContext * draw , FFDrawColor * color , uint8_t rgba [ 4 ] )
{
unsigned i ;
uint8_t rgba_map [ 4 ] ;
if ( ( draw - > desc - > flags & PIX_FMT_RGB ) & & draw - > nb_planes = = 1 & &
ff_fill_rgba_map ( rgba_map , draw - > format ) > = 0 ) {
for ( i = 0 ; i < 4 ; i + + )
color - > comp [ 0 ] . u8 [ rgba_map [ i ] ] = rgba [ i ] ;
} else if ( draw - > nb_planes = = 3 | | draw - > nb_planes = = 4 ) {
/* assume YUV */
color - > comp [ 0 ] . u8 [ 0 ] = RGB_TO_Y_CCIR ( rgba [ 0 ] , rgba [ 1 ] , rgba [ 2 ] ) ;
color - > comp [ 1 ] . u8 [ 0 ] = RGB_TO_U_CCIR ( rgba [ 0 ] , rgba [ 1 ] , rgba [ 2 ] , 0 ) ;
color - > comp [ 2 ] . u8 [ 0 ] = RGB_TO_V_CCIR ( rgba [ 0 ] , rgba [ 1 ] , rgba [ 2 ] , 0 ) ;
color - > comp [ 3 ] . u8 [ 0 ] = rgba [ 3 ] ;
} else if ( draw - > format = = PIX_FMT_GRAY8 | | draw - > format = = PIX_FMT_GRAY8A ) {
color - > comp [ 0 ] . u8 [ 0 ] = RGB_TO_Y_CCIR ( rgba [ 0 ] , rgba [ 1 ] , rgba [ 2 ] ) ;
color - > comp [ 1 ] . u8 [ 0 ] = rgba [ 3 ] ;
} else {
av_log ( NULL , AV_LOG_WARNING ,
" Color conversion not implemented for %s \n " , draw - > desc - > name ) ;
memset ( color , 128 , sizeof ( * color ) ) ;
}
}
static uint8_t * pointer_at ( FFDrawContext * draw , uint8_t * data [ ] , int linesize [ ] ,
int plane , int x , int y )
{
return data [ plane ] +
( y > > draw - > vsub [ plane ] ) * linesize [ plane ] +
( x > > draw - > hsub [ plane ] ) * draw - > pixelstep [ plane ] ;
}
void ff_copy_rectangle2 ( FFDrawContext * draw ,
uint8_t * dst [ ] , int dst_linesize [ ] ,
uint8_t * src [ ] , int src_linesize [ ] ,
int dst_x , int dst_y , int src_x , int src_y ,
int w , int h )
{
int plane , y , wp , hp ;
uint8_t * p , * q ;
for ( plane = 0 ; plane < draw - > nb_planes ; plane + + ) {
p = pointer_at ( draw , src , src_linesize , plane , src_x , src_y ) ;
q = pointer_at ( draw , dst , dst_linesize , plane , dst_x , dst_y ) ;
wp = ( w > > draw - > hsub [ plane ] ) * draw - > pixelstep [ plane ] ;
hp = ( h > > draw - > vsub [ plane ] ) ;
for ( y = 0 ; y < hp ; y + + ) {
memcpy ( q , p , wp ) ;
p + = src_linesize [ plane ] ;
q + = dst_linesize [ plane ] ;
}
}
}
void ff_fill_rectangle ( FFDrawContext * draw , FFDrawColor * color ,
uint8_t * dst [ ] , int dst_linesize [ ] ,
int dst_x , int dst_y , int w , int h )
{
int plane , x , y , wp , hp ;
uint8_t * p0 , * p ;
for ( plane = 0 ; plane < draw - > nb_planes ; plane + + ) {
p0 = pointer_at ( draw , dst , dst_linesize , plane , dst_x , dst_y ) ;
wp = ( w > > draw - > hsub [ plane ] ) ;
hp = ( h > > draw - > vsub [ plane ] ) ;
if ( ! hp )
return ;
p = p0 ;
/* copy first line from color */
for ( x = 0 ; x < wp ; x + + ) {
memcpy ( p , color - > comp [ plane ] . u8 , draw - > pixelstep [ plane ] ) ;
p + = draw - > pixelstep [ plane ] ;
}
wp * = draw - > pixelstep [ plane ] ;
/* copy next lines from first line */
p = p0 + dst_linesize [ plane ] ;
for ( y = 1 ; y < hp ; y + + ) {
memcpy ( p , p0 , wp ) ;
p + = dst_linesize [ plane ] ;
}
}
}
int ff_draw_round_to_sub ( FFDrawContext * draw , int sub_dir , int round_dir ,
int value )
{
unsigned shift = sub_dir ? draw - > vsub_max : draw - > hsub_max ;
if ( ! shift )
return value ;
if ( round_dir > = 0 )
value + = round_dir ? ( 1 < < shift ) - 1 : 1 < < ( shift - 1 ) ;
return ( value > > shift ) < < shift ;
}
AVFilterFormats * ff_draw_supported_pixel_formats ( unsigned flags )
{
enum PixelFormat i , pix_fmts [ PIX_FMT_NB + 1 ] ;
unsigned n = 0 ;
FFDrawContext draw ;
for ( i = 0 ; i < PIX_FMT_NB ; i + + )
if ( ff_draw_init ( & draw , i , flags ) > = 0 )
pix_fmts [ n + + ] = i ;
pix_fmts [ n + + ] = PIX_FMT_NONE ;
return avfilter_make_format_list ( pix_fmts ) ;
}
# ifdef TEST
# undef printf
int main ( void )
{
enum PixelFormat f ;
const AVPixFmtDescriptor * desc ;
FFDrawContext draw ;
FFDrawColor color ;
int r , i ;
for ( f = 0 ; f < PIX_FMT_NB ; f + + ) {
desc = & av_pix_fmt_descriptors [ f ] ;
if ( ! desc - > name )
continue ;
printf ( " Testing %s...%*s " , desc - > name ,
( int ) ( 16 - strlen ( desc - > name ) ) , " " ) ;
r = ff_draw_init ( & draw , f , 0 ) ;
if ( r < 0 ) {
char buf [ 128 ] ;
av_strerror ( r , buf , sizeof ( buf ) ) ;
printf ( " no: %s \n " , buf ) ;
continue ;
}
ff_draw_color ( & draw , & color , ( uint8_t [ ] ) { 1 , 0 , 0 , 1 } ) ;
for ( i = 0 ; i < sizeof ( color ) ; i + + )
if ( ( ( uint8_t * ) & color ) [ i ] ! = 128 )
break ;
if ( i = = sizeof ( color ) ) {
printf ( " fallback color \n " ) ;
continue ;
}
printf ( " ok \n " ) ;
}
return 0 ;
}
# endif