/** * Copyright (c) 2002 Billy Biggs . * Copyright (c) 2002 Doug Bell . * * Modified and adapted to GStreamer by * David I. Lehn * * 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 (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include /*#include "osdtools.h"*/ /*#include "speedy.h"*/ #include "vbiscreen.h" #include "gstvbidec.h" #define ROLL_2 6 #define ROLL_3 7 #define ROLL_4 8 #define POP_UP 9 #define PAINT_ON 10 #define NUM_LINES 15 #define ROWS 15 #define COLS 32 #define FONT_SIZE 20 typedef struct osd_string_s osd_string_t; struct osd_string_s { int width; int height; int r, g, b; int visible; GstVBIDec *vbidec; }; osd_string_t *osd_string_new(char *c, int s, int w, int h, int a, void *user_data) { osd_string_t *os; os = (osd_string_t *)malloc(sizeof(osd_string_t)); if (!os) return NULL; os->width = 0; os->height = 0; os->r = os->g = os->b = 0; os->visible = 1; os->vbidec = (GstVBIDec *)user_data; return os; } void osd_string_show_text(osd_string_t *os, char *s, int len ) { /* FIXME: just print data when it gets here */ if (len > 0) { gst_vbidec_show_text(os->vbidec, s, len); } } int osd_string_get_height(osd_string_t *os) { return os->height; } int osd_string_get_width(osd_string_t *os) { return os->width; } void osd_string_delete(osd_string_t *os) { free(os); } void osd_string_set_colour_rgb(osd_string_t *os, int r, int g, int b) { os->r = r; os->g = g; os->b = b; } void blit_colour_packed422_scanline( unsigned char *d, int w, int luma, int cb, int cr) { } int osd_string_visible(osd_string_t *os) { return os->visible; } void osd_string_composite_packed422_scanline(osd_string_t *os, unsigned char *a, unsigned char *b, int w, int x, int y) { } struct vbiscreen_s { osd_string_t *line[ ROWS ]; char buffers[ ROWS * COLS * 2 ]; char text[ 2 * ROWS * COLS ]; char hiddenbuf[ COLS ]; char paintbuf[ ROWS * COLS ]; unsigned int fgcolour; unsigned int bgcolour; int bg_luma, bg_cb, bg_cr; int frame_width; int frame_height; int frame_aspect; int x, y; /* where to draw console */ int width, height; /* the size box we have to draw in */ int rowheight, charwidth; int curx, cury; /* cursor position */ int rows, cols; /* 32 cols 15 rows */ int captions, style; /* CC (1) or Text (0), RU2 RU3 RU4 POP_UP PAINT_ON */ int first_line; /* where to start drawing */ int curbuffer; int top_of_screen; /* a pointer into line[] */ int indent; int got_eoc; int scroll; char *fontfile; int fontsize; int verbose; void *user_data; }; vbiscreen_t *vbiscreen_new( int video_width, int video_height, double video_aspect, int verbose, void *user_data ) { int i=0, fontsize = FONT_SIZE; vbiscreen_t *vs = (vbiscreen_t *)malloc(sizeof(struct vbiscreen_s)); if( !vs ) { return NULL; } vs->verbose = verbose; vs->x = 0; vs->y = 0; vs->frame_width = video_width; vs->frame_height = video_height; vs->frame_aspect = video_aspect; vs->curx = 0; vs->cury = 0; vs->fgcolour = 0xFFFFFFFFU; /* white */ vs->bgcolour = 0xFF000000U; /* black */ vs->bg_luma = 16; vs->bg_cb = 128; vs->bg_cr = 128; vs->rows = ROWS; vs->cols = COLS; /*vs->fontfile = DATADIR "/FreeMonoBold.ttf";*/ vs->fontfile = NULL; vs->fontsize = fontsize; vs->width = video_width; vs->height = video_height; vs->first_line = 0; vs->captions = 0; vs->style = 0; vs->curbuffer = 0; vs->top_of_screen = 0; vs->indent = 0; memset( vs->buffers, 0, 2 * COLS * ROWS ); memset( vs->hiddenbuf, 0, COLS ); memset( vs->paintbuf, 0, ROWS * COLS ); vs->scroll = 0; vs->user_data = user_data; vs->line[0] = osd_string_new( vs->fontfile, fontsize, video_width, video_height, video_aspect, user_data); if( !vs->line[0] ) { vs->fontfile = "./FreeMonoBold.ttf"; vs->line[0] = osd_string_new( vs->fontfile, fontsize, video_width, video_height, video_aspect, user_data); } if( !vs->line[0] ) { fprintf( stderr, "vbiscreen: Could not find my font (%s)!\n", vs->fontfile ); vbiscreen_delete( vs ); return NULL; } osd_string_show_text( vs->line[ 0 ], "W", 0 ); vs->rowheight = osd_string_get_height( vs->line[ 0 ] ); vs->charwidth = osd_string_get_width( vs->line[ 0 ] ); osd_string_delete( vs->line[ 0 ] ); for( i = 0; i < ROWS; i++ ) { vs->line[ i ] = osd_string_new( vs->fontfile, fontsize, video_width, video_height, video_aspect, user_data); if( !vs->line[ i ] ) { fprintf( stderr, "vbiscreen: Could not allocate a line.\n" ); vbiscreen_delete( vs ); return NULL; } osd_string_set_colour_rgb( vs->line[ i ], (vs->fgcolour & 0xff0000) >> 16, (vs->fgcolour & 0xff00) >> 8, (vs->fgcolour & 0xff) ); osd_string_show_text( vs->line[ i ], " ", 0 ); } memset( vs->text, 0, 2 * ROWS * COLS ); return vs; } void blank_screen( vbiscreen_t *vs ) { int i; if( vs->verbose ) fprintf( stderr, "in blank\n"); for( i = 0; i < ROWS; i++ ) { osd_string_show_text( vs->line[ i ], " ", 0 ); } } void clear_screen( vbiscreen_t *vs ) { int base, i; if( !vs ) return; base = vs->top_of_screen * COLS; for( i = 0; i < ROWS * COLS; i++ ) { vs->text[ base ] = 0; base++; base %= 2 * ROWS * COLS; } blank_screen( vs ); } void clear_hidden_roll( vbiscreen_t *vs ) { if( !vs ) return; memset( vs->hiddenbuf, 0, COLS ); } void clear_hidden_pop( vbiscreen_t *vs ) { if( !vs ) return; memset( vs->buffers + vs->curbuffer * COLS * ROWS , 0, COLS * ROWS ); } void clear_hidden_paint( vbiscreen_t *vs ) { if( !vs ) return; memset( vs->paintbuf , 0, COLS * ROWS ); } void clear_displayed_pop( vbiscreen_t *vs ) { if( !vs ) return; memset( vs->buffers + ( vs->curbuffer ^ 1 ) * COLS * ROWS , 0, COLS * ROWS ); } void vbiscreen_dump_screen_text( vbiscreen_t *vs ) { int i, offset; if( !vs ) return; offset = vs->top_of_screen * COLS; fprintf( stderr, "\n 0123456789abcdefghij012345678901" ); for( i = 0; i < ROWS * COLS; i++ ) { if( !(i % COLS) ) fprintf( stderr, "\n%.2d ", i / COLS ); fprintf( stderr, "%c", vs->text[ offset ] ? vs->text[ offset ] : ' ' ); offset++; offset %= 2 * ROWS * COLS; } fprintf( stderr, "\n 0123456789abcdefghij012345678901\n " ); for( i = 0; i < COLS; i++ ) { fprintf( stderr, "%c", vs->text[ offset ] ? vs->text[ offset ] : ' ' ); offset++; offset %= 2 * ROWS * COLS; } fprintf( stderr, "\n 0123456789abcdefghij012345678901\n" ); } int update_row_x( vbiscreen_t *vs, int row ) { char text[ COLS + 1 ]; int i, j, haschars = 0, base; if( !vs ) return 0; text[ COLS ] = 0; base = ( ( vs->top_of_screen + row ) % ( 2 * ROWS ) ) * COLS; for( j = 0, i = base; i < base + COLS; i++, j++ ) { if( vs->text[ i ] ) { text[ j ] = vs->text[ i ]; haschars = 1; } else { text[ j ] = ' '; } } osd_string_set_colour_rgb( vs->line[ row ], ( vs->fgcolour & 0xff0000 ) >> 16, ( vs->fgcolour & 0xff00 ) >> 8, ( vs->fgcolour & 0xff ) ); if( !haschars ) osd_string_show_text( vs->line[ row ], " ", 0 ); else osd_string_show_text( vs->line[ row ], text, 51 ); return haschars; } void update_row( vbiscreen_t *vs ) { if( !vs ) return; update_row_x( vs, vs->cury ); //vbiscreen_dump_screen_text( vs ); } void update_all_rows( vbiscreen_t *vs ) { int row = 0; if( !vs ) return; for( row = 0; row < ROWS; row++ ) { update_row_x( vs, row ); } //vbiscreen_dump_screen_text( vs ); } void vbiscreen_delete( vbiscreen_t *vs ) { free( vs ); } void copy_row_to_screen( vbiscreen_t *vs, char *row ) { int base, i, j; base = ( ( vs->top_of_screen + vs->cury ) % ( 2 * ROWS ) ) * COLS; for( j = 0, i = base; i < base + COLS; j++, i++ ) { vs->text[ i ] = row[ j ]; } update_row( vs ); } void scroll_screen( vbiscreen_t *vs ) { int start_row; if( !vs || !vs->captions || !vs->style || vs->style > ROLL_4 ) return; start_row = ( vs->first_line + vs->top_of_screen ) % ( 2 * ROWS ); if( vs->verbose ) fprintf ( stderr, "start row : %d first line %d\n ", start_row, vs->first_line ); /* zero out top row */ memset( (char *)( vs->text + start_row * COLS ), 0, COLS ); vs->top_of_screen = ( vs->top_of_screen + 1 ) % ( 2 * ROWS ); vs->curx = vs->indent; update_all_rows( vs ); copy_row_to_screen( vs, vs->hiddenbuf ); clear_hidden_roll( vs ); vs->scroll = 26; } void vbiscreen_new_caption( vbiscreen_t *vs, int indent, int ital, unsigned int colour, int row ) { if( !vs ) return; if( vs->verbose ) fprintf( stderr, "indent: %d, ital: %d, colour: 0x%x, row: %d\n", indent, ital, colour, row ); if( 0 && vs->captions && vs->style <= ROLL_4 && vs->style ) { if( row != vs->cury+1 ) { vs->cury = row - 1; clear_hidden_roll( vs ); } else { // scroll_screen( vs ); } } if( vs->style > ROLL_4 ) { vs->cury = ( ( row > 0 ) ? row - 1 : 0 ); } vs->fgcolour = colour; vs->indent = indent; vs->curx = indent; } void vbiscreen_set_mode( vbiscreen_t *vs, int caption, int style ) { if( !vs ) return; if( vs->verbose ) fprintf( stderr, "in set mode\n"); if( vs->verbose ) { fprintf( stderr, "Caption: %d ", caption ); switch( style ) { case ROLL_2: fprintf( stderr, "ROLL 2\n"); break; case ROLL_3: fprintf( stderr, "ROLL 3\n" ); break; case ROLL_4: fprintf( stderr, "ROLL 4\n" ); break; case POP_UP: fprintf( stderr, "POP UP\n" ); break; case PAINT_ON: fprintf( stderr, "PAINT ON\n" ); break; default: break; } } if( !caption ) { /* text mode */ vs->cury = 0; } else { /* captioning mode */ /* styles: ru2 ru3 ru4 pop paint */ if( style != POP_UP && vs->style == POP_UP && !vs->got_eoc ) { /* stupid that sometimes they dont send a EOC */ vbiscreen_end_of_caption( vs ); } switch( style ) { case ROLL_2: case ROLL_3: case ROLL_4: if( vs->style == style ) { return; } vs->first_line = ROWS - (style - 4); if( vs->verbose ) fprintf( stderr, "first_line %d\n", vs->first_line ); vs->cury = ROWS - 1; break; case POP_UP: vs->got_eoc = 0; break; case PAINT_ON: break; } } vs->captions = caption; vs->style = style; } void vbiscreen_tab( vbiscreen_t *vs, int cols ) { if( !vs ) return; if( cols < 0 || cols > 3 ) return; vs->curx += cols; if( vs->curx > 31 ) vs->curx = 31; } void vbiscreen_set_colour( vbiscreen_t *vs, unsigned int col ) { if( !vs ) return; vs->fgcolour = col; } void vbiscreen_clear_current_cell( vbiscreen_t *vs ) { vs->text[ ( ( vs->top_of_screen + vs->cury ) % ( 2 * ROWS ) ) * COLS + vs->curx + vs->indent ] = 0; } void vbiscreen_set_current_cell( vbiscreen_t *vs, char text ) { int base; if( !vs ) return; base = ( ( vs->top_of_screen + vs->cury ) % ( 2 * ROWS ) ) * COLS; if( isprint( text ) ) vs->text[ base + vs->curx + vs->indent ] = text; else vs->text[ base + vs->curx + vs->indent ] = ' '; } void vbiscreen_delete_to_end( vbiscreen_t *vs ) { int i; if( !vs ) return; if( vs->verbose ) fprintf( stderr, "in del to end\n"); for( i = vs->curx; i < COLS; i++ ) { vbiscreen_clear_current_cell( vs ); vs->curx++; } vs->curx = COLS-1; /* is this right ? */ if( vs->captions && vs->style && vs->style != POP_UP ) update_row( vs ); } void vbiscreen_backspace( vbiscreen_t *vs ) { if( !vs ) return; if( vs->verbose ) fprintf( stderr, "in backspace\n"); if( !vs->curx ) return; vs->curx--; vbiscreen_clear_current_cell( vs ); update_row( vs ); } void vbiscreen_erase_displayed( vbiscreen_t *vs ) { if( !vs ) return; if( vs->verbose ) fprintf( stderr, "in erase disp\n"); if( vs->captions && vs->style && vs->style <= ROLL_4 ) { clear_hidden_roll( vs ); } clear_displayed_pop( vs ); clear_screen( vs ); } void vbiscreen_erase_non_displayed( vbiscreen_t *vs ) { if( !vs ) return; if( vs->verbose ) fprintf( stderr, "in erase non disp\n"); if( vs->captions && vs->style == POP_UP ) { memset( vs->buffers + vs->curbuffer * COLS * ROWS + vs->cury * COLS, 0, COLS ); // clear_hidden_pop( vs ); } else if( vs->captions && vs->style && vs->style <= ROLL_4 ) { clear_hidden_roll( vs ); } } void vbiscreen_carriage_return( vbiscreen_t *vs ) { if( !vs ) return; if( vs->verbose ) fprintf( stderr, "in CR\n"); if( vs->style != POP_UP) { /* not sure if this is right for text mode */ /* in text mode, perhaps a CR on last row clears screen and goes * to (0,0) */ scroll_screen( vs ); } /* keep cursor on bottom for rollup */ if( vs->captions && vs->style && vs->style <= ROLL_4 ) vs->cury--; vs->cury++; vs->curx = 0; } void copy_buf_to_screen( vbiscreen_t *vs, char *buf ) { int base, i, j; if( !vs ) return; base = vs->top_of_screen * COLS; for( j = 0, i = 0; i < ROWS * COLS; i++, j++ ) { vs->text[ base ] = buf[ j ]; base++; base %= 2 * ROWS * COLS; } update_all_rows( vs ); } void vbiscreen_end_of_caption( vbiscreen_t *vs ) { /*int i;*/ if( !vs ) return; if( vs->verbose ) fprintf( stderr, "in end of caption\n"); if( vs->style == PAINT_ON ) { copy_buf_to_screen( vs, vs->paintbuf ); clear_hidden_paint( vs ); } else if( vs->style == POP_UP ) { copy_buf_to_screen( vs, vs->buffers + vs->curbuffer * COLS * ROWS ); vs->curbuffer ^= 1; } /* to be safe? */ vs->curx = 0; vs->cury = ROWS - 1; vs->got_eoc = 1; } void vbiscreen_print( vbiscreen_t *vs, char c1, char c2 ) { if( !vs ) return; if( vs->verbose ) fprintf( stderr, "in print (%d, %d)[%c %c]\n", vs->curx, vs->cury, c1, c2); if( vs->captions && vs->style == POP_UP ) { /* this all gets displayed at another time */ if( vs->curx != COLS-1 ) { *(vs->buffers + vs->curx + vs->curbuffer * ROWS * COLS + vs->cury * COLS ) = c1; vs->curx++; } if( vs->curx != COLS-1 && c2 ) { *(vs->buffers + vs->curx + vs->curbuffer * ROWS * COLS + vs->cury * COLS ) = c2; vs->curx++; } else if( c2 ) { *(vs->buffers + vs->curx + vs->curbuffer * ROWS * COLS + vs->cury * COLS ) = c2; } } if( vs->captions && vs->style == PAINT_ON ) { if( vs->curx != COLS-1 ) { vs->paintbuf[ vs->curx + vs->cury * COLS ] = c1; vs->curx++; } if( vs->curx != COLS-1 && c2 ) { vs->paintbuf[ vs->curx + vs->cury * COLS ] = c2; vs->curx++; } else if( c2 ) { vs->paintbuf[ vs->curx + vs->cury * COLS ] = c2; } } if( vs->captions && vs->style && vs->style <= ROLL_4 ) { if( vs->curx != COLS-1 ) { vs->hiddenbuf[ vs->curx ] = c1; vs->curx++; } else { vs->hiddenbuf[ vs->curx ] = c1; } if( vs->curx != COLS-1 && c2 ) { vs->hiddenbuf[ vs->curx ] = c2; vs->curx++; } else if( c2 ) { vs->hiddenbuf[ vs->curx ] = c2; } } } void vbiscreen_reset( vbiscreen_t *vs ) { if( !vs ) return; clear_screen( vs ); clear_hidden_pop( vs ); clear_displayed_pop( vs ); clear_hidden_roll( vs ); vs->captions = 0; vs->style = 0; } void vbiscreen_composite_packed422_scanline( vbiscreen_t *vs, unsigned char *output, int width, int xpos, int scanline ) { int x=0, y=0, row=0, index=0; if( !vs ) return; if( !output ) return; if( scanline >= vs->y && scanline < vs->y + vs->height ) { if( 0 && !vs->captions ) blit_colour_packed422_scanline( output + (vs->x*2), vs->width, vs->bg_luma, vs->bg_cb, vs->bg_cr ); index = vs->top_of_screen * COLS; x = ( vs->x + vs->charwidth) & ~1; for( row = 0; row < ROWS; row++ ) { y = vs->y + row * vs->rowheight + vs->rowheight; if( osd_string_visible( vs->line[ row ] ) ) { if( scanline >= y && scanline < y + vs->rowheight ) { int startx; int strx; startx = x - xpos; strx = 0; if( startx < 0 ) { strx = -startx; startx = 0; } if( startx < width ) { if( vs->captions ) blit_colour_packed422_scanline( output + (startx*2), osd_string_get_width( vs->line[ row ] ), vs->bg_luma, vs->bg_cb, vs->bg_cr ); osd_string_composite_packed422_scanline( vs->line[ row ], output + (startx*2), output + (startx*2), width - startx, strx, scanline - y ); } } index++; } } } }