From de53ab422f3877a42450820eb40f2a25380ee27d Mon Sep 17 00:00:00 2001 From: Laurent Aimar Date: Thu, 6 May 2010 23:01:14 +0200 Subject: [PATCH] Used subpicture_updater_t for vout_OSDSlider/Icon. --- src/video_output/video_widgets.c | 513 ++++++++++++++----------------- 1 file changed, 232 insertions(+), 281 deletions(-) diff --git a/src/video_output/video_widgets.c b/src/video_output/video_widgets.c index 335edefc03..f8835d2ff3 100644 --- a/src/video_output/video_widgets.c +++ b/src/video_output/video_widgets.c @@ -5,6 +5,7 @@ * $Id$ * * Author: Yoann Peronneau + * Laurent Aimar * * 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 -/* 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); } -- 2.39.2