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

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * access.c: RTMP input.
  3.  *****************************************************************************
  4.  * Copyright (C) URJC - LADyR - Luis Lopez Fernandez
  5.  *
  6.  * Author: Miguel Angel Cabrera Moya
  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 <vlc_plugin.h>
  30. #include <vlc_access.h>
  31. #include <vlc_network.h> /* DOWN: #include <network.h> */
  32. #include <vlc_url.h>
  33. #include <vlc_block.h>
  34. #include "rtmp_amf_flv.h"
  35. /*****************************************************************************
  36.  * Module descriptor
  37.  *****************************************************************************/
  38. #define CACHING_TEXT N_("Caching value in ms")
  39. #define CACHING_LONGTEXT N_( 
  40.     "Caching value for RTMP streams. This " 
  41.     "value should be set in milliseconds." )
  42. static int  Open ( vlc_object_t * );
  43. static void Close( vlc_object_t * );
  44. vlc_module_begin ()
  45.     set_description( N_("RTMP input") )
  46.     set_shortname( N_("RTMP") )
  47.     set_category( CAT_INPUT )
  48.     set_subcategory( SUBCAT_INPUT_ACCESS )
  49.     add_integer( "rtmp-caching", DEFAULT_PTS_DELAY / 1000, NULL, CACHING_TEXT,
  50.                  CACHING_LONGTEXT, true )
  51.     set_capability( "access", 0 )
  52.     set_callbacks( Open, Close )
  53.     add_shortcut( "rtmp" )
  54. vlc_module_end ()
  55. /*****************************************************************************
  56.  * Local prototypes
  57.  *****************************************************************************/
  58. static ssize_t  Read( access_t *, uint8_t *, size_t );
  59. static int Seek( access_t *, int64_t );
  60. static int Control( access_t *, int, va_list );
  61. static void* ThreadControl( vlc_object_t * );
  62. /*****************************************************************************
  63.  * Open: open the rtmp connection
  64.  *****************************************************************************/
  65. static int Open( vlc_object_t *p_this )
  66. {
  67.     access_t *p_access = (access_t *) p_this;
  68.     access_sys_t *p_sys;
  69.     char *psz, *p; 
  70.     int length_path, length_media_name;
  71.     int i;
  72.     STANDARD_READ_ACCESS_INIT
  73.     p_sys->p_thread =
  74.         vlc_object_create( p_access, sizeof( rtmp_control_thread_t ) );
  75.     if( !p_sys->p_thread )
  76.         return VLC_ENOMEM;
  77.     vlc_object_attach( p_sys->p_thread, p_access );
  78.     /* Parse URI - remove spaces */
  79.     p = psz = strdup( p_access->psz_path );
  80.     while( (p = strchr( p, ' ' )) != NULL )
  81.         *p = '+';
  82.     vlc_UrlParse( &p_sys->p_thread->url, psz, 0 );
  83.     free( psz );
  84.     if( p_sys->p_thread->url.psz_host == NULL
  85.         || *p_sys->p_thread->url.psz_host == '' )
  86.     {
  87.         msg_Warn( p_access, "invalid host" );
  88.         goto error;
  89.     }
  90.     if( p_sys->p_thread->url.i_port <= 0 )
  91.         p_sys->p_thread->url.i_port = 1935;
  92.     if( p_sys->p_thread->url.psz_path == NULL )
  93.     {
  94.         msg_Warn( p_access, "invalid path" );
  95.         goto error;
  96.     }
  97.     length_path = strlen( p_sys->p_thread->url.psz_path );
  98.     char* psz_tmp = strrchr( p_sys->p_thread->url.psz_path, '/' );
  99.     if( !psz_tmp )
  100.         goto error;
  101.     length_media_name = strlen( psz_tmp ) - 1;
  102.     p_sys->p_thread->psz_application = strndup( p_sys->p_thread->url.psz_path + 1, length_path - length_media_name - 2 );
  103.     p_sys->p_thread->psz_media = strdup( p_sys->p_thread->url.psz_path + ( length_path - length_media_name ) );
  104.     msg_Dbg( p_access, "rtmp: host='%s' port=%d path='%s'",
  105.              p_sys->p_thread->url.psz_host, p_sys->p_thread->url.i_port, p_sys->p_thread->url.psz_path );
  106.     if( p_sys->p_thread->url.psz_username && *p_sys->p_thread->url.psz_username )
  107.     {
  108.         msg_Dbg( p_access, "      user='%s'", p_sys->p_thread->url.psz_username );
  109.     }
  110.     /* Initialize thread variables */
  111.     p_sys->p_thread->b_die = 0;
  112.     p_sys->p_thread->b_error= 0;
  113.     p_sys->p_thread->p_fifo_input = block_FifoNew();
  114.     p_sys->p_thread->p_empty_blocks = block_FifoNew();
  115.     p_sys->p_thread->has_audio = 0;
  116.     p_sys->p_thread->has_video = 0;
  117.     p_sys->p_thread->metadata_received = 0;
  118.     p_sys->p_thread->first_media_packet = 1;
  119.     p_sys->p_thread->flv_tag_previous_tag_size = 0x00000000; /* FLV_TAG_FIRST_PREVIOUS_TAG_SIZE */
  120.     p_sys->p_thread->chunk_size_recv = 128; /* RTMP_DEFAULT_CHUNK_SIZE */
  121.     p_sys->p_thread->chunk_size_send = 128; /* RTMP_DEFAULT_CHUNK_SIZE */
  122.     for(i = 0; i < 64; i++)
  123.     {
  124.         memset( &p_sys->p_thread->rtmp_headers_recv[i], 0, sizeof( rtmp_packet_t ) );
  125.         p_sys->p_thread->rtmp_headers_send[i].length_header = -1;
  126.         p_sys->p_thread->rtmp_headers_send[i].stream_index = -1;
  127.         p_sys->p_thread->rtmp_headers_send[i].timestamp = -1;
  128.         p_sys->p_thread->rtmp_headers_send[i].timestamp_relative = -1;
  129.         p_sys->p_thread->rtmp_headers_send[i].length_encoded = -1;
  130.         p_sys->p_thread->rtmp_headers_send[i].length_body = -1;
  131.         p_sys->p_thread->rtmp_headers_send[i].content_type = -1;
  132.         p_sys->p_thread->rtmp_headers_send[i].src_dst = -1;
  133.         p_sys->p_thread->rtmp_headers_send[i].body = NULL;
  134.     }
  135.     p_sys->p_thread->p_base_object = p_this;
  136.     vlc_cond_init( &p_sys->p_thread->wait );
  137.     vlc_mutex_init( &p_sys->p_thread->lock );
  138.     p_sys->p_thread->result_connect = 1;
  139.     p_sys->p_thread->result_play = 1;
  140.     p_sys->p_thread->result_stop = 0;
  141.     /* Open connection */
  142.     p_sys->p_thread->fd = net_ConnectTCP( p_access, p_sys->p_thread->url.psz_host, p_sys->p_thread->url.i_port );
  143.     if( p_sys->p_thread->fd == -1 )
  144.     {
  145.         int *p_fd_listen;
  146.         msg_Warn( p_access, "cannot connect to %s:%d", p_sys->p_thread->url.psz_host, p_sys->p_thread->url.i_port );
  147.         msg_Dbg( p_access, "switching to passive mode" );
  148.         p_sys->active = 0;
  149.         p_fd_listen = net_ListenTCP( p_access, p_sys->p_thread->url.psz_host, p_sys->p_thread->url.i_port );
  150.         if( p_fd_listen == NULL )
  151.         {
  152.             msg_Err( p_access, "cannot listen to %s port %i", p_sys->p_thread->url.psz_host, p_sys->p_thread->url.i_port );
  153.             goto error2;
  154.         }
  155.         p_sys->p_thread->fd = net_Accept( p_access, p_fd_listen, -1 );
  156.         net_ListenClose( p_fd_listen );
  157.         if( rtmp_handshake_passive( p_this, p_sys->p_thread->fd ) < 0 )
  158.         {
  159.             msg_Err( p_access, "handshake passive failed");
  160.             goto error2;
  161.         }
  162.         p_sys->p_thread->result_publish = 1;
  163.     }
  164.     else
  165.     {
  166.         p_sys->active = 1;
  167.         if( rtmp_handshake_active( p_this, p_sys->p_thread->fd ) < 0 )
  168.         {
  169.             msg_Err( p_access, "handshake active failed");
  170.             goto error2;
  171.         }
  172.         p_sys->p_thread->result_publish = 0;
  173.     }
  174.     if( vlc_thread_create( p_sys->p_thread, "rtmp control thread", ThreadControl,
  175.                            VLC_THREAD_PRIORITY_INPUT ) )
  176.     {
  177.         msg_Err( p_access, "cannot spawn rtmp control thread" );
  178.         goto error2;
  179.     }
  180.     if( p_sys->active )
  181.     {
  182.         if( rtmp_connect_active( p_sys->p_thread ) < 0 )
  183.         {
  184.             msg_Err( p_access, "connect active failed");
  185.             /* Kill the running thread */
  186.             vlc_object_kill( p_sys->p_thread );
  187.             block_FifoWake( p_sys->p_thread->p_fifo_input );
  188.             vlc_thread_join( p_sys->p_thread );
  189.             goto error2;
  190.         }
  191.     }
  192.     /* Set vars for reading from fifo */
  193.     p_access->p_sys->flv_packet = NULL;
  194.     p_access->p_sys->read_packet = 1;
  195.     /* Update default_pts to a suitable value for rtmp access */
  196.     var_Create( p_access, "rtmp-caching", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
  197.     return VLC_SUCCESS;
  198. error2:
  199.     vlc_cond_destroy( &p_sys->p_thread->wait );
  200.     vlc_mutex_destroy( &p_sys->p_thread->lock );
  201.     block_FifoRelease( p_sys->p_thread->p_fifo_input );
  202.     block_FifoRelease( p_sys->p_thread->p_empty_blocks );
  203.     free( p_sys->p_thread->psz_application );
  204.     free( p_sys->p_thread->psz_media );
  205.     net_Close( p_sys->p_thread->fd );
  206. error:
  207.     vlc_UrlClean( &p_sys->p_thread->url );
  208.     vlc_object_detach( p_sys->p_thread );
  209.     vlc_object_release( p_sys->p_thread );
  210.     free( p_sys );
  211.     return VLC_EGENERIC;
  212. }
  213. /*****************************************************************************
  214.  * Close: close the rtmp connection
  215.  *****************************************************************************/
  216. static void Close( vlc_object_t * p_this )
  217. {
  218.     access_t     *p_access = (access_t *) p_this;
  219.     access_sys_t *p_sys = p_access->p_sys;
  220.     int i;
  221. /*    p_sys->p_thread->b_die = true;*/
  222.     vlc_object_kill( p_sys->p_thread );
  223.     block_FifoWake( p_sys->p_thread->p_fifo_input );
  224.     vlc_thread_join( p_sys->p_thread );
  225.     vlc_cond_destroy( &p_sys->p_thread->wait );
  226.     vlc_mutex_destroy( &p_sys->p_thread->lock );
  227.     block_FifoRelease( p_sys->p_thread->p_fifo_input );
  228.     block_FifoRelease( p_sys->p_thread->p_empty_blocks );
  229.     for( i = 0; i < 64; i++ ) /* RTMP_HEADER_STREAM_INDEX_MASK */
  230.     {
  231.         if( p_sys->p_thread->rtmp_headers_recv[i].body != NULL )
  232.         {
  233.             free( p_sys->p_thread->rtmp_headers_recv[i].body->body );
  234.             free( p_sys->p_thread->rtmp_headers_recv[i].body );
  235.         }
  236.     }
  237.     net_Close( p_sys->p_thread->fd );
  238.     var_Destroy( p_access, "rtmp-caching" );
  239.     vlc_UrlClean( &p_sys->p_thread->url );
  240.     free( p_sys->p_thread->psz_application );
  241.     free( p_sys->p_thread->psz_media );
  242.     vlc_object_detach( p_sys->p_thread );
  243.     vlc_object_release( p_sys->p_thread );
  244.     free( p_sys );
  245. }
  246. /*****************************************************************************
  247.  * Read: standard read on a file descriptor.
  248.  *****************************************************************************/
  249. static ssize_t Read( access_t *p_access, uint8_t *p_buffer, size_t i_len )
  250. {
  251.     access_sys_t *p_sys = p_access->p_sys;
  252.     rtmp_packet_t *rtmp_packet;
  253.     uint8_t *tmp_buffer;
  254.     ssize_t i_ret;
  255.     size_t i_len_tmp;
  256.     i_len_tmp = 0;
  257.     while( i_len_tmp < i_len )
  258.     {
  259.         if( p_sys->p_thread->result_stop || p_access->info.b_eof || !vlc_object_alive (p_access) )
  260.         {
  261.             p_access->info.b_eof = true;
  262.             return 0;
  263.         }
  264.         if( p_sys->read_packet )
  265.         {
  266.             if( !p_sys->p_thread->metadata_received )
  267.             {
  268.                 /* Wait until enough data is received for extracting metadata */
  269.                 if( block_FifoCount( p_sys->p_thread->p_fifo_input ) < 10 )
  270.                 {
  271.                     msleep(100000);
  272.                     continue;
  273.                 }
  274.                 p_sys->flv_packet = flv_get_metadata( p_access );
  275.                 p_sys->p_thread->metadata_received = 1;
  276.             }
  277.             else
  278.             {
  279.                 p_sys->flv_packet = block_FifoGet( p_sys->p_thread->p_fifo_input );
  280.                 if( p_sys->flv_packet == NULL )
  281.                     continue; /* Forced wake-up */
  282.             }
  283.             if( p_sys->p_thread->first_media_packet )
  284.             {
  285.                 p_sys->flv_packet = flv_insert_header( p_access, p_sys->flv_packet );
  286.                 p_sys->p_thread->first_media_packet = 0;
  287.             }
  288.         }
  289.         if( i_len - i_len_tmp >= p_sys->flv_packet->i_buffer )
  290.         {
  291.             p_sys->read_packet = 1;
  292.             memcpy( p_buffer + i_len_tmp, p_sys->flv_packet->p_buffer, p_sys->flv_packet->i_buffer );
  293.             block_FifoPut( p_sys->p_thread->p_empty_blocks, p_sys->flv_packet );
  294.             i_len_tmp += p_sys->flv_packet->i_buffer;
  295.         }
  296.         else
  297.         {
  298.             p_sys->read_packet = 0;
  299.             memcpy( p_buffer + i_len_tmp, p_sys->flv_packet->p_buffer, i_len - i_len_tmp);
  300.             p_sys->flv_packet->i_buffer -= i_len - i_len_tmp;
  301.             memmove( p_sys->flv_packet->p_buffer, p_sys->flv_packet->p_buffer + i_len - i_len_tmp, p_sys->flv_packet->i_buffer );
  302.             i_len_tmp += i_len - i_len_tmp;
  303.         }
  304.     }
  305.     if( i_len_tmp > 0 )
  306.     {
  307.         if( p_sys->p_thread->result_publish )
  308.         {
  309.             /* Send publish onStatus event only once */
  310.             p_sys->p_thread->result_publish = 0;
  311.             rtmp_packet = rtmp_build_publish_start( p_sys->p_thread );
  312.             tmp_buffer = rtmp_encode_packet( p_sys->p_thread, rtmp_packet );
  313.             i_ret = net_Write( p_sys->p_thread, p_sys->p_thread->fd, NULL, tmp_buffer, rtmp_packet->length_encoded );
  314.             if( i_ret != rtmp_packet->length_encoded )
  315.             {
  316.                 free( rtmp_packet->body->body );
  317.                 free( rtmp_packet->body );
  318.                 free( rtmp_packet );
  319.                 free( tmp_buffer );
  320.                 msg_Err( p_access, "failed send publish start" );
  321.                 return -1;
  322.             }
  323.             free( rtmp_packet->body->body );
  324.             free( rtmp_packet->body );
  325.             free( rtmp_packet );
  326.             free( tmp_buffer );
  327.         }
  328.         p_access->info.i_pos += i_len_tmp;
  329.         rtmp_packet = rtmp_build_bytes_read( p_sys->p_thread, p_access->info.i_pos );
  330.         tmp_buffer = rtmp_encode_packet( p_sys->p_thread, rtmp_packet );
  331.  
  332.         i_ret = net_Write( p_sys->p_thread, p_sys->p_thread->fd, NULL, tmp_buffer, rtmp_packet->length_encoded );
  333.         if( i_ret != rtmp_packet->length_encoded )
  334.         {
  335.             free( rtmp_packet->body->body );
  336.             free( rtmp_packet->body );
  337.             free( rtmp_packet );
  338.             free( tmp_buffer );
  339.             msg_Err( p_access, "failed send bytes read" );
  340.             return -1;
  341.         }
  342.         free( rtmp_packet->body->body );
  343.         free( rtmp_packet->body );
  344.         free( rtmp_packet );
  345.         free( tmp_buffer );
  346.     }
  347.     return i_len_tmp;
  348. }
  349. /*****************************************************************************
  350.  * Seek: seek to a specific location in a file
  351.  *****************************************************************************/
  352. static int Seek( access_t *p_access, int64_t i_pos )
  353. {
  354.     VLC_UNUSED( p_access );
  355.     VLC_UNUSED( i_pos );
  356. /*msg_Warn ( p_access, "Seek to %lld", i_pos);
  357.     switch( rtmp_seek( p_access, i_pos ) )
  358.     {
  359.         case -1:
  360.             return VLC_EGENERIC;
  361.         case 0:
  362.             break;
  363.         default:
  364.             msg_Err( p_access, "You should not be here" );
  365.             abort();
  366.     }
  367. */
  368.     return VLC_EGENERIC;
  369. }
  370. /*****************************************************************************
  371.  * Control:
  372.  *****************************************************************************/
  373. static int Control( access_t *p_access, int i_query, va_list args )
  374. {
  375.     bool    *pb_bool;
  376.     int64_t *pi_64;
  377.     switch( i_query )
  378.     {
  379.         /* */
  380.         case ACCESS_CAN_SEEK:
  381.         case ACCESS_CAN_FASTSEEK:
  382.             pb_bool = (bool*) va_arg( args, bool* );
  383.             *pb_bool = false; /* TODO */
  384.             break;
  385.         case ACCESS_CAN_PAUSE:
  386.             pb_bool = (bool*) va_arg( args, bool* );
  387.             *pb_bool = false; /* TODO */
  388.             break;
  389.         case ACCESS_CAN_CONTROL_PACE:
  390.             pb_bool = (bool*) va_arg( args, bool* );
  391.             *pb_bool = true;
  392.             break;
  393.         /* */
  394.         case ACCESS_GET_PTS_DELAY:
  395.             pi_64 = (int64_t*) va_arg( args, int64_t * );
  396.             *pi_64 = var_GetInteger( p_access, "rtmp-caching" ) * INT64_C(1000);
  397.             break;
  398.         /* */
  399.         case ACCESS_SET_PAUSE_STATE:
  400.             /* Nothing to do */
  401.             break;
  402.         case ACCESS_GET_TITLE_INFO:
  403.         case ACCESS_SET_TITLE:
  404.         case ACCESS_SET_SEEKPOINT:
  405.         case ACCESS_SET_PRIVATE_ID_STATE:
  406.         case ACCESS_GET_META:
  407.         case ACCESS_GET_CONTENT_TYPE: /* DOWN: comment this line */
  408.             return VLC_EGENERIC;
  409.         default:
  410.             msg_Warn( p_access, "unimplemented query in control" );
  411.             return VLC_EGENERIC;
  412.     }
  413.     return VLC_SUCCESS;
  414. }
  415. /*****************************************************************************
  416.  * ThreadControl: manage control messages and pipe media to Read
  417.  *****************************************************************************/
  418. static void* ThreadControl( vlc_object_t *p_this )
  419. {
  420.     rtmp_control_thread_t *p_thread = (rtmp_control_thread_t *) p_this;
  421.     rtmp_packet_t *rtmp_packet;
  422.     int canc = vlc_savecancel ();
  423.     rtmp_init_handler( p_thread->rtmp_handler );
  424.     while( vlc_object_alive (p_thread) )
  425.     {
  426.         rtmp_packet = rtmp_read_net_packet( p_thread );
  427.         if( rtmp_packet != NULL )
  428.         {
  429.             if( rtmp_packet->content_type < 0x01 /* RTMP_CONTENT_TYPE_CHUNK_SIZE */
  430.                 || rtmp_packet->content_type > 0x14 ) /* RTMP_CONTENT_TYPE_INVOKE */
  431.             {
  432.                 free( rtmp_packet->body->body );
  433.                 free( rtmp_packet->body );
  434.                 free( rtmp_packet );
  435.                 msg_Warn( p_thread, "unknown content type received" );
  436.             }
  437.             else
  438.                 p_thread->rtmp_handler[rtmp_packet->content_type]( p_thread, rtmp_packet );
  439.         }
  440.         else
  441.         {
  442.             /* Sometimes server close connection too soon */
  443.             if( p_thread->result_connect )
  444.             {
  445.                 vlc_mutex_lock( &p_thread->lock );
  446.                 vlc_cond_signal( &p_thread->wait );
  447.                 vlc_mutex_unlock( &p_thread->lock );
  448.             }
  449.             p_thread->b_die = 1;
  450.             ((access_t *) p_thread->p_base_object)->info.b_eof = true;
  451.             block_FifoWake( p_thread->p_fifo_input );
  452.         }
  453.     }
  454.     vlc_restorecancel (canc);
  455.     return NULL;
  456. }