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

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * mjpeg.c : demuxes mjpeg webcam http streams
  3.  *****************************************************************************
  4.  * Copyright (C) 2004 the VideoLAN team
  5.  * $Id: 9459e91a528dc284347b1346473750f84e3edd1b $
  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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  25.  *****************************************************************************/
  26. /*****************************************************************************
  27.  * Preamble
  28.  *****************************************************************************/
  29. #ifdef HAVE_CONFIG_H
  30. # include "config.h"
  31. #endif
  32. #include <vlc_common.h>
  33. #include <vlc_plugin.h>
  34. #include <vlc_demux.h>
  35. #include <vlc_codecs.h>
  36. /*****************************************************************************
  37.  * Module descriptor
  38.  *****************************************************************************/
  39. static int  Open ( vlc_object_t * );
  40. static void Close( vlc_object_t * );
  41. #define FPS_TEXT N_("Frames per Second")
  42. #define FPS_LONGTEXT N_("This is the desired frame rate when " 
  43.     "playing MJPEG from a file. Use 0 (this is the default value) for a " 
  44.     "live stream (from a camera).")
  45. vlc_module_begin ()
  46.     set_shortname( "MJPEG")
  47.     set_description( N_("M-JPEG camera demuxer") )
  48.     set_capability( "demux", 5 )
  49.     set_callbacks( Open, Close )
  50.     set_category( CAT_INPUT )
  51.     set_subcategory( SUBCAT_INPUT_DEMUX )
  52.     add_float( "mjpeg-fps", 0.0, NULL, FPS_TEXT, FPS_LONGTEXT, false )
  53. vlc_module_end ()
  54. /*****************************************************************************
  55.  * Local prototypes
  56.  *****************************************************************************/
  57. static int MimeDemux( demux_t * );
  58. static int MjpgDemux( demux_t * );
  59. static int Control( demux_t *, int i_query, va_list args );
  60. struct demux_sys_t
  61. {
  62.     es_format_t     fmt;
  63.     es_out_id_t     *p_es;
  64.     bool      b_still;
  65.     mtime_t         i_still_end;
  66.     mtime_t         i_still_length;
  67.     mtime_t         i_time;
  68.     mtime_t         i_frame_length;
  69.     char            *psz_separator;
  70.     int             i_frame_size_estimate;
  71.     const uint8_t   *p_peek;
  72.     int             i_data_peeked;
  73.     int             i_level;
  74. };
  75. /*****************************************************************************
  76.  * Peek: Helper function to peek data with incremental size.
  77.  * return false if peek no more data, true otherwise.
  78.  *****************************************************************************/
  79. static bool Peek( demux_t *p_demux, bool b_first )
  80. {
  81.     int i_data;
  82.     demux_sys_t *p_sys = p_demux->p_sys;
  83.     if( b_first )
  84.     {
  85.         p_sys->i_data_peeked = 0;
  86.     }
  87.     else if( p_sys->i_data_peeked == p_sys->i_frame_size_estimate )
  88.     {
  89.         p_sys->i_frame_size_estimate += 5120;
  90.     }
  91.     i_data = stream_Peek( p_demux->s, &p_sys->p_peek,
  92.                           p_sys->i_frame_size_estimate );
  93.     if( i_data == p_sys->i_data_peeked )
  94.     {
  95.         msg_Warn( p_demux, "no more data" );
  96.         return false;
  97.     }
  98.     p_sys->i_data_peeked = i_data;
  99.     if( i_data <= 0 )
  100.     {
  101.         msg_Warn( p_demux, "cannot peek data" );
  102.         return false;
  103.     }
  104.     return true;
  105. }
  106. /*****************************************************************************
  107.  * GetLine: Internal function used to dup a line of string from the buffer
  108.  *****************************************************************************/
  109. static char* GetLine( demux_t *p_demux, int *p_pos )
  110. {
  111.     demux_sys_t *p_sys = p_demux->p_sys;
  112.     const uint8_t *p_buf;
  113.     int         i_size;
  114.     int         i;
  115.     char        *p_line;
  116.     while( *p_pos >= p_sys->i_data_peeked )
  117.     {
  118.         if( ! Peek( p_demux, false ) )
  119.         {
  120.             return NULL;
  121.         }
  122.     }
  123.     p_buf = p_sys->p_peek + *p_pos;
  124.     i_size = p_sys->i_data_peeked - *p_pos;
  125.     i = 0;
  126.     while( p_buf[i] != 'n' )
  127.     {
  128.         i++;
  129.         if( i == i_size )
  130.         {
  131.             if( ! Peek( p_demux, false ) )
  132.             {
  133.                 return NULL;
  134.             }
  135.             p_buf = p_sys->p_peek + *p_pos;
  136.             i_size = p_sys->i_data_peeked - *p_pos;
  137.         }
  138.     }
  139.     *p_pos += ( i + 1 );
  140.     if( i > 0 && 'r' == p_buf[i - 1] )
  141.     {
  142.         i--;
  143.     }
  144.     p_line = malloc( i + 1 );
  145.     if( p_line == NULL )
  146.         return NULL;
  147.     strncpy ( p_line, (char*)p_buf, i );
  148.     p_line[i] = '';
  149. //    msg_Dbg( p_demux, "i = %d, pos = %d, %s", i, *p_pos, p_line );
  150.     return p_line;
  151. }
  152. /*****************************************************************************
  153.  * CheckMimeHeader: Internal function used to verify and skip mime header
  154.  * param p_header_size Return size of MIME header, 0 if no MIME header
  155.  * detected, minus value if error
  156.  * return true if content type is image/jpeg, false otherwise
  157.  *****************************************************************************/
  158. static bool CheckMimeHeader( demux_t *p_demux, int *p_header_size )
  159. {
  160.     bool  b_jpeg = false;
  161.     int         i_pos;
  162.     char        *psz_line;
  163.     char        *p_ch;
  164.     demux_sys_t *p_sys = p_demux->p_sys;
  165.     if( !Peek( p_demux, true ) )
  166.     {
  167.         msg_Err( p_demux, "cannot peek" );
  168.         *p_header_size = -1;
  169.         return false;
  170.     }
  171.     if( p_sys->i_data_peeked < 5)
  172.     {
  173.         msg_Err( p_demux, "data shortage" );
  174.         *p_header_size = -2;
  175.         return false;
  176.     }
  177.     if( strncmp( (char *)p_sys->p_peek, "--", 2 ) != 0
  178.         && strncmp( (char *)p_sys->p_peek, "rn--", 4 ) != 0 )
  179.     {
  180.         *p_header_size = 0;
  181.         return false;
  182.     }
  183.     i_pos = *p_sys->p_peek == '-' ? 2 : 4;
  184.     psz_line = GetLine( p_demux, &i_pos );
  185.     if( NULL == psz_line )
  186.     {
  187.         msg_Err( p_demux, "no EOL" );
  188.         *p_header_size = -3;
  189.         return false;
  190.     }
  191.     /* Read the separator and remember it if not yet stored */
  192.     if( p_sys->psz_separator == NULL )
  193.     {
  194.         p_sys->psz_separator = psz_line;
  195.         msg_Dbg( p_demux, "Multipart MIME detected, using separator: %s",
  196.                  p_sys->psz_separator );
  197.     }
  198.     else
  199.     {
  200.         if( strcmp( psz_line, p_sys->psz_separator ) )
  201.         {
  202.             msg_Warn( p_demux, "separator %s does not match %s", psz_line,
  203.                       p_sys->psz_separator );
  204.         }
  205.         free( psz_line );
  206.     }
  207.     psz_line = GetLine( p_demux, &i_pos );
  208.     while( psz_line && *psz_line )
  209.     {
  210.         if( !strncasecmp( psz_line, "Content-Type:", 13 ) )
  211.         {
  212.             p_ch = psz_line + 13;
  213.             while( *p_ch != '' && ( *p_ch == ' ' || *p_ch == 't' ) ) p_ch++;
  214.             if( strncasecmp( p_ch, "image/jpeg", 10 ) )
  215.             {
  216.                 msg_Warn( p_demux, "%s, image/jpeg is expected", psz_line );
  217.                 b_jpeg = false;
  218.             }
  219.             else
  220.             {
  221.                 b_jpeg = true;
  222.             }
  223.         }
  224.         else
  225.         {
  226.             msg_Dbg( p_demux, "discard MIME header: %s", psz_line );
  227.         }
  228.         free( psz_line );
  229.         psz_line = GetLine( p_demux, &i_pos );
  230.     }
  231.     if( NULL == psz_line )
  232.     {
  233.         msg_Err( p_demux, "no EOL" );
  234.         *p_header_size = -3;
  235.         return false;
  236.     }
  237.     free( psz_line );
  238.     *p_header_size = i_pos;
  239.     return b_jpeg;
  240. }
  241. static int SendBlock( demux_t *p_demux, int i )
  242. {
  243.     demux_sys_t *p_sys = p_demux->p_sys;
  244.     block_t     *p_block;
  245.     if( ( p_block = stream_Block( p_demux->s, i ) ) == NULL )
  246.     {
  247.         msg_Warn( p_demux, "cannot read data" );
  248.         return 0;
  249.     }
  250.     if( !p_sys->i_frame_length || !p_sys->i_time )
  251.     {
  252.         p_sys->i_time = p_block->i_dts = p_block->i_pts = mdate();
  253.     }
  254.     else
  255.     {
  256.         p_block->i_dts = p_block->i_pts = p_sys->i_time;
  257.         p_sys->i_time += p_sys->i_frame_length;
  258.     }
  259.     /* set PCR */
  260.     es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_block->i_pts );
  261.     es_out_Send( p_demux->out, p_sys->p_es, p_block );
  262.     if( p_sys->b_still )
  263.     {
  264.         p_sys->i_still_end = mdate() + p_sys->i_still_length;
  265.     }
  266.     return 1;
  267. }
  268. /*****************************************************************************
  269.  * Open: check file and initializes structures
  270.  *****************************************************************************/
  271. static int Open( vlc_object_t * p_this )
  272. {
  273.     demux_t     *p_demux = (demux_t*)p_this;
  274.     demux_sys_t *p_sys;
  275.     int         i_size;
  276.     bool        b_matched = false;
  277.     vlc_value_t val;
  278.     p_demux->pf_control = Control;
  279.     p_demux->p_sys      = p_sys = malloc( sizeof( demux_sys_t ) );
  280.     p_sys->p_es         = NULL;
  281.     p_sys->i_time       = 0;
  282.     p_sys->i_level      = 0;
  283.     p_sys->psz_separator = NULL;
  284.     p_sys->i_frame_size_estimate = 15 * 1024;
  285.     b_matched = CheckMimeHeader( p_demux, &i_size);
  286.     if( b_matched )
  287.     {
  288.         p_demux->pf_demux = MimeDemux;
  289.         stream_Read( p_demux->s, NULL, i_size );
  290.     }
  291.     else if( 0 == i_size )
  292.     {
  293.         /* 0xffd8 identify a JPEG SOI */
  294.         if( p_sys->p_peek[0] == 0xFF && p_sys->p_peek[1] == 0xD8 )
  295.         {
  296.             msg_Dbg( p_demux, "JPEG SOI marker detected" );
  297.             p_demux->pf_demux = MjpgDemux;
  298.             p_sys->i_level++;
  299.         }
  300.         else
  301.         {
  302.             goto error;
  303.         }
  304.     }
  305.     else
  306.     {
  307.         goto error;
  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.     /* Check for jpeg file extension */
  313.     p_sys->b_still = false;
  314.     p_sys->i_still_end = 0;
  315.     if( demux_IsPathExtension( p_demux, ".jpeg" ) ||
  316.         demux_IsPathExtension( p_demux, ".jpg" ) )
  317.     {
  318.         p_sys->b_still = true;
  319.         if( val.f_float)
  320.         {
  321.             p_sys->i_still_length = 1000000.0 / val.f_float;
  322.         }
  323.         else
  324.         {
  325.             /* Defaults to 1fps */
  326.             p_sys->i_still_length = 1000000;
  327.         }
  328.     }
  329.     else if ( val.f_float )
  330.     {
  331.         p_sys->i_frame_length = 1000000.0 / val.f_float;
  332.     }
  333.     es_format_Init( &p_sys->fmt, VIDEO_ES, 0 );
  334.     p_sys->fmt.i_codec = VLC_FOURCC('m','j','p','g');
  335.     p_sys->p_es = es_out_Add( p_demux->out, &p_sys->fmt );
  336.     return VLC_SUCCESS;
  337. error:
  338.     free( p_sys );
  339.     return VLC_EGENERIC;
  340. }
  341. /*****************************************************************************
  342.  * Demux: read packet and send them to decoders
  343.  *****************************************************************************
  344.  * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
  345.  *****************************************************************************/
  346. static int MjpgDemux( demux_t *p_demux )
  347. {
  348.     demux_sys_t *p_sys = p_demux->p_sys;
  349.     int i;
  350.     if( p_sys->b_still && p_sys->i_still_end )
  351.     {
  352.         /* Still frame, wait until the pause delay is gone */
  353.         mwait( p_sys->i_still_end );
  354.         p_sys->i_still_end = 0;
  355.         return 1;
  356.     }
  357.     if( !Peek( p_demux, true ) )
  358.     {
  359.         msg_Warn( p_demux, "cannot peek data" );
  360.         return 0;
  361.     }
  362.     if( p_sys->i_data_peeked < 4 )
  363.     {
  364.         msg_Warn( p_demux, "data shortage" );
  365.         return 0;
  366.     }
  367.     i = 3;
  368. FIND_NEXT_EOI:
  369.     while( !( 0xFF == p_sys->p_peek[i-1] && 0xD9 == p_sys->p_peek[i] ) )
  370.     {
  371.         if( 0xFF == p_sys->p_peek[i-1] && 0xD8 == p_sys->p_peek[i] )
  372.         {
  373.             p_sys->i_level++;
  374.             msg_Dbg( p_demux, "we found another JPEG SOI at %d", i );
  375.         }
  376.         i++;
  377.         if( i >= p_sys->i_data_peeked )
  378.         {
  379.             msg_Dbg( p_demux, "did not find JPEG EOI in %d bytes",
  380.                      p_sys->i_data_peeked );
  381.             if( !Peek( p_demux, false ) )
  382.             {
  383.                 msg_Warn( p_demux, "no more data is available at the moment" );
  384.                 return 0;
  385.             }
  386.         }
  387.     }
  388.     i++;
  389.     msg_Dbg( p_demux, "JPEG EOI detected at %d", i );
  390.     p_sys->i_level--;
  391.     if( p_sys->i_level > 0 )
  392.         goto FIND_NEXT_EOI;
  393.     return SendBlock( p_demux, i );
  394. }
  395. static int MimeDemux( demux_t *p_demux )
  396. {
  397.     demux_sys_t *p_sys = p_demux->p_sys;
  398.     int         i_size, i;
  399.     bool  b_match = CheckMimeHeader( p_demux, &i_size );
  400.     if( i_size > 0 )
  401.     {
  402.         stream_Read( p_demux->s, NULL, i_size );
  403.     }
  404.     else if( i_size < 0 )
  405.     {
  406.         return 0;
  407.     }
  408.     else
  409.     {
  410.         // No MIME header, assume OK
  411.         b_match = true;
  412.     }
  413.     if( !Peek( p_demux, true ) )
  414.     {
  415.         msg_Warn( p_demux, "cannot peek data" );
  416.         return 0;
  417.     }
  418.     i = 0;
  419.     i_size = strlen( p_sys->psz_separator ) + 2;
  420.     if( p_sys->i_data_peeked < i_size )
  421.     {
  422.         msg_Warn( p_demux, "data shortage" );
  423.         return 0;
  424.     }
  425.     for( ;; )
  426.     {
  427.         while( !( p_sys->p_peek[i] == '-' && p_sys->p_peek[i+1] == '-' ) )
  428.         {
  429.             i++;
  430.             i_size++;
  431.             if( i_size >= p_sys->i_data_peeked )
  432.             {
  433.                 msg_Dbg( p_demux, "MIME boundary not found in %d bytes of "
  434.                          "data", p_sys->i_data_peeked );
  435.                 if( !Peek( p_demux, false ) )
  436.                 {
  437.                     msg_Warn( p_demux, "no more data is available at the "
  438.                               "moment" );
  439.                     return 0;
  440.                 }
  441.             }
  442.         }
  443.         if( !strncmp( p_sys->psz_separator, (char *)(p_sys->p_peek + i + 2),
  444.                       strlen( p_sys->psz_separator ) ) )
  445.         {
  446.             break;
  447.         }
  448.         i++;
  449.         i_size++;
  450.     }
  451.     if( !b_match )
  452.     {
  453.         msg_Err( p_demux, "discard non-JPEG part" );
  454.         stream_Read( p_demux->s, NULL, i );
  455.         return 0;
  456.     }
  457.     return SendBlock( p_demux, i );
  458. }
  459. /*****************************************************************************
  460.  * Close: frees unused data
  461.  *****************************************************************************/
  462. static void Close ( vlc_object_t * p_this )
  463. {
  464.     demux_t     *p_demux = (demux_t*)p_this;
  465.     demux_sys_t *p_sys  = p_demux->p_sys;
  466.     free( p_sys->psz_separator );
  467.     free( p_sys );
  468. }
  469. /*****************************************************************************
  470.  * Control:
  471.  *****************************************************************************/
  472. static int Control( demux_t *p_demux, int i_query, va_list args )
  473. {
  474.     return demux_vaControlHelper( p_demux->s, 0, 0, 0, 0, i_query, args );
  475. }