video_output_obj = video_output/video_output.o \
video_output/video_text.o \
+ video_output/video_spu.o \
video_output/video_yuv.o
ac3_decoder_obj = ac3_decoder/ac3_decoder_thread.o \
* Decoders FIFO configuration
*/
-/* Size of the FIFO. FIFO_SIZE+1 must be a multiple of 2 */
+/* Size of the FIFO. FIFO_SIZE+1 must be a power of 2 */
#define FIFO_SIZE 1023
* standard width and height broadcasted MPEG-2 streams */
#define VOUT_WIDTH_VAR "vlc_width"
#define VOUT_HEIGHT_VAR "vlc_height"
-#define VOUT_WIDTH_DEFAULT 640
-#define VOUT_HEIGHT_DEFAULT 480
+#define VOUT_WIDTH_DEFAULT 720
+#define VOUT_HEIGHT_DEFAULT 576
/* Maximum width of a scaled source picture - this should be relatively high,
* since higher stream values will result in no display at all. */
u32 i_border_color; /* border color */
u32 i_bg_color; /* background color */
} text;
+ /* DVD subpicture units properties */
+ struct
+ {
+ int i_offset[2]; /* byte offsets to data */
+ } spu;
} type;
/* Subpicture data, format depends of type - data can always be freely
vout_yuv_convert_t * p_Convert422; /* YUV 4:2:2 converter */
vout_yuv_convert_t * p_Convert444; /* YUV 4:4:4 converter */
- /* Pre-calculated convertion tables */
+ /* Pre-calculated conversion tables */
void * p_base; /* base for all conversion tables */
union
{
u32 * p_rgb32; /* RGB 32 bits table */
} yuv;
- /* Temporary convertion buffer and offset array */
+ /* Temporary conversion buffer and offset array */
void * p_buffer; /* convertion buffer */
int * p_offset; /* offset array */
} vout_yuv_t;
break;
case DVD_SPU_ES:
- /* we skip 4 bytes at the beginning of the subpicture payload */
- //p_ts->i_payload_start += 4;
+ /* we skip the first byte at the beginning of the
+ * subpicture payload, it only contains the SPU ID. */
+ p_ts->i_payload_start++;
p_fifo = &(((spudec_thread_t *)(p_es_descriptor->p_dec))->fifo);
break;
*/
while( (!p_spudec->b_die) && (!p_spudec->b_error) )
{
- int i_spu_id;
int i_packet_size;
int i_rle_size;
int i_index;
- int i_pes_size;
- boolean_t b_finished;
+ int i_pes_size;
+ int i_pes_count;
+ boolean_t b_finished;
unsigned char * p_spu_data;
- subpicture_t * p_spu;
+ subpicture_t * p_spu = NULL;
while( !DECODER_FIFO_ISEMPTY(p_spudec->fifo) )
{
- printf( "*** tracking next SPU PES\n" );
+ /* wait for the next SPU ID.
+ * FIXME: We trash 0xff bytes since they come from
+ * an incomplete previous packet */
do
{
- i_spu_id = GetByte( &p_spudec->bit_stream );
+ i_packet_size = GetByte( &p_spudec->bit_stream );
}
- while( (i_spu_id & 0xe0) != 0x20 );
- i_pes_size = DECODER_FIFO_START(p_spudec->fifo)->i_pes_size;
- printf( "got it. size = 0x%.4x\n", i_pes_size );
+ while( i_packet_size == 0xff );
- printf( "SPU id: 0x%.2x\n", i_spu_id );
+ /* the total size - should equal the sum of the
+ * PES packet size that form the SPU packet */
+ i_packet_size = ( i_packet_size << 8 )
+ + GetByte( &p_spudec->bit_stream );
+ i_index = 2;
- i_index = 0;
-
- GetWord( i_packet_size );
- printf( "total size: 0x%.4x\n", i_packet_size );
+ /* get the useful PES size (real size - 10) */
+ i_pes_size = DECODER_FIFO_START(p_spudec->fifo)->i_pes_size - 9;
+ i_pes_count = 1;
+ /* the RLE stuff size */
GetWord( i_rle_size );
- printf( "RLE size: 0x%.4x\n", i_rle_size );
- /* we already read 4 bytes for the total size and the RLE size */
+ /* if the values we got aren't too strange, decode the data */
+ if( i_rle_size < i_packet_size )
+ {
+ /* destroy the previous one */
+ if( p_spu ) vout_DestroySubPicture( p_spudec->p_vout, p_spu );
- p_spu = vout_CreateSubPicture( p_spudec->p_vout,
+ /* allocate the subpicture.
+ * FIXME: we should check if the allocation failed */
+ p_spu = vout_CreateSubPicture( p_spudec->p_vout,
DVD_SUBPICTURE, i_rle_size );
- p_spu_data = p_spu->p_data;
+ p_spu_data = p_spu->p_data;
- if( (i_rle_size < i_packet_size)
- && ((i_spu_id & 0xe0) == 0x20) )
- {
- printf( "doing RLE stuff (%i bytes)\n", i_rle_size );
- printf( "index/size %i/%i\n", i_index, i_pes_size );
- while( i_index++ <i_rle_size )
+ /* getting the RLE part */
+ while( i_index++ < i_rle_size )
{
- //*p_spu_data++ = GetByte( &p_spudec->bit_stream );
- if (i_index == i_pes_size) printf ("\n **** \n");
- /* kludge ??? */
- if (i_index == i_pes_size) printf( "%.2x", *p_spu_data++ = GetByte( &p_spudec->bit_stream ) );
- printf( "%.2x", *p_spu_data++ = GetByte( &p_spudec->bit_stream ) );
+ /* skip the leading byte of a PES */
+ if ( !((i_index + 3) % i_pes_size) )
+ {
+ i_pes_count++;
+ }
+ *p_spu_data++ = GetByte( &p_spudec->bit_stream );
}
- printf( "\nindex/size %i/%i\n", i_index, i_pes_size );
- //printf( "\n" );
- b_finished = 0;
- printf( "control stuff\n" );
- do
+ /* getting the control part */
+ b_finished = 0;
+ do
{
unsigned char i_cmd;
unsigned int i_word;
+ /* the date */
GetWord( i_word );
- printf( "date: 0x%.4x\n", i_word );
+ /* next offset, no next offset if == i_index-5 */
GetWord( i_word );
- printf( " next: 0x%.4x (i-5: %.4x)\n", i_word, i_index-5 );
- b_finished = (i_index - 5 >= i_word );
+ b_finished = ( i_index - 5 >= i_word );
- do
- {
+ do
+ {
i_cmd = GetByte( &p_spudec->bit_stream );
- i_index++;
+ i_index++;
- switch(i_cmd)
- {
+ switch( i_cmd )
+ {
case 0x00:
- printf( " 00 (display now)\n" );
+ /* 00 (display now) */
break;
case 0x01:
- printf( " 01 (start displaying)\n" );
+ /* 01 (start displaying) */
break;
case 0x02:
- printf( " 02 (stop displaying)\n" );
+ /* 02 (stop displaying) */
break;
case 0x03:
- GetWord( i_word );
- printf( " 03 (palette) - %.4x\n", i_word );
+ /* 03xxxx (palette) */
+ GetWord( i_word );
break;
case 0x04:
- GetWord( i_word );
- printf( " 04 (alpha channel) - %.4x\n", i_word );
+ /* 04xxxx (alpha channel) */
+ GetWord( i_word );
break;
case 0x05:
- GetWord( i_word );
- printf( " 05 (coordinates) - %.4x", i_word );
- GetWord( i_word );
- printf( "%.4x", i_word );
- GetWord( i_word );
- printf( "%.4x\n", i_word );
+ /* 05xxxyyyxxxyyy (coordinates) */
+ GetWord( i_word );
+ GetWord( i_word );
+ GetWord( i_word );
break;
case 0x06:
- GetWord( i_word );
- printf( " 06 (byte offsets) - %.4x", i_word );
- GetWord( i_word );
- printf( "%.4x\n", i_word );
+ /* 06xxxxyyyy (byte offsets) */
+ GetWord( i_word );
+ p_spu->type.spu.i_offset[0] = i_word - 4;
+ GetWord( i_word );
+ p_spu->type.spu.i_offset[1] = i_word - 4;
break;
case 0xff:
- printf( " ff (end)\n" );
+ /* ff (end) */
break;
- default:
- printf( " %.2x (unknown command)\n", i_cmd );
+ default:
+ /* ?? (unknown command) */
break;
- }
-
- }
- while( i_cmd != 0xff );
+ }
+ }
+ while( i_cmd != 0xff );
+ }
+ while( !b_finished );
- }
- while( !b_finished );
- printf( "control stuff finished\n" );
- printf( "*** end of PES !\n\n" );
+ /* SPU is finished - we can display it */
+ vout_DisplaySubPicture( p_spudec->p_vout, p_spu );
}
else
{
- printf( "*** invalid PES !\n\n" );
- /* trash the PES packet */
- /*vlc_mutex_lock( &p_spudec->fifo.data_lock );
+ /* Unexpected PES packet - trash it */
+ vlc_mutex_lock( &p_spudec->fifo.data_lock );
input_NetlistFreePES( p_spudec->bit_stream.p_input,
DECODER_FIFO_START(p_spudec->fifo) );
DECODER_FIFO_INCSTART( p_spudec->fifo );
- vlc_mutex_unlock( &p_spudec->fifo.data_lock );*/
+ vlc_mutex_unlock( &p_spudec->fifo.data_lock );
}
}
/* Waiting for the input thread to put new PES packets in the fifo */
- printf( "decoder fifo is empty\n" );
vlc_cond_wait( &p_spudec->fifo.data_wait, &p_spudec->fifo.data_lock );
+
+ if( p_spu ) vout_DestroySubPicture( p_spudec->p_vout, p_spu );
}
/*
#include "video.h"
#include "video_output.h"
#include "video_text.h"
+#include "video_spu.h"
#include "video_yuv.h"
#include "intf_msg.h"
if( (p_vout->p_subpicture[i_subpic].i_type == i_type) &&
(p_vout->p_subpicture[i_subpic].i_size >= i_size) )
{
- /* Memory size do match or is smaller : memory will not be reallocated,
- * and function can end immediately - this is the best possible case,
- * since no memory allocation needs to be done */
+ /* Memory size do match or is smaller : memory will not be
+ * reallocated, and function can end immediately - this is
+ * the best possible case, since no memory allocation needs
+ * to be done */
p_vout->p_subpicture[i_subpic].i_status = RESERVED_SUBPICTURE;
#ifdef DEBUG_VIDEO
intf_DbgMsg("subpicture %p (in destroyed subpicture slot)\n",
/* If no free subpicture is available, use a destroyed subpicture */
if( (p_free_subpic == NULL) && (p_destroyed_subpic != NULL ) )
{
- /* No free subpicture or matching destroyed subpicture has been found, but
- * a destroyed subpicture is still avalaible */
+ /* No free subpicture or matching destroyed subpicture has been
+ * found, but a destroyed subpicture is still avalaible */
free( p_destroyed_subpic->p_data );
p_free_subpic = p_destroyed_subpic;
}
}
}
/*
- * Find the subpicture to display - this operation does not need lock, since
- * only READY_SUBPICTURES are handled. If no picture has been selected,
- * display_date will depend on the subpicture
+ * Find the subpictures to display - this operation does not need
+ * lock, since only READY_SUBPICTURE are handled. If no picture
+ * has been selected, display_date will depend on the subpicture
*/
- /* XXX?? */
+ /* FIXME: we should find *all* subpictures to display, and
+ * check their displaying date as well */
+ for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++ )
+ {
+ if( p_vout->p_subpicture[i_index].i_status == READY_SUBPICTURE )
+ {
+ p_subpic = &p_vout->p_subpicture[i_index];
+ break;
+ }
+ }
/*
* Perform rendering, sleep and display rendered picture
}
/* Remove subpicture from heap */
- vlc_mutex_lock( &p_vout->subpicture_lock );
+ /*vlc_mutex_lock( &p_vout->subpicture_lock );
p_subpic->i_status = DESTROYED_SUBPICTURE;
- vlc_mutex_unlock( &p_vout->subpicture_lock );
+ vlc_mutex_unlock( &p_vout->subpicture_lock );*/
}
}
}
/* Remove subpicture from heap */
- vlc_mutex_lock( &p_vout->subpicture_lock );
+ /*vlc_mutex_lock( &p_vout->subpicture_lock );
p_subpic->i_status = DESTROYED_SUBPICTURE;
- vlc_mutex_unlock( &p_vout->subpicture_lock );
+ vlc_mutex_unlock( &p_vout->subpicture_lock );*/
}
else if( p_vout->b_active ) /* idle or interface screen alone */
{
switch( p_subpic->i_type )
{
+ case DVD_SUBPICTURE: /* DVD subpicture unit */
+ vout_RenderSPU( p_subpic->p_data, p_subpic->type.spu.i_offset,
+ p_vout->p_buffer[ p_vout->i_buffer_index ].p_data,
+ p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line );
+ break;
case TEXT_SUBPICTURE: /* single line text */
/* Select default font if not specified */
p_font = p_subpic->type.text.p_font;
p_font = p_vout->p_default_font;
}
- /* Computes text size (width and height fields are ignored) and print it */
+ /* Compute text size (width and height fields are ignored)
+ * and print it */
vout_TextSize( p_font, p_subpic->type.text.i_style, p_subpic->p_data, &i_width, &i_height );
if( !Align( p_vout, &p_subpic->i_x, &p_subpic->i_y, i_width, i_height,
p_subpic->i_horizontal_align, p_subpic->i_vertical_align ) )
--- /dev/null
+/*****************************************************************************
+ * video_spu.h : DVD subpicture units functions
+ *****************************************************************************
+ * Copyright (C) 1999, 2000 VideoLAN
+ *
+ * Authors:
+ *
+ * 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-1307, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+#include "defs.h"
+
+#include <stdio.h>
+
+#include "config.h"
+#include "common.h"
+#include "video_spu.h"
+
+#include "intf_msg.h"
+
+typedef struct spu_s
+{
+ int i_id;
+ byte_t *p_data;
+
+ int x;
+ int y;
+ int width;
+ int height;
+
+} spu_t;
+
+static int NewLine ( spu_t *p_spu, int *i_id );
+static int PutPixel ( spu_t *p_spu, int len, u8 color );
+
+/* i = get_nibble(); */
+#define GET_NIBBLE( i ) \
+ if( b_aligned ) \
+ { \
+ i_next = *p_dest[i_id]; \
+ /*printf("%.1x", i_next >> 4);*/ \
+ p_dest[ i_id ]++; \
+ b_aligned = 0; \
+ i = i_next >> 4; \
+ } \
+ else \
+ { \
+ b_aligned = 1; \
+ /*printf("%.1x", i_next & 0xf);*/ \
+ i = i_next & 0xf; \
+ }
+
+/* i = j + get_nibble(); */
+#define ADD_NIBBLE( i, j ) \
+ if( b_aligned ) \
+ { \
+ i_next = *p_dest[i_id]; \
+ /*printf("%.1x", i_next >> 4);*/ \
+ p_dest[ i_id ]++; \
+ b_aligned = 0; \
+ i = (j) + (i_next >> 4); \
+ } \
+ else \
+ { \
+ b_aligned = 1; \
+ /*printf("%.1x", i_next & 0xf);*/ \
+ i = (j) + (i_next & 0xf); \
+ }
+
+/*****************************************************************************
+ * vout_RenderSPU: draws an SPU on a picture
+ *****************************************************************************
+ *
+ *****************************************************************************/
+void vout_RenderSPU( byte_t *p_data, int p_offset[2], byte_t *p_pic,
+ int i_bytes_per_pixel, int i_bytes_per_line )
+{
+ int i_code = 0x00;
+ int i_next = 0;
+ int i_id = 0;
+ boolean_t b_aligned = 1;
+ byte_t *p_dest[2];
+ spu_t spu;
+
+ p_dest[0] = p_data + p_offset[0];
+ p_dest[1] = p_data + p_offset[1];
+
+ spu.x = 0;
+ spu.y = 0;
+ spu.width = 720;
+ spu.height = 576;
+ spu.p_data = p_pic;
+
+ while( p_dest[0] < p_data + p_offset[1] + 2 )
+ {
+ GET_NIBBLE( i_code );
+
+ if( i_code >= 0x04 )
+ {
+ found_code:
+ if( PutPixel( &spu, i_code >> 2, i_code & 3 ) < 0 )
+ return;
+
+ if( spu.x >= spu.width )
+ {
+ /* byte-align the stream */
+ b_aligned = 1;
+ /* finish the line */
+ NewLine( &spu, &i_id );
+ }
+ continue;
+ }
+
+ ADD_NIBBLE( i_code, (i_code << 4) );
+ if( i_code >= 0x10 ) /* 1x .. 3x */
+ goto found_code;
+
+ ADD_NIBBLE( i_code, (i_code << 4) );
+ if( i_code >= 0x40 ) /* 04x .. 0fx */
+ goto found_code;
+
+ ADD_NIBBLE( i_code, (i_code << 4) );
+ if( i_code >= 0x100 ) /* 01xx .. 03xx */
+ goto found_code;
+
+ /* 00xx - should only happen for 00 00 */
+ if( !b_aligned )
+ {
+ ADD_NIBBLE( i_code, (i_code << 4) );
+ }
+
+ if( i_code )
+ {
+ intf_DbgMsg( "video_spu: unknown code 0x%x "
+ "(dest %x side %x, x=%d, y=%d)\n",
+ i_code, p_dest[i_id], i_id, spu.x, spu.y );
+ if( NewLine( &spu, &i_id ) < 0 )
+ return;
+ continue;
+ }
+
+ /* aligned 00 00 */
+ if( NewLine( &spu, &i_id ) < 0 )
+ return;
+ }
+}
+
+static int NewLine( spu_t *p_spu, int *i_id )
+{
+ int i_ret = PutPixel( p_spu, p_spu->width - p_spu->x, 0 );
+
+ p_spu->x = 0;
+ p_spu->y++;
+ *i_id = 1 - *i_id;
+
+ return i_ret;
+}
+
+static int PutPixel ( spu_t *p_spu, int i_len, u8 i_color )
+{
+ //static int p_palette[4] = { 0x0000, 0xfef8, 0x7777, 0xffff };
+ static int p_palette[4] = { 0x0000, 0xffff, 0x0000, 0xffff };
+
+ if( (i_len + p_spu->x + p_spu->y * p_spu->width)
+ > p_spu->height * p_spu->width )
+ {
+ intf_DbgMsg ( "video_spu: trying to draw beyond memory area! %d %d\n",
+ i_len, p_spu->height * p_spu->width
+ - ( i_len + p_spu->x + p_spu->y * p_spu->width) );
+ p_spu->x += i_len;
+ return -1;
+ }
+ else
+ {
+
+ if( i_color > 0x0f )
+ intf_DbgMsg( "video_spu: invalid color\n" );
+
+ if( i_color )
+ {
+ u8 *p_target
+ = &p_spu->p_data[2 * ( p_spu->x + p_spu->y * p_spu->width ) ];
+
+ memset( p_target, p_palette[i_color], 2 * i_len );
+ }
+ p_spu->x += i_len;
+ }
+
+ return 0;
+}
+
--- /dev/null
+/*****************************************************************************
+ * video_spu.h : DVD subpicture units functions
+ *****************************************************************************
+ * Copyright (C) 1999, 2000 VideoLAN
+ *
+ * Authors:
+ *
+ * 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-1307, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Prototypes
+ *****************************************************************************/
+void vout_RenderSPU ( byte_t *p_data, int p_offset[2], byte_t *p_pic,
+ int i_bytes_per_pixel, int i_bytes_per_line );