Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

cmml.c

00001 /*****************************************************************************
00002  * cmml.c : CMML annotations/metadata decoder
00003  *****************************************************************************
00004  * Copyright (C) 2003-2004 Commonwealth Scientific and Industrial Research
00005  *                         Organisation (CSIRO) Australia
00006  * Copyright (C) 2004 the VideoLAN team
00007  *
00008  * $Id: cmml.c 12412 2005-08-27 16:40:23Z jpsaman $
00009  *
00010  * Author: Andre Pang <[email protected]>
00011  *
00012  * This program is free software; you can redistribute it and/or modify
00013  * it under the terms of the GNU General Public License as published by
00014  * the Free Software Foundation; either version 2 of the License, or
00015  * (at your option) any later version.
00016  *
00017  * This program is distributed in the hope that it will be useful,
00018  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00019  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020  * GNU General Public License for more details.
00021  *
00022  * You should have received a copy of the GNU General Public License
00023  * along with this program; if not, write to the Free Software
00024  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00025  *****************************************************************************/
00026 
00027 /*****************************************************************************
00028  * Preamble
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  * decoder_sys_t : decoder descriptor
00044  *****************************************************************************/
00045 struct decoder_sys_t
00046 {
00047     intf_thread_t *     p_intf;
00048 };
00049 
00050 /*****************************************************************************
00051  * Local prototypes
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  * Exported prototypes
00062  *****************************************************************************/
00063 int  E_(OpenIntf)  ( vlc_object_t * );
00064 void E_(CloseIntf) ( vlc_object_t * );
00065 
00066 /*****************************************************************************
00067  * Module descriptor.
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  * OpenDecoder: probe the decoder and return score
00082  *****************************************************************************
00083  * Tries to launch a decoder and return score so that the interface is able
00084  * to chose.
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     /* Allocate the memory needed to store the decoder's structure */
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     /* Let other interested modules know that we're a CMML decoder
00113      * We have to set this variable on the input thread, because there's
00114      * typically more than one decoder running so we can't find the CMML
00115      * decoder succesfully with vlc_object_find.  (Any hints on how to achieve
00116      * this would be rather appreciated ;) */
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     /* initialise the CMML responder interface */
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  * DecodeBlock: the whole thing
00140  ****************************************************************************
00141  * This function must be fed with complete subtitles units.
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     /* allocate an empty subpicture to return.  the actual subpicture
00158      * displaying is done in the DisplayAnchor function in intf.c (called from
00159      * DisplayPendingAnchor, which in turn is called from the main RunIntf
00160      * loop). */
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  * CloseDecoder: clean up the decoder
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     /* Destroy the interface object/thread */
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  * ParseText: parse an text subtitle packet and send it to the video output
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     /* We cannot display a subpicture with no date */
00208     if( p_block->i_pts == 0 )
00209     {
00210         msg_Warn( p_dec, "subtitle without a date" );
00211         return;
00212     }
00213 
00214     /* Check validity of packet data */
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     /* get anchor text from CMML */
00222 
00223     /* Copy the whole CMML tag into our own buffer:
00224        allocate i_buffer bytes + 1 for the terminating \0 */
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'; /* terminate the string */
00229 #ifdef CMML_DEBUG
00230     msg_Dbg( p_dec, "psz_cmml is \"%s\"", psz_cmml );
00231 #endif
00232     
00233     /* Parse the <clip> part of the CMML */
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     /* Parse the anchor tag and get its contents */
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     /* get URL from the current clip, if one exists */
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 

Generated on Tue Dec 20 10:14:28 2005 for vlc-0.8.4a by  doxygen 1.4.2