* modules/codec/svcdsub.c: ported svcd subtitles decoder to the new subpicture architecture.
AC_CHECK_LIB(png, png_set_rows, [
VLC_ADD_LDFLAGS([png],[-lpng -lz])
VLC_ADD_PLUGINS([png])
- VLC_ADD_LDFLAGS([svcdsub],[-lpng -lz])
- VLC_ADD_LDFLAGS([cvdsub],[-lpng -lz -lm])
AC_DEFINE(HAVE_LIBPNG, [], [Define if you have the PNG library: libpng])],
[],[-lz])
LDFLAGS="${LDFLAGS_save}"
modules/codec/cmml/Makefile
modules/codec/dmo/Makefile
modules/codec/ffmpeg/Makefile
- modules/codec/ogt/Makefile
modules/codec/spudec/Makefile
modules/control/Makefile
modules/control/corba/Makefile
SOURCES_toolame = toolame.c
SOURCES_dirac = dirac.c
SOURCES_png = png.c
+SOURCES_svcdsub = svcdsub.c
+SOURCES_cvdsub = cvdsub.c
--- /dev/null
+/*****************************************************************************
+ * cvd.c : CVD Subtitle decoder
+ *****************************************************************************
+ * Copyright (C) 2003, 2004 VideoLAN
+ * $Id$
+ *
+ * Authors: Rocky Bernstein
+ * Gildas Bazin <gbazin@videolan.org>
+ * Julio Sanchez Fernandez (http://subhandler.sourceforge.net)
+ * Laurent Aimar <fenrir@via.ecp.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+#include <vlc/vlc.h>
+#include <vlc/vout.h>
+#include <vlc/decoder.h>
+
+#include "vlc_bits.h"
+
+#define DEBUG_CVDSUB 1
+
+/*****************************************************************************
+ * Module descriptor.
+ *****************************************************************************/
+static int DecoderOpen ( vlc_object_t * );
+static int PacketizerOpen( vlc_object_t * );
+static void DecoderClose ( vlc_object_t * );
+
+vlc_module_begin();
+ set_description( _("CVD subtitle decoder") );
+ set_capability( "decoder", 50 );
+ set_callbacks( DecoderOpen, DecoderClose );
+
+ add_submodule();
+ set_description( _("Chaoji VCD subtitle packetizer") );
+ set_capability( "packetizer", 50 );
+ set_callbacks( PacketizerOpen, DecoderClose );
+vlc_module_end();
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+static subpicture_t *Decode( decoder_t *, block_t ** );
+static block_t *Packetize ( decoder_t *, block_t ** );
+static block_t *Reassemble ( decoder_t *, block_t * );
+static void ParseMetaInfo ( decoder_t *, block_t * );
+static void ParseHeader ( decoder_t *, block_t * );
+static subpicture_t *DecodePacket( decoder_t *, block_t * );
+static void RenderImage( decoder_t *, block_t *, subpicture_region_t * );
+
+#define SUBTITLE_BLOCK_EMPTY 0
+#define SUBTITLE_BLOCK_PARTIAL 1
+#define SUBTITLE_BLOCK_COMPLETE 2
+
+struct decoder_sys_t
+{
+ int b_packetizer;
+
+ int i_state; /* data-gathering state for this subtitle */
+
+ block_t *p_spu; /* Bytes of the packet. */
+
+ int i_spu_size; /* goal for subtitle_data_pos while gathering,
+ size of used subtitle_data later */
+
+ uint16_t i_image_offset; /* offset from subtitle_data to compressed
+ image data */
+ int i_image_length; /* size of the compressed image data */
+ int first_field_offset; /* offset of even raster lines */
+ int second_field_offset; /* offset of odd raster lines */
+ int metadata_offset; /* offset to data describing the image */
+ int metadata_length; /* length of metadata */
+
+ mtime_t i_duration; /* how long to display the image, 0 stands
+ for "until next subtitle" */
+
+ uint16_t i_x_start, i_y_start; /* position of top leftmost pixel of
+ image when displayed */
+ uint16_t i_width, i_height; /* dimensions in pixels of image */
+
+ uint8_t p_palette[4][4]; /* Palette of colors used in subtitle */
+ uint8_t p_palette_highlight[4][4];
+};
+
+/*****************************************************************************
+ * DecoderOpen: open/initialize the cvdsub decoder.
+ *****************************************************************************/
+static int DecoderOpen( vlc_object_t *p_this )
+{
+ decoder_t *p_dec = (decoder_t*)p_this;
+ decoder_sys_t *p_sys;
+
+ if( p_dec->fmt_in.i_codec != VLC_FOURCC( 'c','v','d',' ' ) )
+ {
+ return VLC_EGENERIC;
+ }
+
+ p_dec->p_sys = p_sys = malloc( sizeof( decoder_sys_t ) );
+
+ p_sys->b_packetizer = VLC_FALSE;
+
+ p_sys->i_state = SUBTITLE_BLOCK_EMPTY;
+ p_sys->p_spu = NULL;
+
+ es_format_Init( &p_dec->fmt_out, SPU_ES, VLC_FOURCC( 'c','v','d',' ' ) );
+
+ p_dec->pf_decode_sub = Decode;
+ p_dec->pf_packetize = Packetize;
+
+ return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * PacketizerOpen: open/initialize the cvdsub packetizer.
+ *****************************************************************************/
+static int PacketizerOpen( vlc_object_t *p_this )
+{
+ decoder_t *p_dec = (decoder_t*)p_this;
+
+ if( DecoderOpen( p_this ) != VLC_SUCCESS ) return VLC_EGENERIC;
+
+ p_dec->p_sys->b_packetizer = VLC_TRUE;
+
+ return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * DecoderClose: closes the cvdsub decoder/packetizer.
+ *****************************************************************************/
+void DecoderClose( vlc_object_t *p_this )
+{
+ decoder_t *p_dec = (decoder_t*)p_this;
+ decoder_sys_t *p_sys = p_dec->p_sys;
+
+ if( p_sys->p_spu ) block_ChainRelease( p_sys->p_spu );
+ free( p_sys );
+}
+
+/*****************************************************************************
+ * Decode:
+ *****************************************************************************/
+static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
+{
+ block_t *p_block, *p_spu;
+
+ if( pp_block == NULL || *pp_block == NULL ) return NULL;
+
+ p_block = *pp_block;
+ *pp_block = NULL;
+
+ if( !(p_spu = Reassemble( p_dec, p_block )) ) return NULL;
+
+ /* Parse and decode */
+ return DecodePacket( p_dec, p_spu );
+}
+
+/*****************************************************************************
+ * Packetize:
+ *****************************************************************************/
+static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
+{
+ block_t *p_block, *p_spu;
+
+ if( pp_block == NULL || *pp_block == NULL ) return NULL;
+
+ p_block = *pp_block;
+ *pp_block = NULL;
+
+ if( !(p_spu = Reassemble( p_dec, p_block )) ) return NULL;
+
+ p_spu->i_dts = p_spu->i_pts;
+ p_spu->i_length = 0;
+
+ return p_spu;
+}
+
+
+/*****************************************************************************
+ Reassemble:
+
+ Data for single screen subtitle may come in several non-contiguous
+ packets of a stream. This routine is called when the next packet in
+ the stream comes in. The job of this routine is to parse the header,
+ if this is the beginning, and combine the packets into one complete
+ subtitle unit.
+
+ If everything is complete, we will return a block. Otherwise return
+ NULL.
+
+ *****************************************************************************/
+#define SPU_HEADER_LEN 1
+
+static block_t *Reassemble( decoder_t *p_dec, block_t *p_block )
+{
+ decoder_sys_t *p_sys = p_dec->p_sys;
+ uint8_t *p_buffer;
+
+ if( p_block->i_buffer < SPU_HEADER_LEN )
+ {
+ msg_Dbg( p_dec, "invalid packet header (size %d < %d)" ,
+ p_block->i_buffer, SPU_HEADER_LEN );
+ block_Release( p_block );
+ return NULL;
+ }
+
+ p_buffer = p_block->p_buffer;
+
+ /* From the scant data on the format, there is only only way known
+ * to detect the first packet in a subtitle. The first packet
+ * seems to have a valid PTS while later packets for the same
+ * image don't. */
+ if( p_sys->i_state == SUBTITLE_BLOCK_EMPTY && p_block->i_pts == 0 )
+ {
+ msg_Warn( p_dec, "first packet expected but no PTS present");
+ return NULL;
+ }
+
+ p_block->p_buffer += SPU_HEADER_LEN;
+ p_block->i_buffer -= SPU_HEADER_LEN;
+
+ /* First packet in the subtitle block */
+ if( p_sys->i_state == SUBTITLE_BLOCK_EMPTY ) ParseHeader( p_dec, p_block );
+
+ block_ChainAppend( &p_sys->p_spu, p_block );
+ p_sys->p_spu = block_ChainGather( p_sys->p_spu );
+
+ if( p_sys->p_spu->i_buffer >= p_sys->i_spu_size )
+ {
+ block_t *p_spu = p_sys->p_spu;
+
+ if( p_spu->i_buffer != p_sys->i_spu_size )
+ {
+ msg_Warn( p_dec, "SPU packets size=%d should be %d",
+ p_spu->i_buffer, p_sys->i_spu_size );
+ }
+
+ msg_Dbg( p_dec, "subtitle packet complete, size=%d", p_spu->i_buffer);
+
+ ParseMetaInfo( p_dec, p_spu );
+
+ p_sys->i_state = SUBTITLE_BLOCK_EMPTY;
+ p_sys->p_spu = 0;
+ return p_spu;
+ }
+ else
+ {
+ /* Not last block in subtitle, so wait for another. */
+ p_sys->i_state = SUBTITLE_BLOCK_PARTIAL;
+ }
+
+ return NULL;
+}
+
+/*
+ We do not have information on the subtitle format used on CVD's
+ except the submux sample code and a couple of samples of dubious
+ origin. Thus, this is the result of reading some code whose
+ correctness is not known and some experimentation.
+
+ CVD subtitles are different in several ways from SVCD OGT subtitles.
+ Image comes first and metadata is at the end. So that the metadata
+ can be found easily, the subtitle packet starts with two bytes
+ (everything is big-endian again) that give the total size of the
+ subtitle data and the offset to the metadata - i.e. size of the
+ image data plus the four bytes at the beginning.
+
+ Image data comes interlaced is run-length encoded. Each field is a
+ four-bit nibble. Each nibble contains a two-bit repeat count and a
+ two-bit color number so that up to three pixels can be described in
+ four bits. The function of a 0 repeat count is unknown; it might be
+ used for RLE extension. However 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.
+*/
+
+static void ParseHeader( decoder_t *p_dec, block_t *p_block )
+{
+ decoder_sys_t *p_sys = p_dec->p_sys;
+ uint8_t *p = p_block->p_buffer;
+
+ p_sys->i_spu_size = (p[0] << 8) + p[1] + 4; p += 2;
+
+ /* FIXME: check data sanity */
+ p_sys->metadata_offset = (p[0] << 8) + p[1]; p +=2;
+ p_sys->metadata_length = p_sys->i_spu_size - p_sys->metadata_offset;
+
+ p_sys->i_image_offset = 4;
+ p_sys->i_image_length = p_sys->metadata_offset - p_sys->i_image_offset;
+
+#ifdef DEBUG_CVDSUB
+ msg_Dbg( p_dec, "total size: %d image size: %d",
+ p_sys->i_spu_size, p_sys->i_image_length );
+#endif
+
+}
+
+/*
+ We parse the metadata information here.
+
+ Although metadata information does not have to come in a fixed field
+ order, every metadata field consists of a tag byte followed by
+ parameters. In all cases known, the size including tag byte is
+ exactly four bytes in length.
+*/
+
+#define ExtractXY(x, y) x = ((p[1]&0x0f)<<6) + (p[2]>>2); \
+ y = ((p[2]&0x03)<<8) + p[3];
+
+static void ParseMetaInfo( decoder_t *p_dec, block_t *p_spu )
+{
+ /* Last packet in subtitle block. */
+
+ decoder_sys_t *p_sys = p_dec->p_sys;
+ uint8_t *p = p_spu->p_buffer + p_sys->metadata_offset;
+ uint8_t *p_end = p + p_sys->metadata_length;
+
+ for( ; p < p_end; p += 4 )
+ {
+ switch( p[0] )
+ {
+ case 0x04: /* subtitle duration in 1/90000ths of a second */
+ p_sys->i_duration = (p[1]<<16) + (p[2]<<8) + p[3];
+
+#ifdef DEBUG_CVDSUB
+ msg_Dbg( p_dec, "subtitle display duration %lu secs",
+ (long unsigned int)(p_sys->i_duration / 90000) );
+#endif
+ p_sys->i_duration *= 100 / 9;
+ break;
+
+ case 0x0c: /* unknown */
+#ifdef DEBUG_CVDSUB
+ msg_Dbg( p_dec, "subtitle command unknown 0x%0x 0x%0x 0x%0x 0x%0x",
+ (int)p[0], (int)p[1], (int)p[2], (int)p[3] );
+#endif
+ break;
+
+ case 0x17: /* coordinates of subtitle upper left x, y position */
+ ExtractXY(p_sys->i_x_start, p_sys->i_y_start);
+
+#ifdef DEBUG_CVDSUB
+ msg_Dbg( p_dec, "start position (%d,%d)",
+ p_sys->i_x_start, p_sys->i_y_start );
+#endif
+ break;
+
+ case 0x1f: /* coordinates of subtitle bottom right x, y position */
+ {
+ int lastx;
+ int lasty;
+ ExtractXY(lastx, lasty);
+ p_sys->i_width = lastx - p_sys->i_x_start + 1;
+ p_sys->i_height = lasty - p_sys->i_y_start + 1;
+
+#ifdef DEBUG_CVDSUB
+ msg_Dbg( p_dec, "end position (%d,%d), w x h: %dx%d",
+ lastx, lasty, p_sys->i_width, p_sys->i_height );
+#endif
+ break;
+ }
+
+ case 0x24:
+ case 0x25:
+ case 0x26:
+ case 0x27:
+ {
+ uint8_t v = p[0] - 0x24;
+
+#ifdef DEBUG_CVDSUB
+ /* Primary Palette */
+ msg_Dbg( p_dec, "primary palette %d (y,u,v): (0x%0x,0x%0x,0x%0x)",
+ (int)v, (int)p[1], (int)p[2], (int)p[3] );
+#endif
+
+ p_sys->p_palette[v][0] = p[1];
+ p_sys->p_palette[v][1] = p[2];
+ p_sys->p_palette[v][2] = p[3];
+ break;
+ }
+
+ case 0x2c:
+ case 0x2d:
+ case 0x2e:
+ case 0x2f:
+ {
+ uint8_t v = p[0] - 0x2c;
+
+#ifdef DEBUG_CVDSUB
+ msg_Dbg( p_dec,"highlight palette %d (y,u,v): (0x%0x,0x%0x,0x%0x)",
+ (int)v, (int)p[1], (int)p[2], (int)p[3] );
+#endif
+
+ /* Highlight Palette */
+ p_sys->p_palette_highlight[v][0] = p[1];
+ p_sys->p_palette_highlight[v][1] = p[2];
+ p_sys->p_palette_highlight[v][2] = p[3];
+ break;
+ }
+
+ case 0x37:
+ /* transparency for primary palette */
+ p_sys->p_palette[0][3] = (p[3] & 0x0f) << 4;
+ p_sys->p_palette[1][3] = (p[3] >> 4) << 4;
+ p_sys->p_palette[2][3] = (p[2] & 0x0f) << 4;
+ p_sys->p_palette[3][3] = (p[2] >> 4) << 4;
+
+#ifdef DEBUG_CVDSUB
+ msg_Dbg( p_dec, "transparency for primary palette 0..3: "
+ "0x%0x 0x%0x 0x%0x 0x%0x",
+ (int)p_sys->p_palette[0][3], (int)p_sys->p_palette[1][3],
+ (int)p_sys->p_palette[2][3], (int)p_sys->p_palette[3][3]);
+#endif
+ break;
+
+ case 0x3f:
+ /* transparency for highlight palette */
+ p_sys->p_palette_highlight[0][3] = (p[2] & 0x0f) << 4;
+ p_sys->p_palette_highlight[1][3] = (p[2] >> 4) << 4;
+ p_sys->p_palette_highlight[2][3] = (p[1] & 0x0f) << 4;
+ p_sys->p_palette_highlight[3][3] = (p[1] >> 4) << 4;
+
+#ifdef DEBUG_CVDSUB
+ msg_Dbg( p_dec, "transparency for highlight palette 0..3: "
+ "0x%0x 0x%0x 0x%0x 0x%0x",
+ (int)p_sys->p_palette_highlight[0][3],
+ (int)p_sys->p_palette_highlight[1][3],
+ (int)p_sys->p_palette_highlight[2][3],
+ (int)p_sys->p_palette_highlight[3][3] );
+#endif
+ break;
+
+ case 0x47:
+ /* offset to start of even rows of interlaced image, we correct
+ * to make it relative to i_image_offset (usually 4) */
+ p_sys->first_field_offset =
+ (p[2] << 8) + p[3] - p_sys->i_image_offset;
+#ifdef DEBUG_CVDSUB
+ msg_Dbg( p_dec, "1st_field_offset %d", p_sys->first_field_offset );
+#endif
+ break;
+
+ case 0x4f:
+ /* offset to start of odd rows of interlaced image, we correct
+ * to make it relative to i_image_offset (usually 4) */
+ p_sys->second_field_offset =
+ (p[2] << 8) + p[3] - p_sys->i_image_offset;
+#ifdef DEBUG_CVDSUB
+ msg_Dbg( p_dec, "2nd_field_offset %d", p_sys->second_field_offset);
+#endif
+ break;
+
+ default:
+#ifdef DEBUG_CVDSUB
+ msg_Warn( p_dec, "unknown sequence in control header "
+ "0x%0x 0x%0x 0x%0x 0x%0x", p[0], p[1], p[2], p[3]);
+#endif
+ }
+ }
+}
+
+/*****************************************************************************
+ * DecodePacket: parse and decode an SPU packet
+ *****************************************************************************
+ * This function parses and decodes an SPU packet and, if valid, returns a
+ * subpicture.
+ *****************************************************************************/
+static subpicture_t *DecodePacket( decoder_t *p_dec, block_t *p_data )
+{
+ decoder_sys_t *p_sys = p_dec->p_sys;
+ subpicture_t *p_spu;
+ subpicture_region_t *p_region;
+ video_format_t fmt;
+ int i;
+
+ /* Allocate the subpicture internal data. */
+ p_spu = p_dec->pf_spu_buffer_new( p_dec );
+ if( !p_spu ) return NULL;
+
+ p_spu->i_x = p_sys->i_x_start;
+ p_spu->i_x = p_spu->i_x * 3 / 4; /* FIXME: use aspect ratio for x? */
+ p_spu->i_y = p_sys->i_y_start;
+ p_spu->i_start = p_data->i_pts;
+ p_spu->i_stop = p_data->i_pts + p_sys->i_duration;
+ p_spu->b_ephemer = VLC_TRUE;
+
+ /* Create new SPU region */
+ memset( &fmt, 0, sizeof(video_format_t) );
+ fmt.i_chroma = VLC_FOURCC('Y','U','V','P');
+ fmt.i_aspect = VOUT_ASPECT_FACTOR;
+ fmt.i_width = fmt.i_visible_width = p_sys->i_width;
+ fmt.i_height = fmt.i_visible_height = p_sys->i_height;
+ fmt.i_x_offset = fmt.i_y_offset = 0;
+ p_region = p_spu->pf_create_region( VLC_OBJECT(p_dec), &fmt );
+ if( !p_region )
+ {
+ msg_Err( p_dec, "cannot allocate SPU region" );
+ //goto error;
+ }
+
+ p_spu->p_region = p_region;
+ p_region->i_x = p_region->i_y = 0;
+
+ /* Build palette */
+ fmt.p_palette->i_entries = 4;
+ for( i = 0; i < fmt.p_palette->i_entries; i++ )
+ {
+ fmt.p_palette->palette[i][0] = p_sys->p_palette[i][0];
+ fmt.p_palette->palette[i][1] = p_sys->p_palette[i][1];
+ fmt.p_palette->palette[i][2] = p_sys->p_palette[i][2];
+ fmt.p_palette->palette[i][3] = p_sys->p_palette[i][3];
+ }
+
+ RenderImage( p_dec, p_data, p_region );
+
+ return p_spu;
+}
+
+/*****************************************************************************
+ * ParseImage: parse and render the image part of the subtitle
+ *****************************************************************************
+ This part parses the subtitle graphical data and renders it.
+
+ 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
+ a 4-bit alpha (filling 8 bits), and 8-bit y, u, and v entry.
+
+ *****************************************************************************/
+static void RenderImage( decoder_t *p_dec, block_t *p_data,
+ subpicture_region_t *p_region )
+{
+ decoder_sys_t *p_sys = p_dec->p_sys;
+ uint8_t *p_dest = p_region->picture.Y_PIXELS;
+ int i_field; /* The subtitles are interlaced */
+ int i_row, i_column; /* scanline row/column number */
+ uint8_t i_color, i_count;
+ bs_t bs;
+
+ bs_init( &bs, p_data->p_buffer + p_sys->i_image_offset,
+ p_data->i_buffer - p_sys->i_image_offset );
+
+ for( i_field = 0; i_field < 2; i_field++ )
+ {
+ for( i_row = i_field; i_row < p_sys->i_height; i_row += 2 )
+ {
+ for( i_column = 0; i_column < p_sys->i_width; i_column++ )
+ {
+ uint8_t i_val = bs_read( &bs, 4 );
+
+ if( i_val == 0 )
+ {
+ /* Fill the rest of the line with next color */
+ i_color = bs_read( &bs, 4 );
+
+ memset( &p_dest[i_row * p_region->picture.Y_PITCH +
+ i_column], i_color,
+ p_sys->i_width - i_column );
+ i_column = p_sys->i_width;
+ continue;
+ }
+ else
+ {
+ /* Normal case: get color and repeat count */
+ i_count = (i_val >> 2);
+ i_color = i_val & 0x3;
+
+ i_count = __MIN( i_count, p_sys->i_width - i_column );
+
+ memset( &p_dest[i_row * p_region->picture.Y_PITCH +
+ i_column], i_color, i_count );
+ i_column += i_count - 1;
+ continue;
+ }
+ }
+
+ bs_align( &bs );
+ }
+ }
+}
+++ /dev/null
-SOURCES_svcdsub = \
- common.c \
- common.h \
- subtitle.h \
- ogt.c \
- ogt.h \
- ogt_parse.c \
- pixmap.c \
- pixmap.h \
- render.c \
- render.h \
- write_png.c \
- write_png.h \
- $(NULL)
-
-SOURCES_cvdsub = \
- common.c \
- common.h \
- cvd.c \
- cvd.h \
- subtitle.h \
- cvd_parse.c \
- pixmap.c \
- pixmap.h \
- render.c \
- render.h \
- write_png.c \
- write_png.h \
- $(NULL)
+++ /dev/null
-/*****************************************************************************
- * Common SVCD and CVD subtitle routines.
- *****************************************************************************
- * Copyright (C) 2003, 2004 VideoLAN
- * $Id$
- *
- * Author: Rocky Bernstein <rocky@panix.com>
- * based on code from:
- * Julio Sanchez Fernandez (http://subhandler.sourceforge.net)
- * Samuel Hocevar <sam@zoy.org>
- * Laurent Aimar <fenrir@via.ecp.fr>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
- *****************************************************************************/
-
-/*****************************************************************************
- * Preamble
- *****************************************************************************/
-#include <vlc/vlc.h>
-#include <vlc/vout.h>
-#include <vlc/decoder.h>
-
-#include "subtitle.h"
-#include "pixmap.h"
-#include "common.h"
-#ifdef HAVE_LIBPNG
-#include "write_png.h"
-#endif
-
-/*****************************************************************************
- Free Resources associated with subtitle packet.
- *****************************************************************************/
-void VCDSubClose( vlc_object_t *p_this )
-{
- decoder_t *p_dec = (decoder_t*)p_this;
- decoder_sys_t *p_sys = p_dec->p_sys;
-
- dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
-
- if( !p_sys->b_packetizer && p_sys->p_vout )
- {
- /* FIXME check if it's ok to not lock vout */
- spu_Control( p_sys->p_vout->p_spu, SPU_CHANNEL_CLEAR,
- p_sys->i_subpic_channel );
- }
-
- if( p_sys->p_block )
- {
- block_ChainRelease( p_sys->p_block );
- }
-
- free(p_sys->subtitle_data);
- free( p_sys );
-}
-
-/*****************************************************************************
-
-Initialize so the next packet will start off a new one.
-
- *****************************************************************************/
-void
-VCDSubInitSubtitleBlock( decoder_sys_t * p_sys )
-{
- p_sys->i_spu_size = 0;
- p_sys->state = SUBTITLE_BLOCK_EMPTY;
- p_sys->i_spu = 0;
- p_sys->p_block = NULL;
- p_sys->subtitle_data_pos = 0;
-
-}
-
-void
-VCDSubInitSubtitleData(decoder_sys_t *p_sys)
-{
- if ( p_sys->subtitle_data ) {
- if ( p_sys->subtitle_data_size < p_sys->i_spu_size ) {
- p_sys->subtitle_data = realloc(p_sys->subtitle_data,
- p_sys->i_spu_size);
- p_sys->subtitle_data_size = p_sys->i_spu_size;
- }
- } else {
- p_sys->subtitle_data = malloc(p_sys->i_spu_size);
- p_sys->subtitle_data_size = p_sys->i_spu_size;
- /* FIXME: wrong place to get p_sys */
- p_sys->i_image = 0;
- }
- p_sys->subtitle_data_pos = 0;
-}
-
-void
-VCDSubAppendData ( decoder_t *p_dec, uint8_t *buffer, uint32_t buf_len )
-{
- decoder_sys_t *p_sys = p_dec->p_sys;
- int chunk_length = buf_len;
-
- if ( chunk_length > p_sys->i_spu_size - p_sys->subtitle_data_pos ) {
- msg_Warn( p_dec, "too much data (%d) expecting at most %u",
- chunk_length, p_sys->i_spu_size - p_sys->subtitle_data_pos );
-
- chunk_length = p_sys->i_spu_size - p_sys->subtitle_data_pos;
- }
-
- if ( chunk_length > 0 ) {
-#if 0
- int i;
- int8_t *b=buffer;
- for (i=0; i<chunk_length; i++)
- printf ("%02x", b[i]);
- printf("\n");
-#endif
-
- memcpy(p_sys->subtitle_data + p_sys->subtitle_data_pos,
- buffer, chunk_length);
- p_sys->subtitle_data_pos += chunk_length;
- dbg_print(DECODE_DBG_PACKET, "%d bytes appended, pointer now %d",
- chunk_length, p_sys->subtitle_data_pos);
- }
-}
-
-
-/*****************************************************************************
- * FindVout: Find a vout or wait for one to be created.
- *****************************************************************************/
-vout_thread_t *VCDSubFindVout( decoder_t *p_dec )
-{
- vout_thread_t *p_vout = NULL;
-
- /* Find an available video output */
- do
- {
- if( p_dec->b_die || p_dec->b_error )
- {
- break;
- }
-
- p_vout = vlc_object_find( p_dec, VLC_OBJECT_VOUT, FIND_ANYWHERE );
- if( p_vout )
- {
- break;
- }
-
- msleep( VOUT_OUTMEM_SLEEP );
- }
- while( 1 );
-
- return p_vout;
-}
-
-
-
-/**
- Remove color palette by expanding pixel entries to contain the
- palette values. We work from the free space at the end to the
- beginning so we can expand inline.
-*/
-static void
-InlinePalette ( /*inout*/ uint8_t *p_dest, decoder_sys_t *p_sys )
-{
- const unsigned int i_width = p_sys->i_width;
- const unsigned int i_height = p_sys->i_height;
- int n = (i_height * i_width) - 1;
- uint8_t *p_from = p_dest;
- ogt_yuvt_t *p_to = (ogt_yuvt_t *) p_dest;
-
- for ( ; n >= 0 ; n-- ) {
- p_to[n] = p_sys->p_palette[p_from[n]];
- /*p_to[n] = p_sys->p_palette[p_from[3]];*/
- }
-}
-
-/**
- Check to see if user has overridden subtitle aspect ratio.
- 0 is returned for no override which means just counteract any
- scaling effects.
-*/
-unsigned int
-VCDSubGetAROverride(vlc_object_t * p_input, vout_thread_t *p_vout)
-{
- char *psz_string = config_GetPsz( p_input, MODULE_STRING "-aspect-ratio" );
-
- /* Check whether the user tried to override aspect ratio */
- if( !psz_string ) return 0;
-
- {
- unsigned int i_new_aspect = 0;
- char *psz_parser = strchr( psz_string, ':' );
-
- if( psz_parser )
- {
- *psz_parser++ = '\0';
- i_new_aspect = atoi( psz_string ) * VOUT_ASPECT_FACTOR
- / atoi( psz_parser );
- }
- else
- {
- i_new_aspect = p_vout->output.i_width * VOUT_ASPECT_FACTOR
- * atof( psz_string )
- / p_vout->output.i_height;
- }
-
- return i_new_aspect;
- }
-}
-
-
-/**
- Scales down (reduces size) of p_dest in the x direction as
- determined through aspect ratio x_scale by y_scale. Scaling
- is done in place. p_spu->i_width, is updated to new width
-
- The aspect ratio is assumed to be between 1/2 and 1.
-
- Note: the scaling truncates the new width rather than rounds it.
- Perhaps something one might want to address.
-*/
-void
-VCDSubScaleX( decoder_t *p_dec, subpicture_t *p_spu,
- unsigned int i_scale_x, unsigned int i_scale_y )
-{
- int i_row, i_col;
-
- decoder_sys_t *p_sys = p_dec->p_sys;
- uint8_t *p_src1 = p_spu->p_sys->p_data;
- uint8_t *p_src2 = p_src1 + PIXEL_SIZE;
- uint8_t *p_dst = p_src1;
- unsigned int i_new_width = (p_spu->i_width * i_scale_x) / i_scale_y ;
- unsigned int i_used=0; /* Number of bytes used up in p_src1. */
-
- dbg_print( (DECODE_DBG_CALL|DECODE_DBG_TRANSFORM) ,
- "aspect ratio %i:%i, Old width: %d, new width: %d",
- i_scale_x, i_scale_y, p_spu->i_width, i_new_width);
-
- if (! (i_scale_x < i_scale_y && i_scale_y < i_scale_x+i_scale_x) )
- {
- msg_Warn( p_dec, "Need x < y < 2x. x: %i, y: %i", i_scale_x, i_scale_y );
- return;
- }
-
- for ( i_row=0; i_row <= p_spu->i_height - 1; i_row++ ) {
-
- if (i_used != 0) {
- /* Discard the remaining piece of the column of the previous line*/
- i_used=0;
- p_src1 = p_src2;
- p_src2 += PIXEL_SIZE;
- }
-
- for ( i_col=0; i_col <= p_spu->i_width - 2; i_col++ ) {
- unsigned int i;
- unsigned int w1= i_scale_x - i_used;
- unsigned int w2;
-
- if ( i_scale_y - w1 <= i_scale_x ) {
- /* Average spans 2 pixels. */
- w2 = i_scale_y - w1;
-
- for (i = 0; i < PIXEL_SIZE; i++ ) {
- *p_dst = ( (*p_src1 * w1) + (*p_src2 * w2) ) / i_scale_y;
- p_src1++; p_src2++; p_dst++;
- }
- } else {
- /* Average spans 3 pixels. */
- unsigned int w0 = w1;
- unsigned int w1 = i_scale_x;
- uint8_t *p_src0 = p_src1;
- w2 = i_scale_y - w0 - w1;
- p_src1 = p_src2;
- p_src2 += PIXEL_SIZE;
-
- for (i = 0; i < PIXEL_SIZE; i++ ) {
- *p_dst = ( (*p_src0 * w0) + (*p_src1 * w1) + (*p_src2 * w2) )
- / i_scale_y;
- p_src0++; p_src1++; p_src2++; p_dst++;
- }
- i_col++;
- }
-
- i_used = w2;
-
- if (i_scale_x == i_used) {
- /* End of last pixel was end of p_src2. */
- p_src1 = p_src2;
- p_src2 += PIXEL_SIZE;
- i_col++;
- i_used = 0;
- }
- }
- }
- p_spu->i_width = i_new_width;
-
- if ( p_sys && p_sys->i_debug & DECODE_DBG_TRANSFORM )
- {
- ogt_yuvt_t *p_source = (ogt_yuvt_t *) p_spu->p_sys->p_data;
- for ( i_row=0; i_row < p_spu->i_height; i_row++ ) {
- for ( i_col=0; i_col < p_spu->i_width; i_col++ ) {
- printf("%1x", p_source->s.t);
- p_source++;
- }
- printf("\n");
- }
- }
-
-}
-
-/**
- The video may be scaled. However subtitle bitmaps assume an 1:1
- aspect ratio. So unless the user has specified otherwise, we
- need to scale to compensate for or undo the effects of video
- output scaling.
-
- Perhaps this should go in the Render routine? The advantage would
- be that it will deal with a dynamically changing aspect ratio.
- The downside is having to scale many times for each render call.
-
- We also expand palette entries here, unless we are dealing with a
- palettized chroma (e.g. RGB2).
-*/
-
-void
-VCDSubHandleScaling( subpicture_t *p_spu, decoder_t *p_dec )
-{
- vlc_object_t * p_input = p_spu->p_sys->p_input;
- vout_thread_t *p_vout = vlc_object_find( p_input, VLC_OBJECT_VOUT,
- FIND_CHILD );
- int i_aspect_x, i_aspect_y;
- uint8_t *p_dest = (uint8_t *)p_spu->p_sys->p_data;
-
- if (p_vout) {
- /* Check for user-configuration override. */
- unsigned int i_new_aspect;
-
- if ( p_vout->output.i_chroma == VLC_FOURCC('R','G','B','2') ) {
- /* This is an unscaled palettized format. We don't allow
- user scaling here. And to make the render process faster,
- we don't expand the palette entries into a color value.
- */
- return;
- }
-
- InlinePalette( p_dest, p_dec->p_sys );
- i_new_aspect = VCDSubGetAROverride( p_input, p_vout );
-
- if (i_new_aspect == VOUT_ASPECT_FACTOR) {
- /* For scaling 1:1, nothing needs to be done. Note this means
- subtitles will get scaled the same way the video does.
- */
- ;
- } else {
- if (0 == i_new_aspect) {
- /* Counteract the effects of background video scaling when
- there is scaling. That's why x and y are reversed from
- the else branch in the call below.
- */
- switch( p_vout->output.i_chroma )
- {
- /* chromas in which scaling is done outside of our
- blending routine, so we need to compensate for those
- effects before blending gets called: */
- case VLC_FOURCC('I','4','2','0'):
- case VLC_FOURCC('I','Y','U','V'):
- case VLC_FOURCC('Y','V','1','2'):
- case VLC_FOURCC('Y','U','Y','2'):
- break;
-
- /* chromas in which scaling is done in our blending
- routine and thus we don't do it here: */
- case VLC_FOURCC('R','V','1','6'):
- case VLC_FOURCC('R','V','2','4'):
- case VLC_FOURCC('R','V','3','2'):
- case VLC_FOURCC('R','G','B','2'):
- return;
- break;
-
- default:
- msg_Err( p_vout, "unknown chroma %x",
- p_vout->output.i_chroma );
- return;
- break;
- }
- /* We get here only for scaled chromas. */
- vlc_reduce( &i_aspect_x, &i_aspect_y, p_vout->render.i_aspect,
- VOUT_ASPECT_FACTOR, 0 );
- } else {
- /* User knows best? */
- vlc_reduce( &i_aspect_x, &i_aspect_y, p_vout->render.i_aspect,
- VOUT_ASPECT_FACTOR, 0 );
- }
- VCDSubScaleX( p_dec, p_spu, i_aspect_x, i_aspect_y );
- }
- }
-}
-
-
-/**
- * DestroySPU: subpicture destructor
- */
-void VCDSubDestroySPU( subpicture_t *p_spu )
-{
- if( p_spu->p_sys->p_input )
- {
- /* Detach from our input thread */
- vlc_object_release( p_spu->p_sys->p_input );
- }
-
- vlc_mutex_destroy( &p_spu->p_sys->lock );
- free( p_spu->p_sys );
-}
-
-/*****************************************************************************
- This callback is called from the input thread when we need cropping
- *****************************************************************************/
-int VCDSubCropCallback( vlc_object_t *p_object, char const *psz_var,
- vlc_value_t oldval, vlc_value_t newval, void *p_data )
-{
- VCDSubUpdateSPU( (subpicture_t *)p_data, p_object );
-
- return VLC_SUCCESS;
-}
-
-
-/*****************************************************************************
- update subpicture settings
- *****************************************************************************
- This function is called from CropCallback and at initialization time, to
- retrieve crop information from the input.
- *****************************************************************************/
-void VCDSubUpdateSPU( subpicture_t *p_spu, vlc_object_t *p_object )
-{
- vlc_value_t val;
-
- p_spu->p_sys->b_crop = val.b_bool;
- if( !p_spu->p_sys->b_crop )
- {
- return;
- }
-
- if ( VLC_SUCCESS == var_Get( p_object, "x-start", &val ) )
- p_spu->p_sys->i_x_start = val.i_int;
- if ( VLC_SUCCESS == var_Get( p_object, "y-start", &val ) )
- p_spu->p_sys->i_y_start = val.i_int;
- if ( VLC_SUCCESS == var_Get( p_object, "x-end", &val ) )
- p_spu->p_sys->i_x_end = val.i_int;
- if ( VLC_SUCCESS == var_Get( p_object, "y-end", &val ) )
- p_spu->p_sys->i_y_end = val.i_int;
-
-}
-
-/*
- Dump an a subtitle image to standard output - for debugging.
- */
-void VCDSubDumpImage( uint8_t *p_image, uint32_t i_height, uint32_t i_width )
-{
- uint8_t *p = p_image;
- unsigned int i_row; /* scanline row number */
- unsigned int i_column; /* scanline column number */
-
- printf("-------------------------------------\n++");
- for ( i_row=0; i_row < i_height; i_row ++ ) {
- for ( i_column=0; i_column<i_width; i_column++ ) {
- printf("%1d", *p++ & 0x03);
- }
- printf("\n++");
- }
- printf("\n-------------------------------------\n");
-}
-
-#ifdef HAVE_LIBPNG
-
-#define PALETTE_SIZE 4
-/* Note the below assumes the above is a power of 2 */
-#define PALETTE_SIZE_MASK (PALETTE_SIZE-1)
-
-/*
- Dump an a subtitle image to a Portable Network Graphics (PNG) file.
- All we do here is convert YUV palette entries to RGB, expand
- the image into a linear RGB pixel array, and call the routine
- that does the PNG writing.
- */
-
-void
-VCDSubDumpPNG( uint8_t *p_image, decoder_t *p_dec,
- uint32_t i_height, uint32_t i_width, const char *filename,
- png_text *text_ptr, int i_text_count )
-{
- decoder_sys_t *p_sys = p_dec->p_sys;
- uint8_t *p = p_image;
- uint8_t *image_data = malloc(RGB_SIZE * i_height * i_width );
- uint8_t *q = image_data;
- unsigned int i_row; /* scanline row number */
- unsigned int i_column; /* scanline column number */
- uint8_t rgb_palette[PALETTE_SIZE * RGB_SIZE];
- int i;
-
- dbg_print( (DECODE_DBG_CALL), "%s", filename);
-
- if (NULL == image_data) return;
-
- /* Convert palette YUV into RGB. */
- for (i=0; i<PALETTE_SIZE; i++) {
- ogt_yuvt_t *p_yuv = &(p_sys->p_palette[i]);
- uint8_t *p_rgb_out = &(rgb_palette[i*RGB_SIZE]);
- yuv2rgb( p_yuv, p_rgb_out );
- }
-
- /* Convert palette entries into linear RGB array. */
- for ( i_row=0; i_row < i_height; i_row ++ ) {
- for ( i_column=0; i_column<i_width; i_column++ ) {
- uint8_t *p_rgb = &rgb_palette[ ((*p)&PALETTE_SIZE_MASK)*RGB_SIZE ];
- *q++ = p_rgb[0];
- *q++ = p_rgb[1];
- *q++ = p_rgb[2];
- p++;
- }
- }
-
- write_png( filename, i_height, i_width, image_data, text_ptr, i_text_count );
- free(image_data);
-}
-#endif /*HAVE_LIBPNG*/
-
-\f
-/*
- * Local variables:
- * c-file-style: "gnu"
- * tab-width: 8
- * indent-tabs-mode: nil
- * End:
- */
+++ /dev/null
-/*****************************************************************************
- * Header for Common SVCD and VCD subtitle routines.
- *****************************************************************************
- * Copyright (C) 2003, 2004 VideoLAN
- * $Id: common.h,v 1.6 2004/01/16 13:32:37 rocky Exp $
- *
- * Author: Rocky Bernstein
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
- *****************************************************************************/
-
-void VCDSubClose ( vlc_object_t * );
-
-void VCDSubInitSubtitleBlock( decoder_sys_t * p_sys );
-
-void VCDSubInitSubtitleData(decoder_sys_t *p_sys);
-
-void VCDSubAppendData( decoder_t *p_dec, uint8_t *buffer,
- uint32_t buf_len );
-vout_thread_t *VCDSubFindVout( decoder_t *p_dec );
-
-void VCDSubHandleScaling( subpicture_t *p_spu, decoder_t *p_dec ) ;
-
-
-void VCDSubScaleX( decoder_t *p_dec, subpicture_t *p_spu,
- unsigned int i_scale_x, unsigned int i_scale_y );
-
-void VCDSubDestroySPU( subpicture_t *p_spu );
-
-int VCDSubCropCallback( vlc_object_t *p_object, char const *psz_var,
- vlc_value_t oldval, vlc_value_t newval,
- void *p_data );
-
-void VCDSubUpdateSPU( subpicture_t *p_spu, vlc_object_t *p_object );
-
-void VCDSubDumpImage( uint8_t *p_image, uint32_t i_height,
- uint32_t i_width );
-
-unsigned int VCDSubGetAROverride(vlc_object_t * p_input,
- vout_thread_t *p_vout);
-
-#ifdef HAVE_LIBPNG
-#include <png.h>
-void VCDSubDumpPNG( uint8_t *p_image, decoder_t *p_dec,
- uint32_t i_height, uint32_t i_width,
- const char *filename, /*in*/ png_text *text_ptr,
- int i_text_count );
-#endif /*HAVE_LIBPNG*/
+++ /dev/null
-/*****************************************************************************
- * cvd.c : CVD Subtitle decoder thread
- *****************************************************************************
- * Copyright (C) 2003, 2004 VideoLAN
- * $Id$
- *
- * Authors: Rocky Bernstein
- * based on code from:
- * Julio Sanchez Fernandez (http://subhandler.sourceforge.net)
- * Samuel Hocevar <sam@zoy.org>
- * Laurent Aimar <fenrir@via.ecp.fr>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
- *****************************************************************************/
-
-/*****************************************************************************
- * Preamble
- *****************************************************************************/
-#include <vlc/vlc.h>
-#include <vlc/vout.h>
-#include <vlc/decoder.h>
-
-#include "subtitle.h"
-#include "cvd.h"
-#include "common.h"
-
-/*****************************************************************************
- * Module descriptor.
- *****************************************************************************/
-static int VCDSubOpen ( vlc_object_t * );
-static int PacketizerOpen( vlc_object_t * );
-
-vlc_module_begin();
- set_description( _("CVD subtitle decoder") );
- set_capability( "decoder", 50 );
- set_callbacks( VCDSubOpen, VCDSubClose );
- set_category( CAT_INPUT );
- set_subcategory( SUBCAT_INPUT_SCODEC );
-
- add_integer ( MODULE_STRING "-debug", 0, NULL,
- DEBUG_TEXT, DEBUG_LONGTEXT, VLC_TRUE );
-
- add_integer ( MODULE_STRING "-horizontal-correct", 0, NULL,
- HORIZONTAL_CORRECT, HORIZONTAL_CORRECT_LONGTEXT, VLC_FALSE );
-
- add_integer ( MODULE_STRING "-vertical-correct", 0, NULL,
- VERTICAL_CORRECT, VERTICAL_CORRECT_LONGTEXT, VLC_FALSE );
-
- add_string( MODULE_STRING "-aspect-ratio", "", NULL,
- SUB_ASPECT_RATIO_TEXT, SUB_ASPECT_RATIO_LONGTEXT,
- VLC_TRUE );
-
- add_integer( MODULE_STRING "-duration-scaling", 3, NULL,
- DURATION_SCALE_TEXT, DURATION_SCALE_LONGTEXT,
- VLC_TRUE );
-
- add_submodule();
- set_description( _("Chaoji VCD subtitle packetizer") );
- set_capability( "packetizer", 50 );
- set_callbacks( PacketizerOpen, VCDSubClose );
-vlc_module_end();
-
-/*****************************************************************************
- * Local prototypes
- *****************************************************************************/
-
-static block_t *Reassemble( decoder_t *, block_t ** );
-static subpicture_t *Decode( decoder_t *, block_t ** );
-static block_t *Packetize( decoder_t *, block_t ** );
-
-/*****************************************************************************
- * VCDSubOpen
- *****************************************************************************
- * Tries to launch a decoder and return score so that the interface is able
- * to chose.
- *****************************************************************************/
-static int
-VCDSubOpen( vlc_object_t *p_this )
-{
- decoder_t *p_dec = (decoder_t*)p_this;
- decoder_sys_t *p_sys;
-
- if( p_dec->fmt_in.i_codec != VLC_FOURCC( 'c','v','d',' ' ) )
- {
- return VLC_EGENERIC;
- }
-
-
- p_dec->p_sys = p_sys = malloc( sizeof( decoder_sys_t ) );
-
- p_sys->i_debug = config_GetInt( p_this, MODULE_STRING "-debug" );
- p_sys->b_packetizer = VLC_FALSE;
- p_sys->p_vout = NULL;
- p_sys->i_image = -1;
- p_sys->subtitle_data = NULL;
-
- VCDSubInitSubtitleBlock( p_sys );
-
- es_format_Init( &p_dec->fmt_out, SPU_ES, VLC_FOURCC( 'c','v','d',' ' ) );
-
-
- p_dec->pf_decode_sub = Decode;
- p_dec->pf_packetize = Packetize;
-
- dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
-
- return VLC_SUCCESS;
-}
-
-/*****************************************************************************
- * PacketizerOpen
- *****************************************************************************
- * Tries to launch a decoder and return score so that the interface is able
- * to chose.
- *****************************************************************************/
-static int PacketizerOpen( vlc_object_t *p_this )
-{
- decoder_t *p_dec = (decoder_t*)p_this;
-
- if( VCDSubOpen( p_this ) )
- {
- return VLC_EGENERIC;
- }
- p_dec->p_sys->b_packetizer = VLC_TRUE;
-
- return VLC_SUCCESS;
-}
-
-/*****************************************************************************
- * Decode:
- *****************************************************************************/
-static subpicture_t *
-Decode ( decoder_t *p_dec, block_t **pp_block )
-{
- decoder_sys_t *p_sys = p_dec->p_sys;
- block_t *p_spu = Reassemble( p_dec, pp_block );
- vout_thread_t *p_last_vout = p_dec->p_sys->p_vout;
-
- dbg_print( (DECODE_DBG_CALL) , "");
-
- if( p_spu )
- {
- p_sys->i_spu = block_ChainExtract( p_spu, p_sys->buffer, 65536 );
- p_sys->i_pts = p_spu->i_pts;
- block_ChainRelease( p_spu );
-
- if( ( p_sys->p_vout = VCDSubFindVout( p_dec ) ) )
- {
- if( p_last_vout != p_sys->p_vout )
- {
- spu_Control( p_sys->p_vout->p_spu, SPU_CHANNEL_REGISTER,
- &p_sys->i_subpic_channel );
- }
-
- /* Parse and decode */
- E_(ParsePacket)( p_dec );
-
- vlc_object_release( p_sys->p_vout );
- }
-
- VCDSubInitSubtitleBlock ( p_sys );
- }
-
- return NULL;
-}
-
-/*****************************************************************************
- * Packetize:
- *****************************************************************************/
-static block_t *
-Packetize( decoder_t *p_dec, block_t **pp_block )
-{
- decoder_sys_t *p_sys = p_dec->p_sys;
- block_t *p_spu = Reassemble( p_dec, pp_block );
-
- if( p_spu )
- {
- p_spu->i_dts = p_spu->i_pts;
- p_spu->i_length = 0;
-
- VCDSubInitSubtitleBlock( p_sys );
-
- return block_ChainGather( p_spu );
- }
- return NULL;
-}
-
-/* following functions are local */
-
-#define SPU_HEADER_LEN 1
-
-/*****************************************************************************
- Reassemble:
-
- Data for single screen subtitle may come in several non-contiguous
- packets of a stream. This routine is called when the next packet in
- the stream comes in. The job of this routine is to parse the header,
- if this is the beginning, and combine the packets into one complete
- subtitle unit.
-
- If everything is complete, we will return a block. Otherwise return
- NULL.
-
- *****************************************************************************/
-static block_t *
-Reassemble( decoder_t *p_dec, block_t **pp_block )
-{
- decoder_sys_t *p_sys = p_dec->p_sys;
- block_t *p_block;
- uint8_t *p_buffer;
-
- if( pp_block == NULL || *pp_block == NULL )
- {
- return NULL;
- }
- p_block = *pp_block;
- *pp_block = NULL;
-
- if( p_block->i_buffer < SPU_HEADER_LEN )
- {
- msg_Dbg( p_dec, "invalid packet header (size %d < %d)" ,
- p_block->i_buffer, SPU_HEADER_LEN );
- block_Release( p_block );
- return NULL;
- }
-
- p_buffer = p_block->p_buffer;
-
- dbg_print( (DECODE_DBG_CALL|DECODE_DBG_PACKET),
- "header: 0x%02x 0x%02x 0x%02x 0x%02x, 0x%02x, 0x%02x, size: %i",
- p_buffer[1], p_buffer[2], p_buffer[3], p_buffer[4],
- p_buffer[5], p_buffer[6],
- p_block->i_buffer);
-
-
- /* Attach to our input thread and see if subtitle is selected. */
- {
- vlc_object_t * p_input;
- vlc_value_t val;
-
- p_input = vlc_object_find( p_dec, VLC_OBJECT_INPUT, FIND_PARENT );
-
- if( !p_input ) return NULL;
-
- if( var_Get( p_input, "spu-channel", &val ) )
- {
- vlc_object_release( p_input );
- return NULL;
- }
-
- vlc_object_release( p_input );
-
- /* Number could be 0bd, 1bd, 2bd, 3bd for 0..3. If so
- reduce it to 0..3.
- */
- if ( (val.i_int & 0xff) == 0xbd ) val.i_int >>= 8;
-
- if( val.i_int == -1 || val.i_int != p_buffer[0] )
- return NULL;
- }
-
-
- /* From the scant data on the format, there is only only way known
- to detect the first packet in a subtitle. The first packet
- seems to have a valid PTS while later packets for the same
- image don't. */
-
- if ( p_sys->state == SUBTITLE_BLOCK_EMPTY && p_block->i_pts == 0 ) {
- msg_Warn( p_dec,
- "first packet expected but no PTS present -- skipped\n");
- return NULL;
- }
-
- if ( p_sys->subtitle_data_pos == 0 ) {
- /* First packet in the subtitle block */
- E_(ParseHeader)( p_dec, p_buffer, p_block );
- VCDSubInitSubtitleData(p_sys);
- }
-
- /* FIXME - remove append_data and use chainappend */
- VCDSubAppendData( p_dec, p_buffer + SPU_HEADER_LEN,
- p_block->i_buffer - SPU_HEADER_LEN );
-
- block_ChainAppend( &p_sys->p_block, p_block );
-
- p_sys->i_spu += p_block->i_buffer - SPU_HEADER_LEN;
-
- if ( p_sys->subtitle_data_pos == p_sys->i_spu_size ) {
- E_(ParseMetaInfo)( p_dec );
- return p_sys->p_block;
- } else {
- /* Not last block in subtitle, so wait for another. */
- p_sys->state = SUBTITLE_BLOCK_PARTIAL;
- }
-
- return NULL;
-}
+++ /dev/null
-/*****************************************************************************
- * cvd.h : CVD subtitles decoder thread interface
- *****************************************************************************
- * Copyright (C) 2003 VideoLAN
- * $Id: cvd.h,v 1.2 2004/01/04 04:56:21 rocky Exp $
- *
- * Author: Rocky Bernstein
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
- *****************************************************************************/
-
-
-/*****************************************************************************
- * Prototypes
- *****************************************************************************/
-void E_(ParseHeader)( decoder_t *, uint8_t *, block_t * );
-void E_(ParsePacket)( decoder_t * );
-void E_(ParseMetaInfo)( decoder_t *p_dec );
+++ /dev/null
-/*****************************************************************************
- * parse.c: Philips OGT (SVCD subtitle) packet parser
- *****************************************************************************
- * Copyright (C) 2003, 2004 VideoLAN
- * $Id$
- *
- * Authors: Rocky Bernstein
- * based on code from:
- * Julio Sanchez Fernandez (http://subhandler.sourceforge.net)
- * Sam Hocevar <sam@zoy.org>
- * Laurent Aimar <fenrir@via.ecp.fr>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
- *****************************************************************************/
-
-/*****************************************************************************
- * Preamble
- *****************************************************************************/
-#include <vlc/vlc.h>
-#include <vlc/vout.h>
-#include <vlc/decoder.h>
-
-#include "subtitle.h"
-#include "render.h"
-#include "cvd.h"
-#include "common.h"
-
-#ifdef HAVE_LIBPNG
-#include <png.h>
-#endif
-
-/* An image color is a two-bit palette entry: 0..3 */
-typedef uint8_t ogt_color_t;
-
-/*****************************************************************************
- * Local prototypes.
- *****************************************************************************/
-static int ParseImage ( decoder_t *, subpicture_t * );
-
-/*
- We do not have information on the subtitle format used on CVD's
- except the submux sample code and a couple of samples of dubious
- origin. Thus, this is the result of reading some code whose
- correctness is not known and some experimentation.
-
- CVD subtitles are different in several ways from SVCD OGT subtitles.
- Image comes first and metadata is at the end. So that the metadata
- can be found easily, the subtitle packet starts with two bytes
- (everything is big-endian again) that give the total size of the
- subtitle data and the offset to the metadata - i.e. size of the
- image data plus the four bytes at the beginning.
-
- Image data comes interlaced is run-length encoded. Each field is a
- four-bit nibble. Each nibble contains a two-bit repeat count and a
- two-bit color number so that up to three pixels can be described in
- four bits. The function of a 0 repeat count is unknown; it might be
- used for RLE extension. However 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.
-*/
-
-void E_(ParseHeader)( decoder_t *p_dec, uint8_t *p_buffer, block_t *p_block )
-{
- decoder_sys_t *p_sys = p_dec->p_sys;
- uint8_t *p = p_buffer+1;
-
- dbg_print( (DECODE_DBG_CALL|DECODE_DBG_PACKET),
- "header: 0x%02x 0x%02x 0x%02x 0x%02x, 0x%02x, 0x%02x, size: %i",
- p_buffer[0], p_buffer[1], p_buffer[2], p_buffer[3],
- p_buffer[4], p_buffer[5],
- p_block->i_buffer);
-
- dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
-
- p_sys->i_pts = p_block->i_pts;
- p_sys->i_spu_size = (p[0] << 8) + p[1] + 4; p += 2;
-
- /* FIXME: check data sanity */
- p_sys->metadata_offset = GETINT16(p);
- p_sys->metadata_length = p_sys->i_spu_size - p_sys->metadata_offset;
-
- p_sys->i_image_offset = 4;
- p_sys->i_image_length = p_sys->metadata_offset - p_sys->i_image_offset;
-
- dbg_print(DECODE_DBG_PACKET, "total size: %d image size: %d\n",
- p_sys->i_spu_size, p_sys->i_image_length);
-
-}
-
-#define ExtractXY(x, y) \
- x = ((p[1]&0x0f)<<6) + (p[2]>>2); \
- y = ((p[2]&0x03)<<8) + p[3];
-
-
-/*
- We parse the metadata information here.
-
- Although metadata information does not have to come in a fixed field
- order, every metadata field consists of a tag byte followed by
- parameters. In all cases known, the size including tag byte is
- exactly four bytes in length.
-*/
-
-void E_(ParseMetaInfo)( decoder_t *p_dec )
-{
- /* last packet in subtitle block. */
-
- decoder_sys_t *p_sys = p_dec->p_sys;
- uint8_t *p = p_sys->subtitle_data + p_sys->metadata_offset;
- uint8_t *p_end = p + p_sys->metadata_length;
-
- dbg_print( (DECODE_DBG_PACKET),
- "subtitle packet complete, size=%d", p_sys->i_spu );
-
- p_sys->state = SUBTITLE_BLOCK_COMPLETE;
- p_sys->i_image++;
-
- for ( ; p < p_end; p += 4 ) {
-
- switch ( p[0] ) {
-
- case 0x04: /* subtitle duration in 1/90000ths of a second */
- {
- mtime_t i_duration = (p[1]<<16) + (p[2]<<8) + p[3];
- mtime_t i_duration_scale = config_GetInt( p_dec, MODULE_STRING
- "-duration-scaling" );
-
- dbg_print( DECODE_DBG_PACKET,
- "subtitle display duration %lu secs (scaled %lu secs)",
- (long unsigned int) (i_duration / 90000),
- (long unsigned int) (i_duration * i_duration_scale / 90000)
- );
- p_sys->i_duration = i_duration * i_duration_scale ;
- break;
- }
-
-
- case 0x0c: /* unknown */
- dbg_print( DECODE_DBG_PACKET,
- "subtitle command unknown 0x%0x 0x%0x 0x%0x 0x%0x\n",
- p[0], p[1], p[2], p[3]);
- break;
-
- case 0x17: /* coordinates of subtitle upper left x, y position */
- ExtractXY(p_sys->i_x_start, p_sys->i_y_start);
- break;
-
- case 0x1f: /* coordinates of subtitle bottom right x, y position */
- {
- int lastx;
- int lasty;
- ExtractXY(lastx, lasty);
- p_sys->i_width = lastx - p_sys->i_x_start + 1;
- p_sys->i_height = lasty - p_sys->i_y_start + 1;
- dbg_print( DECODE_DBG_PACKET,
- "end position: (%d,%d): %.2x %.2x %.2x, w x h: %dx%d",
- lastx, lasty, p[1], p[2], p[3],
- p_sys->i_width, p_sys->i_height );
- break;
- }
-
-
- case 0x24:
- case 0x25:
- case 0x26:
- case 0x27:
- {
- uint8_t v = p[0]-0x24;
-
- /* Primary Palette */
- dbg_print( DECODE_DBG_PACKET,
- "primary palette %d (y,u,v): (0x%0x,0x%0x,0x%0x)",
- v, p[1], p[2], p[3]);
-
- p_sys->p_palette[v].s.y = p[1];
- p_sys->p_palette[v].s.u = p[2];
- p_sys->p_palette[v].s.v = p[3];
- break;
- }
-
-
- case 0x2c:
- case 0x2d:
- case 0x2e:
- case 0x2f:
- {
- uint8_t v = p[0]-0x2c;
-
- dbg_print( DECODE_DBG_PACKET,
- "highlight palette %d (y,u,v): (0x%0x,0x%0x,0x%0x)",
- v, p[1], p[2], p[3]);
-
- /* Highlight Palette */
- p_sys->p_palette_highlight[v].s.y = p[1];
- p_sys->p_palette_highlight[v].s.u = p[2];
- p_sys->p_palette_highlight[v].s.v = p[3];
- break;
- }
-
- case 0x37:
- /* transparency for primary palette */
- p_sys->p_palette[0].s.t = p[3] & 0x0f;
- p_sys->p_palette[1].s.t = p[3] >> 4;
- p_sys->p_palette[2].s.t = p[2] & 0x0f;
- p_sys->p_palette[3].s.t = p[2] >> 4;
-
- dbg_print( DECODE_DBG_PACKET,
- "transparency for primary palette 0..3: "
- "0x%0x 0x%0x 0x%0x 0x%0x",
- p_sys->p_palette[0].s.t,
- p_sys->p_palette[1].s.t,
- p_sys->p_palette[2].s.t,
- p_sys->p_palette[3].s.t );
-
- break;
-
- case 0x3f:
- /* transparency for highlight palette */
- p_sys->p_palette_highlight[0].s.t = p[2] & 0x0f;
- p_sys->p_palette_highlight[1].s.t = p[2] >> 4;
- p_sys->p_palette_highlight[2].s.t = p[1] & 0x0f;
- p_sys->p_palette_highlight[3].s.t = p[1] >> 4;
-
- dbg_print( DECODE_DBG_PACKET,
- "transparency for primary palette 0..3: "
- "0x%0x 0x%0x 0x%0x 0x%0x",
- p_sys->p_palette_highlight[0].s.t,
- p_sys->p_palette_highlight[1].s.t,
- p_sys->p_palette_highlight[2].s.t,
- p_sys->p_palette_highlight[3].s.t );
-
- break;
-
- case 0x47:
- /* offset to start of even rows of interlaced image, we correct
- to make it relative to i_image_offset (usually 4) */
- p_sys->first_field_offset =
- (p[2] << 8) + p[3] - p_sys->i_image_offset;
- dbg_print( DECODE_DBG_PACKET,
- "first_field_offset %d", p_sys->first_field_offset);
- break;
-
- case 0x4f:
- /* offset to start of odd rows of interlaced image, we correct
- to make it relative to i_image_offset (usually 4) */
- p_sys->second_field_offset =
- (p[2] << 8) + p[3] - p_sys->i_image_offset;
- dbg_print( DECODE_DBG_PACKET,
- "second_field_offset %d", p_sys->second_field_offset);
- break;
-
- default:
- msg_Warn( p_dec,
- "unknown sequence in control header "
- "0x%0x 0x%0x 0x%0x 0x%0x",
- p[0], p[1], p[2], p[3]);
-
- p_sys->subtitle_data_pos = 0;
- }
- }
-}
-
-/*****************************************************************************
- * ParsePacket: parse an SPU packet and send it to the video output
- *****************************************************************************
- * This function parses the SPU packet and, if valid, sends it to the
- * video output.
- *****************************************************************************/
-void
-E_(ParsePacket)( decoder_t *p_dec)
-{
- decoder_sys_t *p_sys = p_dec->p_sys;
-
- subpicture_t *p_spu;
-
- dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
-
- /* Allocate the subpicture internal data. */
- p_spu = spu_CreateSubpicture( p_sys->p_vout->p_spu );
- if( p_spu == NULL ) return;
-
- p_spu->i_channel = p_sys->i_subpic_channel;
-
- /* In ParseImage we expand the run-length encoded color 0's; also
- we expand pixels and remove the color palette. This should
- facilitate scaling and antialiasing and speed up rendering.
- */
- p_spu->p_sys = malloc( sizeof( subpicture_sys_t )
- + PIXEL_SIZE * (p_sys->i_width * p_sys->i_height) );
-
- /* Fill the p_spu structure */
- vlc_mutex_init( p_dec, &p_spu->p_sys->lock );
-
- p_spu->pf_render = VCDSubBlend;
- p_spu->pf_destroy = VCDSubDestroySPU;
- p_spu->p_sys->p_data = (uint8_t*)p_spu->p_sys + sizeof( subpicture_sys_t );
-
- p_spu->p_sys->i_x_end = p_sys->i_x_start + p_sys->i_width - 1;
- p_spu->p_sys->i_y_end = p_sys->i_y_start + p_sys->i_height - 1;
-
- p_spu->i_x = p_sys->i_x_start
- + config_GetInt( p_dec, MODULE_STRING "-horizontal-correct" );
-
- p_spu->p_sys->p_palette[0] = p_sys->p_palette[0];
- p_spu->p_sys->p_palette[1] = p_sys->p_palette[1];
- p_spu->p_sys->p_palette[2] = p_sys->p_palette[2];
- p_spu->p_sys->p_palette[3] = p_sys->p_palette[3];
-
- /* FIXME: use aspect ratio for x? */
- p_spu->i_x = (p_spu->i_x * 3) / 4;
- p_spu->i_y = p_sys->i_y_start
- + config_GetInt( p_dec, MODULE_STRING "-vertical-correct" );
-
- p_spu->i_width = p_sys->i_width;
- p_spu->i_height = p_sys->i_height;
-
- p_spu->i_start = p_sys->i_pts;
- p_spu->i_stop = p_sys->i_pts + (p_sys->i_duration);
-
- p_spu->p_sys->b_crop = VLC_FALSE;
- p_spu->p_sys->i_debug = p_sys->i_debug;
-
- /* Get display time now. If we do it later, we may miss the PTS. */
- p_spu->p_sys->i_pts = p_sys->i_pts;
-
- /* Attach to our input thread */
- p_spu->p_sys->p_input = vlc_object_find( p_dec,
- VLC_OBJECT_INPUT, FIND_PARENT );
-
- /* We try to display it */
- if( ParseImage( p_dec, p_spu ) )
- {
- /* There was a parse error, delete the subpicture */
- spu_DestroySubpicture( p_sys->p_vout->p_spu, p_spu );
- return;
- }
-
- /* SPU is finished - we can ask the video output to display it */
- spu_DisplaySubpicture( p_sys->p_vout->p_spu, p_spu );
-
-}
-
-#define advance_color_byte_pointer \
- p++; \
- i_nibble_field = 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 " \
- " padding (%d,%d,%d)\n", \
- i_field, i_row, i_column ); \
- return VLC_EGENERIC; \
- }
-
-#define CVD_FIELD_BITS (4)
-#define CVD_FIELD_MASK ((1<<CVD_FIELD_BITS) - 1)
-
-/* Get the next field - a 2-bit palette index and a run count. To do
- this we use byte image pointer p, and i_nibble_field which
- indicates where we are in the byte.
-*/
-static inline uint8_t
-ExtractField(uint8_t *p, uint8_t i_nibble_field)
-{
- return ( ( *p >> (CVD_FIELD_BITS*(i_nibble_field-1)) ) & CVD_FIELD_MASK );
-}
-
-/*****************************************************************************
- * ParseImage: parse the image part of the subtitle
- *****************************************************************************
- This part parses the subtitle graphical data and stores it in a more
- convenient structure for later rendering.
-
- 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
- a 4-bit alpha (filling 8 bits), and 8-bit y, u, and v entry.
-
- *****************************************************************************/
-static int
-ParseImage( decoder_t *p_dec, subpicture_t * p_spu )
-{
- decoder_sys_t *p_sys = p_dec->p_sys;
-
- uint8_t 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_nibble_field; /* The 2-bit pixels remaining in byte of *p.
- Has value 0..2. */
- 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->i_image_offset;
- uint8_t *maxp = p + p_sys->i_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_nibble_field = 2; /* 4-bit pieces available in *p */
-
-#if 0
- unsigned int i;
- int8_t *b=p;
- for (i=0; i< i_width * i_height; i++)
- printf ("%02x", b[i]);
- printf("\n");
-#endif
-
- for ( i_row=i_field; i_row < i_height; i_row += 2 ) {
- b_filling = VLC_FALSE;
- 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_nibble_field--);
- if ( i_nibble_field == 0 ) {
- advance_color_byte_pointer;
- }
- if ( i_val == 0 ) {
- /* fill the rest of the line with next color */
- i_color = ExtractField( p, i_nibble_field-- );
- if ( i_nibble_field == 0 ) {
- p++;
- i_nibble_field=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_nibble_field == 1 ) {
- advance_color_byte_pointer;
- }
-
- if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE)
- printf("\n");
- }
- }
-
- if (p_sys && (p_sys->i_debug & DECODE_DBG_IMAGE)) {
- /* Dump out image not interlaced... */
- VCDSubDumpImage( p_dest, i_height, i_width );
- }
-
-#ifdef HAVE_LIBPNG
- if (p_sys && (p_sys->i_debug & DECODE_DBG_PNG)) {
-#define TEXT_COUNT 2
- /* Dump image to a file in PNG format. */
- char filename[300];
- png_text text_ptr[TEXT_COUNT];
-
- text_ptr[0].key = "Preparer";
- text_ptr[0].text = "VLC";
- text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
- text_ptr[1].key = "Description";
- text_ptr[1].text = "CVD Subtitle";
- text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
-
- snprintf(filename, 300, "%s%d.png", "/tmp/vlc-cvd-sub", p_sys->i_image);
- VCDSubDumpPNG( p_dest, p_dec, i_height, i_width, filename,
- text_ptr, TEXT_COUNT );
- }
-#endif /*HAVE_LIBPNG*/
-
- VCDSubHandleScaling( p_spu, p_dec );
-
- return VLC_SUCCESS;
-
-}
-
+++ /dev/null
-/*****************************************************************************
- * ogt.c : Overlay Graphics Text (SVCD subtitles) decoder thread
- *****************************************************************************
- * Copyright (C) 2003, 2004 VideoLAN
- * $Id$
- *
- * Author: Rocky Bernstein
- * based on code from:
- * Julio Sanchez Fernandez (http://subhandler.sourceforge.net)
- * Samuel Hocevar <sam@zoy.org>
- * Laurent Aimar <fenrir@via.ecp.fr>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
- *****************************************************************************/
-
-/*****************************************************************************
- * Preamble
- *****************************************************************************/
-#include <vlc/vlc.h>
-#include <vlc/vout.h>
-#include <vlc/decoder.h>
-
-#include "subtitle.h"
-#include "ogt.h"
-#include "common.h"
-
-/*****************************************************************************
- * Module descriptor.
- *****************************************************************************/
-static int VCDSubOpen ( vlc_object_t * );
-static int PacketizerOpen( vlc_object_t * );
-
-vlc_module_begin();
- set_description( _("Philips OGT (SVCD subtitle) decoder") );
- set_capability( "decoder", 50 );
- set_callbacks( VCDSubOpen, VCDSubClose );
-
- add_integer ( MODULE_STRING "-debug", 0, NULL,
- DEBUG_TEXT, DEBUG_LONGTEXT, VLC_TRUE );
-
- add_integer ( MODULE_STRING "-horizontal-correct", 0, NULL,
- HORIZONTAL_CORRECT, HORIZONTAL_CORRECT_LONGTEXT, VLC_FALSE );
-
- add_integer ( MODULE_STRING "-vertical-correct", 0, NULL,
- VERTICAL_CORRECT, VERTICAL_CORRECT_LONGTEXT, VLC_FALSE );
-
- add_string( MODULE_STRING "-aspect-ratio", "", NULL,
- SUB_ASPECT_RATIO_TEXT, SUB_ASPECT_RATIO_LONGTEXT, VLC_TRUE );
-
- add_integer( MODULE_STRING "-duration-scaling", 9, NULL,
- DURATION_SCALE_TEXT, DURATION_SCALE_LONGTEXT, VLC_TRUE );
-
- add_submodule();
- set_description( _("Philips OGT (SVCD subtitle) packetizer") );
- set_capability( "packetizer", 50 );
- set_callbacks( PacketizerOpen, VCDSubClose );
-vlc_module_end();
-
-/*****************************************************************************
- * Local prototypes
- *****************************************************************************/
-
-static block_t *Reassemble ( decoder_t *, block_t ** );
-static subpicture_t *Decode( decoder_t *, block_t ** );
-static block_t *Packetize ( decoder_t *, block_t ** );
-
-/*****************************************************************************
- * VCDSubOpen
- *****************************************************************************
- * Tries to launch a decoder and return score so that the interface is able
- * to chose.
- *****************************************************************************/
-static int
-VCDSubOpen( vlc_object_t *p_this )
-{
- decoder_t *p_dec = (decoder_t*)p_this;
- decoder_sys_t *p_sys;
-
- if( p_dec->fmt_in.i_codec != VLC_FOURCC( 'o','g','t',' ' ) )
- {
- return VLC_EGENERIC;
- }
-
-
- p_dec->p_sys = p_sys = malloc( sizeof( decoder_sys_t ) );
-
- p_sys->i_debug = config_GetInt( p_this, MODULE_STRING "-debug" );
- p_sys->b_packetizer = VLC_FALSE;
- p_sys->p_vout = NULL;
- p_sys->i_image = -1;
- p_sys->subtitle_data = NULL;
-
- VCDSubInitSubtitleBlock( p_sys );
-
- es_format_Init( &p_dec->fmt_out, SPU_ES, VLC_FOURCC( 'o','g','t',' ' ) );
-
-
- p_dec->pf_decode_sub = Decode;
- p_dec->pf_packetize = Packetize;
-
- dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
-
- return VLC_SUCCESS;
-}
-
-/*****************************************************************************
- * PacketizerOpen
- *****************************************************************************
- * Tries to launch a decoder and return score so that the interface is able
- * to chose.
- *****************************************************************************/
-static int PacketizerOpen( vlc_object_t *p_this )
-{
- decoder_t *p_dec = (decoder_t*)p_this;
-
- if( VCDSubOpen( p_this ) )
- {
- return VLC_EGENERIC;
- }
- p_dec->p_sys->b_packetizer = VLC_TRUE;
-
- return VLC_SUCCESS;
-}
-
-/*****************************************************************************
- * Decode:
- *****************************************************************************/
-static subpicture_t *
-Decode ( decoder_t *p_dec, block_t **pp_block )
-{
- decoder_sys_t *p_sys = p_dec->p_sys;
- block_t *p_spu = Reassemble( p_dec, pp_block );
- vout_thread_t *p_last_vout = p_dec->p_sys->p_vout;
-
- dbg_print( (DECODE_DBG_CALL) , "");
-
- if( p_spu )
- {
- p_sys->i_spu = block_ChainExtract( p_spu, p_sys->buffer, 65536 );
- p_sys->i_pts = p_spu->i_pts;
- block_ChainRelease( p_spu );
-
- if( ( p_sys->p_vout = VCDSubFindVout( p_dec ) ) )
- {
- if( p_last_vout != p_sys->p_vout )
- {
- spu_Control( p_sys->p_vout->p_spu, SPU_CHANNEL_REGISTER,
- &p_sys->i_subpic_channel );
- }
-
- /* Parse and decode */
- E_(ParsePacket)( p_dec );
-
- vlc_object_release( p_sys->p_vout );
- }
-
- VCDSubInitSubtitleBlock ( p_sys );
- }
-
- return NULL;
-}
-
-/*****************************************************************************
- * Packetize:
- *****************************************************************************/
-static block_t *
-Packetize( decoder_t *p_dec, block_t **pp_block )
-{
- decoder_sys_t *p_sys = p_dec->p_sys;
- block_t *p_spu = Reassemble( p_dec, pp_block );
-
- if( p_spu )
- {
- p_spu->i_dts = p_spu->i_pts;
- p_spu->i_length = 0;
-
- VCDSubInitSubtitleBlock( p_sys );
-
- return block_ChainGather( p_spu );
- }
- return NULL;
-}
-
-#define SPU_HEADER_LEN 5
-
-/*****************************************************************************
- Reassemble:
-
- The data for single screen subtitle may come in one of many
- non-contiguous packets of a stream. This routine is called when the
- next packet in the stream comes in. The job of this routine is to
- parse the header, if this is the beginning, and combine the packets
- into one complete subtitle unit.
-
- If everything is complete, we will return a block. Otherwise return
- NULL.
-
-
- The format of the beginning of the subtitle packet that is used here.
-
- size description
- -------------------------------------------
- byte subtitle channel (0..7) in bits 0-3
- byte subtitle packet number of this subtitle image 0-N,
- if the subtitle packet is complete, the top bit of the byte is 1.
- uint16 subtitle image number
-
- *****************************************************************************/
-static block_t *
-Reassemble( decoder_t *p_dec, block_t **pp_block )
-{
- decoder_sys_t *p_sys = p_dec->p_sys;
- block_t *p_block;
- uint8_t *p_buffer;
- uint16_t i_expected_image;
- uint8_t i_packet, i_expected_packet;
-
- if( pp_block == NULL || *pp_block == NULL )
- {
- return NULL;
- }
- p_block = *pp_block;
- *pp_block = NULL;
-
- if( p_block->i_buffer < SPU_HEADER_LEN )
- {
- msg_Dbg( p_dec, "invalid packet header (size %d < %d)" ,
- p_block->i_buffer, SPU_HEADER_LEN );
- block_Release( p_block );
- return NULL;
- }
-
- p_buffer = p_block->p_buffer;
-
- dbg_print( (DECODE_DBG_CALL|DECODE_DBG_PACKET),
- "header: 0x%02x 0x%02x 0x%02x 0x%02x, size: %i",
- p_buffer[1], p_buffer[2], p_buffer[3], p_buffer[4],
- p_block->i_buffer);
-
- /* Attach to our input thread and see if subtitle is selected. */
- {
- vlc_object_t * p_input;
- vlc_value_t val;
-
- p_input = vlc_object_find( p_dec, VLC_OBJECT_INPUT, FIND_PARENT );
-
- if( !p_input ) return NULL;
-
- if( var_Get( p_input, "spu-channel", &val ) )
- {
- vlc_object_release( p_input );
- return NULL;
- }
-
- vlc_object_release( p_input );
- dbg_print( (DECODE_DBG_PACKET),
- "val.i_int %x p_buffer[i] %x", val.i_int, p_buffer[1]);
-
- /* The dummy ES that the menu selection uses has an 0x70 at
- the head which we need to strip off. */
- if( val.i_int == -1 || (val.i_int & 0x03) != p_buffer[1] )
- {
- dbg_print( DECODE_DBG_PACKET, "subtitle not for us.\n");
- return NULL;
- }
- }
-
- if ( p_sys->state == SUBTITLE_BLOCK_EMPTY ) {
- i_expected_image = p_sys->i_image+1;
- i_expected_packet = 0;
- } else {
- i_expected_image = p_sys->i_image;
- i_expected_packet = p_sys->i_packet+1;
- }
-
- p_buffer += 2;
-
- if ( *p_buffer & 0x80 ) {
- p_sys->state = SUBTITLE_BLOCK_COMPLETE;
- i_packet = ( *p_buffer++ & 0x7F );
- } else {
- p_sys->state = SUBTITLE_BLOCK_PARTIAL;
- i_packet = *p_buffer++;
- }
-
- p_sys->i_image = GETINT16(p_buffer);
-
- if ( p_sys->i_image != i_expected_image ) {
- msg_Warn( p_dec, "expecting subtitle image %u but found %u",
- i_expected_image, p_sys->i_image );
- }
-
- if ( i_packet != i_expected_packet ) {
- msg_Warn( p_dec, "expecting subtitle image packet %u but found %u",
- i_expected_packet, i_packet);
- }
-
- p_sys->i_packet = i_packet;
-
- if ( p_sys->i_packet == 0 ) {
- /* First packet in the subtitle block */
- E_(ParseHeader)( p_dec, p_buffer, p_block );
- VCDSubInitSubtitleData(p_sys);
- }
-
- /* FIXME - remove append_data and use chainappend */
- VCDSubAppendData( p_dec, p_buffer, p_block->i_buffer - SPU_HEADER_LEN );
-
- block_ChainAppend( &p_sys->p_block, p_block );
-
- p_sys->i_spu += p_block->i_buffer - SPU_HEADER_LEN;
-
- if (p_sys->state == SUBTITLE_BLOCK_COMPLETE)
- {
- if( p_sys->i_spu != p_sys->i_spu_size )
- {
- msg_Warn( p_dec, "SPU packets size=%d should be %d",
- p_sys->i_spu, p_sys->i_spu_size );
- }
-
- dbg_print( (DECODE_DBG_PACKET),
- "subtitle packet complete, size=%d", p_sys->i_spu );
-
- return p_sys->p_block;
- }
- return NULL;
-}
-
-\f
-/*
- * Local variables:
- * c-file-style: "gnu"
- * tab-width: 8
- * indent-tabs-mode: nil
- * End:
- */
+++ /dev/null
-/*****************************************************************************
- * ogt.h : Overlay Graphics Text (SVCD subtitles) decoder thread interface
- *****************************************************************************
- * Copyright (C) 2003 VideoLAN
- * $Id: ogt.h,v 1.6 2003/12/28 02:01:11 rocky Exp $
- *
- * Author: Rocky Bernstein
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
- *****************************************************************************/
-
-/*****************************************************************************
- * Prototypes
- *****************************************************************************/
-void E_(ParseHeader)( decoder_t *, uint8_t *, block_t * );
-void E_(ParsePacket)( decoder_t * );
-
+++ /dev/null
-/*****************************************************************************
- * Philips OGT (SVCD subtitle) packet parser
- *****************************************************************************
- * Copyright (C) 2003, 2004 VideoLAN
- * $Id$
- *
- * Author: Rocky Bernstein
- * based on code from:
- * Julio Sanchez Fernandez (http://subhandler.sourceforge.net)
- * Sam Hocevar <sam@zoy.org>
- * Laurent Aimar <fenrir@via.ecp.fr>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
- *****************************************************************************/
-
-/*****************************************************************************
- * Preamble
- *****************************************************************************/
-#include <vlc/vlc.h>
-#include <vlc/vout.h>
-#include <vlc/decoder.h>
-
-#include "subtitle.h"
-#include "common.h"
-#include "render.h"
-#include "ogt.h"
-
-#ifdef HAVE_LIBPNG
-#include <png.h>
-#endif
-
-/* An image color is a two-bit palette entry: 0..3 */
-typedef uint8_t ogt_color_t;
-
-/*****************************************************************************
- * Local prototypes.
- *****************************************************************************/
-static int ParseImage ( decoder_t *, subpicture_t * );
-
-/*
- The format is roughly as follows (everything is big-endian):
-
- size description
- -------------------------------------------
- byte subtitle channel (0..7) in bits 0-3
- byte subtitle packet number of this subtitle image 0-N,
- if the subtitle packet is complete, the top bit of the byte is 1.
- u_int16 subtitle image number
- u_int16 length in bytes of the rest
- byte option flags, unknown meaning except bit 3 (0x08) indicates
- presence of the duration field
- byte unknown
- u_int32 duration in 1/90000ths of a second (optional), start time
- is as indicated by the PTS in the PES header
- u_int32 xpos
- u_int32 ypos
- u_int32 width (must be even)
- u_int32 height (must be even)
- byte[16] palette, 4 palette entries, each contains values for
- Y, U, V and transparency, 0 standing for transparent
- byte command,
- cmd>>6==1 indicates shift
- (cmd>>4)&3 is direction from, (0=top,1=left,2=right,3=bottom)
- u_int32 shift duration in 1/90000ths of a second
- u_int16 offset of odd-numbered scanlines - subtitle images are
- given in interlace order
- byte[] limited RLE image data in interlace order (0,2,4... 1,3,5) with
- 2-bits per palette number
-*/
-
-/* FIXME: do we really need p_buffer and p?
- Can't all of thes _offset's and _lengths's get removed?
-*/
-void E_(ParseHeader)( decoder_t *p_dec, uint8_t *p_buffer, block_t *p_block )
-{
- decoder_sys_t *p_sys = p_dec->p_sys;
- uint8_t *p = p_buffer;
- int i;
-
- dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
-
- p_sys->i_pts = p_block->i_pts;
- p_sys->i_spu_size = GETINT16(p);
- p_sys->i_options = *p++;
- p_sys->i_options2 = *p++;
-
- if ( p_sys->i_options & 0x08 ) {
- p_sys->i_duration = GETINT32(p);
- p_sys->i_duration *= config_GetInt( p_dec, MODULE_STRING
- "-duration-scaling" );
- } else {
- /* 0 means display until next subtitle comes in. */
- p_sys->i_duration = 0;
- }
- p_sys->i_x_start= GETINT16(p);
- p_sys->i_y_start= GETINT16(p);
- p_sys->i_width = GETINT16(p);
- p_sys->i_height = GETINT16(p);
-
- for (i=0; i<4; i++) {
- p_sys->p_palette[i].s.y = *p++;
- p_sys->p_palette[i].s.u = *p++;
- p_sys->p_palette[i].s.v = *p++;
- /* 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->p_palette[i].s.t = (*p++) >> 4;
- }
- p_sys->i_cmd = *p++;
- /* We do not really know this, FIXME */
- if ( p_sys->i_cmd ) {
- p_sys->i_cmd_arg = GETINT32(p);
- }
-
- /* Actually, this is measured against a different origin, so we have to
- adjust it */
- p_sys->second_field_offset = GETINT16(p);
- p_sys->i_image_offset = p - p_buffer;
- p_sys->i_image_length = p_sys->i_spu_size - p_sys->i_image_offset;
- p_sys->metadata_length = p_sys->i_image_offset;
-
- if (p_sys && p_sys->i_debug & DECODE_DBG_PACKET) {
- msg_Dbg( p_dec, "x-start: %d, y-start: %d, width: %d, height %d, "
- "spu size: %d, duration: %lu (d:%d p:%d)",
- p_sys->i_x_start, p_sys->i_y_start,
- p_sys->i_width, p_sys->i_height,
- p_sys->i_spu_size, (long unsigned int) p_sys->i_duration,
- p_sys->i_image_length, p_sys->i_image_offset);
-
- for (i=0; i<4; i++) {
- msg_Dbg( p_dec, "palette[%d]= T: %2x, Y: %2x, u: %2x, v: %2x", i,
- p_sys->p_palette[i].s.t, p_sys->p_palette[i].s.y,
- p_sys->p_palette[i].s.u, p_sys->p_palette[i].s.v );
- }
- }
-}
-
-
-/*****************************************************************************
- * ParsePacket: parse an SPU packet and send it to the video output
- *****************************************************************************
- * This function parses the SPU packet and, if valid, sends it to the
- * video output.
- *****************************************************************************/
-void
-E_(ParsePacket)( decoder_t *p_dec)
-{
- decoder_sys_t *p_sys = p_dec->p_sys;
-
- subpicture_t *p_spu;
-
- dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
-
- /* Allocate the subpicture internal data. */
- p_spu = spu_CreateSubpicture( p_sys->p_vout->p_spu );
- if( p_spu == NULL ) return;
-
- p_spu->i_channel = p_sys->i_subpic_channel;
-
- /* In ParseImage we expand the run-length encoded color 0's; also
- we expand pixels and remove the color palette. This should
- facilitate scaling and antialiasing and speed up rendering.
- */
- p_spu->p_sys = malloc( sizeof( subpicture_sys_t )
- + PIXEL_SIZE * (p_sys->i_width * p_sys->i_height) );
-
- /* Fill the p_spu structure */
- vlc_mutex_init( p_dec, &p_spu->p_sys->lock );
-
- p_spu->pf_render = VCDSubBlend;
- p_spu->pf_destroy = VCDSubDestroySPU;
- p_spu->p_sys->p_data = (uint8_t*)p_spu->p_sys + sizeof( subpicture_sys_t );
-
- p_spu->p_sys->i_x_end = p_sys->i_x_start + p_sys->i_width - 1;
- p_spu->p_sys->i_y_end = p_sys->i_y_start + p_sys->i_height - 1;
-
- p_spu->i_x = p_sys->i_x_start
- + config_GetInt( p_dec, MODULE_STRING "-horizontal-correct" );
-
- p_spu->p_sys->p_palette[0] = p_sys->p_palette[0];
- p_spu->p_sys->p_palette[1] = p_sys->p_palette[1];
- p_spu->p_sys->p_palette[2] = p_sys->p_palette[2];
- p_spu->p_sys->p_palette[3] = p_sys->p_palette[3];
-
- /* FIXME: use aspect ratio for x? */
- p_spu->i_x = (p_spu->i_x * 3) / 4;
- p_spu->i_y = p_sys->i_y_start
- + config_GetInt( p_dec, MODULE_STRING "-vertical-correct" );
- p_spu->i_width = p_sys->i_width;
- p_spu->i_height = p_sys->i_height;
-
- p_spu->i_start = p_sys->i_pts;
- p_spu->i_stop = p_sys->i_pts + p_sys->i_duration;
-
- p_spu->p_sys->b_crop = VLC_FALSE;
- p_spu->p_sys->i_debug = p_sys->i_debug;
-
- /* Get display time now. If we do it later, we may miss the PTS. */
- p_spu->p_sys->i_pts = p_sys->i_pts;
-
- /* Attach to our input thread */
- p_spu->p_sys->p_input = vlc_object_find( p_dec,
- VLC_OBJECT_INPUT, FIND_PARENT );
-
- /* We try to display it */
- if( ParseImage( p_dec, p_spu ) )
- {
- /* There was a parse error, delete the subpicture */
- spu_DestroySubpicture( p_sys->p_vout->p_spu, p_spu );
- return;
- }
-
- /* SPU is finished - we can ask the video output to display it */
- spu_DisplaySubpicture( p_sys->p_vout->p_spu, p_spu );
-
-}
-
-/* Advance pointer to image pointer, update internal i_2bit_field counter
- and check that we haven't goine too far in the image data. */
-#define advance_color_pointer_byte \
- p++; \
- i_2bit_field=4; \
- if (p >= maxp) { \
- msg_Warn( p_dec, \
- "broken subtitle - tried to access beyond end " \
- "in image extraction"); \
- return VLC_EGENERIC; \
- } \
-
-#define advance_color_pointer \
- i_2bit_field--; \
- if ( i_2bit_field == 0 ) { \
- advance_color_pointer_byte; \
- }
-
-#define OGT_FIELD_BITS (2)
-#define OGT_FIELD_MASK ((1<<OGT_FIELD_BITS) - 1)
-
-/* 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_2bit_field
- which indicates where we are in the byte.
-*/
-static inline ogt_color_t
-ExtractField(uint8_t *p, unsigned int i_2bit_field)
-{
- return ( ( *p >> (OGT_FIELD_BITS*(i_2bit_field-1)) ) & OGT_FIELD_MASK );
-}
-
-/*****************************************************************************
- * ParseImage: parse the image part of the subtitle
- *****************************************************************************
- 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.
-
- 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 4-bit alpha (filling 8 bits), and 8-bit y, u, and v entry.
-
- *****************************************************************************/
-static int
-ParseImage( decoder_t *p_dec, subpicture_t * p_spu )
-{
- decoder_sys_t *p_sys = p_dec->p_sys;
-
- 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_2bit_field; /* The 2-bit field to sue in byte of *p.
- Has value 0..4. */
- uint8_t i_pending_zero = 0; /* number of pixels to fill with
- color zero 0..3 */
- ogt_color_t i_color; /* current pixel color: 0..3 */
- uint8_t *p = p_sys->subtitle_data + p_sys->i_image_offset;
- uint8_t *maxp = p + p_sys->i_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");
-
- for ( i_field=0; i_field < 2; i_field++ ) {
- i_2bit_field = 4;
- 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_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 {
- i_color = ExtractField( p, i_2bit_field );
- advance_color_pointer;
- if ( i_color == 0 ) {
- i_pending_zero = ExtractField( p, i_2bit_field );
- advance_color_pointer;
- /* Fall through with i_color == 0 to output the first cell */
- }
- }
-
- /* 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 (p_sys && (p_sys->i_debug & DECODE_DBG_IMAGE))
- printf("\n");
-
- if ( i_2bit_field != 4 ) {
- /* Lines are padded to complete bytes, ignore padding */
- advance_color_pointer_byte;
- }
- }
- p = p_sys->subtitle_data + p_sys->i_image_offset
- + p_sys->second_field_offset;
- }
-
- if (p_sys && (p_sys->i_debug & DECODE_DBG_IMAGE)) {
- /* Dump out image not interlaced... */
- VCDSubDumpImage( p_dest, i_height, i_width );
- }
-
-#ifdef HAVE_LIBPNG
- if (p_sys && (p_sys->i_debug & DECODE_DBG_PNG)) {
-#define TEXT_COUNT 2
- /* Dump image to a file in PNG format. */
- char filename[300];
- png_text text_ptr[TEXT_COUNT];
-
- text_ptr[0].key = "Preparer";
- text_ptr[0].text = "VLC";
- text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
- text_ptr[1].key = "Description";
- text_ptr[1].text = "SVCD Subtitle";
- text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
-
- snprintf(filename, 300, "%s%d.png", "/tmp/vlc-svcd-sub", p_sys->i_image);
- VCDSubDumpPNG( p_dest, p_dec, i_height, i_width, filename,
- text_ptr, TEXT_COUNT );
- }
-#endif /*HAVE_LIBPNG*/
-
- VCDSubHandleScaling( p_spu, p_dec );
- return VLC_SUCCESS;
-}
-
-\f
-/*
- * Local variables:
- * c-file-style: "gnu"
- * tab-width: 8
- * indent-tabs-mode: nil
- * End:
- */
+++ /dev/null
-/*****************************************************************************
- * Common pixel/chroma manipulation routines.
- *****************************************************************************
- * Copyright (C) 2003, 2004 VideoLAN
- * $Id: pixmap.c,v 1.3 2004/01/31 05:53:35 rocky Exp $
- *
- * Author: Rocky Bernstein
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
- *****************************************************************************/
-
-#include <vlc/vlc.h>
-#include <vlc/vout.h>
-
-#include "pixmap.h"
-
-/* FIXME: This is copied from modules/video_chroma/i420_rgb.h.
- Include from a more common location.
- */
-
-/*****************************************************************************
- * chroma_sys_t: chroma method descriptor
- *****************************************************************************
- * This structure is part of the chroma transformation descriptor, it
- * describes the yuv2rgb specific properties.
- *****************************************************************************/
-struct chroma_sys_t
-{
- uint8_t *p_buffer;
- int *p_offset;
-
- /* Pre-calculated conversion tables */
- void *p_base; /* base for all conversion tables */
- uint8_t *p_rgb8; /* RGB 8 bits table */
- uint16_t *p_rgb16; /* RGB 16 bits table */
- uint32_t *p_rgb32; /* RGB 32 bits table */
-
- /* To get RGB value for palette entry i, use (p_rgb_r[i], p_rgb_g[i],
- p_rgb_b[i])
- */
- uint16_t p_rgb_r[CMAP_RGB2_SIZE]; /* Red values of palette */
- uint16_t p_rgb_g[CMAP_RGB2_SIZE]; /* Green values of palette */
- uint16_t p_rgb_b[CMAP_RGB2_SIZE]; /* Blue values of palette */
-};
-
-
-/*
- From
- http://www.inforamp.net/~poynton/notes/colour_and_gamma/ColorFAQ.html#RTFToC11
- http://people.ee.ethz.ch/~buc/brechbuehler/mirror/color/ColorFAQ.html#RTFToC1
-
- 11. What is "luma"?
-
- It is useful in a video system to convey a component representative of
- luminance and two other components representative of colour. It is
- important to convey the component representative of luminance in such
- a way that noise (or quantization) introduced in transmission,
- processing and storage has a perceptually similar effect across the
- entire tone scale from black to white. The ideal way to accomplish
- these goals would be to form a luminance signal by matrixing RGB, then
- subjecting luminance to a nonlinear transfer function similar to the
- L* function.
-
- There are practical reasons in video to perform these operations
- in the opposite order. First a nonlinear transfer function - gamma
- correction - is applied to each of the linear R, G and B. Then a
- weighted sum of the nonlinear components is computed to form a
- signal representative of luminance. The resulting component is
- related to brightness but is not CIE luminance. Many video
- engineers call it luma and give it the symbol Y'. It is often
- carelessly called luminance and given the symbol Y. You must be
- careful to determine whether a particular author assigns a linear
- or nonlinear interpretation to the term luminance and the symbol
- Y.
-
- The coefficients that correspond to the "NTSC" red, green and blue
- CRT phosphors of 1953 are standardized in ITU-R Recommendation BT.
- 601-2 (formerly CCIR Rec. 601-2). I call it Rec. 601. To compute
- nonlinear video luma from nonlinear red, green and blue:
-
- Y'601 = 0.299R' 0.587G' + 0.114B'
-
- We will use the integer scaled versions of these numbers below
- as RED_COEF, GREEN_COEF and BLUE_COEF.
- */
-
-/* 19 = round(0.299 * 64) */
-#define RED_COEF ((int32_t) 19)
-
-/* 38 = round(0.587 * 64) */
-#define GREEN_COEF ((int32_t) 37)
-
-/* 7 = round(0.114 * 64) */
-#define BLUE_COEF ((int32_t) 7)
-
-/**
- Find the nearest colormap entry in p_vout (assumed to have RGB2
- chroma, i.e. 256 RGB 8bpp entries) that is closest in color to p_rgb. Set
- out_rgb to the color found and return the colormap index.
- INVALID_CMAP_ENTRY is returned if there is some error.
-
- The closest match is determined by the the Euclidean distance
- using integer-scaled 601-2 coefficients described above.
-
- Actually, we use the square of the Euclidean distance; but in
- comparisons it amounts to the same thing.
-*/
-
-cmap_t
-find_cmap_rgb8_nearest(const vout_thread_t *p_vout, const uint8_t *rgb,
- uint8_t *out_rgb)
-{
- uint16_t *p_cmap_r;
- uint16_t *p_cmap_g;
- uint16_t *p_cmap_b;
-
- int i;
- cmap_t i_bestmatch = INVALID_CMAP_ENTRY;
- uint32_t i_mindist = 0xFFFFFFFF; /* The largest number here. */
-
- /* Check that we really have RGB2. */
-
- if ( !p_vout && p_vout->output.i_chroma != VLC_FOURCC('R','G','B','2') )
- return INVALID_CMAP_ENTRY;
-
- p_cmap_r=p_vout->chroma.p_sys->p_rgb_r;
- p_cmap_g=p_vout->chroma.p_sys->p_rgb_g;
- p_cmap_b=p_vout->chroma.p_sys->p_rgb_b;
-
- for (i = 0; i < CMAP_RGB2_SIZE; i++) {
- /* Interval range calculations to show that we don't overflow the
- word sizes below. pixels component values start out 8
- bits. When we subtract two components we get 9 bits, then
- square to 10 bits. Next we scale by 6 to give 16
- bits. XXX_COEF all fit into 5 bits, so when we multiply we
- should have 21 bits maximum. So computations can be done using
- 32-bit precision. However before storing back distance
- components we scale back down by 12 bits making the precision 9
- bits. (This checks out since it is basically the range of the
- square of the initial 8-bit value.)
-
- The squared distance is the sum of three of the 9-bit components
- described above. This then uses 27-bits and also fits in a
- 32-bit word.
- */
-
- /* We use in integer fixed-point fractions rather than floating
- point for speed. We multiply by 64 (= 1 << 6) before computing
- the product, and divide the result by 64*64 (= 1 >> (6*2)).
- */
-
-#define SCALEBITS 6
-#define int32_sqr(x) ( ((int32_t) (x)) * ((int32_t) x) )
-
- /* colormap entires are scaled to 16 bits, so we need to shift
- them back down to 8. */
-#define CMAP8_RED(i) (p_cmap_r[i]>>8)
-#define CMAP8_GREEN(i) (p_cmap_g[i]>>8)
-#define CMAP8_BLUE(i) (p_cmap_b[i]>>8)
-
- uint32_t dr = ( RED_COEF * ( int32_sqr(rgb[RED_PIXEL] - CMAP8_RED(i))
- << SCALEBITS ) ) >> (SCALEBITS*2);
- uint32_t dg = ( GREEN_COEF * ( int32_sqr(rgb[GREEN_PIXEL] - CMAP8_GREEN(i))
- << SCALEBITS ) ) >> (SCALEBITS*2);
- uint32_t db = ( BLUE_COEF * ( int32_sqr(rgb[BLUE_PIXEL] - CMAP8_BLUE(i))
- << SCALEBITS ) ) >> (SCALEBITS*2);
-
- uint32_t i_dist = dr + dg + db;
- if (i_dist < i_mindist) {
- i_bestmatch = i;
- i_mindist = i_dist;
-#if 0
- printf("+++Change dist to %d RGB cmap %d (%0x, %0x, %0x)\n",
- i_dist, i, p_cmap_r[ i ], p_cmap_g[ i ], p_cmap_b[ i ]);
-#endif
- }
- }
-
- if (out_rgb)
- {
- out_rgb[RED_PIXEL] = CMAP8_RED(i_bestmatch);
- out_rgb[GREEN_PIXEL] = CMAP8_GREEN(i_bestmatch);
- out_rgb[BLUE_PIXEL] = CMAP8_BLUE(i_bestmatch);
- }
-
- return i_bestmatch;
-}
-
-/**
- Get the the rgb value for a given colormap entry for p_vout (which is'
- assumed to have RGB2 chroma).
-
- VLC_FALSE is returned if there was some error.
-*/
-vlc_bool_t
-query_color(const vout_thread_t *p_vout, cmap_t i_cmap,
- /*out*/ uint8_t *out_rgb)
-{
- uint16_t *p_cmap_r;
- uint16_t *p_cmap_g;
- uint16_t *p_cmap_b;
-
- /* Check that we really have RGB2. */
-
- if ( !p_vout && p_vout->output.i_chroma != VLC_FOURCC('R','G','B','2') )
- return VLC_FALSE;
-
- if ( !out_rgb )
- return VLC_FALSE;
-
- p_cmap_r=p_vout->chroma.p_sys->p_rgb_r;
- p_cmap_g=p_vout->chroma.p_sys->p_rgb_g;
- p_cmap_b=p_vout->chroma.p_sys->p_rgb_b;
-
- out_rgb[RED_PIXEL] = CMAP8_RED(i_cmap);
- out_rgb[GREEN_PIXEL] = CMAP8_GREEN(i_cmap);
- out_rgb[BLUE_PIXEL] = CMAP8_BLUE(i_cmap);
-
- return VLC_TRUE;
-}
-
-\f
-/*
- * Local variables:
- * c-file-style: "gnu"
- * tab-width: 8
- * indent-tabs-mode: nil
- * End:
- */
+++ /dev/null
-/*****************************************************************************
- * Common pixel/chroma manipulation routines.
- *****************************************************************************
- * Copyright (C) 2003, 2004 VideoLAN
- * $Id: pixmap.h,v 1.6 2004/01/31 23:33:02 rocky Exp $
- *
- * Author: Rocky Bernstein
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
- *****************************************************************************/
-
-#ifndef PIXMAP_H
-#define PIXMAP_H
-
-/** Color and transparency of a pixel or a palette (CLUT) entry
-*/
-typedef union {
- uint8_t plane[4];
- struct {
- uint8_t y;
- uint8_t v;
- uint8_t u;
- uint8_t t;
- } s;
-} ogt_yuvt_t;
-
-/** An undefined or invalid colormap index. */
-#define INVALID_CMAP_ENTRY -1
-
-/** Type of a palette/colormap index*/
-typedef int16_t cmap_t;
-
-/** Number of entries in RGB palette/colormap*/
-#define CMAP_RGB2_SIZE 256
-
-/**
- Force v in the range 0..255. In video_chroma/i420_rgb.c, this
- is macro is called CLIP. FIXME: Combine with that.
-*/
-#define clip_8_bit(v) \
- ((v < 0) ? 0 : (v > 255) ? 255 : v)
-
-/**
- Color conversion from
- http://www.inforamp.net/~poynton/notes/colour_and_gamma/ColorFAQ.html#RTFToC30
- http://people.ee.ethz.ch/~buc/brechbuehler/mirror/color/ColorFAQ.html
-
- Thanks to Billy Biggs <vektor@dumbterm.net> for the pointer and
- the following conversion.
-
- R' = [ 1.1644 0 1.5960 ] ([ Y' ] [ 16 ])
- G' = [ 1.1644 -0.3918 -0.8130 ] * ([ Cb ] - [ 128 ])
- B' = [ 1.1644 2.0172 0 ] ([ Cr ] [ 128 ])
-
- See also vlc/modules/video_chroma/i420_rgb.h and
- vlc/modules/video_chroma/i420_rgb_c.h for a way to do this in a way
- more optimized for integer arithmetic. Would be nice to merge the
- two routines.
-
-*/
-
-/**
- Convert a YUV pixel into an RGB pixel.
- */
-static inline void
-yuv2rgb(const ogt_yuvt_t *p_yuv, uint8_t *p_rgb_out )
-{
-
- int i_Y = p_yuv->s.y - 16;
- int i_Cb = p_yuv->s.v - 128;
- int i_Cr = p_yuv->s.u - 128;
-
- int i_red = (1.1644 * i_Y) + (1.5960 * i_Cr);
- int i_green = (1.1644 * i_Y) - (0.3918 * i_Cb) - (0.8130 * i_Cr);
- int i_blue = (1.1644 * i_Y) + (2.0172 * i_Cb);
-
- i_red = clip_8_bit( i_red );
- i_green = clip_8_bit( i_green );
- i_blue = clip_8_bit( i_blue );
-
-#ifdef WORDS_BIGENDIAN
- *p_rgb_out++ = i_red;
- *p_rgb_out++ = i_green;
- *p_rgb_out++ = i_blue;
-#else
- *p_rgb_out++ = i_blue;
- *p_rgb_out++ = i_green;
- *p_rgb_out++ = i_red;
-#endif
-
-}
-
-/* The byte storage of an RGB pixel. */
-#define RGB_SIZE 3
-
-#define GREEN_PIXEL 1
-#ifdef WORDS_BIGENDIAN
-#define RED_PIXEL 0
-#define BLUE_PIXEL 2
-#else
-#define RED_PIXEL 2
-#define BLUE_PIXEL 0
-#endif
-
-/**
- Store an RGB pixel into the location of p_pixel, taking into
- account the "Endian"-ness of the underlying machine.
-
- (N.B. Not sure if I've got this right or this is the right thing
- to do.)
- */
-static inline void
-put_rgb24_pixel(const uint8_t *rgb, /*out*/ uint8_t *p_pixel)
-{
-#ifdef WORDS_BIGENDIAN
- *p_pixel++;
-#endif
- *p_pixel++ = rgb[RED_PIXEL];
- *p_pixel++ = rgb[GREEN_PIXEL];
- *p_pixel++ = rgb[BLUE_PIXEL];
-}
-
-/**
- Find the nearest colormap entry in p_vout (assumed to have RGB2
- chroma, i.e. 256 RGB 8bpp entries) that is closest in color to p_rgb. Set
- out_rgb to the color found and return the colormap index.
- INVALID_CMAP_ENTRY is returned if there is some error.
-*/
-cmap_t
-find_cmap_rgb8_nearest(const vout_thread_t *p_vout, const uint8_t *p_rgb,
- /*out*/ uint8_t *out_rgb);
-
-/**
- Get the the rgb value for a given colormap entry for p_vout (which is'
- assumed to have RGB2 chroma).
-
- VLC_FALSE is returned if there was some error.
-*/
-vlc_bool_t
-query_color(const vout_thread_t *p_vout, cmap_t i_cmap,
- /*out*/ uint8_t *rgb);
-
-#endif /* PIXMAP_H */
-
-\f
-/*
- * Local variables:
- * c-file-style: "gnu"
- * tab-width: 8
- * indent-tabs-mode: nil
- * End:
- */
+++ /dev/null
-/*****************************************************************************
- * render.c : Philips OGT and CVD (VCD Subtitle) blending routines.
- * stuff from here might be pulled out, abstracted or used
- * by DVD subtitles.
- *****************************************************************************
- * Copyright (C) 2003, 2004 VideoLAN
- * $Id$
- *
- * Author: Rocky Bernstein <rocky@panix.com>
- * based on code from:
- * Sam Hocevar <sam@zoy.org>
- * Rudolf Cornelissen <rag.cornelissen@inter.nl.net>
- * Roine Gustafsson <roine@popstar.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
- *****************************************************************************/
-
-/*#define TESTING_TRANSPARENCY 1*/
-
-/*****************************************************************************
- * Preamble
- *****************************************************************************/
-#include <vlc/vlc.h>
-#include <vlc/vout.h>
-#include <vlc/decoder.h>
-
-#include "pixmap.h"
-#include "subtitle.h"
-#include "render.h"
-
-/* We use 4 bits for an transparency value: 0..15, 15 is completely
- transparent and 0 completely opaque. Note that although SVCD allow
- 8-bits, for these routines pixels should previously have been be
- scaled down to 4 bits (the range used by DVDs).
-*/
-#define TRANS_BITS (4)
-#define MAX_TRANS ((1<<TRANS_BITS) - 1)
-#define TRANS_SCALEDOWN (8-TRANS_BITS)
-
-/* We use a fixed-point arithmetic in scaling ratios so that we
- can use integer arithmetic and still get fairly precise
- results. ASCALE is a left shift amount.
-*/
-#define ASCALE 6 /* 2^6 = 32 */
-
-/* Horrible hack to get dbg_print to do the right thing */
-#define p_dec p_vout
-
-/**
- Take two 8-bit RGB values and a transparency and do a weighted
- average of them. The "weight" comes from i_trans which is in the
- range 0..MAX_TRANS. To have greater precision using integer
- arithmetic, the RGB values are scaled. The uint16_t cast below is
- to make sure we don't overflow the product in the multiplication
-
- (MAX_TRANS - i_trans) is the additive "inverse" of i_trans, i.e.
- i_trans + (MAX_TRANS - i_trans) = MAX_TRANS. So the resulting sum
- of rgb1*i_trans + rgb2*(MAX_TRANS-i_trans) will be scaled by
- MAX_TRANS. To reduce the value back down to 8 bits, we shift by
- TRANS_BITS, noting that 1 << TRANS_BITS is roughly
- MAX_TRANS. (Actually it is MAX_TRANS - 1).
-*/
-#define avg_8bit_rgb(rgb_vout, rgb_sub, i_trans) \
-{ \
- int i; \
- for (i=0; i < RGB_SIZE; i++) { \
- rgb_vout[i] = ( (uint16_t) rgb_vout[i]*(MAX_TRANS-i_trans) + \
- (uint16_t) rgb_sub [i]*i_trans ) >> TRANS_BITS; \
- } \
-}
-
-
-/*****************************************************************************
- * Local prototypes
- *****************************************************************************/
-static void BlendI420( vout_thread_t *, picture_t *, const subpicture_t *,
- vlc_bool_t );
-static void BlendYUY2( vout_thread_t *p_vout, picture_t *p_pic,
- const subpicture_t *p_spu, vlc_bool_t b_crop );
-static void BlendRV16( vout_thread_t *p_vout, picture_t *p_pic,
- const subpicture_t *p_spu, vlc_bool_t b_crop,
- vlc_bool_t b_15bpp );
-static void BlendRV24( vout_thread_t *p_vout, picture_t *p_pic,
- const subpicture_t *p_spu, vlc_bool_t b_crop );
-static void BlendRV32( vout_thread_t *p_vout, picture_t *p_pic,
- const subpicture_t *p_spu, vlc_bool_t b_crop );
-static void BlendRGB2( vout_thread_t *p_vout, picture_t *p_pic,
- const subpicture_t *p_spu, vlc_bool_t b_crop );
-
-/*****************************************************************************
- * BlendSPU: blend a subtitle into a picture
- *****************************************************************************
-
- This blends subtitles (a subpicture) into the underlying
- picture. Subtitle data has been preprocessed as YUV + transparancy
- or 4 bytes per pixel with interleaving of rows in the subtitle
- removed.
-
- *****************************************************************************/
-void VCDSubBlend( vout_thread_t *p_vout, picture_t *p_pic,
- const subpicture_t *p_spu )
-{
- struct subpicture_sys_t *p_sys = p_spu->p_sys;
-
- dbg_print( (DECODE_DBG_CALL|DECODE_DBG_RENDER),
- "chroma %x", p_vout->output.i_chroma );
-
- switch( p_vout->output.i_chroma )
- {
- /* I420 target, no scaling */
- case VLC_FOURCC('I','4','2','0'):
- case VLC_FOURCC('I','Y','U','V'):
- case VLC_FOURCC('Y','V','1','2'):
- BlendI420( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop );
- break;
-
- /* RGB 555 - scaled */
- case VLC_FOURCC('R','V','1','5'):
- BlendRV16( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop,
- VLC_TRUE );
- break;
-
- case VLC_FOURCC('R','V','1','6'):
- BlendRV16( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop,
- /* Not sure under what conditions RV16 is really
- RV16 and not RV15.
- */
-#if 0
- VLC_FALSE );
-#else
- VLC_TRUE );
-#endif
- break;
-
- /* RV24 target, scaling */
- case VLC_FOURCC('R','V','2','4'):
- BlendRV24( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop );
- break;
-
- /* RV32 target, scaling */
- case VLC_FOURCC('R','V','3','2'):
- BlendRV32( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop );
- break;
-
- /* NVidia overlay, no scaling */
- case VLC_FOURCC('Y','U','Y','2'):
- BlendYUY2( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop );
- break;
-
- /* Palettized 8 bits per pixel (256 colors). Each
- pixel is an uint8_t index in the palette
- Used in ASCII Art.
- */
- case VLC_FOURCC('R','G','B','2'):
- BlendRGB2( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop );
-
- break;
-
- default:
- msg_Err( p_vout, "unknown chroma, can't render SPU" );
- break;
- }
-}
-
-/* Following functions are local */
-
-/*
- YV12 format:
-
- All Y samples are found first in memory as an array of bytes
- (possibly with a larger stride for memory alignment), followed
- immediately by all Cr (=U) samples (with half the stride of the Y
- lines, and half the number of lines), then followed immediately by
- all Cb (=V) samples in a similar fashion.
-*/
-
-static void BlendI420( vout_thread_t *p_vout, picture_t *p_pic,
- const subpicture_t *p_spu, vlc_bool_t b_crop )
-{
- /* Common variables */
- uint8_t *p_pixel_base_Y, *p_pixel_base_V, *p_pixel_base_U;
- ogt_yuvt_t *p_source; /* This is the where the subtitle pixels come from */
-
- int i_x, i_y;
- vlc_bool_t even_scanline = VLC_FALSE;
-
- /* Crop-specific */
- int i_x_start, i_y_start, i_x_end, i_y_end;
- /* int i=0; */
-
- const struct subpicture_sys_t *p_sys = p_spu->p_sys;
-
- dbg_print( (DECODE_DBG_CALL|DECODE_DBG_RENDER),
- "spu width x height: (%dx%d), (x,y)=(%d,%d), yuv pitch (%d,%d,%d)",
- p_spu->i_width, p_spu->i_height, p_spu->i_x, p_spu->i_y,
- p_pic->Y_PITCH, p_pic->U_PITCH, p_pic->V_PITCH );
-
-
- p_pixel_base_Y = p_pic->p[Y_PLANE].p_pixels + p_spu->i_x
- + p_pic->p[Y_PLANE].i_pitch * p_spu->i_y;
-
- p_pixel_base_U = p_pic->p[U_PLANE].p_pixels + p_spu->i_x/2
- + p_pic->p[U_PLANE].i_pitch * p_spu->i_y/2;
-
- p_pixel_base_V = p_pic->p[V_PLANE].p_pixels + p_spu->i_x/2
- + p_pic->p[V_PLANE].i_pitch * p_spu->i_y/2;
-
- i_x_start = p_sys->i_x_start;
- i_y_start = p_pic->p[Y_PLANE].i_pitch * p_sys->i_y_start;
-
- i_x_end = p_sys->i_x_end;
- i_y_end = p_pic->p[Y_PLANE].i_pitch * p_sys->i_y_end;
-
- p_source = (ogt_yuvt_t *)p_sys->p_data;
-
- /* Draw until we reach the bottom of the subtitle */
- for( i_y = 0;
- i_y < p_spu->i_height * p_pic->p[Y_PLANE].i_pitch ;
- i_y += p_pic->p[Y_PLANE].i_pitch )
- {
- uint8_t *p_pixel_base_Y_y = p_pixel_base_Y + i_y;
- uint8_t *p_pixel_base_U_y = p_pixel_base_U + i_y/4;
- uint8_t *p_pixel_base_V_y = p_pixel_base_V + i_y/4;
-
- i_x = 0;
-
- if ( b_crop ) {
- if ( i_y > i_y_end ) break;
- if (i_x_start) {
- i_x = i_x_start;
- p_source += i_x_start;
- }
- }
-
- even_scanline = !even_scanline;
-
- /* Draw until we reach the end of the line */
- for( ; i_x < p_spu->i_width; i_x++, p_source++ )
- {
-
- if( b_crop ) {
-
- /* FIXME: y cropping should be dealt with outside of this loop.*/
- if ( i_y < i_y_start) continue;
-
- if ( i_x > i_x_end )
- {
- p_source += p_spu->i_width - i_x;
- break;
- }
- }
-
-#ifdef TESTING_TRANSPARENCY
- if (p_source->s.t == MAX_TRANS) p_source->s.t >>= 1;
-#endif
-
- switch( p_source->s.t )
- {
- case 0:
- /* Completely transparent. Don't change pixel. */
- break;
-
- case MAX_TRANS:
- {
- /* Completely opaque. Completely overwrite underlying
- pixel with subtitle pixel. */
-
- /* This is the location that's going to get changed.*/
- uint8_t *p_pixel_Y = p_pixel_base_Y_y + i_x;
-
- *p_pixel_Y = p_source->plane[Y_PLANE];
-
- if ( even_scanline && i_x % 2 == 0 ) {
- uint8_t *p_pixel_U = p_pixel_base_U_y + i_x/2;
- uint8_t *p_pixel_V = p_pixel_base_V_y + i_x/2;
- *p_pixel_U = p_source->plane[U_PLANE];
- *p_pixel_V = p_source->plane[V_PLANE];
- }
-
- break;
- }
-
- default:
- {
- /* Blend in underlying subtitle pixel. */
-
- /* This is the location that's going to get changed. */
- uint8_t *p_pixel_Y = p_pixel_base_Y_y + i_x;
-
-
- /* This is the weighted part of the subtitle. The
- color plane is 8 bits and transparancy is 4 bits so
- when multiplied we get up to 12 bits.
- */
- uint16_t i_sub_color_Y =
- (uint16_t) ( p_source->plane[Y_PLANE] *
- (uint16_t) (p_source->s.t) );
-
- /* This is the weighted part of the underlying pixel.
- For the same reasons above, the result is up to 12
- bits. However since the transparancies are
- inverses, the sum of i_sub_color and i_pixel_color
- will not exceed 12 bits.
- */
- uint16_t i_pixel_color_Y =
- (uint16_t) ( *p_pixel_Y *
- (uint16_t) (MAX_TRANS - p_source->s.t) ) ;
-
- /* Scale the 12-bit result back down to 8 bits. A
- precise scaling after adding the two components,
- would divide by one less than a power of 2. However
- to simplify and speed things we use a power of
- 2. This means the boundaries (either all
- transparent and all opaque) aren't handled properly.
- But we deal with them in special cases above. */
-
- *p_pixel_Y = ( i_sub_color_Y + i_pixel_color_Y ) >> TRANS_BITS;
-
- if ( even_scanline && i_x % 2 == 0 ) {
- uint8_t *p_pixel_U = p_pixel_base_U_y + i_x/2
- - p_pic->p[U_PLANE].i_pitch / 2;
- uint8_t *p_pixel_V = p_pixel_base_V_y + i_x/2
- - p_pic->p[V_PLANE].i_pitch / 2;
- uint16_t i_sub_color_U =
- (uint16_t) ( p_source->plane[U_PLANE] *
- (uint16_t) (p_source->s.t) );
-
- uint16_t i_sub_color_V =
- (uint16_t) ( p_source->plane[V_PLANE] *
- (uint16_t) (p_source->s.t) );
- uint16_t i_pixel_color_U =
- (uint16_t) ( *p_pixel_U *
- (uint16_t) (MAX_TRANS - p_source->s.t) ) ;
- uint16_t i_pixel_color_V =
- (uint16_t) ( *p_pixel_V *
- (uint16_t) (MAX_TRANS - p_source->s.t) ) ;
- *p_pixel_U = ( i_sub_color_U + i_pixel_color_U )>>TRANS_BITS;
- *p_pixel_V = ( i_sub_color_V + i_pixel_color_V )>>TRANS_BITS;
- }
- break;
- }
-
- }
- }
- }
-}
-
-/*
-
- YUY2 Format:
-
- Data is found in memory as an array of bytes in which the first byte
- contains the first sample of Y, the second byte contains the first
- sample of Cb (=U), the third byte contains the second sample of Y,
- the fourth byte contains the first sample of Cr (=V); and so
- on. Each 32-bit word then contains information for two contiguous
- horizontal pixels, two 8-bit Y values plus a single Cb and Cr which
- spans the two pixels.
-*/
-
-#define BYTES_PER_PIXEL 4
-
-static void BlendYUY2( vout_thread_t *p_vout, picture_t *p_pic,
- const subpicture_t *p_spu, vlc_bool_t b_crop )
-{
- /* Common variables */
- uint8_t *p_pixel_base;
-
- /* This is the where the subtitle pixels come from */
- ogt_yuvt_t *p_source = (ogt_yuvt_t *) p_spu->p_sys->p_data;
-
- ogt_yuvt_t *p_source_end = (ogt_yuvt_t *)p_spu->p_sys->p_data +
- (p_spu->i_width * p_spu->i_height);
-
- uint16_t i_x, i_y;
-
- /* Make sure we start on a word (4-byte) boundary. */
- uint16_t i_spu_x = (p_spu->i_x & 0xFFFE) * 2;
-
- /* Crop-specific */
- int i_x_start, i_y_start, i_x_end, i_y_end;
-
- const struct subpicture_sys_t *p_sys = p_spu->p_sys;
-
- dbg_print( (DECODE_DBG_CALL|DECODE_DBG_RENDER),
- "spu width x height: (%dx%d), (x,y)=(%d,%d), pitch: %d",
- p_spu->i_width, p_spu->i_height, p_spu->i_x, p_spu->i_y,
- p_pic->p->i_pitch );
-
-
- p_pixel_base = p_pic->p->p_pixels +
- + ( p_spu->i_y * p_pic->p->i_pitch ) + i_spu_x;
-
- i_x_start = p_sys->i_x_start;
- i_y_start = p_sys->i_y_start * p_pic->p->i_pitch;
-
- i_x_end = p_sys->i_x_end;
- i_y_end = p_sys->i_y_end * p_pic->p->i_pitch;
-
- /* Draw until we reach the bottom of the subtitle */
- for( i_y = 0;
- i_y < p_spu->i_height * p_pic->p[Y_PLANE].i_pitch ;
- i_y += p_pic->p[Y_PLANE].i_pitch )
- {
- uint8_t *p_pixel_base_y = p_pixel_base + i_y;
-
- i_x = 0;
-
- if ( b_crop ) {
- if ( i_y > i_y_end ) break;
- if (i_x_start) {
- i_x = i_x_start;
- p_source += (i_x_start*2);
- }
- }
-
-
- /* Draw until we reach the end of the line. Each output pixel
- is a combination of two source pixels.
- */
- for( i_x = 0; i_x < p_spu->i_width / 2; i_x++, p_source +=2 )
- {
- uint16_t i_avg_tr; /* transparancy sort of averaged over 2 pixels*/
-
- if (p_source > p_source_end-1) {
- msg_Err( p_vout, "Trying to access beyond subtitle x: %d y: %d",
- i_x, i_y);
- return;
- }
-
- if( b_crop ) {
-
- /* FIXME: y cropping should be dealt with outside of this loop.*/
- if ( i_y < i_y_start) continue;
-
- if ( i_x > i_x_end )
- {
- p_source += p_spu->i_width - (i_x*2);
- break;
- }
- }
-
-
- /* Favor opaque subtitle pixels. */
- if ( (p_source->s.t == 0) && (p_source+1)->s.t == MAX_TRANS )
- i_avg_tr = (p_source+1)->s.t;
- else if ( (p_source->s.t == MAX_TRANS) && (p_source+1)->s.t == 0 )
- i_avg_tr = p_source->s.t;
- else
- i_avg_tr = ( p_source->s.t + (p_source+1)->s.t ) / 2;
-
-#ifdef TESTING_TRANSPARENCY
- if (i_avg_tr == MAX_TRANS) i_avg_tr >>= 1;
-#endif
-
- switch( i_avg_tr )
- {
- case 0:
- /* Completely transparent. Don't change pixel. */
- break;
-
- case MAX_TRANS:
- {
- /* Completely opaque. Completely overwrite underlying
- pixel with subtitle pixel. */
-
- /* This is the location that's going to get changed. */
- uint8_t *p_pixel = p_pixel_base_y + i_x * BYTES_PER_PIXEL;
- uint8_t i_avg_u;
- uint8_t i_avg_v;
-
- /* Favor opaque subtitle pixel. */
- if (p_source->s.t == MAX_TRANS ) {
- i_avg_u = p_source->plane[U_PLANE] ;
- i_avg_v = p_source->plane[V_PLANE] ;
- } else if ( (p_source+1)->s.t == MAX_TRANS ) {
- i_avg_u = (p_source+1)->plane[U_PLANE] ;
- i_avg_v = (p_source+1)->plane[V_PLANE] ;
- } else {
- i_avg_u = ( p_source->plane[U_PLANE]
- + (p_source+1)->plane[U_PLANE] ) / 2;
- i_avg_v = ( p_source->plane[V_PLANE]
- + (p_source+1)->plane[V_PLANE] ) / 2;
- }
-
- /* draw a two contiguous pixels: 2 Y values, 1 U, and 1 V. */
- *p_pixel++ = p_source->plane[Y_PLANE] ;
- *p_pixel++ = i_avg_u;
- *p_pixel++ = (p_source+1)->plane[Y_PLANE] ;
- *p_pixel++ = i_avg_v;
-
- break;
- }
-
- default:
- {
- /* Blend in underlying subtitle pixels. */
-
- /* This is the location that's going to get changed. */
- uint8_t *p_pixel = p_pixel_base_y + i_x * BYTES_PER_PIXEL;
- uint8_t i_avg_u = ( p_source->plane[U_PLANE]
- + (p_source+1)->plane[U_PLANE] ) / 2;
- uint8_t i_avg_v = ( p_source->plane[V_PLANE]
- + (p_source+1)->plane[V_PLANE] ) / 2;
-
- /* This is the weighted part of the two subtitle
- pixels. The color plane is 8 bits and transparancy
- is 4 bits so when multiplied we get up to 12 bits.
- */
- uint16_t i_sub_color_Y1 =
- (uint16_t) ( p_source->plane[Y_PLANE] *
- (uint16_t) (p_source->s.t) );
-
- uint16_t i_sub_color_Y2 =
- (uint16_t) ( (p_source+1)->plane[Y_PLANE] *
- (uint16_t) ((p_source+1)->s.t) );
-
- /* This is the weighted part of the underlying pixels.
- For the same reasons above, the result is up to 12
- bits. However since the transparancies are
- inverses, the sum of i_sub_color and i_pixel_color
- will not exceed 12 bits.
- */
- uint16_t i_sub_color_U =
- (uint16_t) ( i_avg_u * (uint16_t) i_avg_tr );
-
- uint16_t i_sub_color_V =
- (uint16_t) ( i_avg_v * (uint16_t) i_avg_tr );
-
- uint16_t i_pixel_color_Y1 =
- (uint16_t) ( *(p_pixel) *
- (uint16_t) (MAX_TRANS - i_avg_tr) ) ;
- uint16_t i_pixel_color_Y2 =
- (uint16_t) ( *(p_pixel+2) *
- (uint16_t) (MAX_TRANS - i_avg_tr) ) ;
- uint16_t i_pixel_color_U =
- (uint16_t) ( *(p_pixel+1) *
- (uint16_t) (MAX_TRANS - i_avg_tr) ) ;
- uint16_t i_pixel_color_V =
- (uint16_t) ( *(p_pixel+3) *
- (uint16_t) (MAX_TRANS - i_avg_tr) ) ;
-
- /* draw a two contiguous pixels: 2 Y values, 1 U, and 1 V. */
-
- /* Scale the 12-bit result back down to 8 bits. A
- precise scaling after adding the two components,
- would divide by one less than a power of 2. However
- to simplify and speed things we use a power of
- 2. This means the boundaries (either all
- transparent and all opaque) aren't handled properly.
- But we deal with them in special cases above. */
-
- *p_pixel++ = ( i_sub_color_Y1 + i_pixel_color_Y1 )>>TRANS_BITS;
- *p_pixel++ = ( i_sub_color_U + i_pixel_color_U ) >>TRANS_BITS;
- *p_pixel++ = ( i_sub_color_Y2 + i_pixel_color_Y2 )>>TRANS_BITS;
- *p_pixel++ = ( i_sub_color_V + i_pixel_color_V ) >>TRANS_BITS;
- break;
- }
- }
- }
-
- /* For an odd width source, we'll just have to drop off a pixel. */
- if (p_spu->i_width % 2) p_source++;
- }
-}
-
-/**
- Convert a YUV pixel into a 16-bit RGB 5-5-5 pixel.
-
- A RGB 5-5-5 pixel looks like this:
- RGB 5-5-5 bit (MSB) 7 6 5 4 3 2 1 0 (LSB)
- p ? B4 B3 B2 B1 B0 R4 R3
- q R2 R1 R0 G4 G3 G2 G1 G0
-
-**/
-
-static inline void
-yuv2rgb555(ogt_yuvt_t *p_yuv, uint8_t *p_rgb1, uint8_t *p_rgb2 )
-{
-
- uint8_t rgb[RGB_SIZE];
-
- yuv2rgb(p_yuv, rgb);
-
- /* Scale RGB from 8 bits down to 5. */
- rgb[RED_PIXEL] >>= (8-5);
- rgb[GREEN_PIXEL] >>= (8-5);
- rgb[BLUE_PIXEL] >>= (8-5);
-
- *p_rgb1 = ( (rgb[BLUE_PIXEL] << 2)&0x7c ) | ( (rgb[RED_PIXEL]>>3) & 0x03 );
- *p_rgb2 = ( (rgb[RED_PIXEL] << 5)&0xe0 ) | ( rgb[GREEN_PIXEL]&0x1f );
-
-#if 0
- printf("Y,Cb,Cr,T=(%02x,%02x,%02x,%02x), r,g,b=(%d,%d,%d), "
- "rgb1: %02x, rgb2 %02x\n",
- p_yuv->s.y, p_yuv->s.u, p_yuv->s.v, p_yuv->s.t,
- rgb[RED_PIXEL], rgb[GREEN_PIXEL], rgb[BLUE_PIXEL],
- *p_rgb1, *p_rgb2);
-#endif
-
-}
-
-/**
- Convert a YUV pixel into a 16-bit RGB 5-6-5 pixel.
-
- A RGB 5-6-5 pixel looks like this:
- RGB 5-6-5 bit (MSB) 7 6 5 4 3 2 1 0 (LSB)
- p B4 B3 B2 B1 B0 R5 R4 R3
- q R2 R1 R0 G4 G3 G2 G1 G0
-
-**/
-
-static inline void
-yuv2rgb565(ogt_yuvt_t *p_yuv, uint8_t *p_rgb1, uint8_t *p_rgb2 )
-{
-
- uint8_t rgb[RGB_SIZE];
-
- yuv2rgb(p_yuv, rgb);
-
- /* Scale RGB from 8 bits down to 5 or 6 bits. */
- rgb[RED_PIXEL] >>= (8-6);
- rgb[GREEN_PIXEL] >>= (8-5);
- rgb[BLUE_PIXEL] >>= (8-5);
-
- *p_rgb1 = ( (rgb[BLUE_PIXEL] << 3)&0xF8 ) | ( (rgb[RED_PIXEL]>>3) & 0x07 );
- *p_rgb2 = ( (rgb[RED_PIXEL] << 5)&0xe0 ) | ( rgb[GREEN_PIXEL]&0x1f );
-
-#if 0
- printf("Y,Cb,Cr,T=(%02x,%02x,%02x,%02x), r,g,b=(%d,%d,%d), "
- "rgb1: %02x, rgb2 %02x\n",
- p_yuv->s.y, p_yuv->s.u, p_yuv->s.v, p_yuv->s.t,
- rgb[RED_PIXEL], rgb[GREEN_PIXEL], rgb[BLUE_PIXEL],
- *p_rgb1, *p_rgb2);
-#endif
-
-}
-
-static inline void
-rv16_pack_blend(uint8_t *p_pixel, ogt_yuvt_t *p_source, uint8_t *p_rgb1,
- uint8_t *p_rgb2, vlc_bool_t b_15bpp, uint8_t i_trans,
- int a_scale_down )
-{
- uint8_t rgb_sub[3];
- uint8_t rgb_vout[RGB_SIZE];
- int i;
-
- yuv2rgb(p_source, rgb_sub);
-
- /* Scale RGB from 8 bits down to 6 or 5. */
- rgb_sub[GREEN_PIXEL] >>= (8-5);
- rgb_sub[BLUE_PIXEL] >>= (8-5);
-
- rgb_vout[GREEN_PIXEL] = *(p_pixel+1) & 0x1f;
- if (b_15bpp) {
- rgb_sub[RED_PIXEL] >>= (8-5);
- rgb_vout[BLUE_PIXEL] = ((*p_pixel)>>2) & 0x1f;
- rgb_vout[RED_PIXEL] = ((*p_pixel & 0x03) << 3) | ((*(p_pixel+1)&0xe0)>>5);
- } else {
- rgb_sub[RED_PIXEL] >>= (8-6);
- rgb_vout[BLUE_PIXEL] = ((*p_pixel)>>3) & 0x1f;
- rgb_vout[RED_PIXEL] = ((*p_pixel & 0x07) << 3) | ((*(p_pixel+1)&0xe0)>>5);
- }
-
-
-#if 0
- printf("r,g,b=(%d,%d,%d), sub r,g,b=(%d,%d,%d), trans %d, inv_trans %d\n",
- rgb_vout[RED_PIXEL], rgb_vout[GREEN_PIXEL], rgb_vout[BLUE_PIXEL],
- rgb_sub[RED_PIXEL], rgb_sub[GREEN_PIXEL],
- rgb_sub[BLUE_PIXEL], i_trans, i_inv_trans);
-#endif
-
-#ifdef FIXED_RV16_TRANSPARENCY
- avg_8bit_rgb(rgb_vout, rgb_sub, i_trans);
-#else
- for (i=0; i < RGB_SIZE; i++) {
- /* For now the Best we can do is fade the color. Picking up
- video underneath doesn't work. */
- /* rgb_vout[i] = ( (uint16_t) rgb_vout[i]*i_inv_trans ) >> TRANS_BITS; */
- rgb_vout[i] = ( (uint16_t) rgb_sub[i]*i_trans ) >> TRANS_BITS;
-#endif
- }
-
-
-#if 0
- printf("avg r,g,b=(%d,%d,%d)\n",
- rgb_vout[RED_PIXEL], rgb_vout[GREEN_PIXEL], rgb_vout[BLUE_PIXEL] );
-#endif
-
-#if 0
- if (b_15bpp) {
- *p_rgb1 = ( (rgb_vout[BLUE_PIXEL] << 2)&0x7c )|( (rgb_vout[RED_PIXEL]>>3)&0x03 );
- } else {
- *p_rgb1 = ( (rgb_vout[BLUE_PIXEL] << 3)&0xF8 )|( (rgb_vout[RED_PIXEL]>>3)&0x07 );
- }
- *p_rgb2 = ( (rgb_vout[RED_PIXEL] << 5)&0xe0 ) | ( rgb_vout[GREEN_PIXEL]&0x1f );
-#else
- *p_rgb1 = (*p_rgb1)+1;
- *p_rgb2 = (*p_rgb2)+1;
-#endif
-
-}
-
-#undef BYTES_PER_PIXEL
-#define BYTES_PER_PIXEL 2
-
-static void
-BlendRV16( vout_thread_t *p_vout, picture_t *p_pic,
- const subpicture_t *p_spu, vlc_bool_t b_crop,
- vlc_bool_t b_15bpp )
-{
- /* Common variables */
- uint8_t *p_pixel_base;
- ogt_yuvt_t *p_src_start = (ogt_yuvt_t *)p_spu->p_sys->p_data;
- ogt_yuvt_t *p_src_end = &p_src_start[p_spu->i_height * p_spu->i_width];
- ogt_yuvt_t *p_source;
-
- int i_x, i_y;
- int i_y_src;
-
- /* Chroma specific */
- uint32_t i_xscale; /* Amount we scale subtitle in the x direction,
- multiplied by 2**ASCALE. */
- uint32_t i_yscale; /* Amount we scale subtitle in the y direction.
- multiplied by 2**ASCALE. */
-
- int i_width, i_height, i_ytmp, i_ynext;
-
- /* Crop-specific */
- int i_x_start, i_y_start, i_x_end, i_y_end;
-
- struct subpicture_sys_t *p_sys = p_spu->p_sys;
-
- i_xscale = ( p_vout->output.i_width << ASCALE ) / p_vout->render.i_width;
- i_yscale = ( p_vout->output.i_height << ASCALE ) / p_vout->render.i_height;
-
- dbg_print( (DECODE_DBG_CALL|DECODE_DBG_RENDER),
- "spu: %dx%d, scaled: %dx%d, vout render: %dx%d, scale %dx%d",
- p_spu->i_width, p_spu->i_height,
- p_vout->output.i_width, p_vout->output.i_height,
- p_vout->render.i_width, p_vout->render.i_height,
- i_xscale, i_yscale
- );
-
- i_width = p_spu->i_width * i_xscale;
- i_height = p_spu->i_height * i_yscale;
-
- /* Set where we will start blending subtitle from using
- the picture coordinates subtitle offsets
- */
- p_pixel_base = p_pic->p->p_pixels
- + ( (p_spu->i_x * i_xscale) >> ASCALE ) * BYTES_PER_PIXEL
- + ( (p_spu->i_y * i_yscale) >> ASCALE ) * p_pic->p->i_pitch;
-
- i_x_start = p_sys->i_x_start;
- i_y_start = i_yscale * p_sys->i_y_start;
- i_x_end = p_sys->i_x_end;
- i_y_end = i_yscale * p_sys->i_y_end;
-
- p_source = (ogt_yuvt_t *)p_sys->p_data;
-
- /* Draw until we reach the bottom of the subtitle */
- i_y = 0;
- for( i_y_src = 0 ; i_y_src < p_spu->i_height * p_spu->i_width;
- i_y_src += p_spu->i_width )
- {
- uint8_t *p_pixel_base_y;
- i_ytmp = i_y >> ASCALE;
- i_y += i_yscale;
- p_pixel_base_y = p_pixel_base + (i_ytmp * p_pic->p->i_pitch);
- i_x = 0;
-
- if ( b_crop ) {
- if ( i_y > i_y_end ) break;
- if (i_x_start) {
- i_x = i_x_start;
- p_source += i_x_start;
- }
- }
-
- /* Check whether we need to draw one line or more than one */
- if( i_ytmp + 1 >= ( i_y >> ASCALE ) )
- {
- /* Draw until we reach the end of the line */
- for( ; i_x < p_spu->i_width; i_x++, p_source++ )
- {
-
-#if 0
- uint8_t *p=(uint8_t *) p_source;
- printf("+++ %02x %02x %02x %02x\n",
- p[0], p[1], p[2], p[3]);
-#endif
-
- if( b_crop ) {
-
- /* FIXME: y cropping should be dealt with outside of this
- loop.*/
- if ( i_y < i_y_start) continue;
-
- if ( i_x > i_x_end )
- {
- p_source += p_spu->i_width - i_x;
- break;
- }
- }
-
- if (p_source >= p_src_end) {
- msg_Err( p_vout, "Trying to access beyond subtitle %dx%d %d",
- i_x, i_y / i_yscale, i_height);
- return;
- }
-
-#ifdef TESTING_TRANSPARENCY
- if (p_source->s.t == MAX_TRANS) p_source->s.t >>= 1;
-#endif
-
- switch( p_source->s.t )
- {
- case 0:
- /* Completely transparent. Don't change pixel. */
- break;
-
- case MAX_TRANS:
- {
- /* Completely opaque. Completely overwrite underlying
- pixel with subtitle pixel. */
-
- uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
- * BYTES_PER_PIXEL );
- uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
- * BYTES_PER_PIXEL );
- uint32_t len = i_xlast - i_xdest;
-
- uint8_t i_rgb1;
- uint8_t i_rgb2;
-
- /* This is the location that's going to get changed. */
- uint8_t *p_dest = p_pixel_base_y + i_x * BYTES_PER_PIXEL;
-
- if (b_15bpp)
- yuv2rgb555(p_source, &i_rgb1, &i_rgb2);
- else
- yuv2rgb565(p_source, &i_rgb1, &i_rgb2);
-
- for ( len = i_xlast - i_xdest; len ; len--) {
- *p_dest++ = i_rgb1;
- *p_dest++ = i_rgb2;
- }
- break;
- }
-
- default:
- {
- /* Blend in underlying pixel subtitle pixel. */
-
- uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
- * BYTES_PER_PIXEL );
- uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
- * BYTES_PER_PIXEL );
- uint8_t i_rgb1;
- uint8_t i_rgb2;
- uint32_t len = i_xlast - i_xdest;
-
- /* This is the location that's going to get changed. */
- uint8_t *p_dest = p_pixel_base_y + i_x * BYTES_PER_PIXEL;
-
- for ( len = i_xlast - i_xdest; len ; len--) {
- rv16_pack_blend(p_dest, p_source, &i_rgb1, &i_rgb2,
- b_15bpp, p_source->s.t, TRANS_SCALEDOWN);
- *p_dest++ = i_rgb1;
- *p_dest++ = i_rgb2;
- }
- break;
- }
- }
- }
- }
- else
- {
- i_ynext = p_pic->p->i_pitch * i_y >> ASCALE;
-
-
- /* Draw until we reach the end of the line */
- for( ; i_x < p_spu->i_width; i_x++, p_source++ )
- {
-
- if( b_crop ) {
-
- /* FIXME: y cropping should be dealt with outside of this
- loop.*/
- if ( i_y < i_y_start) continue;
-
- if ( i_x > i_x_end )
- {
- p_source += p_spu->i_width - i_x;
- break;
- }
- }
-
- if (p_source >= p_src_end) {
- msg_Err( p_vout, "trying to access beyond subtitle %dx%d %d",
- i_x, i_y / i_yscale, i_height);
- return;
- }
-
- switch( p_source->s.t )
- {
- case 0:
- /* Completely transparent. Don't change pixel. */
- break;
-
- case MAX_TRANS:
- {
- /* Completely opaque. Completely overwrite underlying
- pixel with subtitle pixel. */
-
- uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
- * BYTES_PER_PIXEL );
- uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
- * BYTES_PER_PIXEL );
- uint32_t len = i_xlast - i_xdest;
-
- uint8_t *p_pixel_base_x = p_pixel_base + i_xdest;
-
- for( ; i_ytmp < i_ynext ; i_ytmp += p_pic->p->i_pitch )
- {
- /* This is the location that's going to get changed. */
- uint8_t *p_dest = p_pixel_base_x + i_ytmp;
- uint8_t i_rgb1, i_rgb2;
- if (b_15bpp)
- yuv2rgb555(p_source, &i_rgb1, &i_rgb2);
- else
- yuv2rgb565(p_source, &i_rgb1, &i_rgb2);
-
- for ( len = i_xlast - i_xdest; len ; len--) {
- *p_dest++ = i_rgb1;
- *p_dest++ = i_rgb2;
- }
- }
- break;
- }
- default:
- {
- uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
- * BYTES_PER_PIXEL );
- uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
- * BYTES_PER_PIXEL );
- uint32_t len = i_xlast - i_xdest;
- uint8_t i_rgb1, i_rgb2;
- for( ; i_ytmp < i_ynext ; i_ytmp += p_pic->p->i_pitch )
- {
- /* Blend in underlying pixel subtitle pixel. */
- uint8_t *p_dest = p_pixel_base + i_ytmp;
- for ( len = i_xlast - i_xdest; len ; len--) {
- rv16_pack_blend(p_dest, p_source, &i_rgb1, &i_rgb2,
- b_15bpp, p_source->s.t, TRANS_SCALEDOWN);
- *p_dest++ = i_rgb1;
- *p_dest++ = i_rgb2;
- }
- }
- break;
- }
- }
- }
- }
- }
-}
-
-#undef BYTES_PER_PIXEL
-#define BYTES_PER_PIXEL 4
-
-static inline void
-rv24_pack_blend(uint8_t *rgb_vout, const uint8_t *rgb_sub, uint8_t i_trans,
- int a_scale_down )
-{
-
-#if 0
- printf("r,g,b=(%d,%d,%d), source r,g,b=(%d,%d,%d), trans %d\n",
- rgb_vout[RED_PIXEL], rgb_vout[GREEN_PIXEL], rgb_vout[BLUE_PIXEL],
- rgb_sub[RED_PIXEL], rgb_sub[GREEN_PIXEL],
- rgb_sub[BLUE_PIXEL], i_trans);
-#endif
-
-#ifdef WORDS_BIGENDIAN
- *rgb_vout++;
-#endif
-
- avg_8bit_rgb(rgb_vout, rgb_sub, i_trans);
-
-#if 0
- printf("avg r,g,b=(%d,%d,%d)\n",
- rgb_vout[RED_PIXEL], rgb_vout[GREEN_PIXEL], rgb_vout[BLUE_PIXEL] );
-#endif
-
-}
-
-/*
- RV24 format??? Is this just for X11? Or just not for Win32? Is this
- the same as RV32?
-
- a pixel is represented by 3 bytes containing a red,
- blue and green sample with blue stored at the lowest address, green
- next then red. One padding byte is added between pixels. Although
- this may not be part of a spec, images should be stored with each
- line padded to a u_int32 boundary.
-*/
-static void
-BlendRV24( vout_thread_t *p_vout, picture_t *p_pic,
- const subpicture_t *p_spu, vlc_bool_t b_crop )
-{
- /* Common variables */
- uint8_t *p_pixel_base;
- ogt_yuvt_t *p_src_start = (ogt_yuvt_t *)p_spu->p_sys->p_data;
- ogt_yuvt_t *p_src_end = &p_src_start[p_spu->i_height * p_spu->i_width];
- ogt_yuvt_t *p_source; /* This is the where the subtitle pixels come from */
-
- int i_x, i_y;
- int i_y_src;
-
- /* Make sure we start on a word (4-byte) boundary. */
- uint32_t i_spu_x;
-
- /* Chroma specific */
- uint32_t i_xscale; /* Amount we scale subtitle in the x direction,
- multiplied by 2**ASCALE. */
- uint32_t i_yscale; /* Amount we scale subtitle in the y direction.
- multiplied by 2**ASCALE. */
-
- int i_width, i_height, i_ytmp, i_ynext;
-
- /* Crop-specific */
- int32_t i_x_start, i_y_start, i_x_end, i_y_end;
-
- struct subpicture_sys_t *p_sys = p_spu->p_sys;
- int i_aspect_x, i_aspect_y;
-
- vlc_reduce( &i_aspect_x, &i_aspect_y, p_vout->render.i_aspect,
- VOUT_ASPECT_FACTOR, 0 );
-
- i_xscale = (( p_vout->output.i_width << ASCALE ) * i_aspect_x)
- / (i_aspect_y * p_vout->render.i_width);
- i_yscale = ( p_vout->output.i_height << ASCALE ) / p_vout->render.i_height;
-
- dbg_print( (DECODE_DBG_CALL|DECODE_DBG_RENDER),
- "spu: %dx%d, scaled: %dx%d, vout render: %dx%d, scale %dx%d",
- p_spu->i_width, p_spu->i_height,
- p_vout->output.i_width, p_vout->output.i_height,
- p_vout->render.i_width, p_vout->render.i_height,
- i_xscale, i_yscale
- );
-
- i_width = p_spu->i_width * i_xscale;
- i_height = p_spu->i_height * i_yscale;
-
- /* Set where we will start blending subtitle from using
- the picture coordinates subtitle offsets.
- */
- i_spu_x = ((p_spu->i_x * i_xscale) >> ASCALE) * BYTES_PER_PIXEL;
-
- p_pixel_base = p_pic->p->p_pixels + i_spu_x
- + ( (p_spu->i_y * i_yscale) >> ASCALE ) * p_pic->p->i_pitch;
-
- i_x_start = p_sys->i_x_start;
- i_y_start = i_yscale * p_sys->i_y_start;
- i_x_end = p_sys->i_x_end;
- i_y_end = i_yscale * p_sys->i_y_end;
-
- p_source = (ogt_yuvt_t *)p_sys->p_data;
-
- /* Draw until we reach the bottom of the subtitle */
- i_y = 0;
- for( i_y_src = 0 ; i_y_src < p_spu->i_height * p_spu->i_width;
- i_y_src += p_spu->i_width )
- {
- uint8_t *p_pixel_base_y;
- i_ytmp = i_y >> ASCALE;
- i_y += i_yscale;
- p_pixel_base_y = p_pixel_base + (i_ytmp * p_pic->p->i_pitch);
- i_x = 0;
-
- if ( b_crop ) {
- if ( i_y > i_y_end ) break;
- if (i_x_start) {
- i_x = i_x_start;
- p_source += i_x_start;
- }
- }
-
- /* Check whether we need to draw one line or more than one */
- if( i_ytmp + 1 >= ( i_y >> ASCALE ) )
- {
- /* Draw until we reach the end of the line */
- for( ; i_x < p_spu->i_width; i_x++, p_source++ )
- {
-
- if( b_crop ) {
-
- /* FIXME: y cropping should be dealt with outside of this
- loop.*/
- if ( i_y < i_y_start) continue;
-
- if ( i_x > i_x_end )
- {
- p_source += p_spu->i_width - i_x;
- break;
- }
- }
-
- if (p_source >= p_src_end) {
- msg_Err( p_vout, "trying to access beyond subtitle %dx%d %d",
- i_x, i_y / i_yscale, i_height);
- return;
- }
-
-#ifdef TESTING_TRANSPARENCY
- if (p_source->s.t == MAX_TRANS) p_source->s.t >>= 2;
-#endif
-
- switch( p_source->s.t )
- {
- case 0:
- /* Completely transparent. Don't change pixel. */
- break;
-
- case MAX_TRANS:
- {
- /* Completely opaque. Completely overwrite underlying
- pixel with subtitle pixel. */
-
- uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
- * BYTES_PER_PIXEL );
- uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
- * BYTES_PER_PIXEL );
- uint32_t len = i_xlast - i_xdest;
-
- uint8_t rgb[RGB_SIZE];
-
- /* This is the location that's going to get changed. */
- uint8_t *p_dest = p_pixel_base_y + i_xdest;
-
- yuv2rgb(p_source, rgb);
-
- for ( len = i_xlast - i_xdest; len ; len--) {
- put_rgb24_pixel(rgb, p_dest);
- p_dest += BYTES_PER_PIXEL;
- }
-
- default:
- {
- /* Blend in underlying pixel subtitle pixel. */
-
- uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
- * BYTES_PER_PIXEL );
- uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
- * BYTES_PER_PIXEL );
- uint32_t len = i_xlast - i_xdest * BYTES_PER_PIXEL;
-
- /* To be able to scale correctly for full
- opaqueness, we add 1 to the transparency.
- This means transparency value 0 won't be
- completely transparent which is not correct.
- But that's handled in a special case above
- anyway. */
-
- /* This is the location that's going to get changed. */
- uint8_t *p_dest = p_pixel_base_y + i_xdest;
- uint8_t rgb[RGB_SIZE];
-
- yuv2rgb(p_source, rgb);
-
- for ( len = i_xlast - i_xdest; len ; len--) {
- rv24_pack_blend(p_dest, rgb, p_source->s.t,
- TRANS_SCALEDOWN);
- p_dest += BYTES_PER_PIXEL;
- }
- break;
- }
- }
- }
- }
- }
- else
- {
- i_ynext = p_pic->p->i_pitch * i_y >> ASCALE;
-
-
- /* Draw until we reach the end of the line */
- for( ; i_x < p_spu->i_width; i_x++, p_source++ )
- {
-
- if( b_crop ) {
-
- /* FIXME: y cropping should be dealt with outside of this
- loop.*/
- if ( i_y < i_y_start) continue;
-
- if ( i_x > i_x_end )
- {
- p_source += p_spu->i_width - i_x;
- break;
- }
- }
-
- if (p_source >= p_src_end) {
- msg_Err( p_vout, "trying to access beyond subtitle %dx%d %d",
- i_x, i_y / i_yscale, i_height);
- return;
- }
-
- switch( p_source->s.t )
- {
- case 0:
- /* Completely transparent. Don't change pixel. */
- break;
-
- case MAX_TRANS:
- {
- /* Completely opaque. Completely overwrite underlying
- pixel with subtitle pixel. */
-
- /* This is the location that's going to get changed. */
- uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
- * BYTES_PER_PIXEL );
- uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
- * BYTES_PER_PIXEL );
- uint32_t len = i_xlast - i_xdest;
-
- uint8_t rgb[RGB_SIZE];
-
- yuv2rgb(p_source, rgb);
-
- for( ; i_ytmp < i_ynext ; i_ytmp += p_pic->p->i_pitch )
- {
- /* Completely opaque. Completely overwrite underlying
- pixel with subtitle pixel. */
-
- /* This is the location that's going to get changed. */
- uint8_t *p_dest = p_pixel_base + i_ytmp + i_xdest;
-
- for ( len = i_xlast - i_xdest; len ; len--) {
- put_rgb24_pixel(rgb, p_dest);
- p_dest += BYTES_PER_PIXEL;
- }
- }
- break;
- }
- default:
- {
-
-
- uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
- * BYTES_PER_PIXEL );
- uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
- * BYTES_PER_PIXEL );
- uint32_t len = i_xlast - i_xdest;
- uint8_t rgb[RGB_SIZE];
-
- yuv2rgb(p_source, rgb);
-
- for( ; i_ytmp < i_ynext ; i_ytmp += p_pic->p->i_pitch )
- {
- /* Blend in underlying pixel subtitle pixel. */
-
- /* This is the location that's going to get changed. */
- uint8_t *p_dest = p_pixel_base + i_ytmp + i_xdest;
-
- /* To be able to scale correctly for full opaqueness, we
- add 1 to the alpha. This means alpha value 0 won't
- be completely transparent and is not correct, but
- that's handled in a special case above anyway. */
-
- for ( len = i_xlast - i_xdest; len ; len--) {
- rv24_pack_blend(p_dest, rgb, p_source->s.t,
- TRANS_SCALEDOWN);
- p_dest += BYTES_PER_PIXEL;
- }
- }
- break;
- }
- }
- }
- }
- }
-}
-
-#undef BYTES_PER_PIXEL
-#define BYTES_PER_PIXEL 4
-
-/*
- RV32 format??? Is this just for X11? Or just not for Win32? Is this
- the same as RV24?
-
- RV32 format: a pixel is represented by 4 bytes containing a red,
- blue and green sample with blue stored at the lowest address, green
- next then red. One padding byte is added between pixels. Although
- this may not be part of a spec, images should be stored with each
- line padded to a u_int32 boundary.
-*/
-static void
-BlendRV32( vout_thread_t *p_vout, picture_t *p_pic,
- const subpicture_t *p_spu, vlc_bool_t b_crop )
-{
- /* Common variables */
- uint8_t *p_pixel_base;
- ogt_yuvt_t *p_src_start = (ogt_yuvt_t *)p_spu->p_sys->p_data;
- ogt_yuvt_t *p_src_end = &p_src_start[p_spu->i_height * p_spu->i_width];
- ogt_yuvt_t *p_source; /* This is the where the subtitle pixels come from */
-
- int i_x, i_y;
- int i_y_src;
-
- /* Make sure we start on a word (4-byte) boundary. */
- uint32_t i_spu_x;
-
- /* Chroma specific */
- uint32_t i_xscale; /* Amount we scale subtitle in the x direction,
- multiplied by 2**ASCALE. */
- uint32_t i_yscale; /* Amount we scale subtitle in the y direction.
- multiplied by 2**ASCALE. */
-
- int i_width, i_height, i_ytmp, i_ynext;
-
- /* Crop-specific */
- int32_t i_x_start, i_y_start, i_x_end, i_y_end;
-
- struct subpicture_sys_t *p_sys = p_spu->p_sys;
- int i_aspect_x, i_aspect_y;
-
- vlc_reduce( &i_aspect_x, &i_aspect_y, p_vout->render.i_aspect,
- VOUT_ASPECT_FACTOR, 0 );
-
- i_xscale = (( p_vout->output.i_width << ASCALE ) * i_aspect_x)
- / (i_aspect_y * p_vout->render.i_width);
- i_yscale = ( p_vout->output.i_height << ASCALE ) / p_vout->render.i_height;
-
- dbg_print( (DECODE_DBG_CALL|DECODE_DBG_RENDER),
- "spu: %dx%d, scaled: %dx%d, vout render: %dx%d, scale %dx%d",
- p_spu->i_width, p_spu->i_height,
- p_vout->output.i_width, p_vout->output.i_height,
- p_vout->render.i_width, p_vout->render.i_height,
- i_xscale, i_yscale
- );
-
- i_width = p_spu->i_width * i_xscale;
- i_height = p_spu->i_height * i_yscale;
-
- /* Set where we will start blending subtitle from using
- the picture coordinates subtitle offsets.
- */
- i_spu_x = ((p_spu->i_x * i_xscale) >> ASCALE) * BYTES_PER_PIXEL;
-
- p_pixel_base = p_pic->p->p_pixels + i_spu_x
- + ( (p_spu->i_y * i_yscale) >> ASCALE ) * p_pic->p->i_pitch;
-
- i_x_start = p_sys->i_x_start;
- i_y_start = i_yscale * p_sys->i_y_start;
- i_x_end = p_sys->i_x_end;
- i_y_end = i_yscale * p_sys->i_y_end;
-
- p_source = (ogt_yuvt_t *)p_sys->p_data;
-
- /* Draw until we reach the bottom of the subtitle */
- i_y = 0;
- for( i_y_src = 0 ; i_y_src < p_spu->i_height * p_spu->i_width;
- i_y_src += p_spu->i_width )
- {
- uint8_t *p_pixel_base_y;
- i_ytmp = i_y >> ASCALE;
- i_y += i_yscale;
- p_pixel_base_y = p_pixel_base + (i_ytmp * p_pic->p->i_pitch);
- i_x = 0;
-
- if ( b_crop ) {
- if ( i_y > i_y_end ) break;
- if (i_x_start) {
- i_x = i_x_start;
- p_source += i_x_start;
- }
- }
-
- /* Check whether we need to draw one line or more than one */
- if( i_ytmp + 1 >= ( i_y >> ASCALE ) )
- {
- /* Draw until we reach the end of the line */
- for( ; i_x < p_spu->i_width; i_x++, p_source++ )
- {
-
- if( b_crop ) {
-
- /* FIXME: y cropping should be dealt with outside of this
- loop.*/
- if ( i_y < i_y_start) continue;
-
- if ( i_x > i_x_end )
- {
- p_source += p_spu->i_width - i_x;
- break;
- }
- }
-
- if (p_source >= p_src_end) {
- msg_Err( p_vout, "trying to access beyond subtitle %dx%d %d",
- i_x, i_y / i_yscale, i_height);
- return;
- }
-
- switch( p_source->s.t )
- {
- case 0:
- /* Completely transparent. Don't change pixel. */
- break;
-
- default:
- case MAX_TRANS:
- {
- /* Completely opaque. Completely overwrite underlying
- pixel with subtitle pixel. */
-
- uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
- * BYTES_PER_PIXEL );
- uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
- * BYTES_PER_PIXEL );
- uint32_t len = i_xlast - i_xdest;
-
- uint8_t rgb[RGB_SIZE];
-
- /* This is the location that's going to get changed. */
- uint8_t *p_dest = p_pixel_base_y + i_xdest;
-
- yuv2rgb(p_source, rgb);
-
- for ( len = i_xlast - i_xdest; len ; len--) {
- *p_dest++ = rgb[BLUE_PIXEL];
- *p_dest++ = rgb[GREEN_PIXEL];
- *p_dest++ = rgb[RED_PIXEL];
- *p_dest++;
- }
-
-#ifdef TRANSPARENCY_FINISHED
- default:
- {
- /* Blend in underlying pixel subtitle pixel. */
-
- uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
- * BYTES_PER_PIXEL );
- uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
- * BYTES_PER_PIXEL );
- uint32_t len = i_xlast - i_xdest;
-
- /* To be able to scale correctly for full opaqueness, we
- add 1 to the alpha. This means alpha value 0 won't
- be completely transparent and is not correct, but
- that's handled in a special case above anyway. */
-
- uint8_t i_destalpha = MAX_TRANS - p_source->s.t;
- uint8_t rgb[RGB_SIZE];
-
- /* This is the location that's going to get changed. */
- uint8_t *p_dest = p_pixel_base_y + i_xdest;
-
- yuv2rgb(p_source, rgb);
- rv32_pack_blend(p_dest, rgb, dest_alpha,
- TRANS_SCALEDOWN);
-
- for ( len = i_xlast - i_xdest; len ; len--) {
- *p_dest++ = rgb[BLUE_PIXEL];
- *p_dest++ = rgb[GREEN_PIXEL];
- *p_dest++ = rgb[RED_PIXEL];
- *p_dest++;
- }
- break;
- }
-#endif /*TRANSPARENCY_FINISHED*/
- }
- }
- }
- }
- else
- {
- i_ynext = p_pic->p->i_pitch * i_y >> ASCALE;
-
-
- /* Draw until we reach the end of the line */
- for( ; i_x < p_spu->i_width; i_x++, p_source++ )
- {
-
- if( b_crop ) {
-
- /* FIXME: y cropping should be dealt with outside of this
- loop.*/
- if ( i_y < i_y_start) continue;
-
- if ( i_x > i_x_end )
- {
- p_source += p_spu->i_width - i_x;
- break;
- }
- }
-
- if (p_source >= p_src_end) {
- msg_Err( p_vout, "Trying to access beyond subtitle %dx%d %d",
- i_x, i_y / i_yscale, i_height);
- return;
- }
-
- switch( p_source->s.t )
- {
- case 0:
- /* Completely transparent. Don't change pixel. */
- break;
-
- default:
- case MAX_TRANS:
- {
- /* Completely opaque. Completely overwrite underlying
- pixel with subtitle pixel. */
-
- /* This is the location that's going to get changed. */
- uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
- * BYTES_PER_PIXEL );
- uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
- * BYTES_PER_PIXEL );
- uint32_t len = i_xlast - i_xdest;
-
- uint8_t rgb[RGB_SIZE];
-
- yuv2rgb(p_source, rgb);
-
- for( ; i_ytmp < i_ynext ; i_ytmp += p_pic->p->i_pitch )
- {
- /* Completely opaque. Completely overwrite underlying
- pixel with subtitle pixel. */
-
- /* This is the location that's going to get changed. */
- uint8_t *p_dest = p_pixel_base + i_ytmp + i_xdest;
-
- for ( len = i_xlast - i_xdest; len ; len--) {
- put_rgb24_pixel(rgb, p_dest);
- }
- }
- break;
- }
-#ifdef TRANSPARENCY_FINISHED
- default:
- {
-
-
- uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
- * BYTES_PER_PIXEL );
- uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
- * BYTES_PER_PIXEL );
- uint32_t len = i_xlast - i_xdest;
- uint8_t rgb[RGB_SIZE];
-
- yuv2rgb(p_source, rgb);
-
- for( ; i_ytmp < i_ynext ; y_ytmp += p_pic->p->i_pitch )
- {
- /* Blend in underlying pixel subtitle pixel. */
-
- /* This is the location that's going to get changed. */
- uint8_t *p_dest = p_pixel_base + i_ytmp + i_xdest;
-
- /* To be able to scale correctly for full opaqueness, we
- add 1 to the alpha. This means alpha value 0 won't
- be completely transparent and is not correct, but
- that's handled in a special case above anyway. */
-
- uint8_t i_destalpha = MAX_TRANS - p_source->s.t;
- rv32_pack_blend(p_dest, rgb, dest_alpha,
- TRANS_SCALEDOWN);
- }
- break;
-#endif /*TRANSPARENCY_FINISHED*/
- }
- }
- }
- }
-}
-
-/* 4-entry array of colormap indices */
-static uint8_t cmap[NUM_SUBTITLE_COLORS];
-
-/* Actual RGB values for above; this is used in blending.*/
-static uint8_t cmap_rgb[NUM_SUBTITLE_COLORS][RGB_SIZE];
-
-/*
- Return the colormap index for the average of i_pixel and a subtitle
- pixel whose subtitle palette entry is i_cmap.
- */
-static inline cmap_t
-avg_rgb2(const vout_thread_t *p_vout, uint8_t i_pixel, uint8_t i_trans,
- int i_cmap, mtime_t i_pts)
-{
- uint8_t rgb_vout[RGB_SIZE];
-
- /* Cache the average of a vout colormap entry and a subtitle palette
- entry. There are not too many of these 256*4 = 1024.
- */
- static cmap_t avg_cache[CMAP_RGB2_SIZE][NUM_SUBTITLE_COLORS];
-
- /* subtitle palettes might change between two subtitles. i_last_pts
- will be used to figure out if the subtitle has changed, and
- we have to invalidate the cache. */
- static mtime_t i_last_pts = -1;
-
- if (i_pts != i_last_pts)
- {
- /* Hack: We rely on the fact that INVALID_CMAP_ENTRY is repeated
- 0xFF.
- */
- memset(avg_cache, 0xFF, sizeof(avg_cache));
- i_last_pts = i_pts;
- }
-
- if ( avg_cache[i_pixel][i_cmap] != INVALID_CMAP_ENTRY )
- return avg_cache[i_pixel][i_cmap];
-
- if ( !query_color(p_vout, i_pixel, rgb_vout) ) return INVALID_CMAP_ENTRY;
-
- avg_8bit_rgb(rgb_vout, cmap_rgb[i_cmap], i_trans);
-
-#if 0
- {
- uint8_t rgb_approx[RGB_SIZE];
-
- avg_cache[i_pixel][i_cmap] =
- find_cmap_rgb8_nearest(p_vout, rgb_vout, rgb_approx);
- printf(
- "cmap old %0x avg approx 0%x sub: %d sub=(%0x, %0x, %0x) "
- "approx=(%0x, %0x, %0x) avg vout=(%0x, %0x, %0x)\n",
- i_pixel, avg_cache[i_pixel][i_cmap], i_cmap,
- cmap_rgb[i_cmap][RED_PIXEL], cmap_rgb[i_cmap][GREEN_PIXEL],
- cmap_rgb[i_cmap][BLUE_PIXEL],
- rgb_approx[RED_PIXEL], rgb_approx[GREEN_PIXEL], rgb_approx[BLUE_PIXEL],
- rgb_vout[RED_PIXEL], rgb_vout[GREEN_PIXEL], rgb_vout[BLUE_PIXEL]);
- }
-#else
- avg_cache[i_pixel][i_cmap] =
- find_cmap_rgb8_nearest(p_vout, rgb_vout, NULL);
-#endif
- return avg_cache[i_pixel][i_cmap];
-}
-
-#undef BYTES_PER_PIXEL
-#define BYTES_PER_PIXEL 1
-
-static void
-BlendRGB2( vout_thread_t *p_vout, picture_t *p_pic,
- const subpicture_t *p_spu, vlc_bool_t b_crop )
-{
- /* Common variables */
- uint8_t *p_pixel_base;
- uint8_t *p_src_start = (uint8_t *)p_spu->p_sys->p_data;
- uint8_t *p_src_end = &p_src_start[p_spu->i_height * p_spu->i_width];
- uint8_t *p_source; /* This is the where the subtitle pixels come from */
- int i;
-
- int i_x, i_y;
- int i_y_src;
-
- /* Chroma specific */
- uint32_t i_xscale; /* Amount we scale subtitle in the x direction,
- multiplied by 2**ASCALE. */
- uint32_t i_yscale; /* Amount we scale subtitle in the y direction.
- multiplied by 2**ASCALE. */
-
- int i_width, i_height, i_ytmp;
-
- /* Crop-specific */
- int i_x_start, i_y_start, i_x_end, i_y_end;
-
- struct subpicture_sys_t *p_sys = p_spu->p_sys;
- int i_aspect_x, i_aspect_y;
-
- vlc_reduce( &i_aspect_x, &i_aspect_y, p_vout->render.i_aspect,
- VOUT_ASPECT_FACTOR, 0 );
-
- i_xscale = (( p_vout->output.i_width << ASCALE ) * i_aspect_x)
- / (i_aspect_y * p_vout->render.i_width);
- i_yscale = ( p_vout->output.i_height << ASCALE ) / p_vout->render.i_height;
-
- dbg_print( (DECODE_DBG_CALL|DECODE_DBG_RENDER),
- "spu: %dx%d, scaled: %dx%d, vout render: %dx%d, scale %dx%d",
- p_spu->i_width, p_spu->i_height,
- p_vout->output.i_width, p_vout->output.i_height,
- p_vout->render.i_width, p_vout->render.i_height,
- i_xscale, i_yscale
- );
-
- i_width = p_spu->i_width * i_xscale;
- i_height = p_spu->i_height * i_yscale;
-
-
- /** FIXME: do once per subtitle in subtitle processing, not here
- each time we render. */
- /* Find a corresponding colormap entries for our palette entries. */
- for( i = 0; i < NUM_SUBTITLE_COLORS; i++ )
- {
-
- if ( p_sys->p_palette[i].s.t != 0 ) {
- uint8_t rgb[RGB_SIZE];
- yuv2rgb(&(p_sys->p_palette[i]), rgb);
- cmap[i] =
- find_cmap_rgb8_nearest(p_vout, rgb, cmap_rgb[i]);
- dbg_print( (DECODE_DBG_RENDER),
- "palette %d RGB=(%0x, %0x, %0x)\n", i,
- rgb[RED_PIXEL], rgb[GREEN_PIXEL], rgb[BLUE_PIXEL]);
- }
- }
-
- /* Set where we will start blending subtitle from using
- the picture coordinates subtitle offsets
- */
- p_pixel_base = p_pic->p->p_pixels
- + ( (p_spu->i_x * i_xscale) >> ASCALE ) * BYTES_PER_PIXEL
- + ( (p_spu->i_y * i_yscale) >> ASCALE ) * p_pic->p->i_pitch;
-
- i_x_start = p_sys->i_x_start;
- i_y_start = i_yscale * p_sys->i_y_start;
- i_x_end = p_sys->i_x_end;
- i_y_end = i_yscale * p_sys->i_y_end;
-
- p_source = (uint8_t *)p_sys->p_data;
-
- /* Draw until we reach the bottom of the subtitle */
- i_y = 0;
- for( i_y_src = 0 ; i_y_src < p_spu->i_height * p_spu->i_width;
- i_y_src += p_spu->i_width )
- {
- uint8_t *p_pixel_base_y;
- i_ytmp = i_y >> ASCALE;
- i_y += i_yscale;
- p_pixel_base_y = p_pixel_base + (i_ytmp * p_pic->p->i_pitch);
- i_x = 0;
-
- if ( b_crop ) {
- if ( i_y > i_y_end ) break;
- if (i_x_start) {
- i_x = i_x_start;
- p_source += i_x_start;
- }
- }
-
- /* Check whether we need to draw one line or more than one */
- if( i_ytmp + 1 >= ( i_y >> ASCALE ) )
- {
-
- /* Draw until we reach the end of the line */
- for( ; i_x < p_spu->i_width; i_x ++, p_source++ )
- {
- ogt_yuvt_t p_yuvt;
-
- if( b_crop ) {
-
- /* FIXME: y cropping should be dealt with outside of this
- loop.*/
- if ( i_y < i_y_start) continue;
-
- if ( i_x > i_x_end )
- {
- p_source += p_spu->i_width - i_x;
- break;
- }
- }
-
- if (p_source >= p_src_end) {
- msg_Err( p_vout, "trying to access beyond subtitle %dx%d %d",
- i_x, i_y / i_yscale, i_height);
- return;
- }
-
- p_yuvt = p_sys->p_palette[*p_source & 0x3];
-
-#ifdef TESTING_TRANSPARENCY
- if (p_yuvt.s.t == MAX_TRANS) p_yuvt.s.t >>= 1;
-#endif
-
- switch ( p_yuvt.s.t )
- {
- case 0:
- /* Completely transparent. Don't change pixel. */
-#if 0
- printf(" "); /*++++*/
-#endif
- break;
- case MAX_TRANS:
- {
- uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
- * BYTES_PER_PIXEL );
- uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
- * BYTES_PER_PIXEL );
- /* This is the pixel that's going to change;*/
- uint8_t *p_dest = p_pixel_base_y + i_xdest;
- memset( p_dest, cmap[*p_source & 0x3], i_xlast - i_xdest );
-#if 0
- printf("%1d", *p_source); /*++++*/
-#endif
- break;
- }
- default:
- {
- uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
- * BYTES_PER_PIXEL );
- uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
- * BYTES_PER_PIXEL );
- /* This is the pixel that's going to change;*/
- uint8_t *p_pixel = p_pixel_base_y + i_xdest;
- uint32_t len = i_xlast - i_xdest;
-
-#if FULL_TRANSPARENCY
- /* This is what should be done, but it may be too
- slow. */
- for ( len = i_xlast - i_xdest -1; len >= 0; len-- )
- {
- cmap_t i_cmap = avg_rgb2(p_vout, *p_pixel, p_yuvt.s.t,
- *p_source, p_sys->i_pts);
-
- if (i_cmap != INVALID_CMAP_ENTRY)
- *p_pixel= (uint8_t) i_cmap;
- p_pixel++;
- }
-#else
- cmap_t i_cmap = avg_rgb2(p_vout, *p_pixel, p_yuvt.s.t,
- *p_source, p_sys->i_pts);
- if (i_cmap != INVALID_CMAP_ENTRY)
- memset(p_pixel, i_cmap, len);
-#endif
-
-#if 0
- printf("%1d", *p_source); /*++++*/
-#endif
- }
- }
- }
-#if 0
- printf("\n"); /*++++*/
-#endif
- } else {
- /* Have to scale over many lines. */
- int i_yreal = p_pic->p->i_pitch * i_ytmp;
- int i_ynext = p_pic->p->i_pitch * i_y >> ASCALE;
-
- /* Draw until we reach the end of the line */
- for( ; i_x < p_spu->i_width; i_x ++, p_source++ )
- {
- ogt_yuvt_t p_yuvt = p_sys->p_palette[*p_source & 0x3];
-
- if( b_crop ) {
-
- /* FIXME: y cropping should be dealt with outside of this
- loop.*/
- if ( i_y < i_y_start) continue;
-
- if ( i_x > i_x_end )
- {
- p_source += p_spu->i_width - i_x;
- break;
- }
- }
-
- if (p_source >= p_src_end) {
- msg_Err( p_vout, "trying to access beyond subtitle %dx%d %d",
- i_x, i_y / i_yscale, i_height);
- return;
- }
-
-#ifdef TESTING_TRANSPARENCY
- if (p_yuvt.s.t == MAX_TRANS) p_yuvt.s.t >>= 1;
-#endif
- switch ( p_yuvt.s.t )
- {
- case 0:
- /* Completely transparent. Don't change pixel. */
-#if 0
- printf(" "); /*++++*/
-#endif
- break;
- case MAX_TRANS:
- {
- uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
- * BYTES_PER_PIXEL );
- uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
- * BYTES_PER_PIXEL );
- uint32_t len = i_xlast - i_xdest;
-#if 0
- printf("%1d", *p_source); /*++++*/
-#endif
- for( i_ytmp = i_yreal ; i_ytmp < i_ynext ;
- i_ytmp += p_pic->p->i_pitch ) {
- uint8_t *p_dest = p_pixel_base + i_ytmp + i_xdest;
- memset( p_dest, cmap[*p_source & 0x3], len );
- }
- break;
- }
- default:
- {
- uint32_t i_xdest = ( ((i_x*i_xscale) >> ASCALE)
- * BYTES_PER_PIXEL );
- uint32_t i_xlast = ( (((i_x+1)*i_xscale) >> ASCALE)
- * BYTES_PER_PIXEL );
- int32_t len = i_xlast - i_xdest;
-#if 0
- printf("%1d", *p_source); /*++++*/
-#endif
-
- for( i_ytmp = i_yreal ; i_ytmp < i_ynext ;
- i_ytmp += p_pic->p->i_pitch ) {
- /* This is the pixel that's going to change;*/
- uint8_t *p_pixel = p_pixel_base + i_ytmp + i_xdest;
-
-#if FULL_TRANSPARENCY
- /* This is what should be done, but it may be too
- slow. */
- for ( len = i_xlast - i_xdest -1; len >= 0; len-- )
- {
- cmap_t i_cmap = avg_rgb2(p_vout, *p_pixel,
- p_yuvt.s.t, *p_source,
- p_sys->i_pts);
- if (i_cmap != INVALID_CMAP_ENTRY)
- *p_pixel= (uint8_t) i_cmap;
- p_pixel++;
- }
-#else
- cmap_t i_cmap = avg_rgb2(p_vout, *p_pixel, p_yuvt.s.t,
- *p_source, p_sys->i_pts);
- if (i_cmap != INVALID_CMAP_ENTRY)
- memset(p_pixel, i_cmap, len);
-#endif
-
- }
- }
- }
- }
- }
- }
-}
-
-\f
-/*
- * Local variables:
- * c-file-style: "gnu"
- * tab-width: 8
- * indent-tabs-mode: nil
- * End:
- */
+++ /dev/null
-/*****************************************************************************
- * render.h : Common SVCD and CVD rendering routine(s).
- *****************************************************************************
- * Copyright (C) 2003 VideoLAN
- * $Id: render.h,v 1.3 2004/01/21 04:45:47 rocky Exp $
- *
- * Author: Rocky Bernstein
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
- *****************************************************************************/
-
-/*****************************************************************************
- * Prototypes
- *****************************************************************************/
-void VCDSubBlend ( vout_thread_t *, picture_t *, const subpicture_t * );
-
+++ /dev/null
-/*****************************************************************************
- * subtitle.h : Common SVCD and CVD subtitles header
- *****************************************************************************
- * Copyright (C) 2003,2004 VideoLAN
- * $Id$
- *
- * Author: Rocky Bernstein
- * based on code from:
- * Julio Sanchez Fernandez (http://subhandler.sourceforge.net)
- * Sam Hocevar <sam@zoy.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
- *****************************************************************************/
-
-#include "pixmap.h"
-
-#define DECODE_DBG_EXT 1 /* Calls from external routines */
-#define DECODE_DBG_CALL 2 /* all calls */
-#define DECODE_DBG_PACKET 4 /* packet assembly info */
-#define DECODE_DBG_IMAGE 8 /* image bitmaps */
-#define DECODE_DBG_TRANSFORM 16 /* bitmap transformations */
-#define DECODE_DBG_RENDER 32 /* rendering information */
-#define DECODE_DBG_PNG 64 /* Extract subtitles to PNG files. */
-#define DECODE_DBG_INFO 128
-
-#define DEBUG_TEXT N_( \
- "If nonzero, this gives additional debug information." \
- )
-
-#define DEBUG_LONGTEXT N_( \
- "This integer when viewed in binary is a debugging mask\n" \
- "external call 1\n" \
- "all calls 2\n" \
- "packet assembly info 4\n" \
- "image bitmaps 8\n" \
- "image transformations 16\n" \
- "rendering information 32\n" \
- "extract subtitles 64\n" \
- "misc info 128\n" )
-
-#define SUB_ASPECT_RATIO_TEXT N_("Subtitle aspect-ratio correction")
-#define SUB_ASPECT_RATIO_LONGTEXT N_( \
- "Use this to force the subtitle aspect ratio. If you give a null string " \
- "the right value will be determined automatically. Usually this is what " \
- "you want. For OGT and CVD subtitles this undoes the effect " \
- "of the underlying video scaling. And using a value of 1 will cause " \
- "no correction; subtitles will be scaled with the same aspect " \
- "ratio as as the underlying video (which not correct for OGT or " \
- "CVD subtitles). You can also force another ratio by giving a pair of " \
- "integers x:y where y should between x and twice x. For example 4:3, or " \
- "16:9. Alternatively, you can give a float value expressing pixel " \
- "squareness. For example 1.25 or 1.3333 which mean the same thing as " \
- "4:3 and 16:9 respectively." \
- )
-
-#define DURATION_SCALE_TEXT N_("Factor to increase subtitle display interval")
-#define DURATION_SCALE_LONGTEXT N_( \
- "If you find you need extra time for reading subtitles, " \
- "you can set this higher and it will multiply the display " \
- "time by that amount. Use 0 to mean until the next " \
- "subtitle.")
-
-#define HORIZONTAL_CORRECT \
- N_("Add this to starting horizontal position of subtitle.")
-#define HORIZONTAL_CORRECT_LONGTEXT N_( \
- "If you need to adjust the subtitle starting position horizontally, " \
- "set this. Negative values shift left and positive values right. 0 would " \
- "be no deviation from where the position specified in the subtitle." \
- )
-
-#define VERTICAL_CORRECT \
- N_("Add this to starting vertical position of subtitle.")
-#define VERTICAL_CORRECT_LONGTEXT N_( \
- "If you need to adjust the subtitle starting position vertically, " \
- "set this. Negative values shift up, positive values down. 0 would " \
- "be no deviation from where the position specified in the subtitle." \
- )
-
-#define DECODE_DEBUG 1
-#if DECODE_DEBUG
-#define dbg_print(mask, s, args...) \
- if (p_sys && p_sys->i_debug & mask) \
- msg_Dbg(p_dec, "%s: "s, __func__ , ##args)
-#else
-#define dbg_print(mask, s, args...)
-#endif
-
-#define LOG_ERR(args...) msg_Err( p_input, args )
-#define LOG_WARN(args...) msg_Warn( p_input, args )
-
-#define GETINT16(p) ( (p[0] << 8) + p[1] ) ; p +=2;
-
-#define GETINT32(p) ( (p[0] << 24) + (p[1] << 16) + \
- (p[2] << 8) + (p[3]) ) ; p += 4;
-
-
-/* The number of color palette entries allowed in a subtitle. */
-#define NUM_SUBTITLE_COLORS 4
-
-typedef enum {
- SUBTITLE_BLOCK_EMPTY,
- SUBTITLE_BLOCK_PARTIAL,
- SUBTITLE_BLOCK_COMPLETE
-} packet_state_t;
-
-/* The byte storage used by one pixel */
-#define PIXEL_SIZE 4
-
-/* Size in bytes of YUV portion above. */
-#define YUV_SIZE 3
-
-
-
-/* Transparency plane. NOTE: see vlc_video.h for V_PLANE */
-#define T_PLANE V_PLANE+1
-
-struct decoder_sys_t
-{
- int i_debug; /* debugging mask */
- mtime_t i_pts; /* Start PTS of subtitle block */
- int i_spu;
- packet_state_t state; /* data-gathering state for this subtitle */
-
- uint16_t i_image; /* image number in the subtitle stream; 0 is the
- first one. */
- uint8_t i_packet;/* packet number for above image number; 0 is the
- first one. */
- block_t *p_block;/* Bytes of the packet. */
-
- uint8_t buffer[65536 + 20 ]; /* we will never overflow more than 11
- bytes if I'm right */
- int b_packetizer;
- int i_spu_size; /* goal for subtitle_data_pos while gathering,
- size of used subtitle_data later */
- vout_thread_t *p_vout;
-
- int i_subpic_channel; /* Subpicture channel in which subtitles will
- be written */
-
- /* FIXME: Remove this? */
- uint8_t *subtitle_data; /* buffer used to accumulate data from
- successive packets in the same subtitle */
- int subtitle_data_size; /* size of the allocated subtitle_data */
-
- /* Move into subpicture_sys_t? */
- uint16_t i_image_offset; /* offset from subtitle_data to compressed
- image data */
- int i_image_length; /* size of the compressed image data */
- int first_field_offset; /* offset of even raster lines. Used
- only for CVD. */
- int second_field_offset; /* offset of odd raster lines */
- int metadata_offset; /* offset to data describing the image */
- int metadata_length; /* length of metadata */
-
- int subtitle_data_pos; /* where to write next chunk */
-
- mtime_t i_duration; /* how long to display the image, 0 stands
- for "until next subtitle" */
-
- uint16_t i_x_start, i_y_start; /* position of top leftmost pixel of
- image when displayed */
- uint16_t i_width, i_height; /* dimensions in pixels of image */
-
- ogt_yuvt_t p_palette[NUM_SUBTITLE_COLORS]; /* Palette of colors used
- in subtitle */
-
-
- ogt_yuvt_t p_palette_highlight[NUM_SUBTITLE_COLORS]; /* Only used
- for CVD */
-
- uint8_t i_options;
- uint8_t i_options2;
- uint8_t i_cmd;
- uint32_t i_cmd_arg;
-};
-
-struct subpicture_sys_t
-{
- int i_debug; /* debugging mask */
- mtime_t i_pts; /* presentation timestamp */
-
- uint8_t *p_data; /* Image data one byte T, Y, U, V */
-
-
- /* Link to our input */
- vlc_object_t * p_input;
-
- /* Cropping properties */
- vlc_mutex_t lock;
- vlc_bool_t b_crop;
- unsigned int i_x_start, i_y_start, i_x_end, i_y_end;
-
- /* This is only used for color palette Chromas like RGB2. */
- ogt_yuvt_t p_palette[NUM_SUBTITLE_COLORS]; /* Palette of colors used
- in subtitle */
-
-};
+++ /dev/null
-/*****************************************************************************
- * Dump an Image to a Portable Network Graphics (PNG) file
- ****************************************************************************
- Copyright (C) 2004 VideoLAN
- Author: Rocky Bernstein
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
- *****************************************************************************/
-
-#include "config.h"
-#ifdef HAVE_LIBPNG
-
-#include <stdio.h>
-#include <stdlib.h>
-#include "write_png.h"
-#include <setjmp.h>
-
-typedef void (*snapshot_messenger_t)(char *message);
-
-#define _(x) x
-
-/*
- * Error functions for use as callbacks by the png libraries
- */
-
-void error_msg(char *message)
-{
- printf("error: %s\n", message);
-}
-
-void warning_msg(char *message)
-{
- printf("warning: %s\n", message);
-}
-
-static snapshot_messenger_t error_msg_cb = error_msg;
-static snapshot_messenger_t warning_msg_cb = warning_msg;
-
-static void
-user_error_fn(png_structp png_ptr, png_const_charp error_msg)
-{
-
- if(error_msg_cb) {
- char uerror[4096];
-
- memset(&uerror, 0, sizeof(uerror));
- sprintf(uerror, _("Error: %s\n"), error_msg);
- error_msg_cb(uerror);
- }
-}
-
-static void
-user_warning_fn(png_structp png_ptr, png_const_charp warning_msg)
-{
- if(error_msg_cb) {
- char uerror[4096];
-
- memset(&uerror, 0, sizeof(uerror));
- sprintf(uerror, _("Error: %s\n"), warning_msg);
- warning_msg_cb(uerror);
- }
-}
-
-/*
- Dump an image to a Portable Network Graphics (PNG) file. File_name
- is where the file goes, i_height and i_width are the height and
- width in pixels of the image. The data for the image is stored as a
- linear array of one byte for each of red, green, and blue
- components of an RGB pixel. Thus row[i] will begin at rgb_image +
- i*(i_width*3) and the blue pixel at image[i][0] would be rgb_image +
- i*(i_width*3) + 1.
-
- */
-void
-write_png(const char *file_name, png_uint_32 i_height, png_uint_32 i_width,
- void *rgb_image, /*in*/ png_text *text_ptr, int i_text_count )
-{
- FILE *fp;
- png_structp png_ptr;
- png_infop info_ptr;
- png_color_8 sig_bit;
- png_bytep *row_pointers;
-
- unsigned int i,j;
-
- /* open the file */
- fp = fopen(file_name, "wb");
- if (fp == NULL)
- return;
-
- /* Create and initialize the png_struct with the desired error handler
- * functions. If you want to use the default stderr and longjump method,
- * you can supply NULL for the last three parameters. We also check that
- * the library version is compatible with the one used at compile time,
- * in case we are using dynamically linked libraries. REQUIRED.
- */
- png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp) NULL,
- user_error_fn, user_warning_fn);
-
- if (png_ptr == NULL)
- {
- fclose(fp);
- return;
- }
-
- /* Allocate/initialize the image information data. REQUIRED */
- info_ptr = png_create_info_struct(png_ptr);
- if (info_ptr == NULL)
- {
- fclose(fp);
- png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
- return;
- }
-
- /* Set error handling. REQUIRED if you aren't supplying your own
- * error handling functions in the png_create_write_struct() call.
- */
- if (setjmp(png_ptr->jmpbuf))
- {
- /* If we get here, we had a problem writing the file */
- fclose(fp);
- png_destroy_write_struct(&png_ptr, (png_infopp) &info_ptr);
- return;
- }
-
- /* Set up the output control using standard C streams. This
- is required. */
- png_init_io(png_ptr, fp);
-
- /* Set the image information here. i_width and i_height are up to 2^31,
- * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
- * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
- * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
- * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or
- * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
- * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
- */
- png_set_IHDR(png_ptr, info_ptr, i_width, i_height, 8, PNG_COLOR_TYPE_RGB,
- PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
- PNG_FILTER_TYPE_BASE);
-
- /* For color images: */
- sig_bit.red = 8;
- sig_bit.green = 8;
- sig_bit.blue = 8;
-
- if (text_ptr)
- png_set_text(png_ptr, info_ptr, text_ptr, i_text_count);
-
- /* Write the file header information. REQUIRED */
- png_write_info(png_ptr, info_ptr);
-
- /* Once we write out the header, the compression type on the text
- * chunks gets changed to PNG_TEXT_COMPRESSION_NONE_WR or
- * PNG_TEXT_COMPRESSION_zTXt_WR, so it doesn't get written out again
- * at the end.
- */
-
- /* Shift the pixels up to a legal bit depth and fill in
- * as appropriate to correctly scale the image.
- */
- png_set_shift(png_ptr, &sig_bit);
-
- /* pack pixels into bytes */
- png_set_packing(png_ptr);
-
- row_pointers = png_malloc(png_ptr, i_height*sizeof(png_bytep *));
- for (i=0, j=0; i<i_height; i++, j+=i_width*3) {
- row_pointers[i] = rgb_image + j;
- }
-
- png_set_rows (png_ptr, info_ptr, row_pointers);
- png_write_image(png_ptr, row_pointers);
-
- /* You can write optional chunks like tEXt, zTXt, and tIME at the end
- * as well.
- */
-
- /* It is REQUIRED to call this to finish writing the rest of the file */
- png_write_end(png_ptr, info_ptr);
-
- /* if you allocated any text comments, free them here */
- /* free image data if allocated. */
-
- /* clean up after the write, and free any memory allocated */
- png_destroy_info_struct(png_ptr, &info_ptr);
-
- /* clean up after the write, and free any memory allocated */
- png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
-
- fclose(fp);
-
- return;
-}
-
-#ifdef STANDALONE
-int
-main(int argc, char **argv)
-{
- char image_data[3*16 * 3*16 * 3];
- int i,j,k,l,m;
- char r,g,b,t, or,og,ob;
-
- or=0x00; og=0xFF; ob=0x0;
- m=0;
- for (i=0; i<3; i++) {
- t=or; or=og; og=ob; ob=t;
- for (j=0; j<16; j++) {
- r=or; g=og; b=ob;
- for (k=0; k<3; k++) {
- for (l=0; l<16; l++) {
- image_data[m++]=r;
- image_data[m++]=g;
- image_data[m++]=b;
- }
- t=r; r=g; g=b; b=t;
- }
- }
- }
-
- write_png("/tmp/pngtest.png", 3*16, 3*16, (void *) image_data) ;
- return 0;
-}
-#endif /*STANDALONE*/
-
-#endif /*HAVE_LIBPNG*/
+++ /dev/null
-/*****************************************************************************
- * Dump an Image to a Portable Network Graphics (PNG) file
- ****************************************************************************
- Copyright (C) 2004 VideoLAN
- Author: Rocky Bernstein
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
- *****************************************************************************/
-
-#include <png.h>
-
-/*
- Dump an image to a Portable Network Graphics (PNG) file. File_name
- is where the file goes, i_height and i_width are the height and
- width in pixels of the image. The data for the image is stored as a
- linear array RGB pixel entries: one byte for each of red, green,
- and blue component. Thus row[i] will begin at rgb_image +
- i*(i_width*3) and the blue pixel at image[i][0] would be rgb_image
- + i*(i_width*3) + 1.
-
- text_ptr contains comments that can be written to the image. It can
- be null. i_text_count is the number of entries in text_ptr.
-
- */
-void write_png(const char *file_name, png_uint_32 i_height,
- png_uint_32 i_width, void *rgb_image,
- /*in*/ png_text *text_ptr, int i_text_count );
-
--- /dev/null
+/*****************************************************************************
+ * svcdsub.c : Overlay Graphics Text (SVCD subtitles) decoder
+ *****************************************************************************
+ * Copyright (C) 2003, 2004 VideoLAN
+ * $Id$
+ *
+ * Authors: Rocky Bernstein
+ * Gildas Bazin <gbazin@videolan.org>
+ * Julio Sanchez Fernandez (http://subhandler.sourceforge.net)
+ * Laurent Aimar <fenrir@via.ecp.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
+ *****************************************************************************/
+
+#define DEBUG_SVCD 1
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+#include <vlc/vlc.h>
+#include <vlc/decoder.h>
+
+#include "vlc_bits.h"
+
+/*****************************************************************************
+ * Module descriptor.
+ *****************************************************************************/
+static int DecoderOpen ( vlc_object_t * );
+static int PacketizerOpen( vlc_object_t * );
+static void DecoderClose ( vlc_object_t * );
+
+vlc_module_begin();
+ set_description( _("Philips OGT (SVCD subtitle) decoder") );
+ set_capability( "decoder", 50 );
+ set_callbacks( DecoderOpen, DecoderClose );
+
+ add_submodule();
+ set_description( _("Philips OGT (SVCD subtitle) packetizer") );
+ set_capability( "packetizer", 50 );
+ set_callbacks( PacketizerOpen, DecoderClose );
+vlc_module_end();
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+static subpicture_t *Decode( decoder_t *, block_t ** );
+static block_t *Packetize ( decoder_t *, block_t ** );
+static block_t *Reassemble ( decoder_t *, block_t * );
+static void ParseHeader( decoder_t *, block_t * );
+static subpicture_t *DecodePacket( decoder_t *, block_t * );
+static void RenderImage( decoder_t *, block_t *, subpicture_region_t * );
+
+#define GETINT16(p) ( (p[0] << 8) + p[1] ) ; p +=2;
+
+#define GETINT32(p) ( (p[0] << 24) + (p[1] << 16) + \
+ (p[2] << 8) + (p[3]) ) ; p += 4;
+
+#define SUBTITLE_BLOCK_EMPTY 0
+#define SUBTITLE_BLOCK_PARTIAL 1
+#define SUBTITLE_BLOCK_COMPLETE 2
+
+struct decoder_sys_t
+{
+ int b_packetizer;
+
+ int i_state; /* data-gathering state for this subtitle */
+
+ block_t *p_spu; /* Bytes of the packet. */
+
+ uint16_t i_image; /* image number in the subtitle stream */
+ uint8_t i_packet; /* packet number for above image number */
+
+ int i_spu_size; /* goal for subtitle_data_pos while gathering,
+ size of used subtitle_data later */
+
+ uint16_t i_image_offset; /* offset from subtitle_data to compressed
+ image data */
+ int i_image_length; /* size of the compressed image data */
+ int second_field_offset; /* offset of odd raster lines */
+ int metadata_offset; /* offset to data describing the image */
+ int metadata_length; /* length of metadata */
+
+ mtime_t i_duration; /* how long to display the image, 0 stands
+ for "until next subtitle" */
+
+ uint16_t i_x_start, i_y_start; /* position of top leftmost pixel of
+ image when displayed */
+ uint16_t i_width, i_height; /* dimensions in pixels of image */
+
+ uint8_t p_palette[4][4]; /* Palette of colors used in subtitle */
+};
+
+/*****************************************************************************
+ * DecoderOpen: open/initialize the svcdsub decoder.
+ *****************************************************************************/
+static int DecoderOpen( vlc_object_t *p_this )
+{
+ decoder_t *p_dec = (decoder_t*)p_this;
+ decoder_sys_t *p_sys;
+
+ if( p_dec->fmt_in.i_codec != VLC_FOURCC( 'o','g','t',' ' ) )
+ {
+ return VLC_EGENERIC;
+ }
+
+ p_dec->p_sys = p_sys = malloc( sizeof( decoder_sys_t ) );
+
+ p_sys->b_packetizer = VLC_FALSE;
+ p_sys->i_image = -1;
+
+ p_sys->i_state = SUBTITLE_BLOCK_EMPTY;
+ p_sys->p_spu = NULL;
+
+ es_format_Init( &p_dec->fmt_out, SPU_ES, VLC_FOURCC( 'o','g','t',' ' ) );
+
+ p_dec->pf_decode_sub = Decode;
+ p_dec->pf_packetize = Packetize;
+
+ return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * PacketizerOpen: open/initialize the svcdsub packetizer.
+ *****************************************************************************/
+static int PacketizerOpen( vlc_object_t *p_this )
+{
+ decoder_t *p_dec = (decoder_t*)p_this;
+
+ if( DecoderOpen( p_this ) != VLC_SUCCESS ) return VLC_EGENERIC;
+
+ p_dec->p_sys->b_packetizer = VLC_TRUE;
+
+ return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * DecoderClose: closes the svcdsub decoder/packetizer.
+ *****************************************************************************/
+void DecoderClose( vlc_object_t *p_this )
+{
+ decoder_t *p_dec = (decoder_t*)p_this;
+ decoder_sys_t *p_sys = p_dec->p_sys;
+
+ if( p_sys->p_spu ) block_ChainRelease( p_sys->p_spu );
+ free( p_sys );
+}
+
+/*****************************************************************************
+ * Decode:
+ *****************************************************************************/
+static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
+{
+ block_t *p_block, *p_spu;
+
+ if( pp_block == NULL || *pp_block == NULL ) return NULL;
+
+ p_block = *pp_block;
+ *pp_block = NULL;
+
+ if( !(p_spu = Reassemble( p_dec, p_block )) ) return NULL;
+
+ /* Parse and decode */
+ return DecodePacket( p_dec, p_spu );
+}
+
+/*****************************************************************************
+ * Packetize:
+ *****************************************************************************/
+static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
+{
+ block_t *p_block, *p_spu;
+
+ if( pp_block == NULL || *pp_block == NULL ) return NULL;
+
+ p_block = *pp_block;
+ *pp_block = NULL;
+
+ if( !(p_spu = Reassemble( p_dec, p_block )) ) return NULL;
+
+ p_spu->i_dts = p_spu->i_pts;
+ p_spu->i_length = 0;
+
+ return p_spu;
+}
+
+/*****************************************************************************
+ Reassemble:
+
+ The data for single screen subtitle may come in one of many
+ non-contiguous packets of a stream. This routine is called when the
+ next packet in the stream comes in. The job of this routine is to
+ parse the header, if this is the beginning, and combine the packets
+ into one complete subtitle unit.
+
+ If everything is complete, we will return a block. Otherwise return
+ NULL.
+
+
+ The format of the beginning of the subtitle packet that is used here.
+
+ size description
+ -------------------------------------------
+ byte subtitle channel (0..7) in bits 0-3
+ byte subtitle packet number of this subtitle image 0-N,
+ if the subtitle packet is complete, the top bit of the byte is 1.
+ uint16 subtitle image number
+
+ *****************************************************************************/
+#define SPU_HEADER_LEN 5
+
+static block_t *Reassemble( decoder_t *p_dec, block_t *p_block )
+{
+ decoder_sys_t *p_sys = p_dec->p_sys;
+ uint8_t *p_buffer;
+ uint16_t i_expected_image;
+ uint8_t i_packet, i_expected_packet;
+
+ if( p_block->i_buffer < SPU_HEADER_LEN )
+ {
+ msg_Dbg( p_dec, "invalid packet header (size %d < %d)" ,
+ p_block->i_buffer, SPU_HEADER_LEN );
+ block_Release( p_block );
+ return NULL;
+ }
+
+ p_buffer = p_block->p_buffer;
+
+ if( p_sys->i_state == SUBTITLE_BLOCK_EMPTY )
+ {
+ i_expected_image = p_sys->i_image + 1;
+ i_expected_packet = 0;
+ }
+ else
+ {
+ i_expected_image = p_sys->i_image;
+ i_expected_packet = p_sys->i_packet + 1;
+ }
+
+ p_buffer += 2;
+
+ if( *p_buffer & 0x80 )
+ {
+ p_sys->i_state = SUBTITLE_BLOCK_COMPLETE;
+ i_packet = *p_buffer++ & 0x7F;
+ }
+ else
+ {
+ p_sys->i_state = SUBTITLE_BLOCK_PARTIAL;
+ i_packet = *p_buffer++;
+ }
+
+ p_sys->i_image = GETINT16(p_buffer);
+
+ if( p_sys->i_image != i_expected_image )
+ {
+ msg_Warn( p_dec, "expected subtitle image %u but found %u",
+ i_expected_image, p_sys->i_image );
+ }
+
+ if( i_packet != i_expected_packet )
+ {
+ msg_Warn( p_dec, "expected subtitle image packet %u but found %u",
+ i_expected_packet, i_packet );
+ }
+
+ p_block->p_buffer += SPU_HEADER_LEN;
+ p_block->i_buffer -= SPU_HEADER_LEN;
+
+ p_sys->i_packet = i_packet;
+ /* First packet in the subtitle block */
+ if( !p_sys->i_packet ) ParseHeader( p_dec, p_block );
+
+ block_ChainAppend( &p_sys->p_spu, p_block );
+
+ if( p_sys->i_state == SUBTITLE_BLOCK_COMPLETE )
+ {
+ block_t *p_spu = block_ChainGather( p_sys->p_spu );
+
+ if( p_spu->i_buffer != p_sys->i_spu_size )
+ {
+ msg_Warn( p_dec, "SPU packets size=%d should be %d",
+ p_spu->i_buffer, p_sys->i_spu_size );
+ }
+
+ msg_Dbg( p_dec, "subtitle packet complete, size=%d", p_spu->i_buffer);
+
+ p_sys->i_state = SUBTITLE_BLOCK_EMPTY;
+ p_sys->p_spu = 0;
+ return p_spu;
+ }
+
+ return NULL;
+}
+
+/******************************************************************************
+ The format is roughly as follows (everything is big-endian):
+
+ size description
+ -------------------------------------------
+ byte subtitle channel (0..7) in bits 0-3
+ byte subtitle packet number of this subtitle image 0-N,
+ if the subtitle packet is complete, the top bit of the byte is 1.
+ u_int16 subtitle image number
+ u_int16 length in bytes of the rest
+ byte option flags, unknown meaning except bit 3 (0x08) indicates
+ presence of the duration field
+ byte unknown
+ u_int32 duration in 1/90000ths of a second (optional), start time
+ is as indicated by the PTS in the PES header
+ u_int32 xpos
+ u_int32 ypos
+ u_int32 width (must be even)
+ u_int32 height (must be even)
+ byte[16] palette, 4 palette entries, each contains values for
+ Y, U, V and transparency, 0 standing for transparent
+ byte command,
+ cmd>>6==1 indicates shift
+ (cmd>>4)&3 is direction from, (0=top,1=left,2=right,3=bottom)
+ u_int32 shift duration in 1/90000ths of a second
+ u_int16 offset of odd-numbered scanlines - subtitle images are
+ given in interlace order
+ byte[] limited RLE image data in interlace order (0,2,4... 1,3,5) with
+ 2-bits per palette number
+******************************************************************************/
+static void ParseHeader( decoder_t *p_dec, block_t *p_block )
+{
+ decoder_sys_t *p_sys = p_dec->p_sys;
+ uint8_t *p = p_block->p_buffer;
+ uint8_t i_options, i_options2, i_cmd, i_cmd_arg;
+ int i;
+
+ p_sys->i_spu_size = GETINT16(p);
+ i_options = *p++;
+ i_options2 = *p++;
+
+ if( i_options & 0x08 ) { p_sys->i_duration = GETINT32(p); }
+ else p_sys->i_duration = 0; /* Ephemer subtitle */
+ p_sys->i_duration *= 100 / 9;
+
+ p_sys->i_x_start = GETINT16(p);
+ p_sys->i_y_start = GETINT16(p);
+ p_sys->i_width = GETINT16(p);
+ p_sys->i_height = GETINT16(p);
+
+ for( i = 0; i < 4; i++ )
+ {
+ p_sys->p_palette[i][0] = *p++;
+ p_sys->p_palette[i][1] = *p++;
+ p_sys->p_palette[i][2] = *p++;
+ p_sys->p_palette[i][3] = *p++;
+ }
+
+ i_cmd = *p++;
+ /* We do not really know this, FIXME */
+ if( i_cmd ) {i_cmd_arg = GETINT32(p);}
+
+ /* Actually, this is measured against a different origin, so we have to
+ * adjust it */
+ p_sys->second_field_offset = GETINT16(p);
+ p_sys->i_image_offset = p - p_block->p_buffer;
+ p_sys->i_image_length = p_sys->i_spu_size - p_sys->i_image_offset;
+ p_sys->metadata_length = p_sys->i_image_offset;
+
+#ifdef DEBUG_SVCD
+ msg_Dbg( p_dec, "x-start: %d, y-start: %d, width: %d, height %d, "
+ "spu size: %d, duration: %lu (d:%d p:%d)",
+ p_sys->i_x_start, p_sys->i_y_start,
+ p_sys->i_width, p_sys->i_height,
+ p_sys->i_spu_size, (long unsigned int) p_sys->i_duration,
+ p_sys->i_image_length, p_sys->i_image_offset);
+
+ for( i = 0; i < 4; i++ )
+ {
+ msg_Dbg( p_dec, "palette[%d]= T: %2x, Y: %2x, u: %2x, v: %2x", i,
+ p_sys->p_palette[i][3], p_sys->p_palette[i][0],
+ p_sys->p_palette[i][1], p_sys->p_palette[i][2] );
+ }
+#endif
+}
+
+/*****************************************************************************
+ * DecodePacket: parse and decode an SPU packet
+ *****************************************************************************
+ * This function parses and decodes an SPU packet and, if valid, returns a
+ * subpicture.
+ *****************************************************************************/
+static subpicture_t *DecodePacket( decoder_t *p_dec, block_t *p_data )
+{
+ decoder_sys_t *p_sys = p_dec->p_sys;
+ subpicture_t *p_spu;
+ subpicture_region_t *p_region;
+ video_format_t fmt;
+ int i;
+
+ /* Allocate the subpicture internal data. */
+ p_spu = p_dec->pf_spu_buffer_new( p_dec );
+ if( !p_spu ) return NULL;
+
+ p_spu->i_x = p_sys->i_x_start;
+ p_spu->i_x = p_spu->i_x * 3 / 4; /* FIXME: use aspect ratio for x? */
+ p_spu->i_y = p_sys->i_y_start;
+ p_spu->i_start = p_data->i_pts;
+ p_spu->i_stop = p_data->i_pts + p_sys->i_duration;
+ p_spu->b_ephemer = VLC_TRUE;
+
+ /* Create new SPU region */
+ memset( &fmt, 0, sizeof(video_format_t) );
+ fmt.i_chroma = VLC_FOURCC('Y','U','V','P');
+ fmt.i_aspect = VOUT_ASPECT_FACTOR;
+ fmt.i_width = fmt.i_visible_width = p_sys->i_width;
+ fmt.i_height = fmt.i_visible_height = p_sys->i_height;
+ fmt.i_x_offset = fmt.i_y_offset = 0;
+ p_region = p_spu->pf_create_region( VLC_OBJECT(p_dec), &fmt );
+ if( !p_region )
+ {
+ msg_Err( p_dec, "cannot allocate SPU region" );
+ //goto error;
+ }
+
+ p_spu->p_region = p_region;
+ p_region->i_x = p_region->i_y = 0;
+
+ /* Build palette */
+ fmt.p_palette->i_entries = 4;
+ for( i = 0; i < fmt.p_palette->i_entries; i++ )
+ {
+ fmt.p_palette->palette[i][0] = p_sys->p_palette[i][0];
+ fmt.p_palette->palette[i][1] = p_sys->p_palette[i][1];
+ fmt.p_palette->palette[i][2] = p_sys->p_palette[i][2];
+ fmt.p_palette->palette[i][3] = p_sys->p_palette[i][3];
+ }
+
+ RenderImage( p_dec, p_data, p_region );
+
+ return p_spu;
+}
+
+/*****************************************************************************
+ * ParseImage: parse the image part of the subtitle
+ *****************************************************************************
+ This part parses the subtitle graphical data and renders it.
+
+ 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.
+
+ However we'll transform this so that that the RLE is expanded and
+ interlacing will also be removed.
+ *****************************************************************************/
+static void RenderImage( decoder_t *p_dec, block_t *p_data,
+ subpicture_region_t *p_region )
+{
+ decoder_sys_t *p_sys = p_dec->p_sys;
+ uint8_t *p_dest = p_region->picture.Y_PIXELS;
+ int i_field; /* The subtitles are interlaced */
+ int i_row, i_column; /* scanline row/column number */
+ uint8_t i_color, i_count;
+ bs_t bs;
+
+ bs_init( &bs, p_data->p_buffer + p_sys->i_image_offset,
+ p_data->i_buffer - p_sys->i_image_offset );
+
+ for( i_field = 0; i_field < 2; i_field++ )
+ {
+ for( i_row = i_field; i_row < p_sys->i_height; i_row += 2 )
+ {
+ for( i_column = 0; i_column < p_sys->i_width; i_column++ )
+ {
+ i_color = bs_read( &bs, 2 );
+ if( i_color == 0 && (i_count = bs_read( &bs, 2 )) )
+ {
+ i_count = __MIN( i_count, p_sys->i_width - i_column );
+ memset( &p_dest[i_row * p_region->picture.Y_PITCH +
+ i_column], 0, i_count + 1 );
+ i_column += i_count;
+ continue;
+ }
+
+ p_dest[i_row * p_region->picture.Y_PITCH + i_column] = i_color;
+ }
+
+ bs_align( &bs );
+ }
+
+ /* odd field */
+ bs_init( &bs, p_data->p_buffer + p_sys->i_image_offset +
+ p_sys->second_field_offset,
+ p_data->i_buffer - p_sys->i_image_offset -
+ p_sys->second_field_offset );
+ }
+}