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

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * mjpeg.c : demuxes mjpeg webcam http streams
  3.  *****************************************************************************
  4.  * Copyright (C) 2004 VideoLAN
  5.  * $Id: mjpeg.c 7196 2004-03-29 21:29:31Z fenrir $
  6.  *
  7.  * Authors: Henry Jen (slowhog) <henryjen@ztune.net>
  8.  *          Derk-Jan Hartman (thedj)
  9.  *          Sigmund Augdal (Dnumgis)
  10.  *          Laurent Aimar <fenrir@via.ecp.fr>
  11.  *
  12.  * This program is free software; you can redistribute it and/or modify
  13.  * it under the terms of the GNU General Public License as published by
  14.  * the Free Software Foundation; either version 2 of the License, or
  15.  * (at your option) any later version.
  16.  *
  17.  * This program is distributed in the hope that it will be useful,
  18.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.  * GNU General Public License for more details.
  21.  *
  22.  * You should have received a copy of the GNU General Public License
  23.  * along with this program; if not, write to the Free Software
  24.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  25.  *****************************************************************************/
  26. /*****************************************************************************
  27.  * Preamble
  28.  *****************************************************************************/
  29. #include <stdlib.h>                                      /* malloc(), free() */
  30. #include <vlc/vlc.h>
  31. #include <vlc/input.h>
  32. #include <codecs.h>
  33. /*****************************************************************************
  34.  * Module descriptor
  35.  *****************************************************************************/
  36. static int  Open ( vlc_object_t * );
  37. static void Close( vlc_object_t * );
  38. #define FPS_TEXT N_("Frames per Second")
  39. #define FPS_LONGTEXT N_("Allows you to set the desired frame rate when " 
  40.     "playing from files, use 0 for live.")
  41. vlc_module_begin();
  42.     set_description( _("JPEG camera demuxer") );
  43.     set_capability( "demux2", 5 );
  44.     set_callbacks( Open, Close );
  45.     add_float( "mjpeg-fps", 0.0, NULL, FPS_TEXT, FPS_LONGTEXT, VLC_FALSE );
  46. vlc_module_end();
  47. /*****************************************************************************
  48.  * Local prototypes
  49.  *****************************************************************************/
  50. static int MimeDemux( demux_t * );
  51. static int MjpgDemux( demux_t * );
  52. static int Control( demux_t *, int i_query, va_list args );
  53. struct demux_sys_t
  54. {
  55.     es_format_t     fmt;
  56.     es_out_id_t     *p_es;
  57.     vlc_bool_t      b_still;
  58.     mtime_t         i_still_end;
  59.     mtime_t         i_time;
  60.     mtime_t         i_frame_length;
  61.     char            *psz_separator;
  62.     int             i_frame_size_estimate;
  63.     uint8_t         *p_peek;
  64.     int             i_data_peeked;
  65. };
  66. /*****************************************************************************
  67.  * Peek: Helper function to peek data with incremental size. 
  68.  * return VLC_FALSE if peek no more data, VLC_TRUE otherwise.
  69.  *****************************************************************************/
  70. static vlc_bool_t Peek( demux_t *p_demux, vlc_bool_t b_first )
  71. {
  72.     int i_data;
  73.     demux_sys_t *p_sys = p_demux->p_sys;
  74.     if( b_first )
  75.     {
  76.         p_sys->i_data_peeked = 0;
  77.     }
  78.     else if( p_sys->i_data_peeked == p_sys->i_frame_size_estimate )
  79.     {
  80.         p_sys->i_frame_size_estimate += 5120;
  81.     }
  82.     i_data = stream_Peek( p_demux->s, &p_sys->p_peek,
  83.                           p_sys->i_frame_size_estimate );
  84.     if( i_data == p_sys->i_data_peeked )
  85.     {
  86.         msg_Warn( p_demux, "no more data" );
  87.         return VLC_FALSE;
  88.     }
  89.     p_sys->i_data_peeked = i_data;
  90.     if( i_data <= 0 )
  91.     {
  92.         msg_Warn( p_demux, "cannot peek data" );
  93.         return VLC_FALSE;
  94.     }
  95.     return VLC_TRUE;
  96. }
  97. /*****************************************************************************
  98.  * GetLine: Internal function used to dup a line of string from the buffer
  99.  *****************************************************************************/
  100. static char* GetLine( demux_t *p_demux, int *p_pos )
  101. {
  102.     demux_sys_t *p_sys = p_demux->p_sys;
  103.     uint8_t     *p_buf;
  104.     int         i_size;
  105.     int         i;
  106.     char        *p_line;
  107.     while( *p_pos > p_sys->i_data_peeked )
  108.     {
  109.         if( ! Peek( p_demux, VLC_FALSE ) )
  110.         {
  111.             return NULL;
  112.         }
  113.     }
  114.     p_buf = p_sys->p_peek + *p_pos;
  115.     i_size = p_sys->i_data_peeked - *p_pos;
  116.     i = 0;
  117.     while( p_buf[i] != 'n' )
  118.     {
  119.         i++;
  120.         if( i == i_size )
  121.         {
  122.             if( ! Peek( p_demux, VLC_FALSE ) )
  123.             {
  124.                 return NULL;
  125.             }
  126.         }
  127.         p_buf = p_sys->p_peek + *p_pos;
  128.         i_size = p_sys->i_data_peeked - *p_pos;
  129.     }
  130.     *p_pos += ( i + 1 );
  131.     if( i > 0 && 'r' == p_buf[i - 1] )
  132.     {
  133.         i--;
  134.     }
  135.     p_line = malloc( i + 1 );
  136.     if( NULL == p_line )
  137.     {
  138.         msg_Err( p_demux, "out of memory" );
  139.         return NULL;
  140.     }
  141.     strncpy ( p_line, p_buf, i );
  142.     p_line[i] = '';
  143. //    msg_Dbg( p_demux, "i = %d, pos = %d, %s", i, *p_pos, p_line );
  144.     return p_line;
  145. }
  146. /*****************************************************************************
  147.  * CheckMimeHeader: Internal function used to verify and skip mime header
  148.  * param p_header_size Return size of MIME header, 0 if no MIME header
  149.  * detected, minus value if error
  150.  * return VLC_TRUE if content type is image/jpeg, VLC_FALSE otherwise
  151.  *****************************************************************************/
  152. static vlc_bool_t CheckMimeHeader( demux_t *p_demux, int *p_header_size )
  153. {
  154.     vlc_bool_t  b_jpeg = VLC_FALSE;
  155.     int         i_pos;
  156.     char        *psz_line;
  157.     char        *p_ch;
  158.     demux_sys_t *p_sys = p_demux->p_sys;
  159.     if( !Peek( p_demux, VLC_TRUE ) )
  160.     {
  161.         msg_Err( p_demux, "cannot peek" );
  162.         *p_header_size = -1;
  163.         return VLC_FALSE;
  164.     }
  165.     if( p_sys->i_data_peeked < 3)
  166.     {
  167.         msg_Err( p_demux, "data shortage" );
  168.         *p_header_size = -2;
  169.         return VLC_FALSE;
  170.     }
  171.     if( strncmp( p_sys->p_peek, "--", 2 ) )
  172.     {
  173.         *p_header_size = 0;
  174.         return VLC_FALSE;
  175.     }
  176.     i_pos = 2;
  177.     psz_line = GetLine( p_demux, &i_pos );
  178.     if( NULL == psz_line )
  179.     {
  180.         msg_Err( p_demux, "no EOL" );
  181.         *p_header_size = -3;
  182.         return VLC_FALSE;
  183.     }
  184.     if( NULL == p_sys->psz_separator )
  185.     {
  186.         p_sys->psz_separator = psz_line;
  187.         msg_Dbg( p_demux, "Multipart MIME detected, using separator: %s",
  188.                  p_sys->psz_separator );
  189.     }
  190.     else
  191.     {
  192.         if( strcmp( psz_line, p_sys->psz_separator ) )
  193.         {
  194.             msg_Warn( p_demux, "separator %s does not match %s", psz_line,
  195.                       p_sys->psz_separator );
  196.         }
  197.         free( psz_line );
  198.     }
  199.     psz_line = GetLine( p_demux, &i_pos );
  200.     while( psz_line && *psz_line )
  201.     {
  202.         if( !strncasecmp( psz_line, "Content-Type:", 13 ) )
  203.         {
  204.             p_ch = psz_line + 13;
  205.             while( *p_ch != '' && ( *p_ch == ' ' || *p_ch == 't' ) ) p_ch++;
  206.             if( strncasecmp( p_ch, "image/jpeg", 10 ) )
  207.             {
  208.                 msg_Warn( p_demux, "%s, image/jpeg is expected", psz_line );
  209.                 b_jpeg = VLC_FALSE;
  210.             }
  211.             else
  212.             {
  213.                 b_jpeg = VLC_TRUE;
  214.             }
  215.         }
  216.         else
  217.         {
  218.             msg_Dbg( p_demux, "Discard MIME header: %s", psz_line );
  219.         }
  220.         free( psz_line );
  221.         psz_line = GetLine( p_demux, &i_pos );
  222.     }
  223.     if( NULL == psz_line )
  224.     {
  225.         msg_Err( p_demux, "no EOL" );
  226.         *p_header_size = -3;
  227.         return VLC_FALSE;
  228.     }
  229.     free( psz_line );
  230.     *p_header_size = i_pos;
  231.     return b_jpeg;
  232. }
  233. static int SendBlock( demux_t *p_demux, int i )
  234. {
  235.     demux_sys_t *p_sys = p_demux->p_sys;
  236.     block_t     *p_block;
  237.     if( ( p_block = stream_Block( p_demux->s, i ) ) == NULL )
  238.     {
  239.         msg_Warn( p_demux, "cannot read data" );
  240.         return 0;
  241.     }
  242.     if( !p_sys->i_frame_length || !p_sys->i_time )
  243.     {
  244.         p_sys->i_time = p_block->i_dts = p_block->i_pts = mdate();
  245.     }
  246.     else
  247.     {
  248.         p_block->i_dts = p_block->i_pts = p_sys->i_time;
  249.         p_sys->i_time += p_sys->i_frame_length;
  250.     }
  251.     /* set PCR */
  252.     es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_block->i_pts );
  253.     es_out_Send( p_demux->out, p_sys->p_es, p_block );
  254.     if( p_sys->b_still )
  255.     {
  256.         p_sys->i_still_end = mdate() + I64C(5000000);
  257.     }
  258.     return 1;
  259. }
  260. /*****************************************************************************
  261.  * Open: check file and initializes structures
  262.  *****************************************************************************/
  263. static int Open( vlc_object_t * p_this )
  264. {
  265.     demux_t     *p_demux = (demux_t*)p_this;
  266.     demux_sys_t *p_sys;
  267.     int         i_size;
  268.     int         b_matched = VLC_FALSE;
  269.     vlc_value_t val;
  270.     char *psz_ext;
  271.     p_demux->pf_control = Control;
  272.     p_demux->p_sys      = p_sys = malloc( sizeof( demux_sys_t ) );
  273.     p_sys->p_es         = NULL;
  274.     p_sys->i_time       = 0;
  275.     p_sys->psz_separator = NULL;
  276.     p_sys->i_frame_size_estimate = 15 * 1024;
  277.     b_matched = CheckMimeHeader( p_demux, &i_size);
  278.     if( b_matched )
  279.     {
  280.         p_demux->pf_demux = MimeDemux;
  281.         stream_Read( p_demux->s, NULL, i_size );
  282.     }
  283.     else if( 0 == i_size )
  284.     {
  285.         /* 0xffd8 identify a JPEG SOI */
  286.         if( p_sys->p_peek[0] == 0xFF && p_sys->p_peek[1] == 0xD8 )
  287.         {
  288.             msg_Dbg( p_demux, "JPEG SOI marker detected" );
  289.             p_demux->pf_demux = MjpgDemux;
  290.         }
  291.         else
  292.         {
  293.             goto error;
  294.         }
  295.     }
  296.     else
  297.     {
  298.         goto error;
  299.     }
  300.     /* Check for jpeg file extension */
  301.     p_sys->b_still = VLC_FALSE;
  302.     p_sys->i_still_end = 0;
  303.     psz_ext = strrchr( p_demux->psz_path, '.' );
  304.     if( psz_ext && ( !strcasecmp( psz_ext, ".jpeg" ) ||
  305.                      !strcasecmp( psz_ext, ".jpg" ) ) )
  306.     {
  307.         p_sys->b_still = VLC_TRUE;
  308.     }
  309.     var_Create( p_demux, "mjpeg-fps", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
  310.     var_Get( p_demux, "mjpeg-fps", &val );
  311.     p_sys->i_frame_length = 0;
  312.     if( val.f_float )
  313.     {
  314.         p_sys->i_frame_length = 1000000.0 / val.f_float;
  315.     }
  316.     es_format_Init( &p_sys->fmt, VIDEO_ES, 0 );
  317.     p_sys->fmt.i_codec = VLC_FOURCC('m','j','p','g');
  318.     p_sys->p_es = es_out_Add( p_demux->out, &p_sys->fmt );
  319.     return VLC_SUCCESS;
  320. error:
  321.     free( p_sys );
  322.     return VLC_EGENERIC;
  323. }
  324. /*****************************************************************************
  325.  * Demux: read packet and send them to decoders
  326.  *****************************************************************************
  327.  * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
  328.  *****************************************************************************/
  329. static int MjpgDemux( demux_t *p_demux )
  330. {
  331.     demux_sys_t *p_sys = p_demux->p_sys;
  332.     int i;
  333.     if( p_sys->b_still && p_sys->i_still_end && p_sys->i_still_end < mdate() )
  334.     {
  335.         /* Still frame, wait until the pause delay is gone */
  336.         p_sys->i_still_end = 0;
  337.     }
  338.     else if( p_sys->b_still && p_sys->i_still_end )
  339.     {
  340.         msleep( 40000 );
  341.         return 1;
  342.     }
  343.     if( !Peek( p_demux, VLC_TRUE ) )
  344.     {
  345.         msg_Warn( p_demux, "cannot peek data" );
  346.         return 0;
  347.     }
  348.     if( p_sys->i_data_peeked < 4 )
  349.     {
  350.         msg_Warn( p_demux, "data shortage" );
  351.         return 0;
  352.     }
  353.     i = 3;
  354.     while( !( 0xFF == p_sys->p_peek[i-1] && 0xD9 == p_sys->p_peek[i] ) )
  355.     {
  356.         i++;
  357.         if( i >= p_sys->i_data_peeked )
  358.         {
  359.             msg_Dbg( p_demux, "Did not find JPEG EOI in %d bytes",
  360.                      p_sys->i_data_peeked );
  361.             if( !Peek( p_demux, VLC_FALSE ) )
  362.             {
  363.                 msg_Warn( p_demux, "No more data is available at the moment" );
  364.                 return 0;
  365.             }
  366.         }
  367.     }
  368.     i++;
  369.     msg_Dbg( p_demux, "JPEG EOI detected at %d", i );
  370.     return SendBlock( p_demux, i );
  371. }
  372. static int MimeDemux( demux_t *p_demux )
  373. {
  374.     demux_sys_t *p_sys = p_demux->p_sys;
  375.     int         i_size, i;
  376.     vlc_bool_t  b_match;
  377.     vlc_bool_t  b_done;
  378.     b_match = CheckMimeHeader( p_demux, &i_size );
  379.     if( i_size > 0 )
  380.     {
  381.         stream_Read( p_demux->s, NULL, i_size );
  382.     }
  383.     else if( i_size < 0 )
  384.     {
  385.         return 0;
  386.     }
  387.     else
  388.     {
  389.         // No MIME header, assume OK
  390.         b_match = VLC_TRUE;
  391.     }
  392.     if( !Peek( p_demux, VLC_TRUE ) )
  393.     {
  394.         msg_Warn( p_demux, "cannot peek data" );
  395.         return 0;
  396.     }
  397.     i = 0;
  398.     i_size = strlen( p_sys->psz_separator ) + 2;
  399.     if( p_sys->i_data_peeked < i_size )
  400.     {
  401.         msg_Warn( p_demux, "data shortage" );
  402.         return 0;
  403.     }
  404.     b_done = VLC_FALSE;
  405.     while( !b_done )
  406.     {
  407.         while( !( p_sys->p_peek[i] == '-' && p_sys->p_peek[i+1] == '-' ) )
  408.         {
  409.             i++;
  410.             i_size++;
  411.             if( i_size >= p_sys->i_data_peeked )
  412.             {
  413.                 msg_Dbg( p_demux, "MIME boundary not found in %d bytes of "
  414.                          "data", p_sys->i_data_peeked );
  415.                 if( !Peek( p_demux, VLC_FALSE ) )
  416.                 {
  417.                     msg_Warn( p_demux, "No more data is available at the "
  418.                               "moment" );
  419.                     return 0;
  420.                 }
  421.             }
  422.         }
  423.         if( !strncmp( p_sys->psz_separator, p_sys->p_peek + i + 2,
  424.                       strlen( p_sys->psz_separator ) ) )
  425.         {
  426.             b_done = VLC_TRUE;
  427.         }
  428.         else
  429.         {
  430.             i++;
  431.             i_size++;
  432.         }
  433.     }
  434.     if( !b_match )
  435.     {
  436.         msg_Err( p_demux, "Discard non-JPEG part" );
  437.         stream_Read( p_demux->s, NULL, i );
  438.         return 0;
  439.     }
  440.     return SendBlock( p_demux, i );
  441. }
  442. /*****************************************************************************
  443.  * Close: frees unused data
  444.  *****************************************************************************/
  445. static void Close ( vlc_object_t * p_this )
  446. {
  447.     demux_t     *p_demux = (demux_t*)p_this;
  448.     demux_sys_t *p_sys  = p_demux->p_sys;
  449.     if( p_sys->psz_separator )
  450.     {
  451.         free( p_sys->psz_separator );
  452.     }
  453.     free( p_sys );
  454. }
  455. /*****************************************************************************
  456.  * Control:
  457.  *****************************************************************************/
  458. static int Control( demux_t *p_demux, int i_query, va_list args )
  459. {
  460.     return demux2_vaControlHelper( p_demux->s, 0, 0, 0, 0, i_query, args );
  461. }