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

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * demux.c
  3.  *****************************************************************************
  4.  * Copyright (C) 1999-2004 VideoLAN
  5.  * $Id: demux.c 9152 2004-11-05 12:42:32Z hartman $
  6.  *
  7.  * Author: 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. #include <stdlib.h>
  24. #include <vlc/vlc.h>
  25. #include <vlc/input.h>
  26. #include "input_internal.h"
  27. /*****************************************************************************
  28.  * demux2_New:
  29.  *  if s is NULL then load a access_demux
  30.  *****************************************************************************/
  31. demux_t *__demux2_New( vlc_object_t *p_obj,
  32.                        char *psz_access, char *psz_demux, char *psz_path,
  33.                        stream_t *s, es_out_t *out )
  34. {
  35.     demux_t *p_demux = vlc_object_create( p_obj, VLC_OBJECT_DEMUX );
  36.     char *psz_module;
  37.     if( p_demux == NULL )
  38.     {
  39.         return NULL;
  40.     }
  41.     /* Parse URL */
  42.     p_demux->psz_access = strdup( psz_access );
  43.     p_demux->psz_demux  = strdup( psz_demux );
  44.     p_demux->psz_path   = strdup( psz_path );
  45.     /* Take into account "demux" to be able to do :demux=dump */
  46.     if( *p_demux->psz_demux == '' )
  47.     {
  48.         free( p_demux->psz_demux );
  49.         p_demux->psz_demux = var_GetString( p_obj, "demux" );
  50.     }
  51.     msg_Dbg( p_obj, "demux2_New: access='%s' demux='%s' path='%s'",
  52.              p_demux->psz_access, p_demux->psz_demux, p_demux->psz_path );
  53.     p_demux->s          = s;
  54.     p_demux->out        = out;
  55.     p_demux->pf_demux   = NULL;
  56.     p_demux->pf_control = NULL;
  57.     p_demux->p_sys      = NULL;
  58.     p_demux->info.i_update = 0;
  59.     p_demux->info.i_title  = 0;
  60.     p_demux->info.i_seekpoint = 0;
  61.     if( s )
  62.         psz_module = p_demux->psz_demux;
  63.     else
  64.         psz_module = p_demux->psz_access;
  65.     if( s && *psz_module == '' && strrchr( p_demux->psz_path, '.' ) )
  66.     {
  67.         /* XXX: add only file without any problem here and with strong detection.
  68.          *  - no .mp3, .a52, ... (aac is added as it works only by file ext anyway
  69.          *  - wav can't be added 'cause of a52 and dts in them as raw audio
  70.          */
  71.         static struct { char *ext; char *demux; } exttodemux[] =
  72.         {
  73.             { "aac",  "aac" },
  74.             { "aiff", "aiff" },
  75.             { "asf",  "asf" }, { "wmv",  "asf" }, { "wma",  "asf" },
  76.             { "avi",  "avi" },
  77.             { "au",   "au" },
  78.             { "flac", "flac" },
  79.             { "dv",   "dv" },
  80.             { "m3u",  "m3u" },
  81.             { "mkv",  "mkv" }, { "mka",  "mkv" }, { "mks",  "mkv" },
  82.             { "mp4",  "mp4" }, { "m4a",  "mp4" }, { "mov",  "mp4" }, { "moov", "mp4" },
  83.             { "mod",  "mod" }, { "xm",   "mod" },
  84.             { "nsv",  "nsv" },
  85.             { "ogg",  "ogg" }, { "ogm",  "ogg" },
  86.             { "pva",  "pva" },
  87.             { "rm",   "rm" },
  88.             { NULL,  NULL },
  89.         };
  90.         char *psz_ext = strrchr( p_demux->psz_path, '.' ) + 1;
  91.         int  i;
  92.         for( i = 0; exttodemux[i].ext != NULL; i++ )
  93.         {
  94.             if( !strcasecmp( psz_ext, exttodemux[i].ext ) )
  95.             {
  96.                 psz_module = exttodemux[i].demux;
  97.                 break;
  98.             }
  99.         }
  100.     }
  101.     /* Before module_Need (for var_Create...) */
  102.     vlc_object_attach( p_demux, p_obj );
  103.     if( s )
  104.     {
  105.         p_demux->p_module =
  106.             module_Need( p_demux, "demux2", psz_module,
  107.                          !strcmp( psz_module, p_demux->psz_demux ) ?
  108.                          VLC_TRUE : VLC_FALSE );
  109.     }
  110.     else
  111.     {
  112.         p_demux->p_module =
  113.             module_Need( p_demux, "access_demux", psz_module,
  114.                          !strcmp( psz_module, p_demux->psz_access ) ?
  115.                          VLC_TRUE : VLC_FALSE );
  116.     }
  117.     if( p_demux->p_module == NULL )
  118.     {
  119.         vlc_object_detach( p_demux );
  120.         free( p_demux->psz_path );
  121.         free( p_demux->psz_demux );
  122.         free( p_demux->psz_access );
  123.         vlc_object_destroy( p_demux );
  124.         return NULL;
  125.     }
  126.     return p_demux;
  127. }
  128. /*****************************************************************************
  129.  * demux2_Delete:
  130.  *****************************************************************************/
  131. void demux2_Delete( demux_t *p_demux )
  132. {
  133.     module_Unneed( p_demux, p_demux->p_module );
  134.     vlc_object_detach( p_demux );
  135.     free( p_demux->psz_path );
  136.     free( p_demux->psz_demux );
  137.     free( p_demux->psz_access );
  138.     vlc_object_destroy( p_demux );
  139. }
  140. /*****************************************************************************
  141.  * demux2_vaControlHelper:
  142.  *****************************************************************************/
  143. int demux2_vaControlHelper( stream_t *s,
  144.                             int64_t i_start, int64_t i_end,
  145.                             int i_bitrate, int i_align,
  146.                             int i_query, va_list args )
  147. {
  148.     int64_t i_tell;
  149.     double  f, *pf;
  150.     int64_t i64, *pi64;
  151.     if( i_end < 0 )    i_end   = stream_Size( s );
  152.     if( i_start < 0 )  i_start = 0;
  153.     if( i_align <= 0 ) i_align = 1;
  154.     i_tell = stream_Tell( s );
  155.     switch( i_query )
  156.     {
  157.         case DEMUX_GET_LENGTH:
  158.             pi64 = (int64_t*)va_arg( args, int64_t * );
  159.             if( i_bitrate > 0 && i_end > i_start )
  160.             {
  161.                 *pi64 = I64C(8000000) * (i_end - i_start) / i_bitrate;
  162.                 return VLC_SUCCESS;
  163.             }
  164.             return VLC_EGENERIC;
  165.         case DEMUX_GET_TIME:
  166.             pi64 = (int64_t*)va_arg( args, int64_t * );
  167.             if( i_bitrate > 0 && i_end > i_start )
  168.             {
  169.                 *pi64 = I64C(8000000) * (i_tell - i_start) / i_bitrate;
  170.                 return VLC_SUCCESS;
  171.             }
  172.             return VLC_EGENERIC;
  173.         case DEMUX_GET_POSITION:
  174.             pf = (double*)va_arg( args, double * );
  175.             if( i_start < i_end )
  176.             {
  177.                 *pf = (double)( i_tell - i_start ) /
  178.                       (double)( i_end  - i_start );
  179.                 return VLC_SUCCESS;
  180.             }
  181.             return VLC_EGENERIC;
  182.         case DEMUX_SET_POSITION:
  183.             f = (double)va_arg( args, double );
  184.             if( i_start < i_end && f >= 0.0 && f <= 1.0 )
  185.             {
  186.                 int64_t i_block = (f * ( i_end - i_start )) / i_align;
  187.                 if( stream_Seek( s, i_start + i_block * i_align ) )
  188.                 {
  189.                     return VLC_EGENERIC;
  190.                 }
  191.                 return VLC_SUCCESS;
  192.             }
  193.             return VLC_EGENERIC;
  194.         case DEMUX_SET_TIME:
  195.             i64 = (int64_t)va_arg( args, int64_t );
  196.             if( i_bitrate > 0 && i64 >= 0 )
  197.             {
  198.                 int64_t i_block = i64 * i_bitrate / I64C(8000000) / i_align;
  199.                 if( stream_Seek( s, i_start + i_block * i_align ) )
  200.                 {
  201.                     return VLC_EGENERIC;
  202.                 }
  203.                 return VLC_SUCCESS;
  204.             }
  205.             return VLC_EGENERIC;
  206.         case DEMUX_GET_FPS:
  207.         case DEMUX_GET_META:
  208.         case DEMUX_SET_NEXT_DEMUX_TIME:
  209.         case DEMUX_GET_TITLE_INFO:
  210.         case DEMUX_SET_GROUP:
  211.             return VLC_EGENERIC;
  212.         default:
  213.             msg_Err( s, "unknown query in demux_vaControlDefault" );
  214.             return VLC_EGENERIC;
  215.     }
  216. }
  217. /****************************************************************************
  218.  * stream_Demux*: create a demuxer for an outpout stream (allow demuxer chain)
  219.  ****************************************************************************/
  220. typedef struct
  221. {
  222.     /* Data buffer */
  223.     block_fifo_t *p_fifo;
  224.     block_t      *p_block;
  225.     int64_t     i_pos;
  226.     /* Demuxer */
  227.     char        *psz_name;
  228.     es_out_t    *out;
  229.     demux_t     *p_demux;
  230. } d_stream_sys_t;
  231. static int DStreamRead   ( stream_t *, void *p_read, int i_read );
  232. static int DStreamPeek   ( stream_t *, uint8_t **pp_peek, int i_peek );
  233. static int DStreamControl( stream_t *, int i_query, va_list );
  234. static int DStreamThread ( stream_t * );
  235. stream_t *__stream_DemuxNew( vlc_object_t *p_obj, char *psz_demux,
  236.                              es_out_t *out )
  237. {
  238.     /* We create a stream reader, and launch a thread */
  239.     stream_t       *s;
  240.     d_stream_sys_t *p_sys;
  241.     if( psz_demux == NULL || *psz_demux == '' ) return NULL;
  242.     s = vlc_object_create( p_obj, VLC_OBJECT_STREAM );
  243.     s->pf_block  = NULL;
  244.     s->pf_read   = DStreamRead;
  245.     s->pf_peek   = DStreamPeek;
  246.     s->pf_control= DStreamControl;
  247.     s->p_sys = malloc( sizeof( d_stream_sys_t) );
  248.     p_sys = (d_stream_sys_t*)s->p_sys;
  249.     p_sys->i_pos = 0;
  250.     p_sys->out = out;
  251.     p_sys->p_demux = NULL;
  252.     p_sys->p_block = NULL;
  253.     p_sys->psz_name = strdup( psz_demux );
  254.     /* decoder fifo */
  255.     if( ( p_sys->p_fifo = block_FifoNew( s ) ) == NULL )
  256.     {
  257.         msg_Err( s, "out of memory" );
  258.         vlc_object_destroy( s );
  259.         free( p_sys );
  260.         return NULL;
  261.     }
  262.     if( vlc_thread_create( s, "stream out", DStreamThread,
  263.                            VLC_THREAD_PRIORITY_INPUT, VLC_FALSE ) )
  264.     {
  265.         vlc_object_destroy( s );
  266.         free( p_sys );
  267.         return NULL;
  268.     }
  269.     return s;
  270. }
  271. void stream_DemuxSend( stream_t *s, block_t *p_block )
  272. {
  273.     d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
  274.     if( p_block ) block_FifoPut( p_sys->p_fifo, p_block );
  275. }
  276. void stream_DemuxDelete( stream_t *s )
  277. {
  278.     d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
  279.     block_t *p_empty;
  280.     s->b_die = VLC_TRUE;
  281.     if( p_sys->p_demux ) p_sys->p_demux->b_die = VLC_TRUE;
  282.     p_empty = block_New( s, 1 ); p_empty->i_buffer = 0;
  283.     block_FifoPut( p_sys->p_fifo, p_empty );
  284.     vlc_thread_join( s );
  285.     if( p_sys->p_demux ) demux2_Delete( p_sys->p_demux );
  286.     if( p_sys->p_block ) block_Release( p_sys->p_block );
  287.     block_FifoRelease( p_sys->p_fifo );
  288.     free( p_sys->psz_name );
  289.     free( p_sys );
  290.     vlc_object_destroy( s );
  291. }
  292. static int DStreamRead( stream_t *s, void *p_read, int i_read )
  293. {
  294.     d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
  295.     uint8_t *p_out = p_read;
  296.     int i_out = 0;
  297.     //msg_Dbg( s, "DStreamRead: wanted %d bytes", i_read );
  298.     while( !s->b_die && !s->b_error && i_read )
  299.     {
  300.         block_t *p_block = p_sys->p_block;
  301.         int i_copy;
  302.         if( !p_block )
  303.         {
  304.             p_block = block_FifoGet( p_sys->p_fifo );
  305.             if( !p_block ) s->b_error = 1;
  306.             p_sys->p_block = p_block;
  307.         }
  308.         if( p_block && i_read )
  309.         {
  310.             i_copy = __MIN( i_read, p_block->i_buffer );
  311.             if( p_out && i_copy ) memcpy( p_out, p_block->p_buffer, i_copy );
  312.             i_read -= i_copy;
  313.             i_out += i_copy;
  314.             p_block->i_buffer -= i_copy;
  315.             p_block->p_buffer += i_copy;
  316.             if( !p_block->i_buffer )
  317.             {
  318.                 block_Release( p_block );
  319.                 p_sys->p_block = NULL;
  320.             }
  321.         }
  322.     }
  323.     p_sys->i_pos += i_out;
  324.     return i_out;
  325. }
  326. static int DStreamPeek( stream_t *s, uint8_t **pp_peek, int i_peek )
  327. {
  328.     d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
  329.     block_t **pp_block = &p_sys->p_block;
  330.     int i_out = 0;
  331.     *pp_peek = 0;
  332.     //msg_Dbg( s, "DStreamPeek: wanted %d bytes", i_peek );
  333.     while( !s->b_die && !s->b_error && i_peek )
  334.     {
  335.         int i_copy;
  336.         if( !*pp_block )
  337.         {
  338.             *pp_block = block_FifoGet( p_sys->p_fifo );
  339.             if( !*pp_block ) s->b_error = 1;
  340.         }
  341.         if( *pp_block && i_peek )
  342.         {
  343.             i_copy = __MIN( i_peek, (*pp_block)->i_buffer );
  344.             i_peek -= i_copy;
  345.             i_out += i_copy;
  346.             if( i_peek ) pp_block = &(*pp_block)->p_next;
  347.         }
  348.     }
  349.     if( p_sys->p_block )
  350.     {
  351.         p_sys->p_block = block_ChainGather( p_sys->p_block );
  352.         *pp_peek = p_sys->p_block->p_buffer;
  353.     }
  354.     return i_out;
  355. }
  356. static int DStreamControl( stream_t *s, int i_query, va_list args )
  357. {
  358.     d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
  359.     int64_t    *p_i64;
  360.     vlc_bool_t *p_b;
  361.     int        *p_int;
  362.     switch( i_query )
  363.     {
  364.         case STREAM_GET_SIZE:
  365.             p_i64 = (int64_t*) va_arg( args, int64_t * );
  366.             *p_i64 = 0;
  367.             return VLC_SUCCESS;
  368.         case STREAM_CAN_SEEK:
  369.             p_b = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
  370.             *p_b = VLC_FALSE;
  371.             return VLC_SUCCESS;
  372.         case STREAM_CAN_FASTSEEK:
  373.             p_b = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
  374.             *p_b = VLC_FALSE;
  375.             return VLC_SUCCESS;
  376.         case STREAM_GET_POSITION:
  377.             p_i64 = (int64_t*) va_arg( args, int64_t * );
  378.             *p_i64 = p_sys->i_pos;
  379.             return VLC_SUCCESS;
  380.         case STREAM_SET_POSITION:
  381.         {
  382.             int64_t i64 = (int64_t)va_arg( args, int64_t );
  383.             int i_skip;
  384.             if( i64 < p_sys->i_pos ) return VLC_EGENERIC;
  385.             i_skip = i64 - p_sys->i_pos;
  386.             while( i_skip > 0 )
  387.             {
  388.                 int i_read = DStreamRead( s, NULL, i_skip );
  389.                 if( i_read <= 0 ) return VLC_EGENERIC;
  390.                 i_skip -= i_read;
  391.             }
  392.             return VLC_SUCCESS;
  393.         }
  394.         case STREAM_GET_MTU:
  395.             p_int = (int*) va_arg( args, int * );
  396.             *p_int = 0;
  397.             return VLC_SUCCESS;
  398.         case STREAM_CONTROL_ACCESS:
  399.             return VLC_EGENERIC;
  400.         default:
  401.             msg_Err( s, "invalid DStreamControl query=0x%x", i_query );
  402.             return VLC_EGENERIC;
  403.     }
  404. }
  405. static int DStreamThread( stream_t *s )
  406. {
  407.     d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
  408.     demux_t *p_demux;
  409.     /* Create the demuxer */
  410.     if( !(p_demux = demux2_New( s, "", p_sys->psz_name, "", s, p_sys->out )) )
  411.     {
  412.         return VLC_EGENERIC;
  413.     }
  414.     p_sys->p_demux = p_demux;
  415.     /* Main loop */
  416.     while( !s->b_die && !p_demux->b_die )
  417.     {
  418.         if( p_demux->pf_demux( p_demux ) <= 0 ) break;
  419.     }
  420.     p_demux->b_die = VLC_TRUE;
  421.     return VLC_SUCCESS;
  422. }