summaryrefslogtreecommitdiff
path: root/src/libspucc/cc_decoder.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libspucc/cc_decoder.c')
-rw-r--r--src/libspucc/cc_decoder.c1486
1 files changed, 0 insertions, 1486 deletions
diff --git a/src/libspucc/cc_decoder.c b/src/libspucc/cc_decoder.c
deleted file mode 100644
index 00300adc2..000000000
--- a/src/libspucc/cc_decoder.c
+++ /dev/null
@@ -1,1486 +0,0 @@
-/*
- * Copyright (C) 2000-2003 the xine project
- *
- * Copyright (C) Christian Vogler
- * cvogler@gradient.cis.upenn.edu - December 2001
- *
- * This file is part of xine, a free video player.
- *
- * xine 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.
- *
- * xine 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * stuff needed to provide closed captioning decoding and display
- *
- * Some small bits and pieces of the EIA-608 captioning decoder were
- * adapted from CCDecoder 0.9.1 by Mike Baker. The latest version is
- * available at http://sourceforge.net/projects/ccdecoder/.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <sys/time.h>
-
-#include <inttypes.h>
-
-#include "xine_internal.h"
-#include "video_out.h"
-#include "xineutils.h"
-#include "osd.h"
-#include "cc_decoder.h"
-#include "osd.h"
-
-/*
-#define LOG_DEBUG 3
-*/
-
-/* at 29.97 fps, each NTSC frame takes 3003 metronom ticks on the average. */
-#define NTSC_FRAME_DURATION 3003
-
-#define CC_ROWS 15
-#define CC_COLUMNS 32
-#define CC_CHANNELS 2
-
-/* 1 is the caption background color index in the OSD palettes. */
-#define CAP_BG_COL 1
-
-/* number of text colors specified by EIA-608 standard */
-#define NUM_FG_COL 7
-
-#ifndef WIN32
-/* colors specified by the EIA 608 standard */
-enum { WHITE, GREEN, BLUE, CYAN, RED, YELLOW, MAGENTA, BLACK, TRANSPARENT };
-#else
-/* colors specified by the EIA 608 standard */
-enum { WHITE, GREEN, BLUE, CYAN, RED, YELLOW, MAGENTA, BLACK };
-#endif
-
-
-
-/* color mapping to OSD text color indices */
-static const int text_colormap[NUM_FG_COL] = {
- OSD_TEXT1, OSD_TEXT2, OSD_TEXT3, OSD_TEXT4, OSD_TEXT5, OSD_TEXT6, OSD_TEXT7
-};
-
-
-/* -------------------- caption text colors -----------------------------*/
-/* FIXME: The colors look fine on an XShm display, but they look *terrible*
- with the Xv display on the NVidia driver on a GeForce 3. The colors bleed
- into each other more than I'd expect from the downsampling into YUV
- colorspace.
- At this moment, it looks like a problem in the Xv YUV blending functions.
-*/
-typedef struct colorinfo_s {
- clut_t bgcol; /* text background color */
- clut_t bordercol; /* text border color */
- clut_t textcol; /* text color */
-} colorinfo_t;
-
-
-static const colorinfo_t cc_text_trans[NUM_FG_COL] = {
- /* white, black border, translucid */
- {
- CLUT_Y_CR_CB_INIT(0x80, 0x80, 0x80),
- CLUT_Y_CR_CB_INIT(0x00, 0x80, 0x80),
- CLUT_Y_CR_CB_INIT(0xff, 0x80, 0x80)
- },
-
- /* green, black border, translucid */
- {
- CLUT_Y_CR_CB_INIT(0x80, 0x80, 0x80),
- CLUT_Y_CR_CB_INIT(0x00, 0x80, 0x80),
- CLUT_Y_CR_CB_INIT(0x90, 0x22, 0x35)
- },
-
- /* blue, black border, translucid */
- {
- CLUT_Y_CR_CB_INIT(0x80, 0x80, 0x80),
- CLUT_Y_CR_CB_INIT(0x00, 0x80, 0x80),
- CLUT_Y_CR_CB_INIT(0x29, 0x6e, 0xff)
- },
-
- /* cyan, black border, translucid */
- {
- CLUT_Y_CR_CB_INIT(0x80, 0x80, 0x80),
- CLUT_Y_CR_CB_INIT(0x00, 0x80, 0x80),
- CLUT_Y_CR_CB_INIT(0xaa, 0x10, 0xa6)
- },
-
- /* red, black border, translucid */
- {
- CLUT_Y_CR_CB_INIT(0x80, 0x80, 0x80),
- CLUT_Y_CR_CB_INIT(0x00, 0x80, 0x80),
- CLUT_Y_CR_CB_INIT(0x52, 0xf0, 0x5a)
- },
-
- /* yellow, black border, translucid */
- {
- CLUT_Y_CR_CB_INIT(0x80, 0x80, 0x80),
- CLUT_Y_CR_CB_INIT(0x00, 0x80, 0x80),
- CLUT_Y_CR_CB_INIT(0xd4, 0x92, 0x10)
- },
-
- /* magenta, black border, translucid */
- {
- CLUT_Y_CR_CB_INIT(0x80, 0x80, 0x80),
- CLUT_Y_CR_CB_INIT(0x00, 0x80, 0x80),
- CLUT_Y_CR_CB_INIT(0x6b, 0xde, 0xca)
- }
-};
-
-static const colorinfo_t cc_text_solid[NUM_FG_COL] = {
- /* white, black border, solid */
- {
- CLUT_Y_CR_CB_INIT(0x00, 0x80, 0x80),
- CLUT_Y_CR_CB_INIT(0x00, 0x80, 0x80),
- CLUT_Y_CR_CB_INIT(0xff, 0x80, 0x80)
- },
-
- /* green, black border, solid */
- {
- CLUT_Y_CR_CB_INIT(0x00, 0x80, 0x80),
- CLUT_Y_CR_CB_INIT(0x00, 0x80, 0x80),
- CLUT_Y_CR_CB_INIT(0x90, 0x22, 0x35)
- },
-
- /* blue, black border, solid */
- {
- CLUT_Y_CR_CB_INIT(0x00, 0x80, 0x80),
- CLUT_Y_CR_CB_INIT(0x00, 0x80, 0x80),
- CLUT_Y_CR_CB_INIT(0x29, 0x6e, 0xff)
- },
-
- /* cyan, black border, solid */
- {
- CLUT_Y_CR_CB_INIT(0x00, 0x80, 0x80),
- CLUT_Y_CR_CB_INIT(0x00, 0x80, 0x80),
- CLUT_Y_CR_CB_INIT(0xaa, 0x10, 0xa6)
- },
-
- /* red, black border, solid */
- {
- CLUT_Y_CR_CB_INIT(0x00, 0x80, 0x80),
- CLUT_Y_CR_CB_INIT(0x00, 0x80, 0x80),
- CLUT_Y_CR_CB_INIT(0x52, 0xf0, 0x5a)
- },
-
- /* yellow, black border, solid */
- {
- CLUT_Y_CR_CB_INIT(0x00, 0x80, 0x80),
- CLUT_Y_CR_CB_INIT(0x00, 0x80, 0x80),
- CLUT_Y_CR_CB_INIT(0xd4, 0x92, 0x10)
- },
-
- /* magenta, black border, solid */
- {
- CLUT_Y_CR_CB_INIT(0x00, 0x80, 0x80),
- CLUT_Y_CR_CB_INIT(0x00, 0x80, 0x80),
- CLUT_Y_CR_CB_INIT(0x6b, 0xde, 0xca)
- }
-};
-
-
-static const uint8_t cc_text_trans_alpha[TEXT_PALETTE_SIZE] = {
- 0, 8, 9, 10, 11, 12, 15, 15, 15, 15, 15
-};
-
-static const uint8_t cc_text_solid_alpha[TEXT_PALETTE_SIZE] = {
- 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15
-};
-
-
-static const colorinfo_t *const cc_text_palettes[NUM_CC_PALETTES] = {
- cc_text_trans,
- cc_text_solid
-};
-
-static const uint8_t *const cc_alpha_palettes[NUM_CC_PALETTES] = {
- cc_text_trans_alpha,
- cc_text_solid_alpha
-};
-
-/* --------------------- misc. EIA 608 definitions -------------------*/
-
-#define TRANSP_SPACE 0x19 /* code for transparent space, essentially
- arbitrary */
-
-/* mapping from PAC row code to actual CC row */
-static const int rowdata[] = {10, -1, 0, 1, 2, 3, 11, 12, 13, 14, 4, 5, 6,
- 7, 8, 9};
-/* FIXME: do real ™ (U+2122) */
-/* Code 182 must be mapped as a musical note ('♪', U+266A) in the caption font */
-static const char specialchar[] = {
- 174 /* ® */, 176 /* ° */, 189 /* ½ */, 191 /* ¿ */,
- 'T' /* ™ */, 162 /* ¢ */, 163 /* £ */, 182 /* ¶ => ♪ */,
- 224 /* à */, TRANSP_SPACE,232 /* è */, 226 /* â */,
- 234 /* ê */, 238 /* î */, 244 /* ô */, 251 /* û */
-};
-
-/* character translation table - EIA 608 codes are not all the same as ASCII */
-static char chartbl[128];
-
-/* CC codes use odd parity for error detection, since they originally were */
-/* transmitted via noisy video signals */
-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.
- */
-/*FIXME: bug in OSD or SPU?*/
- int64_t display_vpts; /* vpts of currently displayed caption */
-
- /* this variable is an even worse hack: in some rare cases, the pts
- information on the DVD gets out of sync with the caption information.
- If this happens, the vpts of a hide caption event can actually be
- slightly higher than the vpts of the following show caption event.
- For this reason, we remember the vpts of the hide event and force
- the next show event's vpts to be at least equal to the hide event's
- vpts.
- */
- int64_t last_hide_vpts;
-
- /* caption palette and alpha channel */
- uint32_t cc_palette[OVL_PALETTE_SIZE];
- uint8_t cc_trans[OVL_PALETTE_SIZE];
-
- metronom_t *metronom; /* the active xine metronom */
-
- cc_state_t *cc_state; /* captioning configuration */
-};
-
-
-/* CC attribute */
-typedef struct cc_attribute_s {
- uint8_t italic;
- uint8_t underline;
- uint8_t foreground;
- uint8_t background;
-} cc_attribute_t;
-
-/* CC character cell */
-typedef struct cc_char_cell_s {
- uint8_t c; /* character code, not the same as ASCII */
- cc_attribute_t attributes; /* attributes of this character, if changed */
- /* here */
- int midrow_attr; /* true if this cell changes an attribute */
-} cc_char_cell_t;
-
-/* a single row in the closed captioning memory */
-typedef struct cc_row_s {
- cc_char_cell_t cells[CC_COLUMNS];
- int pos; /* position of the cursor */
- int num_chars; /* how many characters in the row are data */
- int attr_chg; /* true if midrow attr. change at cursor pos */
- int pac_attr_chg; /* true if attribute has changed via PAC */
- cc_attribute_t pac_attr; /* PAC attr. that hasn't been applied yet */
-} cc_row_t;
-
-/* closed captioning memory for a single channel */
-typedef struct cc_buffer_s {
- cc_row_t rows[CC_ROWS];
- int rowpos; /* row cursor position */
-} cc_buffer_t;
-
-/* captioning memory for all channels */
-typedef struct cc_memory_s {
- cc_buffer_t channel[CC_CHANNELS];
- int channel_no; /* currently active channel */
-} cc_memory_t;
-
-/* The closed captioning decoder data structure */
-struct cc_decoder_s {
- /* CC decoder buffer - one onscreen, one offscreen */
- cc_memory_t buffer[2];
- /* onscreen, offscreen buffer ptrs */
- cc_memory_t *on_buf;
- cc_memory_t *off_buf;
- /* which buffer is active for receiving data */
- cc_memory_t **active;
-
- /* for logging and debugging purposes, captions are assigned increasing */
- /* unique ids. */
- uint32_t capid;
-
- /* the last captioning code seen (control codes are often sent twice
- in a row, but should be processed only once) */
- uint32_t lastcode;
-
- /* The PTS and SCR at which the captioning chunk started */
- int64_t pts;
- /* holds the NTSC frame offset to last known pts/scr */
- uint32_t f_offset;
-
- /* active OSD renderer */
- osd_renderer_t *renderer;
- /* true when caption currently is displayed */
- int displayed;
-
- /* configuration and intrinsics of CC decoder */
- cc_state_t *cc_state;
-
- metronom_t *metronom;
-};
-
-
-/*---------------- general utility functions ---------------------*/
-
-static void get_font_metrics(osd_renderer_t *renderer,
- const char *fontname, int font_size,
- int *maxw, int *maxh)
-{
- int c;
- osd_object_t *testc = renderer->new_object(renderer, 640, 480);
-
- *maxw = 0;
- *maxh = 0;
-
- renderer->set_font(testc, (char *) fontname, font_size);
- renderer->set_encoding(testc, "iso-8859-1");
- for (c = 32; c < 256; c++) {
- int tw, th;
- char buf[2];
-
- buf[0] = (char)c;
- buf[1] = '\0';
-
- renderer->get_text_size(testc, buf, &tw, &th);
- *maxw = MAX(*maxw, tw);
- *maxh = MAX(*maxh, th);
- }
- renderer->free_object(testc);
-}
-
-
-static int parity(uint8_t byte)
-{
- int i;
- int ones = 0;
-
- for (i = 0; i < 7; i++) {
- if (byte & (1 << i))
- ones++;
- }
-
- return ones & 1;
-}
-
-
-static void build_parity_table(void)
-{
- uint8_t byte;
- int parity_v;
- for (byte = 0; byte <= 127; byte++) {
- parity_v = parity(byte);
- /* CC uses odd parity (i.e., # of 1's in byte is odd.) */
- parity_table[byte] = parity_v;
- parity_table[byte | 0x80] = !parity_v;
- }
-}
-
-
-static int good_parity(uint16_t data)
-{
- int ret = parity_table[data & 0xff] && parity_table[(data & 0xff00) >> 8];
- if (! ret)
- printf("Bad parity in EIA-608 data (%x)\n", data);
- return ret;
-}
-
-
-static void build_char_table(void)
-{
- int i;
- /* first the normal ASCII codes */
- for (i = 0; i < 128; i++)
- chartbl[i] = (char) i;
- /* now the special codes */
- chartbl[0x2a] = 225; /* á */
- chartbl[0x5c] = 233; /* é */
- chartbl[0x5e] = 237; /* í */
- chartbl[0x5f] = 243; /* ó */
- chartbl[0x60] = 250; /* ú */
- chartbl[0x7b] = 231; /* ç */
- chartbl[0x7c] = 247; /* ÷ */
- chartbl[0x7d] = 209; /* Ñ */
- chartbl[0x7e] = 241; /* ñ */
- chartbl[0x7f] = 164; /* ¤ FIXME: should be a solid block ('█'; U+2588) */
-}
-
-
-static clut_t interpolate_color(clut_t src, clut_t dest, int steps,
- int current_step)
-{
- int diff_y = ((int) dest.y) - ((int) src.y);
- int diff_cr = ((int) dest.cr) - ((int) src.cr);
- int diff_cb = ((int) dest.cb) - ((int) src.cb);
- int res_y = ((int) src.y) + (diff_y * current_step / (steps + 1));
- int res_cr = ((int) src.cr) + (diff_cr * current_step / (steps + 1));
- int res_cb = ((int) src.cb) + (diff_cb * current_step / (steps + 1));
-#if __SUNPRO_C
- /*
- * Sun's Forte compiler refuses to initialize automatic structure
- * variable with bitfields, so we use explicit assignments for now.
- */
- clut_t res;
- res.y = res_y;
- res.cr = res_cr;
- res.cb = res_cb;
- res.foo = 0;
-#else
- clut_t res = CLUT_Y_CR_CB_INIT((uint8_t) res_y, (uint8_t) res_cr,
- (uint8_t) res_cb);
-#endif
- return res;
-}
-
-/*----------------- cc_row_t methods --------------------------------*/
-
-static void ccrow_fill_transp(cc_row_t *rowbuf){
- int i;
-
-#ifdef LOG_DEBUG
- printf("cc_decoder: ccrow_fill_transp: Filling in %d transparent spaces.\n",
- rowbuf->pos - rowbuf->num_chars);
-#endif
- for (i = rowbuf->num_chars; i < rowbuf->pos; i++) {
- rowbuf->cells[i].c = TRANSP_SPACE;
- rowbuf->cells[i].midrow_attr = 0;
- }
-}
-
-
-static int ccrow_find_next_text_part(cc_row_t *this, int pos)
-{
- while (pos < this->num_chars && this->cells[pos].c == TRANSP_SPACE)
- pos++;
- return pos;
-}
-
-
-static int ccrow_find_end_of_text_part(cc_row_t *this, int pos)
-{
- while (pos < this->num_chars && this->cells[pos].c != TRANSP_SPACE)
- pos++;
- return pos;
-}
-
-
-static int ccrow_find_current_attr(cc_row_t *this, int pos)
-{
- while (pos > 0 && !this->cells[pos].midrow_attr)
- pos--;
- return pos;
-}
-
-
-static int ccrow_find_next_attr_change(cc_row_t *this, int pos, int lastpos)
-{
- pos++;
- while (pos < lastpos && !this->cells[pos].midrow_attr)
- pos++;
- return pos;
-}
-
-
-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_config_t *cap_info = renderer->cc_state->cc_cfg;
-
- if (attr->italic)
- fontname = cap_info->italic_font;
- else
- fontname = cap_info->font;
- renderer->osd_renderer->set_font(renderer->cap_display, (char *) fontname,
- cap_info->font_size);
-}
-
-
-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_config_t *cap_info = renderer->cc_state->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 = (renderer->height * rownum * 100 + renderer->height * 50) /
- (CC_ROWS * 100);
- }
- else
- 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 */
- while (pos < this->num_chars) {
- int endpos = ccrow_find_end_of_text_part(this, pos);
- int seg_begin = pos;
- int seg_end;
- int i;
- int text_w = 0, text_h = 0;
- int x, y;
- int seg_w, seg_h;
- int seg_pos[CC_COLUMNS + 1];
- int seg_attr[CC_COLUMNS];
- int cumulative_seg_width[CC_COLUMNS + 1];
- int num_seg = 0;
- int seg;
-
- /* break down each part into segments bounded by attribute changes and */
- /* find text metrics of the parts */
- seg_pos[0] = seg_begin;
- cumulative_seg_width[0] = 0;
- while (seg_begin < endpos) {
- int attr_pos = ccrow_find_current_attr(this, seg_begin);
- seg_end = ccrow_find_next_attr_change(this, seg_begin, endpos);
-
- /* compute text size of segment */
- 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(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;
- text_h += seg_h;
- seg_pos[num_seg + 1] = seg_end;
- seg_attr[num_seg] = attr_pos;
- cumulative_seg_width[num_seg + 1] = text_w;
- num_seg++;
-
- seg_begin = seg_end;
- }
-
- /* compute x coordinate of part */
- if (cap_info->center) {
- 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 - (renderer->max_char_height + 1) / 2;
- }
- else {
- x = renderer->width * pos / CC_COLUMNS;
- y = base_y;
- }
-
-#ifdef LOG_DEBUG
- printf("text_w, text_h = %d, %d\n", text_w, text_h);
- printf("cc from %d to %d; text plotting from %d, %d (basey = %d)\n", pos, endpos, x, y, base_y);
-#endif
-
- /* render text part by rendering each attributed text segment */
- for (seg = 0; seg < num_seg; seg++) {
- int textcol = text_colormap[this->cells[seg_attr[seg]].attributes.foreground];
- int box_x1 = x + cumulative_seg_width[seg];
- int box_x2 = x + cumulative_seg_width[seg + 1];
-
-#ifdef LOG_DEBUG
- printf("ccrow_render: rendering segment %d from %d to %d / %d to %d\n",
- seg, seg_pos[seg], seg_pos[seg + 1],
- x + cumulative_seg_width[seg], x + cumulative_seg_width[seg + 1]);
-#endif
- /* make caption background a uniform box. Without this line, the */
- /* background is uneven for superscript characters. */
- /* Also pad left & right ends of caption to make it more readable */
-/*FIXME: There may be off-by one errors in the rendering - check with Miguel*/
- if (seg == 0)
- box_x1 -= renderer->max_char_width;
- if (seg == num_seg - 1)
- box_x2 += renderer->max_char_width;
- osd_renderer->filled_rect(renderer->cap_display, box_x1, y, box_x2,
- y + renderer->max_char_height,
- textcol + CAP_BG_COL);
-
- 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(renderer, this, seg_attr[seg]);
-
- /* text is already mapped from EIA-608 into iso-8859-1 */
- osd_renderer->render_text(renderer->cap_display,
- x + cumulative_seg_width[seg], y, buf,
- textcol);
- }
-
- pos = ccrow_find_next_text_part(this, endpos);
- }
-}
-
-
-/*----------------- cc_buffer_t methods --------------------------------*/
-
-static int ccbuf_has_displayable(cc_buffer_t *this)
-{
- int i;
- int found = 0;
- for (i = 0; !found && i < CC_ROWS; i++) {
- if (this->rows[i].num_chars > 0)
- found = 1;
- }
- return found;
-}
-
-
-static void ccbuf_add_char(cc_buffer_t *this, uint8_t c)
-{
- cc_row_t *rowbuf = &this->rows[this->rowpos];
- int pos = rowbuf->pos;
- int left_displayable = (pos > 0) && (pos <= rowbuf->num_chars);
-
-#if LOG_DEBUG > 2
- printf("cc_decoder: ccbuf_add_char: %c @ %d/%d\n", c, this->rowpos, pos);
-#endif
-
- if (pos >= CC_COLUMNS) {
- printf("cc_decoder: ccbuf_add_char: row buffer overflow\n");
- return;
- }
-
- if (pos > rowbuf->num_chars) {
- /* fill up to indented position with transparent spaces, if necessary */
- ccrow_fill_transp(rowbuf);
- }
-
- /* midrow PAC attributes are applied only if there is no displayable */
- /* character to the immediate left. This makes the implementation rather */
- /* complicated, but this is what the EIA-608 standard specifies. :-( */
- if (rowbuf->pac_attr_chg && !rowbuf->attr_chg && !left_displayable) {
- rowbuf->attr_chg = 1;
- rowbuf->cells[pos].attributes = rowbuf->pac_attr;
-#ifdef LOG_DEBUG
- printf("cc_decoder: ccbuf_add_char: Applying midrow PAC.\n");
-#endif
- }
-
- rowbuf->cells[pos].c = c;
- rowbuf->cells[pos].midrow_attr = rowbuf->attr_chg;
- rowbuf->pos++;
-
- if (rowbuf->num_chars < rowbuf->pos)
- rowbuf->num_chars = rowbuf->pos;
-
- rowbuf->attr_chg = 0;
- rowbuf->pac_attr_chg = 0;
-}
-
-
-static void ccbuf_set_cursor(cc_buffer_t *this, int row, int column,
- int underline, int italics, int color)
-{
- cc_row_t *rowbuf = &this->rows[row];
- cc_attribute_t attr;
-
- attr.italic = italics;
- attr.underline = underline;
- attr.foreground = color;
- attr.background = BLACK;
-
- rowbuf->pac_attr = attr;
- rowbuf->pac_attr_chg = 1;
-
- this->rowpos = row;
- rowbuf->pos = column;
- rowbuf->attr_chg = 0;
-}
-
-
-static void ccbuf_apply_attribute(cc_buffer_t *this, cc_attribute_t *attr)
-{
- cc_row_t *rowbuf = &this->rows[this->rowpos];
- int pos = rowbuf->pos;
-
- rowbuf->attr_chg = 1;
- rowbuf->cells[pos].attributes = *attr;
- /* A midrow attribute always counts as a space */
- ccbuf_add_char(this, chartbl[(unsigned int) ' ']);
-}
-
-
-static void ccbuf_tab(cc_buffer_t *this, int tabsize)
-{
- cc_row_t *rowbuf = &this->rows[this->rowpos];
- rowbuf->pos += tabsize;
- if (rowbuf->pos > CC_COLUMNS) {
-#ifdef LOG_DEBUG
- printf("cc_decoder: ccbuf_tab: row buffer overflow\n");
-#endif
- rowbuf->pos = CC_COLUMNS;
- return;
- }
- /* tabs have no effect on pending PAC attribute changes */
-}
-
-
-static void ccbuf_render(cc_renderer_t *renderer, cc_buffer_t *this)
-{
- int row;
-
-#ifdef LOG_DEBUG
- printf("cc_decoder: ccbuf_render\n");
-#endif
-
- for (row = 0; row < CC_ROWS; ++row) {
- if (this->rows[row].num_chars > 0)
- ccrow_render(renderer, &this->rows[row], row);
- }
-}
-
-
-/*----------------- cc_memory_t methods --------------------------------*/
-
-static void ccmem_clear(cc_memory_t *this)
-{
-#ifdef LOG_DEBUG
- printf("cc_decoder.c: ccmem_clear: Clearing CC memory\n");
-#endif
- memset(this, 0, sizeof (cc_memory_t));
-}
-
-
-static void ccmem_init(cc_memory_t *this)
-{
- ccmem_clear(this);
-}
-
-
-static void ccmem_exit(cc_memory_t *this)
-{
-/*FIXME: anything to deallocate?*/
-}
-
-
-/*----------------- cc_renderer_t methods -------------------------------*/
-
-static void cc_renderer_build_palette(cc_renderer_t *this)
-{
- int i, j;
- const colorinfo_t *cc_text = cc_text_palettes[this->cc_state->cc_cfg->cc_scheme];
- const uint8_t *cc_alpha = cc_alpha_palettes[this->cc_state->cc_cfg->cc_scheme];
-
- memset(this->cc_palette, 0, sizeof (this->cc_palette));
- memset(this->cc_trans, 0, sizeof (this->cc_trans));
- for (i = 0; i < NUM_FG_COL; i++) {
- /* background color */
- this->cc_palette[i * TEXT_PALETTE_SIZE + 1 + OSD_TEXT1] =
- *(uint32_t *) &cc_text[i].bgcol;
- /* background -> border */
- for (j = 2; j <= 5; j++) {
- clut_t col = interpolate_color(cc_text[i].bgcol,
- cc_text[i].bordercol, 4, j - 1);
- this->cc_palette[i * TEXT_PALETTE_SIZE + j + OSD_TEXT1] =
- *(uint32_t *) &col;
- }
- /* border color */
- this->cc_palette[i * TEXT_PALETTE_SIZE + 6 + OSD_TEXT1] =
- *(uint32_t *) &cc_text[i].bordercol;
- /* border -> foreground */
- for (j = 7; j <= 9; j++) {
- clut_t col = interpolate_color(cc_text[i].bordercol,
- cc_text[i].textcol, 3, j - 6);
- this->cc_palette[i * TEXT_PALETTE_SIZE + j + OSD_TEXT1] =
- *(uint32_t *) &col;
- }
- /* foreground color */
- this->cc_palette[i * TEXT_PALETTE_SIZE + 10 + OSD_TEXT1] =
- *(uint32_t *) &cc_text[i].textcol;
-
- /* alpha values */
- for (j = 0; j <= 10; j++)
- this->cc_trans[i * TEXT_PALETTE_SIZE + j + OSD_TEXT1] = cc_alpha[j];
- }
-}
-
-
-static int64_t cc_renderer_calc_vpts(cc_renderer_t *this, int64_t pts,
- uint32_t ntsc_frame_offset)
-{
- metronom_t *metronom = this->metronom;
- int64_t vpts = metronom->got_spu_packet(metronom, pts);
- 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, int64_t vpts)
-{
- if (this->displayed) {
- this->osd_renderer->hide(this->cap_display, vpts);
- this->displayed = 0;
- this->last_hide_vpts = vpts;
- }
-}
-
-
-static void cc_renderer_show_caption(cc_renderer_t *this, cc_buffer_t *buf,
- int64_t vpts)
-{
-#ifdef LOG_DEBUG
- 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);
- vpts = MAX(vpts, this->last_hide_vpts);
- this->osd_renderer->show(this->cap_display, vpts);
-
- this->displayed = 1;
- this->display_vpts = vpts;
-}
-
-
-static void cc_renderer_free_osd_object(cc_renderer_t *this)
-{
- /* 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 void cc_renderer_adjust_osd_object(cc_renderer_t *this)
-{
- 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_palette(this->cap_display, this->cc_palette,
- this->cc_trans);
- this->osd_renderer->set_encoding(this->cap_display, "iso-8859-1");
-}
-
-
-cc_renderer_t *cc_renderer_open(osd_renderer_t *osd_renderer,
- metronom_t *metronom, cc_state_t *cc_state,
- int video_width, int video_height)
-{
- cc_renderer_t *this = calloc(1, sizeof (cc_renderer_t));
-
- this->osd_renderer = osd_renderer;
- this->metronom = metronom;
- this->cc_state = cc_state;
- cc_renderer_update_cfg(this, video_width, video_height);
-#ifdef LOG_DEBUG
- printf("spucc: cc_renderer: open\n");
-#endif
- return this;
-}
-
-
-void cc_renderer_close(cc_renderer_t *this_obj)
-{
- 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;
-
- /* fill in text palette */
- cc_renderer_build_palette(this_obj);
-
- /* 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_state->cc_cfg->font,
- this_obj->cc_state->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_state->cc_cfg->italic_font,
- this_obj->cc_state->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("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;
- }
-
- if (required_w <= this_obj->video_width &&
- required_h <= this_obj->video_height) {
- this_obj->cc_state->can_cc = 1;
- cc_renderer_adjust_osd_object(this_obj);
- }
- else {
- this_obj->cc_state->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
-
- if (cc_renderer_on_display(this->cc_state->renderer)) {
- int64_t vpts = cc_renderer_calc_vpts(this->cc_state->renderer, this->pts,
- this->f_offset);
-#ifdef LOG_DEBUG
- printf("cc_decoder: cc_hide_displayed: hiding caption %u at vpts %u\n", this->capid, vpts);
-#endif
- cc_renderer_hide_caption(this->cc_state->renderer, vpts);
- }
-}
-
-
-static void cc_show_displayed(cc_decoder_t *this)
-{
-#ifdef LOG_DEBUG
- printf("cc_decoder: cc_show_displayed\n");
-#endif
-
- if (cc_onscreen_displayable(this)) {
- int64_t vpts = cc_renderer_calc_vpts(this->cc_state->renderer, this->pts,
- this->f_offset);
-#ifdef LOG_DEBUG
- printf("cc_decoder: cc_show_displayed: showing caption %u at vpts %u\n", this->capid, vpts);
-#endif
- this->capid++;
- cc_renderer_show_caption(this->cc_state->renderer,
- &this->on_buf->channel[this->on_buf->channel_no],
- vpts);
- }
-}
-
-
-static void cc_swap_buffers(cc_decoder_t *this)
-{
- cc_memory_t *temp;
-
- /* hide caption in displayed memory */
- cc_hide_displayed(this);
-
-#ifdef LOG_DEBUG
- printf("cc_decoder: cc_swap_buffers: swapping caption memory\n");
-#endif
- temp = this->on_buf;
- this->on_buf = this->off_buf;
- this->off_buf = temp;
-
- /* show new displayed memory */
- cc_show_displayed(this);
-}
-
-static void cc_decode_standard_char(cc_decoder_t *this, uint8_t c1, uint8_t c2)
-{
- cc_buffer_t *buf = active_ccbuffer(this);
- /* c1 always is a valid character */
- ccbuf_add_char(buf, chartbl[c1]);
- /* c2 might not be a printable character, even if c1 was */
- if (c2 & 0x60)
- ccbuf_add_char(buf, chartbl[c2]);
-}
-
-
-static void cc_decode_PAC(cc_decoder_t *this, int channel,
- uint8_t c1, uint8_t c2)
-{
- cc_buffer_t *buf;
- int row, column = 0;
- int underline, italics = 0, color;
-
- /* There is one invalid PAC code combination. Ignore it. */
- if (c1 == 0x10 && c2 > 0x5f)
- return;
-
- cc_set_channel(this, channel);
- buf = active_ccbuffer(this);
-
- row = rowdata[((c1 & 0x07) << 1) | ((c2 & 0x20) >> 5)];
- if (c2 & 0x10) {
- column = ((c2 & 0x0e) >> 1) * 4; /* preamble indentation */
- color = WHITE; /* indented lines have white color */
- }
- else if ((c2 & 0x0e) == 0x0e) {
- italics = 1; /* italics, they are always white */
- color = WHITE;
- }
- else
- color = (c2 & 0x0e) >> 1;
- underline = c2 & 0x01;
-
-#ifdef LOG_DEBUG
- printf("cc_decoder: cc_decode_PAC: row %d, col %d, ul %d, it %d, clr %d\n",
- row, column, underline, italics, color);
-#endif
-
- ccbuf_set_cursor(buf, row, column, underline, italics, color);
-}
-
-
-static void cc_decode_ext_attribute(cc_decoder_t *this, int channel,
- uint8_t c1, uint8_t c2)
-{
- cc_set_channel(this, channel);
-}
-
-
-static void cc_decode_special_char(cc_decoder_t *this, int channel,
- uint8_t c1, uint8_t c2)
-{
- cc_buffer_t *buf;
-
- cc_set_channel(this, channel);
- buf = active_ccbuffer(this);
-#ifdef LOG_DEBUG
- printf("cc_decoder: cc_decode_special_char: Mapping %x to %x\n", c2, specialchar[c2 & 0xf]);
-#endif
- ccbuf_add_char(buf, specialchar[c2 & 0xf]);
-}
-
-
-static void cc_decode_midrow_attr(cc_decoder_t *this, int channel,
- uint8_t c1, uint8_t c2)
-{
- cc_buffer_t *buf;
- cc_attribute_t attr;
-
- cc_set_channel(this, channel);
- buf = active_ccbuffer(this);
- if (c2 < 0x2e) {
- attr.italic = 0;
- attr.foreground = (c2 & 0xe) >> 1;
- }
- else {
- attr.italic = 1;
- attr.foreground = WHITE;
- }
- attr.underline = c2 & 0x1;
- attr.background = BLACK;
-#ifdef LOG_DEBUG
- printf("cc_decoder: cc_decode_midrow_attr: attribute %x\n", c2);
- printf("cc_decoder: cc_decode_midrow_attr: ul %d, it %d, clr %d\n",
- attr.underline, attr.italic, attr.foreground);
-#endif
-
- ccbuf_apply_attribute(buf, &attr);
-}
-
-
-static void cc_decode_misc_control_code(cc_decoder_t *this, int channel,
- uint8_t c1, uint8_t c2)
-{
-#ifdef LOG_DEBUG
- printf("cc_decoder: decode_misc: decoding %x %x\n", c1, c2);
-#endif
-
- cc_set_channel(this, channel);
-
- switch (c2) { /* 0x20 <= c2 <= 0x2f */
-
- case 0x20: /* RCL */
- break;
-
- case 0x21: /* backspace */
-#ifdef LOG_DEBUG
- printf("cc_decoder: backspace\n");
-#endif
- break;
-
- case 0x24: /* DER */
- break;
-
- case 0x25: /* RU2 */
- break;
-
- case 0x26: /* RU3 */
- break;
-
- case 0x27: /* RU4 */
- break;
-
- case 0x28: /* FON */
- break;
-
- case 0x29: /* RDC */
- break;
-
- case 0x2a: /* TR */
- break;
-
- case 0x2b: /* RTD */
- break;
-
- case 0x2c: /* EDM - erase displayed memory */
- cc_hide_displayed(this);
- ccmem_clear(this->on_buf);
- break;
-
- case 0x2d: /* carriage return */
- break;
-
- case 0x2e: /* ENM - erase non-displayed memory */
- ccmem_clear(this->off_buf);
- break;
-
- case 0x2f: /* EOC - swap displayed and non displayed memory */
- cc_swap_buffers(this);
- break;
- }
-}
-
-
-static void cc_decode_tab(cc_decoder_t *this, int channel,
- uint8_t c1, uint8_t c2)
-{
- cc_buffer_t *buf;
-
- cc_set_channel(this, channel);
- buf = active_ccbuffer(this);
- ccbuf_tab(buf, c2 & 0x3);
-}
-
-
-static void cc_decode_EIA608(cc_decoder_t *this, uint16_t data)
-{
- uint8_t c1 = data & 0x7f;
- uint8_t c2 = (data >> 8) & 0x7f;
-
-#if LOG_DEBUG >= 3
- printf("decoding %x %x\n", c1, c2);
-#endif
-
- if (c1 & 0x60) { /* normal character, 0x20 <= c1 <= 0x7f */
- cc_decode_standard_char(this, c1, c2);
- }
- else if (c1 & 0x10) { /* control code or special character */
- /* 0x10 <= c1 <= 0x1f */
- int channel = (c1 & 0x08) >> 3;
- c1 &= ~0x08;
-
- /* control sequences are often repeated. In this case, we should */
- /* evaluate it only once. */
- if (data != this->lastcode) {
-
- if (c2 & 0x40) { /* preamble address code: 0x40 <= c2 <= 0x7f */
- cc_decode_PAC(this, channel, c1, c2);
- }
- else {
- switch (c1) {
-
- case 0x10: /* extended background attribute code */
- cc_decode_ext_attribute(this, channel, c1, c2);
- break;
-
- case 0x11: /* attribute or special character */
- if ((c2 & 0x30) == 0x30) { /* special char: 0x30 <= c2 <= 0x3f */
- cc_decode_special_char(this, channel, c1, c2);
- }
- else if (c2 & 0x20) { /* midrow attribute: 0x20 <= c2 <= 0x2f */
- cc_decode_midrow_attr(this, channel, c1, c2);
- }
- break;
-
- case 0x14: /* possibly miscellaneous control code */
- cc_decode_misc_control_code(this, channel, c1, c2);
- break;
-
- case 0x17: /* possibly misc. control code TAB offset */
- /* 0x21 <= c2 <= 0x23 */
- if (c2 >= 0x21 && c2 <= 0x23) {
- cc_decode_tab(this, channel, c1, c2);
- }
- break;
- }
- }
- }
- }
-
- this->lastcode = data;
-}
-
-
-void decode_cc(cc_decoder_t *this, uint8_t *buffer, uint32_t buf_len,
- int64_t pts)
-{
- /* The first number may denote a channel number. I don't have the
- * EIA-708 standard, so it is hard to say.
- * From what I could figure out so far, the general format seems to be:
- *
- * repeat
- *
- * 0xfe starts 2 byte sequence of unknown purpose. It might denote
- * field #2 in line 21 of the VBI. We'll ignore it for the
- * time being.
- *
- * 0xff starts 2 byte EIA-608 sequence, field #1 in line 21 of the VBI.
- * Followed by a 3-code triplet that starts either with 0xff or
- * 0xfe. In either case, the following triplet needs to be ignored
- * for line 21, field 1.
- *
- * 0x00 is padding, followed by 2 more 0x00.
- *
- * 0x01 always seems to appear at the beginning, always seems to
- * be followed by 0xf8, 8-bit number.
- * The lower 7 bits of this 8-bit number seem to denote the
- * number of code triplets that follow.
- * The most significant bit denotes whether the Line 21 field 1
- * captioning information is at odd or even triplet offsets from this
- * beginning triplet. 1 denotes odd offsets, 0 denotes even offsets.
- *
- * Most captions are encoded with odd offsets, so this is what we
- * will assume.
- *
- * until end of packet
- */
- uint8_t *current = buffer;
- uint32_t curbytes = 0;
- uint8_t data1, data2;
- uint8_t cc_code;
- int odd_offset = 1;
-
- this->f_offset = 0;
- this->pts = pts;
-
-#if LOG_DEBUG >= 2
- printf("libspucc: decode_cc: got pts %u\n", pts);
- {
- uint8_t *cur_d = buffer;
- printf("libspucc: decode_cc: codes: ");
- while (cur_d < buffer + buf_len) {
- printf("0x%0x ", *cur_d++);
- }
- printf("\n");
- }
-#endif
-
- while (curbytes < buf_len) {
- int skip = 2;
-
- cc_code = *current++;
- curbytes++;
-
- if (buf_len - curbytes < 2) {
-#ifdef LOG_DEBUG
- fprintf(stderr, "Not enough data for 2-byte CC encoding\n");
-#endif
- break;
- }
-
- data1 = *current;
- data2 = *(current + 1);
-
- switch (cc_code) {
- case 0xfe:
- /* expect 2 byte encoding (perhaps CC3, CC4?) */
- /* ignore for time being */
- skip = 2;
- break;
-
- case 0xff:
- /* expect EIA-608 CC1/CC2 encoding */
- if (good_parity(data1 | (data2 << 8))) {
- cc_decode_EIA608(this, data1 | (data2 << 8));
- this->f_offset++;
- }
- skip = 5;
- break;
-
- case 0x00:
- /* This seems to be just padding */
- skip = 2;
- break;
-
- case 0x01:
- odd_offset = data2 & 0x80;
- if (odd_offset)
- skip = 2;
- else
- skip = 5;
- break;
-
- default:
-#ifdef LOG_DEBUG
- fprintf(stderr, "Unknown CC encoding: %x\n", cc_code);
-#endif
- skip = 2;
- break;
- }
- current += skip;
- curbytes += skip;
- }
-}
-
-
-
-cc_decoder_t *cc_decoder_open(cc_state_t *cc_state)
-{
- cc_decoder_t *this = calloc(1, sizeof (cc_decoder_t));
- /* configfile stuff */
- this->cc_state = cc_state;
-
- ccmem_init(&this->buffer[0]);
- ccmem_init(&this->buffer[1]);
- this->on_buf = &this->buffer[0];
- this->off_buf = &this->buffer[1];
- this->active = &this->off_buf;
-
- this->lastcode = 0;
- this->capid = 0;
-
- this->pts = this->f_offset = 0;
-
-#ifdef LOG_DEBUG
- printf("spucc: cc_decoder_open\n");
-#endif
- return this;
-}
-
-
-void cc_decoder_close(cc_decoder_t *this)
-{
- ccmem_exit(&this->buffer[0]);
- ccmem_exit(&this->buffer[1]);
-
- free(this);
-
-#ifdef LOG_DEBUG
- printf("spucc: cc_decoder_close\n");
-#endif
-}
-
-
-/*--------------- initialization methods --------------------------*/
-
-void cc_decoder_init(void)
-{
- build_parity_table();
- build_char_table();
-}
-