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

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * mmsh.c:
  3.  *****************************************************************************
  4.  * Copyright (C) 2001, 2002 VideoLAN
  5.  * $Id: mmsh.c 8936 2004-10-06 14:15:03Z hartman $
  6.  *
  7.  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  22.  *****************************************************************************/
  23. /*****************************************************************************
  24.  * Preamble
  25.  *****************************************************************************/
  26. #include <stdlib.h>
  27. #include <vlc/vlc.h>
  28. #include <vlc/input.h>
  29. #include "vlc_playlist.h"
  30. #include "network.h"
  31. #include "asf.h"
  32. #include "buffer.h"
  33. #include "mms.h"
  34. #include "mmsh.h"
  35. /* TODO:
  36.  *  - http_proxy
  37.  *  - authentication
  38.  */
  39. /*****************************************************************************
  40.  * Local prototypes
  41.  *****************************************************************************/
  42. int  E_(MMSHOpen)  ( access_t * );
  43. void E_(MMSHClose) ( access_t * );
  44. static int  Read( access_t *, uint8_t *, int );
  45. static int  ReadRedirect( access_t *, uint8_t *, int );
  46. static int  Seek( access_t *, int64_t );
  47. static int  Control( access_t *, int, va_list );
  48. static int  Describe( access_t  *, char **ppsz_location );
  49. static int  Start( access_t *, int64_t );
  50. static void Stop( access_t * );
  51. static int  GetPacket( access_t *, chunk_t * );
  52. /****************************************************************************
  53.  * Open: connect to ftp server and ask for file
  54.  ****************************************************************************/
  55. int E_(MMSHOpen)( access_t *p_access )
  56. {
  57.     access_sys_t    *p_sys;
  58.     char            *psz_location = NULL;
  59.     /* init p_sys */
  60.     /* Set up p_access */
  61.     p_access->pf_read = Read;
  62.     p_access->pf_block = NULL;
  63.     p_access->pf_control = Control;
  64.     p_access->pf_seek = Seek;
  65.     p_access->info.i_update = 0;
  66.     p_access->info.i_size = 0;
  67.     p_access->info.i_pos = 0;
  68.     p_access->info.b_eof = VLC_FALSE;
  69.     p_access->info.i_title = 0;
  70.     p_access->info.i_seekpoint = 0;
  71.     p_access->p_sys = p_sys = malloc( sizeof( access_sys_t ) );
  72.     memset( p_sys, 0, sizeof( access_sys_t ) );
  73.     p_sys->i_proto= MMS_PROTO_HTTP;
  74.     p_sys->fd     = -1;
  75.     p_sys->i_start= 0;
  76.     /* open a tcp connection */
  77.     vlc_UrlParse( &p_sys->url, p_access->psz_path, 0 );
  78.     if( p_sys->url.psz_host == NULL || *p_sys->url.psz_host == '' )
  79.     {
  80.         msg_Err( p_access, "invalid host" );
  81.         vlc_UrlClean( &p_sys->url );
  82.         free( p_sys );
  83.         return VLC_EGENERIC;
  84.     }
  85.     if( p_sys->url.i_port <= 0 )
  86.         p_sys->url.i_port = 80;
  87.     if( Describe( p_access, &psz_location ) )
  88.     {
  89.         vlc_UrlClean( &p_sys->url );
  90.         free( p_sys );
  91.         return VLC_EGENERIC;
  92.     }
  93.     /* Handle redirection */
  94.     if( psz_location && *psz_location )
  95.     {
  96.         playlist_t * p_playlist = vlc_object_find( p_access, VLC_OBJECT_PLAYLIST, FIND_PARENT );
  97.         msg_Dbg( p_access, "redirection to %s", psz_location );
  98.         if( !p_playlist )
  99.         {
  100.             msg_Err( p_access, "redirection failed: can't find playlist" );
  101.             free( psz_location );
  102.             return VLC_EGENERIC;
  103.         }
  104.         p_playlist->pp_items[p_playlist->i_index]->b_autodeletion = VLC_TRUE;
  105.         playlist_Add( p_playlist, psz_location, psz_location,
  106.                       PLAYLIST_INSERT | PLAYLIST_GO,
  107.                       p_playlist->i_index + 1 );
  108.         vlc_object_release( p_playlist );
  109.         free( psz_location );
  110.         p_access->pf_read = ReadRedirect;
  111.         return VLC_SUCCESS;
  112.     }
  113.     /* Start playing */
  114.     if( Start( p_access, 0 ) )
  115.     {
  116.         msg_Err( p_access, "cannot start stream" );
  117.         free( p_sys->p_header );
  118.         vlc_UrlClean( &p_sys->url );
  119.         free( p_sys );
  120.         return VLC_EGENERIC;
  121.     }
  122.     if( !p_sys->b_broadcast )
  123.     {
  124.         p_access->info.i_size = p_sys->asfh.i_file_size;
  125.     }
  126.     return VLC_SUCCESS;
  127. }
  128. /*****************************************************************************
  129.  * Close: free unused data structures
  130.  *****************************************************************************/
  131. void E_( MMSHClose )( access_t *p_access )
  132. {
  133.     access_sys_t *p_sys = p_access->p_sys;
  134.     Stop( p_access );
  135.     free( p_sys );
  136. }
  137. /*****************************************************************************
  138.  * Control:
  139.  *****************************************************************************/
  140. static int Control( access_t *p_access, int i_query, va_list args )
  141. {
  142.     access_sys_t *p_sys = p_access->p_sys;
  143.     vlc_bool_t   *pb_bool;
  144.     int          *pi_int;
  145.     int64_t      *pi_64;
  146.     switch( i_query )
  147.     {
  148.         /* */
  149.         case ACCESS_CAN_SEEK:
  150.             pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
  151.             *pb_bool = !p_sys->b_broadcast;
  152.             break;
  153.         case ACCESS_CAN_FASTSEEK:
  154.         case ACCESS_CAN_PAUSE:
  155.         case ACCESS_CAN_CONTROL_PACE:
  156.             pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
  157.             *pb_bool = VLC_FALSE;
  158.             break;
  159.         /* */
  160.         case ACCESS_GET_MTU:
  161.             pi_int = (int*)va_arg( args, int * );
  162.             *pi_int = 3 * p_sys->asfh.i_min_data_packet_size;
  163.             break;
  164.         case ACCESS_GET_PTS_DELAY:
  165.             pi_64 = (int64_t*)va_arg( args, int64_t * );
  166.             *pi_64 = (int64_t)var_GetInteger( p_access, "mms-caching" ) * I64C(1000);
  167.             break;
  168.         /* */
  169.         case ACCESS_SET_PAUSE_STATE:
  170.         case ACCESS_GET_TITLE_INFO:
  171.         case ACCESS_SET_TITLE:
  172.         case ACCESS_SET_SEEKPOINT:
  173.         case ACCESS_SET_PRIVATE_ID_STATE:
  174.             return VLC_EGENERIC;
  175.         default:
  176.             msg_Warn( p_access, "unimplemented query in control" );
  177.             return VLC_EGENERIC;
  178.     }
  179.     return VLC_SUCCESS;
  180. }
  181. /*****************************************************************************
  182.  * Seek: try to go at the right place
  183.  *****************************************************************************/
  184. static int Seek( access_t *p_access, int64_t i_pos )
  185. {
  186.     access_sys_t *p_sys = p_access->p_sys;
  187.     chunk_t      ck;
  188.     off_t        i_offset;
  189.     off_t        i_packet;
  190.     msg_Dbg( p_access, "seeking to "I64Fd, i_pos );
  191.     i_packet = ( i_pos - p_sys->i_header ) / p_sys->asfh.i_min_data_packet_size;
  192.     i_offset = ( i_pos - p_sys->i_header ) % p_sys->asfh.i_min_data_packet_size;
  193.     Stop( p_access );
  194.     Start( p_access, i_packet * p_sys->asfh.i_min_data_packet_size );
  195.     while( !p_access->b_die )
  196.     {
  197.         if( GetPacket( p_access, &ck ) )
  198.             break;
  199.         /* skip headers */
  200.         if( ck.i_type != 0x4824 )
  201.             break;
  202.         msg_Warn( p_access, "skipping header" );
  203.     }
  204.     p_access->info.i_pos = i_pos;
  205.     p_access->info.b_eof = VLC_FALSE;
  206.     p_sys->i_packet_used += i_offset;
  207.     return VLC_SUCCESS;
  208. }
  209. /*****************************************************************************
  210.  * Read:
  211.  *****************************************************************************/
  212. static int ReadRedirect( access_t *p_access, uint8_t *p, int i_len )
  213. {
  214.     return 0;
  215. }
  216. /*****************************************************************************
  217.  * Read:
  218.  *****************************************************************************/
  219. static int Read( access_t *p_access, uint8_t *p_buffer, int i_len )
  220. {
  221.     access_sys_t *p_sys = p_access->p_sys;
  222.     size_t       i_copy;
  223.     size_t       i_data = 0;
  224.     if( p_access->info.b_eof )
  225.         return 0;
  226.     while( i_data < i_len )
  227.     {
  228.         if( p_access->info.i_pos < p_sys->i_start + p_sys->i_header )
  229.         {
  230.             int i_offset = p_access->info.i_pos - p_sys->i_start;
  231.             i_copy = __MIN( p_sys->i_header - i_offset, i_len - i_data );
  232.             memcpy( &p_buffer[i_data], &p_sys->p_header[i_offset], i_copy );
  233.             i_data += i_copy;
  234.             p_access->info.i_pos += i_copy;
  235.         }
  236.         else if( p_sys->i_packet_used < p_sys->i_packet_length )
  237.         {
  238.             i_copy = __MIN( p_sys->i_packet_length - p_sys->i_packet_used,
  239.                             i_len - i_data );
  240.             memcpy( &p_buffer[i_data],
  241.                     &p_sys->p_packet[p_sys->i_packet_used],
  242.                     i_copy );
  243.             i_data += i_copy;
  244.             p_sys->i_packet_used += i_copy;
  245.             p_access->info.i_pos += i_copy;
  246.         }
  247.         else if( p_sys->i_packet_length > 0 &&
  248.                  (int)p_sys->i_packet_used < p_sys->asfh.i_min_data_packet_size )
  249.         {
  250.             i_copy = __MIN( p_sys->asfh.i_min_data_packet_size - p_sys->i_packet_used,
  251.                             i_len - i_data );
  252.             memset( &p_buffer[i_data], 0, i_copy );
  253.             i_data += i_copy;
  254.             p_sys->i_packet_used += i_copy;
  255.             p_access->info.i_pos += i_copy;
  256.         }
  257.         else
  258.         {
  259.             chunk_t ck;
  260.             if( GetPacket( p_access, &ck ) )
  261.             {
  262.                 if( ck.i_type == 0x4524 && ck.i_sequence != 0 && p_sys->b_broadcast )
  263.                 {
  264.                     char *psz_location = NULL;
  265.                     p_sys->i_start = p_access->info.i_pos;
  266.                     msg_Dbg( p_access, "stoping the stream" );
  267.                     Stop( p_access );
  268.                     msg_Dbg( p_access, "describe the stream" );
  269.                     if( Describe( p_access, &psz_location ) )
  270.                     {
  271.                         msg_Err( p_access, "describe failed" );
  272.                         p_access->info.b_eof = VLC_TRUE;
  273.                         return 0;
  274.                     }
  275.                     if( Start( p_access, 0 ) )
  276.                     {
  277.                         msg_Err( p_access, "Start failed" );
  278.                         p_access->info.b_eof = VLC_TRUE;
  279.                         return 0;
  280.                     }
  281.                 }
  282.                 else
  283.                 {
  284.                     p_access->info.b_eof = VLC_TRUE;
  285.                     return 0;
  286.                 }
  287.             }
  288.             if( ck.i_type != 0x4424 )
  289.             {
  290.                 p_sys->i_packet_used = 0;
  291.                 p_sys->i_packet_length = 0;
  292.             }
  293.         }
  294.     }
  295.     return( i_data );
  296. }
  297. /*****************************************************************************
  298.  * Describe:
  299.  *****************************************************************************/
  300. static int Describe( access_t  *p_access, char **ppsz_location )
  301. {
  302.     access_sys_t *p_sys = p_access->p_sys;
  303.     char         *psz_location = NULL;
  304.     char         *psz;
  305.     int          i_code;
  306.     /* Reinit context */
  307.     p_sys->b_broadcast = VLC_TRUE;
  308.     p_sys->i_request_context = 1;
  309.     p_sys->i_packet_sequence = 0;
  310.     p_sys->i_packet_used = 0;
  311.     p_sys->i_packet_length = 0;
  312.     p_sys->p_packet = NULL;
  313.     E_( GenerateGuid )( &p_sys->guid );
  314.     if( ( p_sys->fd = net_OpenTCP( p_access, p_sys->url.psz_host,
  315.                                             p_sys->url.i_port ) ) < 0 )
  316.     {
  317.         msg_Err( p_access, "cannot connect to %s:%d", p_sys->url.psz_host, p_sys->url.i_port );
  318.         goto error;
  319.     }
  320.     /* send first request */
  321.     net_Printf( VLC_OBJECT(p_access), p_sys->fd,
  322.                 "GET %s HTTP/1.0rn"
  323.                 "Accept: */*rn"
  324.                 "User-Agent: NSPlayer/4.1.0.3856rn"
  325.                 "Host: %s:%drn"
  326.                 "Pragma: no-cache,rate=1.000000,stream-time=0,stream-offset=0:0,request-context=%d,max-duration=0rn"
  327.                 "Pragma: xClientGUID={"GUID_FMT"}rn"
  328.                 "Connection: Closern",
  329.                 ( p_sys->url.psz_path == NULL || *p_sys->url.psz_path == '' ) ? "/" : p_sys->url.psz_path,
  330.                 p_sys->url.psz_host, p_sys->url.i_port,
  331.                 p_sys->i_request_context++,
  332.                 GUID_PRINT( p_sys->guid ) );
  333.     if( net_Printf( VLC_OBJECT(p_access), p_sys->fd, "rn" ) < 0 )
  334.     {
  335.         msg_Err( p_access, "failed to send request" );
  336.         goto error;
  337.     }
  338.     /* Receive the http header */
  339.     if( ( psz = net_Gets( VLC_OBJECT(p_access), p_sys->fd ) ) == NULL )
  340.     {
  341.         msg_Err( p_access, "failed to read answer" );
  342.         goto error;
  343.     }
  344.     if( strncmp( psz, "HTTP/1.", 7 ) )
  345.     {
  346.         msg_Err( p_access, "invalid HTTP reply '%s'", psz );
  347.         free( psz );
  348.         goto error;
  349.     }
  350.     i_code = atoi( &psz[9] );
  351.     if( i_code >= 400 )
  352.     {
  353.         msg_Err( p_access, "error: %s", psz );
  354.         free( psz );
  355.         goto error;
  356.     }
  357.     msg_Dbg( p_access, "HTTP reply '%s'", psz );
  358.     free( psz );
  359.     for( ;; )
  360.     {
  361.         char *psz = net_Gets( p_access, p_sys->fd );
  362.         char *p;
  363.         if( psz == NULL )
  364.         {
  365.             msg_Err( p_access, "failed to read answer" );
  366.             goto error;
  367.         }
  368.         if( *psz == '' )
  369.         {
  370.             free( psz );
  371.             break;
  372.         }
  373.         if( ( p = strchr( psz, ':' ) ) == NULL )
  374.         {
  375.             msg_Err( p_access, "malformed header line: %s", psz );
  376.             free( psz );
  377.             goto error;
  378.         }
  379.         *p++ = '';
  380.         while( *p == ' ' ) p++;
  381.         /* FIXME FIXME test Content-Type to see if it's a plain stream or an
  382.          * asx FIXME */
  383.         if( !strcasecmp( psz, "Pragma" ) )
  384.         {
  385.             if( strstr( p, "features" ) )
  386.             {
  387.                 /* FIXME, it is a bit badly done here ..... */
  388.                 if( strstr( p, "broadcast" ) )
  389.                 {
  390.                     msg_Dbg( p_access, "stream type = broadcast" );
  391.                     p_sys->b_broadcast = VLC_TRUE;
  392.                 }
  393.                 else if( strstr( p, "seekable" ) )
  394.                 {
  395.                     msg_Dbg( p_access, "stream type = seekable" );
  396.                     p_sys->b_broadcast = VLC_FALSE;
  397.                 }
  398.                 else
  399.                 {
  400.                     msg_Warn( p_access, "unknow stream types (%s)", p );
  401.                     p_sys->b_broadcast = VLC_FALSE;
  402.                 }
  403.             }
  404.         }
  405.         else if( !strcasecmp( psz, "Location" ) )
  406.         {
  407.             psz_location = strdup( p );
  408.         }
  409.         free( psz );
  410.     }
  411.     /* Handle the redirection */
  412.     if( ( i_code == 301 || i_code == 302 ||
  413.           i_code == 303 || i_code == 307 ) &&
  414.         psz_location && *psz_location )
  415.     {
  416.         msg_Dbg( p_access, "redirection to %s", psz_location );
  417.         net_Close( p_sys->fd ); p_sys->fd = -1;
  418.         *ppsz_location = psz_location;
  419.         return VLC_SUCCESS;
  420.     }
  421.     /* Read the asf header */
  422.     p_sys->i_header = 0;
  423.     p_sys->p_header = NULL;
  424.     for( ;; )
  425.     {
  426.         chunk_t ck;
  427.         if( GetPacket( p_access, &ck ) ||
  428.             ck.i_type != 0x4824 )
  429.         {
  430.             break;
  431.         }
  432.         if( ck.i_data > 0 )
  433.         {
  434.             p_sys->i_header += ck.i_data;
  435.             p_sys->p_header = realloc( p_sys->p_header, p_sys->i_header );
  436.             memcpy( &p_sys->p_header[p_sys->i_header - ck.i_data],
  437.                     ck.p_data, ck.i_data );
  438.         }
  439.     }
  440.     msg_Dbg( p_access, "complete header size=%d", p_sys->i_header );
  441.     if( p_sys->i_header <= 0 )
  442.     {
  443.         msg_Err( p_access, "header size == 0" );
  444.         goto error;
  445.     }
  446.     /* close this connection */
  447.     net_Close( p_sys->fd ); p_sys->fd = -1;
  448.     /* *** parse header and get stream and their id *** */
  449.     /* get all streams properties,
  450.      *
  451.      * TODO : stream bitrates properties(optional)
  452.      *        and bitrate mutual exclusion(optional) */
  453.     E_( asf_HeaderParse )( &p_sys->asfh,
  454.                            p_sys->p_header, p_sys->i_header );
  455.     msg_Dbg( p_access, "packet count=%lld packet size=%d",
  456.              p_sys->asfh.i_data_packets_count,
  457.              p_sys->asfh.i_min_data_packet_size );
  458.     E_( asf_StreamSelect)( &p_sys->asfh,
  459.                            var_CreateGetInteger( p_access, "mms-maxbitrate" ),
  460.                            var_CreateGetInteger( p_access, "mms-all" ),
  461.                            var_CreateGetInteger( p_access, "audio" ),
  462.                            var_CreateGetInteger( p_access, "video" ) );
  463.     return VLC_SUCCESS;
  464. error:
  465.     if( p_sys->fd > 0 )
  466.     {
  467.         net_Close( p_sys->fd  );
  468.         p_sys->fd = -1;
  469.     }
  470.     return VLC_EGENERIC;
  471. }
  472. /*****************************************************************************
  473.  *
  474.  *****************************************************************************/
  475. static int Start( access_t *p_access, off_t i_pos )
  476. {
  477.     access_sys_t *p_sys = p_access->p_sys;
  478.     int  i_streams = 0;
  479.     int  i;
  480.     char *psz;
  481.     msg_Dbg( p_access, "starting stream" );
  482.     if( ( p_sys->fd = net_OpenTCP( p_access, p_sys->url.psz_host,
  483.                                             p_sys->url.i_port ) ) < 0 )
  484.     {
  485.         /* should not occur */
  486.         msg_Err( p_access, "cannot connect to the server" );
  487.         return VLC_EGENERIC;
  488.     }
  489.     for( i = 1; i < 128; i++ )
  490.     {
  491.         if( p_sys->asfh.stream[i].i_selected )
  492.         {
  493.             i_streams++;
  494.         }
  495.     }
  496.     if( i_streams <= 0 )
  497.     {
  498.         msg_Err( p_access, "no stream selected" );
  499.         return VLC_EGENERIC;
  500.     }
  501.     net_Printf( VLC_OBJECT(p_access), p_sys->fd,
  502.                 "GET %s HTTP/1.0rn"
  503.                 "Accept: */*rn"
  504.                 "User-Agent: NSPlayer/4.1.0.3856rn"
  505.                 "Host: %s:%drn",
  506.                 ( p_sys->url.psz_path == NULL || *p_sys->url.psz_path == '' ) ? "/" : p_sys->url.psz_path,
  507.                 p_sys->url.psz_host, p_sys->url.i_port );
  508.     if( p_sys->b_broadcast )
  509.     {
  510.         net_Printf( VLC_OBJECT(p_access), p_sys->fd,
  511.                     "Pragma: no-cache,rate=1.000000,request-context=%drn",
  512.                     p_sys->i_request_context++ );
  513.     }
  514.     else
  515.     {
  516.         net_Printf( VLC_OBJECT(p_access), p_sys->fd,
  517.                     "Pragma: no-cache,rate=1.000000,stream-time=0,stream-offset=%u:%u,request-context=%d,max-duration=0rn",
  518.                     (uint32_t)((i_pos >> 32)&0xffffffff),
  519.                     (uint32_t)(i_pos&0xffffffff),
  520.                     p_sys->i_request_context++ );
  521.     }
  522.     net_Printf( VLC_OBJECT(p_access), p_sys->fd,
  523.                 "Pragma: xPlayStrm=1rn"
  524.                 "Pragma: xClientGUID={"GUID_FMT"}rn"
  525.                 "Pragma: stream-switch-count=%drn"
  526.                 "Pragma: stream-switch-entry=",
  527.                 GUID_PRINT( p_sys->guid ),
  528.                 i_streams);
  529.     for( i = 1; i < 128; i++ )
  530.     {
  531.         if( p_sys->asfh.stream[i].i_cat != ASF_STREAM_UNKNOWN )
  532.         {
  533.             int i_select = 2;
  534.             if( p_sys->asfh.stream[i].i_selected )
  535.             {
  536.                 i_select = 0;
  537.             }
  538.             net_Printf( VLC_OBJECT(p_access), p_sys->fd,
  539.                         "ffff:%d:%d ", i, i_select );
  540.         }
  541.     }
  542.     net_Printf( VLC_OBJECT(p_access), p_sys->fd, "rn" );
  543.     net_Printf( VLC_OBJECT(p_access), p_sys->fd, "Connection: Closern" );
  544.     if( net_Printf( VLC_OBJECT(p_access), p_sys->fd, "rn" ) < 0 )
  545.     {
  546.         msg_Err( p_access, "failed to send request" );
  547.         return VLC_EGENERIC;
  548.     }
  549.     if( ( psz = net_Gets( VLC_OBJECT(p_access), p_sys->fd ) ) == NULL )
  550.     {
  551.         msg_Err( p_access, "cannot read data" );
  552.         return VLC_EGENERIC;
  553.     }
  554.     if( atoi( &psz[9] ) >= 400 )
  555.     {
  556.         msg_Err( p_access, "error: %s", psz );
  557.         free( psz );
  558.         return VLC_EGENERIC;
  559.     }
  560.     msg_Dbg( p_access, "HTTP reply '%s'", psz );
  561.     free( psz );
  562.     /* FIXME check HTTP code */
  563.     for( ;; )
  564.     {
  565.         char *psz = net_Gets( p_access, p_sys->fd );
  566.         if( psz == NULL )
  567.         {
  568.             msg_Err( p_access, "cannot read data" );
  569.             return VLC_EGENERIC;
  570.         }
  571.         if( *psz == '' )
  572.         {
  573.             free( psz );
  574.             break;
  575.         }
  576.         msg_Dbg( p_access, "%s", psz );
  577.         free( psz );
  578.     }
  579.     p_sys->i_packet_used   = 0;
  580.     p_sys->i_packet_length = 0;
  581.     return VLC_SUCCESS;
  582. }
  583. /*****************************************************************************
  584.  *
  585.  *****************************************************************************/
  586. static void Stop( access_t *p_access )
  587. {
  588.     access_sys_t *p_sys = p_access->p_sys;
  589.     msg_Dbg( p_access, "closing stream" );
  590.     if( p_sys->fd > 0 )
  591.     {
  592.         net_Close( p_sys->fd );
  593.         p_sys->fd = -1;
  594.     }
  595. }
  596. /*****************************************************************************
  597.  *
  598.  *****************************************************************************/
  599. static int GetPacket( access_t * p_access, chunk_t *p_ck )
  600. {
  601.     access_sys_t *p_sys = p_access->p_sys;
  602.     /* chunk_t */
  603.     memset( p_ck, 0, sizeof( chunk_t ) );
  604.     /* Read the chunk header */
  605.     if( net_Read( p_access, p_sys->fd, p_sys->buffer, 12, VLC_TRUE ) < 12 )
  606.     {
  607.         /* msg_Err( p_access, "cannot read data" ); */
  608.         return VLC_EGENERIC;
  609.     }
  610.     p_ck->i_type      = GetWLE( p_sys->buffer);
  611.     p_ck->i_size      = GetWLE( p_sys->buffer + 2);
  612.     p_ck->i_sequence  = GetDWLE( p_sys->buffer + 4);
  613.     p_ck->i_unknown   = GetWLE( p_sys->buffer + 8);
  614.     p_ck->i_size2     = GetWLE( p_sys->buffer + 10);
  615.     p_ck->p_data      = p_sys->buffer + 12;
  616.     p_ck->i_data      = p_ck->i_size2 - 8;
  617.     if( p_ck->i_type == 0x4524 )   // Transfer complete
  618.     {
  619.         if( p_ck->i_sequence == 0 )
  620.         {
  621.             msg_Warn( p_access, "EOF" );
  622.             return VLC_EGENERIC;
  623.         }
  624.         else
  625.         {
  626.             msg_Warn( p_access, "Next stream follow but not supported" );
  627.             return VLC_EGENERIC;
  628.         }
  629.     }
  630.     else if( p_ck->i_type != 0x4824 && p_ck->i_type != 0x4424 )
  631.     {
  632.         msg_Err( p_access, "invalid chunk FATAL (0x%x)", p_ck->i_type );
  633.         return VLC_EGENERIC;
  634.     }
  635.     if( p_ck->i_data > 0 &&
  636.         net_Read( p_access, p_sys->fd, &p_sys->buffer[12], p_ck->i_data, VLC_TRUE ) < p_ck->i_data )
  637.     {
  638.         msg_Err( p_access, "cannot read data" );
  639.         return VLC_EGENERIC;
  640.     }
  641.     if( p_sys->i_packet_sequence != 0 &&
  642.         p_ck->i_sequence != p_sys->i_packet_sequence )
  643.     {
  644.         msg_Warn( p_access, "packet lost ? (%d != %d)", p_ck->i_sequence, p_sys->i_packet_sequence );
  645.     }
  646.     p_sys->i_packet_sequence = p_ck->i_sequence + 1;
  647.     p_sys->i_packet_used   = 0;
  648.     p_sys->i_packet_length = p_ck->i_data;
  649.     p_sys->p_packet        = p_ck->p_data;
  650.     return VLC_SUCCESS;
  651. }