X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fvideo_output%2Fvideo_spu.c;h=2232ebd885f587271d0224bd549cf5c471939d5b;hb=f2f265d02cb5ee156141af8c3ca4a2cf57632a8c;hp=b0e555357c7d12889b6f9b0f16fa48ef5ef14d5f;hpb=c2e97975f7560f6e8bbfef20d7768a243dc2957b;p=vlc diff --git a/src/video_output/video_spu.c b/src/video_output/video_spu.c index b0e555357c..2232ebd885 100644 --- a/src/video_output/video_spu.c +++ b/src/video_output/video_spu.c @@ -1,10 +1,11 @@ /***************************************************************************** - * video_spu.h : DVD subpicture units functions + * video_spu.c : DVD subpicture units functions ***************************************************************************** - * Copyright (C) 1999, 2000 VideoLAN - * - * Authors: + * Copyright (C) 1999-2001 VideoLAN + * $Id: video_spu.c,v 1.22 2001/11/28 15:08:06 massiot Exp $ * + * Authors: Samuel Hocevar + * * 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 @@ -26,201 +27,171 @@ #include "defs.h" #include +#include /* memcpy(), memset() */ #include "config.h" #include "common.h" +#include "intf_msg.h" #include "threads.h" -#include "plugins.h" #include "mtime.h" + #include "video.h" #include "video_output.h" #include "video_spu.h" -#include "intf_msg.h" - -typedef struct vout_spu_s -{ - int i_id; - byte_t *p_data; - - /* drawing coordinates inside the spu */ - int i_x; - int i_y; - /* target size */ - int i_width; - int i_height; - -} vout_spu_t; - -static int NewLine ( vout_spu_t *p_vspu, int *i_id ); - -/* i = get_nibble(); */ -#define GET_NIBBLE( i ) \ - if( b_aligned ) \ - { \ - i_next = *p_from[i_id]; \ - p_from[ i_id ]++; \ - b_aligned = 0; \ - i = i_next >> 4; \ - } \ - else \ - { \ - b_aligned = 1; \ - i = i_next & 0xf; \ - } - -/* i = j + get_nibble(); */ -#define ADD_NIBBLE( i, j ) \ - if( b_aligned ) \ - { \ - i_next = *p_from[i_id]; \ - p_from[ i_id ]++; \ - b_aligned = 0; \ - i = (j) + (i_next >> 4); \ - } \ - else \ - { \ - b_aligned = 1; \ - i = (j) + (i_next & 0xf); \ - } +/* FIXME: fake palette - the real one has to be sought in the .IFO */ +static int p_palette[4] = { 0x0000, 0xffff, 0x5555, 0x8888 }; /***************************************************************************** - * vout_RenderSPU: draws an SPU on a picture + * vout_RenderRGBSPU: draw an SPU on a picture ***************************************************************************** - * + * This is a fast implementation of the subpicture drawing code. The data + * has been preprocessed once in spu_decoder.c, so we don't need to parse the + * RLE buffer again and again. Most sanity checks are done in spu_decoder.c + * so that this routine can be as fast as possible. *****************************************************************************/ -void vout_RenderSPU( vout_buffer_t *p_buffer, subpicture_t *p_subpic, - int i_bytes_per_pixel, int i_bytes_per_line ) +void vout_RenderRGBSPU( picture_t *p_pic, const subpicture_t *p_spu, + vout_buffer_t *p_buffer, + int i_bytes_per_pixel, int i_bytes_per_line ) { - int i_code = 0x00; - int i_next = 0; - int i_id = 0; - int i_color; - - /* FIXME: we need a way to get this information from the stream */ - #define TARGET_WIDTH 720 - #define TARGET_HEIGHT 576 - int i_x_scale = ( p_buffer->i_pic_width << 6 ) / TARGET_WIDTH; - int i_y_scale = ( p_buffer->i_pic_height << 6 ) / TARGET_HEIGHT; - - /* FIXME: fake palette - the real one has to be sought in the .IFO */ - static int p_palette[4] = { 0x0000, 0x0000, 0x5555, 0xffff }; - - boolean_t b_aligned = 1; - byte_t *p_from[2]; - vout_spu_t vspu; - - p_from[1] = p_subpic->p_data + p_subpic->type.spu.i_offset[1]; - p_from[0] = p_subpic->p_data + p_subpic->type.spu.i_offset[0]; - - vspu.i_x = 0; - vspu.i_y = 0; - vspu.i_width = TARGET_WIDTH; - vspu.i_height = TARGET_HEIGHT; - vspu.p_data = p_buffer->p_data - /* add the picture coordinates and the SPU coordinates */ - + ( p_buffer->i_pic_x + ((p_subpic->i_x * i_x_scale) >> 6)) - * i_bytes_per_pixel - + ( p_buffer->i_pic_y + ((p_subpic->i_y * i_y_scale) >> 6)) - * i_bytes_per_line; - - while( p_from[0] < (byte_t *)p_subpic->p_data - + p_subpic->type.spu.i_offset[1] ) + int i_len, i_color; + u16 *p_source = (u16 *)p_spu->p_data; + + int i_xscale = ( p_buffer->i_pic_width << 6 ) / p_pic->i_width; + int i_yscale = ( p_buffer->i_pic_height << 6 ) / p_pic->i_height; + + int i_width = p_spu->i_width * i_xscale; + int i_height = p_spu->i_height * i_yscale; + + int i_x, i_y, i_ytmp, i_yreal, i_ynext; + + u8 *p_dest = p_buffer->p_data + ( i_width >> 6 ) * i_bytes_per_pixel + /* Add the picture coordinates and the SPU coordinates */ + + ( p_buffer->i_pic_x + ((p_spu->i_x * i_xscale) >> 6)) + * i_bytes_per_pixel + + ( p_buffer->i_pic_y + ((p_spu->i_y * i_yscale) >> 6)) + * i_bytes_per_line; + + /* Draw until we reach the bottom of the subtitle */ + i_y = 0; + + while( i_y < i_height ) { - GET_NIBBLE( i_code ); + i_ytmp = i_y >> 6; + i_y += i_yscale; - if( i_code >= 0x04 ) + /* Check whether we need to draw one line or more than one */ + if( i_ytmp + 1 >= ( i_y >> 6 ) ) { - found_code: + /* Just one line : we precalculate i_y >> 6 */ + i_yreal = i_bytes_per_line * i_ytmp; - if( ((i_code >> 2) + vspu.i_x + vspu.i_y * vspu.i_width) - > vspu.i_height * vspu.i_width ) - { - intf_DbgMsg ( "video_spu: invalid draw request ! %d %d\n", - i_code >> 2, vspu.i_height * vspu.i_width - - ( (i_code >> 2) + vspu.i_x - + vspu.i_y * vspu.i_width ) ); - return; - } - else + /* Draw until we reach the end of the line */ + i_x = i_width; + + while( i_x ) { - if( (i_color = i_code & 0x3) ) + /* Get the RLE part */ + i_color = *p_source & 0x3; + + /* Draw the line */ + if( i_color ) { - u8 *p_target = &vspu.p_data[ - i_bytes_per_pixel * ((vspu.i_x * i_x_scale) >> 6) - + i_bytes_per_line * ((vspu.i_y * i_y_scale) >> 6) ]; - - memset( p_target, p_palette[i_color], - ((((i_code - 1) * i_x_scale) >> 8) + 1) - * i_bytes_per_pixel ); - - /* if we need some horizontal scaling (unlikely ) - * we only scale up to 2x, someone watching a DVD - * with more than 2x zoom must be braindead */ - if( i_y_scale >= (1 << 6) ) - { - p_target += i_bytes_per_line; + i_len = i_xscale * ( *p_source++ >> 2 ); - memset( p_target, p_palette[i_color], - ((((i_code - 1) * i_x_scale) >> 8) + 1) - * i_bytes_per_pixel ); - } + memset( p_dest - i_bytes_per_pixel * ( i_x >> 6 ) + + i_yreal, + p_palette[ i_color ], + i_bytes_per_pixel * ( ( i_len >> 6 ) + 1 ) ); + + i_x -= i_len; + continue; } - vspu.i_x += i_code >> 2; - } - if( vspu.i_x >= vspu.i_width ) - { - /* byte-align the stream */ - b_aligned = 1; - /* finish the line */ - NewLine( &vspu, &i_id ); + i_x -= i_xscale * ( *p_source++ >> 2 ); } - continue; } + else + { + i_yreal = i_bytes_per_line * i_ytmp; + i_ynext = i_bytes_per_line * i_y >> 6; - ADD_NIBBLE( i_code, (i_code << 4) ); - if( i_code >= 0x10 ) /* 00 11 xx cc */ - goto found_code; /* 00 01 xx cc */ + /* Draw until we reach the end of the line */ + i_x = i_width; - ADD_NIBBLE( i_code, (i_code << 4) ); - if( i_code >= 0x040 ) /* 00 00 11 xx xx cc */ - goto found_code; /* 00 00 01 xx xx cc */ + while( i_x ) + { + /* Get the RLE part */ + i_color = *p_source & 0x3; - ADD_NIBBLE( i_code, (i_code << 4) ); - if( i_code >= 0x0100 ) /* 00 00 00 11 xx xx xx cc */ - goto found_code; /* 00 00 00 01 xx xx xx cc */ + /* Draw as many lines as needed */ + if( i_color ) + { + i_len = i_xscale * ( *p_source++ >> 2 ); - /* if the 14 first bits are 0, then it's a newline */ - if( i_code <= 0x0003 ) - { - if( NewLine( &vspu, &i_id ) < 0 ) - return; + for( i_ytmp = i_yreal ; + i_ytmp < i_ynext ; + i_ytmp += i_bytes_per_line ) + { + memset( p_dest - i_bytes_per_pixel * ( i_x >> 6 ) + + i_ytmp, + p_palette[ i_color ], + i_bytes_per_pixel * ( ( i_len >> 6 ) + 1 ) ); + } - if( !b_aligned ) - b_aligned = 1; - } - else - { - /* we have a boo boo ! */ - intf_DbgMsg( "video_spu: unknown code 0x%x " - "(dest %x side %x, x=%d, y=%d)\n", - i_code, p_from[i_id], i_id, vspu.i_x, vspu.i_y ); - if( NewLine( &vspu, &i_id ) < 0 ) - return; - continue; + i_x -= i_len; + continue; + } + + i_x -= i_xscale * ( *p_source++ >> 2 ); + } } } } -static int NewLine( vout_spu_t *p_vspu, int *i_id ) +/***************************************************************************** + * vout_RenderYUVSPU: draw an SPU on an YUV overlay + ***************************************************************************** + * This is a fast implementation of the subpicture drawing code. The data + * has been preprocessed once in spu_decoder.c, so we don't need to parse the + * RLE buffer again and again. Most sanity checks are done in spu_decoder.c + * so that this routine can be as fast as possible. + *****************************************************************************/ +void vout_RenderYUVSPU( picture_t *p_pic, const subpicture_t *p_spu ) { - *i_id = 1 - *i_id; + int i_len, i_color; + u16 *p_source = (u16 *)p_spu->p_data; + + int i_x, i_y; + + u8 *p_dest = p_pic->p_y + p_spu->i_x + p_spu->i_width + + p_pic->i_width * ( p_spu->i_y + p_spu->i_height ); - p_vspu->i_x = 0; - p_vspu->i_y++; + /* Draw until we reach the bottom of the subtitle */ + i_y = p_spu->i_height * p_pic->i_width; - return( p_vspu->i_width - p_vspu->i_y ); + while( i_y ) + { + /* Draw until we reach the end of the line */ + i_x = p_spu->i_width; + + while( i_x ) + { + /* Draw the line if needed */ + i_color = *p_source & 0x3; + if( i_color ) + { + i_len = *p_source++ >> 2; + memset( p_dest - i_x - i_y, p_palette[ i_color ], i_len ); + i_x -= i_len; + continue; + } + + i_x -= *p_source++ >> 2; + } + + i_y -= p_pic->i_width; + } }