📄 dvbsub.c
字号:
/***************************************************************************** * dvbsub.c : DVB subtitles decoder * DVB subtitles encoder (developed for Anevia, www.anevia.com) ***************************************************************************** * Copyright (C) 2003 ANEVIA * Copyright (C) 2003-2005 VideoLAN * $Id: dvbsub.c 10585 2005-04-07 04:58:36Z rocky $ * * Authors: Gildas Bazin <gbazin@videolan.org> * Damien LUCAS <damien.lucas@anevia.com> * 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 * * FIXME: * DVB subtitles coded as strings of characters are not handled correctly. * The character codes in the string should actually be indexes refering to a * character table identified in the subtitle descriptor. *****************************************************************************/#include <vlc/vlc.h>#include <vlc/vout.h>#include <vlc/decoder.h>#include <vlc/sout.h>#include "vlc_bits.h"//#define DEBUG_DVBSUB 1/***************************************************************************** * Module descriptor. *****************************************************************************/static int Open ( vlc_object_t * );static void Close( vlc_object_t * );static subpicture_t *Decode( decoder_t *, block_t ** );static int OpenEncoder ( vlc_object_t * );static void CloseEncoder( vlc_object_t * );static block_t *Encode ( encoder_t *, subpicture_t * );vlc_module_begin(); set_description( _("DVB subtitles decoder") ); set_capability( "decoder", 50 ); set_category( CAT_INPUT ); set_subcategory( SUBCAT_INPUT_SCODEC ); set_callbacks( Open, Close );# define ENC_CFG_PREFIX "sout-dvbsub-" add_submodule(); set_description( _("DVB subtitles encoder") ); set_capability( "encoder", 100 ); set_callbacks( OpenEncoder, CloseEncoder );vlc_module_end();static const char *ppsz_enc_options[] = { NULL };/**************************************************************************** * Local structures **************************************************************************** * Those structures refer closely to the ETSI 300 743 Object model ****************************************************************************//* The object definition gives the position of the object in a region */typedef struct dvbsub_objectdef_s{ int i_id; int i_type; int i_x; int i_y; int i_fg_pc; int i_bg_pc; char *psz_text; /* for string of characters objects */} dvbsub_objectdef_t;/* The entry in the palette CLUT */typedef struct{ uint8_t Y; uint8_t Cr; uint8_t Cb; uint8_t T;} dvbsub_color_t;/* */typedef struct dvbsub_clut_s{ uint8_t i_id; uint8_t i_version; dvbsub_color_t c_2b[4]; dvbsub_color_t c_4b[16]; dvbsub_color_t c_8b[256]; struct dvbsub_clut_s *p_next;} dvbsub_clut_t;/* The Region is an aera on the image * with a list of the object definitions associated and a CLUT */typedef struct dvbsub_region_s{ int i_id; int i_version; int i_x; int i_y; int i_width; int i_height; int i_level_comp; int i_depth; int i_clut; uint8_t *p_pixbuf; int i_object_defs; dvbsub_objectdef_t *p_object_defs; struct dvbsub_region_s *p_next;} dvbsub_region_t;/* The object definition gives the position of the object in a region */typedef struct dvbsub_regiondef_s{ int i_id; int i_x; int i_y;} dvbsub_regiondef_t;/* The page defines the list of regions */typedef struct{ int i_id; int i_timeout; int i_state; int i_version; int i_region_defs; dvbsub_regiondef_t *p_region_defs;} dvbsub_page_t;struct decoder_sys_t{ bs_t bs; /* Decoder internal data */ int i_id; int i_ancillary_id; mtime_t i_pts; vlc_bool_t b_page; dvbsub_page_t *p_page; dvbsub_region_t *p_regions; dvbsub_clut_t *p_cluts; dvbsub_clut_t default_clut;};// List of different SEGMENT TYPES// According to EN 300-743, table 2#define DVBSUB_ST_PAGE_COMPOSITION 0x10#define DVBSUB_ST_REGION_COMPOSITION 0x11#define DVBSUB_ST_CLUT_DEFINITION 0x12#define DVBSUB_ST_OBJECT_DATA 0x13#define DVBSUB_ST_ENDOFDISPLAY 0x80#define DVBSUB_ST_STUFFING 0xff// List of different OBJECT TYPES// According to EN 300-743, table 6#define DVBSUB_OT_BASIC_BITMAP 0x00#define DVBSUB_OT_BASIC_CHAR 0x01#define DVBSUB_OT_COMPOSITE_STRING 0x02// Pixel DATA TYPES// According to EN 300-743, table 9#define DVBSUB_DT_2BP_CODE_STRING 0x10#define DVBSUB_DT_4BP_CODE_STRING 0x11#define DVBSUB_DT_8BP_CODE_STRING 0x12#define DVBSUB_DT_24_TABLE_DATA 0x20#define DVBSUB_DT_28_TABLE_DATA 0x21#define DVBSUB_DT_48_TABLE_DATA 0x22#define DVBSUB_DT_END_LINE 0xf0// List of different Page Composition Segment state// According to EN 300-743, 7.2.1 table 3#define DVBSUB_PCS_STATE_ACQUISITION 0x01#define DVBSUB_PCS_STATE_CHANGE 0x10/***************************************************************************** * Local prototypes *****************************************************************************/static void decode_segment( decoder_t *, bs_t * );static void decode_page_composition( decoder_t *, bs_t * );static void decode_region_composition( decoder_t *, bs_t * );static void decode_object( decoder_t *, bs_t * );static void decode_clut( decoder_t *, bs_t * );static void free_all( decoder_t * );static void default_clut_init( decoder_t * );static subpicture_t *render( decoder_t * );/***************************************************************************** * Open: probe the decoder and return score ***************************************************************************** * Tries to launch a decoder and return score so that the interface is able * to chose. *****************************************************************************/static int Open( 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('d','v','b','s') ) { return VLC_EGENERIC; } p_dec->pf_decode_sub = Decode; p_sys = p_dec->p_sys = malloc( sizeof(decoder_sys_t) ); memset( p_sys, 0, sizeof(decoder_sys_t) ); p_sys->i_pts = 0; p_sys->i_id = p_dec->fmt_in.subs.dvb.i_id & 0xFFFF; p_sys->i_ancillary_id = p_dec->fmt_in.subs.dvb.i_id >> 16; p_sys->p_regions = NULL; p_sys->p_cluts = NULL; p_sys->p_page = NULL; es_format_Init( &p_dec->fmt_out, SPU_ES, VLC_FOURCC( 'd','v','b','s' ) ); default_clut_init( p_dec ); return VLC_SUCCESS;}/***************************************************************************** * Close: *****************************************************************************/static void Close( vlc_object_t *p_this ){ decoder_t *p_dec = (decoder_t*) p_this; decoder_sys_t *p_sys = p_dec->p_sys; free_all( p_dec ); free( p_sys );}/***************************************************************************** * 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_block; subpicture_t *p_spu = NULL; if( pp_block == NULL || *pp_block == NULL ) return NULL; p_block = *pp_block; *pp_block = NULL; p_sys->i_pts = p_block->i_pts; if( p_sys->i_pts <= 0 ) {#ifdef DEBUG_DVBSUB /* Some DVB channels send stuffing segments in non-dated packets so * don't complain too loudly. */ msg_Warn( p_dec, "non dated subtitle" );#endif block_Release( p_block ); return NULL; } bs_init( &p_sys->bs, p_block->p_buffer, p_block->i_buffer ); if( bs_read( &p_sys->bs, 8 ) != 0x20 ) /* Data identifier */ { msg_Dbg( p_dec, "invalid data identifier" ); block_Release( p_block ); return NULL; } if( bs_read( &p_sys->bs, 8 ) ) /* Subtitle stream id */ { msg_Dbg( p_dec, "invalid subtitle stream id" ); block_Release( p_block ); return NULL; }#ifdef DEBUG_DVBSUB msg_Dbg( p_dec, "subtitle packet received: "I64Fd, p_sys->i_pts );#endif p_sys->b_page = VLC_FALSE; while( bs_show( &p_sys->bs, 8 ) == 0x0f ) /* Sync byte */ { decode_segment( p_dec, &p_sys->bs ); } if( bs_read( &p_sys->bs, 8 ) != 0xff ) /* End marker */ { msg_Warn( p_dec, "end marker not found (corrupted subtitle ?)" ); block_Release( p_block ); return NULL; } /* Check if the page is to be displayed */ if( p_sys->p_page && p_sys->b_page ) p_spu = render( p_dec ); block_Release( p_block ); return p_spu;}/* following functions are local *//***************************************************************************** * default_clut_init: default clut as defined in EN 300-743 section 10 *****************************************************************************/static void default_clut_init( decoder_t *p_dec ){ decoder_sys_t *p_sys = p_dec->p_sys; uint8_t i;#define RGB_TO_Y(r, g, b) ((int16_t) 77 * r + 150 * g + 29 * b) / 256;#define RGB_TO_U(r, g, b) ((int16_t) -44 * r - 87 * g + 131 * b) / 256;#define RGB_TO_V(r, g, b) ((int16_t) 131 * r - 110 * g - 21 * b) / 256; /* 4 entries CLUT */ for( i = 0; i < 4; i++ ) { uint8_t R = 0, G = 0, B = 0, T = 0; if( !(i & 0x2) && !(i & 0x1) ) T = 0xFF; else if( !(i & 0x2) && (i & 0x1) ) R = G = B = 0xFF; else if( (i & 0x2) && !(i & 0x1) ) R = G = B = 0; else R = G = B = 0x7F; p_sys->default_clut.c_2b[i].Y = RGB_TO_Y(R,G,B); p_sys->default_clut.c_2b[i].Cr = RGB_TO_U(R,G,B); p_sys->default_clut.c_2b[i].Cb = RGB_TO_V(R,G,B); p_sys->default_clut.c_2b[i].T = T; } /* 16 entries CLUT */ for( i = 0; i < 16; i++ ) { uint8_t R = 0, G = 0, B = 0, T = 0; if( !(i & 0x8) ) { if( !(i & 0x4) && !(i & 0x2) && !(i & 0x1) ) { T = 0xFF; } else { R = (i & 0x1) ? 0xFF : 0; G = (i & 0x2) ? 0xFF : 0; B = (i & 0x4) ? 0xFF : 0; } } else { R = (i & 0x1) ? 0x7F : 0; G = (i & 0x2) ? 0x7F : 0; B = (i & 0x4) ? 0x7F : 0; } p_sys->default_clut.c_4b[i].Y = RGB_TO_Y(R,G,B); p_sys->default_clut.c_4b[i].Cr = RGB_TO_U(R,G,B); p_sys->default_clut.c_4b[i].Cb = RGB_TO_V(R,G,B); p_sys->default_clut.c_4b[i].T = T; } /* 256 entries CLUT (TODO) */ memset( p_sys->default_clut.c_8b, 0xFF, 256 * sizeof(dvbsub_color_t) );}static void decode_segment( decoder_t *p_dec, bs_t *s ){ decoder_sys_t *p_sys = p_dec->p_sys; int i_type; int i_page_id; int i_size; /* sync_byte (already checked) */ bs_skip( s, 8 ); /* segment type */ i_type = bs_read( s, 8 ); /* page id */ i_page_id = bs_read( s, 16 ); /* segment size */ i_size = bs_show( s, 16 ); if( i_page_id != p_sys->i_id && i_page_id != p_sys->i_ancillary_id ) {#ifdef DEBUG_DVBSUB msg_Dbg( p_dec, "subtitle skipped (page id: %i, %i)", i_page_id, p_sys->i_id );#endif bs_skip( s, 8 * ( 2 + i_size ) ); return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -