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

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * dynamicoverlay.c : dynamic overlay plugin for vlc
  3.  *****************************************************************************
  4.  * Copyright (C) 2007 the VideoLAN team
  5.  * $Id: 6d9f4556d848332114284867907047bf4af905bb $
  6.  *
  7.  * Author: Søren Bøg <avacore@videolan.org>
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2 of the License, or
  12.  * (at your option) any later version.
  13.  *
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program; if not, write to the Free Software
  21.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  22.  *****************************************************************************/
  23. /*****************************************************************************
  24.  * Preamble
  25.  *****************************************************************************/
  26. #ifdef HAVE_CONFIG_H
  27. # include "config.h"
  28. #endif
  29. #include <vlc_common.h>
  30. #include <vlc_plugin.h>
  31. #include <vlc_sout.h>
  32. #include <vlc_vout.h>
  33. #include <vlc_filter.h>
  34. #include <vlc_osd.h>
  35. #include <ctype.h>
  36. #include <fcntl.h>
  37. #include "dynamicoverlay.h"
  38. /*****************************************************************************
  39.  * Local prototypes
  40.  *****************************************************************************/
  41. static int Create( vlc_object_t * );
  42. static void Destroy( vlc_object_t * );
  43. static subpicture_t *Filter( filter_t *, mtime_t );
  44. static int AdjustCallback( vlc_object_t *p_this, char const *psz_var,
  45.                            vlc_value_t oldval, vlc_value_t newval,
  46.                            void *p_data );
  47. /*****************************************************************************
  48.  * Module descriptor
  49.  *****************************************************************************/
  50. #define INPUT_TEXT N_("Input FIFO")
  51. #define INPUT_LONGTEXT N_("FIFO which will be read for commands")
  52. #define OUTPUT_TEXT N_("Output FIFO")
  53. #define OUTPUT_LONGTEXT N_("FIFO which will be written to for responses")
  54. vlc_module_begin ()
  55.     set_description( N_("Dynamic video overlay") )
  56.     set_shortname( N_("Overlay" ))
  57.     set_category( CAT_VIDEO )
  58.     set_subcategory( SUBCAT_VIDEO_VFILTER )
  59.     set_capability( "sub filter", 0 )
  60.     add_file( "overlay-input", NULL, NULL, INPUT_TEXT, INPUT_LONGTEXT,
  61.               false )
  62.     add_file( "overlay-output", NULL, NULL, OUTPUT_TEXT, OUTPUT_LONGTEXT,
  63.               false )
  64.     add_shortcut( "overlay" )
  65.     set_callbacks( Create, Destroy )
  66. vlc_module_end ()
  67. static const char *const ppsz_filter_options[] = {
  68.     "input", "output", NULL
  69. };
  70. /*****************************************************************************
  71.  * Create: allocates adjust video thread output method
  72.  *****************************************************************************
  73.  * This function allocates and initializes a adjust vout method.
  74.  *****************************************************************************/
  75. static int Create( vlc_object_t *p_this )
  76. {
  77.     filter_t *p_filter = (filter_t *)p_this;
  78.     filter_sys_t *p_sys;
  79.     /* Allocate structure */
  80.     p_filter->p_sys = malloc( sizeof( filter_sys_t ) );
  81.     if( p_filter->p_sys == NULL )
  82.         return VLC_ENOMEM;
  83.     p_sys = p_filter->p_sys;
  84.     BufferInit( &p_sys->input );
  85.     BufferInit( &p_sys->output );
  86.     QueueInit( &p_sys->atomic );
  87.     QueueInit( &p_sys->pending );
  88.     QueueInit( &p_sys->processed );
  89.     ListInit( &p_sys->overlays );
  90.     p_sys->i_inputfd = -1;
  91.     p_sys->i_outputfd = -1;
  92.     p_sys->b_updated = true;
  93.     p_sys->b_atomic = false;
  94.     vlc_mutex_init( &p_sys->lock );
  95.     p_filter->pf_sub_filter = Filter;
  96.     config_ChainParse( p_filter, "overlay-", ppsz_filter_options,
  97.                        p_filter->p_cfg );
  98.     p_sys->psz_inputfile = var_CreateGetStringCommand( p_filter,
  99.                                                        "overlay-input" );
  100.     p_sys->psz_outputfile = var_CreateGetStringCommand( p_filter,
  101.                                                         "overlay-output" );
  102.     var_AddCallback( p_filter, "overlay-input", AdjustCallback, p_sys );
  103.     var_AddCallback( p_filter, "overlay-output", AdjustCallback, p_sys );
  104.     RegisterCommand( p_filter );
  105.     return VLC_SUCCESS;
  106. }
  107. /*****************************************************************************
  108.  * Destroy: destroy adjust video thread output method
  109.  *****************************************************************************
  110.  * Terminate an output method created by adjustCreateOutputMethod
  111.  *****************************************************************************/
  112. static void Destroy( vlc_object_t *p_this )
  113. {
  114.     filter_t *p_filter = (filter_t *)p_this;
  115.     filter_sys_t *p_sys = p_filter->p_sys;
  116.     BufferDestroy( &p_sys->input );
  117.     BufferDestroy( &p_sys->output );
  118.     QueueDestroy( &p_sys->atomic );
  119.     QueueDestroy( &p_sys->pending );
  120.     QueueDestroy( &p_sys->processed );
  121.     ListDestroy( &p_sys->overlays );
  122.     UnregisterCommand( p_filter );
  123.     var_DelCallback( p_filter, "overlay-input", AdjustCallback, p_sys );
  124.     var_DelCallback( p_filter, "overlay-output", AdjustCallback, p_sys );
  125.     vlc_mutex_destroy( &p_sys->lock );
  126.     free( p_sys->psz_inputfile );
  127.     free( p_sys->psz_outputfile );
  128.     free( p_sys );
  129. }
  130. /*****************************************************************************
  131.  * Render: displays previously rendered output
  132.  *****************************************************************************
  133.  * This function send the currently rendered image to adjust modified image,
  134.  * waits until it is displayed and switch the two rendering buffers, preparing
  135.  * next frame.
  136.  *****************************************************************************/
  137. static subpicture_t *Filter( filter_t *p_filter, mtime_t date )
  138. {
  139.     filter_sys_t *p_sys = p_filter->p_sys;
  140.     /* We might need to open these at any time. */
  141.     vlc_mutex_lock( &p_sys->lock );
  142.     if( p_sys->i_inputfd == -1 )
  143.     {
  144.         p_sys->i_inputfd = open( p_sys->psz_inputfile, O_RDONLY | O_NONBLOCK );
  145.         if( p_sys->i_inputfd == -1 )
  146.         {
  147.             msg_Warn( p_filter, "Failed to grab input file: %s (%s)",
  148.                       p_sys->psz_inputfile, strerror( errno ) );
  149.         }
  150.         else
  151.         {
  152.             msg_Info( p_filter, "Grabbed input file: %s",
  153.                       p_sys->psz_inputfile );
  154.         }
  155.     }
  156.     if( p_sys->i_outputfd == -1 )
  157.     {
  158.         p_sys->i_outputfd = open( p_sys->psz_outputfile,
  159.                                   O_WRONLY | O_NONBLOCK );
  160.         if( p_sys->i_outputfd == -1 )
  161.         {
  162.             if( errno != ENXIO )
  163.             {
  164.                 msg_Warn( p_filter, "Failed to grab output file: %s (%s)",
  165.                           p_sys->psz_outputfile, strerror( errno ) );
  166.             }
  167.         }
  168.         else
  169.         {
  170.             msg_Info( p_filter, "Grabbed output file: %s",
  171.                       p_sys->psz_outputfile );
  172.         }
  173.     }
  174.     vlc_mutex_unlock( &p_sys->lock );
  175.     /* Read any waiting commands */
  176.     if( p_sys->i_inputfd != -1 )
  177.     {
  178.         char p_buffer[1024];
  179.         ssize_t i_len = read( p_sys->i_inputfd, p_buffer, 1024 );
  180.         if( i_len == -1 )
  181.         {
  182.             /* We hit an error */
  183.             if( errno != EAGAIN )
  184.             {
  185.                 msg_Warn( p_filter, "Error on input file: %s",
  186.                           strerror( errno ) );
  187.                 close( p_sys->i_inputfd );
  188.                 p_sys->i_inputfd = -1;
  189.             }
  190.         }
  191.         else if( i_len == 0 )
  192.         {
  193.             /* We hit the end-of-file */
  194.         }
  195.         else
  196.         {
  197.             BufferAdd( &p_sys->input, p_buffer, i_len );
  198.         }
  199.     }
  200.     /* Parse any complete commands */
  201.     char *p_end, *p_cmd;
  202.     while( ( p_end = memchr( p_sys->input.p_begin, 'n',
  203.                              p_sys->input.i_length ) ) )
  204.     {
  205.         commanddesc_t *p_cur = NULL;
  206.         bool b_found = false;
  207.         size_t i_index = 0;
  208.         *p_end = '';
  209.         p_cmd = BufferGetToken( &p_sys->input );
  210.         msg_Info( p_filter, "Search command: %s", p_cmd );
  211.         for( i_index = 0; i_index < p_sys->i_commands; i_index++ )
  212.         {
  213.             p_cur = p_sys->pp_commands[i_index];
  214.             if( !strncmp( p_cur->psz_command, p_cmd, strlen(p_cur->psz_command) ) )
  215.             {
  216.                 p_cmd[strlen(p_cur->psz_command)] = '';
  217.                 b_found = true;
  218.                 break;
  219.             }
  220.         }
  221.         if( !b_found )
  222.         {
  223.             /* No matching command */
  224.             msg_Err( p_filter, "Got invalid command: %s", p_cmd );
  225.             BufferPrintf( &p_sys->output, "FAILURE: %d Invalid Commandn", VLC_EGENERIC );
  226.         }
  227.         else
  228.         {
  229.             msg_Info( p_filter, "Got valid command: %s", p_cmd );
  230.             command_t *p_cmddesc = malloc( sizeof( command_t ) );
  231.             if( !p_cmddesc )
  232.                 return NULL;
  233.             p_cmd = p_cmd + strlen(p_cur->psz_command) +1;
  234.             p_cmddesc->p_command = p_cur;
  235.             p_cmddesc->p_command->pf_parser( p_cmd, p_end,
  236.                                              &p_cmddesc->params );
  237.             if( ( p_cmddesc->p_command->b_atomic == true ) &&
  238.                 ( p_sys->b_atomic == true ) )
  239.                 QueueEnqueue( &p_sys->atomic, p_cmddesc );
  240.             else
  241.                 QueueEnqueue( &p_sys->pending, p_cmddesc );
  242.         }
  243.         BufferDel( &p_sys->input, p_end - p_sys->input.p_begin + 1 );
  244.     }
  245.     /* Process any pending commands */
  246.     command_t *p_command = NULL;
  247.     while( (p_command = QueueDequeue( &p_sys->pending )) )
  248.     {
  249.         p_command->i_status =
  250.             p_command->p_command->pf_execute( p_filter, &p_command->params,
  251.                                               &p_command->results );
  252.         QueueEnqueue( &p_sys->processed, p_command );
  253.     }
  254.     /* Output any processed commands */
  255.     while( (p_command = QueueDequeue( &p_sys->processed )) )
  256.     {
  257.         if( p_command->i_status == VLC_SUCCESS )
  258.         {
  259.             const char *psz_success = "SUCCESS:";
  260.             const char *psz_nl = "n";
  261.             BufferAdd( &p_sys->output, psz_success, 8 );
  262.             p_command->p_command->pf_unparse( &p_command->results,
  263.                                               &p_sys->output );
  264.             BufferAdd( &p_sys->output, psz_nl, 1 );
  265.         }
  266.         else
  267.         {
  268.             BufferPrintf( &p_sys->output, "FAILURE: %dn",
  269.                           p_command->i_status );
  270.         }
  271.     }
  272.     /* Try emptying the output buffer */
  273.     if( p_sys->i_outputfd != -1 )
  274.     {
  275.         ssize_t i_len = write( p_sys->i_outputfd, p_sys->output.p_begin,
  276.                               p_sys->output.i_length );
  277.         if( i_len == -1 )
  278.         {
  279.             /* We hit an error */
  280.             if( errno != EAGAIN )
  281.             {
  282.                 msg_Warn( p_filter, "Error on output file: %s",
  283.                           strerror( errno ) );
  284.                 close( p_sys->i_outputfd );
  285.                 p_sys->i_outputfd = -1;
  286.             }
  287.         }
  288.         else
  289.         {
  290.             BufferDel( &p_sys->output, i_len );
  291.         }
  292.     }
  293.     if( p_sys->b_updated == false )
  294.         return NULL;
  295.     subpicture_t *p_spu = NULL;
  296.     overlay_t *p_overlay = NULL;
  297.     p_spu = p_filter->pf_sub_buffer_new( p_filter );
  298.     if( !p_spu )
  299.     {
  300.         msg_Err( p_filter, "cannot allocate subpicture" );
  301.         return NULL;
  302.     }
  303.     p_spu->b_absolute = true;
  304.     p_spu->i_start = date;
  305.     p_spu->i_stop = 0;
  306.     p_spu->b_ephemer = true;
  307.     subpicture_region_t **pp_region = &p_spu->p_region;
  308.     while( (p_overlay = ListWalk( &p_sys->overlays )) )
  309.     {
  310.         subpicture_region_t *p_region;
  311.         *pp_region = p_region = subpicture_region_New( &p_overlay->format );
  312.         if( !p_region )
  313.             break;
  314.         msg_Dbg( p_filter, "Displaying overlay: %4.4s, %d, %d, %d",
  315.                  (char*)&p_overlay->format.i_chroma, p_overlay->i_x, p_overlay->i_y,
  316.                  p_overlay->i_alpha );
  317.         if( p_overlay->format.i_chroma == VLC_FOURCC('T','E','X','T') )
  318.         {
  319.             p_region->psz_text = strdup( p_overlay->data.p_text );
  320.             p_region->p_style = malloc( sizeof(struct text_style_t) );
  321.             if( p_region->p_style )
  322.                 *p_region->p_style = p_overlay->fontstyle;
  323.         }
  324.         else
  325.         {
  326.             /* FIXME the copy is probably not needed anymore */
  327.             picture_Copy( p_region->p_picture, p_overlay->data.p_pic );
  328.         }
  329.         p_region->i_x = p_overlay->i_x;
  330.         p_region->i_y = p_overlay->i_y;
  331.         p_region->i_align = OSD_ALIGN_LEFT | OSD_ALIGN_TOP;
  332.         p_region->i_alpha = p_overlay->i_alpha;
  333.         pp_region = &p_region->p_next;
  334.     }
  335.     p_sys->b_updated = false;
  336.     return p_spu;
  337. }
  338. static int AdjustCallback( vlc_object_t *p_this, char const *psz_var,
  339.                            vlc_value_t oldval, vlc_value_t newval,
  340.                            void *p_data )
  341. {
  342.     filter_sys_t *p_sys = (filter_sys_t *)p_data;
  343.     VLC_UNUSED(p_this); VLC_UNUSED(oldval);
  344.     vlc_mutex_lock( &p_sys->lock );
  345.     if( !strncmp( psz_var, "overlay-input", 13 ) )
  346.     {
  347.         free( p_sys->psz_inputfile );
  348.         p_sys->psz_inputfile = strdup( newval.psz_string );
  349.     }
  350.     else if( !strncmp( psz_var, "overlay-output", 14 ) )
  351.     {
  352.         free( p_sys->psz_outputfile );
  353.         p_sys->psz_outputfile = strdup( newval.psz_string );
  354.     }
  355.     vlc_mutex_unlock( &p_sys->lock );
  356.     return VLC_EGENERIC;
  357. }