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

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * vout_subpictures.c : subpicture management functions
  3.  *****************************************************************************
  4.  * Copyright (C) 2000-2004 VideoLAN
  5.  * $Id: vout_subpictures.c 9274 2004-11-10 15:16:51Z gbazin $
  6.  *
  7.  * Authors: Vincent Seguin <seguin@via.ecp.fr>
  8.  *          Samuel Hocevar <sam@zoy.org>
  9.  *          Gildas Bazin <gbazin@videolan.org>
  10.  *
  11.  * This program is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 2 of the License, or
  14.  * (at your option) any later version.
  15.  *
  16.  * This program is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  *
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with this program; if not, write to the Free Software
  23.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  24.  *****************************************************************************/
  25. /*****************************************************************************
  26.  * Preamble
  27.  *****************************************************************************/
  28. #include <stdlib.h>                                                /* free() */
  29. #include <stdio.h>                                              /* sprintf() */
  30. #include <string.h>                                            /* strerror() */
  31. #include <vlc/vlc.h>
  32. #include "vlc_block.h"
  33. #include "vlc_video.h"
  34. #include "video_output.h"
  35. #include "vlc_spu.h"
  36. #include "vlc_filter.h"
  37. /*****************************************************************************
  38.  * Local prototypes
  39.  *****************************************************************************/
  40. static void UpdateSPU   ( spu_t *, vlc_object_t * );
  41. static int  CropCallback( vlc_object_t *, char const *,
  42.                           vlc_value_t, vlc_value_t, void * );
  43. static int spu_vaControlDefault( spu_t *, int, va_list );
  44. static subpicture_t *sub_new_buffer( filter_t * );
  45. static void sub_del_buffer( filter_t *, subpicture_t * );
  46. static subpicture_t *spu_new_buffer( filter_t * );
  47. static void spu_del_buffer( filter_t *, subpicture_t * );
  48. static picture_t *spu_new_video_buffer( filter_t * );
  49. static void spu_del_video_buffer( filter_t *, picture_t * );
  50. struct filter_owner_sys_t
  51. {
  52.     spu_t *p_spu;
  53.     int i_channel;
  54. };
  55. /**
  56.  * Creates the subpicture unit
  57.  *
  58.  * param p_this the parent object which creates the subpicture unit
  59.  */
  60. spu_t *__spu_Create( vlc_object_t *p_this )
  61. {
  62.     int i_index;
  63.     spu_t *p_spu = vlc_object_create( p_this, VLC_OBJECT_SPU );
  64.     for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++)
  65.     {
  66.         p_spu->p_subpicture[i_index].i_status = FREE_SUBPICTURE;
  67.     }
  68.     p_spu->p_blend = NULL;
  69.     p_spu->p_text = NULL;
  70.     p_spu->p_scale = NULL;
  71.     p_spu->i_filter = 0;
  72.     p_spu->pf_control = spu_vaControlDefault;
  73.     /* Register the default subpicture channel */
  74.     p_spu->i_channel = 2;
  75.     vlc_mutex_init( p_this, &p_spu->subpicture_lock );
  76.     vlc_object_attach( p_spu, p_this );
  77.     return p_spu;
  78. }
  79. /**
  80.  * Initialise the subpicture unit
  81.  *
  82.  * param p_spu the subpicture unit object
  83.  */
  84. int spu_Init( spu_t *p_spu )
  85. {
  86.     char *psz_filter, *psz_filter_orig;
  87.     vlc_value_t val;
  88.     /* If the user requested an SPU margin, we force the position. */
  89.     var_Create( p_spu, "spumargin", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
  90.     var_Get( p_spu, "spumargin", &val );
  91.     p_spu->i_margin = val.i_int;
  92.     var_Create( p_spu, "sub-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
  93.     var_Get( p_spu, "sub-filter", &val );
  94.     psz_filter = psz_filter_orig = val.psz_string;
  95.     while( psz_filter && *psz_filter )
  96.     {
  97.         char *psz_parser = strchr( psz_filter, ',' );
  98.         if( !psz_parser ) psz_parser = strchr( psz_filter, ':' );
  99.         if( psz_parser ) *psz_parser++ = 0;
  100.         p_spu->pp_filter[p_spu->i_filter] =
  101.             vlc_object_create( p_spu, VLC_OBJECT_FILTER );
  102.         vlc_object_attach( p_spu->pp_filter[p_spu->i_filter], p_spu );
  103.         p_spu->pp_filter[p_spu->i_filter]->pf_sub_buffer_new = sub_new_buffer;
  104.         p_spu->pp_filter[p_spu->i_filter]->pf_sub_buffer_del = sub_del_buffer;
  105.         p_spu->pp_filter[p_spu->i_filter]->p_module =
  106.             module_Need( p_spu->pp_filter[p_spu->i_filter],
  107.                          "sub filter", psz_filter, 0 );
  108.         if( p_spu->pp_filter[p_spu->i_filter]->p_module )
  109.         {
  110.             filter_owner_sys_t *p_sys = malloc( sizeof(filter_owner_sys_t) );
  111.             p_spu->pp_filter[p_spu->i_filter]->p_owner = p_sys;
  112.             spu_Control( p_spu, SPU_CHANNEL_REGISTER, &p_sys->i_channel );
  113.             p_sys->p_spu = p_spu;
  114.             p_spu->i_filter++;
  115.         }
  116.         else
  117.         {
  118.             msg_Dbg( p_spu, "no sub filter found" );
  119.             vlc_object_detach( p_spu->pp_filter[p_spu->i_filter] );
  120.             vlc_object_destroy( p_spu->pp_filter[p_spu->i_filter] );
  121.         }
  122.         if( p_spu->i_filter >= 10 )
  123.         {
  124.             msg_Dbg( p_spu, "can't add anymore filters" );
  125.         }
  126.         psz_filter = psz_parser;
  127.     }
  128.     if( psz_filter_orig ) free( psz_filter_orig );
  129.     return VLC_EGENERIC;
  130. }
  131. /**
  132.  * Destroy the subpicture unit
  133.  *
  134.  * param p_this the parent object which destroys the subpicture unit
  135.  */
  136. void spu_Destroy( spu_t *p_spu )
  137. {
  138.     int i_index;
  139.     vlc_object_detach( p_spu );
  140.     /* Destroy all remaining subpictures */
  141.     for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++ )
  142.     {
  143.         if( p_spu->p_subpicture[i_index].i_status != FREE_SUBPICTURE )
  144.         {
  145.             spu_DestroySubpicture( p_spu, &p_spu->p_subpicture[i_index] );
  146.         }
  147.     }
  148.     if( p_spu->p_blend )
  149.     {
  150.         if( p_spu->p_blend->p_module )
  151.             module_Unneed( p_spu->p_blend, p_spu->p_blend->p_module );
  152.         vlc_object_detach( p_spu->p_blend );
  153.         vlc_object_destroy( p_spu->p_blend );
  154.     }
  155.     if( p_spu->p_text )
  156.     {
  157.         if( p_spu->p_text->p_module )
  158.             module_Unneed( p_spu->p_text, p_spu->p_text->p_module );
  159.         vlc_object_detach( p_spu->p_text );
  160.         vlc_object_destroy( p_spu->p_text );
  161.     }
  162.     if( p_spu->p_scale )
  163.     {
  164.         if( p_spu->p_scale->p_module )
  165.             module_Unneed( p_spu->p_scale, p_spu->p_scale->p_module );
  166.         vlc_object_detach( p_spu->p_scale );
  167.         vlc_object_destroy( p_spu->p_scale );
  168.     }
  169.     while( p_spu->i_filter-- )
  170.     {
  171.         module_Unneed( p_spu->pp_filter[p_spu->i_filter],
  172.                        p_spu->pp_filter[p_spu->i_filter]->p_module );
  173.         free( p_spu->pp_filter[p_spu->i_filter]->p_owner );
  174.         vlc_object_detach( p_spu->pp_filter[p_spu->i_filter] );
  175.         vlc_object_destroy( p_spu->pp_filter[p_spu->i_filter] );
  176.     }
  177.     vlc_mutex_destroy( &p_spu->subpicture_lock );
  178.     vlc_object_destroy( p_spu );
  179. }
  180. /**
  181.  * Attach/Detach the SPU from any input
  182.  *
  183.  * param p_this the object in which to destroy the subpicture unit
  184.  * param b_attach to select attach or detach
  185.  */
  186. void spu_Attach( spu_t *p_spu, vlc_object_t *p_this, vlc_bool_t b_attach )
  187. {
  188.     vlc_object_t *p_input;
  189.     p_input = vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_PARENT );
  190.     if( !p_input ) return;
  191.     if( b_attach )
  192.     {
  193.         UpdateSPU( p_spu, VLC_OBJECT(p_input) );
  194.         var_AddCallback( p_input, "highlight", CropCallback, p_spu );
  195.         vlc_object_release( p_input );
  196.     }
  197.     else
  198.     {
  199.         /* Delete callback */
  200.         var_DelCallback( p_input, "highlight", CropCallback, p_spu );
  201.         vlc_object_release( p_input );
  202.     }
  203. }
  204. /**
  205.  * Create a subpicture region
  206.  *
  207.  * param p_this vlc_object_t
  208.  * param p_fmt the format that this subpicture region should have
  209.  */
  210. static void RegionPictureRelease( picture_t *p_pic )
  211. {
  212.     if( p_pic->p_data_orig ) free( p_pic->p_data_orig );
  213. }
  214. subpicture_region_t *__spu_CreateRegion( vlc_object_t *p_this,
  215.                                          video_format_t *p_fmt )
  216. {
  217.     subpicture_region_t *p_region = malloc( sizeof(subpicture_region_t) );
  218.     memset( p_region, 0, sizeof(subpicture_region_t) );
  219.     p_region->p_next = 0;
  220.     p_region->p_cache = 0;
  221.     p_region->fmt = *p_fmt;
  222.     p_region->psz_text = 0;
  223.     if( p_fmt->i_chroma == VLC_FOURCC('Y','U','V','P') )
  224.         p_fmt->p_palette = p_region->fmt.p_palette =
  225.             malloc( sizeof(video_palette_t) );
  226.     else p_fmt->p_palette = p_region->fmt.p_palette = NULL;
  227.     p_region->picture.p_data_orig = 0;
  228.     if( p_fmt->i_chroma == VLC_FOURCC('T','E','X','T') ) return p_region;
  229.     vout_AllocatePicture( p_this, &p_region->picture, p_fmt->i_chroma,
  230.                           p_fmt->i_width, p_fmt->i_height, p_fmt->i_aspect );
  231.     if( !p_region->picture.i_planes )
  232.     {
  233.         free( p_region );
  234.         free( p_fmt->p_palette );
  235.         return NULL;
  236.     }
  237.     p_region->picture.pf_release = RegionPictureRelease;
  238.     return p_region;
  239. }
  240. /**
  241.  * Destroy a subpicture region
  242.  *
  243.  * param p_this vlc_object_t
  244.  * param p_region the subpicture region to destroy
  245.  */
  246. void __spu_DestroyRegion( vlc_object_t *p_this, subpicture_region_t *p_region )
  247. {
  248.     if( !p_region ) return;
  249.     if( p_region->picture.pf_release )
  250.         p_region->picture.pf_release( &p_region->picture );
  251.     if( p_region->fmt.p_palette ) free( p_region->fmt.p_palette );
  252.     if( p_region->psz_text ) free( p_region->psz_text );
  253.     if( p_region->p_cache ) __spu_DestroyRegion( p_this, p_region->p_cache );
  254.     free( p_region );
  255. }
  256. /**
  257.  * Display a subpicture
  258.  *
  259.  * Remove the reservation flag of a subpicture, which will cause it to be
  260.  * ready for display.
  261.  * param p_spu the subpicture unit object
  262.  * param p_subpic the subpicture to display
  263.  */
  264. void spu_DisplaySubpicture( spu_t *p_spu, subpicture_t *p_subpic )
  265. {
  266.     /* Check if status is valid */
  267.     if( p_subpic->i_status != RESERVED_SUBPICTURE )
  268.     {
  269.         msg_Err( p_spu, "subpicture %p has invalid status #%d",
  270.                  p_subpic, p_subpic->i_status );
  271.     }
  272.     /* Remove reservation flag */
  273.     p_subpic->i_status = READY_SUBPICTURE;
  274.     if( p_subpic->i_channel == DEFAULT_CHAN )
  275.     {
  276.         p_subpic->i_channel = 0xFFFF;
  277.         spu_Control( p_spu, SPU_CHANNEL_CLEAR, DEFAULT_CHAN );
  278.         p_subpic->i_channel = DEFAULT_CHAN;
  279.     }
  280. }
  281. /**
  282.  * Allocate a subpicture in the spu heap.
  283.  *
  284.  * This function create a reserved subpicture in the spu heap.
  285.  * A null pointer is returned if the function fails. This method provides an
  286.  * already allocated zone of memory in the spu data fields. It needs locking
  287.  * since several pictures can be created by several producers threads.
  288.  * param p_spu the subpicture unit in which to create the subpicture
  289.  * return NULL on error, a reserved subpicture otherwise
  290.  */
  291. subpicture_t *spu_CreateSubpicture( spu_t *p_spu )
  292. {
  293.     int                 i_subpic;                        /* subpicture index */
  294.     subpicture_t *      p_subpic = NULL;            /* first free subpicture */
  295.     /* Get lock */
  296.     vlc_mutex_lock( &p_spu->subpicture_lock );
  297.     /*
  298.      * Look for an empty place
  299.      */
  300.     p_subpic = NULL;
  301.     for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ )
  302.     {
  303.         if( p_spu->p_subpicture[i_subpic].i_status == FREE_SUBPICTURE )
  304.         {
  305.             /* Subpicture is empty and ready for allocation */
  306.             p_subpic = &p_spu->p_subpicture[i_subpic];
  307.             p_spu->p_subpicture[i_subpic].i_status = RESERVED_SUBPICTURE;
  308.             break;
  309.         }
  310.     }
  311.     /* If no free subpicture could be found */
  312.     if( p_subpic == NULL )
  313.     {
  314.         msg_Err( p_spu, "subpicture heap is full" );
  315.         vlc_mutex_unlock( &p_spu->subpicture_lock );
  316.         return NULL;
  317.     }
  318.     /* Copy subpicture information, set some default values */
  319.     memset( p_subpic, 0, sizeof(subpicture_t) );
  320.     p_subpic->i_status   = RESERVED_SUBPICTURE;
  321.     p_subpic->b_absolute = VLC_TRUE;
  322.     p_subpic->b_fade     = VLC_FALSE;
  323.     p_subpic->pf_render  = 0;
  324.     p_subpic->pf_destroy = 0;
  325.     p_subpic->p_sys      = 0;
  326.     vlc_mutex_unlock( &p_spu->subpicture_lock );
  327.     p_subpic->pf_create_region = __spu_CreateRegion;
  328.     p_subpic->pf_destroy_region = __spu_DestroyRegion;
  329.     return p_subpic;
  330. }
  331. /**
  332.  * Remove a subpicture from the heap
  333.  *
  334.  * This function frees a previously reserved subpicture.
  335.  * It is meant to be used when the construction of a picture aborted.
  336.  * This function does not need locking since reserved subpictures are ignored
  337.  * by the spu.
  338.  */
  339. void spu_DestroySubpicture( spu_t *p_spu, subpicture_t *p_subpic )
  340. {
  341.     /* Get lock */
  342.     vlc_mutex_lock( &p_spu->subpicture_lock );
  343.     /* There can be race conditions so we need to check the status */
  344.     if( p_subpic->i_status == FREE_SUBPICTURE )
  345.     {
  346.         vlc_mutex_unlock( &p_spu->subpicture_lock );
  347.         return;
  348.     }
  349.     /* Check if status is valid */
  350.     if( ( p_subpic->i_status != RESERVED_SUBPICTURE )
  351.            && ( p_subpic->i_status != READY_SUBPICTURE ) )
  352.     {
  353.         msg_Err( p_spu, "subpicture %p has invalid status %d",
  354.                          p_subpic, p_subpic->i_status );
  355.     }
  356.     while( p_subpic->p_region )
  357.     {
  358.         subpicture_region_t *p_region = p_subpic->p_region;
  359.         p_subpic->p_region = p_region->p_next;
  360.         spu_DestroyRegion( p_spu, p_region );
  361.     }
  362.     if( p_subpic->pf_destroy )
  363.     {
  364.         p_subpic->pf_destroy( p_subpic );
  365.     }
  366.     p_subpic->i_status = FREE_SUBPICTURE;
  367.     vlc_mutex_unlock( &p_spu->subpicture_lock );
  368. }
  369. /*****************************************************************************
  370.  * spu_RenderSubpictures: render a subpicture list
  371.  *****************************************************************************
  372.  * This function renders all sub picture units in the list.
  373.  *****************************************************************************/
  374. void spu_RenderSubpictures( spu_t *p_spu, video_format_t *p_fmt,
  375.                             picture_t *p_pic_dst, picture_t *p_pic_src,
  376.                             subpicture_t *p_subpic,
  377.                             int i_scale_width_orig, int i_scale_height_orig )
  378. {
  379.     /* Get lock */
  380.     vlc_mutex_lock( &p_spu->subpicture_lock );
  381.     /* Check i_status again to make sure spudec hasn't destroyed the subpic */
  382.     while( p_subpic != NULL && p_subpic->i_status != FREE_SUBPICTURE )
  383.     {
  384.         subpicture_region_t *p_region = p_subpic->p_region;
  385.         int i_scale_width, i_scale_height;
  386.         /* Load the blending module */
  387.         if( !p_spu->p_blend && p_region )
  388.         {
  389.             p_spu->p_blend = vlc_object_create( p_spu, sizeof(filter_t) );
  390.             vlc_object_attach( p_spu->p_blend, p_spu );
  391.             p_spu->p_blend->fmt_out.video.i_x_offset =
  392.                 p_spu->p_blend->fmt_out.video.i_y_offset = 0;
  393.             p_spu->p_blend->fmt_out.video.i_aspect = p_fmt->i_aspect;
  394.             p_spu->p_blend->fmt_out.video.i_chroma = p_fmt->i_chroma;
  395.             p_spu->p_blend->fmt_in.video.i_chroma = VLC_FOURCC('Y','U','V','P');
  396.             p_spu->p_blend->p_module =
  397.                 module_Need( p_spu->p_blend, "video blending", 0, 0 );
  398.         }
  399.         /* Load the text rendering module */
  400.         if( !p_spu->p_text && p_region )
  401.         {
  402.             p_spu->p_text = vlc_object_create( p_spu, sizeof(filter_t) );
  403.             vlc_object_attach( p_spu->p_text, p_spu );
  404.             p_spu->p_text->fmt_out.video.i_width =
  405.                 p_spu->p_text->fmt_out.video.i_visible_width =
  406.                     p_fmt->i_width;
  407.             p_spu->p_text->fmt_out.video.i_height =
  408.                 p_spu->p_text->fmt_out.video.i_visible_height =
  409.                     p_fmt->i_height;
  410.             p_spu->p_text->pf_sub_buffer_new = spu_new_buffer;
  411.             p_spu->p_text->pf_sub_buffer_del = spu_del_buffer;
  412.             p_spu->p_text->p_module =
  413.                 module_Need( p_spu->p_text, "text renderer", 0, 0 );
  414.         }
  415.         i_scale_width = i_scale_width_orig;
  416.         i_scale_height = i_scale_height_orig;
  417.         if( p_subpic->i_original_picture_width &&
  418.             p_subpic->i_original_picture_height )
  419.         {
  420.             i_scale_width = i_scale_width * p_fmt->i_width /
  421.                 p_subpic->i_original_picture_width;
  422.             i_scale_height = i_scale_height * p_fmt->i_height /
  423.                 p_subpic->i_original_picture_height;
  424.         }
  425.         /* Take care of the aspect ratio */
  426.         if( p_region && p_region->fmt.i_sar_num * p_fmt->i_sar_den !=
  427.             p_region->fmt.i_sar_den * p_fmt->i_sar_num )
  428.         {
  429.             i_scale_width = i_scale_width *
  430.                 (int64_t)p_region->fmt.i_sar_num * p_fmt->i_sar_den /
  431.                 p_region->fmt.i_sar_den / p_fmt->i_sar_num;
  432.         }
  433.         /* Load the scaling module */
  434.         if( !p_spu->p_scale && (i_scale_width != 1000 ||
  435.             i_scale_height != 1000) )
  436.         {
  437.             p_spu->p_scale = vlc_object_create( p_spu, VLC_OBJECT_FILTER );
  438.             vlc_object_attach( p_spu->p_scale, p_spu );
  439.             p_spu->p_scale->fmt_out.video.i_chroma =
  440.                 p_spu->p_scale->fmt_in.video.i_chroma =
  441.                     VLC_FOURCC('Y','U','V','P');
  442.             p_spu->p_scale->fmt_in.video.i_width =
  443.                 p_spu->p_scale->fmt_in.video.i_height = 32;
  444.             p_spu->p_scale->fmt_out.video.i_width =
  445.                 p_spu->p_scale->fmt_out.video.i_height = 16;
  446.             p_spu->p_scale->pf_vout_buffer_new = spu_new_video_buffer;
  447.             p_spu->p_scale->pf_vout_buffer_del = spu_del_video_buffer;
  448.             p_spu->p_scale->p_module =
  449.                 module_Need( p_spu->p_scale, "video filter2", 0, 0 );
  450.         }
  451.         if( p_subpic->pf_render )
  452.         {
  453.             /* HACK to remove when the ogt subpic decoder is gone */
  454.             if( p_spu->p_parent &&
  455.                 p_spu->p_parent->i_object_type == VLC_OBJECT_VOUT )
  456.             {
  457.                 vout_thread_t *p_vout = (vout_thread_t *)p_spu->p_parent;
  458.                 p_subpic->pf_render( p_vout, p_pic_dst, p_subpic );
  459.             }
  460.         }
  461.         else while( p_region && p_spu->p_blend &&
  462.                     p_spu->p_blend->pf_video_blend )
  463.         {
  464.             int i_fade_alpha = 255;
  465.             int i_x_offset = p_region->i_x + p_subpic->i_x;
  466.             int i_y_offset = p_region->i_y + p_subpic->i_y;
  467.             if( p_region->fmt.i_chroma == VLC_FOURCC('T','E','X','T') )
  468.             {
  469.                 if( p_spu->p_text && p_spu->p_text->p_module &&
  470.                     p_spu->p_text->pf_render_string )
  471.                 {
  472.                     /* TODO: do it in a less hacky way
  473.                      * (modify text renderer API) */
  474.                     subpicture_t *p_subpic_tmp;
  475.                     subpicture_region_t tmp_region;
  476.                     block_t *p_new_block =
  477.                         block_New( p_spu, strlen(p_region->psz_text) + 1 );
  478.                     if( p_new_block )
  479.                     {
  480.                         memcpy( p_new_block->p_buffer, p_region->psz_text,
  481.                                 p_new_block->i_buffer );
  482.                         p_new_block->i_pts = p_new_block->i_dts =
  483.                             p_subpic->i_start;
  484.                         p_new_block->i_length =
  485.                             p_subpic->i_start - p_subpic->i_stop;
  486.                         p_subpic_tmp = p_spu->p_text->pf_render_string(
  487.                             p_spu->p_text, p_new_block );
  488.                         if( p_subpic_tmp )
  489.                         {
  490.                             tmp_region = *p_region;
  491.                             *p_region = *p_subpic_tmp->p_region;
  492.                             p_region->p_next = tmp_region.p_next;
  493.                             *p_subpic_tmp->p_region = tmp_region;
  494.                             p_spu->p_text->pf_sub_buffer_del( p_spu->p_text,
  495.                                                               p_subpic_tmp );
  496.                         }
  497.                     }
  498.                 }
  499.             }
  500.             /* Force palette if requested */
  501.             if( p_spu->b_force_alpha && VLC_FOURCC('Y','U','V','P') ==
  502.                 p_region->fmt.i_chroma )
  503.             {
  504.                 p_region->fmt.p_palette->palette[0][3] = p_spu->pi_alpha[0];
  505.                 p_region->fmt.p_palette->palette[1][3] = p_spu->pi_alpha[1];
  506.                 p_region->fmt.p_palette->palette[2][3] = p_spu->pi_alpha[2];
  507.                 p_region->fmt.p_palette->palette[3][3] = p_spu->pi_alpha[3];
  508.             }
  509.             /* Scale SPU if necessary */
  510.             if( p_region->p_cache )
  511.             {
  512.                 if( i_scale_width * p_region->fmt.i_width / 1000 !=
  513.                     p_region->p_cache->fmt.i_width ||
  514.                     i_scale_height * p_region->fmt.i_height / 1000 !=
  515.                     p_region->p_cache->fmt.i_height )
  516.                 {
  517.                     p_subpic->pf_destroy_region( VLC_OBJECT(p_spu),
  518.                                                  p_region->p_cache );
  519.                     p_region->p_cache = 0;
  520.                 }
  521.             }
  522.             if( (i_scale_width != 1000 || i_scale_height != 1000) &&
  523.                 p_spu->p_scale && !p_region->p_cache )
  524.             {
  525.                 picture_t *p_pic;
  526.                 p_spu->p_scale->fmt_in.video = p_region->fmt;
  527.                 p_spu->p_scale->fmt_out.video = p_region->fmt;
  528.                 p_region->p_cache =
  529.                     p_subpic->pf_create_region( VLC_OBJECT(p_spu),
  530.                         &p_spu->p_scale->fmt_out.video );
  531.                 if( p_spu->p_scale->fmt_out.video.p_palette )
  532.                     *p_spu->p_scale->fmt_out.video.p_palette =
  533.                         *p_region->fmt.p_palette;
  534.                 p_region->p_cache->p_next = p_region->p_next;
  535.                 vout_CopyPicture( p_spu, &p_region->p_cache->picture,
  536.                                   &p_region->picture );
  537.                 p_spu->p_scale->fmt_out.video.i_width =
  538.                     p_region->fmt.i_width * i_scale_width / 1000;
  539.                 p_spu->p_scale->fmt_out.video.i_visible_width =
  540.                     p_region->fmt.i_visible_width * i_scale_width / 1000;
  541.                 p_spu->p_scale->fmt_out.video.i_height =
  542.                     p_region->fmt.i_height * i_scale_height / 1000;
  543.                 p_spu->p_scale->fmt_out.video.i_visible_height =
  544.                     p_region->fmt.i_visible_height * i_scale_height / 1000;
  545.                 p_region->p_cache->fmt = p_spu->p_scale->fmt_out.video;
  546.                 p_region->p_cache->i_x = p_region->i_x * i_scale_width / 1000;
  547.                 p_region->p_cache->i_y = p_region->i_y * i_scale_height / 1000;
  548.                 p_pic = p_spu->p_scale->pf_video_filter(
  549.                                  p_spu->p_scale, &p_region->p_cache->picture );
  550.                 if( p_pic )
  551.                 {
  552.                     picture_t p_pic_tmp = p_region->p_cache->picture;
  553.                     p_region->p_cache->picture = *p_pic;
  554.                     *p_pic = p_pic_tmp;
  555.                     free( p_pic );
  556.                 }
  557.             }
  558.             if( (i_scale_width != 1000 || i_scale_height != 1000) &&
  559.                 p_spu->p_scale && p_region->p_cache )
  560.             {
  561.                 p_region = p_region->p_cache;
  562.             }
  563.             if( p_subpic->i_flags & SUBPICTURE_ALIGN_BOTTOM )
  564.             {
  565.                 i_y_offset = p_fmt->i_height - p_region->fmt.i_height -
  566.                     p_subpic->i_y;
  567.             }
  568.             else if ( !(p_subpic->i_flags & SUBPICTURE_ALIGN_TOP) )
  569.             {
  570.                 i_y_offset = p_fmt->i_height / 2 - p_region->fmt.i_height / 2;
  571.             }
  572.             if( p_subpic->i_flags & SUBPICTURE_ALIGN_RIGHT )
  573.             {
  574.                 i_x_offset = p_fmt->i_width - p_region->fmt.i_width -
  575.                     p_subpic->i_x;
  576.             }
  577.             else if ( !(p_subpic->i_flags & SUBPICTURE_ALIGN_LEFT) )
  578.             {
  579.                 i_x_offset = p_fmt->i_width / 2 - p_region->fmt.i_width / 2;
  580.             }
  581.             if( p_subpic->b_absolute )
  582.             {
  583.                 i_x_offset = p_region->i_x +
  584.                     p_subpic->i_x * i_scale_width / 1000;
  585.                 i_y_offset = p_region->i_y +
  586.                     p_subpic->i_y * i_scale_height / 1000;
  587.                 if( p_spu->i_margin >= 0 )
  588.                 {
  589.                     if( p_subpic->i_height + (unsigned int)p_spu->i_margin <=
  590.                         p_fmt->i_height )
  591.                     {
  592.                         i_y_offset = p_fmt->i_height -
  593.                             p_spu->i_margin - p_subpic->i_height;
  594.                     }
  595.                 }
  596.             }
  597.             p_spu->p_blend->fmt_in.video = p_region->fmt;
  598.             /* Force cropping if requested */
  599.             if( p_spu->b_force_crop )
  600.             {
  601.                 video_format_t *p_fmt = &p_spu->p_blend->fmt_in.video;
  602. int i_crop_x = p_spu->i_crop_x * i_scale_width / 1000;
  603. int i_crop_y = p_spu->i_crop_y * i_scale_height / 1000;
  604. int i_crop_width = p_spu->i_crop_width * i_scale_width / 1000;
  605. int i_crop_height = p_spu->i_crop_height * i_scale_height/1000;
  606.                 /* Find the intersection */
  607.                 if( i_crop_x + i_crop_width <= i_x_offset ||
  608.                     i_x_offset + (int)p_fmt->i_visible_width < i_crop_x ||
  609.                     i_crop_y + i_crop_height <= i_y_offset ||
  610.                     i_y_offset + (int)p_fmt->i_visible_height < i_crop_y )
  611.                 {
  612.                     /* No intersection */
  613.                     p_fmt->i_visible_width = p_fmt->i_visible_height = 0;
  614.                 }
  615.                 else
  616.                 {
  617.                     int i_x, i_y, i_x_end, i_y_end;
  618.                     i_x = __MAX( i_crop_x, i_x_offset );
  619.                     i_y = __MAX( i_crop_y, i_y_offset );
  620.                     i_x_end = __MIN( i_crop_x + i_crop_width,
  621.                                    i_x_offset + (int)p_fmt->i_visible_width );
  622.                     i_y_end = __MIN( i_crop_y + i_crop_height,
  623.                                    i_y_offset + (int)p_fmt->i_visible_height );
  624.                     p_fmt->i_x_offset = i_x - i_x_offset;
  625.                     p_fmt->i_y_offset = i_y - i_y_offset;
  626.                     p_fmt->i_visible_width = i_x_end - i_x;
  627.                     p_fmt->i_visible_height = i_y_end - i_y;
  628.                     i_x_offset = i_x;
  629.                     i_y_offset = i_y;
  630.                 }
  631.             }
  632.             /* Update the output picture size */
  633.             p_spu->p_blend->fmt_out.video.i_width =
  634.                 p_spu->p_blend->fmt_out.video.i_visible_width =
  635.                     p_fmt->i_width;
  636.             p_spu->p_blend->fmt_out.video.i_height =
  637.                 p_spu->p_blend->fmt_out.video.i_visible_height =
  638.                     p_fmt->i_height;
  639.             if( p_subpic->b_fade )
  640.             {
  641.                 mtime_t i_fade_start = ( p_subpic->i_stop +
  642.                                          p_subpic->i_start ) / 2;
  643.                 mtime_t i_now = mdate();
  644.                 if( i_now >= i_fade_start && p_subpic->i_stop > i_fade_start )
  645.                 {
  646.                     i_fade_alpha = 255 * ( p_subpic->i_stop - i_now ) /
  647.                                    ( p_subpic->i_stop - i_fade_start );
  648.                 }
  649.             }
  650.             p_spu->p_blend->pf_video_blend( p_spu->p_blend, p_pic_dst,
  651.                 p_pic_src, &p_region->picture, i_x_offset, i_y_offset,
  652.                 i_fade_alpha );
  653.             p_region = p_region->p_next;
  654.         }
  655.         p_subpic = p_subpic->p_next;
  656.     }
  657.     vlc_mutex_unlock( &p_spu->subpicture_lock );
  658. }
  659. /*****************************************************************************
  660.  * spu_SortSubpictures: find the subpictures to display
  661.  *****************************************************************************
  662.  * This function parses all subpictures and decides which ones need to be
  663.  * displayed. This operation does not need lock, since only READY_SUBPICTURE
  664.  * are handled. If no picture has been selected, display_date will depend on
  665.  * the subpicture.
  666.  * We also check for ephemer DVD subpictures (subpictures that have
  667.  * to be removed if a newer one is available), which makes it a lot
  668.  * more difficult to guess if a subpicture has to be rendered or not.
  669.  *****************************************************************************/
  670. subpicture_t *spu_SortSubpictures( spu_t *p_spu, mtime_t display_date )
  671. {
  672.     int i_index, i_channel;
  673.     subpicture_t *p_subpic = NULL;
  674.     subpicture_t *p_ephemer;
  675.     mtime_t      ephemer_date;
  676.     /* Run subpicture filters */
  677.     for( i_index = 0; i_index < p_spu->i_filter; i_index++ )
  678.     {
  679.         subpicture_t *p_subpic_filter;
  680.         p_subpic_filter = p_spu->pp_filter[i_index]->
  681.             pf_sub_filter( p_spu->pp_filter[i_index], display_date );
  682.         if( p_subpic_filter )
  683.         {
  684.             spu_DisplaySubpicture( p_spu, p_subpic_filter );
  685.         }
  686.     }
  687.     /* We get an easily parsable chained list of subpictures which
  688.      * ends with NULL since p_subpic was initialized to NULL. */
  689.     for( i_channel = 0; i_channel < p_spu->i_channel; i_channel++ )
  690.     {
  691.         p_ephemer = 0;
  692.         ephemer_date = 0;
  693.         for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++ )
  694.         {
  695.             if( p_spu->p_subpicture[i_index].i_channel != i_channel ||
  696.                 p_spu->p_subpicture[i_index].i_status != READY_SUBPICTURE )
  697.             {
  698.                 continue;
  699.             }
  700.             if( display_date &&
  701.                 display_date < p_spu->p_subpicture[i_index].i_start )
  702.             {
  703.                 /* Too early, come back next monday */
  704.                 continue;
  705.             }
  706.             if( p_spu->p_subpicture[i_index].i_start > ephemer_date )
  707.                 ephemer_date = p_spu->p_subpicture[i_index].i_start;
  708.             if( display_date > p_spu->p_subpicture[i_index].i_stop &&
  709.                 ( !p_spu->p_subpicture[i_index].b_ephemer ||
  710.                   p_spu->p_subpicture[i_index].i_stop >
  711.                   p_spu->p_subpicture[i_index].i_start ) )
  712.             {
  713.                 /* Too late, destroy the subpic */
  714.                 spu_DestroySubpicture( p_spu, &p_spu->p_subpicture[i_index] );
  715.                 continue;
  716.             }
  717.             /* If this is an ephemer subpic, add it to our list */
  718.             if( p_spu->p_subpicture[i_index].b_ephemer )
  719.             {
  720.                 p_spu->p_subpicture[i_index].p_next = p_ephemer;
  721.                 p_ephemer = &p_spu->p_subpicture[i_index];
  722.                 continue;
  723.             }
  724.             p_spu->p_subpicture[i_index].p_next = p_subpic;
  725.             p_subpic = &p_spu->p_subpicture[i_index];
  726.         }
  727.         /* If we found ephemer subpictures, check if they have to be
  728.          * displayed or destroyed */
  729.         while( p_ephemer != NULL )
  730.         {
  731.             subpicture_t *p_tmp = p_ephemer;
  732.             p_ephemer = p_ephemer->p_next;
  733.             if( p_tmp->i_start < ephemer_date )
  734.             {
  735.                 /* Ephemer subpicture has lived too long */
  736.                 spu_DestroySubpicture( p_spu, p_tmp );
  737.             }
  738.             else
  739.             {
  740.                 /* Ephemer subpicture can still live a bit */
  741.                 p_tmp->p_next = p_subpic;
  742.                 p_subpic = p_tmp;
  743.             }
  744.         }
  745.     }
  746.     return p_subpic;
  747. }
  748. /*****************************************************************************
  749.  * SpuClearChannel: clear an spu channel
  750.  *****************************************************************************
  751.  * This function destroys the subpictures which belong to the spu channel
  752.  * corresponding to i_channel_id.
  753.  *****************************************************************************/
  754. static void SpuClearChannel( spu_t *p_spu, int i_channel )
  755. {
  756.     int          i_subpic;                               /* subpicture index */
  757.     subpicture_t *p_subpic = NULL;                  /* first free subpicture */
  758.     vlc_mutex_lock( &p_spu->subpicture_lock );
  759.     for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ )
  760.     {
  761.         p_subpic = &p_spu->p_subpicture[i_subpic];
  762.         if( p_subpic->i_status == FREE_SUBPICTURE
  763.             || ( p_subpic->i_status != RESERVED_SUBPICTURE
  764.                  && p_subpic->i_status != READY_SUBPICTURE ) )
  765.         {
  766.             continue;
  767.         }
  768.         if( p_subpic->i_channel == i_channel )
  769.         {
  770.             while( p_subpic->p_region )
  771.             {
  772.                 subpicture_region_t *p_region = p_subpic->p_region;
  773.                 p_subpic->p_region = p_region->p_next;
  774.                 spu_DestroyRegion( p_spu, p_region );
  775.             }
  776.             if( p_subpic->pf_destroy ) p_subpic->pf_destroy( p_subpic );
  777.             p_subpic->i_status = FREE_SUBPICTURE;
  778.         }
  779.     }
  780.     vlc_mutex_unlock( &p_spu->subpicture_lock );
  781. }
  782. /*****************************************************************************
  783.  * spu_ControlDefault: default methods for the subpicture unit control.
  784.  *****************************************************************************/
  785. static int spu_vaControlDefault( spu_t *p_spu, int i_query, va_list args )
  786. {
  787.     int *pi, i;
  788.     switch( i_query )
  789.     {
  790.     case SPU_CHANNEL_REGISTER:
  791.         pi = (int *)va_arg( args, int * );
  792.         if( pi ) *pi = p_spu->i_channel++;
  793.         msg_Dbg( p_spu, "Registering subpicture channel, ID: %i",
  794.                  p_spu->i_channel - 1 );
  795.         break;
  796.     case SPU_CHANNEL_CLEAR:
  797.         i = (int)va_arg( args, int );
  798.         SpuClearChannel( p_spu, i );
  799.         break;
  800.     default:
  801.         msg_Dbg( p_spu, "control query not supported" );
  802.         return VLC_EGENERIC;
  803.     }
  804.     return VLC_SUCCESS;
  805. }
  806. /*****************************************************************************
  807.  * Object variables callbacks
  808.  *****************************************************************************/
  809. /*****************************************************************************
  810.  * UpdateSPU: update subpicture settings
  811.  *****************************************************************************
  812.  * This function is called from CropCallback and at initialization time, to
  813.  * retrieve crop information from the input.
  814.  *****************************************************************************/
  815. static void UpdateSPU( spu_t *p_spu, vlc_object_t *p_object )
  816. {
  817.     vlc_value_t val;
  818.     p_spu->b_force_alpha = VLC_FALSE;
  819.     p_spu->b_force_crop = VLC_FALSE;
  820.     if( var_Get( p_object, "highlight", &val ) || !val.b_bool ) return;
  821.     p_spu->b_force_crop = VLC_TRUE;
  822.     var_Get( p_object, "x-start", &val );
  823.     p_spu->i_crop_x = val.i_int;
  824.     var_Get( p_object, "y-start", &val );
  825.     p_spu->i_crop_y = val.i_int;
  826.     var_Get( p_object, "x-end", &val );
  827.     p_spu->i_crop_width = val.i_int - p_spu->i_crop_x;
  828.     var_Get( p_object, "y-end", &val );
  829.     p_spu->i_crop_height = val.i_int - p_spu->i_crop_y;
  830. #if 0
  831.     if( var_Get( p_object, "color", &val ) == VLC_SUCCESS )
  832.     {
  833.         int i;
  834.         for( i = 0; i < 4; i++ )
  835.         {
  836.             p_spu->pi_color[i] = ((uint8_t *)val.p_address)[i];
  837.         }
  838.     }
  839. #endif
  840.     if( var_Get( p_object, "contrast", &val ) == VLC_SUCCESS )
  841.     {
  842.         int i;
  843.         for( i = 0; i < 4; i++ )
  844.         {
  845.             p_spu->pi_alpha[i] = ((uint8_t *)val.p_address)[i];
  846.             p_spu->pi_alpha[i] = p_spu->pi_alpha[i] == 0xf ?
  847.                 0xff : p_spu->pi_alpha[i] << 4;
  848.         }
  849.         p_spu->b_force_alpha = VLC_TRUE;
  850.     }
  851.     msg_Dbg( p_object, "crop: %i,%i,%i,%i, alpha: %i",
  852.              p_spu->i_crop_x, p_spu->i_crop_y,
  853.              p_spu->i_crop_width, p_spu->i_crop_height, p_spu->b_force_alpha );
  854. }
  855. /*****************************************************************************
  856.  * CropCallback: called when the highlight properties are changed
  857.  *****************************************************************************
  858.  * This callback is called from the input thread when we need cropping
  859.  *****************************************************************************/
  860. static int CropCallback( vlc_object_t *p_object, char const *psz_var,
  861.                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
  862. {
  863.     UpdateSPU( (spu_t *)p_data, p_object );
  864.     return VLC_SUCCESS;
  865. }
  866. /*****************************************************************************
  867.  * Buffers allocation callbacks for the filters
  868.  *****************************************************************************/
  869. static subpicture_t *sub_new_buffer( filter_t *p_filter )
  870. {
  871.     filter_owner_sys_t *p_sys = p_filter->p_owner;
  872.     subpicture_t *p_subpicture = spu_CreateSubpicture( p_sys->p_spu );
  873.     if( p_subpicture ) p_subpicture->i_channel = p_sys->i_channel;
  874.     return p_subpicture;
  875. }
  876. static void sub_del_buffer( filter_t *p_filter, subpicture_t *p_subpic )
  877. {
  878.     filter_owner_sys_t *p_sys = p_filter->p_owner;
  879.     spu_DestroySubpicture( p_sys->p_spu, p_subpic );
  880. }
  881. static subpicture_t *spu_new_buffer( filter_t *p_filter )
  882. {
  883.     subpicture_t *p_subpic = (subpicture_t *)malloc(sizeof(subpicture_t));
  884.     memset( p_subpic, 0, sizeof(subpicture_t) );
  885.     p_subpic->b_absolute = VLC_TRUE;
  886.     p_subpic->pf_create_region = __spu_CreateRegion;
  887.     p_subpic->pf_destroy_region = __spu_DestroyRegion;
  888.     return p_subpic;
  889. }
  890. static void spu_del_buffer( filter_t *p_filter, subpicture_t *p_subpic )
  891. {
  892.     while( p_subpic->p_region )
  893.     {
  894.         subpicture_region_t *p_region = p_subpic->p_region;
  895.         p_subpic->p_region = p_region->p_next;
  896.         p_subpic->pf_destroy_region( VLC_OBJECT(p_filter), p_region );
  897.     }
  898.     free( p_subpic );
  899. }
  900. static picture_t *spu_new_video_buffer( filter_t *p_filter )
  901. {
  902.     picture_t *p_picture = malloc( sizeof(picture_t) );
  903.     if( vout_AllocatePicture( p_filter, p_picture,
  904.                               p_filter->fmt_out.video.i_chroma,
  905.                               p_filter->fmt_out.video.i_width,
  906.                               p_filter->fmt_out.video.i_height,
  907.                               p_filter->fmt_out.video.i_aspect )
  908.         != VLC_SUCCESS )
  909.     {
  910.         free( p_picture );
  911.         return NULL;
  912.     }
  913.     p_picture->pf_release = RegionPictureRelease;
  914.     return p_picture;
  915. }
  916. static void spu_del_video_buffer( filter_t *p_filter, picture_t *p_pic )
  917. {
  918.     if( p_pic && p_pic->p_data_orig ) free( p_pic->p_data_orig );
  919.     if( p_pic ) free( p_pic );
  920. }