Commit de53ab42 authored by Laurent Aimar's avatar Laurent Aimar

Used subpicture_updater_t for vout_OSDSlider/Icon.

parent 2991f900
......@@ -5,6 +5,7 @@
* $Id$
*
* Author: Yoann Peronneau <yoann@videolan.org>
* Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
*
* 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
......@@ -35,339 +36,289 @@
#include <vlc_filter.h>
/* TODO remove access to private vout data */
#include "vout_internal.h"
#define STYLE_EMPTY 0
#define STYLE_FILLED 1
/*****************************************************************************
* Draws a rectangle at the given position in the subpic.
/**
* Draws a rectangle at the given position in the region.
* It may be filled (fill == STYLE_FILLED) or empty (fill == STYLE_EMPTY).
*****************************************************************************/
static void DrawRect( subpicture_t *p_subpic, int i_x1, int i_y1,
int i_x2, int i_y2, short fill )
*/
static void DrawRect(subpicture_region_t *r, int fill,
int x1, int y1, int x2, int y2)
{
int x, y;
uint8_t *p_a = p_subpic->p_region->p_picture->A_PIXELS;
int i_pitch = p_subpic->p_region->p_picture->Y_PITCH;
if( fill == STYLE_FILLED )
{
for( y = i_y1; y <= i_y2; y++ )
{
for( x = i_x1; x <= i_x2; x++ )
{
p_a[ x + i_pitch * y ] = 0xff;
}
uint8_t *a = r->p_picture->A_PIXELS;
int pitch = r->p_picture->A_PITCH;
if (fill == STYLE_FILLED) {
for (int y = y1; y <= y2; y++) {
for (int x = x1; x <= x2; x++)
a[x + pitch * y] = 0xff;
}
}
else
{
for( y = i_y1; y <= i_y2; y++ )
{
p_a[ i_x1 + i_pitch * y ] = 0xff;
p_a[ i_x2 + i_pitch * y ] = 0xff;
} else {
for (int y = y1; y <= y2; y++) {
a[x1 + pitch * y] = 0xff;
a[x2 + pitch * y] = 0xff;
}
for( x = i_x1; x <= i_x2; x++ )
{
p_a[ x + i_pitch * i_y1 ] = 0xff;
p_a[ x + i_pitch * i_y2 ] = 0xff;
for (int x = x1; x <= x2; x++) {
a[x + pitch * y1] = 0xff;
a[x + pitch * y2] = 0xff;
}
}
}
/*****************************************************************************
* Draws a triangle at the given position in the subpic.
/**
* Draws a triangle at the given position in the region.
* It may be filled (fill == STYLE_FILLED) or empty (fill == STYLE_EMPTY).
*****************************************************************************/
static void DrawTriangle( subpicture_t *p_subpic, int i_x1, int i_y1,
int i_x2, int i_y2, short fill )
*/
static void DrawTriangle(subpicture_region_t *r, int fill,
int x1, int y1, int x2, int y2)
{
int x, y, i_mid, h;
uint8_t *p_a = p_subpic->p_region->p_picture->A_PIXELS;
int i_pitch = p_subpic->p_region->p_picture->Y_PITCH;
i_mid = i_y1 + ( ( i_y2 - i_y1 ) >> 1 );
if( i_x2 >= i_x1 )
{
if( fill == STYLE_FILLED )
{
for( y = i_y1; y <= i_mid; y++ )
{
h = y - i_y1;
for( x = i_x1; x <= i_x1 + h && x <= i_x2; x++ )
{
p_a[ x + i_pitch * y ] = 0xff;
p_a[ x + i_pitch * ( i_y2 - h ) ] = 0xff;
uint8_t *a = r->p_picture->A_PIXELS;
int pitch = r->p_picture->A_PITCH;
const int mid = y1 + (y2 - y1) / 2;
/* TODO factorize it */
if (x2 >= x1) {
if (fill == STYLE_FILLED) {
for (int y = y1; y <= mid; y++) {
int h = y - y1;
for (int x = x1; x <= x1 + h && x <= x2; x++) {
a[x + pitch * y ] = 0xff;
a[x + pitch * (y2 - h)] = 0xff;
}
}
}
else
{
for( y = i_y1; y <= i_mid; y++ )
{
h = y - i_y1;
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;
} else {
for (int y = y1; y <= mid; y++) {
int h = y - y1;
a[x1 + pitch * y ] = 0xff;
a[x1 + h + pitch * y ] = 0xff;
a[x1 + pitch * (y2 - h)] = 0xff;
a[x1 + h + pitch * (y2 - h)] = 0xff;
}
}
}
else
{
if( fill == STYLE_FILLED )
{
for( y = i_y1; y <= i_mid; y++ )
{
h = y - i_y1;
for( x = i_x1; x >= i_x1 - h && x >= i_x2; x-- )
{
p_a[ x + i_pitch * y ] = 0xff;
p_a[ x + i_pitch * ( i_y2 - h ) ] = 0xff;
} else {
if( fill == STYLE_FILLED) {
for (int y = y1; y <= mid; y++) {
int h = y - y1;
for (int x = x1; x >= x1 - h && x >= x2; x--) {
a[x + pitch * y ] = 0xff;
a[x + pitch * (y2 - h)] = 0xff;
}
}
}
else
{
for( y = i_y1; y <= i_mid; y++ )
{
h = y - i_y1;
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;
} else {
for (int y = y1; y <= mid; y++) {
int h = y - y1;
a[ x1 + pitch * y ] = 0xff;
a[ x1 - h + pitch * y ] = 0xff;
a[ x1 + pitch * (y2 - h)] = 0xff;
a[ x1 - h + pitch * (y2 - h)] = 0xff;
}
}
}
}
/*****************************************************************************
* Create Picture: creates subpicture region and picture
*****************************************************************************/
static int CreatePicture( subpicture_t *p_subpic,
int i_x, int i_y, int i_width, int i_height )
/**
* Create a region with a white transparent picture.
*/
static subpicture_region_t *OSDRegion(int x, int y, int width, int height)
{
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_CODEC_YUVA;
fmt.i_width = fmt.i_visible_width = i_width;
fmt.i_height = fmt.i_visible_height = i_height;
fmt.i_x_offset = fmt.i_y_offset = 0;
p_subpic->p_region = subpicture_region_New( &fmt );
if( !p_subpic->p_region )
return VLC_EGENERIC;
p_subpic->p_region->i_x = i_x;
p_subpic->p_region->i_y = i_y;
p_y = p_subpic->p_region->p_picture->Y_PIXELS;
p_u = p_subpic->p_region->p_picture->U_PIXELS;
p_v = p_subpic->p_region->p_picture->V_PIXELS;
p_a = p_subpic->p_region->p_picture->A_PIXELS;
i_pitch = p_subpic->p_region->p_picture->Y_PITCH;
/* 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 );
return VLC_SUCCESS;
video_format_Init(&fmt, VLC_CODEC_YUVA);
fmt.i_width =
fmt.i_visible_width = width;
fmt.i_height =
fmt.i_visible_height = height;
fmt.i_sar_num = 0;
fmt.i_sar_den = 1;
subpicture_region_t *r = subpicture_region_New(&fmt);
if (!r)
return NULL;
r->i_x = x;
r->i_y = y;
for (int i = 0; i < r->p_picture->i_planes; i++) {
plane_t *p = &r->p_picture->p[i];
int colors[PICTURE_PLANE_MAX] = {
0xff, 0x80, 0x80, 0x00
};
memset(p->p_pixels, colors[i], p->i_pitch * height);
}
return r;
}
/*****************************************************************************
* Creates and initializes an OSD widget.
*****************************************************************************/
static subpicture_t *CreateWidget( int i_channel )
/**
* Create the region for an OSD slider.
* Types are: OSD_HOR_SLIDER and OSD_VERT_SLIDER.
*/
static subpicture_region_t *OSDSlider(int type, int position,
const video_format_t *fmt)
{
subpicture_t *p_subpic;
mtime_t i_now = mdate();
/* Create and initialize a subpicture */
p_subpic = subpicture_New( NULL );
if( p_subpic == NULL ) return NULL;
const int size = __MAX(fmt->i_visible_width, fmt->i_visible_height);
const int margin = size * 0.10;
p_subpic->i_channel = i_channel;
p_subpic->i_start = i_now;
p_subpic->i_stop = i_now + 1200000;
p_subpic->b_ephemer = true;
p_subpic->b_fade = true;
int x, y;
int width, height;
if (type == OSD_HOR_SLIDER) {
width = __MAX(fmt->i_visible_width - 2 * margin, 1);
height = __MAX(fmt->i_visible_height * 0.05, 1);
x = __MIN(fmt->i_x_offset + margin, fmt->i_visible_width - width);
y = __MAX(fmt->i_y_offset + fmt->i_visible_height - margin, 0);
} else {
width = __MAX(fmt->i_visible_width * 0.025, 1);
height = __MAX(fmt->i_visible_height - 2 * margin, 1);
x = __MAX(fmt->i_x_offset + fmt->i_visible_width - margin, 0);
y = __MIN(fmt->i_y_offset + margin, fmt->i_visible_height - height);
}
return p_subpic;
subpicture_region_t *r = OSDRegion(x, y, width, height);
if( !r)
return NULL;
if (type == OSD_HOR_SLIDER) {
int pos_x = (width - 2) * position / 100;
DrawRect(r, STYLE_FILLED, pos_x - 1, 2, pos_x + 1, height - 3);
DrawRect(r, STYLE_EMPTY, 0, 0, width - 1, height - 1);
} else {
int pos_mid = height / 2;
int pos_y = height - (height - 2) * position / 100;
DrawRect(r, STYLE_FILLED, 2, pos_y, width - 3, height - 3);
DrawRect(r, STYLE_FILLED, 1, pos_mid, 1, pos_mid );
DrawRect(r, STYLE_FILLED, width - 2, pos_mid, width - 2, pos_mid );
DrawRect(r, STYLE_EMPTY, 0, 0, width - 1, height - 1);
}
return r;
}
/*****************************************************************************
* Displays an OSD slider.
* Types are: OSD_HOR_SLIDER and OSD_VERT_SLIDER.
*****************************************************************************/
static int OsdSlider( spu_t *p_spu,
int i_render_width, int i_render_height,
int i_margin_left, int i_margin_bottom,
int i_channel, int i_position, short i_type )
/**
* Create the region for an OSD slider.
* Types are: OSD_PLAY_ICON, OSD_PAUSE_ICON, OSD_SPEAKER_ICON, OSD_MUTE_ICON
*/
static subpicture_region_t *OSDIcon(int type, const video_format_t *fmt)
{
subpicture_t *p_subpic;
int i_x_margin, i_y_margin, i_x, i_y, i_width, i_height;
p_subpic = CreateWidget( i_channel );
if( p_subpic == NULL )
{
return VLC_EGENERIC;
const float size_ratio = 0.05;
const float margin_ratio = 0.07;
const int size = __MAX(fmt->i_visible_width, fmt->i_visible_height);
const int width = size * size_ratio;
const int height = size * size_ratio;
const int x = fmt->i_x_offset + fmt->i_visible_width - margin_ratio * size - width;
const int y = fmt->i_y_offset + margin_ratio * size;
subpicture_region_t *r = OSDRegion(__MAX(x, 0),
__MIN(y, (int)fmt->i_visible_height - height),
width, height);
if (!r)
return NULL;
if (type == OSD_PAUSE_ICON) {
int bar_width = width / 3;
DrawRect(r, STYLE_FILLED, 0, 0, bar_width - 1, height -1);
DrawRect(r, STYLE_FILLED, width - bar_width, 0, width - 1, height - 1);
} else if (type == OSD_PLAY_ICON) {
int mid = height >> 1;
int delta = (width - mid) >> 1;
int y2 = ((height - 1) >> 1) * 2;
DrawTriangle(r, STYLE_FILLED, delta, 0, width - delta, y2);
} else {
int mid = height >> 1;
int delta = (width - mid) >> 1;
int y2 = ((height - 1) >> 1) * 2;
DrawRect(r, STYLE_FILLED, delta, mid / 2, width - delta, height - 1 - mid / 2);
DrawTriangle(r, STYLE_FILLED, width - delta, 0, delta, y2);
if (type == OSD_MUTE_ICON) {
uint8_t *a = r->p_picture->A_PIXELS;
int pitch = r->p_picture->A_PITCH;
for (int i = 1; i < pitch; i++) {
int k = i + (height - i - 1) * pitch;
a[k] = 0xff - a[k];
}
}
}
return r;
}
i_y_margin = i_render_height / 10;
i_x_margin = i_y_margin + i_margin_left;
i_y_margin += i_margin_bottom;
if( i_type == OSD_HOR_SLIDER )
{
i_width = i_render_width - 2 * i_x_margin;
i_height = i_render_height / 20;
i_x = i_x_margin;
i_y = i_render_height - i_y_margin - i_height;
}
else
{
i_width = i_render_width / 40;
i_height = i_render_height - 2 * i_y_margin;
i_x = i_render_width - i_x_margin - i_width;
i_y = i_y_margin;
}
struct subpicture_updater_sys_t {
int type;
int position;
};
/* Create subpicture region and picture */
CreatePicture( p_subpic, i_x, i_y, i_width, i_height );
static int OSDWidgetValidate(subpicture_t *subpic,
bool has_src_changed, const video_format_t *fmt_src,
bool has_dst_changed, const video_format_t *fmt_dst,
mtime_t ts)
{
VLC_UNUSED(subpic); VLC_UNUSED(ts); VLC_UNUSED(fmt_src);
VLC_UNUSED(has_dst_changed); VLC_UNUSED(fmt_dst);
if( i_type == OSD_HOR_SLIDER )
{
int i_x_pos = ( i_width - 2 ) * i_position / 100;
DrawRect( p_subpic, i_x_pos - 1, 2, i_x_pos + 1,
i_height - 3, STYLE_FILLED );
DrawRect( p_subpic, 0, 0, i_width - 1, i_height - 1, STYLE_EMPTY );
}
else if( i_type == OSD_VERT_SLIDER )
{
int i_y_pos = i_height / 2;
DrawRect( p_subpic, 2, i_height - ( i_height - 2 ) * i_position / 100,
i_width - 3, i_height - 3, STYLE_FILLED );
DrawRect( p_subpic, 1, i_y_pos, 1, i_y_pos, STYLE_FILLED );
DrawRect( p_subpic, i_width - 2, i_y_pos,
i_width - 2, i_y_pos, STYLE_FILLED );
DrawRect( p_subpic, 0, 0, i_width - 1, i_height - 1, STYLE_EMPTY );
}
if (!has_src_changed && !has_dst_changed)
return VLC_SUCCESS;
return VLC_EGENERIC;
}
spu_DisplaySubpicture( p_spu, p_subpic );
static void OSDWidgetUpdate(subpicture_t *subpic,
const video_format_t *fmt_src,
const video_format_t *fmt_dst,
mtime_t ts)
{
subpicture_updater_sys_t *sys = subpic->updater.p_sys;
VLC_UNUSED(fmt_dst); VLC_UNUSED(ts);
return VLC_SUCCESS;
subpic->i_original_picture_width = fmt_src->i_width;
subpic->i_original_picture_height = fmt_src->i_height;
if (sys->type == OSD_HOR_SLIDER || sys->type == OSD_VERT_SLIDER)
subpic->p_region = OSDSlider(sys->type, sys->position, fmt_src);
else
subpic->p_region = OSDIcon(sys->type, fmt_src);
}
/*****************************************************************************
* Displays an OSD icon.
* Types are: OSD_PLAY_ICON, OSD_PAUSE_ICON, OSD_SPEAKER_ICON, OSD_MUTE_ICON
*****************************************************************************/
static int OsdIcon( spu_t *p_spu,
int i_render_width, int i_render_height, int i_margin_right,
int i_margin_top, int i_channel, short i_type )
static void OSDWidgetDestroy(subpicture_t *subpic)
{
subpicture_t *p_subpic;
int i_x_margin, i_y_margin, i_x, i_y, i_width, i_height;
free(subpic->updater.p_sys);
}
p_subpic = CreateWidget( i_channel );
if( p_subpic == NULL )
{
return VLC_EGENERIC;
}
static void OSDWidget(vout_thread_t *vout, int channel, int type, int position)
{
if (!var_InheritBool(vout, "osd"))
return;
if (type == OSD_HOR_SLIDER || type == OSD_VERT_SLIDER)
position = __MIN(__MAX(position, 0), 100);
i_y_margin = i_render_height / 15;
i_x_margin = i_y_margin + i_margin_right;
i_y_margin += i_margin_top;
i_width = i_render_width / 20;
i_height = i_width;
i_x = i_render_width - i_x_margin - i_width;
i_y = i_y_margin;
/* Create subpicture region and picture */
CreatePicture( p_subpic, i_x, i_y, i_width, i_height );
if( i_type == OSD_PAUSE_ICON )
{
int i_bar_width = i_width / 3;
DrawRect( p_subpic, 0, 0, i_bar_width - 1, i_height -1, STYLE_FILLED );
DrawRect( p_subpic, i_width - i_bar_width, 0,
i_width - 1, i_height - 1, STYLE_FILLED );
}
else if( i_type == OSD_PLAY_ICON )
{
int i_mid = i_height >> 1;
int i_delta = ( i_width - i_mid ) >> 1;
int i_y2 = ( ( i_height - 1 ) >> 1 ) * 2;
DrawTriangle( p_subpic, i_delta, 0, i_width - i_delta, i_y2,
STYLE_FILLED );
}
else if( i_type == OSD_SPEAKER_ICON || i_type == OSD_MUTE_ICON )
{
int i_mid = i_height >> 1;
int i_delta = ( i_width - i_mid ) >> 1;
int i_y2 = ( ( i_height - 1 ) >> 1 ) * 2;
DrawRect( p_subpic, i_delta, i_mid / 2, i_width - i_delta,
i_height - 1 - i_mid / 2, STYLE_FILLED );
DrawTriangle( p_subpic, 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->p_picture->A_PIXELS;
int i_pitch = p_subpic->p_region->p_picture->Y_PITCH;
int i;
for( i = 1; i < i_pitch; i++ )
{
int k = i + ( i_height - i - 1 ) * i_pitch;
p_a[ k ] = 0xff - p_a[ k ];
}
}
subpicture_updater_sys_t *sys = malloc(sizeof(*sys));
if (!sys)
return;
sys->type = type;
sys->position = position;
subpicture_updater_t updater = {
.pf_validate = OSDWidgetValidate,
.pf_update = OSDWidgetUpdate,
.pf_destroy = OSDWidgetDestroy,
.p_sys = sys,
};
subpicture_t *subpic = subpicture_New(&updater);
if (!subpic) {
free(sys);
return;
}
spu_DisplaySubpicture( p_spu, p_subpic );
subpic->i_channel = channel;
subpic->i_start = mdate();
subpic->i_stop = subpic->i_start + 1200000;
subpic->b_ephemer = true;
subpic->b_absolute = true;
subpic->b_fade = true;
return VLC_SUCCESS;
spu_DisplaySubpicture(vout_GetSpu(vout), subpic);
}
/*****************************************************************************
* Displays an OSD slider.
* Types are: OSD_HOR_SLIDER and OSD_VERT_SLIDER.
*****************************************************************************/
void vout_OSDSlider( vout_thread_t *p_vout, int i_channel, int i_position,
short i_type )
{
if( !var_InheritBool( p_vout, "osd" ) || i_position < 0 )
return;
OsdSlider( vout_GetSpu( p_vout ),
p_vout->p->fmt_render.i_width,
p_vout->p->fmt_render.i_height,
p_vout->p->fmt_in.i_x_offset,
p_vout->p->fmt_in.i_height - p_vout->p->fmt_in.i_visible_height
- p_vout->p->fmt_in.i_y_offset,
i_channel, i_position, i_type );
void vout_OSDSlider(vout_thread_t *vout, int channel, int position, short type)
{
OSDWidget(vout, channel, type, position);
}
/*****************************************************************************
* Displays an OSD icon.
* Types are: OSD_PLAY_ICON, OSD_PAUSE_ICON, OSD_SPEAKER_ICON, OSD_MUTE_ICON
*****************************************************************************/
void vout_OSDIcon( vout_thread_t *p_vout, int i_channel, short i_type )
void vout_OSDIcon(vout_thread_t *vout, int channel, short type )
{
if( !var_InheritBool( p_vout, "osd" ) )
return;
OsdIcon( vout_GetSpu( p_vout ),
p_vout->p->fmt_render.i_width,
p_vout->p->fmt_render.i_height,
p_vout->p->fmt_in.i_width - p_vout->p->fmt_in.i_visible_width
- p_vout->p->fmt_in.i_x_offset,
p_vout->p->fmt_in.i_y_offset,
i_channel, i_type );
OSDWidget(vout, channel, type, 0);
}
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