diff options
author | Christian Vogler <cvogler@users.sourceforge.net> | 2002-01-07 19:30:09 +0000 |
---|---|---|
committer | Christian Vogler <cvogler@users.sourceforge.net> | 2002-01-07 19:30:09 +0000 |
commit | 16be79073dc84a67b72f7e1a5cac93a5b34782aa (patch) | |
tree | 14071f2a3a8e5a59b5208ec1bd7bd684a6342df8 | |
parent | d984be942f5a0d4601ff791683050ca36bd5c4cb (diff) | |
download | xine-lib-16be79073dc84a67b72f7e1a5cac93a5b34782aa.tar.gz xine-lib-16be79073dc84a67b72f7e1a5cac93a5b34782aa.tar.bz2 |
move all configuration responsibilities to xine_decoder.c.
cc decoder is now initialized only if CC events arrive.
clean up cc_config_t by moving out renderer specific parts to new
cc_renderer_t.
fix event race conditions and simplify code by using one global lock
for cc decoder that stays locked for the entire duration of a CC function
call.
CVS patchset: 1368
CVS date: 2002/01/07 19:30:09
-rw-r--r-- | src/libspucc/cc_decoder.c | 553 | ||||
-rw-r--r-- | src/libspucc/cc_decoder.h | 46 | ||||
-rw-r--r-- | src/libspucc/xine_decoder.c | 278 |
3 files changed, 503 insertions, 374 deletions
diff --git a/src/libspucc/cc_decoder.c b/src/libspucc/cc_decoder.c index 0078fba6a..e4fe3ef1f 100644 --- a/src/libspucc/cc_decoder.c +++ b/src/libspucc/cc_decoder.c @@ -20,7 +20,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: cc_decoder.c,v 1.1 2002/01/05 21:41:18 miguelfreitas Exp $ + * $Id: cc_decoder.c,v 1.2 2002/01/07 19:30:09 cvogler Exp $ * * stuff needed to provide closed captioning decoding and display * @@ -39,6 +39,7 @@ #include "video_out.h" #include "xine_internal.h" +#include "xineutils.h" #include "osd.h" #include "cc_decoder.h" @@ -89,6 +90,36 @@ static int parity_table[256]; /*---------------- decoder data structures -----------------------*/ +/* CC renderer */ +struct cc_renderer_s { + int video_width; /* video dimensions */ + int video_height; + + int x; /* coordinates of the captioning area */ + int y; + int width; + int height; + int max_char_height; /* captioning font properties */ + int max_char_width; + + osd_renderer_t *osd_renderer; /* active OSD renderer */ + osd_object_t *cap_display; /* caption display object */ + int displayed; /* true when caption currently is displayed */ + + /* the next variable is a hack: hiding a caption with vpts 0 doesn't seem + to work if the caption has been registered in the SPU event queue, but + not yet displayed. So we remember the vpts of the show event, and use + that as the vpts of the hide event upon an osd free. + */ +#warning "FIXME: bug in OSD or SPU?" + int display_vpts; /* vpts of currently displayed caption */ + + metronom_t *metronom; /* the active xine metronom */ + + cc_config_t *cc_cfg; /* captioning configuration */ +}; + + /* CC attribute */ typedef struct cc_attribute_s { uint8_t italic; @@ -189,13 +220,6 @@ static void get_font_metrics(osd_renderer_t *renderer, } -static void copy_str(char *d, const char *s, size_t maxbytes) -{ - strncpy(d, s, maxbytes); - d[maxbytes] = '\0'; -} - - static int parity(uint8_t byte) { int i; @@ -302,43 +326,40 @@ static int ccrow_find_next_attr_change(cc_row_t *this, int pos, int lastpos) } -/* CAUTION: THIS FUNCTION ASSUMES THAT THE MUTEX IS ALREADY LOCKED! */ -static void ccrow_set_attributes(cc_row_t *this, osd_renderer_t *renderer, - osd_object_t *display, int pos, - cc_config_t *cap_cfg) +static void ccrow_set_attributes(cc_renderer_t *renderer, cc_row_t *this, + int pos) { const cc_attribute_t *attr = &this->cells[pos].attributes; const char *fontname; - cc_confvar_t *cap_info = &cap_cfg->vars; + cc_config_t *cap_info = renderer->cc_cfg; if (attr->italic) fontname = cap_info->italic_font; else fontname = cap_info->font; - renderer->set_font(display, (char *) fontname, cap_info->font_size); + renderer->osd_renderer->set_font(renderer->cap_display, (char *) fontname, + cap_info->font_size); } -/* CAUTION: THIS FUNCTION ASSUMES THAT THE MUTEX IS ALREADY LOCKED! */ -static void ccrow_render(cc_row_t *this, int rownum, - cc_config_t *cap_cfg, osd_renderer_t *renderer, - osd_object_t *display) +static void ccrow_render(cc_renderer_t *renderer, cc_row_t *this, int rownum) { char buf[CC_COLUMNS + 1]; int base_y; int pos = ccrow_find_next_text_part(this, 0); - cc_confvar_t *cap_info = &cap_cfg->vars; + cc_config_t *cap_info = renderer->cc_cfg; + osd_renderer_t *osd_renderer = renderer->osd_renderer; /* find y coordinate of caption */ if (cap_info->center) { /* find y-center of the desired row; the next line computes */ /* cap_info->height * (rownum + 0.5) / CC_ROWS */ /* in integer arithmetic for this purpose. */ - base_y = (cap_info->height * rownum * 100 + cap_info->height * 50) / + base_y = (renderer->height * rownum * 100 + renderer->height * 50) / (CC_ROWS * 100); } else - base_y = cap_info->height * rownum / CC_ROWS; + base_y = renderer->height * rownum / CC_ROWS; /* break down captions into parts separated by transparent space, and */ /* center each part individually along the x axis */ @@ -367,8 +388,9 @@ static void ccrow_render(cc_row_t *this, int rownum, for (i = seg_begin; i < seg_end; i++) buf[i - seg_begin] = this->cells[i].c; buf[seg_end - seg_begin] = '\0'; - ccrow_set_attributes(this, renderer, display, attr_pos, cap_cfg); - renderer->get_text_size(display, buf, &seg_w, &seg_h); + ccrow_set_attributes(renderer, this, attr_pos); + osd_renderer->get_text_size(renderer->cap_display, buf, + &seg_w, &seg_h); /* update cumulative segment statistics */ text_w += seg_w; @@ -382,15 +404,15 @@ static void ccrow_render(cc_row_t *this, int rownum, /* compute x coordinate of part */ if (cap_info->center) { - int cell_width = cap_info->width / CC_COLUMNS; - x = (cap_info->width * (pos + endpos) / 2) / CC_COLUMNS; + int cell_width = renderer->width / CC_COLUMNS; + x = (renderer->width * (pos + endpos) / 2) / CC_COLUMNS; x -= text_w / 2; /* clamp x coordinate to nearest character cell */ x = ((x + cell_width / 2) / CC_COLUMNS) * CC_COLUMNS + cell_width; - y = base_y - (cap_info->max_char_height + 1) / 2; + y = base_y - (renderer->max_char_height + 1) / 2; } else { - x = cap_info->width * pos / CC_COLUMNS; + x = renderer->width * pos / CC_COLUMNS; y = base_y; } @@ -403,9 +425,10 @@ static void ccrow_render(cc_row_t *this, int rownum, /* background is uneven for superscript characters. Also, pad left and */ /* right with one character width to make text more readable. */ #warning "FIXME: There may be off-by one errors in the rendering - check with Miguel" - renderer->filled_rect(display, x - cap_info->max_char_width, y, - x + text_w + cap_info->max_char_width, - y + cap_info->max_char_height, CAP_BG_COL); + osd_renderer->filled_rect(renderer->cap_display, + x - renderer->max_char_width, y, + x + text_w + renderer->max_char_width, + y + renderer->max_char_height, CAP_BG_COL); /* render text part by rendering each attributed text segment */ for (seg = 0; seg < num_seg; seg++) { @@ -417,8 +440,9 @@ static void ccrow_render(cc_row_t *this, int rownum, for (i = seg_pos[seg]; i < seg_pos[seg + 1]; i++) buf[i - seg_pos[seg]] = this->cells[i].c; buf[seg_pos[seg + 1] - seg_pos[seg]] = '\0'; - ccrow_set_attributes(this, renderer, display, seg_pos[seg], cap_cfg); - renderer->render_text(display, x + cumulative_seg_width[seg], y, buf); + ccrow_set_attributes(renderer, this, seg_pos[seg]); + osd_renderer->render_text(renderer->cap_display, + x + cumulative_seg_width[seg], y, buf); } pos = ccrow_find_next_text_part(this, endpos); @@ -529,10 +553,7 @@ static void ccbuf_tab(cc_buffer_t *this, int tabsize) } -/* CAUTION: THIS FUNCTION ASSUMES THAT THE MUTEX IS ALREADY LOCKED! */ -static void ccbuf_render(cc_buffer_t *this, - cc_config_t *cap_info, osd_renderer_t *renderer, - osd_object_t *display) +static void ccbuf_render(cc_renderer_t *renderer, cc_buffer_t *this) { int row; @@ -542,7 +563,7 @@ static void ccbuf_render(cc_buffer_t *this, for (row = 0; row < CC_ROWS; ++row) { if (this->rows[row].num_chars > 0) - ccrow_render(&this->rows[row], row, cap_info, renderer, display); + ccrow_render(renderer, &this->rows[row], row); } } @@ -570,63 +591,215 @@ static void ccmem_exit(cc_memory_t *this) } -/*----------------- cc_decoder_t methods --------------------------------*/ +/*----------------- cc_renderer_t methods -------------------------------*/ -static void cc_set_channel(cc_decoder_t *this, int channel) +static uint32_t cc_renderer_calc_vpts(cc_renderer_t *this, uint32_t pts, + uint32_t scr, uint32_t ntsc_frame_offset) +{ + metronom_t *metronom = this->metronom; + uint32_t vpts = metronom->got_spu_packet(metronom, pts, 0, scr); + return vpts + ntsc_frame_offset * NTSC_FRAME_DURATION; +} + + +/* returns true if a caption is on display */ +static int cc_renderer_on_display(cc_renderer_t *this) +{ + return this->displayed; +} + + +static void cc_renderer_hide_caption(cc_renderer_t *this, uint32_t vpts) +{ + if (this->displayed) { + this->osd_renderer->hide(this->cap_display, vpts); + this->displayed = 0; + } +} + + +static void cc_renderer_show_caption(cc_renderer_t *this, cc_buffer_t *buf, + uint32_t vpts) { - (*this->active)->channel_no = channel; #ifdef LOG_DEBUG - printf("cc_decoder: cc_set_channel: selecting channel %d\n", channel); + printf("spucc: cc_renderer: show\n"); #endif + + if (this->displayed) { + cc_renderer_hide_caption(this, vpts); + printf("spucc: cc_renderer: show: OOPS - caption was already displayed!\n"); + } + + this->osd_renderer->clear(this->cap_display); + ccbuf_render(this, buf); + this->osd_renderer->set_position(this->cap_display, + this->x, + this->y); + this->osd_renderer->show(this->cap_display, vpts); + + this->displayed = 1; + this->display_vpts = vpts; } -static cc_buffer_t *active_ccbuffer(cc_decoder_t *this) +static void cc_renderer_free_osd_object(cc_renderer_t *this) { - cc_memory_t *mem = *this->active; - return &mem->channel[mem->channel_no]; + /* hide and free old displayed caption object if necessary */ + if (this->cap_display) { + cc_renderer_hide_caption(this, this->display_vpts); + this->osd_renderer->free_object(this->cap_display); + this->cap_display = NULL; + } } -static uint32_t cc_calc_vpts(cc_decoder_t *this) +static void cc_renderer_adjust_osd_object(cc_renderer_t *this) { - metronom_t *metronom = this->metronom; - uint32_t vpts = metronom->got_spu_packet(metronom, this->pts, 0, this->scr); - return vpts + this->f_offset * NTSC_FRAME_DURATION; + cc_renderer_free_osd_object(this); + +#ifdef LOG_DEBUG + printf("spucc: cc_renderer: adjust_osd_object: creating %dx%d OSD object\n", + this->width, this->height); +#endif + + /* create display object */ + this->cap_display = this->osd_renderer->new_object(this->osd_renderer, + this->width, + this->height); + this->osd_renderer->set_text_palette(this->cap_display, 2); } -static int cc_onscreen_displayable(cc_decoder_t *this) +cc_renderer_t *cc_renderer_open(osd_renderer_t *osd_renderer, + metronom_t *metronom, cc_config_t *cc_cfg, + int video_width, int video_height) { - return ccbuf_has_displayable(&this->on_buf->channel[this->on_buf->channel_no]); + cc_renderer_t *this = (cc_renderer_t *) xine_xmalloc(sizeof (cc_renderer_t)); + + this->osd_renderer = osd_renderer; + this->metronom = metronom; + this->cc_cfg = cc_cfg; + cc_renderer_update_cfg(this, video_width, video_height); +#ifdef LOG_DEBUG + printf("spucc: cc_renderer: open\n"); +#endif + return this; } -/* CAUTION: THIS FUNCTION ASSUMES THAT THE MUTEX IS ALREADY LOCKED! */ -static void cc_do_hide(cc_decoder_t *this) +void cc_renderer_close(cc_renderer_t *this_obj) { - if (this->displayed) { - uint32_t vpts = cc_calc_vpts(this); + cc_renderer_free_osd_object(this_obj); + free(this_obj); + +#ifdef LOG_DEBUG + printf("spucc: cc_renderer: close\n"); +#endif +} + + +void cc_renderer_update_cfg(cc_renderer_t *this_obj, int video_width, + int video_height) +{ + int fontw, fonth; + int required_w, required_h; + + this_obj->video_width = video_width; + this_obj->video_height = video_height; + + /* calculate preferred captioning area, as per the EIA-608 standard */ + this_obj->x = this_obj->video_width * 10 / 100; + this_obj->y = this_obj->video_height * 10 / 100; + this_obj->width = this_obj->video_width * 80 / 100; + this_obj->height = this_obj->video_height * 80 / 100; + + /* find maximum text width and height for normal & italic captioning */ + /* font */ + get_font_metrics(this_obj->osd_renderer, this_obj->cc_cfg->font, + this_obj->cc_cfg->font_size, &fontw, &fonth); + this_obj->max_char_width = fontw; + this_obj->max_char_height = fonth; + get_font_metrics(this_obj->osd_renderer, this_obj->cc_cfg->italic_font, + this_obj->cc_cfg->font_size, &fontw, &fonth); + this_obj->max_char_width = MAX(fontw, this_obj->max_char_width); + this_obj->max_char_height = MAX(fonth, this_obj->max_char_height); +#ifdef LOG_DEBUG + printf("spucc: cc_renderer: update config: max text extents: %d, %d\n", + this_obj->max_char_width, this_obj->max_char_height); +#endif + /* need to adjust captioning area to accommodate font? */ + required_w = CC_COLUMNS * (this_obj->max_char_width + 1); + required_h = CC_ROWS * (this_obj->max_char_height + 1); + if (required_w > this_obj->width) { +#ifdef LOG_DEBUG + printf("spucc: cc_renderer: update config: adjusting cap area width: %d\n", + required_w); +#endif + this_obj->width = required_w; + this_obj->x = (this_obj->video_width - required_w) / 2; + } + if (required_h > this_obj->height) { #ifdef LOG_DEBUG - printf("cc_decoder: cc_do_hide: hiding caption %u at vpts %u\n", this->capid, vpts); + printf("spucc: cc_renderer: update config: adjusting cap area height: %d\n", + required_h); #endif + this_obj->height = required_h; + this_obj->y = (this_obj->video_height - required_h) / 2; + } - this->renderer->hide(this->cap_display, vpts); - this->displayed = 0; + if (required_w <= this_obj->video_width && + required_h <= this_obj->video_height) { + this_obj->cc_cfg->can_cc = 1; + cc_renderer_adjust_osd_object(this_obj); + } + else { + this_obj->cc_cfg->can_cc = 0; + cc_renderer_free_osd_object(this_obj); + printf("spucc: required captioning area %dx%d exceeds screen %dx%d!\n" + " Captions disabled. Perhaps you should choose a smaller" + " font?\n", + required_w, required_h, this_obj->video_width, + this_obj->video_height); } } +/*----------------- cc_decoder_t methods --------------------------------*/ + +static void cc_set_channel(cc_decoder_t *this, int channel) +{ + (*this->active)->channel_no = channel; +#ifdef LOG_DEBUG + printf("cc_decoder: cc_set_channel: selecting channel %d\n", channel); +#endif +} + + +static cc_buffer_t *active_ccbuffer(cc_decoder_t *this) +{ + cc_memory_t *mem = *this->active; + return &mem->channel[mem->channel_no]; +} + + +static int cc_onscreen_displayable(cc_decoder_t *this) +{ + return ccbuf_has_displayable(&this->on_buf->channel[this->on_buf->channel_no]); +} + + static void cc_hide_displayed(cc_decoder_t *this) { #ifdef LOG_DEBUG printf("cc_decoder: cc_hide_displayed\n"); #endif - pthread_mutex_lock(&this->cc_cfg->cc_mutex); - cc_do_hide(this); - pthread_mutex_unlock(&this->cc_cfg->cc_mutex); + if (cc_renderer_on_display(this->cc_cfg->renderer)) { + uint32_t vpts = cc_renderer_calc_vpts(this->cc_cfg->renderer, this->pts, + this->scr, this->f_offset); + cc_renderer_hide_caption(this->cc_cfg->renderer, vpts); + } } @@ -636,32 +809,17 @@ static void cc_show_displayed(cc_decoder_t *this) printf("cc_decoder: cc_show_displayed\n"); #endif - pthread_mutex_lock(&this->cc_cfg->cc_mutex); - - if (this->displayed) { - cc_do_hide(this); - printf("cc_decoder: cc_show_displayed: OOPS - caption was already displayed!\n"); - } - if (cc_onscreen_displayable(this)) { - uint32_t vpts = cc_calc_vpts(this); - this->capid++; - + uint32_t vpts = cc_renderer_calc_vpts(this->cc_cfg->renderer, this->pts, + this->scr, this->f_offset); #ifdef LOG_DEBUG printf("cc_decoder: cc_show_displayed: showing caption %u at vpts %u\n", this->capid, vpts); #endif - - this->renderer->clear(this->cap_display); - ccbuf_render(&this->on_buf->channel[this->on_buf->channel_no], - this->cc_cfg, this->renderer, this->cap_display); - this->renderer->set_position(this->cap_display, this->cc_cfg->vars.x, - this->cc_cfg->vars.y); - this->renderer->show(this->cap_display, vpts); - - this->displayed = 1; + this->capid++; + cc_renderer_show_caption(this->cc_cfg->renderer, + &this->on_buf->channel[this->on_buf->channel_no], + vpts); } - - pthread_mutex_unlock(&this->cc_cfg->cc_mutex); } @@ -986,114 +1144,13 @@ void decode_cc(cc_decoder_t *this, uint8_t *buffer, uint32_t buf_len, } -/* CAUTION: THIS FUNCTION ASSUMES THAT THE MUTEX IS ALREADY LOCKED! */ -static void cc_free_osd_object(cc_decoder_t *this) -{ - /* hide and free old displayed caption object if necessary */ - if (this->cap_display) { - cc_do_hide(this); - this->renderer->free_object(this->cap_display); - this->cap_display = NULL; - } -} - -/* CAUTION: THIS FUNCTION ASSUMES THAT THE MUTEX IS ALREADY LOCKED! */ -static void cc_adjust_osd_object(cc_decoder_t *this) +cc_decoder_t *cc_decoder_open(cc_config_t *cc_cfg) { - cc_free_osd_object(this); - -#ifdef LOG_DEBUG - printf("cc_decoder: cc_adjust_osd_object: creating %dx%d OSD object\n", - this->cc_cfg->vars.width, this->cc_cfg->vars.height); -#endif - - /* create display object */ - this->cap_display = this->renderer->new_object(this->renderer, - this->cc_cfg->vars.width, - this->cc_cfg->vars.height); - this->renderer->set_text_palette(this->cap_display, 2); -} - - -/* CAUTION: THIS FUNCTION ASSUMES THAT THE MUTEX IS ALREADY LOCKED! */ -static void cc_adjust_cap_area(cc_config_t *cfg) -{ - int fontw, fonth; - int required_w, required_h; - cc_confvar_t *cfgvars = &cfg->vars; - -#ifdef LOG_DEBUG - printf("cc_decoder: cc_adjust_cap_area\n"); -#endif - - if (cfgvars->decoder && cfgvars->cc_enabled) { - /* calculate preferred captioning area, as per the EIA-608 standard */ - cfgvars->x = cfgvars->video_width * 10 / 100; - cfgvars->y = cfgvars->video_height * 10 / 100; - cfgvars->width = cfgvars->video_width * 80 / 100; - cfgvars->height = cfgvars->video_height * 80 / 100; - - /* find maximum text width and height for normal & italic captioning */ - /* font */ - get_font_metrics(cfgvars->decoder->renderer, cfgvars->font, cfgvars->font_size, - &fontw, &fonth); - cfgvars->max_char_width = fontw; - cfgvars->max_char_height = fonth; - get_font_metrics(cfgvars->decoder->renderer, cfgvars->italic_font, - cfgvars->font_size, &fontw, &fonth); - cfgvars->max_char_width = MAX(fontw, cfgvars->max_char_width); - cfgvars->max_char_height = MAX(fonth, cfgvars->max_char_height); -#ifdef LOG_DEBUG - printf("cc_decoder: cc_adjust_cap_area: max text extents: %d, %d\n", - cfgvars->max_char_width, cfgvars->max_char_height); -#endif - - /* need to adjust captioning area to accommodate font? */ - required_w = CC_COLUMNS * (cfgvars->max_char_width + 1); - required_h = CC_ROWS * (cfgvars->max_char_height + 1); - if (required_w > cfgvars->width) { -#ifdef LOG_DEBUG - printf("cc_decoder: cc_adjust_cap_area: adjusting cap area width: %d\n", - required_w); -#endif - cfgvars->width = required_w; - cfgvars->x = (cfgvars->video_width - required_w) / 2; - } - if (required_h > cfgvars->height) { -#ifdef LOG_DEBUG - printf("cc_decoder: cc_adjust_cap_area: adjusting cap area height: %d\n", - required_h); -#endif - cfgvars->height = required_h; - cfgvars->y = (cfgvars->video_height - required_h) / 2; - } - - if (required_w <= cfgvars->video_width && required_h <= cfgvars->video_height) { - cfgvars->can_cc = 1; - cc_adjust_osd_object(cfgvars->decoder); - } - else { - cfgvars->can_cc = 0; - cc_free_osd_object(cfgvars->decoder); - printf("cc_decoder: required captioning area %dx%d exceeds screen %dx%d," - " captions disabled\n" - " Perhaps you should choose a smaller font?\n", - required_w, required_h, cfgvars->video_width, cfgvars->video_height); - } - } -} - - -cc_decoder_t *cc_decoder_open(osd_renderer_t *renderer, metronom_t *metronom, - config_values_t *cfg, cc_config_t *cc_cfg) -{ - cc_decoder_t *this = (cc_decoder_t *) malloc(sizeof (cc_decoder_t)); + cc_decoder_t *this = (cc_decoder_t *) xine_xmalloc(sizeof (cc_decoder_t)); /* configfile stuff */ this->cc_cfg = cc_cfg; - this->metronom = metronom; - ccmem_init(&this->buffer[0]); ccmem_init(&this->buffer[1]); this->on_buf = &this->buffer[0]; @@ -1105,147 +1162,31 @@ cc_decoder_t *cc_decoder_open(osd_renderer_t *renderer, metronom_t *metronom, this->pts = this->scr = this->f_offset = 0; - /* create text renderer */ - this->renderer = renderer; - - pthread_mutex_lock(&this->cc_cfg->cc_mutex); - this->displayed = 0; - this->cap_display = NULL; - this->cc_cfg->vars.decoder = this; - cc_adjust_cap_area(this->cc_cfg); - pthread_mutex_unlock(&this->cc_cfg->cc_mutex); - +#ifdef LOG_DEBUG + printf("spucc: cc_decoder_open\n"); +#endif return this; } void cc_decoder_close(cc_decoder_t *this) { - pthread_mutex_lock(&this->cc_cfg->cc_mutex); - cc_free_osd_object(this); - pthread_mutex_unlock(&this->cc_cfg->cc_mutex); - ccmem_exit(&this->buffer[0]); ccmem_exit(&this->buffer[1]); free(this); -} - -/*----------------- configuration listeners --------------------------------*/ - -static void cc_cfg_enable_change(void *cfg, cfg_entry_t *value) -{ - cc_config_t *cc_cfg = (cc_config_t *) cfg; - - pthread_mutex_lock(&cc_cfg->cc_mutex); - cc_cfg->vars.cc_enabled = value->num_value; - if (cc_cfg->vars.cc_enabled) - cc_adjust_cap_area(cc_cfg); - else if (cc_cfg->vars.decoder) - cc_free_osd_object(cc_cfg->vars.decoder); - pthread_mutex_unlock(&cc_cfg->cc_mutex); - -#ifdef LOG_DEBUG - printf("cc_decoder: closed captions are now %s.\n", cc_cfg->vars.cc_enabled? - "enabled" : "disabled"); -#endif - -} - -static void cc_font_change(void *cfg, cfg_entry_t *value) -{ - cc_config_t *cc_cfg = (cc_config_t *) cfg; - char *font; - - if (strcmp(value->key, "misc.cc_font") == 0) - font = cc_cfg->vars.font; - else - font = cc_cfg->vars.italic_font; - - pthread_mutex_lock(&cc_cfg->cc_mutex); - copy_str(font, value->str_value, CC_FONT_MAX); - cc_adjust_cap_area(cc_cfg); - pthread_mutex_unlock(&cc_cfg->cc_mutex); #ifdef LOG_DEBUG - printf("cc_decoder: changing %s to font %s\n", value->key, font); + printf("spucc: cc_decoder_close\n"); #endif } -static void cc_num_change(void *cfg, cfg_entry_t *value) -{ - cc_config_t *cc_cfg = (cc_config_t *) cfg; - int *num; - if (strcmp(value->key, "misc.cc_font_size") == 0) - num = &cc_cfg->vars.font_size; - else - num = &cc_cfg->vars.center; - - pthread_mutex_lock(&cc_cfg->cc_mutex); - *num = value->num_value; - cc_adjust_cap_area(cc_cfg); - pthread_mutex_unlock(&cc_cfg->cc_mutex); - -#ifdef LOG_DEBUG - printf("cc_decoder: changing %s to %d\n", value->key, *num); -#endif -} - +/*--------------- initialization methods --------------------------*/ -/* called when the video frame size changes */ -void cc_notify_frame_change(cc_decoder_t *this, int width, int height) +void cc_decoder_init(void) { -#ifdef LOG_DEBUG - printf("cc_decoder: new frame size: %dx%d\n", width, height); -#endif - - pthread_mutex_lock(&this->cc_cfg->cc_mutex); - this->cc_cfg->vars.video_width = width; - this->cc_cfg->vars.video_height = height; - cc_adjust_cap_area(this->cc_cfg); - pthread_mutex_unlock(&this->cc_cfg->cc_mutex); -} - - -/*-------- initialization methods and main hook --------------------------*/ - -void cc_decoder_init(config_values_t *cfg, cc_config_t *cc_cfg) -{ - cc_confvar_t *cc_vars = &cc_cfg->vars; - build_parity_table(); build_char_table(); - - pthread_mutex_init(&cc_cfg->cc_mutex, NULL); - - cc_vars->cc_enabled = cfg->register_bool(cfg, - "misc.cc_enabled", 0, - "Enable closed captions in MPEG-2 streams", - NULL, cc_cfg_enable_change, - cc_cfg); - - copy_str(cc_vars->font, - cfg->register_string(cfg, "misc.cc_font", "cc", - "Standard closed captioning font", - NULL, cc_font_change, cc_cfg), - CC_FONT_MAX); - - copy_str(cc_vars->italic_font, - cfg->register_string(cfg, "misc.cc_italic_font", "cci", - "Italic closed captioning font", - NULL, cc_font_change, cc_cfg), - CC_FONT_MAX); - - cc_vars->font_size = cfg->register_num(cfg, "misc.cc_font_size", 24, - "Closed captioning font size", - NULL, cc_num_change, - cc_cfg); - - cc_vars->center = cfg->register_bool(cfg, "misc.cc_center", 1, - "Center-adjust closed captions", - NULL, cc_num_change, - cc_cfg); } - diff --git a/src/libspucc/cc_decoder.h b/src/libspucc/cc_decoder.h index bf8210ad7..80553a80d 100644 --- a/src/libspucc/cc_decoder.h +++ b/src/libspucc/cc_decoder.h @@ -1,44 +1,40 @@ typedef struct cc_decoder_s cc_decoder_t; +typedef struct cc_renderer_s cc_renderer_t; #define CC_FONT_MAX 256 -typedef struct cc_confvar_s { +typedef struct cc_config_s { int cc_enabled; /* true if closed captions are enabled */ - char font[CC_FONT_MAX + 1]; /* standard captioning font & size */ + char font[CC_FONT_MAX]; /* standard captioning font & size */ int font_size; - char italic_font[CC_FONT_MAX + 1]; /* italic captioning font & size */ + char italic_font[CC_FONT_MAX]; /* italic captioning font & size */ int center; /* true if captions should be centered */ /* according to text width */ /* the following variables are not controlled by configuration files; they */ /* are intrinsic to the properties of the configuration options and the */ /* currently played video */ - int x; /* coordinates of the captioning area */ - int y; - int width; - int height; - int max_char_height; /* captioning font properties */ - int max_char_width; - int video_width; /* video dimensions */ - int video_height; int can_cc; /* true if captions can be displayed */ - /* (i.e., font fits on screen) */ - - cc_decoder_t *decoder; /* back pointer to decoder (necessary for */ - /* sending some messages after config changes) */ -} cc_confvar_t; - + /* (e.g., font fits on screen) */ -typedef struct cc_config_s { - cc_confvar_t vars; - pthread_mutex_t cc_mutex; + cc_renderer_t *renderer; /* closed captioning renderer */ } cc_config_t; - -cc_decoder_t *cc_decoder_open(osd_renderer_t *renderer, metronom_t *metronom, - config_values_t *cfg, cc_config_t *cc_cfg); +cc_decoder_t *cc_decoder_open(cc_config_t *cc_cfg); void cc_decoder_close(cc_decoder_t *this_obj); -void cc_decoder_init(config_values_t *cfg, cc_config_t *cc_cfg); -void cc_notify_frame_change(cc_decoder_t *this, int width, int height); +void cc_decoder_init(void); + void decode_cc(cc_decoder_t *this, uint8_t *buffer, uint32_t buf_len, uint32_t pts, uint32_t scr); + +/* Instantiates a new closed captioning renderer. */ +cc_renderer_t *cc_renderer_open(osd_renderer_t *osd_renderer, + metronom_t *metronom, cc_config_t *cc_cfg, + int video_width, int video_height); + +/* Destroys a closed captioning renderer. */ +void cc_renderer_close(cc_renderer_t *this_obj); + +/* Updates the renderer configuration variables */ +void cc_renderer_update_cfg(cc_renderer_t *this_obj, int video_width, + int video_height); diff --git a/src/libspucc/xine_decoder.c b/src/libspucc/xine_decoder.c index 4d5b40ef5..8bdb1f6c3 100644 --- a/src/libspucc/xine_decoder.c +++ b/src/libspucc/xine_decoder.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: xine_decoder.c,v 1.1 2002/01/05 21:41:18 miguelfreitas Exp $ + * $Id: xine_decoder.c,v 1.2 2002/01/07 19:30:09 cvogler Exp $ * * closed caption spu decoder. receive data by events. * @@ -25,6 +25,7 @@ #include <stdlib.h> #include <stdio.h> +#include <string.h> #include "buffer.h" #include "events.h" @@ -32,9 +33,8 @@ #include "xineutils.h" #include "cc_decoder.h" -/* -#define LOG 1 -*/ + +#define LOG_DEBUG 1 typedef struct spucc_decoder_s { @@ -44,15 +44,209 @@ typedef struct spucc_decoder_s { /* closed captioning decoder state */ cc_decoder_t *ccdec; + /* true if ccdec has been initialized */ + int cc_open; - /* closed captioning decoder configuration */ + /* closed captioning decoder configuration and intrinsics */ cc_config_t cc_cfg; - int cc_open; - + /* video dimensions captured in frame change events */ + int video_width; + int video_height; + + /* big lock regulating access to the CC decoder, CC renderer, and + configuration changes. For CC decoding, fine-grained locking is not + necessary. Using just single lock for everything makes the code + for configuraton changes *a lot* simpler, and *much* easier to + debug and maintain. + */ + pthread_mutex_t cc_mutex; } spucc_decoder_t; +/*------------------- general utility functions ----------------------------*/ + +static void copy_str(char *d, const char *s, size_t maxbytes) +{ + strncpy(d, s, maxbytes - 1); + d[maxbytes - 1] = '\0'; +} + + +/*------------------- private methods --------------------------------------*/ + +/* CAUTION: THIS FUNCTION ASSUMES THAT THE MUTEX IS ALREADY LOCKED! */ +static void spucc_update_intrinsics(spucc_decoder_t *this) +{ +#ifdef LOG_DEBUG + printf("spucc: update_intrinsics\n"); +#endif + + if (this->cc_open) + cc_renderer_update_cfg(this->cc_cfg.renderer, this->video_width, + this->video_height); +} + + +/* CAUTION: THIS FUNCTION ASSUMES THAT THE MUTEX IS ALREADY LOCKED! */ +static void spucc_do_close(spucc_decoder_t *this) +{ + if (this->cc_open) { +#ifdef LOG_DEBUG + printf("spucc: close\n"); +#endif + cc_decoder_close(this->ccdec); + cc_renderer_close(this->cc_cfg.renderer); + this->cc_open = 0; + } +} + + +/* CAUTION: THIS FUNCTION ASSUMES THAT THE MUTEX IS ALREADY LOCKED! */ +static void spucc_do_init (spucc_decoder_t *this, vo_instance_t *vo_out) +{ + if (! this->cc_open) { +#ifdef LOG_DEBUG + printf("spucc: init\n"); +#endif + /* initialize caption renderer */ + this->cc_cfg.renderer = cc_renderer_open(this->xine->osd_renderer, + this->xine->metronom, + &this->cc_cfg, + this->video_width, + this->video_height); + spucc_update_intrinsics(this); + + /* initialize CC decoder */ + this->ccdec = cc_decoder_open(&this->cc_cfg); + this->cc_open = 1; + } +} + + +/*----------------- configuration listeners --------------------------------*/ + +static void spucc_cfg_enable_change(void *this_gen, cfg_entry_t *value) +{ + spucc_decoder_t *this = (spucc_decoder_t *) this_gen; + cc_config_t *cc_cfg = &this->cc_cfg; + + pthread_mutex_lock(&this->cc_mutex); + + cc_cfg->cc_enabled = value->num_value; + if (! cc_cfg->cc_enabled) { + /* captions were just disabled? */ + spucc_do_close(this); + } + /* caption decoder is initialized on demand, so do nothing on open */ + +#ifdef LOG_DEBUG + printf("spucc: closed captions are now %s.\n", cc_cfg->cc_enabled? + "enabled" : "disabled"); +#endif + + pthread_mutex_unlock(&this->cc_mutex); +} + + +static void spucc_font_change(void *this_gen, cfg_entry_t *value) +{ + spucc_decoder_t *this = (spucc_decoder_t *) this_gen; + cc_config_t *cc_cfg = &this->cc_cfg; + char *font; + + if (strcmp(value->key, "misc.cc_font") == 0) + font = cc_cfg->font; + else + font = cc_cfg->italic_font; + + pthread_mutex_lock(&this->cc_mutex); + + copy_str(font, value->str_value, CC_FONT_MAX); + spucc_update_intrinsics(this); +#ifdef LOG_DEBUG + printf("spucc: changing %s to font %s\n", value->key, font); +#endif + + pthread_mutex_unlock(&this->cc_mutex); +} + + +static void spucc_num_change(void *this_gen, cfg_entry_t *value) +{ + spucc_decoder_t *this = (spucc_decoder_t *) this_gen; + cc_config_t *cc_cfg = &this->cc_cfg; + int *num; + + if (strcmp(value->key, "misc.cc_font_size") == 0) + num = &cc_cfg->font_size; + else + num = &cc_cfg->center; + + pthread_mutex_lock(&this->cc_mutex); + + *num = value->num_value; + spucc_update_intrinsics(this); +#ifdef LOG_DEBUG + printf("spucc: changing %s to %d\n", value->key, *num); +#endif + + pthread_mutex_unlock(&this->cc_mutex); +} + + +static void spucc_register_cfg_vars(spucc_decoder_t *this, + config_values_t *xine_cfg) { + cc_config_t *cc_vars = &this->cc_cfg; + + cc_vars->cc_enabled = xine_cfg->register_bool(xine_cfg, + "misc.cc_enabled", 0, + "Enable closed captions in MPEG-2 streams", + NULL, spucc_cfg_enable_change, + this); + + copy_str(cc_vars->font, + xine_cfg->register_string(xine_cfg, "misc.cc_font", "cc", + "Standard closed captioning font", + NULL, spucc_font_change, this), + CC_FONT_MAX); + + copy_str(cc_vars->italic_font, + xine_cfg->register_string(xine_cfg, "misc.cc_italic_font", "cci", + "Italic closed captioning font", + NULL, spucc_font_change, this), + CC_FONT_MAX); + + cc_vars->font_size = xine_cfg->register_num(xine_cfg, "misc.cc_font_size", + 24, + "Closed captioning font size", + NULL, spucc_num_change, + this); + + cc_vars->center = xine_cfg->register_bool(xine_cfg, "misc.cc_center", 1, + "Center-adjust closed captions", + NULL, spucc_num_change, + this); +} + + +/* called when the video frame size changes */ +void spucc_notify_frame_change(spucc_decoder_t *this, int width, int height) +{ +#ifdef LOG_DEBUG + printf("spucc: new frame size: %dx%d\n", width, height); +#endif + + pthread_mutex_lock(&this->cc_mutex); + this->video_width = width; + this->video_height = height; + spucc_update_intrinsics(this); + pthread_mutex_unlock(&this->cc_mutex); +} + + +/*------------------- implementation of spudec interface -------------------*/ + static int spudec_can_handle (spu_decoder_t *this_gen, int buf_type) { /*int type = buf_type & 0xFFFF0000; return (type == BUF_SPU_TEXT); */ @@ -63,39 +257,39 @@ static int spudec_can_handle (spu_decoder_t *this_gen, int buf_type) { static void spudec_init (spu_decoder_t *this_gen, vo_instance_t *vo_out) { spucc_decoder_t *this = (spucc_decoder_t *) this_gen; - - /* initialize CC decoder */ - this->ccdec = cc_decoder_open(this->xine->osd_renderer, this->xine->metronom, - this->xine->config, &this->cc_cfg); - this->cc_open = 1; + + pthread_mutex_lock(&this->cc_mutex); + spucc_do_init(this, vo_out); + pthread_mutex_unlock(&this->cc_mutex); } + static void spudec_decode_data (spu_decoder_t *this_gen, buf_element_t *buf) { spucc_decoder_t *this = (spucc_decoder_t *) this_gen; - int do_decode; if (buf->decoder_info[0] == 0) { } else { - if( !this->cc_open ) - spudec_init (this_gen, NULL); - - pthread_mutex_lock(&this->cc_cfg.cc_mutex); - do_decode = this->cc_cfg.vars.cc_enabled && this->cc_cfg.vars.can_cc; - pthread_mutex_unlock(&this->cc_cfg.cc_mutex); + pthread_mutex_lock(&this->cc_mutex); + if (this->cc_cfg.cc_enabled) { + if( !this->cc_open ) + spucc_do_init (this, NULL); - if( do_decode ) { - decode_cc(this->ccdec, buf->content, buf->size, - buf->PTS, buf->SCR); + if(this->cc_cfg.can_cc) { + decode_cc(this->ccdec, buf->content, buf->size, + buf->PTS, buf->SCR); + } } + pthread_mutex_unlock(&this->cc_mutex); } } static void spudec_close (spu_decoder_t *this_gen) { spucc_decoder_t *this = (spucc_decoder_t *) this_gen; - - cc_decoder_close(this->ccdec); - this->cc_open = 0; + + pthread_mutex_lock(&this->cc_mutex); + spucc_do_close(this); + pthread_mutex_unlock(&this->cc_mutex); } static void spudec_event_listener(void *this_gen, xine_event_t *event_gen) { @@ -111,11 +305,8 @@ static void spudec_event_listener(void *this_gen, xine_event_t *event_gen) { xine_frame_change_event_t *frame_change = (xine_frame_change_event_t *)event_gen; - if( !this->cc_open ) - spudec_init (this_gen, NULL); - - cc_notify_frame_change( this->ccdec, frame_change->width, - frame_change->height); + spucc_notify_frame_change(this, frame_change->width, + frame_change->height); } break; @@ -123,19 +314,18 @@ static void spudec_event_listener(void *this_gen, xine_event_t *event_gen) { { xine_closed_caption_event_t *closed_caption = (xine_closed_caption_event_t *)event_gen; - int do_decode; - if( !this->cc_open ) - spudec_init (this_gen, NULL); - - pthread_mutex_lock(&this->cc_cfg.cc_mutex); - do_decode = this->cc_cfg.vars.cc_enabled && this->cc_cfg.vars.can_cc; - pthread_mutex_unlock(&this->cc_cfg.cc_mutex); - - if( do_decode ) { - decode_cc(this->ccdec, closed_caption->buffer, closed_caption->buf_len, - closed_caption->pts, closed_caption->scr); + pthread_mutex_lock(&this->cc_mutex); + if (this->cc_cfg.cc_enabled) { + if (!this->cc_open) + spucc_do_init (this, NULL); + if (this->cc_cfg.can_cc) { + decode_cc(this->ccdec, closed_caption->buffer, + closed_caption->buf_len, closed_caption->pts, + closed_caption->scr); + } } + pthread_mutex_unlock(&this->cc_mutex); } break; } @@ -170,8 +360,10 @@ spu_decoder_t *init_spu_decoder_plugin (int iface_version, xine_t *xine) { this->xine = xine; this->cc_open = 0; - - cc_decoder_init(xine->config, &this->cc_cfg); + + pthread_mutex_init(&this->cc_mutex, NULL); + spucc_register_cfg_vars(this, xine->config); + cc_decoder_init(); xine_register_event_listener(xine, spudec_event_listener, this); |