]> git.sesse.net Git - vlc/blob - modules/codec/cmml/cmml.c
x264 change that qcomp-parameter determinates rc-mode
[vlc] / modules / codec / cmml / cmml.c
1 /*****************************************************************************
2  * cmml.c : CMML annotations/metadata decoder
3  *****************************************************************************
4  * Copyright (C) 2003-2004 Commonwealth Scientific and Industrial Research
5  *                         Organisation (CSIRO) Australia
6  * Copyright (C) 2004 the VideoLAN team
7  *
8  * $Id$
9  *
10  * Author: Andre Pang <Andre.Pang@csiro.au>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25  *****************************************************************************/
26
27 /*****************************************************************************
28  * Preamble
29  *****************************************************************************/
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
36 #include <vlc_input.h>
37 #include <vlc_codec.h>
38 #include <vlc_osd.h>
39 #include <vlc_charset.h>
40 #include <vlc_interface.h>
41 #include "xtag.h"
42
43 #undef  CMML_DEBUG
44
45 /*****************************************************************************
46  * Local prototypes
47  *****************************************************************************/
48 static int           OpenDecoder   ( vlc_object_t * );
49 static void          CloseDecoder  ( vlc_object_t * );
50
51 static subpicture_t *DecodeBlock   ( decoder_t *, block_t ** );
52
53 static void          ParseText     ( decoder_t *, block_t * );
54
55 /*****************************************************************************
56  * Exported prototypes
57  *****************************************************************************/
58 decoder_sys_t *OpenIntf( vlc_object_t * );
59 void CloseIntf( decoder_sys_t * );
60
61 /*****************************************************************************
62  * Module descriptor.
63  *****************************************************************************/
64 vlc_module_begin ()
65     set_description( N_("CMML annotations decoder") )
66     set_capability( "decoder", 50 )
67     set_callbacks( OpenDecoder, CloseDecoder )
68     add_shortcut( "cmml" )
69
70     add_submodule ()
71         set_capability( "interface", 0 )
72         set_callbacks( OpenIntf, CloseIntf )
73         add_shortcut( "cmml" )
74 vlc_module_end ()
75
76 /*****************************************************************************
77  * OpenDecoder: probe the decoder and return score
78  *****************************************************************************
79  * Tries to launch a decoder and return score so that the interface is able
80  * to chose.
81  *****************************************************************************/
82 static int OpenDecoder( vlc_object_t *p_this )
83 {
84     decoder_t *p_dec = (decoder_t*)p_this;
85     input_thread_t * p_input;
86
87     if( p_dec->fmt_in.i_codec != VLC_CODEC_CMML )
88         return VLC_EGENERIC;
89
90     p_dec->pf_decode_sub = DecodeBlock;
91
92     /* Let other interested modules know that we're a CMML decoder
93      * We have to set this variable on the input thread, because there's
94      * typically more than one decoder running so we can't find the CMML
95      * decoder succesfully with vlc_object_find.  (Any hints on how to achieve
96      * this would be rather appreciated ;) */
97     p_input = vlc_object_find( p_dec, VLC_OBJECT_INPUT, FIND_ANYWHERE );
98     if( p_input )
99     {
100         vlc_value_t val;
101
102 #ifdef CMML_DEBUG
103         msg_Dbg( p_dec, "p_input is at %p", p_input );
104 #endif
105         val.p_address = p_dec;
106         var_Create( p_input, "has-cmml-decoder",
107                     VLC_VAR_ADDRESS|VLC_VAR_DOINHERIT );
108
109         if( var_Set( p_input, "has-cmml-decoder", val ) != VLC_SUCCESS )
110             msg_Dbg( p_dec, "var_Set of has-cmml-decoder failed" );
111         vlc_object_release( p_input );
112     }
113
114     /* initialise the CMML responder interface */
115     p_dec->p_sys = OpenIntf( VLC_OBJECT(p_dec) );
116     p_dec->fmt_out.i_cat = SPU_ES;
117     p_dec->fmt_out.i_codec = 0;
118
119     return VLC_SUCCESS;
120 }
121
122 /****************************************************************************
123  * DecodeBlock: the whole thing
124  ****************************************************************************
125  * This function must be fed with complete subtitles units.
126  ****************************************************************************/
127 static subpicture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
128 {
129     subpicture_t *p_spu;
130
131     if( !pp_block || *pp_block == NULL )
132     {
133         return NULL;
134     }
135
136     ParseText( p_dec, *pp_block );
137
138     block_Release( *pp_block );
139     *pp_block = NULL;
140
141     /* allocate an empty subpicture to return.  the actual subpicture
142      * displaying is done in the DisplayAnchor function in intf.c (called from
143      * DisplayPendingAnchor, which in turn is called from the main RunIntf
144      * loop). */
145     p_spu = decoder_NewSubpicture( p_dec );
146     if( !p_spu )
147     {
148         msg_Dbg( p_dec, "couldn't allocate new subpicture" );
149         return NULL;
150     }
151
152     return p_spu;
153 }
154
155 /*****************************************************************************
156  * CloseDecoder: clean up the decoder
157  *****************************************************************************/
158 static void CloseDecoder( vlc_object_t *p_this )
159 {
160     decoder_t *p_dec = (decoder_t *)p_this;
161
162     CloseIntf( p_dec->p_sys );
163 }
164
165 /*****************************************************************************
166  * ParseText: parse an text subtitle packet and send it to the video output
167  *****************************************************************************/
168 static void ParseText( decoder_t *p_dec, block_t *p_block )
169 {
170     char *psz_subtitle, *psz_cmml, *psz_url;
171     XTag *p_clip_parser, *p_anchor;
172     vlc_value_t val;
173
174     /* We cannot display a subpicture with no date */
175     if( p_block->i_pts == 0 )
176     {
177         msg_Warn( p_dec, "subtitle without a date" );
178         return;
179     }
180
181     /* Check validity of packet data */
182     if( p_block->i_buffer <= 1 ||  p_block->p_buffer[0] == '\0' )
183     {
184         msg_Warn( p_dec, "empty subtitle" );
185         return;
186     }
187
188     /* get anchor text from CMML */
189
190     /* Copy the whole CMML tag into our own buffer:
191        allocate i_buffer bytes + 1 for the terminating \0 */
192     if( (psz_cmml = malloc( p_block->i_buffer + 1 )) == NULL )
193         return;
194     memcpy( psz_cmml, p_block->p_buffer, p_block->i_buffer );
195     psz_cmml[p_block->i_buffer] = '\0'; /* terminate the string */
196 #ifdef CMML_DEBUG
197     msg_Dbg( p_dec, "psz_cmml is \"%s\"", psz_cmml );
198 #endif
199  
200     /* Parse the <clip> part of the CMML */
201     p_clip_parser = xtag_new_parse( psz_cmml, p_block->i_buffer );
202     if( !p_clip_parser )
203     {
204         msg_Warn( p_dec, "couldn't initialise <clip> parser" );
205         free( psz_cmml );
206         return;
207     }
208
209     /* Parse the anchor tag and get its contents */
210     p_anchor = xtag_first_child( p_clip_parser, "a" );
211     if( p_anchor != NULL )
212     {
213         psz_subtitle = xtag_get_pcdata( p_anchor );
214     }
215     else
216     {
217         psz_subtitle = strdup( " " );
218     }
219
220 #ifdef CMML_DEBUG
221     msg_Dbg( p_dec, "psz_subtitle is \"%s\"", psz_subtitle );
222 #endif
223
224     /* get URL from the current clip, if one exists */
225     psz_url = xtag_get_attribute( p_anchor, "href" );
226 #ifdef CMML_DEBUG
227     msg_Dbg( p_dec, "psz_url is \"%s\"", psz_url );
228 #endif
229     if( psz_url )
230     {
231         char *psz_tmp = strdup( psz_url );
232  
233         val.p_address = psz_tmp;
234         if( var_Set( p_dec, "psz-current-anchor-url", val ) != VLC_SUCCESS )
235         {
236             var_Create( p_dec, "psz-current-anchor-url",
237                         VLC_VAR_ADDRESS | VLC_VAR_DOINHERIT );
238             msg_Dbg( p_dec, "creating psz-current-anchor-url" );
239             if( var_Set( p_dec, "psz-current-anchor-url", val ) != VLC_SUCCESS )
240                 msg_Dbg( p_dec, "var_Set of psz-current-anchor-url failed" );
241         }
242     }
243
244     if( psz_subtitle )
245     {
246         char *psz_tmp = strdup( psz_subtitle );
247
248         val.p_address = psz_tmp;
249         if( var_Set( p_dec, "psz-current-anchor-description", val ) != VLC_SUCCESS )
250         {
251             var_Create( p_dec, "psz-current-anchor-description",
252                         VLC_VAR_ADDRESS | VLC_VAR_DOINHERIT );
253             msg_Dbg( p_dec, "creating psz-current-anchor-description" );
254             if( var_Set( p_dec, "psz-current-anchor-description", val ) != VLC_SUCCESS )
255                 msg_Dbg( p_dec, "var_Set of psz-current-anchor-description failed" );
256         }
257
258     }
259
260     free( psz_subtitle );
261     free( psz_cmml );
262     free( p_anchor );
263     free( p_clip_parser );
264     free( psz_url );
265 }
266