Commit 3482c341 authored by Sam Hocevar's avatar Sam Hocevar

NEWS:

 . encore un peu de parsage de sous-titres
 . affichage des sous-titres.

BUGS:
 . �a segfaulte toujours au moment o� on quitte, mais c'est le probl�me
  habituel, �a sera r�gl�.
 . pour le moment ils sont en noir et blanc, parce qu'il faut aller
  chercher cette putain de palette dans les .IFO du dvd et que pour
  l'instant j'ai la flemme
 . les sous-titres ne sont pas affich�s comme il faut si la largeur
  de l'�cran n'est pas 720.
 . dimensions par d�faut mises � 720x576 (format DVD) au lieu de 640x480
  pour la raison �voqu�e ci-dessus. mais �a sera r�gl� bient�t.
 . pas de gestion de transparence, coordonn�es, fade in/fade out
 . pas de gestion de date : le sous-titre est affich� d�s qu'il est re�u
  et n'est pas effac� tant qu'on en a pas re�u un nouveau.
parent 3b8adcbd
...@@ -222,6 +222,7 @@ audio_output_obj = audio_output/audio_output.o ...@@ -222,6 +222,7 @@ audio_output_obj = audio_output/audio_output.o
video_output_obj = video_output/video_output.o \ video_output_obj = video_output/video_output.o \
video_output/video_text.o \ video_output/video_text.o \
video_output/video_spu.o \
video_output/video_yuv.o video_output/video_yuv.o
ac3_decoder_obj = ac3_decoder/ac3_decoder_thread.o \ ac3_decoder_obj = ac3_decoder/ac3_decoder_thread.o \
......
...@@ -109,7 +109,7 @@ ...@@ -109,7 +109,7 @@
* Decoders FIFO configuration * 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 #define FIFO_SIZE 1023
...@@ -266,8 +266,8 @@ ...@@ -266,8 +266,8 @@
* standard width and height broadcasted MPEG-2 streams */ * standard width and height broadcasted MPEG-2 streams */
#define VOUT_WIDTH_VAR "vlc_width" #define VOUT_WIDTH_VAR "vlc_width"
#define VOUT_HEIGHT_VAR "vlc_height" #define VOUT_HEIGHT_VAR "vlc_height"
#define VOUT_WIDTH_DEFAULT 640 #define VOUT_WIDTH_DEFAULT 720
#define VOUT_HEIGHT_DEFAULT 480 #define VOUT_HEIGHT_DEFAULT 576
/* Maximum width of a scaled source picture - this should be relatively high, /* Maximum width of a scaled source picture - this should be relatively high,
* since higher stream values will result in no display at all. */ * since higher stream values will result in no display at all. */
......
...@@ -147,6 +147,11 @@ typedef struct subpicture_s ...@@ -147,6 +147,11 @@ typedef struct subpicture_s
u32 i_border_color; /* border color */ u32 i_border_color; /* border color */
u32 i_bg_color; /* background color */ u32 i_bg_color; /* background color */
} text; } text;
/* DVD subpicture units properties */
struct
{
int i_offset[2]; /* byte offsets to data */
} spu;
} type; } type;
/* Subpicture data, format depends of type - data can always be freely /* Subpicture data, format depends of type - data can always be freely
......
...@@ -57,7 +57,7 @@ typedef struct vout_yuv_s ...@@ -57,7 +57,7 @@ typedef struct vout_yuv_s
vout_yuv_convert_t * p_Convert422; /* YUV 4:2:2 converter */ vout_yuv_convert_t * p_Convert422; /* YUV 4:2:2 converter */
vout_yuv_convert_t * p_Convert444; /* YUV 4:4:4 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 */ void * p_base; /* base for all conversion tables */
union union
{ {
...@@ -69,7 +69,7 @@ typedef struct vout_yuv_s ...@@ -69,7 +69,7 @@ typedef struct vout_yuv_s
u32 * p_rgb32; /* RGB 32 bits table */ u32 * p_rgb32; /* RGB 32 bits table */
} yuv; } yuv;
/* Temporary convertion buffer and offset array */ /* Temporary conversion buffer and offset array */
void * p_buffer; /* convertion buffer */ void * p_buffer; /* convertion buffer */
int * p_offset; /* offset array */ int * p_offset; /* offset array */
} vout_yuv_t; } vout_yuv_t;
......
...@@ -1226,8 +1226,9 @@ static __inline__ void input_ParsePES( input_thread_t *p_input, ...@@ -1226,8 +1226,9 @@ static __inline__ void input_ParsePES( input_thread_t *p_input,
break; break;
case DVD_SPU_ES: case DVD_SPU_ES:
/* we skip 4 bytes at the beginning of the subpicture payload */ /* we skip the first byte at the beginning of the
//p_ts->i_payload_start += 4; * subpicture payload, it only contains the SPU ID. */
p_ts->i_payload_start++;
p_fifo = &(((spudec_thread_t *)(p_es_descriptor->p_dec))->fifo); p_fifo = &(((spudec_thread_t *)(p_es_descriptor->p_dec))->fifo);
break; break;
......
...@@ -202,141 +202,143 @@ static void RunThread( spudec_thread_t *p_spudec ) ...@@ -202,141 +202,143 @@ static void RunThread( spudec_thread_t *p_spudec )
*/ */
while( (!p_spudec->b_die) && (!p_spudec->b_error) ) while( (!p_spudec->b_die) && (!p_spudec->b_error) )
{ {
int i_spu_id;
int i_packet_size; int i_packet_size;
int i_rle_size; int i_rle_size;
int i_index; int i_index;
int i_pes_size; int i_pes_size;
boolean_t b_finished; int i_pes_count;
boolean_t b_finished;
unsigned char * p_spu_data; unsigned char * p_spu_data;
subpicture_t * p_spu; subpicture_t * p_spu = NULL;
while( !DECODER_FIFO_ISEMPTY(p_spudec->fifo) ) 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 do
{ {
i_spu_id = GetByte( &p_spudec->bit_stream ); i_packet_size = GetByte( &p_spudec->bit_stream );
} }
while( (i_spu_id & 0xe0) != 0x20 ); while( i_packet_size == 0xff );
i_pes_size = DECODER_FIFO_START(p_spudec->fifo)->i_pes_size;
printf( "got it. size = 0x%.4x\n", i_pes_size );
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; /* get the useful PES size (real size - 10) */
i_pes_size = DECODER_FIFO_START(p_spudec->fifo)->i_pes_size - 9;
GetWord( i_packet_size ); i_pes_count = 1;
printf( "total size: 0x%.4x\n", i_packet_size );
/* the RLE stuff size */
GetWord( i_rle_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 ); 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) /* getting the RLE part */
&& ((i_spu_id & 0xe0) == 0x20) ) while( i_index++ < i_rle_size )
{
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 )
{ {
//*p_spu_data++ = GetByte( &p_spudec->bit_stream ); /* skip the leading byte of a PES */
if (i_index == i_pes_size) printf ("\n **** \n"); if ( !((i_index + 3) % i_pes_size) )
/* kludge ??? */ {
if (i_index == i_pes_size) printf( "%.2x", *p_spu_data++ = GetByte( &p_spudec->bit_stream ) ); i_pes_count++;
printf( "%.2x", *p_spu_data++ = GetByte( &p_spudec->bit_stream ) ); }
*p_spu_data++ = GetByte( &p_spudec->bit_stream );
} }
printf( "\nindex/size %i/%i\n", i_index, i_pes_size );
//printf( "\n" );
b_finished = 0; /* getting the control part */
printf( "control stuff\n" ); b_finished = 0;
do do
{ {
unsigned char i_cmd; unsigned char i_cmd;
unsigned int i_word; unsigned int i_word;
/* the date */
GetWord( i_word ); GetWord( i_word );
printf( "date: 0x%.4x\n", i_word );
/* next offset, no next offset if == i_index-5 */
GetWord( i_word ); 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_cmd = GetByte( &p_spudec->bit_stream );
i_index++; i_index++;
switch(i_cmd) switch( i_cmd )
{ {
case 0x00: case 0x00:
printf( " 00 (display now)\n" ); /* 00 (display now) */
break; break;
case 0x01: case 0x01:
printf( " 01 (start displaying)\n" ); /* 01 (start displaying) */
break; break;
case 0x02: case 0x02:
printf( " 02 (stop displaying)\n" ); /* 02 (stop displaying) */
break; break;
case 0x03: case 0x03:
GetWord( i_word ); /* 03xxxx (palette) */
printf( " 03 (palette) - %.4x\n", i_word ); GetWord( i_word );
break; break;
case 0x04: case 0x04:
GetWord( i_word ); /* 04xxxx (alpha channel) */
printf( " 04 (alpha channel) - %.4x\n", i_word ); GetWord( i_word );
break; break;
case 0x05: case 0x05:
GetWord( i_word ); /* 05xxxyyyxxxyyy (coordinates) */
printf( " 05 (coordinates) - %.4x", i_word ); GetWord( i_word );
GetWord( i_word ); GetWord( i_word );
printf( "%.4x", i_word ); GetWord( i_word );
GetWord( i_word );
printf( "%.4x\n", i_word );
break; break;
case 0x06: case 0x06:
GetWord( i_word ); /* 06xxxxyyyy (byte offsets) */
printf( " 06 (byte offsets) - %.4x", i_word ); GetWord( i_word );
GetWord( i_word ); p_spu->type.spu.i_offset[0] = i_word - 4;
printf( "%.4x\n", i_word ); GetWord( i_word );
p_spu->type.spu.i_offset[1] = i_word - 4;
break; break;
case 0xff: case 0xff:
printf( " ff (end)\n" ); /* ff (end) */
break; break;
default: default:
printf( " %.2x (unknown command)\n", i_cmd ); /* ?? (unknown command) */
break; break;
} }
}
} while( i_cmd != 0xff );
while( i_cmd != 0xff ); }
while( !b_finished );
} /* SPU is finished - we can display it */
while( !b_finished ); vout_DisplaySubPicture( p_spudec->p_vout, p_spu );
printf( "control stuff finished\n" );
printf( "*** end of PES !\n\n" );
} }
else else
{ {
printf( "*** invalid PES !\n\n" ); /* Unexpected PES packet - trash it */
/* trash the PES packet */ vlc_mutex_lock( &p_spudec->fifo.data_lock );
/*vlc_mutex_lock( &p_spudec->fifo.data_lock );
input_NetlistFreePES( p_spudec->bit_stream.p_input, input_NetlistFreePES( p_spudec->bit_stream.p_input,
DECODER_FIFO_START(p_spudec->fifo) ); DECODER_FIFO_START(p_spudec->fifo) );
DECODER_FIFO_INCSTART( 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 */ /* 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 ); vlc_cond_wait( &p_spudec->fifo.data_wait, &p_spudec->fifo.data_lock );
if( p_spu ) vout_DestroySubPicture( p_spudec->p_vout, p_spu );
} }
/* /*
......
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
#include "video.h" #include "video.h"
#include "video_output.h" #include "video_output.h"
#include "video_text.h" #include "video_text.h"
#include "video_spu.h"
#include "video_yuv.h" #include "video_yuv.h"
#include "intf_msg.h" #include "intf_msg.h"
...@@ -360,9 +361,10 @@ subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type, ...@@ -360,9 +361,10 @@ subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type,
if( (p_vout->p_subpicture[i_subpic].i_type == i_type) && if( (p_vout->p_subpicture[i_subpic].i_type == i_type) &&
(p_vout->p_subpicture[i_subpic].i_size >= i_size) ) (p_vout->p_subpicture[i_subpic].i_size >= i_size) )
{ {
/* Memory size do match or is smaller : memory will not be reallocated, /* Memory size do match or is smaller : memory will not be
* and function can end immediately - this is the best possible case, * reallocated, and function can end immediately - this is
* since no memory allocation needs to be done */ * the best possible case, since no memory allocation needs
* to be done */
p_vout->p_subpicture[i_subpic].i_status = RESERVED_SUBPICTURE; p_vout->p_subpicture[i_subpic].i_status = RESERVED_SUBPICTURE;
#ifdef DEBUG_VIDEO #ifdef DEBUG_VIDEO
intf_DbgMsg("subpicture %p (in destroyed subpicture slot)\n", intf_DbgMsg("subpicture %p (in destroyed subpicture slot)\n",
...@@ -389,8 +391,8 @@ subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type, ...@@ -389,8 +391,8 @@ subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type,
/* If no free subpicture is available, use a destroyed subpicture */ /* If no free subpicture is available, use a destroyed subpicture */
if( (p_free_subpic == NULL) && (p_destroyed_subpic != NULL ) ) if( (p_free_subpic == NULL) && (p_destroyed_subpic != NULL ) )
{ {
/* No free subpicture or matching destroyed subpicture has been found, but /* No free subpicture or matching destroyed subpicture has been
* a destroyed subpicture is still avalaible */ * found, but a destroyed subpicture is still avalaible */
free( p_destroyed_subpic->p_data ); free( p_destroyed_subpic->p_data );
p_free_subpic = p_destroyed_subpic; p_free_subpic = p_destroyed_subpic;
} }
...@@ -1021,11 +1023,20 @@ last_display_date = display_date; ...@@ -1021,11 +1023,20 @@ last_display_date = display_date;
} }
} }
/* /*
* Find the subpicture to display - this operation does not need lock, since * Find the subpictures to display - this operation does not need
* only READY_SUBPICTURES are handled. If no picture has been selected, * lock, since only READY_SUBPICTURE are handled. If no picture
* display_date will depend on the subpicture * 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 * Perform rendering, sleep and display rendered picture
...@@ -1075,9 +1086,9 @@ last_display_date = display_date; ...@@ -1075,9 +1086,9 @@ last_display_date = display_date;
} }
/* Remove subpicture from heap */ /* Remove subpicture from heap */
vlc_mutex_lock( &p_vout->subpicture_lock ); /*vlc_mutex_lock( &p_vout->subpicture_lock );
p_subpic->i_status = DESTROYED_SUBPICTURE; p_subpic->i_status = DESTROYED_SUBPICTURE;
vlc_mutex_unlock( &p_vout->subpicture_lock ); vlc_mutex_unlock( &p_vout->subpicture_lock );*/
} }
} }
...@@ -1104,9 +1115,9 @@ last_display_date = display_date; ...@@ -1104,9 +1115,9 @@ last_display_date = display_date;
} }
/* Remove subpicture from heap */ /* Remove subpicture from heap */
vlc_mutex_lock( &p_vout->subpicture_lock ); /*vlc_mutex_lock( &p_vout->subpicture_lock );
p_subpic->i_status = DESTROYED_SUBPICTURE; 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 */ else if( p_vout->b_active ) /* idle or interface screen alone */
{ {
...@@ -1816,6 +1827,11 @@ static void RenderSubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic ) ...@@ -1816,6 +1827,11 @@ static void RenderSubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic )
switch( p_subpic->i_type ) 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 */ case TEXT_SUBPICTURE: /* single line text */
/* Select default font if not specified */ /* Select default font if not specified */
p_font = p_subpic->type.text.p_font; p_font = p_subpic->type.text.p_font;
...@@ -1824,7 +1840,8 @@ static void RenderSubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic ) ...@@ -1824,7 +1840,8 @@ static void RenderSubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic )
p_font = p_vout->p_default_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 ); 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, 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 ) ) p_subpic->i_horizontal_align, p_subpic->i_vertical_align ) )
......
/*****************************************************************************
* 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 );