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

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * resource.c
  3.  *****************************************************************************
  4.  * Copyright (C) 2008 Laurent Aimar
  5.  * $Id: d0cd74268c775181ecb2dddd03a6e1b8a5e47f77 $
  6.  *
  7.  * Authors: Laurent Aimar < fenrir _AT_ videolan _DOT_ org >
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2 of the License, or
  12.  * (at your option) any later version.
  13.  *
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program; if not, write to the Free Software
  21.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  22.  *****************************************************************************/
  23. /*****************************************************************************
  24.  * Preamble
  25.  *****************************************************************************/
  26. #ifdef HAVE_CONFIG_H
  27. # include "config.h"
  28. #endif
  29. #include <vlc_common.h>
  30. #include <vlc_vout.h>
  31. #include <vlc_osd.h>
  32. #include <vlc_aout.h>
  33. #include <vlc_sout.h>
  34. #include "../libvlc.h"
  35. #include "../stream_output/stream_output.h"
  36. #include "../audio_output/aout_internal.h"
  37. #include "../video_output/vout_control.h"
  38. #include "input_interface.h"
  39. #include "resource.h"
  40. struct input_resource_t
  41. {
  42.     /* This lock is used to serialize request and protect
  43.      * our variables */
  44.     vlc_mutex_t    lock;
  45.     /* */
  46.     input_thread_t *p_input;
  47.     sout_instance_t *p_sout;
  48.     vout_thread_t   *p_vout_free;
  49.     /* This lock is used to protect vout resources access (for hold)
  50.      * It is a special case because of embed video (possible deadlock
  51.      * between vout window request and vout holds in some(qt4) interface)
  52.      */
  53.     vlc_mutex_t    lock_hold;
  54.     /* You need lock+lock_hold to write to the following variables and
  55.      * only lock or lock_hold to read them */
  56.     int             i_vout;
  57.     vout_thread_t   **pp_vout;
  58.     aout_instance_t *p_aout;
  59. };
  60. /* */
  61. static void DestroySout( input_resource_t *p_resource )
  62. {
  63. #ifdef ENABLE_SOUT
  64.     if( p_resource->p_sout )
  65.         sout_DeleteInstance( p_resource->p_sout );
  66. #endif
  67.     p_resource->p_sout = NULL;
  68. }
  69. static sout_instance_t *DetachSout( input_resource_t *p_resource )
  70. {
  71.     sout_instance_t *p_sout = p_resource->p_sout;
  72.     p_resource->p_sout = NULL;
  73.     return p_sout;
  74. }
  75. static sout_instance_t *RequestSout( input_resource_t *p_resource,
  76.                                      sout_instance_t *p_sout, const char *psz_sout )
  77. {
  78. #ifdef ENABLE_SOUT
  79.     if( !p_sout && !psz_sout )
  80.     {
  81.         if( p_resource->p_sout )
  82.             msg_Dbg( p_resource->p_sout, "destroying useless sout" );
  83.         DestroySout( p_resource );
  84.         return NULL;
  85.     }
  86.     assert( p_resource->p_input );
  87.     assert( !p_sout || ( !p_resource->p_sout && !psz_sout ) );
  88.     /* Check the validity of the sout */
  89.     if( p_resource->p_sout &&
  90.         strcmp( p_resource->p_sout->psz_sout, psz_sout ) )
  91.     {
  92.         msg_Dbg( p_resource->p_input, "destroying unusable sout" );
  93.         DestroySout( p_resource );
  94.     }
  95.     if( psz_sout )
  96.     {
  97.         if( p_resource->p_sout )
  98.         {
  99.             /* Reuse it */
  100.             msg_Dbg( p_resource->p_input, "reusing sout" );
  101.             msg_Dbg( p_resource->p_input, "you probably want to use gather stream_out" );
  102.             vlc_object_attach( p_resource->p_sout, p_resource->p_input );
  103.         }
  104.         else
  105.         {
  106.             /* Create a new one */
  107.             p_resource->p_sout = sout_NewInstance( p_resource->p_input, psz_sout );
  108.         }
  109.         p_sout = p_resource->p_sout;
  110.         p_resource->p_sout = NULL;
  111.         return p_sout;
  112.     }
  113.     else
  114.     {
  115.         vlc_object_detach( p_sout );
  116.         p_resource->p_sout = p_sout;
  117.         return NULL;
  118.     }
  119. #else
  120.     return NULL;
  121. #endif
  122. }
  123. /* */
  124. static void DestroyVout( input_resource_t *p_resource )
  125. {
  126.     assert( p_resource->i_vout == 0 );
  127.     if( p_resource->p_vout_free )
  128.         vout_CloseAndRelease( p_resource->p_vout_free );
  129.     p_resource->p_vout_free = NULL;
  130. }
  131. static vout_thread_t *DetachVout( input_resource_t *p_resource )
  132. {
  133.     assert( p_resource->i_vout == 0 );
  134.     vout_thread_t *p_vout = p_resource->p_vout_free;
  135.     p_resource->p_vout_free = NULL;
  136.     return p_vout;
  137. }
  138. static void DisplayVoutTitle( input_resource_t *p_resource,
  139.                               vout_thread_t *p_vout )
  140. {
  141.     assert( p_resource->p_input );
  142.     /* TODO display the title only one time for the same input ? */
  143.     input_item_t *p_item = input_GetItem( p_resource->p_input );
  144.     char *psz_nowplaying = input_item_GetNowPlaying( p_item );
  145.     if( psz_nowplaying && *psz_nowplaying )
  146.     {
  147.         vout_DisplayTitle( p_vout, psz_nowplaying );
  148.     }
  149.     else
  150.     {
  151.         char *psz_artist = input_item_GetArtist( p_item );
  152.         char *psz_name = input_item_GetTitle( p_item );
  153.         if( !psz_name || *psz_name == '' )
  154.         {
  155.             free( psz_name );
  156.             psz_name = input_item_GetName( p_item );
  157.         }
  158.         if( psz_artist && *psz_artist )
  159.         {
  160.             char *psz_string;
  161.             if( asprintf( &psz_string, "%s - %s", psz_name, psz_artist ) != -1 )
  162.             {
  163.                 vout_DisplayTitle( p_vout, psz_string );
  164.                 free( psz_string );
  165.             }
  166.         }
  167.         else if( psz_name )
  168.         {
  169.             vout_DisplayTitle( p_vout, psz_name );
  170.         }
  171.         free( psz_name );
  172.         free( psz_artist );
  173.     }
  174.     free( psz_nowplaying );
  175. }
  176. static vout_thread_t *RequestVout( input_resource_t *p_resource,
  177.                                    vout_thread_t *p_vout, video_format_t *p_fmt,
  178.                                    bool b_recycle )
  179. {
  180.     if( !p_vout && !p_fmt )
  181.     {
  182.         if( p_resource->p_vout_free )
  183.         {
  184.             msg_Dbg( p_resource->p_vout_free, "destroying useless vout" );
  185.             vout_CloseAndRelease( p_resource->p_vout_free );
  186.             p_resource->p_vout_free = NULL;
  187.         }
  188.         return NULL;
  189.     }
  190.     assert( p_resource->p_input );
  191.     if( p_fmt )
  192.     {
  193.         /* */
  194.         if( !p_vout && p_resource->p_vout_free )
  195.         {
  196.             msg_Dbg( p_resource->p_input, "trying to reuse free vout" );
  197.             p_vout = p_resource->p_vout_free;
  198.             p_resource->p_vout_free = NULL;
  199.         }
  200.         else if( p_vout )
  201.         {
  202.             assert( p_vout != p_resource->p_vout_free );
  203.             vlc_mutex_lock( &p_resource->lock_hold );
  204.             TAB_REMOVE( p_resource->i_vout, p_resource->pp_vout, p_vout );
  205.             vlc_mutex_unlock( &p_resource->lock_hold );
  206.         }
  207.         /* */
  208.         p_vout = vout_Request( p_resource->p_input, p_vout, p_fmt );
  209.         if( !p_vout )
  210.             return NULL;
  211.         DisplayVoutTitle( p_resource, p_vout );
  212.         vlc_mutex_lock( &p_resource->lock_hold );
  213.         TAB_APPEND( p_resource->i_vout, p_resource->pp_vout, p_vout );
  214.         vlc_mutex_unlock( &p_resource->lock_hold );
  215.         return p_vout;
  216.     }
  217.     else
  218.     {
  219.         assert( p_vout );
  220.         vlc_mutex_lock( &p_resource->lock_hold );
  221.         TAB_REMOVE( p_resource->i_vout, p_resource->pp_vout, p_vout );
  222.         const int i_vout_active = p_resource->i_vout;
  223.         vlc_mutex_unlock( &p_resource->lock_hold );
  224.         if( p_resource->p_vout_free || i_vout_active > 0 || !b_recycle )
  225.         {
  226.             if( b_recycle )
  227.                 msg_Dbg( p_resource->p_input, "detroying vout (already one saved or active)" );
  228.             vout_CloseAndRelease( p_vout );
  229.         }
  230.         else
  231.         {
  232.             msg_Dbg( p_resource->p_input, "saving a free vout" );
  233.             vout_Flush( p_vout, 1 );
  234.             spu_Control( p_vout->p_spu, SPU_CHANNEL_CLEAR, -1 );
  235.             p_resource->p_vout_free = p_vout;
  236.         }
  237.         return NULL;
  238.     }
  239. }
  240. static vout_thread_t *HoldVout( input_resource_t *p_resource )
  241. {
  242.     /* TODO FIXME: p_resource->pp_vout order is NOT stable */
  243.     vlc_mutex_lock( &p_resource->lock_hold );
  244.     vout_thread_t *p_vout = p_resource->i_vout > 0 ? p_resource->pp_vout[0] : NULL;
  245.     if( p_vout )
  246.         vlc_object_hold( p_vout );
  247.     vlc_mutex_unlock( &p_resource->lock_hold );
  248.     return p_vout;
  249. }
  250. static void HoldVouts( input_resource_t *p_resource, vout_thread_t ***ppp_vout, int *pi_vout )
  251. {
  252.     vout_thread_t **pp_vout;
  253.     *pi_vout = 0;
  254.     *ppp_vout = NULL;
  255.     vlc_mutex_lock( &p_resource->lock_hold );
  256.     if( p_resource->i_vout <= 0 )
  257.         goto exit;
  258.     pp_vout = calloc( p_resource->i_vout, sizeof(*pp_vout) );
  259.     if( !pp_vout )
  260.         goto exit;
  261.     *ppp_vout = pp_vout;
  262.     *pi_vout = p_resource->i_vout;
  263.     for( int i = 0; i < p_resource->i_vout; i++ )
  264.     {
  265.         pp_vout[i] = p_resource->pp_vout[i];
  266.         vlc_object_hold( pp_vout[i] );
  267.     }
  268. exit:
  269.     vlc_mutex_unlock( &p_resource->lock_hold );
  270. }
  271. /* */
  272. static void DestroyAout( input_resource_t *p_resource )
  273. {
  274.     if( p_resource->p_aout )
  275.         vlc_object_release( p_resource->p_aout );
  276.     p_resource->p_aout = NULL;
  277. }
  278. static aout_instance_t *DetachAout( input_resource_t *p_resource )
  279. {
  280.     vlc_mutex_lock( &p_resource->lock_hold );
  281.     aout_instance_t *p_aout = p_resource->p_aout;
  282.     p_resource->p_aout = NULL;
  283.     vlc_mutex_unlock( &p_resource->lock_hold );
  284.     return p_aout;
  285. }
  286. static aout_instance_t *RequestAout( input_resource_t *p_resource, aout_instance_t *p_aout )
  287. {
  288.     assert( p_resource->p_input );
  289.     if( p_aout )
  290.     {
  291.         msg_Dbg( p_resource->p_input, "releasing aout" );
  292.         vlc_object_release( p_aout );
  293.         return NULL;
  294.     }
  295.     else
  296.     {
  297.         p_aout = p_resource->p_aout;
  298.         if( !p_aout )
  299.         {
  300.             msg_Dbg( p_resource->p_input, "creating aout" );
  301.             p_aout = aout_New( p_resource->p_input );
  302.             vlc_mutex_lock( &p_resource->lock_hold );
  303.             p_resource->p_aout = p_aout;
  304.             vlc_mutex_unlock( &p_resource->lock_hold );
  305.         }
  306.         else
  307.         {
  308.             msg_Dbg( p_resource->p_input, "reusing aout" );
  309.         }
  310.         if( !p_aout )
  311.             return NULL;
  312.         vlc_object_detach( p_aout );
  313.         vlc_object_attach( p_aout, p_resource->p_input );
  314.         vlc_object_hold( p_aout );
  315.         return p_aout;
  316.     }
  317. }
  318. static aout_instance_t *HoldAout( input_resource_t *p_resource )
  319. {
  320.     vlc_mutex_lock( &p_resource->lock_hold );
  321.     aout_instance_t *p_aout = p_resource->p_aout;
  322.     if( p_aout )
  323.         vlc_object_hold( p_aout );
  324.     vlc_mutex_unlock( &p_resource->lock_hold );
  325.     return p_aout;
  326. }
  327. /* */
  328. input_resource_t *input_resource_New( void )
  329. {
  330.     input_resource_t *p_resource = calloc( 1, sizeof(*p_resource) );
  331.     if( !p_resource )
  332.         return NULL;
  333.     vlc_mutex_init( &p_resource->lock );
  334.     vlc_mutex_init( &p_resource->lock_hold );
  335.     return p_resource;
  336. }
  337. void input_resource_Delete( input_resource_t *p_resource )
  338. {
  339.     DestroySout( p_resource );
  340.     DestroyVout( p_resource );
  341.     DestroyAout( p_resource );
  342.     vlc_mutex_destroy( &p_resource->lock_hold );
  343.     vlc_mutex_destroy( &p_resource->lock );
  344.     free( p_resource );
  345. }
  346. void input_resource_SetInput( input_resource_t *p_resource, input_thread_t *p_input )
  347. {
  348.     vlc_mutex_lock( &p_resource->lock );
  349.     if( p_resource->p_input && !p_input )
  350.     {
  351.         if( p_resource->p_aout )
  352.             vlc_object_detach( p_resource->p_aout );
  353.         assert( p_resource->i_vout == 0 );
  354.         if( p_resource->p_vout_free )
  355.             vlc_object_detach( p_resource->p_vout_free );
  356.         if( p_resource->p_sout )
  357.             vlc_object_detach( p_resource->p_sout );
  358.     }
  359.     /* */
  360.     p_resource->p_input = p_input;
  361.     vlc_mutex_unlock( &p_resource->lock );
  362. }
  363. input_resource_t *input_resource_Detach( input_resource_t *p_resource )
  364. {
  365.     input_resource_t *p_ret = input_resource_New();
  366.     if( !p_ret )
  367.         return NULL;
  368.     vlc_mutex_lock( &p_resource->lock );
  369.     assert( !p_resource->p_input );
  370.     p_ret->p_sout = DetachSout( p_resource );
  371.     p_ret->p_vout_free = DetachVout( p_resource );
  372.     p_ret->p_aout = DetachAout( p_resource );
  373.     vlc_mutex_unlock( &p_resource->lock );
  374.     return p_ret;
  375. }
  376. vout_thread_t *input_resource_RequestVout( input_resource_t *p_resource,
  377.                                             vout_thread_t *p_vout, video_format_t *p_fmt, bool b_recycle )
  378. {
  379.     vlc_mutex_lock( &p_resource->lock );
  380.     vout_thread_t *p_ret = RequestVout( p_resource, p_vout, p_fmt, b_recycle );
  381.     vlc_mutex_unlock( &p_resource->lock );
  382.     return p_ret;
  383. }
  384. vout_thread_t *input_resource_HoldVout( input_resource_t *p_resource )
  385. {
  386.     return HoldVout( p_resource );
  387. }
  388. void input_resource_HoldVouts( input_resource_t *p_resource, vout_thread_t ***ppp_vout, int *pi_vout )
  389. {
  390.     HoldVouts( p_resource, ppp_vout, pi_vout );
  391. }
  392. void input_resource_TerminateVout( input_resource_t *p_resource )
  393. {
  394.     input_resource_RequestVout( p_resource, NULL, NULL, false );
  395. }
  396. bool input_resource_HasVout( input_resource_t *p_resource )
  397. {
  398.     vlc_mutex_lock( &p_resource->lock );
  399.     assert( !p_resource->p_input );
  400.     const bool b_vout = p_resource->p_vout_free != NULL;
  401.     vlc_mutex_unlock( &p_resource->lock );
  402.     return b_vout;
  403. }
  404. /* */
  405. aout_instance_t *input_resource_RequestAout( input_resource_t *p_resource, aout_instance_t *p_aout )
  406. {
  407.     vlc_mutex_lock( &p_resource->lock );
  408.     aout_instance_t *p_ret = RequestAout( p_resource, p_aout );
  409.     vlc_mutex_unlock( &p_resource->lock );
  410.     return p_ret;
  411. }
  412. aout_instance_t *input_resource_HoldAout( input_resource_t *p_resource )
  413. {
  414.     return HoldAout( p_resource );
  415. }
  416. /* */
  417. sout_instance_t *input_resource_RequestSout( input_resource_t *p_resource, sout_instance_t *p_sout, const char *psz_sout )
  418. {
  419.     vlc_mutex_lock( &p_resource->lock );
  420.     sout_instance_t *p_ret = RequestSout( p_resource, p_sout, psz_sout );
  421.     vlc_mutex_unlock( &p_resource->lock );
  422.     return p_ret;
  423. }
  424. void input_resource_TerminateSout( input_resource_t *p_resource )
  425. {
  426.     input_resource_RequestSout( p_resource, NULL, NULL );
  427. }