* parse.c: Philips OGT (SVCD subtitle) packet parser
*****************************************************************************
* Copyright (C) 2003 VideoLAN
- * $Id: cvd_parse.c,v 1.2 2003/12/28 11:26:52 rocky Exp $
+ * $Id: cvd_parse.c,v 1.3 2003/12/29 04:47:44 rocky Exp $
*
* Authors: Rocky Bernstein
* based on code from:
}
-/* Advance pointer to image pointer, update internal i_remaining counter
- and check that we haven't goine too far in the image data. */
-#define advance_color_pointer_byte \
+#define advance_color_byte_pointer \
p++; \
- i_remaining=4; \
+ i_remaining = 2; \
+ /* \
+ * This is wrong, it may exceed maxp if it is the last, check \
+ * should be moved to use location or the algorithm changed to \
+ * that in vob2sub \
+ */ \
if (p >= maxp) { \
msg_Warn( p_dec, \
- "broken subtitle - tried to access beyond end " \
- "in image extraction"); \
+ "broken subtitle - overflow while decoding " \
+ " padding (%d,%d,%d)\n", \
+ i_field, i_row, i_column ); \
return VLC_EGENERIC; \
- } \
-
-#define advance_color_pointer \
- i_remaining--; \
- if ( i_remaining == 0 ) { \
- advance_color_pointer_byte; \
}
/* Get the next field - either a palette index or a RLE count for
color 0. To do this we use byte image pointer p, and i_remaining
which indicates where we are in the byte.
*/
-static inline ogt_color_t
+static inline uint8_t
ExtractField(uint8_t *p, unsigned int i_remaining)
{
- return ( ( *p >> 2*(i_remaining-1) ) & 0x3 );
+ return ( ( *p >> 4*(i_remaining-1) ) & 0xf );
}
/*****************************************************************************
This part parses the subtitle graphical data and stores it in a more
convenient structure for later rendering.
- The image is encoded using two bits per pixel that select a palette
- entry except that value 0 starts a limited run-length encoding for
- color 0. When 0 is seen, the next two bits encode one less than the
- number of pixels, so we can encode run lengths from 1 to 4. These get
- filled with the color in palette entry 0.
-
- The encoding of each line is padded to a whole number of bytes. The
- first field is padded to an even byte length and the complete subtitle
- is padded to a 4-byte multiple that always include one zero byte at
- the end.
+ Image data comes interlaced and is run-length encoded (RLE). Each
+ field is a four-bit nibbles that is further subdivided in a two-bit
+ repeat count and a two-bit color number - up to three pixels can be
+ described in four bits. What a 0 repeat count means is unknown. It
+ might be used for RLE extension. There is a special case of a 0
+ repeat count though. When the full nibble is zero, the rest of the
+ line is filled with the color value in the next nibble. It is
+ unknown what happens if the color value is greater than three. The
+ rest seems to use a 4-entries palette. It is not impossible that the
+ fill-line complete case above is not as described and the zero repeat
+ count means fill line. The sample code never produces this, so it
+ may be untested.
However we'll transform this so that that the RLE is expanded and
interlacing will also be removed. On output each pixel entry will by
- an 8-bit alpha, y, u, and v entry.
+ a 4-bit alpha (filling 8 bits), and 8-bit y, u, and v entry.
*****************************************************************************/
static int
{
decoder_sys_t *p_sys = p_dec->p_sys;
- dbg_print( (DECODE_DBG_CALL) , "");
+ unsigned int i_field; /* The subtitles are interlaced, are we on an
+ even or odd scanline? */
+
+ unsigned int i_row; /* scanline row number */
+ unsigned int i_column; /* scanline column number */
+
+ unsigned int i_width = p_sys->i_width;
+ unsigned int i_height = p_sys->i_height;
+
+ uint8_t *p_dest = (uint8_t *)p_spu->p_sys->p_data;
+
+ uint8_t i_remaining; /* number of 2-bit pixels remaining
+ in byte of *p */
+ vlc_bool_t b_filling; /* Filling i_color to the of the line. */
+ uint8_t i_pending = 0; /* number of pixels to fill with
+ color zero 0..3 */
+ ogt_color_t i_color=0; /* current pixel color: 0..3 */
+ uint8_t *p = p_sys->subtitle_data + p_sys->comp_image_offset;
+ uint8_t *maxp = p + p_sys->comp_image_length;
+
+ dbg_print( (DECODE_DBG_CALL) , "width x height: %dx%d ",
+ i_width, i_height);
+
+ if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE)
+ printf("\n");
+
+ i_pending = 0;
+
+ for ( i_field=0; i_field < 2; i_field++ ) {
+ i_remaining = 2; /* 4-bit pieces available in *p */
+ b_filling = VLC_FALSE;
+
+ for ( i_row=i_field; i_row < i_height; i_row += 2 ) {
+ for ( i_column=0; i_column<i_width; i_column++ ) {
+ if ( i_pending ) {
+ /* We are in the middle of a RLE expansion, just decrement and
+ fall through with current color value */
+ i_pending--;
+ } else if ( b_filling ) {
+ /* We are just filling to the end of line with one color, just
+ reuse current color value */
+ } else {
+ uint8_t i_val = ExtractField(p, i_remaining--);
+ if ( i_remaining == 0 ) {
+ advance_color_byte_pointer;
+ }
+ if ( i_val == 0 ) {
+ /* fill the rest of the line with next color */
+ i_color = ExtractField( p, i_remaining-- );
+ if ( i_remaining == 0 ) {
+ p++;
+ i_remaining=2;
+ /*
+ This is wrong, it may exceed maxp if it is the
+ last, check should be moved to use location or the
+ algorithm changed to that in vob2sub
+ */
+ if (p >= maxp) {
+ msg_Warn( p_dec,
+ "broken subtitle - overflow while decoding "
+ " filling (%d,%d,%d)",
+ i_field, i_row, i_column);
+ /* return VLC_EGENERIC; */
+ }
+ }
+ b_filling = VLC_TRUE;
+ } else {
+ /* Normal case: get color and repeat count,
+ this iteration will output the first (or only)
+ instance */
+ i_pending = (i_val >> 2);
+ i_color = i_val & 0x3;
+ /* This time counts against the total */
+ i_pending--;
+ }
+ }
+ /* Color is 0-3. */
+ p_dest[i_row*i_width+i_column] = i_color;
+
+ if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE)
+ printf("%1d", i_color);
+
+ }
+
+ if ( i_remaining != 0 && i_remaining !=2 ) {
+ advance_color_byte_pointer;
+ }
+
+ if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE)
+ printf("\n");
+ }
+ }
+
+ /* The video is automatically scaled. However subtitle bitmaps
+ assume a 1:1 aspect ratio. So we need to scale to compensate for
+ or undo the effects of video output scaling.
+ */
+ /* FIXME do the right scaling depending on vout. It may not be 4:3 */
+ VCDSubScaleX( p_dec, p_spu, 3, 4 );
+
/* To be finished...*/
- return VLC_EGENERIC;
+ return VLC_SUCCESS;
}
* Philips OGT (SVCD subtitle) packet parser
*****************************************************************************
* Copyright (C) 2003 VideoLAN
- * $Id: ogt_parse.c,v 1.2 2003/12/28 11:26:52 rocky Exp $
+ * $Id: ogt_parse.c,v 1.3 2003/12/29 04:47:44 rocky Exp $
*
* Author: Rocky Bernstein
* based on code from:
p_sys->pi_palette[i].s.y = *p++;
p_sys->pi_palette[i].s.u = *p++;
p_sys->pi_palette[i].s.v = *p++;
- /* Note alpha is 8 bits. DVD's use only 4 bits. Our rendering routine
- will use an 8-bit transparancy.
+ /* OGT has 8-bit resolution for alpha, but DVD's and CVDS use 4-bits.
+ Since we want to use the same render routine, rather than scale up
+ CVD (and DVD) subtitles, we'll scale down ours.
*/
- p_sys->pi_palette[i].s.t = *p++;
+ p_sys->pi_palette[i].s.t = (*p++) >> 4;
}
p_sys->i_cmd = *p++;
/* We do not really know this, FIXME */
the end.
However we'll transform this so that that the RLE is expanded and
- interlacing will also be removed. On output each pixel entry will by
- an 8-bit alpha, y, u, and v entry.
+ interlacing will also be removed. On output each pixel entry will by
+ an 4-bit alpha (filling 8 bits), and 8-bit y, u, and v entry.
*****************************************************************************/
static int
uint8_t i_remaining; /* number of 2-bit pixels remaining
in byte of *p */
uint8_t i_pending_zero = 0; /* number of pixels to fill with
- color zero 0..4 */
+ color zero 0..3 */
ogt_color_t i_color; /* current pixel color: 0..3 */
uint8_t *p = p_sys->subtitle_data + p_sys->comp_image_offset;
uint8_t *maxp = p + p_sys->comp_image_length;
for ( i_column=0; i_column<i_width; i_column++ ) {
if ( i_pending_zero ) {
+ /* We are in the middle of a RLE expansion, just decrement and
+ fall through with current color value */
i_pending_zero--;
i_color = 0;
} else {