summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Vogler <cvogler@users.sourceforge.net>2002-01-07 19:30:09 +0000
committerChristian Vogler <cvogler@users.sourceforge.net>2002-01-07 19:30:09 +0000
commit16be79073dc84a67b72f7e1a5cac93a5b34782aa (patch)
tree14071f2a3a8e5a59b5208ec1bd7bd684a6342df8
parentd984be942f5a0d4601ff791683050ca36bd5c4cb (diff)
downloadxine-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.c553
-rw-r--r--src/libspucc/cc_decoder.h46
-rw-r--r--src/libspucc/xine_decoder.c278
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);