decoder: remove unused variable
[vlc.git] / modules / demux / mjpeg.c
blobd5e8dbdfcf9baf534260972a0dee5f728bec7097
1 /*****************************************************************************
2 * mjpeg.c : demuxes mjpeg webcam http streams
3 *****************************************************************************
4 * Copyright (C) 2004 VLC authors and VideoLAN
6 * Authors: Henry Jen (slowhog) <henryjen@ztune.net>
7 * Derk-Jan Hartman (thedj)
8 * Sigmund Augdal (Dnumgis)
9 * Laurent Aimar <fenrir@via.ecp.fr>
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation; either version 2.1 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public License
22 * along with this program; if not, write to the Free Software Foundation,
23 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 *****************************************************************************/
26 /*****************************************************************************
27 * Preamble
28 *****************************************************************************/
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
36 #include <vlc_demux.h>
37 #include "mxpeg_helper.h"
39 /*****************************************************************************
40 * Module descriptor
41 *****************************************************************************/
42 static int Open ( vlc_object_t * );
44 #define FPS_TEXT N_("Frames per Second")
45 #define FPS_LONGTEXT N_("This is the desired frame rate when " \
46 "playing MJPEG from a file. Use 0 (this is the default value) for a " \
47 "live stream (from a camera).")
49 vlc_module_begin ()
50 set_shortname( "MJPEG")
51 set_description( N_("M-JPEG camera demuxer") )
52 set_capability( "demux", 5 )
53 set_callback( Open )
54 set_category( CAT_INPUT )
55 set_subcategory( SUBCAT_INPUT_DEMUX )
56 add_float( "mjpeg-fps", 0.0, FPS_TEXT, FPS_LONGTEXT, false )
57 vlc_module_end ()
59 /*****************************************************************************
60 * Local prototypes
61 *****************************************************************************/
62 static int MimeDemux( demux_t * );
63 static int MjpgDemux( demux_t * );
64 static int Control( demux_t *, int i_query, va_list args );
66 typedef struct
68 es_format_t fmt;
69 es_out_id_t *p_es;
71 bool b_still;
72 vlc_tick_t i_still_end;
73 vlc_tick_t i_time;
74 vlc_tick_t i_frame_length;
75 char *psz_separator;
76 int i_frame_size_estimate;
77 const uint8_t *p_peek;
78 int i_data_peeked;
79 int i_level;
80 } demux_sys_t;
82 /*****************************************************************************
83 * Peek: Helper function to peek data with incremental size.
84 * \return false if peek no more data, true otherwise.
85 *****************************************************************************/
86 static bool Peek( demux_t *p_demux, bool b_first )
88 int i_data;
89 demux_sys_t *p_sys = p_demux->p_sys;
91 if( b_first )
93 p_sys->i_data_peeked = 0;
95 else if( p_sys->i_data_peeked == p_sys->i_frame_size_estimate )
97 p_sys->i_frame_size_estimate += 5120;
99 i_data = vlc_stream_Peek( p_demux->s, &p_sys->p_peek,
100 p_sys->i_frame_size_estimate );
101 if( i_data == p_sys->i_data_peeked )
103 msg_Warn( p_demux, "no more data" );
104 return false;
106 p_sys->i_data_peeked = i_data;
107 if( i_data <= 0 )
109 msg_Warn( p_demux, "cannot peek data" );
110 return false;
112 return true;
115 /*****************************************************************************
116 * GetLine: Internal function used to dup a line of string from the buffer
117 *****************************************************************************/
118 static char* GetLine( demux_t *p_demux, int *p_pos )
120 demux_sys_t *p_sys = p_demux->p_sys;
121 const uint8_t *p_buf;
122 int i_size;
123 int i;
124 char *p_line;
126 while( *p_pos >= p_sys->i_data_peeked )
128 if( ! Peek( p_demux, false ) )
130 return NULL;
133 p_buf = p_sys->p_peek + *p_pos;
134 i_size = p_sys->i_data_peeked - *p_pos;
135 i = 0;
136 while( p_buf[i] != '\n' )
138 i++;
139 if( i == i_size )
141 if( ! Peek( p_demux, false ) )
143 return NULL;
145 p_buf = p_sys->p_peek + *p_pos;
146 i_size = p_sys->i_data_peeked - *p_pos;
149 *p_pos += i + 1;
150 if( i > 0 && p_buf[i - 1] == '\r' )
152 i--;
154 p_line = malloc( i + 1 );
155 if( unlikely( p_line == NULL ) )
156 return NULL;
157 strncpy ( p_line, (char*)p_buf, i );
158 p_line[i] = '\0';
159 return p_line;
162 /*****************************************************************************
163 * CheckMimeHeader: Internal function used to verify and skip mime header
164 * \param p_header_size Return size of MIME header, 0 if no MIME header
165 * detected, minus value if error
166 * \return true if content type is image/jpeg, false otherwise
167 *****************************************************************************/
168 static bool CheckMimeHeader( demux_t *p_demux, int *p_header_size )
170 bool b_jpeg = false;
171 int i_pos = 0;
172 char *psz_line;
173 char *p_ch;
174 demux_sys_t *p_sys = p_demux->p_sys;
176 *p_header_size = -1;
177 if( !Peek( p_demux, true ) )
179 msg_Err( p_demux, "cannot peek" );
180 return false;
182 if( p_sys->i_data_peeked < 5)
184 msg_Err( p_demux, "data shortage" );
185 return false;
187 if( strncmp( (char *)p_sys->p_peek, "--", 2 ) != 0
188 && strncmp( (char *)p_sys->p_peek, "\r\n--", 4 ) != 0 )
190 *p_header_size = 0;
191 return false;
193 else
195 i_pos = *p_sys->p_peek == '-' ? 2 : 4;
196 psz_line = GetLine( p_demux, &i_pos );
197 if( NULL == psz_line )
199 msg_Err( p_demux, "no EOL" );
200 return false;
203 /* Read the separator and remember it if not yet stored */
204 if( p_sys->psz_separator == NULL )
206 p_sys->psz_separator = psz_line;
207 msg_Dbg( p_demux, "Multipart MIME detected, using separator: %s",
208 p_sys->psz_separator );
210 else
212 if( strcmp( psz_line, p_sys->psz_separator ) )
214 msg_Warn( p_demux, "separator %s does not match %s", psz_line,
215 p_sys->psz_separator );
217 free( psz_line );
221 psz_line = GetLine( p_demux, &i_pos );
222 while( psz_line && *psz_line )
224 if( !strncasecmp( psz_line, "Content-Type:", 13 ) )
226 p_ch = psz_line + 13;
227 while( *p_ch != '\0' && ( *p_ch == ' ' || *p_ch == '\t' ) ) p_ch++;
228 if( strncasecmp( p_ch, "image/jpeg", 10 ) )
230 msg_Warn( p_demux, "%s, image/jpeg is expected", psz_line );
231 b_jpeg = false;
233 else
235 b_jpeg = true;
238 else
240 msg_Dbg( p_demux, "discard MIME header: %s", psz_line );
242 free( psz_line );
243 psz_line = GetLine( p_demux, &i_pos );
246 if( NULL == psz_line )
248 msg_Err( p_demux, "no EOL" );
249 return false;
252 free( psz_line );
254 *p_header_size = i_pos;
255 return b_jpeg;
258 static int SendBlock( demux_t *p_demux, int i )
260 demux_sys_t *p_sys = p_demux->p_sys;
261 block_t *p_block;
263 if( ( p_block = vlc_stream_Block( p_demux->s, i ) ) == NULL )
265 msg_Warn( p_demux, "cannot read data" );
266 return VLC_DEMUXER_EOF;
269 if( p_sys->i_frame_length != VLC_TICK_INVALID )
271 p_block->i_pts = p_sys->i_time;
272 p_sys->i_time += p_sys->i_frame_length;
274 else
276 p_block->i_pts = vlc_tick_now();
278 p_block->i_dts = p_block->i_pts;
280 es_out_SetPCR( p_demux->out, p_block->i_pts );
281 es_out_Send( p_demux->out, p_sys->p_es, p_block );
283 if( p_sys->b_still )
284 p_sys->i_still_end = vlc_tick_now() + p_sys->i_frame_length;
286 return VLC_DEMUXER_SUCCESS;
289 /*****************************************************************************
290 * Open: check file and initializes structures
291 *****************************************************************************/
292 static int Open( vlc_object_t * p_this )
294 demux_t *p_demux = (demux_t*)p_this;
295 int i_size;
296 bool b_matched = false;
298 if( IsMxpeg( p_demux->s ) && !p_demux->obj.force )
299 // let avformat handle this case
300 return VLC_EGENERIC;
302 demux_sys_t *p_sys = vlc_obj_malloc( p_this, sizeof (*p_sys) );
303 if( unlikely(p_sys == NULL) )
304 return VLC_ENOMEM;
306 p_demux->p_sys = p_sys;
307 p_sys->p_es = NULL;
308 p_sys->i_time = VLC_TICK_0;
309 p_sys->i_level = 0;
311 p_sys->psz_separator = NULL;
312 p_sys->i_frame_size_estimate = 15 * 1024;
314 char *content_type = stream_ContentType( p_demux->s );
315 if ( content_type )
317 //FIXME: this is not fully match to RFC
318 char* boundary = strstr( content_type, "boundary=" );
319 if( boundary )
321 boundary += strlen( "boundary=" );
322 size_t len = strlen( boundary );
323 if( len > 2 && boundary[0] == '"'
324 && boundary[len-1] == '"' )
326 boundary[len-1] = '\0';
327 boundary++;
329 p_sys->psz_separator = vlc_obj_strdup( p_this, boundary );
330 if( !p_sys->psz_separator )
332 free( content_type );
333 return VLC_ENOMEM;
336 free( content_type );
339 b_matched = CheckMimeHeader( p_demux, &i_size);
340 if( b_matched )
342 p_demux->pf_demux = MimeDemux;
343 if( vlc_stream_Read( p_demux->s, NULL, i_size ) < i_size )
344 return VLC_EGENERIC;
346 else if( i_size == 0 )
348 /* 0xffd8 identify a JPEG SOI */
349 if( p_sys->p_peek[0] == 0xFF && p_sys->p_peek[1] == 0xD8 )
351 msg_Dbg( p_demux, "JPEG SOI marker detected" );
352 p_demux->pf_demux = MjpgDemux;
353 p_sys->i_level++;
355 else
357 return VLC_EGENERIC;
360 else
362 return VLC_EGENERIC;
365 /* Frame rate */
366 float f_fps = var_InheritFloat( p_demux, "mjpeg-fps" );
368 p_sys->i_still_end = VLC_TICK_INVALID;
369 if( demux_IsPathExtension( p_demux, ".jpeg" ) ||
370 demux_IsPathExtension( p_demux, ".jpg" ) )
372 /* Plain JPEG file = single still picture */
373 p_sys->b_still = true;
374 if( f_fps == 0.f )
375 /* Defaults to 1fps */
376 f_fps = 1.f;
378 else
379 p_sys->b_still = false;
380 p_sys->i_frame_length = f_fps ? vlc_tick_rate_duration(f_fps) : VLC_TICK_INVALID;
382 es_format_Init( &p_sys->fmt, VIDEO_ES, VLC_CODEC_MJPG );
384 p_sys->fmt.i_id = 0;
385 p_sys->p_es = es_out_Add( p_demux->out, &p_sys->fmt );
386 if( unlikely(p_sys->p_es == NULL) )
387 return VLC_ENOMEM;
389 p_demux->pf_control = Control;
390 return VLC_SUCCESS;
393 /*****************************************************************************
394 * Demux: read packet and send them to decoders
395 *****************************************************************************
396 * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
397 *****************************************************************************/
398 static int MjpgDemux( demux_t *p_demux )
400 demux_sys_t *p_sys = p_demux->p_sys;
401 int i;
403 if( p_sys->b_still && p_sys->i_still_end != VLC_TICK_INVALID )
405 /* Still frame, wait until the pause delay is gone */
406 vlc_tick_wait( p_sys->i_still_end );
407 p_sys->i_still_end = VLC_TICK_INVALID;
408 return VLC_DEMUXER_SUCCESS;
411 if( !Peek( p_demux, true ) )
413 msg_Warn( p_demux, "cannot peek data" );
414 return VLC_DEMUXER_EOF;
416 if( p_sys->i_data_peeked < 4 )
418 msg_Warn( p_demux, "data shortage" );
419 return VLC_DEMUXER_EOF;
421 i = 3;
422 FIND_NEXT_EOI:
423 while( !( p_sys->p_peek[i-1] == 0xFF && p_sys->p_peek[i] == 0xD9 ) )
425 if( p_sys->p_peek[i-1] == 0xFF && p_sys->p_peek[i] == 0xD9 )
427 p_sys->i_level++;
428 msg_Dbg( p_demux, "we found another JPEG SOI at %d", i );
430 i++;
431 if( i >= p_sys->i_data_peeked )
433 msg_Dbg( p_demux, "did not find JPEG EOI in %d bytes",
434 p_sys->i_data_peeked );
435 if( !Peek( p_demux, false ) )
437 msg_Warn( p_demux, "no more data is available at the moment" );
438 return VLC_DEMUXER_EOF;
442 i++;
444 msg_Dbg( p_demux, "JPEG EOI detected at %d", i );
445 p_sys->i_level--;
447 if( p_sys->i_level > 0 )
448 goto FIND_NEXT_EOI;
449 return SendBlock( p_demux, i );
452 static int MimeDemux( demux_t *p_demux )
454 demux_sys_t *p_sys = p_demux->p_sys;
455 int i_size, i;
457 bool b_match = CheckMimeHeader( p_demux, &i_size );
459 if( i_size > 0 )
461 if( vlc_stream_Read( p_demux->s, NULL, i_size ) != i_size )
462 return VLC_DEMUXER_EOF;
464 else if( i_size < 0 )
466 return VLC_DEMUXER_EOF;
468 else
470 // No MIME header, assume OK
471 b_match = true;
474 if( !Peek( p_demux, true ) )
476 msg_Warn( p_demux, "cannot peek data" );
477 return VLC_DEMUXER_EOF;
480 i = 0;
481 i_size = strlen( p_sys->psz_separator ) + 2;
482 if( p_sys->i_data_peeked < i_size )
484 msg_Warn( p_demux, "data shortage" );
485 return VLC_DEMUXER_EOF;
488 for( ;; )
490 while( !( p_sys->p_peek[i] == '-' && p_sys->p_peek[i+1] == '-' ) )
492 i++;
493 i_size++;
494 if( i_size >= p_sys->i_data_peeked )
496 msg_Dbg( p_demux, "MIME boundary not found in %d bytes of "
497 "data", p_sys->i_data_peeked );
499 if( !Peek( p_demux, false ) )
501 msg_Warn( p_demux, "no more data is available at the "
502 "moment" );
503 return VLC_DEMUXER_EOF;
508 /* Handle old and new style of separators */
509 if (!strncmp(p_sys->psz_separator, (char *)(p_sys->p_peek + i + 2),
510 strlen( p_sys->psz_separator ))
511 || ((strlen(p_sys->psz_separator) > 4)
512 && !strncmp(p_sys->psz_separator, "--", 2)
513 && !strncmp(p_sys->psz_separator, (char *)(p_sys->p_peek + i),
514 strlen( p_sys->psz_separator))))
516 break;
519 i++;
520 i_size++;
523 if( !b_match )
525 msg_Err( p_demux, "discard non-JPEG part" );
526 return VLC_DEMUXER_EOF;
529 return SendBlock( p_demux, i );
532 /*****************************************************************************
533 * Control:
534 *****************************************************************************/
535 static int Control( demux_t *p_demux, int i_query, va_list args )
537 return demux_vaControlHelper( p_demux->s, 0, 0, 0, 0, i_query, args );