00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include <vlc/vlc.h>
00031 #include <vlc/decoder.h>
00032 #include <vlc/intf.h>
00033
00034 #include <vlc_osd.h>
00035
00036 #include "charset.h"
00037
00038 #include "xtag.h"
00039
00040 #undef CMML_DEBUG
00041
00042
00043
00044
00045 struct decoder_sys_t
00046 {
00047 intf_thread_t * p_intf;
00048 };
00049
00050
00051
00052
00053 static int OpenDecoder ( vlc_object_t * );
00054 static void CloseDecoder ( vlc_object_t * );
00055
00056 static subpicture_t *DecodeBlock ( decoder_t *, block_t ** );
00057
00058 static void ParseText ( decoder_t *, block_t * );
00059
00060
00061
00062
00063 int E_(OpenIntf) ( vlc_object_t * );
00064 void E_(CloseIntf) ( vlc_object_t * );
00065
00066
00067
00068
00069 vlc_module_begin();
00070 set_description( _("CMML annotations decoder") );
00071 set_capability( "decoder", 50 );
00072 set_callbacks( OpenDecoder, CloseDecoder );
00073 add_shortcut( "cmml" );
00074
00075 add_submodule();
00076 set_capability( "interface", 0 );
00077 set_callbacks( E_(OpenIntf), E_(CloseIntf) );
00078 vlc_module_end();
00079
00080
00081
00082
00083
00084
00085
00086 static int OpenDecoder( vlc_object_t *p_this )
00087 {
00088 decoder_t *p_dec = (decoder_t*)p_this;
00089 input_thread_t * p_input;
00090 decoder_sys_t *p_sys;
00091 vlc_value_t val;
00092
00093 if( p_dec->fmt_in.i_codec != VLC_FOURCC('c','m','m','l') )
00094 {
00095 return VLC_EGENERIC;
00096 }
00097
00098 p_dec->pf_decode_sub = DecodeBlock;
00099
00100 #ifdef CMML_DEBUG
00101 msg_Dbg( p_dec, "I am at %p", p_dec );
00102 #endif
00103
00104
00105 if( ( p_dec->p_sys = p_sys =
00106 (decoder_sys_t *)malloc(sizeof(decoder_sys_t)) ) == NULL )
00107 {
00108 msg_Err( p_dec, "out of memory" );
00109 return VLC_EGENERIC;
00110 }
00111
00112
00113
00114
00115
00116
00117 p_input = vlc_object_find( p_dec, VLC_OBJECT_INPUT, FIND_ANYWHERE );
00118 #ifdef CMML_DEBUG
00119 msg_Dbg( p_dec, "p_input is at %p", p_input );
00120 #endif
00121 val.p_address = p_dec;
00122 var_Create( p_input, "has-cmml-decoder",
00123 VLC_VAR_ADDRESS|VLC_VAR_DOINHERIT );
00124 if( var_Set( p_input, "has-cmml-decoder", val ) != VLC_SUCCESS )
00125 {
00126 msg_Dbg( p_dec, "var_Set of has-cmml-decoder failed" );
00127 }
00128 vlc_object_release( p_input );
00129
00130
00131 p_sys->p_intf = intf_Create( p_dec, "cmml" );
00132 p_sys->p_intf->b_block = VLC_FALSE;
00133 intf_RunThread( p_sys->p_intf );
00134
00135 return VLC_SUCCESS;
00136 }
00137
00138
00139
00140
00141
00142
00143 static subpicture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
00144 {
00145 subpicture_t *p_spu;
00146
00147 if( !pp_block || *pp_block == NULL )
00148 {
00149 return NULL;
00150 }
00151
00152 ParseText( p_dec, *pp_block );
00153
00154 block_Release( *pp_block );
00155 *pp_block = NULL;
00156
00157
00158
00159
00160
00161 p_spu = p_dec->pf_spu_buffer_new( p_dec );
00162 if( !p_spu )
00163 {
00164 msg_Dbg( p_dec, "couldn't allocate new subpicture" );
00165 return NULL;
00166 }
00167
00168 return p_spu;
00169 }
00170
00171
00172
00173
00174 static void CloseDecoder( vlc_object_t *p_this )
00175 {
00176 decoder_t *p_dec = (decoder_t *)p_this;
00177 decoder_sys_t *p_sys = p_dec->p_sys;
00178 intf_thread_t *p_intf;
00179
00180
00181 p_intf = vlc_object_find( p_dec, VLC_OBJECT_INTF, FIND_CHILD );
00182 if( p_intf != NULL )
00183 {
00184 #ifdef CMML_DEBUG
00185 msg_Dbg( p_dec, "CMML decoder is freeing interface thread" );
00186 #endif
00187 intf_StopThread( p_intf );
00188 vlc_object_detach( p_intf );
00189 vlc_object_release( p_intf );
00190 intf_Destroy( p_intf );
00191 }
00192
00193 p_sys->p_intf = NULL;
00194
00195 free( p_sys );
00196 }
00197
00198
00199
00200
00201 static void ParseText( decoder_t *p_dec, block_t *p_block )
00202 {
00203 char *psz_subtitle, *psz_cmml, *psz_url;
00204 XTag *p_clip_parser, *p_anchor;
00205 vlc_value_t val;
00206
00207
00208 if( p_block->i_pts == 0 )
00209 {
00210 msg_Warn( p_dec, "subtitle without a date" );
00211 return;
00212 }
00213
00214
00215 if( p_block->i_buffer <= 1 || p_block->p_buffer[0] == '\0' )
00216 {
00217 msg_Warn( p_dec, "empty subtitle" );
00218 return;
00219 }
00220
00221
00222
00223
00224
00225 if ( (psz_cmml = malloc( p_block->i_buffer + 1 )) == NULL )
00226 return;
00227 psz_cmml = memcpy( psz_cmml, p_block->p_buffer, p_block->i_buffer );
00228 psz_cmml[p_block->i_buffer] = '\0';
00229 #ifdef CMML_DEBUG
00230 msg_Dbg( p_dec, "psz_cmml is \"%s\"", psz_cmml );
00231 #endif
00232
00233
00234 p_clip_parser = xtag_new_parse( psz_cmml, p_block->i_buffer );
00235 if( !p_clip_parser )
00236 {
00237 msg_Warn( p_dec, "couldn't initialise <clip> parser" );
00238 free( psz_cmml );
00239 return;
00240 }
00241
00242
00243 p_anchor = xtag_first_child( p_clip_parser, "a" );
00244 if( p_anchor != NULL )
00245 {
00246 psz_subtitle = xtag_get_pcdata( p_anchor );
00247 }
00248 else
00249 {
00250 psz_subtitle = strdup( " " );
00251 }
00252
00253 #ifdef CMML_DEBUG
00254 msg_Dbg( p_dec, "psz_subtitle is \"%s\"", psz_subtitle );
00255 #endif
00256
00257
00258 psz_url = xtag_get_attribute( p_anchor, "href" );
00259 #ifdef CMML_DEBUG
00260 msg_Dbg( p_dec, "psz_url is \"%s\"", psz_url );
00261 #endif
00262 if( psz_url )
00263 {
00264 char *psz_tmp = strdup( psz_url );
00265
00266 val.p_address = psz_tmp;
00267 if( var_Set( p_dec, "psz-current-anchor-url", val ) != VLC_SUCCESS )
00268 {
00269 (void) var_Create( p_dec, "psz-current-anchor-url",
00270 VLC_VAR_ADDRESS|VLC_VAR_DOINHERIT );
00271 msg_Dbg( p_dec, "creating psz-current-anchor-url" );
00272 if( var_Set( p_dec, "psz-current-anchor-url", val ) != VLC_SUCCESS )
00273 msg_Dbg( p_dec, "var_Set of psz-current-anchor-url failed" );
00274 }
00275 }
00276
00277 if( psz_subtitle )
00278 {
00279 char *psz_tmp = strdup( psz_subtitle );
00280
00281 val.p_address = psz_tmp;
00282 if( var_Set( p_dec, "psz-current-anchor-description", val ) != VLC_SUCCESS )
00283 {
00284 (void) var_Create( p_dec, "psz-current-anchor-description",
00285 VLC_VAR_ADDRESS|VLC_VAR_DOINHERIT );
00286 msg_Dbg( p_dec, "creating psz-current-anchor-description" );
00287 if( var_Set( p_dec, "psz-current-anchor-description", val ) != VLC_SUCCESS )
00288 msg_Dbg( p_dec, "var_Set of psz-current-anchor-description failed" );
00289 }
00290
00291 }
00292
00293 if( psz_subtitle ) free( psz_subtitle );
00294 if( psz_cmml ) free( psz_cmml );
00295 if( p_anchor ) free( p_anchor );
00296 if( p_clip_parser ) free( p_clip_parser );
00297 if( psz_url ) free( psz_url );
00298 }
00299