Commit 53772811 authored by Vincent Penquerc'h's avatar Vincent Penquerc'h Committed by Rémi Denis-Courmont

basic support for Kate streams as subtitles

Signed-off-by: default avatarRémi Denis-Courmont <rem@videolan.org>
parent 36f89cb8
...@@ -4004,6 +4004,39 @@ then ...@@ -4004,6 +4004,39 @@ then
VLC_ADD_PLUGIN([cmml]) VLC_ADD_PLUGIN([cmml])
fi fi
dnl
dnl kate decoder plugin
dnl
AC_ARG_ENABLE(kate,
[ --enable-kate kate codec (default enabled)])
if test "${enable_kate}" != "no"; then
PKG_CHECK_MODULES(KATE,[kate >= 0.1.1], [
VLC_ADD_PLUGINS([kate])
VLC_ADD_CFLAGS([kate],[$KATE_CFLAGS])
VLC_ADD_LIBS([kate],[$KATE_LIBS]) ],[
AC_CHECK_HEADERS(kate/kate.h, [
AC_CHECK_LIB(kate, kate_decode_init, [
if test "${SYS}" = "mingw32"; then
VLC_ADD_PLUGINS([kate])
else
VLC_ADD_BUILTINS([kate])
fi
kate_libs="-lkate -logg"
VLC_ADD_LDFLAGS([kate],[${kate_libs}]) ],[
if test "${enable_kate}" == "yes"; then
AC_MSG_ERROR([libkate doesn't appear to be installed on your system.
You also need to check that you have a libogg posterior to the 1.0 release.])
fi],
[-lkate -logg])
],[
if test "${enable_kate}" == "yes"; then
AC_MSG_ERROR([libkate headers do not appear to be installed on your system.
You also need to check that you have a libogg posterior to the 1.0 release.])
fi
])
])
fi
dnl dnl
dnl Video plugins dnl Video plugins
......
...@@ -160,6 +160,7 @@ $Id$ ...@@ -160,6 +160,7 @@ $Id$
* inhibit: preventing the computer from suspending * inhibit: preventing the computer from suspending
* invert: inverse video filter. * invert: inverse video filter.
* jack: jack server audio output * jack: jack server audio output
* kate: kate text bitstream decoder
* libmpeg2: Mpeg2 video decoder using libmpeg2 * libmpeg2: Mpeg2 video decoder using libmpeg2
* linear_resampler: linear audio resampler * linear_resampler: linear audio resampler
* lirc: Linux infrared control module * lirc: Linux infrared control module
......
...@@ -33,3 +33,4 @@ SOURCES_csri = csri.c ...@@ -33,3 +33,4 @@ SOURCES_csri = csri.c
SOURCES_cdg = cdg.c SOURCES_cdg = cdg.c
SOURCES_fluidsynth = fluidsynth.c SOURCES_fluidsynth = fluidsynth.c
SOURCES_cc = cc.c cc.h SOURCES_cc = cc.c cc.h
SOURCES_kate = kate.c
This diff is collapsed.
...@@ -2550,6 +2550,58 @@ bool matroska_segment_c::Select( mtime_t i_start_time ) ...@@ -2550,6 +2550,58 @@ bool matroska_segment_c::Select( mtime_t i_start_time )
} }
tracks[i_track]->fmt.audio.i_blockalign = ( tracks[i_track]->fmt.audio.i_bitspersample + 7 ) / 8 * tracks[i_track]->fmt.audio.i_channels; tracks[i_track]->fmt.audio.i_blockalign = ( tracks[i_track]->fmt.audio.i_bitspersample + 7 ) / 8 * tracks[i_track]->fmt.audio.i_channels;
} }
#if 0
/* disabled due to the potential "S_KATE" namespace issue */
else if( !strcmp( tracks[i_track]->psz_codec, "S_KATE" ) )
{
int i, i_offset = 1, *i_size, i_extra, num_headers, size_so_far;
uint8_t *p_extra;
tracks[i_track]->fmt.i_codec = VLC_FOURCC( 'k', 'a', 't', 'e' );
tracks[i_track]->fmt.subs.psz_encoding = strdup( "UTF-8" );
/* Recover the number of headers to expect */
num_headers = tracks[i_track]->p_extra_data[0]+1;
msg_Dbg( &sys.demuxer, "kate in mkv detected: %d headers in %u bytes",
num_headers, tracks[i_track]->i_extra_data);
/* this won't overflow the stack as is can allocate only 1020 bytes max */
i_size = (int*)alloca(num_headers*sizeof(int));
/* Split the headers */
size_so_far = 0;
for( i = 0; i < num_headers-1; i++ )
{
i_size[i] = 0;
while( i_offset < tracks[i_track]->i_extra_data )
{
i_size[i] += tracks[i_track]->p_extra_data[i_offset];
if( tracks[i_track]->p_extra_data[i_offset++] != 0xff ) break;
}
msg_Dbg( &sys.demuxer, "kate header %d is %d bytes", i, i_size[i]);
size_so_far += i_size[i];
}
i_size[num_headers-1] = tracks[i_track]->i_extra_data - (size_so_far+i_offset);
msg_Dbg( &sys.demuxer, "kate last header (%d) is %d bytes", num_headers-1, i_size[num_headers-1]);
tracks[i_track]->fmt.i_extra = 1 + num_headers * 2 + size_so_far + i_size[num_headers-1];
tracks[i_track]->fmt.p_extra = malloc( tracks[i_track]->fmt.i_extra );
p_extra = (uint8_t *)tracks[i_track]->fmt.p_extra;
i_extra = 0;
*(p_extra++) = num_headers;
++i_extra;
for( i = 0; i < num_headers; i++ )
{
*(p_extra++) = i_size[i] >> 8;
*(p_extra++) = i_size[i] & 0xFF;
memcpy( p_extra, tracks[i_track]->p_extra_data + i_offset + i_extra-1,
i_size[i] );
p_extra += i_size[i];
i_extra += i_size[i];
}
}
#endif
else if( !strcmp( tracks[i_track]->psz_codec, "S_TEXT/UTF8" ) ) else if( !strcmp( tracks[i_track]->psz_codec, "S_TEXT/UTF8" ) )
{ {
tracks[i_track]->fmt.i_codec = VLC_FOURCC( 's', 'u', 'b', 't' ); tracks[i_track]->fmt.i_codec = VLC_FOURCC( 's', 'u', 'b', 't' );
......
...@@ -85,7 +85,10 @@ typedef struct logical_stream_s ...@@ -85,7 +85,10 @@ typedef struct logical_stream_s
/* Misc */ /* Misc */
int b_reinit; int b_reinit;
int i_theora_keyframe_granule_shift; int i_granule_shift;
/* kate streams have the number of headers in the ID header */
int i_kate_num_headers;
/* for Annodex logical bitstreams */ /* for Annodex logical bitstreams */
int secondary_header_packets; int secondary_header_packets;
...@@ -175,6 +178,7 @@ static void Ogg_EndOfStream( demux_t *p_demux ); ...@@ -175,6 +178,7 @@ static void Ogg_EndOfStream( demux_t *p_demux );
static void Ogg_ReadTheoraHeader( logical_stream_t *, ogg_packet * ); static void Ogg_ReadTheoraHeader( logical_stream_t *, ogg_packet * );
static void Ogg_ReadVorbisHeader( logical_stream_t *, ogg_packet * ); static void Ogg_ReadVorbisHeader( logical_stream_t *, ogg_packet * );
static void Ogg_ReadSpeexHeader( logical_stream_t *, ogg_packet * ); static void Ogg_ReadSpeexHeader( logical_stream_t *, ogg_packet * );
static void Ogg_ReadKateHeader( logical_stream_t *, ogg_packet * );
static void Ogg_ReadFlacHeader( demux_t *, logical_stream_t *, ogg_packet * ); static void Ogg_ReadFlacHeader( demux_t *, logical_stream_t *, ogg_packet * );
static void Ogg_ReadAnnodexHeader( vlc_object_t *, logical_stream_t *, ogg_packet * ); static void Ogg_ReadAnnodexHeader( vlc_object_t *, logical_stream_t *, ogg_packet * );
...@@ -443,21 +447,22 @@ static void Ogg_UpdatePCR( logical_stream_t *p_stream, ...@@ -443,21 +447,22 @@ static void Ogg_UpdatePCR( logical_stream_t *p_stream,
/* Convert the granulepos into a pcr */ /* Convert the granulepos into a pcr */
if( p_oggpacket->granulepos >= 0 ) if( p_oggpacket->granulepos >= 0 )
{ {
if( p_stream->fmt.i_codec != VLC_FOURCC( 't','h','e','o' ) ) if( p_stream->fmt.i_codec == VLC_FOURCC( 't','h','e','o' ) ||
{ p_stream->fmt.i_codec == VLC_FOURCC( 'k','a','t','e' ) )
p_stream->i_pcr = p_oggpacket->granulepos * INT64_C(1000000)
/ p_stream->f_rate;
}
else
{ {
ogg_int64_t iframe = p_oggpacket->granulepos >> ogg_int64_t iframe = p_oggpacket->granulepos >>
p_stream->i_theora_keyframe_granule_shift; p_stream->i_granule_shift;
ogg_int64_t pframe = p_oggpacket->granulepos - ogg_int64_t pframe = p_oggpacket->granulepos -
( iframe << p_stream->i_theora_keyframe_granule_shift ); ( iframe << p_stream->i_granule_shift );
p_stream->i_pcr = ( iframe + pframe ) * INT64_C(1000000) p_stream->i_pcr = ( iframe + pframe ) * INT64_C(1000000)
/ p_stream->f_rate; / p_stream->f_rate;
} }
else
{
p_stream->i_pcr = p_oggpacket->granulepos * INT64_C(1000000)
/ p_stream->f_rate;
}
p_stream->i_interpolated_pcr = p_stream->i_pcr; p_stream->i_interpolated_pcr = p_stream->i_pcr;
} }
...@@ -520,6 +525,7 @@ static void Ogg_DecodePacket( demux_t *p_demux, ...@@ -520,6 +525,7 @@ static void Ogg_DecodePacket( demux_t *p_demux,
{ {
uint8_t *p_extra; uint8_t *p_extra;
bool b_store_size = true; bool b_store_size = true;
bool b_store_num_headers = false;
p_stream->i_packets_backup++; p_stream->i_packets_backup++;
switch( p_stream->fmt.i_codec ) switch( p_stream->fmt.i_codec )
...@@ -548,6 +554,12 @@ static void Ogg_DecodePacket( demux_t *p_demux, ...@@ -548,6 +554,12 @@ static void Ogg_DecodePacket( demux_t *p_demux,
b_store_size = false; b_store_size = false;
break; break;
case VLC_FOURCC( 'k','a','t','e' ):
if( p_stream->i_packets_backup == 1)
b_store_num_headers = true;
if( p_stream->i_packets_backup == p_stream->i_kate_num_headers ) p_stream->b_force_backup = 0;
break;
default: default:
p_stream->b_force_backup = 0; p_stream->b_force_backup = 0;
break; break;
...@@ -556,15 +568,21 @@ static void Ogg_DecodePacket( demux_t *p_demux, ...@@ -556,15 +568,21 @@ static void Ogg_DecodePacket( demux_t *p_demux,
/* Backup the ogg packet (likely an header packet) */ /* Backup the ogg packet (likely an header packet) */
p_stream->p_headers = p_stream->p_headers =
realloc( p_stream->p_headers, p_stream->i_headers + realloc( p_stream->p_headers, p_stream->i_headers +
p_oggpacket->bytes + (b_store_size ? 2 : 0) ); p_oggpacket->bytes + (b_store_size ? 2 : 0) + (b_store_num_headers ? 1 : 0) );
p_extra = p_stream->p_headers + p_stream->i_headers; p_extra = p_stream->p_headers + p_stream->i_headers;
if( b_store_num_headers )
{
/* Kate streams store the number of headers in the first header,
so we can't just test for 3 as Vorbis/Theora */
*(p_extra++) = p_stream->i_kate_num_headers;
}
if( b_store_size ) if( b_store_size )
{ {
*(p_extra++) = p_oggpacket->bytes >> 8; *(p_extra++) = p_oggpacket->bytes >> 8;
*(p_extra++) = p_oggpacket->bytes & 0xFF; *(p_extra++) = p_oggpacket->bytes & 0xFF;
} }
memcpy( p_extra, p_oggpacket->packet, p_oggpacket->bytes ); memcpy( p_extra, p_oggpacket->packet, p_oggpacket->bytes );
p_stream->i_headers += p_oggpacket->bytes + (b_store_size ? 2 : 0); p_stream->i_headers += p_oggpacket->bytes + (b_store_size ? 2 : 0) + (b_store_num_headers ? 1 : 0);
if( !p_stream->b_force_backup ) if( !p_stream->b_force_backup )
{ {
...@@ -673,7 +691,8 @@ static void Ogg_DecodePacket( demux_t *p_demux, ...@@ -673,7 +691,8 @@ static void Ogg_DecodePacket( demux_t *p_demux,
p_stream->fmt.i_codec != VLC_FOURCC( 'f','l','a','c' ) && p_stream->fmt.i_codec != VLC_FOURCC( 'f','l','a','c' ) &&
p_stream->fmt.i_codec != VLC_FOURCC( 't','a','r','k' ) && p_stream->fmt.i_codec != VLC_FOURCC( 't','a','r','k' ) &&
p_stream->fmt.i_codec != VLC_FOURCC( 't','h','e','o' ) && p_stream->fmt.i_codec != VLC_FOURCC( 't','h','e','o' ) &&
p_stream->fmt.i_codec != VLC_FOURCC( 'c','m','m','l' ) ) p_stream->fmt.i_codec != VLC_FOURCC( 'c','m','m','l' ) &&
p_stream->fmt.i_codec != VLC_FOURCC( 'k','a','t','e' ) )
{ {
/* We remove the header from the packet */ /* We remove the header from the packet */
i_header_len = (*p_oggpacket->packet & PACKET_LEN_BITS01) >> 6; i_header_len = (*p_oggpacket->packet & PACKET_LEN_BITS01) >> 6;
...@@ -877,6 +896,13 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux ) ...@@ -877,6 +896,13 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux )
Ogg_ReadAnnodexHeader( VLC_OBJECT(p_demux), p_stream, Ogg_ReadAnnodexHeader( VLC_OBJECT(p_demux), p_stream,
&oggpacket ); &oggpacket );
} }
/* Check for Kate header */
else if( oggpacket.bytes >= 9 &&
! memcmp( &oggpacket.packet[1], "kate\0\0\0\0", 8 ) )
{
Ogg_ReadKateHeader( p_stream, &oggpacket );
msg_Dbg( p_demux, "found kate header" );
}
else if( oggpacket.bytes >= 142 && else if( oggpacket.bytes >= 142 &&
!memcmp( &oggpacket.packet[1], !memcmp( &oggpacket.packet[1],
"Direct Show Samples embedded in Ogg", 35 )) "Direct Show Samples embedded in Ogg", 35 ))
...@@ -1157,6 +1183,7 @@ static int Ogg_BeginningOfStream( demux_t *p_demux ) ...@@ -1157,6 +1183,7 @@ static int Ogg_BeginningOfStream( demux_t *p_demux )
#define p_stream p_ogg->pp_stream[i_stream] #define p_stream p_ogg->pp_stream[i_stream]
p_stream->p_es = es_out_Add( p_demux->out, &p_stream->fmt ); p_stream->p_es = es_out_Add( p_demux->out, &p_stream->fmt );
// TODO: something to do here ?
if( p_stream->fmt.i_codec == VLC_FOURCC('c','m','m','l') ) if( p_stream->fmt.i_codec == VLC_FOURCC('c','m','m','l') )
{ {
/* Set the CMML stream active */ /* Set the CMML stream active */
...@@ -1249,11 +1276,11 @@ static void Ogg_ReadTheoraHeader( logical_stream_t *p_stream, ...@@ -1249,11 +1276,11 @@ static void Ogg_ReadTheoraHeader( logical_stream_t *p_stream,
i_keyframe_frequency_force = 1 << bs_read( &bitstream, 5 ); i_keyframe_frequency_force = 1 << bs_read( &bitstream, 5 );
/* granule_shift = i_log( frequency_force -1 ) */ /* granule_shift = i_log( frequency_force -1 ) */
p_stream->i_theora_keyframe_granule_shift = 0; p_stream->i_granule_shift = 0;
i_keyframe_frequency_force--; i_keyframe_frequency_force--;
while( i_keyframe_frequency_force ) while( i_keyframe_frequency_force )
{ {
p_stream->i_theora_keyframe_granule_shift++; p_stream->i_granule_shift++;
i_keyframe_frequency_force >>= 1; i_keyframe_frequency_force >>= 1;
} }
...@@ -1340,6 +1367,59 @@ static void Ogg_ReadFlacHeader( demux_t *p_demux, logical_stream_t *p_stream, ...@@ -1340,6 +1367,59 @@ static void Ogg_ReadFlacHeader( demux_t *p_demux, logical_stream_t *p_stream,
} }
} }
static void Ogg_ReadKateHeader( logical_stream_t *p_stream,
ogg_packet *p_oggpacket )
{
oggpack_buffer opb;
int32_t gnum;
int32_t gden;
int n;
p_stream->fmt.i_cat = SPU_ES;
p_stream->fmt.i_codec = VLC_FOURCC( 'k','a','t','e' );
/* Signal that we want to keep a backup of the kate
* stream headers. They will be used when switching between
* kate streams. */
p_stream->b_force_backup = 1;
/* Cheat and get additionnal info ;) */
oggpack_readinit( &opb, p_oggpacket->packet, p_oggpacket->bytes);
oggpack_adv( &opb, 11*8 ); /* packet type, kate magic, version */
p_stream->i_kate_num_headers = oggpack_read( &opb, 8 );
oggpack_adv( &opb, 3*8 );
p_stream->i_granule_shift = oggpack_read( &opb, 8 );
oggpack_adv( &opb, 8*8 ); /* reserved */
gnum = oggpack_read( &opb, 32 );
gden = oggpack_read( &opb, 32 );
p_stream->f_rate = (double)gnum/gden;
p_stream->fmt.psz_language = malloc(16);
if (p_stream->fmt.psz_language)
{
for (n=0;n<16;++n)
p_stream->fmt.psz_language[n] = oggpack_read(&opb,8);
p_stream->fmt.psz_language[15] = 0; /* just in case */
}
else
{
for (n=0;n<16;++n)
oggpack_read(&opb,8);
}
p_stream->fmt.psz_description = malloc(16);
if (p_stream->fmt.psz_description)
{
for (n=0;n<16;++n)
p_stream->fmt.psz_description[n] = oggpack_read(&opb,8);
p_stream->fmt.psz_description[15] = 0; /* just in case */
}
else
{
for (n=0;n<16;++n)
oggpack_read(&opb,8);
}
}
static void Ogg_ReadAnnodexHeader( vlc_object_t *p_this, static void Ogg_ReadAnnodexHeader( vlc_object_t *p_this,
logical_stream_t *p_stream, logical_stream_t *p_stream,
ogg_packet *p_oggpacket ) ogg_packet *p_oggpacket )
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment