cmml.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:10k
源码类别:

多媒体

开发平台:

MultiPlatform

  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 VideoLAN
  7.  *
  8.  * $Id: cmml.c 7397 2004-04-20 17:27:30Z sam $
  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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  25.  *****************************************************************************/
  26. /*****************************************************************************
  27.  * Preamble
  28.  *****************************************************************************/
  29. #include <vlc/vlc.h>
  30. #include <vlc/decoder.h>
  31. #include <vlc/intf.h>
  32. #include <osd.h>
  33. #include "charset.h"
  34. #include "xtag.h"
  35. #undef CMML_DEBUG
  36. /*****************************************************************************
  37.  * decoder_sys_t : decoder descriptor
  38.  *****************************************************************************/
  39. struct decoder_sys_t
  40. {
  41.     intf_thread_t *     p_intf;
  42. };
  43. /*****************************************************************************
  44.  * Local prototypes
  45.  *****************************************************************************/
  46. static int  OpenDecoder   ( vlc_object_t * );
  47. static void CloseDecoder  ( vlc_object_t * );
  48. static void DecodeBlock   ( decoder_t *, block_t ** );
  49. static void ParseText     ( decoder_t *, block_t * );
  50. /*****************************************************************************
  51.  * Exported prototypes
  52.  *****************************************************************************/
  53. int  E_(OpenIntf)  ( vlc_object_t * );
  54. void E_(CloseIntf) ( vlc_object_t * );
  55. /*****************************************************************************
  56.  * Module descriptor.
  57.  *****************************************************************************/
  58. vlc_module_begin();
  59.     set_description( _("CMML annotations decoder") );
  60.     set_capability( "decoder", 50 );
  61.     set_callbacks( OpenDecoder, CloseDecoder );
  62.     add_shortcut( "cmml" );
  63.     add_submodule();
  64.         set_capability( "interface", 0 );
  65.         set_callbacks( E_(OpenIntf), E_(CloseIntf) );
  66. vlc_module_end();
  67. /*****************************************************************************
  68.  * OpenDecoder: probe the decoder and return score
  69.  *****************************************************************************
  70.  * Tries to launch a decoder and return score so that the interface is able
  71.  * to chose.
  72.  *****************************************************************************/
  73. static int OpenDecoder( vlc_object_t *p_this )
  74. {
  75.     decoder_t *p_dec = (decoder_t*)p_this;
  76.     input_thread_t * p_input;
  77.     decoder_sys_t *p_sys;
  78.     vlc_value_t val;
  79.     if( p_dec->fmt_in.i_codec != VLC_FOURCC('c','m','m','l') )
  80.     {
  81.         return VLC_EGENERIC;
  82.     }
  83.     p_dec->pf_decode_sub = DecodeBlock;
  84. #ifdef CMML_DEBUG
  85.     msg_Dbg( p_dec, "I am at %p", p_dec );
  86. #endif
  87.     /* Allocate the memory needed to store the decoder's structure */
  88.     if( ( p_dec->p_sys = p_sys =
  89.           (decoder_sys_t *)malloc(sizeof(decoder_sys_t)) ) == NULL )
  90.     {
  91.         msg_Err( p_dec, "out of memory" );
  92.         return VLC_EGENERIC;
  93.     }
  94.     /* Let other interested modules know that we're a CMML decoder
  95.      * We have to set this variable on the input thread, because there's
  96.      * typically more than one decoder running so we can't find the CMML
  97.      * decoder succesfully with vlc_object_find.  (Any hints on how to achieve
  98.      * this would be rather appreciated ;) */
  99.     p_input = vlc_object_find( p_dec, VLC_OBJECT_INPUT, FIND_ANYWHERE );
  100. #ifdef CMML_DEBUG
  101.     msg_Dbg( p_dec, "p_input is at %p", p_input );
  102. #endif
  103.     val.p_address = p_dec;
  104.     var_Create( p_input, "has-cmml-decoder",
  105.                 VLC_VAR_ADDRESS|VLC_VAR_DOINHERIT );
  106.     if( var_Set( p_input, "has-cmml-decoder", val ) != VLC_SUCCESS )
  107.     {
  108.         msg_Dbg( p_dec, "var_Set of has-cmml-decoder failed" );
  109.     }
  110.     vlc_object_release( p_input );
  111.     /* initialise the CMML responder interface */
  112.     p_sys->p_intf = intf_Create( p_dec, "cmml" );
  113.     p_sys->p_intf->b_block = VLC_FALSE;
  114.     intf_RunThread( p_sys->p_intf );
  115.     return VLC_SUCCESS;
  116. }
  117. /****************************************************************************
  118.  * DecodeBlock: the whole thing
  119.  ****************************************************************************
  120.  * This function must be fed with complete subtitles units.
  121.  ****************************************************************************/
  122. static void DecodeBlock( decoder_t *p_dec, block_t **pp_block )
  123. {
  124.     if( !pp_block || *pp_block == NULL )
  125.     {
  126.         return;
  127.     }
  128.     ParseText( p_dec, *pp_block );
  129.     block_Release( *pp_block );
  130.     *pp_block = NULL;
  131. }
  132. /*****************************************************************************
  133.  * CloseDecoder: clean up the decoder
  134.  *****************************************************************************/
  135. static void CloseDecoder( vlc_object_t *p_this )
  136. {
  137.     decoder_t *p_dec = (decoder_t *)p_this;
  138.     decoder_sys_t *p_sys = p_dec->p_sys;
  139.     intf_thread_t *p_intf;
  140.     /* Destroy the interface object/thread */
  141.     p_intf = vlc_object_find( p_dec, VLC_OBJECT_INTF, FIND_CHILD );
  142.     if( p_intf != NULL )
  143.     {
  144. #ifdef CMML_DEBUG
  145.         msg_Dbg( p_dec, "CMML decoder is freeing interface thread" );
  146. #endif
  147.         intf_StopThread( p_intf );
  148.         vlc_object_detach( p_intf );
  149.         vlc_object_release( p_intf );
  150.         intf_Destroy( p_intf );
  151.     }
  152.     p_sys->p_intf = NULL;
  153.     free( p_sys );
  154. }
  155. /*****************************************************************************
  156.  * ParseText: parse an text subtitle packet and send it to the video output
  157.  *****************************************************************************/
  158. static void ParseText( decoder_t *p_dec, block_t *p_block )
  159. {
  160.     char *psz_subtitle, *psz_cmml, *psz_url;
  161.     XTag *p_clip_parser, *p_anchor;
  162.     vlc_value_t val;
  163.     /* We cannot display a subpicture with no date */
  164.     if( p_block->i_pts == 0 )
  165.     {
  166.         msg_Warn( p_dec, "subtitle without a date" );
  167.         return;
  168.     }
  169.     /* Check validity of packet data */
  170.     if( p_block->i_buffer <= 1 ||  p_block->p_buffer[0] == '' )
  171.     {
  172.         msg_Warn( p_dec, "empty subtitle" );
  173.         return;
  174.     }
  175.     /* get anchor text from CMML */
  176.     /* Copy the whole CMML tag into our own buffer:
  177.        allocate i_buffer bytes + 1 for the terminating  */
  178.     if ( (psz_cmml = malloc( p_block->i_buffer + 1 )) == NULL )
  179.         return;
  180.     psz_cmml = memcpy( psz_cmml, p_block->p_buffer, p_block->i_buffer );
  181.     psz_cmml[p_block->i_buffer] = ''; /* terminate the string */
  182. #ifdef CMML_DEBUG
  183.     msg_Dbg( p_dec, "psz_cmml is "%s"", psz_cmml );
  184. #endif
  185.     
  186.     /* Parse the <clip> part of the CMML */
  187.     p_clip_parser = xtag_new_parse( psz_cmml, p_block->i_buffer );
  188.     if( !p_clip_parser )
  189.     {
  190.         msg_Warn( p_dec, "couldn't initialise <clip> parser" );
  191.         free( psz_cmml );
  192.         return;
  193.     }
  194.     /* Parse the anchor tag and get its contents */
  195.     p_anchor = xtag_first_child( p_clip_parser, "a" );
  196.     if( p_anchor != NULL )
  197.     {
  198.         psz_subtitle = xtag_get_pcdata( p_anchor );
  199.     }
  200.     else
  201.     {
  202.         psz_subtitle = strdup( " " );
  203.     }
  204. #ifdef CMML_DEBUG
  205.     msg_Dbg( p_dec, "psz_subtitle is "%s"", psz_subtitle );
  206. #endif
  207.     /* get URL from the current clip, if one exists */
  208.     psz_url = xtag_get_attribute( p_anchor, "href" );
  209. #ifdef CMML_DEBUG
  210.     msg_Dbg( p_dec, "psz_url is "%s"", psz_url );
  211. #endif
  212.     if( psz_url )
  213.     {
  214.         char *psz_tmp = strdup( psz_url );
  215.         
  216.         val.p_address = psz_tmp;
  217.         if( var_Set( p_dec, "psz-current-anchor-url", val ) != VLC_SUCCESS )
  218.         {
  219.             (void) var_Create( p_dec, "psz-current-anchor-url",
  220.                                VLC_VAR_ADDRESS|VLC_VAR_DOINHERIT );
  221.             msg_Dbg( p_dec, "creating psz-current-anchor-url" );
  222.             if( var_Set( p_dec, "psz-current-anchor-url", val ) != VLC_SUCCESS )
  223.                 msg_Dbg( p_dec, "var_Set of psz-current-anchor-url failed" );
  224.         }
  225.     }
  226.     if( psz_subtitle )
  227.     {
  228.         char *psz_tmp = strdup( psz_subtitle );
  229.         val.p_address = psz_tmp;
  230.         if( var_Set( p_dec, "psz-current-anchor-description", val ) != VLC_SUCCESS )
  231.         {
  232.             (void) var_Create( p_dec, "psz-current-anchor-description",
  233.                                VLC_VAR_ADDRESS|VLC_VAR_DOINHERIT );
  234.             msg_Dbg( p_dec, "creating psz-current-anchor-description" );
  235.             if( var_Set( p_dec, "psz-current-anchor-description", val ) != VLC_SUCCESS )
  236.                 msg_Dbg( p_dec, "var_Set of psz-current-anchor-description failed" );
  237.         }
  238.     }
  239.     if( psz_subtitle ) free( psz_subtitle );
  240.     if( psz_cmml ) free( psz_cmml );
  241.     if( p_anchor ) free( p_anchor );
  242.     if( p_clip_parser ) free( p_clip_parser );
  243.     if( psz_url ) free( psz_url );
  244. }