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

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * opencv_wrapper.c : OpenCV wrapper video filter
  3.  *****************************************************************************
  4.  * Copyright (C) 2006 the VideoLAN team
  5.  *
  6.  * Authors: Dugal Harris <dugalh@protoclea.co.za>
  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. #include <cxcore.h>
  26. #include <cv.h>
  27. #include <highgui.h>
  28. #ifdef HAVE_CONFIG_H
  29. # include "config.h"
  30. #endif
  31. #include <vlc_common.h>
  32. #include <vlc_plugin.h>
  33. #include <vlc_vout.h>
  34. #include <math.h>
  35. #include <time.h>
  36. #include "vlc_filter.h"
  37. #include "filter_common.h"
  38. #include <vlc_charset.h>
  39. #include "vlc_image.h"
  40. #include "vlc_input.h"
  41. #include "vlc_playlist.h"
  42. /*****************************************************************************
  43.  * Local prototypes
  44.  *****************************************************************************/
  45. static int  Create    ( vlc_object_t * );
  46. static void Destroy   ( vlc_object_t * );
  47. static int  Init      ( vout_thread_t * );
  48. static void End       ( vout_thread_t * );
  49. static void Render    ( vout_thread_t *, picture_t * );
  50. static void ReleaseImages( vout_thread_t *p_vout );
  51. static void VlcPictureToIplImage( vout_thread_t *p_vout, picture_t *p_in );
  52. /*****************************************************************************
  53.  * Module descriptor
  54.  *****************************************************************************/
  55. static const char *const chroma_list[] = { "input", "I420", "RGB32"};
  56. static const char *const chroma_list_text[] = { N_("Use input chroma unaltered"),
  57.   N_("I420 - first plane is greyscale"), N_("RGB32")};
  58. static const char *const output_list[] = { "none", "input", "processed"};
  59. static const char *const output_list_text[] = { N_("Don't display any video"),
  60.   N_("Display the input video"), N_("Display the processed video")};
  61. static const char *const verbosity_list[] = { "error", "warning", "debug"};
  62. static const char *const verbosity_list_text[] = { N_("Show only errors"),
  63.   N_("Show errors and warnings"), N_("Show everything including debug messages")};
  64. vlc_module_begin ()
  65.     set_description( N_("OpenCV video filter wrapper") )
  66.     set_shortname( N_("OpenCV" ))
  67.     set_category( CAT_VIDEO )
  68.     set_subcategory( SUBCAT_VIDEO_VFILTER )
  69.     set_capability( "video filter", 0 )
  70.     add_shortcut( "opencv_wrapper" )
  71.     set_callbacks( Create, Destroy )
  72.     add_float_with_range( "opencv-scale", 1.0, 0.1, 2.0, NULL,
  73.                           N_("Scale factor (0.1-2.0)"),
  74.                           N_("Ammount by which to scale the picture before sending it to the internal OpenCV filter"),
  75.                           false )
  76.     add_string( "opencv-chroma", "input", NULL,
  77.                           N_("OpenCV filter chroma"),
  78.                           N_("Chroma to convert picture to before sending it to the internal OpenCV filter"), false);
  79.         change_string_list( chroma_list, chroma_list_text, 0);
  80.     add_string( "opencv-output", "input", NULL,
  81.                           N_("Wrapper filter output"),
  82.                           N_("Determines what (if any) video is displayed by the wrapper filter"), false);
  83.         change_string_list( output_list, output_list_text, 0);
  84.     add_string( "opencv-verbosity", "error", NULL,
  85.                           N_("Wrapper filter verbosity"),
  86.                           N_("Determines wrapper filter verbosity level"), false);
  87.         change_string_list( verbosity_list, verbosity_list_text, 0);
  88.     add_string( "opencv-filter-name", "none", NULL,
  89.                           N_("OpenCV internal filter name"),
  90.                           N_("Name of internal OpenCV plugin filter to use"), false);
  91. vlc_module_end ()
  92. /*****************************************************************************
  93.  * wrapper_output_t: what video is output
  94.  *****************************************************************************/
  95. enum wrapper_output_t
  96. {
  97.    NONE,    //not working yet
  98.    VINPUT,
  99.    PROCESSED
  100. };
  101. /*****************************************************************************
  102.  * internal_chroma_t: what chroma is sent to the internal opencv filter
  103.  *****************************************************************************/
  104. enum internal_chroma_t
  105. {
  106.    CINPUT,
  107.    GREY,
  108.    RGB
  109. };
  110. /*****************************************************************************
  111.  * verbosity_t:
  112.  *****************************************************************************/
  113. enum verbosity_t
  114. {
  115.    VERB_ERROR,
  116.    VERB_WARN,
  117.    VERB_DEBUG
  118. };
  119. /*****************************************************************************
  120.  * vout_sys_t: opencv_wrapper video output method descriptor
  121.  *****************************************************************************
  122.  * This structure is part of the video output thread descriptor.
  123.  * It describes the opencv_wrapper specific properties of an output thread.
  124.  *****************************************************************************/
  125. struct vout_sys_t
  126. {
  127.     vout_thread_t *p_vout;
  128.     image_handler_t *p_image;
  129.     int i_cv_image_size;
  130.     picture_t *p_proc_image;
  131.     picture_t *p_to_be_freed;
  132.     float f_scale;
  133.     int i_wrapper_output;
  134.     int i_internal_chroma;
  135.     int i_verbosity;
  136.     IplImage *p_cv_image[VOUT_MAX_PLANES];
  137.     filter_t *p_opencv;
  138.     char* psz_inner_name;
  139.     picture_t hacked_pic;
  140. };
  141. /*****************************************************************************
  142.  * Control: control facility for the vout (forwards to child vout)
  143.  *****************************************************************************/
  144. static int Control( vout_thread_t *p_vout, int i_query, va_list args )
  145. {
  146.     return vout_vaControl( p_vout->p_sys->p_vout, i_query, args );
  147. }
  148. /*****************************************************************************
  149.  * Create: allocates opencv_wrapper video thread output method
  150.  *****************************************************************************
  151.  * This function allocates and initializes a opencv_wrapper vout method.
  152.  *****************************************************************************/
  153. static int Create( vlc_object_t *p_this )
  154. {
  155.     vout_thread_t *p_vout = (vout_thread_t *)p_this;
  156.     char *psz_chroma, *psz_output, *psz_verbosity;
  157.     int i = 0;
  158.     /* Allocate structure */
  159.     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
  160.     if( p_vout->p_sys == NULL )
  161.         return VLC_ENOMEM;
  162.     /* Init structure */
  163.     p_vout->p_sys->p_image = image_HandlerCreate( p_vout );
  164.     for (i = 0; i < VOUT_MAX_PLANES; i++)
  165.         p_vout->p_sys->p_cv_image[i] = NULL;
  166.     p_vout->p_sys->p_proc_image = NULL;
  167.     p_vout->p_sys->p_to_be_freed = NULL;
  168.     p_vout->p_sys->i_cv_image_size = 0;
  169.     p_vout->pf_init = Init;
  170.     p_vout->pf_end = End;
  171.     p_vout->pf_manage = NULL;
  172.     p_vout->pf_render = Render;
  173.     p_vout->pf_display = NULL;
  174.     p_vout->pf_control = Control;
  175.     /* Retrieve and apply config */
  176.     if( !(psz_chroma = config_GetPsz( p_vout, "opencv-chroma" )) )
  177.     {
  178.         msg_Err( p_vout, "configuration variable %s empty, using 'grey'",
  179.                          "opencv-chroma" );
  180.         p_vout->p_sys->i_internal_chroma = GREY;
  181.     }
  182.     else
  183.     {
  184.         if( !strcmp( psz_chroma, "input" ) )
  185.             p_vout->p_sys->i_internal_chroma = CINPUT;
  186.         else if( !strcmp( psz_chroma, "I420" ) )
  187.             p_vout->p_sys->i_internal_chroma = GREY;
  188.         else if( !strcmp( psz_chroma, "RGB32" ) )
  189.             p_vout->p_sys->i_internal_chroma = RGB;
  190.         else
  191.         {
  192.             msg_Err( p_vout, "no valid opencv-chroma provided, using 'grey'" );
  193.             p_vout->p_sys->i_internal_chroma = GREY;
  194.         }
  195.     }
  196.     free( psz_chroma);
  197.     if( !(psz_output = config_GetPsz( p_vout, "opencv-output" )) )
  198.     {
  199.         msg_Err( p_vout, "configuration variable %s empty, using 'input'",
  200.                          "opencv-output" );
  201.         p_vout->p_sys->i_wrapper_output = VINPUT;
  202.     }
  203.     else
  204.     {
  205.         if( !strcmp( psz_output, "none" ) )
  206.             p_vout->p_sys->i_wrapper_output = NONE;
  207.         else if( !strcmp( psz_output, "input" ) )
  208.             p_vout->p_sys->i_wrapper_output = VINPUT;
  209.         else if( !strcmp( psz_output, "processed" ) )
  210.             p_vout->p_sys->i_wrapper_output = PROCESSED;
  211.         else
  212.         {
  213.             msg_Err( p_vout, "no valid opencv-output provided, using 'input'" );
  214.             p_vout->p_sys->i_wrapper_output = VINPUT;
  215.         }
  216.     }
  217.     free( psz_output);
  218.     if( !(psz_verbosity = config_GetPsz( p_vout, "opencv-verbosity" )) )
  219.     {
  220.         msg_Err( p_vout, "configuration variable %s empty, using 'input'",
  221.                          "opencv-verbosity" );
  222.         p_vout->p_sys->i_verbosity = VERB_ERROR;
  223.     }
  224.     else
  225.     {
  226.         if( !strcmp( psz_verbosity, "error" ) )
  227.             p_vout->p_sys->i_verbosity = VERB_ERROR;
  228.         else if( !strcmp( psz_verbosity, "warning" ) )
  229.             p_vout->p_sys->i_verbosity = VERB_WARN;
  230.         else if( !strcmp( psz_verbosity, "debug" ) )
  231.             p_vout->p_sys->i_verbosity = VERB_DEBUG;
  232.         else
  233.         {
  234.             msg_Err( p_vout, "no valid opencv-verbosity provided, using 'error'" );
  235.             p_vout->p_sys->i_verbosity = VERB_ERROR;
  236.         }
  237.     }
  238.     free( psz_verbosity);
  239.     p_vout->p_sys->psz_inner_name = config_GetPsz( p_vout, "opencv-filter-name" );
  240.     p_vout->p_sys->f_scale =
  241.         config_GetFloat( p_vout, "opencv-scale" );
  242.     if (p_vout->p_sys->i_verbosity > VERB_WARN)
  243.         msg_Info(p_vout, "Configuration: opencv-scale: %f, opencv-chroma: %d, "
  244.             "opencv-output: %d, opencv-verbosity %d, opencv-filter %s",
  245.             p_vout->p_sys->f_scale,
  246.             p_vout->p_sys->i_internal_chroma,
  247.             p_vout->p_sys->i_wrapper_output,
  248.             p_vout->p_sys->i_verbosity,
  249.             p_vout->p_sys->psz_inner_name);
  250.     return VLC_SUCCESS;
  251. }
  252. /*****************************************************************************
  253.  * Init: initialize opencv_wrapper video thread output method
  254.  *****************************************************************************/
  255. static int Init( vout_thread_t *p_vout )
  256. {
  257.     video_format_t fmt;
  258.     vout_sys_t *p_sys = p_vout->p_sys;
  259.     I_OUTPUTPICTURES = 0;
  260.     /* Initialize the output video format */
  261.     memset( &fmt, 0, sizeof(video_format_t) );
  262.     p_vout->output.i_chroma = p_vout->render.i_chroma;
  263.     p_vout->output.i_width  = p_vout->render.i_width;
  264.     p_vout->output.i_height = p_vout->render.i_height;
  265.     p_vout->output.i_aspect = p_vout->render.i_aspect;
  266.     p_vout->fmt_out = p_vout->fmt_in;           //set to input video format
  267.     fmt = p_vout->fmt_out;
  268.     if (p_sys->i_wrapper_output == PROCESSED)   //set to processed video format
  269.     {
  270.         fmt.i_width = fmt.i_width * p_sys->f_scale;
  271.         fmt.i_height = fmt.i_height * p_sys->f_scale;
  272.         fmt.i_visible_width = fmt.i_visible_width * p_sys->f_scale;
  273.         fmt.i_visible_height = fmt.i_visible_height * p_sys->f_scale;
  274.         fmt.i_x_offset = fmt.i_x_offset * p_sys->f_scale;
  275.         fmt.i_y_offset = fmt.i_y_offset * p_sys->f_scale;
  276.         if (p_sys->i_internal_chroma == GREY)
  277.             fmt.i_chroma = VLC_FOURCC('I','4','2','0');
  278.         else if (p_sys->i_internal_chroma == RGB)
  279.             fmt.i_chroma = VLC_FOURCC('R','V','3','2');
  280.     }
  281.     /* Load the internal opencv filter */
  282.     /* We don't need to set up video formats for this filter as it not actually using a picture_t */
  283.     p_sys->p_opencv = vlc_object_create( p_vout, sizeof(filter_t) );
  284.     vlc_object_attach( p_sys->p_opencv, p_vout );
  285.     if (p_vout->p_sys->psz_inner_name)
  286.         p_sys->p_opencv->p_module =
  287.             module_need( p_sys->p_opencv, p_sys->psz_inner_name, NULL, false );
  288.     if( !p_sys->p_opencv->p_module )
  289.     {
  290.         msg_Err( p_vout, "can't open internal opencv filter: %s", p_vout->p_sys->psz_inner_name );
  291.         p_vout->p_sys->psz_inner_name = NULL;
  292.         vlc_object_detach( p_sys->p_opencv );
  293.         vlc_object_release( p_sys->p_opencv );
  294.         p_sys->p_opencv = NULL;
  295.     }
  296.     /* Try to open the real video output */
  297.     if (p_sys->i_verbosity > VERB_WARN)
  298.         msg_Dbg( p_vout, "spawning the real video output" );
  299.     p_vout->p_sys->p_vout = vout_Create( p_vout, &fmt );
  300.     /* Everything failed */
  301.     if( p_vout->p_sys->p_vout == NULL )
  302.     {
  303.         msg_Err( p_vout, "can't open vout, aborting" );
  304.         return VLC_EGENERIC;
  305.     }
  306.     vout_filter_AllocateDirectBuffers( p_vout, VOUT_MAX_PICTURES );
  307.     vout_filter_AddChild( p_vout, p_vout->p_sys->p_vout, NULL );
  308.     return VLC_SUCCESS;
  309. }
  310. /*****************************************************************************
  311.  * End: terminate opencv_wrapper video thread output method
  312.  *****************************************************************************/
  313. static void End( vout_thread_t *p_vout )
  314. {
  315.     vout_sys_t *p_sys = p_vout->p_sys;
  316.     vout_filter_DelChild( p_vout, p_sys->p_vout, NULL );
  317.     vout_CloseAndRelease( p_sys->p_vout );
  318.     vout_filter_ReleaseDirectBuffers( p_vout );
  319.     if( p_sys->p_opencv )
  320.     {
  321.         //release the internal opencv filter
  322.         if( p_sys->p_opencv->p_module )
  323.             module_unneed( p_sys->p_opencv, p_sys->p_opencv->p_module );
  324.         vlc_object_detach( p_sys->p_opencv );
  325.         vlc_object_release( p_sys->p_opencv );
  326.         p_sys->p_opencv = NULL;
  327.     }
  328. }
  329. /*****************************************************************************
  330.  * Destroy: destroy opencv_wrapper video thread output method
  331.  *****************************************************************************
  332.  * Terminate an output method created by opencv_wrapperCreateOutputMethod
  333.  *****************************************************************************/
  334. static void Destroy( vlc_object_t *p_this )
  335. {
  336.     vout_thread_t *p_vout = (vout_thread_t *)p_this;
  337.     ReleaseImages(p_vout);
  338.     if( p_vout->p_sys->p_image )
  339.         image_HandlerDelete( p_vout->p_sys->p_image );
  340.     free( p_vout->p_sys );
  341. }
  342. /*****************************************************************************
  343.  * ReleaseImages: Release OpenCV images in vout_sys_t.
  344.  *****************************************************************************/
  345. static void ReleaseImages(vout_thread_t *p_vout)
  346. {
  347.     int i = 0;
  348.     if (p_vout->p_sys->p_cv_image)
  349.     {
  350.         for (i = 0; i < VOUT_MAX_PLANES; i++)
  351.         {
  352.             if (p_vout->p_sys->p_cv_image[i])
  353.                 cvReleaseImageHeader(&(p_vout->p_sys->p_cv_image[i]));
  354.             p_vout->p_sys->p_cv_image[i] = NULL;
  355.         }
  356.     }
  357.     p_vout->p_sys->i_cv_image_size = 0;
  358.     /* Release temp picture_t if it exists */
  359.     if (p_vout->p_sys->p_to_be_freed)
  360.     {
  361.         picture_Release( p_vout->p_sys->p_to_be_freed );
  362.         p_vout->p_sys->p_to_be_freed = NULL;
  363.     }
  364.     if (p_vout->p_sys->i_verbosity > VERB_WARN)
  365.         msg_Dbg( p_vout, "images released" );
  366. }
  367. /*****************************************************************************
  368.  * VlcPictureToIplImage: Convert picture_t to IplImage
  369.  *****************************************************************************
  370.  * Converts given picture_t into IplImage(s) according to module config.
  371.  * IplImage(s) are stored in vout_sys_t.
  372.  *****************************************************************************/
  373. static void VlcPictureToIplImage( vout_thread_t *p_vout, picture_t *p_in )
  374. {
  375.     int planes = p_in->i_planes;    //num input video planes
  376.     // input video size
  377.     CvSize sz = cvSize(abs(p_in->format.i_width), abs(p_in->format.i_height));
  378.     video_format_t fmt_out;
  379.     clock_t start, finish;  //performance measures
  380.     double  duration;
  381.     int i = 0;
  382.     vout_sys_t* p_sys = p_vout->p_sys;
  383.     memset( &fmt_out, 0, sizeof(video_format_t) );
  384.     start = clock();
  385.     //do scale / color conversion according to p_sys config
  386.     if ((p_sys->f_scale != 1) || (p_sys->i_internal_chroma != CINPUT))
  387.     {
  388.         fmt_out = p_in->format;
  389.         //calc the scaled video size
  390.         fmt_out.i_width = p_in->format.i_width * p_sys->f_scale;
  391.         fmt_out.i_height = p_in->format.i_height * p_sys->f_scale;
  392.         if (p_sys->i_internal_chroma == RGB)
  393.         {
  394.             //rgb2 gives 3 separate planes, this gives 1 interleaved plane
  395.             //rv24 gives is about 20% faster but gives r&b the wrong way round
  396.             //and I cant think of an easy way to fix this
  397.             fmt_out.i_chroma = VLC_FOURCC('R','V','3','2');
  398.         }
  399.         else if (p_sys->i_internal_chroma == GREY)
  400.         {
  401.             //take the I (gray) plane (video seems to commonly be in this fmt so usually the
  402.             //conversion does nothing)
  403.             fmt_out.i_chroma = VLC_FOURCC('I','4','2','0');
  404.         }
  405.         //convert from the input image
  406.         p_sys->p_proc_image = image_Convert( p_sys->p_image, p_in,
  407.                                      &(p_in->format), &fmt_out );
  408.         if (!p_sys->p_proc_image)
  409.         {
  410.             msg_Err(p_vout, "can't convert (unsupported formats?), aborting...");
  411.             return;
  412.         }
  413.         p_sys->p_to_be_freed = p_sys->p_proc_image;    //remember this so we can free it later
  414.     }
  415.     else    //((p_sys->f_scale != 1) || (p_sys->i_internal_chroma != CINPUT))
  416.     {
  417.         //use the input image without conversion
  418.         p_sys->p_proc_image = p_in;
  419.     }
  420.     //Convert to the IplImage array that is to be processed.
  421.     //If there are multiple planes in p_sys->p_proc_image, then 1 IplImage
  422.     //is created for each plane.
  423.     planes = p_sys->p_proc_image->i_planes;
  424.     p_sys->i_cv_image_size = planes;
  425.     for ( i = 0; i < planes; i++ )
  426.     {
  427.         sz = cvSize(abs(p_sys->p_proc_image->p[i].i_visible_pitch /
  428.             p_sys->p_proc_image->p[i].i_pixel_pitch),
  429.             abs(p_sys->p_proc_image->p[i].i_visible_lines));
  430.         p_sys->p_cv_image[i] = cvCreateImageHeader(sz, IPL_DEPTH_8U,
  431.             p_sys->p_proc_image->p[i].i_pixel_pitch);
  432.         cvSetData( p_sys->p_cv_image[i],
  433.             (char*)(p_sys->p_proc_image->p[i].p_pixels), p_sys->p_proc_image->p[i].i_pitch );
  434.     }
  435.     //Hack the above opencv image array into a picture_t so that it can be sent to
  436.     //another video filter
  437.     p_sys->hacked_pic.p_data_orig = p_sys->p_cv_image;
  438.     p_sys->hacked_pic.i_planes = planes;
  439.     p_sys->hacked_pic.format.i_chroma = fmt_out.i_chroma;
  440.     //calculate duration of conversion
  441.     finish = clock();
  442.     duration = (double)(finish - start) / CLOCKS_PER_SEC;
  443.     if (p_sys->i_verbosity > VERB_WARN)
  444.         msg_Dbg( p_vout, "VlcPictureToIplImageRgb took %2.4f seconds", duration );
  445. }
  446. /*****************************************************************************
  447.  * Render: displays previously rendered output
  448.  *****************************************************************************
  449.  * This function send the currently rendered image to the internal opencv
  450.  * filter for processing.
  451.  *****************************************************************************/
  452. static void Render( vout_thread_t *p_vout, picture_t *p_pic )
  453. {
  454.     picture_t *p_outpic = NULL;
  455.     clock_t start, finish;
  456.     double  duration;
  457.     while( ( p_outpic = vout_CreatePicture( p_vout->p_sys->p_vout, 0, 0, 0 ) )
  458.               == NULL )
  459.     {
  460.         if( !vlc_object_alive (p_vout) || p_vout->b_error )
  461.         {   return; }
  462.         msleep( VOUT_OUTMEM_SLEEP );
  463.     }
  464.     vout_LinkPicture( p_vout->p_sys->p_vout, p_outpic );
  465.     start = clock();
  466.     if (p_vout->p_sys->i_wrapper_output == VINPUT)  //output = input video
  467.     {
  468.         //This copy is a bit unfortunate but image_Convert can't write into an existing image so it is better to copy the
  469.         //(say) 16bit YUV image here than a 32bit RGB image somehwere else.
  470.         //It is also not that expensive in time.
  471.         picture_Copy( p_outpic, p_pic );
  472.         VlcPictureToIplImage( p_vout, p_pic);
  473.         //pass the image to the internal opencv filter for processing
  474.         if ((p_vout->p_sys->p_opencv) && (p_vout->p_sys->p_opencv->p_module))
  475.             p_vout->p_sys->p_opencv->pf_video_filter( p_vout->p_sys->p_opencv, &(p_vout->p_sys->hacked_pic));
  476.     }
  477.     else    //output = processed video (NONE option not working yet)
  478.     {
  479.         VlcPictureToIplImage( p_vout, p_pic);
  480.         //pass the image to the internal opencv filter for processing
  481.         if ((p_vout->p_sys->p_opencv) && (p_vout->p_sys->p_opencv->p_module))
  482.             p_vout->p_sys->p_opencv->pf_video_filter( p_vout->p_sys->p_opencv, &(p_vout->p_sys->hacked_pic));
  483.         //copy the processed image into the output image
  484.         if ((p_vout->p_sys->p_proc_image) && (p_vout->p_sys->p_proc_image->p_data))
  485.             picture_Copy( p_outpic, p_vout->p_sys->p_proc_image );
  486.     }
  487.     //calculate duration
  488.     finish = clock();
  489.     duration = (double)(finish - start) / CLOCKS_PER_SEC;
  490.     if (p_vout->p_sys->i_verbosity > VERB_WARN)
  491.         msg_Dbg( p_vout, "Render took %2.4f seconds", duration );
  492.     ReleaseImages(p_vout);
  493.     p_outpic->date  = p_pic->date;
  494.     
  495.     vout_UnlinkPicture( p_vout->p_sys->p_vout, p_outpic );
  496.     vout_DisplayPicture( p_vout->p_sys->p_vout, p_outpic );
  497. }