Commit 2ec88591 authored by Yoann Peronneau's avatar Yoann Peronneau

* src/video_output/video_widgets.c: now uses blend() for OSD widgets.

parent 5aa8d01f
......@@ -28,23 +28,18 @@
#include <vlc/vout.h>
#include <osd.h>
#include "vlc_video.h"
#include "vlc_filter.h"
#define STYLE_EMPTY 0
#define STYLE_FILLED 1
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static void DrawRect( vout_thread_t *, subpicture_t *, int, int, int, int,
short );
static void DrawTriangle( vout_thread_t *, subpicture_t *, int, int, int, int,
short );
static void Render ( vout_thread_t *, picture_t *, const subpicture_t * );
static void RenderI420( vout_thread_t *, picture_t *, const subpicture_t *,
int );
static void RenderYUY2( vout_thread_t *, picture_t *, const subpicture_t *,
int );
static void RenderRV32( vout_thread_t *, picture_t *, const subpicture_t *,
int );
static void DrawRect( subpicture_t *, int, int, int, int, short );
static void DrawTriangle( subpicture_t *, int, int, int, int, short );
static void CreatePicture( vout_thread_t *, subpicture_t * );
static subpicture_t *vout_CreateWidget( vout_thread_t *, int );
static void FreeWidget( subpicture_t * );
......@@ -57,18 +52,18 @@ struct subpicture_sys_t
int i_y;
int i_width;
int i_height;
uint8_t *p_pic;
};
/*****************************************************************************
* Draws a rectangle at the given position in the subpic.
* It may be filled (fill == STYLE_FILLED) or empty (fill == STYLE_EMPTY).
*****************************************************************************/
static void DrawRect( vout_thread_t *p_vout, subpicture_t *p_subpic,
int i_x1, int i_y1, int i_x2, int i_y2, short fill )
static void DrawRect( subpicture_t *p_subpic, int i_x1, int i_y1,
int i_x2, int i_y2, short fill )
{
int x, y;
subpicture_sys_t *p_widget = p_subpic->p_sys;
uint8_t *p_a = p_subpic->p_region->picture.A_PIXELS;
int i_pitch = p_subpic->p_region->picture.Y_PITCH;
if( fill == STYLE_FILLED )
{
......@@ -76,7 +71,7 @@ static void DrawRect( vout_thread_t *p_vout, subpicture_t *p_subpic,
{
for( x = i_x1; x <= i_x2; x++ )
{
p_widget->p_pic[ x + p_widget->i_width * y ] = 1;
p_a[ x + i_pitch * y ] = 0xff;
}
}
}
......@@ -84,13 +79,13 @@ static void DrawRect( vout_thread_t *p_vout, subpicture_t *p_subpic,
{
for( y = i_y1; y <= i_y2; y++ )
{
p_widget->p_pic[ i_x1 + p_widget->i_width * y ] = 1;
p_widget->p_pic[ i_x2 + p_widget->i_width * y ] = 1;
p_a[ i_x1 + i_pitch * y ] = 0xff;
p_a[ i_x2 + i_pitch * y ] = 0xff;
}
for( x = i_x1; x <= i_x2; x++ )
{
p_widget->p_pic[ x + p_widget->i_width * i_y1 ] = 1;
p_widget->p_pic[ x + p_widget->i_width * i_y2 ] = 1;
p_a[ x + i_pitch * i_y1 ] = 0xff;
p_a[ x + i_pitch * i_y2 ] = 0xff;
}
}
}
......@@ -99,11 +94,12 @@ static void DrawRect( vout_thread_t *p_vout, subpicture_t *p_subpic,
* Draws a triangle at the given position in the subpic.
* It may be filled (fill == STYLE_FILLED) or empty (fill == STYLE_EMPTY).
*****************************************************************************/
static void DrawTriangle( vout_thread_t *p_vout, subpicture_t *p_subpic,
int i_x1, int i_y1, int i_x2, int i_y2, short fill )
static void DrawTriangle( subpicture_t *p_subpic, int i_x1, int i_y1,
int i_x2, int i_y2, short fill )
{
int x, y, i_mid, h;
subpicture_sys_t *p_widget = p_subpic->p_sys;
uint8_t *p_a = p_subpic->p_region->picture.A_PIXELS;
int i_pitch = p_subpic->p_region->picture.Y_PITCH;
i_mid = i_y1 + ( ( i_y2 - i_y1 ) >> 1 );
......@@ -116,8 +112,8 @@ static void DrawTriangle( vout_thread_t *p_vout, subpicture_t *p_subpic,
h = y - i_y1;
for( x = i_x1; x <= i_x1 + h && x <= i_x2; x++ )
{
p_widget->p_pic[ x + p_widget->i_width * y ] = 1;
p_widget->p_pic[ x + p_widget->i_width * ( i_y2 - h ) ] = 1;
p_a[ x + i_pitch * y ] = 0xff;
p_a[ x + i_pitch * ( i_y2 - h ) ] = 0xff;
}
}
}
......@@ -126,10 +122,10 @@ static void DrawTriangle( vout_thread_t *p_vout, subpicture_t *p_subpic,
for( y = i_y1; y <= i_mid; y++ )
{
h = y - i_y1;
p_widget->p_pic[ i_x1 + p_widget->i_width * y ] = 1;
p_widget->p_pic[ i_x1 + h + p_widget->i_width * y ] = 1;
p_widget->p_pic[ i_x1 + p_widget->i_width * ( i_y2 - h ) ] = 1;
p_widget->p_pic[ i_x1 + h + p_widget->i_width * ( i_y2 - h ) ] = 1;
p_a[ i_x1 + i_pitch * y ] = 0xff;
p_a[ i_x1 + h + i_pitch * y ] = 0xff;
p_a[ i_x1 + i_pitch * ( i_y2 - h ) ] = 0xff;
p_a[ i_x1 + h + i_pitch * ( i_y2 - h ) ] = 0xff;
}
}
}
......@@ -142,8 +138,8 @@ static void DrawTriangle( vout_thread_t *p_vout, subpicture_t *p_subpic,
h = y - i_y1;
for( x = i_x1; x >= i_x1 - h && x >= i_x2; x-- )
{
p_widget->p_pic[ x + p_widget->i_width * y ] = 1;
p_widget->p_pic[ x + p_widget->i_width * ( i_y2 - h ) ] = 1;
p_a[ x + i_pitch * y ] = 0xff;
p_a[ x + i_pitch * ( i_y2 - h ) ] = 0xff;
}
}
}
......@@ -152,221 +148,53 @@ static void DrawTriangle( vout_thread_t *p_vout, subpicture_t *p_subpic,
for( y = i_y1; y <= i_mid; y++ )
{
h = y - i_y1;
p_widget->p_pic[ i_x1 + p_widget->i_width * y ] = 1;
p_widget->p_pic[ i_x1 - h + p_widget->i_width * y ] = 1;
p_widget->p_pic[ i_x1 + p_widget->i_width * ( i_y2 - h ) ] = 1;
p_widget->p_pic[ i_x1 - h + p_widget->i_width * ( i_y2 - h ) ] = 1;
p_a[ i_x1 + i_pitch * y ] = 0xff;
p_a[ i_x1 - h + i_pitch * y ] = 0xff;
p_a[ i_x1 + i_pitch * ( i_y2 - h ) ] = 0xff;
p_a[ i_x1 - h + i_pitch * ( i_y2 - h ) ] = 0xff;
}
}
}
}
/*****************************************************************************
* Render: place widget in picture
*****************************************************************************
* This function merges the previously drawn widget into a picture
* Create Picture: creates subpicture region and picture
*****************************************************************************/
static void Render( vout_thread_t *p_vout, picture_t *p_pic,
const subpicture_t *p_subpic )
{
int i_fade_alpha = 255;
mtime_t i_fade_start = ( p_subpic->i_stop + p_subpic->i_start ) / 2;
mtime_t i_now = mdate();
if( i_now >= i_fade_start )
{
i_fade_alpha = 255 * ( p_subpic->i_stop - i_now ) /
( p_subpic->i_stop - i_fade_start );
}
switch( p_vout->output.i_chroma )
{
/* I420 target, no scaling */
case VLC_FOURCC('I','4','2','0'):
case VLC_FOURCC('I','Y','U','V'):
case VLC_FOURCC('Y','V','1','2'):
RenderI420( p_vout, p_pic, p_subpic, i_fade_alpha );
break;
/* RV32 target, scaling */
case VLC_FOURCC('R','V','2','4'):
case VLC_FOURCC('R','V','3','2'):
RenderRV32( p_vout, p_pic, p_subpic, i_fade_alpha );
break;
/* NVidia or BeOS overlay, no scaling */
case VLC_FOURCC('Y','U','Y','2'):
RenderYUY2( p_vout, p_pic, p_subpic, i_fade_alpha );
break;
default:
msg_Err( p_vout, "unknown chroma, can't render SPU" );
break;
}
}
/**
* Draw a widget on a I420 (or similar) picture
*/
static void RenderI420( vout_thread_t *p_vout, picture_t *p_pic,
const subpicture_t *p_subpic, int i_fade_alpha )
static void CreatePicture( vout_thread_t *p_vout, subpicture_t *p_subpic )
{
subpicture_sys_t *p_widget = p_subpic->p_sys;
int i_plane, x, y, pen_x, pen_y;
for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
{
uint8_t *p_in = p_pic->p[ i_plane ].p_pixels;
int i_pic_pitch = p_pic->p[ i_plane ].i_pitch;
if ( i_plane == 0 )
{
pen_x = p_widget->i_x;
pen_y = p_widget->i_y;
#define alpha p_widget->p_pic[ x + y * p_widget->i_width ] * i_fade_alpha
#define pixel p_in[ ( pen_y + y ) * i_pic_pitch + pen_x + x ]
for( y = 0; y < p_widget->i_height; y++ )
{
for( x = 0; x < p_widget->i_width; x++ )
{
if( alpha == 0 ) continue;
pen_y--;
pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
pen_y++; pen_x--;
pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
pen_x += 2;
pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
pen_y++; pen_x--;
pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
pen_y--;
}
}
for( y = 0; y < p_widget->i_height; y++ )
{
for( x = 0; x < p_widget->i_width; x++ )
{
pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 ) +
( 255 * alpha >> 8 );
}
}
#undef alpha
#undef pixel
}
else
{
pen_x = p_widget->i_x >> 1;
pen_y = p_widget->i_y >> 1;
#define alpha p_widget->p_pic[ x + y * p_widget->i_width ] * i_fade_alpha
#define pixel p_in[ ( pen_y + (y >> 1) ) * i_pic_pitch + pen_x + (x >> 1) ]
for( y = 0; y < p_widget->i_height; y+=2 )
{
for( x = 0; x < p_widget->i_width; x+=2 )
{
if( alpha == 0 ) continue;
pixel = ( ( pixel * ( 0xFF - alpha ) ) >> 8 ) +
( 0x80 * alpha >> 8 );
}
}
#undef alpha
#undef pixel
}
spu_t *p_spu = p_vout->p_spu;
uint8_t *p_y, *p_u, *p_v, *p_a;
video_format_t fmt;
int i_pitch;
/* Create a new subpicture region */
memset( &fmt, 0, sizeof(video_format_t) );
fmt.i_chroma = VLC_FOURCC('Y','U','V','A');
fmt.i_aspect = VOUT_ASPECT_FACTOR;
fmt.i_width = fmt.i_visible_width = p_widget->i_width;
fmt.i_height = fmt.i_visible_height = p_widget->i_height;
fmt.i_x_offset = fmt.i_y_offset = 0;
p_subpic->p_region = p_subpic->pf_create_region( VLC_OBJECT(p_spu), &fmt );
if( !p_subpic->p_region )
{
msg_Err( p_spu, "cannot allocate SPU region" );
return;
}
}
/**
* Draw a widget on a YUY2 picture
*/
static void RenderYUY2( vout_thread_t *p_vout, picture_t *p_pic,
const subpicture_t *p_subpic, int i_fade_alpha )
{
subpicture_sys_t *p_widget = p_subpic->p_sys;
int x, y, pen_x, pen_y;
uint8_t *p_in = p_pic->p[0].p_pixels;
int i_pic_pitch = p_pic->p[0].i_pitch;
pen_x = p_widget->i_x;
pen_y = p_widget->i_y;
#define alpha p_widget->p_pic[ x + y * p_widget->i_width ] * i_fade_alpha
#define pixel p_in[ ( pen_y + y ) * i_pic_pitch + 2 * ( pen_x + x ) ]
for( y = 0; y < p_widget->i_height; y++ )
{
for( x = 0; x < p_widget->i_width; x++ )
{
pen_y--;
pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
pen_y++; pen_x--;
pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
pen_x += 2;
pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
pen_y++; pen_x--;
pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
pen_y--;
}
}
for( y = 0; y < p_widget->i_height; y++ )
{
for( x = 0; x < p_widget->i_width; x++ )
{
pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 ) +
( 255 * alpha >> 8 );
}
}
#undef alpha
#undef pixel
}
p_subpic->p_region->i_x = p_widget->i_x;
p_subpic->p_region->i_y = p_widget->i_y;
p_y = p_subpic->p_region->picture.Y_PIXELS;
p_u = p_subpic->p_region->picture.U_PIXELS;
p_v = p_subpic->p_region->picture.V_PIXELS;
p_a = p_subpic->p_region->picture.A_PIXELS;
i_pitch = p_subpic->p_region->picture.Y_PITCH;
/**
* Draw a widget on a RV32 picture
*/
static void RenderRV32( vout_thread_t *p_vout, picture_t *p_pic,
const subpicture_t *p_subpic, int i_fade_alpha )
{
subpicture_sys_t *p_widget = p_subpic->p_sys;
int x, y, pen_x, pen_y;
uint8_t *p_in = p_pic->p[0].p_pixels;
int i_pic_pitch = p_pic->p[0].i_pitch;
pen_x = p_widget->i_x;
pen_y = p_widget->i_y;
#define alpha p_widget->p_pic[ x + y * p_widget->i_width ] * i_fade_alpha
#define pixel( c ) p_in[ ( pen_y + y ) * i_pic_pitch + 4 * ( pen_x + x ) + c ]
for(y = 0; y < p_widget->i_height; y++ )
{
for( x = 0; x < p_widget->i_width; x++ )
{
pen_y--;
pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 );
pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 );
pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 );
pen_y++; pen_x--;
pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 );
pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 );
pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 );
pen_x += 2;
pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 );
pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 );
pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 );
pen_y++; pen_x--;
pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 );
pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 );
pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 );
pen_y--;
}
}
for(y = 0; y < p_widget->i_height; y++ )
{
for( x = 0; x < p_widget->i_width; x++ )
{
pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 ) +
( 255 * alpha >> 8 );
pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 ) +
( 255 * alpha >> 8 );
pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 ) +
( 255 * alpha >> 8 );
}
}
#undef alpha
#undef pixel
/* Initialize the region pixels (only the alpha will be changed later) */
memset( p_y, 0xff, i_pitch * p_subpic->p_region->fmt.i_height );
memset( p_u, 0x80, i_pitch * p_subpic->p_region->fmt.i_height );
memset( p_v, 0x80, i_pitch * p_subpic->p_region->fmt.i_height );
memset( p_a, 0x00, i_pitch * p_subpic->p_region->fmt.i_height );
}
/*****************************************************************************
......@@ -388,7 +216,6 @@ subpicture_t *vout_CreateWidget( vout_thread_t *p_vout, int i_channel )
return NULL;
}
p_subpic->i_channel = i_channel;
p_subpic->pf_render = Render;
p_subpic->pf_destroy = FreeWidget;
p_subpic->i_start = i_now;
p_subpic->i_stop = i_now + 1200000;
......@@ -450,35 +277,28 @@ void vout_OSDSlider( vlc_object_t *p_caller, int i_channel, int i_position,
p_widget->i_y = i_y_margin;
}
p_widget->p_pic = (uint8_t *)malloc( p_widget->i_width *
p_widget->i_height );
if( p_widget->p_pic == NULL )
{
FreeWidget( p_subpic );
spu_DestroySubpicture( p_vout->p_spu, p_subpic );
return;
}
memset( p_widget->p_pic, 0, p_widget->i_width * p_widget->i_height );
/* Create subpicture region and picture */
CreatePicture( p_vout, p_subpic );
if( i_type == OSD_HOR_SLIDER )
{
int i_x_pos = ( p_widget->i_width - 2 ) * i_position / 100;
DrawRect( p_vout, p_subpic, i_x_pos - 1, 2, i_x_pos + 1,
DrawRect( p_subpic, i_x_pos - 1, 2, i_x_pos + 1,
p_widget->i_height - 3, STYLE_FILLED );
DrawRect( p_vout, p_subpic, 0, 0, p_widget->i_width - 1,
DrawRect( p_subpic, 0, 0, p_widget->i_width - 1,
p_widget->i_height - 1, STYLE_EMPTY );
}
else if( i_type == OSD_VERT_SLIDER )
{
int i_y_pos = p_widget->i_height / 2;
DrawRect( p_vout, p_subpic, 2, p_widget->i_height -
DrawRect( p_subpic, 2, p_widget->i_height -
( p_widget->i_height - 2 ) * i_position / 100,
p_widget->i_width - 3, p_widget->i_height - 3,
STYLE_FILLED );
DrawRect( p_vout, p_subpic, 1, i_y_pos, 1, i_y_pos, STYLE_FILLED );
DrawRect( p_vout, p_subpic, p_widget->i_width - 2, i_y_pos,
DrawRect( p_subpic, 1, i_y_pos, 1, i_y_pos, STYLE_FILLED );
DrawRect( p_subpic, p_widget->i_width - 2, i_y_pos,
p_widget->i_width - 2, i_y_pos, STYLE_FILLED );
DrawRect( p_vout, p_subpic, 0, 0, p_widget->i_width - 1,
DrawRect( p_subpic, 0, 0, p_widget->i_width - 1,
p_widget->i_height - 1, STYLE_EMPTY );
}
......@@ -520,22 +340,15 @@ void vout_OSDIcon( vlc_object_t *p_caller, int i_channel, short i_type )
p_widget->i_width;
p_widget->i_y = i_y_margin;
p_widget->p_pic = (uint8_t *)malloc( p_widget->i_width *
p_widget->i_height );
if( p_widget->p_pic == NULL )
{
FreeWidget( p_subpic );
spu_DestroySubpicture( p_vout->p_spu, p_subpic );
return;
}
memset( p_widget->p_pic, 0, p_widget->i_width * p_widget->i_height );
/* Create subpicture region and picture */
CreatePicture( p_vout, p_subpic );
if( i_type == OSD_PAUSE_ICON )
{
int i_bar_width = p_widget->i_width / 3;
DrawRect( p_vout, p_subpic, 0, 0, i_bar_width - 1,
DrawRect( p_subpic, 0, 0, i_bar_width - 1,
p_widget->i_height - 1, STYLE_FILLED );
DrawRect( p_vout, p_subpic, p_widget->i_width - i_bar_width, 0,
DrawRect( p_subpic, p_widget->i_width - i_bar_width, 0,
p_widget->i_width - 1, p_widget->i_height - 1, STYLE_FILLED );
}
else if( i_type == OSD_PLAY_ICON )
......@@ -543,26 +356,27 @@ void vout_OSDIcon( vlc_object_t *p_caller, int i_channel, short i_type )
int i_mid = p_widget->i_height >> 1;
int i_delta = ( p_widget->i_width - i_mid ) >> 1;
int i_y2 = ( ( p_widget->i_height - 1 ) >> 1 ) * 2;
DrawTriangle( p_vout, p_subpic, i_delta, 0,
p_widget->i_width - i_delta, i_y2, STYLE_FILLED );
DrawTriangle( p_subpic, i_delta, 0, p_widget->i_width - i_delta, i_y2,
STYLE_FILLED );
}
else if( i_type == OSD_SPEAKER_ICON || i_type == OSD_MUTE_ICON )
{
int i_mid = p_widget->i_height >> 1;
int i_delta = ( p_widget->i_width - i_mid ) >> 1;
int i_y2 = ( ( p_widget->i_height - 1 ) >> 1 ) * 2;
DrawRect( p_vout, p_subpic, i_delta, i_mid / 2,
p_widget->i_width - i_delta,
DrawRect( p_subpic, i_delta, i_mid / 2, p_widget->i_width - i_delta,
p_widget->i_height - 1 - i_mid / 2, STYLE_FILLED );
DrawTriangle( p_vout, p_subpic, p_widget->i_width - i_delta, 0,
i_delta, i_y2, STYLE_FILLED );
DrawTriangle( p_subpic, p_widget->i_width - i_delta, 0, i_delta, i_y2,
STYLE_FILLED );
if( i_type == OSD_MUTE_ICON )
{
uint8_t *p_a = p_subpic->p_region->picture.A_PIXELS;
int i_pitch = p_subpic->p_region->picture.Y_PITCH;
int i;
for( i = 1; i < p_widget->i_width; i++ )
for( i = 1; i < i_pitch; i++ )
{
int k = i + ( p_widget->i_height - i - 1 ) * p_widget->i_width;
p_widget->p_pic[ k ] = 1 - p_widget->p_pic[ k ];
int k = i + ( p_widget->i_height - i - 1 ) * i_pitch;
p_a[ k ] = 0xff - p_a[ k ];
}
}
}
......@@ -582,9 +396,5 @@ static void FreeWidget( subpicture_t *p_subpic )
if( p_subpic->p_sys == NULL ) return;
if( p_widget->p_pic != NULL )
{
free( p_widget->p_pic );
}
free( p_widget );
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment