00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include <stdlib.h>
00028
00029 #include <vlc/vlc.h>
00030 #include <vlc/sout.h>
00031
00032 #define SEPARATOR_TEXT N_( "Multipart separator string" )
00033 #define SEPARATOR_LONGTEXT N_( "Multipart strings like MPJPEG use a " \
00034 "separator string between content pieces. "\
00035 "You can select this string. Default is "\
00036 "--myboundary" )
00037
00038
00039 #define CONTENT_TYPE "Content-Type: image/jpeg"
00040
00041
00042
00043 static int Open ( vlc_object_t * );
00044 static void Close ( vlc_object_t * );
00045
00046 #define SOUT_CFG_PREFIX "sout-mpjpeg-"
00047
00048 vlc_module_begin();
00049 set_shortname( "MPJPEG" );
00050 set_description( _("Multipart jpeg muxer") );
00051 set_capability( "sout mux", 5 );
00052 add_string( SOUT_CFG_PREFIX "separator", "--myboundary", NULL,
00053 SEPARATOR_TEXT, SEPARATOR_LONGTEXT, VLC_TRUE );
00054 set_category( CAT_SOUT );
00055 set_subcategory( SUBCAT_SOUT_MUX );
00056 set_callbacks( Open, Close );
00057 add_shortcut( "mpjpeg" );
00058 vlc_module_end();
00059
00060
00061
00062
00063 static const char *ppsz_sout_options[] = { "separator", NULL };
00064
00065 static int Control ( sout_mux_t *, int, va_list );
00066 static int AddStream( sout_mux_t *, sout_input_t * );
00067 static int DelStream( sout_mux_t *, sout_input_t * );
00068 static int Mux ( sout_mux_t * );
00069
00070 struct sout_mux_sys_t
00071 {
00072 block_t *p_separator;
00073 vlc_bool_t b_send_headers;
00074 };
00075
00076
00077
00078
00079 static int Open( vlc_object_t *p_this )
00080 {
00081 int i_size;
00082 sout_mux_t *p_mux = (sout_mux_t*)p_this;
00083 sout_mux_sys_t *p_sys;
00084 char *psz_separator_block, *psz_separator;
00085
00086 msg_Dbg( p_mux, "Multipart jpeg muxer opened" );
00087 sout_CfgParse( p_mux, SOUT_CFG_PREFIX, ppsz_sout_options, p_mux->p_cfg );
00088
00089 p_sys = p_mux->p_sys = malloc( sizeof(sout_mux_sys_t) );
00090 p_sys->b_send_headers = VLC_TRUE;
00091
00092 psz_separator = var_GetString( p_mux, SOUT_CFG_PREFIX "separator" );
00093 i_size = strlen( psz_separator ) + 2 + 2 + 2 + strlen( CONTENT_TYPE );
00094 psz_separator_block = (char*)malloc( i_size );
00095 sprintf( psz_separator_block, "\r\n%s\r\n%s\r\n", psz_separator,
00096 CONTENT_TYPE );
00097 p_sys->p_separator = block_New( p_mux, i_size );
00098 memcpy( p_sys->p_separator->p_buffer, psz_separator_block , i_size );
00099
00100 if( psz_separator_block ) free( psz_separator_block );
00101
00102 p_mux->pf_control = Control;
00103 p_mux->pf_addstream = AddStream;
00104 p_mux->pf_delstream = DelStream;
00105 p_mux->pf_mux = Mux;
00106
00107 return VLC_SUCCESS;
00108 }
00109
00110
00111
00112
00113
00114 static void Close( vlc_object_t * p_this )
00115 {
00116 sout_mux_t *p_mux = (sout_mux_t*)p_this;
00117 sout_mux_sys_t *p_sys = p_mux->p_sys;
00118
00119 msg_Dbg( p_mux, "Multipart jpeg muxer closed" );
00120 block_Release( p_sys->p_separator );
00121 free( p_sys );
00122 }
00123
00124 static int Control( sout_mux_t *p_mux, int i_query, va_list args )
00125 {
00126 vlc_bool_t *pb_bool;
00127 char **ppsz;
00128
00129 switch( i_query )
00130 {
00131 case MUX_CAN_ADD_STREAM_WHILE_MUXING:
00132 pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
00133 *pb_bool = VLC_TRUE;
00134 return VLC_SUCCESS;
00135
00136 case MUX_GET_ADD_STREAM_WAIT:
00137 pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
00138 *pb_bool = VLC_TRUE;
00139 return VLC_SUCCESS;
00140
00141 case MUX_GET_MIME:
00142 ppsz = (char**)va_arg( args, char ** );
00143 *ppsz = strdup( "multipart/x-mixed-replace; boundary=This Random String" );
00144 return VLC_SUCCESS;
00145
00146 default:
00147 return VLC_EGENERIC;
00148 }
00149 }
00150
00151 static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
00152 {
00153 if( p_mux->i_nb_inputs > 1 )
00154 {
00155 msg_Dbg( p_mux, "only 1 input allowed" );
00156 return VLC_EGENERIC;
00157 }
00158
00159 msg_Dbg( p_mux, "adding input" );
00160 if( p_input->p_fmt->i_codec != VLC_FOURCC('M','J','P','G') &&
00161 p_input->p_fmt->i_codec != VLC_FOURCC('m','j','p','g') &&
00162 p_input->p_fmt->i_codec != VLC_FOURCC('j','p','e','g') &&
00163 p_input->p_fmt->i_codec != VLC_FOURCC('J','P','E','G') &&
00164 p_input->p_fmt->i_codec != VLC_FOURCC('J','F','I','F') &&
00165 p_input->p_fmt->i_codec != VLC_FOURCC('J','P','G','L') &&
00166 p_input->p_fmt->i_codec != VLC_FOURCC('m','j','p','a') )
00167 {
00168 return VLC_EGENERIC;
00169 }
00170
00171 return VLC_SUCCESS;
00172 }
00173
00174 static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
00175 {
00176 msg_Dbg( p_mux, "removing input" );
00177 return VLC_SUCCESS;
00178 }
00179
00180 static int Mux( sout_mux_t *p_mux )
00181 {
00182 block_fifo_t *p_fifo;
00183 sout_mux_sys_t *p_sys = p_mux->p_sys;
00184 int i_count;
00185
00186 char psz_content_length[25];
00187
00188 if( p_sys->b_send_headers )
00189 {
00190 block_t *p_header;
00191 char *psz_separator = var_CreateGetString( p_mux,
00192 SOUT_CFG_PREFIX "separator" );
00193 char *psz_separator_block = (char *)malloc( strlen( psz_separator ) +
00194 2 + strlen( CONTENT_TYPE ) );
00195
00196 sprintf( psz_separator_block, "%s\r\n%s\r\n", psz_separator,
00197 CONTENT_TYPE );
00198
00199 p_header = block_New( p_mux, strlen( psz_separator_block ) );
00200 memcpy( p_header->p_buffer, psz_separator_block ,
00201 strlen( psz_separator_block ) );
00202 p_header->i_flags |= BLOCK_FLAG_HEADER;
00203 sout_AccessOutWrite( p_mux->p_access, p_header );
00204 p_sys->b_send_headers = VLC_FALSE;
00205 if( psz_separator_block ) free( psz_separator_block );
00206 }
00207
00208 if( !p_mux->i_nb_inputs ) return VLC_SUCCESS;
00209
00210 p_fifo = p_mux->pp_inputs[0]->p_fifo;
00211 i_count = p_fifo->i_depth;
00212 while( i_count > 0 )
00213 {
00214 block_t *p_length = block_New( p_mux, 25 );
00215 block_t *p_data = block_FifoGet( p_fifo );
00216 sout_AccessOutWrite( p_mux->p_access,
00217 block_Duplicate( p_sys->p_separator ) );
00218 memset( psz_content_length, 0, 25 );
00219 snprintf( psz_content_length, 25, "Content-Length: %i\r\n\r\n",
00220 p_data->i_buffer );
00221 memcpy( p_length->p_buffer, psz_content_length, 25 );
00222 sout_AccessOutWrite( p_mux->p_access, p_length );
00223 sout_AccessOutWrite( p_mux->p_access, p_data );
00224
00225 i_count--;
00226 }
00227
00228 return VLC_SUCCESS;
00229 }