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

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * vout_intf.c : video output interface
  3.  *****************************************************************************
  4.  * Copyright (C) 2000-2007 the VideoLAN team
  5.  *
  6.  * Authors: Gildas Bazin <gbazin@videolan.org>
  7.  *
  8.  * This program is free software; you can redistribute it and/or modify
  9.  * it under the terms of the GNU General Public License as published by
  10.  * the Free Software Foundation; either version 2 of the License, or
  11.  * (at your option) any later version.
  12.  *
  13.  * This program is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.  * GNU General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU General Public License
  19.  * along with this program; if not, write to the Free Software
  20.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  21.  *****************************************************************************/
  22. /*****************************************************************************
  23.  * Preamble
  24.  *****************************************************************************/
  25. #ifdef HAVE_CONFIG_H
  26. # include "config.h"
  27. #endif
  28. #include <vlc_common.h>
  29. #include <stdio.h>
  30. #include <stdlib.h>                                                /* free() */
  31. #include <sys/types.h>                                          /* opendir() */
  32. #include <sys/stat.h>
  33. #include <dirent.h>                                             /* opendir() */
  34. #include <assert.h>
  35. #include <time.h>                                           /* strftime */
  36. #include <vlc_interface.h>
  37. #include <vlc_block.h>
  38. #include <vlc_playlist.h>
  39. #include <vlc_vout.h>
  40. #include <vlc_window.h>
  41. #include <vlc_image.h>
  42. #include <vlc_osd.h>
  43. #include <vlc_charset.h>
  44. #include <vlc_strings.h>
  45. #include <vlc_charset.h>
  46. #include "../libvlc.h"
  47. #include "vout_internal.h"
  48. /*****************************************************************************
  49.  * Local prototypes
  50.  *****************************************************************************/
  51. static void InitWindowSize( vout_thread_t *, unsigned *, unsigned * );
  52. /* Object variables callbacks */
  53. static int ZoomCallback( vlc_object_t *, char const *,
  54.                          vlc_value_t, vlc_value_t, void * );
  55. static int CropCallback( vlc_object_t *, char const *,
  56.                          vlc_value_t, vlc_value_t, void * );
  57. static int AspectCallback( vlc_object_t *, char const *,
  58.                            vlc_value_t, vlc_value_t, void * );
  59. static int ScalingCallback( vlc_object_t *, char const *,
  60.                             vlc_value_t, vlc_value_t, void * );
  61. static int OnTopCallback( vlc_object_t *, char const *,
  62.                           vlc_value_t, vlc_value_t, void * );
  63. static int FullscreenCallback( vlc_object_t *, char const *,
  64.                                vlc_value_t, vlc_value_t, void * );
  65. static int SnapshotCallback( vlc_object_t *, char const *,
  66.                              vlc_value_t, vlc_value_t, void * );
  67. static int TitleShowCallback( vlc_object_t *, char const *,
  68.                               vlc_value_t, vlc_value_t, void * );
  69. static int TitleTimeoutCallback( vlc_object_t *, char const *,
  70.                                  vlc_value_t, vlc_value_t, void * );
  71. static int TitlePositionCallback( vlc_object_t *, char const *,
  72.                                   vlc_value_t, vlc_value_t, void * );
  73. /**
  74.  * Creates a video output window.
  75.  * On Unix systems, this is an X11 drawable (handle).
  76.  * On Windows, this is a Win32 window (handle).
  77.  * Video output plugins are supposed to called this function and display the
  78.  * video within the resulting window, while in windowed mode.
  79.  *
  80.  * @param p_vout video output thread to create a window for
  81.  * @param psz_cap VLC module capability (window system type)
  82.  * @param pi_x_hint pointer to store the recommended horizontal position [OUT]
  83.  * @param pi_y_hint pointer to store the recommended vertical position [OUT]
  84.  * @param pi_width_hint pointer to store the recommended width [OUT]
  85.  * @param pi_height_hint pointer to store the recommended height [OUT]
  86.  *
  87.  * @return a vout_window_t object, or NULL in case of failure.
  88.  * The window is released with vout_ReleaseWindow().
  89.  */
  90. vout_window_t *vout_RequestWindow( vout_thread_t *p_vout, const char *psz_cap,
  91.                           int *pi_x_hint, int *pi_y_hint,
  92.                           unsigned int *pi_width_hint,
  93.                           unsigned int *pi_height_hint )
  94. {
  95.     /* Get requested coordinates */
  96.     *pi_x_hint = var_GetInteger( p_vout, "video-x" );
  97.     *pi_y_hint = var_GetInteger( p_vout, "video-y" );
  98.     *pi_width_hint = p_vout->i_window_width;
  99.     *pi_height_hint = p_vout->i_window_height;
  100.     vout_window_t *wnd = vlc_custom_create (VLC_OBJECT(p_vout), sizeof (*wnd),
  101.                                             VLC_OBJECT_GENERIC, "window");
  102.     if (wnd == NULL)
  103.         return NULL;
  104.     wnd->vout = p_vout;
  105.     wnd->width = *pi_width_hint;
  106.     wnd->height = *pi_height_hint;
  107.     wnd->pos_x = *pi_x_hint;
  108.     wnd->pos_y = *pi_y_hint;
  109.     vlc_object_attach (wnd, p_vout);
  110.     wnd->module = module_need (wnd, psz_cap, NULL, false);
  111.     if (wnd->module == NULL)
  112.     {
  113.         msg_Dbg (wnd, "no "%s" window provider available", psz_cap);
  114.         vlc_object_release (wnd);
  115.         return NULL;
  116.     }
  117.     *pi_width_hint = wnd->width;
  118.     *pi_height_hint = wnd->height;
  119.     *pi_x_hint = wnd->pos_x;
  120.     *pi_y_hint = wnd->pos_y;
  121.     return wnd;
  122. }
  123. /**
  124.  * Releases a window handle obtained with vout_RequestWindow().
  125.  * @param p_vout video output thread that allocated the window
  126.  *               (if this is NULL; this fnction is a no-op).
  127.  */
  128. void vout_ReleaseWindow( vout_window_t *wnd )
  129. {
  130.     if (wnd == NULL)
  131.         return;
  132.     assert (wnd->module);
  133.     module_unneed (wnd, wnd->module);
  134.     vlc_object_release (wnd);
  135. }
  136. int vout_ControlWindow( vout_window_t *wnd, int i_query, va_list args )
  137. {
  138.     if (wnd == NULL)
  139.         return VLC_EGENERIC;
  140.     assert (wnd->control);
  141.     return wnd->control (wnd, i_query, args);
  142. }
  143. /*****************************************************************************
  144.  * vout_IntfInit: called during the vout creation to initialise misc things.
  145.  *****************************************************************************/
  146. static const struct
  147. {
  148.     double f_value;
  149.     const char *psz_label;
  150. } p_zoom_values[] = {
  151.     { 0.25, N_("1:4 Quarter") },
  152.     { 0.5, N_("1:2 Half") },
  153.     { 1, N_("1:1 Original") },
  154.     { 2, N_("2:1 Double") },
  155.     { 0, NULL } };
  156. static const struct
  157. {
  158.     const char *psz_value;
  159.     const char *psz_label;
  160. } p_crop_values[] = {
  161.     { "", N_("Default") },
  162.     { "16:10", "16:10" },
  163.     { "16:9", "16:9" },
  164.     { "185:100", "1.85:1" },
  165.     { "221:100", "2.21:1" },
  166.     { "235:100", "2.35:1" },
  167.     { "239:100", "2.39:1" },
  168.     { "5:3", "5:3" },
  169.     { "4:3", "4:3" },
  170.     { "5:4", "5:4" },
  171.     { "1:1", "1:1" },
  172.     { NULL, NULL } };
  173. static const struct
  174. {
  175.     const char *psz_value;
  176.     const char *psz_label;
  177. } p_aspect_ratio_values[] = {
  178.     { "", N_("Default") },
  179.     { "1:1", "1:1" },
  180.     { "4:3", "4:3" },
  181.     { "16:9", "16:9" },
  182.     { "16:10", "16:10" },
  183.     { "221:100", "2.21:1" },
  184.     { "5:4", "5:4" },
  185.     { NULL, NULL } };
  186. static void AddCustomRatios( vout_thread_t *p_vout, const char *psz_var,
  187.                              char *psz_list )
  188. {
  189.     if( psz_list && *psz_list )
  190.     {
  191.         char *psz_cur = psz_list;
  192.         char *psz_next;
  193.         while( psz_cur && *psz_cur )
  194.         {
  195.             vlc_value_t val, text;
  196.             psz_next = strchr( psz_cur, ',' );
  197.             if( psz_next )
  198.             {
  199.                 *psz_next = '';
  200.                 psz_next++;
  201.             }
  202.             val.psz_string = psz_cur;
  203.             text.psz_string = psz_cur;
  204.             var_Change( p_vout, psz_var, VLC_VAR_ADDCHOICE, &val, &text);
  205.             psz_cur = psz_next;
  206.         }
  207.     }
  208. }
  209. void vout_IntfInit( vout_thread_t *p_vout )
  210. {
  211.     vlc_value_t val, text, old_val;
  212.     bool b_force_par = false;
  213.     char *psz_buf;
  214.     int i;
  215.     /* Create a few object variables we'll need later on */
  216.     var_Create( p_vout, "snapshot-path", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
  217.     var_Create( p_vout, "snapshot-prefix", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
  218.     var_Create( p_vout, "snapshot-format", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
  219.     var_Create( p_vout, "snapshot-preview", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
  220.     var_Create( p_vout, "snapshot-sequential",
  221.                 VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
  222.     var_Create( p_vout, "snapshot-num", VLC_VAR_INTEGER );
  223.     var_SetInteger( p_vout, "snapshot-num", 1 );
  224.     var_Create( p_vout, "snapshot-width", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
  225.     var_Create( p_vout, "snapshot-height", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
  226.     var_Create( p_vout, "width", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
  227.     var_Create( p_vout, "height", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
  228.     p_vout->i_alignment = var_CreateGetInteger( p_vout, "align" );
  229.     var_Create( p_vout, "video-x", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
  230.     var_Create( p_vout, "video-y", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
  231.     var_Create( p_vout, "mouse-hide-timeout",
  232.                 VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
  233.     p_vout->p->b_title_show = var_CreateGetBool( p_vout, "video-title-show" );
  234.     p_vout->p->i_title_timeout =
  235.         (mtime_t)var_CreateGetInteger( p_vout, "video-title-timeout" );
  236.     p_vout->p->i_title_position =
  237.         var_CreateGetInteger( p_vout, "video-title-position" );
  238.     p_vout->p->psz_title =  NULL;
  239.     var_AddCallback( p_vout, "video-title-show", TitleShowCallback, NULL );
  240.     var_AddCallback( p_vout, "video-title-timeout", TitleTimeoutCallback, NULL );
  241.     var_AddCallback( p_vout, "video-title-position", TitlePositionCallback, NULL );
  242.     /* Zoom object var */
  243.     var_Create( p_vout, "zoom", VLC_VAR_FLOAT | VLC_VAR_ISCOMMAND |
  244.                 VLC_VAR_HASCHOICE | VLC_VAR_DOINHERIT );
  245.     text.psz_string = _("Zoom");
  246.     var_Change( p_vout, "zoom", VLC_VAR_SETTEXT, &text, NULL );
  247.     var_Get( p_vout, "zoom", &old_val );
  248.     for( i = 0; p_zoom_values[i].f_value; i++ )
  249.     {
  250.         if( old_val.f_float == p_zoom_values[i].f_value )
  251.             var_Change( p_vout, "zoom", VLC_VAR_DELCHOICE, &old_val, NULL );
  252.         val.f_float = p_zoom_values[i].f_value;
  253.         text.psz_string = _( p_zoom_values[i].psz_label );
  254.         var_Change( p_vout, "zoom", VLC_VAR_ADDCHOICE, &val, &text );
  255.     }
  256.     var_Set( p_vout, "zoom", old_val ); /* Is this really needed? */
  257.     var_AddCallback( p_vout, "zoom", ZoomCallback, NULL );
  258.     /* Crop offset vars */
  259.     var_Create( p_vout, "crop-left", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
  260.     var_Create( p_vout, "crop-top", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
  261.     var_Create( p_vout, "crop-right", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
  262.     var_Create( p_vout, "crop-bottom", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND );
  263.     var_AddCallback( p_vout, "crop-left", CropCallback, NULL );
  264.     var_AddCallback( p_vout, "crop-top", CropCallback, NULL );
  265.     var_AddCallback( p_vout, "crop-right", CropCallback, NULL );
  266.     var_AddCallback( p_vout, "crop-bottom", CropCallback, NULL );
  267.     /* Crop object var */
  268.     var_Create( p_vout, "crop", VLC_VAR_STRING | VLC_VAR_ISCOMMAND |
  269.                 VLC_VAR_HASCHOICE | VLC_VAR_DOINHERIT );
  270.     text.psz_string = _("Crop");
  271.     var_Change( p_vout, "crop", VLC_VAR_SETTEXT, &text, NULL );
  272.     val.psz_string = (char*)"";
  273.     var_Change( p_vout, "crop", VLC_VAR_DELCHOICE, &val, 0 );
  274.     for( i = 0; p_crop_values[i].psz_value; i++ )
  275.     {
  276.         val.psz_string = (char*)p_crop_values[i].psz_value;
  277.         text.psz_string = _( p_crop_values[i].psz_label );
  278.         var_Change( p_vout, "crop", VLC_VAR_ADDCHOICE, &val, &text );
  279.     }
  280.     /* update triggered every time the vout's crop parameters are changed */
  281.     var_Create( p_vout, "crop-update", VLC_VAR_VOID );
  282.     /* Add custom crop ratios */
  283.     psz_buf = config_GetPsz( p_vout, "custom-crop-ratios" );
  284.     AddCustomRatios( p_vout, "crop", psz_buf );
  285.     free( psz_buf );
  286.     var_AddCallback( p_vout, "crop", CropCallback, NULL );
  287.     var_Get( p_vout, "crop", &old_val );
  288.     if( old_val.psz_string && *old_val.psz_string )
  289.         var_TriggerCallback( p_vout, "crop" );
  290.     free( old_val.psz_string );
  291.     /* Monitor pixel aspect-ratio */
  292.     var_Create( p_vout, "monitor-par", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
  293.     var_Get( p_vout, "monitor-par", &val );
  294.     if( val.psz_string && *val.psz_string )
  295.     {
  296.         char *psz_parser = strchr( val.psz_string, ':' );
  297.         unsigned int i_aspect_num = 0, i_aspect_den = 0;
  298.         float i_aspect = 0;
  299.         if( psz_parser )
  300.         {
  301.             i_aspect_num = strtol( val.psz_string, 0, 10 );
  302.             i_aspect_den = strtol( ++psz_parser, 0, 10 );
  303.         }
  304.         else
  305.         {
  306.             i_aspect = us_atof( val.psz_string );
  307.             vlc_ureduce( &i_aspect_num, &i_aspect_den,
  308.                          i_aspect *VOUT_ASPECT_FACTOR, VOUT_ASPECT_FACTOR, 0 );
  309.         }
  310.         if( !i_aspect_num || !i_aspect_den ) i_aspect_num = i_aspect_den = 1;
  311.         p_vout->p->i_par_num = i_aspect_num;
  312.         p_vout->p->i_par_den = i_aspect_den;
  313.         vlc_ureduce( &p_vout->p->i_par_num, &p_vout->p->i_par_den,
  314.                      p_vout->p->i_par_num, p_vout->p->i_par_den, 0 );
  315.         msg_Dbg( p_vout, "overriding monitor pixel aspect-ratio: %i:%i",
  316.                  p_vout->p->i_par_num, p_vout->p->i_par_den );
  317.         b_force_par = true;
  318.     }
  319.     free( val.psz_string );
  320.     /* Aspect-ratio object var */
  321.     var_Create( p_vout, "aspect-ratio", VLC_VAR_STRING | VLC_VAR_ISCOMMAND |
  322.                 VLC_VAR_HASCHOICE | VLC_VAR_DOINHERIT );
  323.     text.psz_string = _("Aspect-ratio");
  324.     var_Change( p_vout, "aspect-ratio", VLC_VAR_SETTEXT, &text, NULL );
  325.     val.psz_string = (char*)"";
  326.     var_Change( p_vout, "aspect-ratio", VLC_VAR_DELCHOICE, &val, 0 );
  327.     for( i = 0; p_aspect_ratio_values[i].psz_value; i++ )
  328.     {
  329.         val.psz_string = (char*)p_aspect_ratio_values[i].psz_value;
  330.         text.psz_string = _( p_aspect_ratio_values[i].psz_label );
  331.         var_Change( p_vout, "aspect-ratio", VLC_VAR_ADDCHOICE, &val, &text );
  332.     }
  333.     /* Add custom aspect ratios */
  334.     psz_buf = config_GetPsz( p_vout, "custom-aspect-ratios" );
  335.     AddCustomRatios( p_vout, "aspect-ratio", psz_buf );
  336.     free( psz_buf );
  337.     var_AddCallback( p_vout, "aspect-ratio", AspectCallback, NULL );
  338.     var_Get( p_vout, "aspect-ratio", &old_val );
  339.     if( (old_val.psz_string && *old_val.psz_string) || b_force_par )
  340.         var_TriggerCallback( p_vout, "aspect-ratio" );
  341.     free( old_val.psz_string );
  342.     /* Add variables to manage scaling video */
  343.     var_Create( p_vout, "autoscale", VLC_VAR_BOOL | VLC_VAR_DOINHERIT
  344.                 | VLC_VAR_ISCOMMAND );
  345.     text.psz_string = _("Autoscale video");
  346.     var_Change( p_vout, "autoscale", VLC_VAR_SETTEXT, &text, NULL );
  347.     var_AddCallback( p_vout, "autoscale", ScalingCallback, NULL );
  348.     p_vout->b_autoscale = var_GetBool( p_vout, "autoscale" );
  349.     var_Create( p_vout, "scale", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT
  350.                 | VLC_VAR_ISCOMMAND );
  351.     text.psz_string = _("Scale factor");
  352.     var_Change( p_vout, "scale", VLC_VAR_SETTEXT, &text, NULL );
  353.     var_AddCallback( p_vout, "scale", ScalingCallback, NULL );
  354.     p_vout->i_zoom = (int)( ZOOM_FP_FACTOR * var_GetFloat( p_vout, "scale" ) );
  355.     /* Initialize the dimensions of the video window */
  356.     InitWindowSize( p_vout, &p_vout->i_window_width,
  357.                     &p_vout->i_window_height );
  358.     /* Add a variable to indicate if the window should be on top of others */
  359.     var_Create( p_vout, "video-on-top", VLC_VAR_BOOL | VLC_VAR_DOINHERIT
  360.                 | VLC_VAR_ISCOMMAND );
  361.     text.psz_string = _("Always on top");
  362.     var_Change( p_vout, "video-on-top", VLC_VAR_SETTEXT, &text, NULL );
  363.     var_AddCallback( p_vout, "video-on-top", OnTopCallback, NULL );
  364.     /* Add a variable to indicate whether we want window decoration or not */
  365.     var_Create( p_vout, "video-deco", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
  366.     /* Add a fullscreen variable */
  367.     if( var_CreateGetBoolCommand( p_vout, "fullscreen" ) )
  368.     {
  369.         /* user requested fullscreen */
  370.         p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
  371.     }
  372.     text.psz_string = _("Fullscreen");
  373.     var_Change( p_vout, "fullscreen", VLC_VAR_SETTEXT, &text, NULL );
  374.     var_AddCallback( p_vout, "fullscreen", FullscreenCallback, NULL );
  375.     /* Add a snapshot variable */
  376.     var_Create( p_vout, "video-snapshot", VLC_VAR_VOID | VLC_VAR_ISCOMMAND );
  377.     text.psz_string = _("Snapshot");
  378.     var_Change( p_vout, "video-snapshot", VLC_VAR_SETTEXT, &text, NULL );
  379.     var_AddCallback( p_vout, "video-snapshot", SnapshotCallback, NULL );
  380.     /* Mouse coordinates */
  381.     var_Create( p_vout, "mouse-x", VLC_VAR_INTEGER );
  382.     var_Create( p_vout, "mouse-y", VLC_VAR_INTEGER );
  383.     var_Create( p_vout, "mouse-button-down", VLC_VAR_INTEGER );
  384.     var_Create( p_vout, "mouse-moved", VLC_VAR_BOOL );
  385.     var_Create( p_vout, "mouse-clicked", VLC_VAR_BOOL );
  386.     var_Create( p_vout, "intf-change", VLC_VAR_BOOL );
  387.     var_SetBool( p_vout, "intf-change", true );
  388. }
  389. /*****************************************************************************
  390.  * vout_Snapshot: generates a snapshot.
  391.  *****************************************************************************/
  392. /**
  393.  * This function will inject a subpicture into the vout with the provided
  394.  * picture
  395.  */
  396. static int VoutSnapshotPip( vout_thread_t *p_vout, picture_t *p_pic )
  397. {
  398.     video_format_t fmt_in = p_pic->format;
  399.     video_format_t fmt_out;
  400.     picture_t *p_pip;
  401.     subpicture_t *p_subpic;
  402.     /* */
  403.     memset( &fmt_out, 0, sizeof(fmt_out) );
  404.     fmt_out = fmt_in;
  405.     fmt_out.i_chroma = VLC_FOURCC('Y','U','V','A');
  406.     /* */
  407.     image_handler_t *p_image = image_HandlerCreate( p_vout );
  408.     if( !p_image )
  409.         return VLC_EGENERIC;
  410.     p_pip = image_Convert( p_image, p_pic, &fmt_in, &fmt_out );
  411.     image_HandlerDelete( p_image );
  412.     if( !p_pip )
  413.         return VLC_EGENERIC;
  414.     p_subpic = subpicture_New();
  415.     if( !p_subpic )
  416.     {
  417.          picture_Release( p_pip );
  418.          return VLC_EGENERIC;
  419.     }
  420.     p_subpic->i_channel = 0;
  421.     p_subpic->i_start = mdate();
  422.     p_subpic->i_stop = mdate() + 4000000;
  423.     p_subpic->b_ephemer = true;
  424.     p_subpic->b_fade = true;
  425.     p_subpic->i_original_picture_width = fmt_out.i_width * 4;
  426.     p_subpic->i_original_picture_height = fmt_out.i_height * 4;
  427.     fmt_out.i_aspect = 0;
  428.     fmt_out.i_sar_num =
  429.     fmt_out.i_sar_den = 0;
  430.     p_subpic->p_region = subpicture_region_New( &fmt_out );
  431.     if( p_subpic->p_region )
  432.     {
  433.         picture_Release( p_subpic->p_region->p_picture );
  434.         p_subpic->p_region->p_picture = p_pip;
  435.     }
  436.     else
  437.     {
  438.         picture_Release( p_pip );
  439.     }
  440.     spu_DisplaySubpicture( p_vout->p_spu, p_subpic );
  441.     return VLC_SUCCESS;
  442. }
  443. /**
  444.  * This function will return the default directory used for snapshots
  445.  */
  446. static char *VoutSnapshotGetDefaultDirectory( void )
  447. {
  448.     char *psz_path = NULL;
  449. #if defined(__APPLE__) || defined(SYS_BEOS)
  450.     if( asprintf( &psz_path, "%s/Desktop",
  451.                   config_GetHomeDir() ) == -1 )
  452.         psz_path = NULL;
  453. #elif defined(WIN32) && !defined(UNDER_CE)
  454.     /* Get the My Pictures folder path */
  455.     char *p_mypicturesdir = NULL;
  456.     typedef HRESULT (WINAPI *SHGETFOLDERPATH)( HWND, int, HANDLE, DWORD,
  457.                                                LPWSTR );
  458.     #ifndef CSIDL_FLAG_CREATE
  459.     #   define CSIDL_FLAG_CREATE 0x8000
  460.     #endif
  461.     #ifndef CSIDL_MYPICTURES
  462.     #   define CSIDL_MYPICTURES 0x27
  463.     #endif
  464.     #ifndef SHGFP_TYPE_CURRENT
  465.     #   define SHGFP_TYPE_CURRENT 0
  466.     #endif
  467.     HINSTANCE shfolder_dll;
  468.     SHGETFOLDERPATH SHGetFolderPath ;
  469.     /* load the shfolder dll to retrieve SHGetFolderPath */
  470.     if( ( shfolder_dll = LoadLibrary( _T("SHFolder.dll") ) ) != NULL )
  471.     {
  472.        wchar_t wdir[PATH_MAX];
  473.        SHGetFolderPath = (void *)GetProcAddress( shfolder_dll,
  474.                                                   _T("SHGetFolderPathW") );
  475.         if ((SHGetFolderPath != NULL )
  476.          && SUCCEEDED (SHGetFolderPath (NULL,
  477.                                        CSIDL_MYPICTURES | CSIDL_FLAG_CREATE,
  478.                                        NULL, SHGFP_TYPE_CURRENT,
  479.                                        wdir)))
  480.             p_mypicturesdir = FromWide (wdir);
  481.         FreeLibrary( shfolder_dll );
  482.     }
  483.     if( p_mypicturesdir == NULL )
  484.         psz_path = strdup( config_GetHomeDir() );
  485.     else
  486.         psz_path = p_mypicturesdir;
  487. #else
  488.     /* XXX: This saves in the data directory. Shouldn't we try saving
  489.      *      to psz_homedir/Desktop or something nicer ? */
  490.     char *psz_datadir = config_GetUserDataDir();
  491.     if( psz_datadir )
  492.     {
  493.         if( asprintf( &psz_path, "%s", psz_datadir ) == -1 )
  494.             psz_path = NULL;
  495.         free( psz_datadir );
  496.     }
  497. #endif
  498.     return psz_path;
  499. }
  500. /**
  501.  * This function will save a video snapshot to a file
  502.  */
  503. static int VoutWriteSnapshot( vout_thread_t *p_vout, char **ppsz_filename,
  504.                               const block_t *p_image,
  505.                               const char *psz_path,
  506.                               const char *psz_format,
  507.                               const char *psz_prefix_fmt )
  508. {
  509.     /* */
  510.     char *psz_filename;
  511.     DIR *p_path = utf8_opendir( psz_path );
  512.     if( p_path != NULL )
  513.     {
  514.         /* The use specified a directory path */
  515.         closedir( p_path );
  516.         /* */
  517.         char *psz_prefix = NULL;
  518.         if( psz_prefix_fmt )
  519.             psz_prefix = str_format( p_vout, psz_prefix_fmt );
  520.         if( !psz_prefix )
  521.         {
  522.             psz_prefix = strdup( "vlcsnap-" );
  523.             if( !psz_prefix )
  524.                 goto error;
  525.         }
  526.         if( var_GetBool( p_vout, "snapshot-sequential" ) )
  527.         {
  528.             int i_num = var_GetInteger( p_vout, "snapshot-num" );
  529.             for( ; ; i_num++ )
  530.             {
  531.                 struct stat st;
  532.                 if( asprintf( &psz_filename, "%s" DIR_SEP "%s%05d.%s",
  533.                               psz_path, psz_prefix, i_num++, psz_format ) < 0 )
  534.                 {
  535.                     free( psz_prefix );
  536.                     goto error;
  537.                 }
  538.                 if( utf8_stat( psz_filename, &st ) )
  539.                     break;
  540.                 free( psz_filename );
  541.             }
  542.             var_SetInteger( p_vout, "snapshot-num", i_num );
  543.         }
  544.         else
  545.         {
  546.             struct tm    curtime;
  547.             time_t       lcurtime = time( NULL ) ;
  548.             if( !localtime_r( &lcurtime, &curtime ) )
  549.             {
  550.                 const unsigned int i_id = (p_image->i_pts / 100000) & 0xFFFFFF;
  551.                 msg_Warn( p_vout, "failed to get current time. Falling back to legacy snapshot naming" );
  552.                 if( asprintf( &psz_filename, "%s" DIR_SEP "%s%u.%s",
  553.                               psz_path, psz_prefix, i_id, psz_format ) < 0 )
  554.                     psz_filename = NULL;
  555.             }
  556.             else
  557.             {
  558.                 /* suffix with the last decimal digit in 10s of seconds resolution
  559.                  * FIXME gni ? */
  560.                 const int i_id = (p_image->i_pts / (100*1000)) & 0xFF;
  561.                 char psz_curtime[128];
  562.                 if( !strftime( psz_curtime, sizeof(psz_curtime), "%Y-%m-%d-%Hh%Mm%Ss", &curtime ) )
  563.                     strcpy( psz_curtime, "error" );
  564.                 if( asprintf( &psz_filename, "%s" DIR_SEP "%s%s%1u.%s",
  565.                               psz_path, psz_prefix, psz_curtime, i_id, psz_format ) < 0 )
  566.                     psz_filename = NULL;
  567.             }
  568.         }
  569.         free( psz_prefix );
  570.     }
  571.     else
  572.     {
  573.         /* The user specified a full path name (including file name) */
  574.         psz_filename = str_format( p_vout, psz_path );
  575.         path_sanitize( psz_filename );
  576.     }
  577.     if( !psz_filename )
  578.         goto error;
  579.     /* Save the snapshot */
  580.     FILE *p_file = utf8_fopen( psz_filename, "wb" );
  581.     if( !p_file )
  582.     {
  583.         msg_Err( p_vout, "Failed to open '%s'", psz_filename );
  584.         free( psz_filename );
  585.         goto error;
  586.     }
  587.     if( fwrite( p_image->p_buffer, p_image->i_buffer, 1, p_file ) != 1 )
  588.     {
  589.         msg_Err( p_vout, "Failed to write to '%s'", psz_filename );
  590.         fclose( p_file );
  591.         free( psz_filename );
  592.         goto error;
  593.     }
  594.     fclose( p_file );
  595.     /* */
  596.     if( ppsz_filename )
  597.         *ppsz_filename = psz_filename;
  598.     else
  599.         free( psz_filename );
  600.     return VLC_SUCCESS;
  601. error:
  602.     msg_Err( p_vout, "could not save snapshot" );
  603.     return VLC_EGENERIC;
  604. }
  605. /**
  606.  * This function will display the name and a PIP of the provided snapshot
  607.  */
  608. static void VoutOsdSnapshot( vout_thread_t *p_vout, picture_t *p_pic, const char *psz_filename )
  609. {
  610.     msg_Dbg( p_vout, "snapshot taken (%s)", psz_filename );
  611.     vout_OSDMessage( VLC_OBJECT( p_vout ), DEFAULT_CHAN, "%s", psz_filename );
  612.     if( var_GetBool( p_vout, "snapshot-preview" ) )
  613.     {
  614.         if( VoutSnapshotPip( p_vout, p_pic ) )
  615.             msg_Warn( p_vout, "Failed to display snapshot" );
  616.     }
  617. }
  618. /* */
  619. int vout_GetSnapshot( vout_thread_t *p_vout,
  620.                       block_t **pp_image, picture_t **pp_picture,
  621.                       video_format_t *p_fmt,
  622.                       const char *psz_format, mtime_t i_timeout )
  623. {
  624.     vout_thread_sys_t *p_sys = p_vout->p;
  625.     vlc_mutex_lock( &p_sys->snapshot.lock );
  626.     p_sys->snapshot.i_request++;
  627.     const mtime_t i_deadline = mdate() + i_timeout;
  628.     while( p_sys->snapshot.b_available && !p_sys->snapshot.p_picture &&
  629.            mdate() < i_deadline )
  630.     {
  631.         vlc_cond_timedwait( &p_sys->snapshot.wait, &p_sys->snapshot.lock,
  632.                             i_deadline );
  633.     }
  634.     picture_t *p_picture = p_sys->snapshot.p_picture;
  635.     if( p_picture )
  636.         p_sys->snapshot.p_picture = p_picture->p_next;
  637.     else if( p_sys->snapshot.i_request > 0 )
  638.         p_sys->snapshot.i_request--;
  639.     vlc_mutex_unlock( &p_sys->snapshot.lock );
  640.     if( !p_picture )
  641.     {
  642.         msg_Err( p_vout, "Failed to grab a snapshot" );
  643.         return VLC_EGENERIC;
  644.     }
  645.     if( pp_image )
  646.     {
  647.         vlc_fourcc_t i_format = VLC_FOURCC('p','n','g',' ');
  648.         if( psz_format && image_Type2Fourcc( psz_format ) )
  649.             i_format = image_Type2Fourcc( psz_format );
  650.         const int i_override_width  = var_GetInteger( p_vout, "snapshot-width" );
  651.         const int i_override_height = var_GetInteger( p_vout, "snapshot-height" );
  652.         if( picture_Export( VLC_OBJECT(p_vout), pp_image, p_fmt,
  653.                             p_picture, i_format, i_override_width, i_override_height ) )
  654.         {
  655.             msg_Err( p_vout, "Failed to convert image for snapshot" );
  656.             picture_Release( p_picture );
  657.             return VLC_EGENERIC;
  658.         }
  659.     }
  660.     if( pp_picture )
  661.         *pp_picture = p_picture;
  662.     else
  663.         picture_Release( p_picture );
  664.     return VLC_SUCCESS;
  665. }
  666. /**
  667.  * This function will handle a snapshot request
  668.  */
  669. static void VoutSaveSnapshot( vout_thread_t *p_vout )
  670. {
  671.     char *psz_path = var_GetNonEmptyString( p_vout, "snapshot-path" );
  672.     char *psz_format = var_GetNonEmptyString( p_vout, "snapshot-format" );
  673.     char *psz_prefix = var_GetNonEmptyString( p_vout, "snapshot-prefix" );
  674.     /* */
  675.     picture_t *p_picture;
  676.     block_t *p_image;
  677.     video_format_t fmt;
  678.     /* 500ms timeout
  679.      * XXX it will cause trouble with low fps video (< 2fps) */
  680.     if( vout_GetSnapshot( p_vout, &p_image, &p_picture, &fmt, psz_format, 500*1000 ) )
  681.     {
  682.         p_picture = NULL;
  683.         p_image = NULL;
  684.         goto exit;
  685.     }
  686.     if( !psz_path )
  687.     {
  688.         psz_path = VoutSnapshotGetDefaultDirectory();
  689.         if( !psz_path )
  690.         {
  691.             msg_Err( p_vout, "no path specified for snapshots" );
  692.             goto exit;
  693.         }
  694.     }
  695.     char *psz_filename;
  696.     if( VoutWriteSnapshot( p_vout, &psz_filename,
  697.                            p_image,
  698.                            psz_path, psz_format, psz_prefix ) )
  699.         goto exit;
  700.     VoutOsdSnapshot( p_vout, p_picture, psz_filename );
  701.     /* Generate a media player event  - Right now just trigger a global libvlc var
  702.         CHECK: Could not find a more local object. The goal is to communicate
  703.         vout_thread with libvlc_media_player or its input_thread */
  704.     var_SetString( p_vout->p_libvlc, "vout-snapshottaken", psz_filename );
  705.     free( psz_filename );
  706. exit:
  707.     if( p_image )
  708.         block_Release( p_image );
  709.     if( p_picture )
  710.         picture_Release( p_picture );
  711.     free( psz_prefix );
  712.     free( psz_format );
  713.     free( psz_path );
  714. }
  715. /*****************************************************************************
  716.  * Handle filters
  717.  *****************************************************************************/
  718. void vout_EnableFilter( vout_thread_t *p_vout, char *psz_name,
  719.                         bool b_add, bool b_setconfig )
  720. {
  721.     char *psz_parser;
  722.     char *psz_string = config_GetPsz( p_vout, "vout-filter" );
  723.     /* Todo : Use some generic chain manipulation functions */
  724.     if( !psz_string ) psz_string = strdup("");
  725.     psz_parser = strstr( psz_string, psz_name );
  726.     if( b_add )
  727.     {
  728.         if( !psz_parser )
  729.         {
  730.             psz_parser = psz_string;
  731.             if( asprintf( &psz_string, (*psz_string) ? "%s:%s" : "%s%s",
  732.                           psz_string, psz_name ) == -1 )
  733.             {
  734.                 free( psz_parser );
  735.                 return;
  736.             }
  737.             free( psz_parser );
  738.         }
  739.         else
  740.             return;
  741.     }
  742.     else
  743.     {
  744.         if( psz_parser )
  745.         {
  746.             memmove( psz_parser, psz_parser + strlen(psz_name) +
  747.                             (*(psz_parser + strlen(psz_name)) == ':' ? 1 : 0 ),
  748.                             strlen(psz_parser + strlen(psz_name)) + 1 );
  749.             /* Remove trailing : : */
  750.             if( *(psz_string+strlen(psz_string ) -1 ) == ':' )
  751.             {
  752.                 *(psz_string+strlen(psz_string ) -1 ) = '';
  753.             }
  754.          }
  755.          else
  756.          {
  757.              free( psz_string );
  758.              return;
  759.          }
  760.     }
  761.     if( b_setconfig )
  762.         config_PutPsz( p_vout, "vout-filter", psz_string );
  763.     var_SetString( p_vout, "vout-filter", psz_string );
  764.     free( psz_string );
  765. }
  766. /*****************************************************************************
  767.  * InitWindowSize: find the initial dimensions the video window should have.
  768.  *****************************************************************************
  769.  * This function will check the "width", "height" and "zoom" config options and
  770.  * will calculate the size that the video window should have.
  771.  *****************************************************************************/
  772. static void InitWindowSize( vout_thread_t *p_vout, unsigned *pi_width,
  773.                             unsigned *pi_height )
  774. {
  775. #define FP_FACTOR 1000                             /* our fixed point factor */
  776.     int i_width = var_GetInteger( p_vout, "width" );
  777.     int i_height = var_GetInteger( p_vout, "height" );
  778.     float f_zoom = var_GetFloat( p_vout, "zoom" );
  779.     uint64_t ll_zoom = (uint64_t)( FP_FACTOR * f_zoom );
  780.     if( i_width > 0 && i_height > 0)
  781.     {
  782.         *pi_width = (int)( i_width * ll_zoom / FP_FACTOR );
  783.         *pi_height = (int)( i_height * ll_zoom / FP_FACTOR );
  784.     }
  785.     else if( i_width > 0 )
  786.     {
  787.         *pi_width = (int)( i_width * ll_zoom / FP_FACTOR );
  788.         *pi_height = (int)( p_vout->fmt_in.i_visible_height * ll_zoom *
  789.             p_vout->fmt_in.i_sar_den * i_width / p_vout->fmt_in.i_sar_num /
  790.             FP_FACTOR / p_vout->fmt_in.i_visible_width );
  791.     }
  792.     else if( i_height > 0 )
  793.     {
  794.         *pi_height = (int)( i_height * ll_zoom / FP_FACTOR );
  795.         *pi_width = (int)( p_vout->fmt_in.i_visible_width * ll_zoom *
  796.             p_vout->fmt_in.i_sar_num * i_height / p_vout->fmt_in.i_sar_den /
  797.             FP_FACTOR / p_vout->fmt_in.i_visible_height );
  798.     }
  799.     else if( p_vout->fmt_in.i_sar_num == 0 || p_vout->fmt_in.i_sar_den == 0 )
  800.     {
  801.         msg_Warn( p_vout, "aspect ratio screwed up" );
  802.         *pi_width = (int)( p_vout->fmt_in.i_visible_width * ll_zoom / FP_FACTOR );
  803.         *pi_height = (int)( p_vout->fmt_in.i_visible_height * ll_zoom /FP_FACTOR);
  804.     }
  805.     else if( p_vout->fmt_in.i_sar_num >= p_vout->fmt_in.i_sar_den )
  806.     {
  807.         *pi_width = (int)( p_vout->fmt_in.i_visible_width * ll_zoom *
  808.             p_vout->fmt_in.i_sar_num / p_vout->fmt_in.i_sar_den / FP_FACTOR );
  809.         *pi_height = (int)( p_vout->fmt_in.i_visible_height * ll_zoom
  810.             / FP_FACTOR );
  811.     }
  812.     else
  813.     {
  814.         *pi_width = (int)( p_vout->fmt_in.i_visible_width * ll_zoom
  815.             / FP_FACTOR );
  816.         *pi_height = (int)( p_vout->fmt_in.i_visible_height * ll_zoom *
  817.             p_vout->fmt_in.i_sar_den / p_vout->fmt_in.i_sar_num / FP_FACTOR );
  818.     }
  819.     msg_Dbg( p_vout, "window size: %ux%u", *pi_width, *pi_height );
  820. #undef FP_FACTOR
  821. }
  822. /*****************************************************************************
  823.  * Object variables callbacks
  824.  *****************************************************************************/
  825. static int ZoomCallback( vlc_object_t *p_this, char const *psz_cmd,
  826.                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
  827. {
  828.     vout_thread_t *p_vout = (vout_thread_t *)p_this;
  829.     (void)psz_cmd; (void)oldval; (void)newval; (void)p_data;
  830.     InitWindowSize( p_vout, &p_vout->i_window_width,
  831.                     &p_vout->i_window_height );
  832.     vout_Control( p_vout, VOUT_SET_SIZE, p_vout->i_window_width,
  833.                   p_vout->i_window_height );
  834.     return VLC_SUCCESS;
  835. }
  836. static int CropCallback( vlc_object_t *p_this, char const *psz_cmd,
  837.                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
  838. {
  839.     vout_thread_t *p_vout = (vout_thread_t *)p_this;
  840.     int64_t i_aspect_num, i_aspect_den;
  841.     unsigned int i_width, i_height;
  842.     (void)oldval; (void)p_data;
  843.     /* Restore defaults */
  844.     p_vout->fmt_in.i_x_offset = p_vout->fmt_render.i_x_offset;
  845.     p_vout->fmt_in.i_visible_width = p_vout->fmt_render.i_visible_width;
  846.     p_vout->fmt_in.i_y_offset = p_vout->fmt_render.i_y_offset;
  847.     p_vout->fmt_in.i_visible_height = p_vout->fmt_render.i_visible_height;
  848.     if( !strcmp( psz_cmd, "crop" ) )
  849.     {
  850.         char *psz_end = NULL, *psz_parser = strchr( newval.psz_string, ':' );
  851.         if( psz_parser )
  852.         {
  853.             /* We're using the 3:4 syntax */
  854.             i_aspect_num = strtol( newval.psz_string, &psz_end, 10 );
  855.             if( psz_end == newval.psz_string || !i_aspect_num ) goto crop_end;
  856.             i_aspect_den = strtol( ++psz_parser, &psz_end, 10 );
  857.             if( psz_end == psz_parser || !i_aspect_den ) goto crop_end;
  858.             i_width = p_vout->fmt_in.i_sar_den*p_vout->fmt_render.i_visible_height *
  859.                 i_aspect_num / i_aspect_den / p_vout->fmt_in.i_sar_num;
  860.             i_height = p_vout->fmt_render.i_visible_width*p_vout->fmt_in.i_sar_num *
  861.                 i_aspect_den / i_aspect_num / p_vout->fmt_in.i_sar_den;
  862.             if( i_width < p_vout->fmt_render.i_visible_width )
  863.             {
  864.                 p_vout->fmt_in.i_x_offset = p_vout->fmt_render.i_x_offset +
  865.                     (p_vout->fmt_render.i_visible_width - i_width) / 2;
  866.                 p_vout->fmt_in.i_visible_width = i_width;
  867.             }
  868.             else
  869.             {
  870.                 p_vout->fmt_in.i_y_offset = p_vout->fmt_render.i_y_offset +
  871.                     (p_vout->fmt_render.i_visible_height - i_height) / 2;
  872.                 p_vout->fmt_in.i_visible_height = i_height;
  873.             }
  874.         }
  875.         else
  876.         {
  877.             psz_parser = strchr( newval.psz_string, 'x' );
  878.             if( psz_parser )
  879.             {
  880.                 /* Maybe we're using the <width>x<height>+<left>+<top> syntax */
  881.                 unsigned int i_crop_width, i_crop_height, i_crop_top, i_crop_left;
  882.                 i_crop_width = strtol( newval.psz_string, &psz_end, 10 );
  883.                 if( psz_end != psz_parser ) goto crop_end;
  884.                 psz_parser = strchr( ++psz_end, '+' );
  885.                 i_crop_height = strtol( psz_end, &psz_end, 10 );
  886.                 if( psz_end != psz_parser ) goto crop_end;
  887.                 psz_parser = strchr( ++psz_end, '+' );
  888.                 i_crop_left = strtol( psz_end, &psz_end, 10 );
  889.                 if( psz_end != psz_parser ) goto crop_end;
  890.                 psz_end++;
  891.                 i_crop_top = strtol( psz_end, &psz_end, 10 );
  892.                 if( *psz_end != '' ) goto crop_end;
  893.                 if( i_crop_top + i_crop_height >= p_vout->fmt_render.i_visible_height ||
  894.                     i_crop_left + i_crop_width >= p_vout->fmt_render.i_visible_width )
  895.                 {
  896.                     msg_Err( p_vout, "Unable to crop over picture boundaries");
  897.                     return VLC_EGENERIC;
  898.                 }
  899.                 i_width = i_crop_width;
  900.                 p_vout->fmt_in.i_visible_width = i_width;
  901.                 i_height = i_crop_height;
  902.                 p_vout->fmt_in.i_visible_height = i_height;
  903.                 p_vout->fmt_in.i_x_offset = i_crop_left;
  904.                 p_vout->fmt_in.i_y_offset = i_crop_top;
  905.             }
  906.             else
  907.             {
  908.                 /* Maybe we're using the <left>+<top>+<right>+<bottom> syntax */
  909.                 unsigned int i_crop_top, i_crop_left, i_crop_bottom, i_crop_right;
  910.                 psz_parser = strchr( newval.psz_string, '+' );
  911.                 i_crop_left = strtol( newval.psz_string, &psz_end, 10 );
  912.                 if( psz_end != psz_parser ) goto crop_end;
  913.                 psz_parser = strchr( ++psz_end, '+' );
  914.                 i_crop_top = strtol( psz_end, &psz_end, 10 );
  915.                 if( psz_end != psz_parser ) goto crop_end;
  916.                 psz_parser = strchr( ++psz_end, '+' );
  917.                 i_crop_right = strtol( psz_end, &psz_end, 10 );
  918.                 if( psz_end != psz_parser ) goto crop_end;
  919.                 psz_end++;
  920.                 i_crop_bottom = strtol( psz_end, &psz_end, 10 );
  921.                 if( *psz_end != '' ) goto crop_end;
  922.                 if( i_crop_top + i_crop_bottom >= p_vout->fmt_render.i_visible_height ||
  923.                     i_crop_right + i_crop_left >= p_vout->fmt_render.i_visible_width )
  924.                 {
  925.                     msg_Err( p_vout, "Unable to crop over picture boundaries" );
  926.                     return VLC_EGENERIC;
  927.                 }
  928.                 i_width = p_vout->fmt_render.i_visible_width
  929.                           - i_crop_left - i_crop_right;
  930.                 p_vout->fmt_in.i_visible_width = i_width;
  931.                 i_height = p_vout->fmt_render.i_visible_height
  932.                            - i_crop_top - i_crop_bottom;
  933.                 p_vout->fmt_in.i_visible_height = i_height;
  934.                 p_vout->fmt_in.i_x_offset = i_crop_left;
  935.                 p_vout->fmt_in.i_y_offset = i_crop_top;
  936.             }
  937.         }
  938.     }
  939.     else if( !strcmp( psz_cmd, "crop-top" )
  940.           || !strcmp( psz_cmd, "crop-left" )
  941.           || !strcmp( psz_cmd, "crop-bottom" )
  942.           || !strcmp( psz_cmd, "crop-right" ) )
  943.     {
  944.         unsigned int i_crop_top, i_crop_left, i_crop_bottom, i_crop_right;
  945.         i_crop_top = var_GetInteger( p_vout, "crop-top" );
  946.         i_crop_left = var_GetInteger( p_vout, "crop-left" );
  947.         i_crop_right = var_GetInteger( p_vout, "crop-right" );
  948.         i_crop_bottom = var_GetInteger( p_vout, "crop-bottom" );
  949.         if( i_crop_top + i_crop_bottom >= p_vout->fmt_render.i_visible_height ||
  950.             i_crop_right + i_crop_left >= p_vout->fmt_render.i_visible_width )
  951.         {
  952.             msg_Err( p_vout, "Unable to crop over picture boundaries" );
  953.             return VLC_EGENERIC;
  954.         }
  955.         i_width = p_vout->fmt_render.i_visible_width
  956.                   - i_crop_left - i_crop_right;
  957.         p_vout->fmt_in.i_visible_width = i_width;
  958.         i_height = p_vout->fmt_render.i_visible_height
  959.                    - i_crop_top - i_crop_bottom;
  960.         p_vout->fmt_in.i_visible_height = i_height;
  961.         p_vout->fmt_in.i_x_offset = i_crop_left;
  962.         p_vout->fmt_in.i_y_offset = i_crop_top;
  963.     }
  964.  crop_end:
  965.     InitWindowSize( p_vout, &p_vout->i_window_width,
  966.                     &p_vout->i_window_height );
  967.     p_vout->i_changes |= VOUT_CROP_CHANGE;
  968.     msg_Dbg( p_vout, "cropping picture %ix%i to %i,%i,%ix%i",
  969.              p_vout->fmt_in.i_width, p_vout->fmt_in.i_height,
  970.              p_vout->fmt_in.i_x_offset, p_vout->fmt_in.i_y_offset,
  971.              p_vout->fmt_in.i_visible_width,
  972.              p_vout->fmt_in.i_visible_height );
  973.     var_SetVoid( p_vout, "crop-update" );
  974.     return VLC_SUCCESS;
  975. }
  976. static int AspectCallback( vlc_object_t *p_this, char const *psz_cmd,
  977.                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
  978. {
  979.     vout_thread_t *p_vout = (vout_thread_t *)p_this;
  980.     unsigned int i_aspect_num, i_aspect_den, i_sar_num, i_sar_den;
  981.     vlc_value_t val;
  982.     char *psz_end, *psz_parser = strchr( newval.psz_string, ':' );
  983.     (void)psz_cmd; (void)oldval; (void)p_data;
  984.     /* Restore defaults */
  985.     p_vout->fmt_in.i_sar_num = p_vout->fmt_render.i_sar_num;
  986.     p_vout->fmt_in.i_sar_den = p_vout->fmt_render.i_sar_den;
  987.     p_vout->fmt_in.i_aspect = p_vout->fmt_render.i_aspect;
  988.     p_vout->render.i_aspect = p_vout->fmt_render.i_aspect;
  989.     if( !psz_parser ) goto aspect_end;
  990.     i_aspect_num = strtol( newval.psz_string, &psz_end, 10 );
  991.     if( psz_end == newval.psz_string || !i_aspect_num ) goto aspect_end;
  992.     i_aspect_den = strtol( ++psz_parser, &psz_end, 10 );
  993.     if( psz_end == psz_parser || !i_aspect_den ) goto aspect_end;
  994.     i_sar_num = i_aspect_num * p_vout->fmt_render.i_visible_height;
  995.     i_sar_den = i_aspect_den * p_vout->fmt_render.i_visible_width;
  996.     vlc_ureduce( &i_sar_num, &i_sar_den, i_sar_num, i_sar_den, 0 );
  997.     p_vout->fmt_in.i_sar_num = i_sar_num;
  998.     p_vout->fmt_in.i_sar_den = i_sar_den;
  999.     p_vout->fmt_in.i_aspect = i_aspect_num * VOUT_ASPECT_FACTOR / i_aspect_den;
  1000.     p_vout->render.i_aspect = p_vout->fmt_in.i_aspect;
  1001.  aspect_end:
  1002.     if( p_vout->p->i_par_num && p_vout->p->i_par_den )
  1003.     {
  1004.         p_vout->fmt_in.i_sar_num *= p_vout->p->i_par_den;
  1005.         p_vout->fmt_in.i_sar_den *= p_vout->p->i_par_num;
  1006.         p_vout->fmt_in.i_aspect = p_vout->fmt_in.i_aspect *
  1007.             p_vout->p->i_par_den / p_vout->p->i_par_num;
  1008.         p_vout->render.i_aspect = p_vout->fmt_in.i_aspect;
  1009.     }
  1010.     p_vout->i_changes |= VOUT_ASPECT_CHANGE;
  1011.     vlc_ureduce( &i_aspect_num, &i_aspect_den,
  1012.                  p_vout->fmt_in.i_aspect, VOUT_ASPECT_FACTOR, 0 );
  1013.     msg_Dbg( p_vout, "new aspect-ratio %i:%i, sample aspect-ratio %i:%i",
  1014.              i_aspect_num, i_aspect_den,
  1015.              p_vout->fmt_in.i_sar_num, p_vout->fmt_in.i_sar_den );
  1016.     if( var_Get( p_vout, "crop", &val ) )
  1017.         return VLC_EGENERIC;
  1018.     int i_ret = CropCallback( p_this, "crop", val, val, 0 );
  1019.     free( val.psz_string );
  1020.     return i_ret;
  1021. }
  1022. static int ScalingCallback( vlc_object_t *p_this, char const *psz_cmd,
  1023.                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
  1024. {
  1025.     vout_thread_t *p_vout = (vout_thread_t *)p_this;
  1026.     (void)oldval; (void)newval; (void)p_data;
  1027.     vlc_mutex_lock( &p_vout->change_lock );
  1028.     if( !strcmp( psz_cmd, "autoscale" ) )
  1029.     {
  1030.         p_vout->i_changes |= VOUT_SCALE_CHANGE;
  1031.     }
  1032.     else if( !strcmp( psz_cmd, "scale" ) )
  1033.     {
  1034.         p_vout->i_changes |= VOUT_ZOOM_CHANGE;
  1035.     }
  1036.     vlc_mutex_unlock( &p_vout->change_lock );
  1037.     return VLC_SUCCESS;
  1038. }
  1039. static int OnTopCallback( vlc_object_t *p_this, char const *psz_cmd,
  1040.                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
  1041. {
  1042.     vout_thread_t *p_vout = (vout_thread_t *)p_this;
  1043.     vlc_mutex_lock( &p_vout->change_lock );
  1044.     p_vout->i_changes |= VOUT_ON_TOP_CHANGE;
  1045.     p_vout->b_on_top = newval.b_bool;
  1046.     vlc_mutex_unlock( &p_vout->change_lock );
  1047.     /* Modify libvlc as well because the vout might have to be restarted */
  1048.     var_Create( p_vout->p_libvlc, "video-on-top", VLC_VAR_BOOL );
  1049.     var_Set( p_vout->p_libvlc, "video-on-top", newval );
  1050.     (void)psz_cmd; (void)oldval; (void)p_data;
  1051.     return VLC_SUCCESS;
  1052. }
  1053. static int FullscreenCallback( vlc_object_t *p_this, char const *psz_cmd,
  1054.                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
  1055. {
  1056.     vout_thread_t *p_vout = (vout_thread_t *)p_this;
  1057.     vlc_value_t val;
  1058.     (void)psz_cmd; (void)oldval; (void)p_data;
  1059.     p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
  1060.     /* Modify libvlc as well because the vout might have to be restarted */
  1061.     var_Create( p_vout->p_libvlc, "fullscreen", VLC_VAR_BOOL );
  1062.     var_Set( p_vout->p_libvlc, "fullscreen", newval );
  1063.     val.b_bool = true;
  1064.     var_Set( p_vout, "intf-change", val );
  1065.     return VLC_SUCCESS;
  1066. }
  1067. static int SnapshotCallback( vlc_object_t *p_this, char const *psz_cmd,
  1068.                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
  1069. {
  1070.     vout_thread_t *p_vout = (vout_thread_t *)p_this;
  1071.     VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
  1072.     VLC_UNUSED(newval); VLC_UNUSED(p_data);
  1073.     VoutSaveSnapshot( p_vout );
  1074.     return VLC_SUCCESS;
  1075. }
  1076. static int TitleShowCallback( vlc_object_t *p_this, char const *psz_cmd,
  1077.                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
  1078. {
  1079.     VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
  1080.     VLC_UNUSED(p_data);
  1081.     vout_thread_t *p_vout = (vout_thread_t *)p_this;
  1082.     p_vout->p->b_title_show = newval.b_bool;
  1083.     return VLC_SUCCESS;
  1084. }
  1085. static int TitleTimeoutCallback( vlc_object_t *p_this, char const *psz_cmd,
  1086.                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
  1087. {
  1088.     VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); VLC_UNUSED(p_data);
  1089.     vout_thread_t *p_vout = (vout_thread_t *)p_this;
  1090.     p_vout->p->i_title_timeout = (mtime_t) newval.i_int;
  1091.     return VLC_SUCCESS;
  1092. }
  1093. static int TitlePositionCallback( vlc_object_t *p_this, char const *psz_cmd,
  1094.                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
  1095. {
  1096.     VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
  1097.     VLC_UNUSED(p_data);
  1098.     vout_thread_t *p_vout = (vout_thread_t *)p_this;
  1099.     p_vout->p->i_title_position = newval.i_int;
  1100.     return VLC_SUCCESS;
  1101. }