cmml.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:10k
源码类别:

midi

开发平台:

Unix_Linux

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