From 4dec9682f6b5b0b6ed2d5187f4652cb680f39000 Mon Sep 17 00:00:00 2001 From: Laurent Aimar Date: Sun, 13 Apr 2003 20:00:21 +0000 Subject: [PATCH] * all: new sout scheme. Now a chain of module are created that can modify/apply on all streams, --sout has the same behavour expect when starting with a '#'. With a starting '#' you can specify a chain of modules, it's still unstable but a lot more powerfull. You have access to duplicate(that duplicate all stream), transcode (using only ffmpeg), standard/std and es (that apply muxers and access), and display. You could chain them with ':' and specify options with {option1=value,option2=value[,...]}. ex: * to stream and see the stream to udp/ts:ip --sout '#duplicate{dst=display,dst=std{access=udp,mux=ts,url=ip}}' * to transcode,see and stream --sout '#transcode{acodec=mpga}:duplicate{dst=display,dst=std{access=udp,mux=ts,url=ip}}' Without a starting '#', the url is converted into '#std{acces=,mux=,url}' Test and report bugs :) --- configure.ac.in | 19 +- include/input_ext-intf.h | 5 +- include/stream_output.h | 176 ++++- include/vlc_common.h | 8 +- modules/Makefile.am | 1 + modules/mux/avi.c | 138 ++-- modules/mux/mpeg/ps.c | 8 +- modules/mux/mpeg/ts.c | 49 +- modules/mux/ogg.c | 59 +- modules/packetizer/a52.c | 25 +- modules/packetizer/copy.c | 86 ++- modules/packetizer/mpeg4audio.c | 28 +- modules/packetizer/mpeg4video.c | 62 +- modules/packetizer/mpegaudio.c | 27 +- modules/packetizer/mpegvideo.c | 51 +- modules/stream_out/Modules.am | 6 + modules/stream_out/display.c | 285 ++++++++ modules/stream_out/dummy.c | 116 ++++ modules/stream_out/duplicate.c | 211 ++++++ modules/stream_out/es.c | 326 ++++++++++ modules/stream_out/standard.c | 174 +++++ modules/stream_out/transcode.c | 940 +++++++++++++++++++++++++++ src/input/input_dec.c | 48 +- src/input/input_programs.c | 3 +- src/stream_output/stream_output.c | 1004 ++++++++++++----------------- 25 files changed, 2958 insertions(+), 897 deletions(-) create mode 100644 modules/stream_out/Modules.am create mode 100644 modules/stream_out/display.c create mode 100644 modules/stream_out/dummy.c create mode 100644 modules/stream_out/duplicate.c create mode 100644 modules/stream_out/es.c create mode 100644 modules/stream_out/standard.c create mode 100644 modules/stream_out/transcode.c diff --git a/configure.ac.in b/configure.ac.in index 3c2944cb56..d8f050ec16 100644 --- a/configure.ac.in +++ b/configure.ac.in @@ -334,6 +334,7 @@ AC_CHECK_LIB(m,cos, LDFLAGS_a52tofloat32="${LDFLAGS_a52tofloat32} -lm") AC_CHECK_LIB(m,pow, LDFLAGS_ffmpeg="${LDFLAGS_ffmpeg} -lm" + LDFLAGS_stream_out_transcode="${LDFLAGS_stream_out_transcode} -lm" LDFLAGS_imdct="${LDFLAGS_imdct} -lm" LDFLAGS_imdct3dn="${LDFLAGS_imdct3dn} -lm" LDFLAGS_imdctsse="${LDFLAGS_imdctsse} -lm" @@ -1017,7 +1018,8 @@ then PLUGINS="${PLUGINS} packetizer_mpeg4video packetizer_mpeg4audio" PLUGINS="${PLUGINS} packetizer_copy" - PLUGINS="${PLUGINS} vout_encoder" + PLUGINS="${PLUGINS} stream_out_dummy stream_out_standard stream_out_es" + PLUGINS="${PLUGINS} stream_out_duplicate stream_out_display" dnl Ogg/ogm AC_CHECK_HEADERS(ogg/ogg.h, [ @@ -1510,6 +1512,10 @@ then then CPPFLAGS_ffmpeg="${CPPFLAGS_ffmpeg} -I${with_ffmpeg}/include/ffmpeg" LDFLAGS_ffmpeg="${LDFLAGS_ffmpeg} -L${with_ffmpeg}/lib" + + CPPFLAGS_stream_out_transcode="${CPPFLAGS_stream_out_transcode} -I${with_ffmpeg}/include/ffmpeg" + LDFLAGS_stream_out_transcode="${LDFLAGS_stream_out_transcode} -L${with_ffmpeg}/lib" + fi dnl Add postprocessing modules @@ -1538,9 +1544,13 @@ then then dnl Use a custom libffmpeg AC_MSG_RESULT(${real_ffmpeg_tree}/libavcodec/libavcodec.a) - BUILTINS="${BUILTINS} ffmpeg" + BUILTINS="${BUILTINS} ffmpeg stream_out_transcode" LDFLAGS_ffmpeg="${LDFLAGS_ffmpeg} -L${real_ffmpeg_tree}/libavcodec -lavcodec" CPPFLAGS_ffmpeg="${CPPFLAGS_ffmpeg} -I${real_ffmpeg_tree}/libavcodec" + + LDFLAGS_stream_out_transcode="${LDFLAGS_stream_out_transcode} -L${real_ffmpeg_tree}/libavcodec -lavcodec" + CPPFLAGS_stream_out_transcode="${CPPFLAGS_stream_out_transcode} -I${real_ffmpeg_tree}/libavcodec" + else dnl The given libavcodec wasn't built AC_MSG_RESULT(no) @@ -1550,8 +1560,9 @@ then CPPFLAGS="${CPPFLAGS_save} ${CPPFLAGS_ffmpeg}" LDFLAGS="${LDFLAGS_save} ${LDFLAGS_ffmpeg}" AC_CHECK_LIB(avcodec, avcodec_init, [ - BUILTINS="${BUILTINS} ffmpeg" - LDFLAGS_ffmpeg="${LDFLAGS_ffmpeg} -lavcodec" ], + BUILTINS="${BUILTINS} ffmpeg stream_out_transcode" + LDFLAGS_ffmpeg="${LDFLAGS_ffmpeg} -lavcodec" + LDFLAGS_stream_out_transcode="${LDFLAGS_stream_out_transcode} -lavcodec" ], [ AC_MSG_ERROR([Cannot find libavcodec library...]) ]) LDFLAGS="${LDFLAGS_save}" CPPFLAGS="${CPPFLAGS_save}" diff --git a/include/input_ext-intf.h b/include/input_ext-intf.h index fa6acdbd1b..6b382fe4b9 100644 --- a/include/input_ext-intf.h +++ b/include/input_ext-intf.h @@ -4,7 +4,7 @@ * control the pace of reading. ***************************************************************************** * Copyright (C) 1999, 2000 VideoLAN - * $Id: input_ext-intf.h,v 1.87 2003/03/24 17:15:29 gbazin Exp $ + * $Id: input_ext-intf.h,v 1.88 2003/04/13 20:00:20 fenrir Exp $ * * Authors: Christophe Massiot * @@ -71,6 +71,9 @@ struct es_descriptor_t count_t c_packets; /* total packets read */ count_t c_invalid_packets; /* invalid packets read */ + + /* XXX hack: to force a decoder instead of mode based on sout */ + vlc_bool_t b_force_decoder; }; /* Special PID values - note that the PID is only on 13 bits, and that values diff --git a/include/stream_output.h b/include/stream_output.h index 91427b2166..56ac3f3eaf 100644 --- a/include/stream_output.h +++ b/include/stream_output.h @@ -2,7 +2,7 @@ * stream_output.h : stream output module ***************************************************************************** * Copyright (C) 2002 VideoLAN - * $Id: stream_output.h,v 1.9 2003/03/11 19:02:30 fenrir Exp $ + * $Id: stream_output.h,v 1.10 2003/04/13 20:00:20 fenrir Exp $ * * Authors: Christophe Massiot * Laurent Aimar @@ -57,12 +57,24 @@ struct sout_buffer_t struct sout_buffer_t *p_next; }; -struct sout_packet_format_t +struct sout_format_t { - int i_cat; // AUDIO_ES, VIDEO_ES, SPU_ES + int i_cat; vlc_fourcc_t i_fourcc; - void *p_format; // WAVEFORMATEX or BITMAPINFOHEADER + /* audio */ + int i_sample_rate; + int i_channels; + int i_block_align; + + /* video */ + int i_width; + int i_height; + + int i_bitrate; + int i_extra_data; + uint8_t *p_extra_data; + }; struct sout_fifo_t @@ -75,39 +87,36 @@ struct sout_fifo_t sout_buffer_t **pp_last; }; +typedef struct sout_stream_id_t sout_stream_id_t; + /* for mux */ struct sout_input_t { -// vlc_mutex_t lock; - - sout_instance_t *p_sout; + sout_instance_t *p_sout; - sout_packet_format_t input_format; - sout_fifo_t *p_fifo; + sout_format_t *p_fmt; + sout_fifo_t *p_fifo; - void *p_sys; + void *p_sys; }; -/* for packetizr */ +/* for packetizer */ struct sout_packetizer_input_t { - sout_instance_t *p_sout; - sout_packet_format_t input_format; - -// vlc_mutex_t lock; - int i_nb_inputs; - sout_input_t **pp_inputs; + sout_instance_t *p_sout; - int i_nb_mux; // not really used, just usefull with TAB_* - sout_mux_t **pp_mux; + sout_format_t *p_fmt; + sout_stream_id_t *id; }; + #define SOUT_METHOD_NONE 0x00 #define SOUT_METHOD_FILE 0x10 #define SOUT_METHOD_NETWORK 0x20 +typedef struct sout_access_out_sys_t sout_access_out_sys_t; struct sout_access_out_t { VLC_COMMON_MEMBERS @@ -180,36 +189,129 @@ struct sout_mux_t mtime_t i_add_stream_start; }; + + +struct sout_cfg_t +{ + sout_cfg_t *p_next; + + char *psz_name; + char *psz_value; +}; + +typedef struct sout_stream_sys_t sout_stream_sys_t; +struct sout_stream_t +{ + VLC_COMMON_MEMBERS + + module_t *p_module; + sout_instance_t *p_sout; + + char *psz_name; + sout_cfg_t *p_cfg; + char *psz_next; + + /* add, remove a stream */ + sout_stream_id_t * (*pf_add) ( sout_stream_t *, sout_format_t * ); + int (*pf_del) ( sout_stream_t *, sout_stream_id_t * ); + + /* manage a packet */ + int (*pf_send)( sout_stream_t *, sout_stream_id_t *, sout_buffer_t* ); + + /* private */ + sout_stream_sys_t *p_sys; +}; + typedef struct sout_instance_sys_t sout_instance_sys_t; struct sout_instance_t { VLC_COMMON_MEMBERS - /* complete sout string like udp/ts:239.255.12.42#file/ps://essai.ps */ char * psz_sout; - - /* here are stored the parsed psz_sout */ - int i_nb_dest; - char **ppsz_dest; + char * psz_chain; /* muxer data */ int i_preheader; /* max over all muxer */ - int i_nb_mux; - sout_mux_t **pp_mux; - - /* here are all packetizer inputs accepted by at least one muxer */ vlc_mutex_t lock; - int i_nb_inputs; - sout_packetizer_input_t **pp_inputs; + sout_stream_t *p_stream; /* sout private */ sout_instance_sys_t *p_sys; }; +/* some macro */ +#define TAB_APPEND( count, tab, p ) \ + if( (count) > 0 ) \ + { \ + (tab) = realloc( (tab), sizeof( void ** ) * ( (count) + 1 ) ); \ + } \ + else \ + { \ + (tab) = malloc( sizeof( void ** ) ); \ + } \ + (void**)(tab)[(count)] = (void*)(p); \ + (count)++ + +#define TAB_FIND( count, tab, p, index ) \ + { \ + int _i_; \ + (index) = -1; \ + for( _i_ = 0; _i_ < (count); _i_++ ) \ + { \ + if((void**)(tab)[_i_]==(void*)(p)) \ + { \ + (index) = _i_; \ + break; \ + } \ + } \ + } + +#define TAB_REMOVE( count, tab, p ) \ + { \ + int i_index; \ + TAB_FIND( count, tab, p, i_index ); \ + if( i_index >= 0 ) \ + { \ + if( count > 1 ) \ + { \ + memmove( ((void**)tab + i_index), \ + ((void**)tab + i_index+1), \ + ( (count) - i_index - 1 ) * sizeof( void* ) );\ + } \ + else \ + { \ + free( tab ); \ + (tab) = NULL; \ + } \ + (count)--; \ + } \ + } + +static inline sout_cfg_t *sout_cfg_find( sout_cfg_t *p_cfg, char *psz_name ) +{ + while( p_cfg && strcmp( p_cfg->psz_name, psz_name ) ) + { + p_cfg = p_cfg->p_next; + } + return p_cfg; +} - +static inline char *sout_cfg_find_value( sout_cfg_t *p_cfg, char *psz_name ) +{ + while( p_cfg && strcmp( p_cfg->psz_name, psz_name ) ) + { + p_cfg = p_cfg->p_next; + } + + if( p_cfg && p_cfg->psz_value ) + { + return( p_cfg->psz_value ); + } + + return NULL; +} /***************************************************************************** * Prototypes *****************************************************************************/ @@ -227,7 +329,7 @@ VLC_EXPORT( sout_buffer_t *, sout_FifoShow, ( sout_fifo_t * ) ); #define sout_InputNew( a, b ) __sout_InputNew( VLC_OBJECT(a), b ) -VLC_EXPORT( sout_packetizer_input_t *, __sout_InputNew, ( vlc_object_t *, sout_packet_format_t * ) ); +VLC_EXPORT( sout_packetizer_input_t *, __sout_InputNew, ( vlc_object_t *, sout_format_t * ) ); VLC_EXPORT( int, sout_InputDelete, ( sout_packetizer_input_t * ) ); VLC_EXPORT( int, sout_InputSendBuffer, ( sout_packetizer_input_t *, sout_buffer_t* ) ); @@ -243,3 +345,13 @@ VLC_EXPORT( void, sout_AccessOutDelete, ( sout_access_out_t * ) ) VLC_EXPORT( int, sout_AccessOutSeek, ( sout_access_out_t *, off_t ) ); VLC_EXPORT( int, sout_AccessOutWrite, ( sout_access_out_t *, sout_buffer_t * ) ); +VLC_EXPORT( sout_mux_t *, sout_MuxNew, ( sout_instance_t*, char *, sout_access_out_t * ) ); +VLC_EXPORT( sout_input_t *, sout_MuxAddStream, ( sout_mux_t *, sout_format_t * ) ); +VLC_EXPORT( void, sout_MuxDeleteStream, ( sout_mux_t *, sout_input_t * ) ); +VLC_EXPORT( void, sout_MuxDelete, ( sout_mux_t * ) ); +VLC_EXPORT( void, sout_MuxSendBuffer, ( sout_mux_t *, sout_input_t *, sout_buffer_t * ) ); + +VLC_EXPORT( char *, sout_cfg_parser, ( char **, sout_cfg_t **, char * ) ); +VLC_EXPORT( sout_stream_t *, sout_stream_new, ( sout_instance_t *, char *psz_chain ) ); +VLC_EXPORT( void, sout_stream_delete, ( sout_stream_t *p_stream ) ); + diff --git a/include/vlc_common.h b/include/vlc_common.h index 457b7ffa87..7ae22b179f 100644 --- a/include/vlc_common.h +++ b/include/vlc_common.h @@ -3,7 +3,7 @@ * Collection of useful common types and macros definitions ***************************************************************************** * Copyright (C) 1998, 1999, 2000 VideoLAN - * $Id: vlc_common.h,v 1.59 2003/03/17 18:02:11 sam Exp $ + * $Id: vlc_common.h,v 1.60 2003/04/13 20:00:20 fenrir Exp $ * * Authors: Samuel Hocevar * Vincent Seguin @@ -249,11 +249,11 @@ typedef struct sout_fifo_t sout_fifo_t; typedef struct sout_input_t sout_input_t; typedef struct sout_packetizer_input_t sout_packetizer_input_t; typedef struct sout_buffer_t sout_buffer_t; -typedef struct sout_packet_format_t sout_packet_format_t; typedef struct sout_access_out_t sout_access_out_t; typedef struct sout_mux_t sout_mux_t; -typedef struct sout_access_out_sys_t sout_access_out_sys_t; - +typedef struct sout_stream_t sout_stream_t; +typedef struct sout_cfg_t sout_cfg_t; +typedef struct sout_format_t sout_format_t; /* Decoders */ typedef struct decoder_fifo_t decoder_fifo_t; diff --git a/modules/Makefile.am b/modules/Makefile.am index 0f70f23566..03c2ca167c 100644 --- a/modules/Makefile.am +++ b/modules/Makefile.am @@ -62,6 +62,7 @@ EXTRA_DIST = \ mux/Modules.am \ mux/mpeg/Modules.am \ packetizer/Modules.am \ + stream_out/Modules.am \ video_chroma/Modules.am \ video_filter/Modules.am \ video_filter/deinterlace/Modules.am \ diff --git a/modules/mux/avi.c b/modules/mux/avi.c index 03f1b589fa..5593e794e9 100644 --- a/modules/mux/avi.c +++ b/modules/mux/avi.c @@ -2,7 +2,7 @@ * avi.c ***************************************************************************** * Copyright (C) 2001, 2002 VideoLAN - * $Id: avi.c,v 1.11 2003/03/31 03:46:11 fenrir Exp $ + * $Id: avi.c,v 1.12 2003/04/13 20:00:21 fenrir Exp $ * * Authors: Laurent Aimar * @@ -231,12 +231,12 @@ static void Close( vlc_object_t * p_this ) (uint64_t)p_stream->i_totalsize / (uint64_t)p_stream->i_duration; } - msg_Err( p_mux, "stream[%d] duration:%lld totalsize:%lld frames:%d fps:%f kb/s:%d", - i_stream, - (int64_t)p_stream->i_duration / (int64_t)1000000, - p_stream->i_totalsize, - p_stream->i_frames, - p_stream->f_fps, p_stream->i_bitrate/1024 ); + msg_Info( p_mux, "stream[%d] duration:%lld totalsize:%lld frames:%d fps:%f kb/s:%d", + i_stream, + (int64_t)p_stream->i_duration / (int64_t)1000000, + p_stream->i_totalsize, + p_stream->i_frames, + p_stream->f_fps, p_stream->i_bitrate/1024 ); } p_hdr = avi_HeaderCreateRIFF( p_mux ); @@ -266,11 +266,6 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input ) msg_Err( p_mux, "too many streams" ); return( -1 ); } - if( p_input->input_format.p_format == NULL ) - { - msg_Err( p_mux, "stream descriptor missing" ); - return( -1 ); - } msg_Dbg( p_mux, "adding input" ); p_input->p_sys = malloc( sizeof( int ) ); @@ -278,49 +273,96 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input ) *((int*)p_input->p_sys) = p_sys->i_streams; p_stream = &p_sys->stream[p_sys->i_streams]; - switch( p_input->input_format.i_cat ) + switch( p_input->p_fmt->i_cat ) { case AUDIO_ES: + p_stream->i_cat = AUDIO_ES; + p_stream->fcc[0] = '0' + p_sys->i_streams / 10; + p_stream->fcc[1] = '0' + p_sys->i_streams % 10; + p_stream->fcc[2] = 'w'; + p_stream->fcc[3] = 'b'; + + p_stream->p_bih = NULL; + + p_stream->p_wf = malloc( sizeof( WAVEFORMATEX ) + p_input->p_fmt->i_extra_data ); +#define p_wf p_stream->p_wf + p_wf->cbSize = p_input->p_fmt->i_extra_data; + if( p_wf->cbSize > 0 ) + { + memcpy( &p_wf[1], + p_input->p_fmt->p_extra_data, + p_input->p_fmt->i_extra_data ); + } + p_wf->nChannels = p_input->p_fmt->i_channels; + p_wf->nSamplesPerSec = p_input->p_fmt->i_sample_rate; + p_wf->nBlockAlign = p_input->p_fmt->i_block_align; + p_wf->nAvgBytesPerSec= p_input->p_fmt->i_bitrate / 8; + p_wf->wBitsPerSample = 0; + + switch( p_input->p_fmt->i_fourcc ) { - WAVEFORMATEX *p_wf = - (WAVEFORMATEX*)p_input->input_format.p_format; - - p_stream->i_cat = AUDIO_ES; - p_stream->fcc[0] = '0' + p_sys->i_streams / 10; - p_stream->fcc[1] = '0' + p_sys->i_streams % 10; - p_stream->fcc[2] = 'w'; - p_stream->fcc[3] = 'b'; - - p_stream->p_bih = NULL; - p_stream->p_wf = malloc( sizeof( WAVEFORMATEX ) + p_wf->cbSize ); - memcpy( p_stream->p_wf, - p_wf, - sizeof( WAVEFORMATEX ) + p_wf->cbSize); + case VLC_FOURCC( 'a', '5', '2', ' ' ): + p_wf->wFormatTag = WAVE_FORMAT_A52; + break; + case VLC_FOURCC( 'm', 'p', 'g', 'a' ): + p_wf->wFormatTag = WAVE_FORMAT_MPEGLAYER3; + break; + case VLC_FOURCC( 'w', 'm', 'a', '1' ): + p_wf->wFormatTag = WAVE_FORMAT_WMA1; + break; + case VLC_FOURCC( 'w', 'm', 'a', '2' ): + p_wf->wFormatTag = WAVE_FORMAT_WMA2; + break; + case VLC_FOURCC( 'w', 'm', 'a', '3' ): + p_wf->wFormatTag = WAVE_FORMAT_WMA3; + break; + default: + return VLC_EGENERIC; } +#undef p_wf break; case VIDEO_ES: + p_stream->i_cat = VIDEO_ES; + p_stream->fcc[0] = '0' + p_sys->i_streams / 10; + p_stream->fcc[1] = '0' + p_sys->i_streams % 10; + p_stream->fcc[2] = 'd'; + p_stream->fcc[3] = 'c'; + if( p_sys->i_stream_video < 0 ) { - BITMAPINFOHEADER *p_bih = - (BITMAPINFOHEADER*)p_input->input_format.p_format;; - - p_stream->i_cat = VIDEO_ES; - p_stream->fcc[0] = '0' + p_sys->i_streams / 10; - p_stream->fcc[1] = '0' + p_sys->i_streams % 10; - p_stream->fcc[2] = 'd'; - p_stream->fcc[3] = 'c'; - if( p_sys->i_stream_video < 0 ) - { - p_sys->i_stream_video = p_sys->i_streams; - } - p_stream->p_wf = NULL; - p_stream->p_bih = malloc( p_bih->biSize ); - memcpy( p_stream->p_bih, - p_bih, - p_bih->biSize ); + p_sys->i_stream_video = p_sys->i_streams; } + p_stream->p_wf = NULL; + p_stream->p_bih = malloc( sizeof( BITMAPINFOHEADER ) + p_input->p_fmt->i_extra_data ); +#define p_bih p_stream->p_bih + p_bih->biSize = sizeof( BITMAPINFOHEADER ) + p_input->p_fmt->i_extra_data; + if( p_input->p_fmt->i_extra_data > 0 ) + { + memcpy( &p_bih[1], + p_input->p_fmt->p_extra_data, + p_input->p_fmt->i_extra_data ); + } + p_bih->biWidth = p_input->p_fmt->i_width; + p_bih->biHeight= p_input->p_fmt->i_height; + p_bih->biPlanes= 1; + p_bih->biBitCount = 24; + p_bih->biSizeImage = 0; + p_bih->biXPelsPerMeter = 0; + p_bih->biYPelsPerMeter = 0; + p_bih->biClrUsed = 0; + p_bih->biClrImportant = 0; + switch( p_input->p_fmt->i_fourcc ) + { + case VLC_FOURCC( 'm', 'p', '4', 'v' ): + p_bih->biCompression = VLC_FOURCC( 'X', 'V', 'I', 'D' ); + break; + default: + p_bih->biCompression = p_input->p_fmt->i_fourcc; + break; + } +#undef p_bih break; default: - return( -1 ); + return( VLC_EGENERIC ); } p_stream->i_totalsize = 0; p_stream->i_frames = 0; @@ -333,7 +375,7 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input ) p_sys->i_streams++; - return( 0 ); + return( VLC_SUCCESS ); } static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input ) @@ -431,8 +473,8 @@ static int Mux ( sout_mux_t *p_mux ) p_data->i_size += 1; } - sout_AccessOutWrite( p_mux->p_access, p_data ); p_sys->i_movi_size += p_data->i_size; + sout_AccessOutWrite( p_mux->p_access, p_data ); i_count--; } @@ -649,7 +691,7 @@ static int avi_HeaderAdd_strh( sout_mux_t *p_mux, if( i_samplesize > 1 ) { i_scale = i_samplesize; - i_rate = i_scale * p_stream->i_bitrate / 8; + i_rate = /*i_scale **/ p_stream->i_bitrate / 8; } else { diff --git a/modules/mux/mpeg/ps.c b/modules/mux/mpeg/ps.c index f3f6ebf92c..72474f16d8 100644 --- a/modules/mux/mpeg/ps.c +++ b/modules/mux/mpeg/ps.c @@ -2,7 +2,7 @@ * ps.c ***************************************************************************** * Copyright (C) 2001, 2002 VideoLAN - * $Id: ps.c,v 1.11 2003/03/11 19:02:30 fenrir Exp $ + * $Id: ps.c,v 1.12 2003/04/13 20:00:21 fenrir Exp $ * * Authors: Laurent Aimar * Eric Petit @@ -174,11 +174,11 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input ) msg_Dbg( p_mux, "adding input" ); p_input->p_sys = (void*)p_stream = malloc( sizeof( ps_stream_t ) ); p_stream->i_ok = 0; - switch( p_input->input_format.i_cat ) + switch( p_input->p_fmt->i_cat ) { case VIDEO_ES: - switch( p_input->input_format.i_fourcc ) + switch( p_input->p_fmt->i_fourcc ) { case VLC_FOURCC( 'm', 'p', 'g', 'v' ): p_stream->i_stream_id = p_sys->i_stream_id_mpgv; @@ -190,7 +190,7 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input ) } break; case AUDIO_ES: - switch( p_input->input_format.i_fourcc ) + switch( p_input->p_fmt->i_fourcc ) { case VLC_FOURCC( 'a', '5', '2', ' ' ): case VLC_FOURCC( 'a', '5', '2', 'b' ): diff --git a/modules/mux/mpeg/ts.c b/modules/mux/mpeg/ts.c index 9e3811a72f..ca347dab60 100644 --- a/modules/mux/mpeg/ts.c +++ b/modules/mux/mpeg/ts.c @@ -2,7 +2,7 @@ * ts.c ***************************************************************************** * Copyright (C) 2001, 2002 VideoLAN - * $Id: ts.c,v 1.15 2003/03/11 19:02:30 fenrir Exp $ + * $Id: ts.c,v 1.16 2003/04/13 20:00:21 fenrir Exp $ * * Authors: Laurent Aimar * Eric Petit @@ -223,8 +223,6 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input ) { sout_mux_sys_t *p_sys = p_mux->p_sys; ts_stream_t *p_stream; - BITMAPINFOHEADER *p_bih; - WAVEFORMATEX *p_wf; msg_Dbg( p_mux, "adding input" ); p_input->p_sys = (void*)p_stream = malloc( sizeof( ts_stream_t ) ); @@ -236,10 +234,10 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input ) } p_stream->i_continuity_counter = 0; - switch( p_input->input_format.i_cat ) + switch( p_input->p_fmt->i_cat ) { case VIDEO_ES: - switch( p_input->input_format.i_fourcc ) + switch( p_input->p_fmt->i_fourcc ) { case VLC_FOURCC( 'm', 'p','g', 'v' ): p_stream->i_stream_type = 0x02; @@ -269,38 +267,28 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input ) return( -1 ); } p_sys->i_video_bound++; - p_bih = (BITMAPINFOHEADER*)p_input->input_format.p_format; - if( p_bih ) - { - p_stream->i_bih_codec = p_input->input_format.i_fourcc; - p_stream->i_bih_width = p_bih->biWidth; - p_stream->i_bih_height = p_bih->biHeight; - } - else - { - p_stream->i_bih_codec = 0x0; - p_stream->i_bih_width = 0; - p_stream->i_bih_height = 0; - } - if( p_bih && p_bih->biSize > sizeof( BITMAPINFOHEADER ) ) + p_stream->i_bih_codec = p_input->p_fmt->i_fourcc; + p_stream->i_bih_width = p_input->p_fmt->i_width; + p_stream->i_bih_height = p_input->p_fmt->i_height; + + p_stream->i_decoder_specific_info_len = p_input->p_fmt->i_extra_data; + if( p_stream->i_decoder_specific_info_len > 0 ) { - p_stream->i_decoder_specific_info_len = - p_bih->biSize - sizeof( BITMAPINFOHEADER ); p_stream->p_decoder_specific_info = malloc( p_stream->i_decoder_specific_info_len ); memcpy( p_stream->p_decoder_specific_info, - &p_bih[1], - p_stream->i_decoder_specific_info_len ); + p_input->p_fmt->p_extra_data, + p_input->p_fmt->i_extra_data ); } else { p_stream->p_decoder_specific_info = NULL; - p_stream->i_decoder_specific_info_len = 0; } break; + case AUDIO_ES: - switch( p_input->input_format.i_fourcc ) + switch( p_input->p_fmt->i_fourcc ) { case VLC_FOURCC( 'a', '5','2', ' ' ): case VLC_FOURCC( 'a', '5','2', 'b' ): @@ -324,20 +312,19 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input ) return( -1 ); } p_sys->i_audio_bound++; - p_wf = (WAVEFORMATEX*)p_input->input_format.p_format; - if( p_wf && p_wf->cbSize > 0 ) + + p_stream->i_decoder_specific_info_len = p_input->p_fmt->i_extra_data; + if( p_stream->i_decoder_specific_info_len > 0 ) { - p_stream->i_decoder_specific_info_len = p_wf->cbSize; p_stream->p_decoder_specific_info = malloc( p_stream->i_decoder_specific_info_len ); memcpy( p_stream->p_decoder_specific_info, - &p_wf[1], - p_stream->i_decoder_specific_info_len ); + p_input->p_fmt->p_extra_data, + p_input->p_fmt->i_extra_data ); } else { p_stream->p_decoder_specific_info = NULL; - p_stream->i_decoder_specific_info_len = 0; } break; default: diff --git a/modules/mux/ogg.c b/modules/mux/ogg.c index 08607be629..ca48bbdfd2 100644 --- a/modules/mux/ogg.c +++ b/modules/mux/ogg.c @@ -2,7 +2,7 @@ * ogg.c ***************************************************************************** * Copyright (C) 2001, 2002 VideoLAN - * $Id: ogg.c,v 1.4 2003/03/31 03:46:11 fenrir Exp $ + * $Id: ogg.c,v 1.5 2003/04/13 20:00:21 fenrir Exp $ * * Authors: Laurent Aimar * @@ -209,33 +209,29 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input ) sout_mux_sys_t *p_sys = p_mux->p_sys; ogg_stream_t *p_stream; - BITMAPINFOHEADER *p_bih; - WAVEFORMATEX *p_wf; - msg_Dbg( p_mux, "adding input" ); p_input->p_sys = (void*)p_stream = malloc( sizeof( ogg_stream_t ) ); - p_stream->i_cat = p_input->input_format.i_cat; - p_stream->i_fourcc = p_input->input_format.i_fourcc; + p_stream->i_cat = p_input->p_fmt->i_cat; + p_stream->i_fourcc = p_input->p_fmt->i_fourcc; p_stream->i_packet_no = 0; p_stream->header.i_packet_type = PACKET_TYPE_HEADER; - switch( p_input->input_format.i_cat ) + switch( p_input->p_fmt->i_cat ) { case VIDEO_ES: - p_bih = (BITMAPINFOHEADER*)p_input->input_format.p_format; - switch( p_input->input_format.i_fourcc ) + switch( p_input->p_fmt->i_fourcc ) { case VLC_FOURCC( 'm', 'p','4', 'v' ): case VLC_FOURCC( 'D', 'I','V', '3' ): memcpy( p_stream->header.stream_type, "video ", 8 ); - if( p_input->input_format.i_fourcc == VLC_FOURCC( 'm', 'p','4', 'v' ) ) + if( p_input->p_fmt->i_fourcc == VLC_FOURCC( 'm', 'p','4', 'v' ) ) { memcpy( p_stream->header.sub_type, "XVID", 4 ); } - else if( p_input->input_format.i_fourcc == VLC_FOURCC( 'D', 'I','V', '3' ) ) + else if( p_input->p_fmt->i_fourcc == VLC_FOURCC( 'D', 'I','V', '3' ) ) { memcpy( p_stream->header.sub_type, "DIV3", 4 ); } @@ -246,16 +242,8 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input ) SetDWLE( &p_stream->header.i_default_len, 0 ); /* ??? */ SetDWLE( &p_stream->header.i_buffer_size, 1024*1024 ); SetWLE( &p_stream->header.i_bits_per_sample, 0 ); - if( p_bih ) - { - SetDWLE( &p_stream->header.header.video.i_width, p_bih->biWidth ); - SetDWLE( &p_stream->header.header.video.i_height, p_bih->biHeight ); - } - else - { - SetDWLE( &p_stream->header.header.video.i_width, 0 ); - SetDWLE( &p_stream->header.header.video.i_height, 0 ); - } + SetDWLE( &p_stream->header.header.video.i_width, p_input->p_fmt->i_width ); + SetDWLE( &p_stream->header.header.video.i_height, p_input->p_fmt->i_height ); break; default: FREE( p_input->p_sys ); @@ -263,19 +251,18 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input ) } break; case AUDIO_ES: - p_wf = (WAVEFORMATEX*)p_input->input_format.p_format; - switch( p_input->input_format.i_fourcc ) + switch( p_input->p_fmt->i_fourcc ) { case VLC_FOURCC( 'm', 'p','g', 'a' ): case VLC_FOURCC( 'a', '5','2', ' ' ): memcpy( p_stream->header.stream_type, "audio ", 8 ); - if( p_input->input_format.i_fourcc == VLC_FOURCC( 'm', 'p','g', 'a' ) ) + if( p_input->p_fmt->i_fourcc == VLC_FOURCC( 'm', 'p','g', 'a' ) ) { memcpy( p_stream->header.sub_type, "55 ", 4 ); } - else if( p_input->input_format.i_fourcc == VLC_FOURCC( 'a', '5','2', ' ' ) ) + else if( p_input->p_fmt->i_fourcc == VLC_FOURCC( 'a', '5','2', ' ' ) ) { memcpy( p_stream->header.sub_type, "2000", 4 ); } @@ -283,23 +270,11 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input ) SetQWLE( &p_stream->header.i_time_unit, 1000000 ); /* is it used ? */ SetDWLE( &p_stream->header.i_default_len, 0 ); /* ??? */ SetDWLE( &p_stream->header.i_buffer_size, 30*1024 ); - if( p_wf ) - { - SetQWLE( &p_stream->header.i_samples_per_unit, p_wf->nSamplesPerSec ); - SetWLE( &p_stream->header.i_bits_per_sample, p_wf->wBitsPerSample ); - SetDWLE( &p_stream->header.header.audio.i_channels, p_wf->nChannels ); - SetDWLE( &p_stream->header.header.audio.i_block_align, p_wf->nBlockAlign ); - SetDWLE( &p_stream->header.header.audio.i_avgbytespersec, p_wf->nAvgBytesPerSec ); - } - else - { - /* perhaps it's better to fail */ - SetQWLE( &p_stream->header.i_samples_per_unit, 44100 ); - SetWLE( &p_stream->header.i_bits_per_sample, 0 ); - SetDWLE( &p_stream->header.header.audio.i_channels, 2 ); - SetDWLE( &p_stream->header.header.audio.i_block_align, 0 ); - SetDWLE( &p_stream->header.header.audio.i_avgbytespersec, 0 ); - } + SetQWLE( &p_stream->header.i_samples_per_unit, p_input->p_fmt->i_sample_rate ); + SetWLE( &p_stream->header.i_bits_per_sample, 0 ); + SetDWLE( &p_stream->header.header.audio.i_channels, p_input->p_fmt->i_channels ); + SetDWLE( &p_stream->header.header.audio.i_block_align, p_input->p_fmt->i_block_align ); + SetDWLE( &p_stream->header.header.audio.i_avgbytespersec, 0 ); break; case VLC_FOURCC( 'v', 'o', 'r', 'b' ): default: diff --git a/modules/packetizer/a52.c b/modules/packetizer/a52.c index 11cbded978..5e82503c42 100644 --- a/modules/packetizer/a52.c +++ b/modules/packetizer/a52.c @@ -2,7 +2,7 @@ * a52.c ***************************************************************************** * Copyright (C) 2001, 2002 VideoLAN - * $Id: a52.c,v 1.3 2003/03/31 03:46:11 fenrir Exp $ + * $Id: a52.c,v 1.4 2003/04/13 20:00:21 fenrir Exp $ * * Authors: Laurent Aimar * Eric Petit @@ -45,7 +45,7 @@ typedef struct packetizer_s /* Output properties */ sout_packetizer_input_t *p_sout_input; - sout_packet_format_t output_format; + sout_format_t output_format; uint64_t i_samplescount; @@ -155,8 +155,6 @@ static int InitThread( packetizer_t *p_pack ) p_pack->output_format.i_cat = AUDIO_ES; p_pack->output_format.i_fourcc = VLC_FOURCC( 'a', '5', '2', ' ' ); - p_pack->output_format.p_format = NULL; - p_pack->p_sout_input = NULL; p_pack->i_samplescount = 0; @@ -230,19 +228,12 @@ static void PacketizeThread( packetizer_t *p_pack ) if( !p_pack->p_sout_input ) { - /* add a input for the stream ouput */ - WAVEFORMATEX *p_wf; - - p_wf = malloc( sizeof( WAVEFORMATEX ) ); - p_pack->output_format.p_format = (void*)p_wf; - - p_wf->wFormatTag = WAVE_FORMAT_A52; - p_wf->nChannels = i_channels; - p_wf->nSamplesPerSec = i_samplerate; - p_wf->nAvgBytesPerSec = 0; - p_wf->nBlockAlign = 1; - p_wf->wBitsPerSample = 0; - p_wf->cbSize = 0; + p_pack->output_format.i_sample_rate = i_samplerate; + p_pack->output_format.i_channels = i_channels; + p_pack->output_format.i_block_align = 0; + p_pack->output_format.i_bitrate = 0; + p_pack->output_format.i_extra_data = 0; + p_pack->output_format.p_extra_data = NULL; p_pack->p_sout_input = sout_InputNew( p_pack->p_fifo, diff --git a/modules/packetizer/copy.c b/modules/packetizer/copy.c index e302640232..197d34ae7b 100644 --- a/modules/packetizer/copy.c +++ b/modules/packetizer/copy.c @@ -2,7 +2,7 @@ * copy.c ***************************************************************************** * Copyright (C) 2001, 2002 VideoLAN - * $Id: copy.c,v 1.6 2003/03/31 03:46:11 fenrir Exp $ + * $Id: copy.c,v 1.7 2003/04/13 20:00:21 fenrir Exp $ * * Authors: Laurent Aimar * Eric Petit @@ -45,7 +45,7 @@ typedef struct packetizer_thread_s /* Output properties */ sout_packetizer_input_t *p_sout_input; - sout_packet_format_t output_format; + sout_format_t output_format; // mtime_t i_last_pts; @@ -243,11 +243,26 @@ static int InitThread( packetizer_thread_t *p_pack ) p_pack->output_format.i_fourcc = VLC_FOURCC( 'd', 'v', 's', 'l' ); p_pack->output_format.i_cat = VIDEO_ES; break; + case VLC_FOURCC( 'S', 'V', 'Q', '1' ): + p_pack->output_format.i_fourcc = VLC_FOURCC( 'S', 'V', 'Q', '1' ); + p_pack->output_format.i_cat = VIDEO_ES; + break; - default: - p_pack->output_format.i_fourcc = p_pack->p_fifo->i_fourcc; - p_pack->output_format.i_cat = UNKNOWN_ES; + case VLC_FOURCC( 'w', 'm', 'a', '1' ): + p_pack->output_format.i_fourcc = VLC_FOURCC( 'w', 'm', 'a', '1' ); + p_pack->output_format.i_cat = AUDIO_ES; + break; + case VLC_FOURCC( 'w', 'm', 'a', '2' ): + p_pack->output_format.i_fourcc = VLC_FOURCC( 'w', 'm', 'a', '2' ); + p_pack->output_format.i_cat = AUDIO_ES; break; + + default: + msg_Err( p_pack->p_fifo, "unknown es type !!" ); + return VLC_EGENERIC; + //p_pack->output_format.i_fourcc = p_pack->p_fifo->i_fourcc; + //p_pack->output_format.i_cat = UNKNOWN_ES; + //break; } switch( p_pack->output_format.i_cat ) @@ -257,12 +272,32 @@ static int InitThread( packetizer_thread_t *p_pack ) WAVEFORMATEX *p_wf = (WAVEFORMATEX*)p_pack->p_fifo->p_waveformatex; if( p_wf ) { - p_pack->output_format.p_format = malloc( sizeof( WAVEFORMATEX ) + p_wf->cbSize ); - memcpy( p_pack->output_format.p_format, p_wf, sizeof( WAVEFORMATEX ) + p_wf->cbSize ); + p_pack->output_format.i_sample_rate = p_wf->nSamplesPerSec; + p_pack->output_format.i_channels = p_wf->nChannels; + p_pack->output_format.i_block_align = p_wf->nBlockAlign; + p_pack->output_format.i_bitrate = p_wf->nAvgBytesPerSec * 8; + p_pack->output_format.i_extra_data = p_wf->cbSize; + if( p_wf->cbSize > 0 ) + { + p_pack->output_format.p_extra_data = + malloc( p_pack->output_format.i_extra_data ); + memcpy( p_pack->output_format.p_extra_data, + &p_wf[1], + p_pack->output_format.i_extra_data ); + } + else + { + p_pack->output_format.p_extra_data = NULL; + } } else { - p_pack->output_format.p_format = NULL; + p_pack->output_format.i_sample_rate = 0; + p_pack->output_format.i_channels = 0; + p_pack->output_format.i_block_align = 0; + p_pack->output_format.i_bitrate = 0; + p_pack->output_format.i_extra_data = 0; + p_pack->output_format.p_extra_data = NULL; } } break; @@ -270,29 +305,34 @@ static int InitThread( packetizer_thread_t *p_pack ) case VIDEO_ES: { BITMAPINFOHEADER *p_bih = (BITMAPINFOHEADER*)p_pack->p_fifo->p_bitmapinfoheader; + + p_pack->output_format.i_bitrate = 0; if( p_bih ) { - p_pack->output_format.p_format = malloc( p_bih->biSize ); - memcpy( p_pack->output_format.p_format, p_bih, p_bih->biSize ); - if( p_pack->output_format.i_fourcc == VLC_FOURCC( 'm', 'p', '4', 'v' ) ) - { - p_bih->biCompression = VLC_FOURCC( 'd', 'i', 'v', 'x' ); - } - else + p_pack->output_format.i_width = p_bih->biWidth; + p_pack->output_format.i_height = p_bih->biHeight; + p_pack->output_format.i_extra_data = p_bih->biSize - sizeof( BITMAPINFOHEADER ); + if( p_pack->output_format.i_extra_data > 0 ) { - p_bih->biCompression = p_pack->output_format.i_fourcc; + p_pack->output_format.p_extra_data = + malloc( p_pack->output_format.i_extra_data ); + memcpy( p_pack->output_format.p_extra_data, + &p_bih[1], + p_pack->output_format.i_extra_data ); } - } else { - p_pack->output_format.p_format = NULL; + p_pack->output_format.i_width = 0; + p_pack->output_format.i_height = 0; + p_pack->output_format.i_extra_data = 0; + p_pack->output_format.p_extra_data = NULL; } } break; + default: - p_pack->output_format.p_format = NULL; - break; + return VLC_EGENERIC; } p_pack->p_sout_input = @@ -302,10 +342,10 @@ static int InitThread( packetizer_thread_t *p_pack ) if( !p_pack->p_sout_input ) { msg_Err( p_pack->p_fifo, "cannot add a new stream" ); - return( -1 ); + return VLC_EGENERIC; } // p_pack->i_last_pts = 0; - return( 0 ); + return( VLC_SUCCESS ); } /***************************************************************************** @@ -329,7 +369,7 @@ static void PacketizeThread( packetizer_thread_t *p_pack ) if( i_pts <= 0 ) //&& p_pack->i_last_pts <= 0 ) { - msg_Err( p_pack->p_fifo, "need pts != 0" ); + msg_Dbg( p_pack->p_fifo, "need pts != 0" ); input_DeletePES( p_pack->p_fifo->p_packets_mgt, p_pes ); return; } diff --git a/modules/packetizer/mpeg4audio.c b/modules/packetizer/mpeg4audio.c index 3177d3833b..981e1b1cd4 100644 --- a/modules/packetizer/mpeg4audio.c +++ b/modules/packetizer/mpeg4audio.c @@ -2,7 +2,7 @@ * mpeg4audio.c ***************************************************************************** * Copyright (C) 2001, 2002 VideoLAN - * $Id: mpeg4audio.c,v 1.4 2003/03/31 03:46:11 fenrir Exp $ + * $Id: mpeg4audio.c,v 1.5 2003/04/13 20:00:21 fenrir Exp $ * * Authors: Laurent Aimar * @@ -60,7 +60,7 @@ typedef struct packetizer_thread_s /* Output properties */ sout_packetizer_input_t *p_sout_input; - sout_packet_format_t output_format; + sout_format_t output_format; // mtime_t i_pts_start; mtime_t i_last_pts; @@ -187,17 +187,8 @@ static int InitThread( packetizer_thread_t *p_pack ) if( p_wf && p_wf->cbSize > 0) { uint8_t *p_config = (uint8_t*)&p_wf[1]; - int i_wf = sizeof( WAVEFORMATEX ) + p_wf->cbSize; - int i_index; + int i_index; - - p_pack->p_wf = malloc( i_wf ); - memcpy( p_pack->p_wf, - p_wf, - i_wf ); - p_pack->output_format.i_cat = AUDIO_ES; - p_pack->output_format.i_fourcc = VLC_FOURCC( 'm', 'p', '4', 'a' ); - p_pack->output_format.p_format = p_pack->p_wf; p_pack->b_adts = 0; i_index = ( ( p_config[0] << 1 ) | ( p_config[1] >> 7 ) )&0x0f; @@ -216,6 +207,19 @@ static int InitThread( packetizer_thread_t *p_pack ) "aac %dHz %d samples/frame", p_pack->i_sample_rate, p_pack->i_frame_size ); + + p_pack->output_format.i_cat = AUDIO_ES; + p_pack->output_format.i_fourcc = VLC_FOURCC( 'm', 'p', '4', 'a' ); + p_pack->output_format.i_sample_rate = p_pack->i_sample_rate; + p_pack->output_format.i_channels = p_wf->nChannels; + p_pack->output_format.i_block_align = 0; + p_pack->output_format.i_bitrate = 0; + + p_pack->output_format.i_extra_data = p_wf->cbSize; + p_pack->output_format.p_extra_data = malloc( p_wf->cbSize ); + memcpy( p_pack->output_format.p_extra_data, + &p_wf[1], + p_wf->cbSize ); } else { diff --git a/modules/packetizer/mpeg4video.c b/modules/packetizer/mpeg4video.c index 008d07b564..58bc86f585 100644 --- a/modules/packetizer/mpeg4video.c +++ b/modules/packetizer/mpeg4video.c @@ -2,7 +2,7 @@ * mpeg4video.c ***************************************************************************** * Copyright (C) 2001, 2002 VideoLAN - * $Id: mpeg4video.c,v 1.9 2003/03/31 03:46:11 fenrir Exp $ + * $Id: mpeg4video.c,v 1.10 2003/04/13 20:00:21 fenrir Exp $ * * Authors: Laurent Aimar * Eric Petit @@ -46,7 +46,7 @@ typedef struct packetizer_thread_s /* Output properties */ sout_packetizer_input_t *p_sout_input; - sout_packet_format_t output_format; + sout_format_t output_format; mtime_t i_last_pts; @@ -198,8 +198,15 @@ static int InitThread( packetizer_thread_t *p_pack ) /* create stream input output */ p_pack->output_format.i_cat = VIDEO_ES; p_pack->output_format.i_fourcc = VLC_FOURCC( 'm', 'p', '4', 'v' ); - p_pack->output_format.p_format = malloc( p_bih->biSize ); - memcpy( p_pack->output_format.p_format, p_bih, p_bih->biSize ); + p_pack->output_format.i_width = p_bih->biWidth; + p_pack->output_format.i_height = p_bih->biHeight; + p_pack->output_format.i_bitrate= 0; + + p_pack->output_format.i_extra_data = p_pack->i_vol; + p_pack->output_format.p_extra_data = malloc( p_pack->i_vol ); + memcpy( p_pack->output_format.p_extra_data, + p_pack->p_vol, + p_pack->i_vol ); msg_Warn( p_pack->p_fifo, "opening with vol size:%d", p_pack->i_vol ); p_pack->p_sout_input = @@ -212,7 +219,11 @@ static int InitThread( packetizer_thread_t *p_pack ) p_pack->p_vol = 0; p_pack->output_format.i_cat = UNKNOWN_ES; p_pack->output_format.i_fourcc = VLC_FOURCC( 'n', 'u', 'l', 'l' ); - p_pack->output_format.p_format = NULL; + p_pack->output_format.i_width = 0; + p_pack->output_format.i_height = 0; + p_pack->output_format.i_bitrate= 0; + p_pack->output_format.i_extra_data = 0; + p_pack->output_format.p_extra_data = NULL; p_pack->p_sout_input = sout_InputNew( p_pack->p_fifo, @@ -260,12 +271,14 @@ static void PacketizeThread( packetizer_thread_t *p_pack ) } i_pts = p_pes->i_pts; +#if 0 if( i_pts <= 0 && p_pack->i_last_pts <= 0 ) { - msg_Err( p_pack->p_fifo, "need a starting pts" ); + msg_Dbg( p_pack->p_fifo, "need a starting pts" ); input_DeletePES( p_pack->p_fifo->p_packets_mgt, p_pes ); return; } +#endif i_size = p_pes->i_pes_size; if( i_size > 0 ) @@ -364,8 +377,6 @@ static void PacketizeThread( packetizer_thread_t *p_pack ) if( p_vol_end != NULL && p_vol_begin < p_vol_end ) { - BITMAPINFOHEADER *p_bih; - p_pack->i_vol = p_vol_end - p_vol_begin; msg_Dbg( p_pack->p_fifo, "Reopening output" ); @@ -376,21 +387,16 @@ static void PacketizeThread( packetizer_thread_t *p_pack ) p_pack->output_format.i_cat = VIDEO_ES; p_pack->output_format.i_fourcc = VLC_FOURCC( 'm', 'p', '4', 'v' ); - p_pack->output_format.p_format = - (void*)p_bih = malloc( sizeof( BITMAPINFOHEADER ) + p_pack->i_vol); - - p_bih->biSize = sizeof( BITMAPINFOHEADER ) + p_pack->i_vol; - p_bih->biWidth = 0; - p_bih->biHeight = 0; - p_bih->biPlanes = 1; - p_bih->biBitCount = 24; - p_bih->biCompression = VLC_FOURCC( 'd', 'i', 'v', 'x' ); - p_bih->biSizeImage = 0; - p_bih->biXPelsPerMeter = 0; - p_bih->biYPelsPerMeter = 0; - p_bih->biClrUsed = 0; - p_bih->biClrImportant = 0; - memcpy( &p_bih[1], p_pack->p_vol, p_pack->i_vol ); + + p_pack->output_format.i_width = 0; + p_pack->output_format.i_height = 0; + p_pack->output_format.i_bitrate= 0; + + p_pack->output_format.i_extra_data = p_pack->i_vol; + p_pack->output_format.p_extra_data = malloc( p_pack->i_vol ); + memcpy( p_pack->output_format.p_extra_data, + p_pack->p_vol, + p_pack->i_vol ); p_pack->p_sout_input = sout_InputNew( p_pack->p_fifo, @@ -410,8 +416,16 @@ static void PacketizeThread( packetizer_thread_t *p_pack ) } } - sout_InputSendBuffer( p_pack->p_sout_input, + if( i_pts > 0 ) + { + sout_InputSendBuffer( p_pack->p_sout_input, + p_sout_buffer ); + } + else + { + sout_BufferDelete( p_pack->p_sout_input->p_sout, p_sout_buffer ); + } } input_DeletePES( p_pack->p_fifo->p_packets_mgt, p_pes ); diff --git a/modules/packetizer/mpegaudio.c b/modules/packetizer/mpegaudio.c index faaa19163f..ee95286a40 100644 --- a/modules/packetizer/mpegaudio.c +++ b/modules/packetizer/mpegaudio.c @@ -2,7 +2,7 @@ * mpegaudio.c ***************************************************************************** * Copyright (C) 2001, 2002 VideoLAN - * $Id: mpegaudio.c,v 1.5 2003/03/31 03:46:11 fenrir Exp $ + * $Id: mpegaudio.c,v 1.6 2003/04/13 20:00:21 fenrir Exp $ * * Authors: Laurent Aimar * Eric Petit @@ -45,7 +45,7 @@ typedef struct packetizer_s /* Output properties */ sout_packetizer_input_t *p_sout_input; - sout_packet_format_t output_format; + sout_format_t output_format; uint64_t i_samplescount; uint32_t i_samplespersecond; @@ -180,8 +180,13 @@ static int InitThread( packetizer_t *p_pack ) p_pack->output_format.i_cat = AUDIO_ES; p_pack->output_format.i_fourcc = p_pack->p_fifo->i_fourcc; + p_pack->output_format.i_sample_rate = 0; + p_pack->output_format.i_channels = 0; + p_pack->output_format.i_block_align = 0; + p_pack->output_format.i_bitrate = 0; + p_pack->output_format.i_extra_data = 0; + p_pack->output_format.p_extra_data = NULL; - p_pack->output_format.p_format = NULL; p_pack->p_sout_input = NULL; @@ -301,18 +306,10 @@ static void PacketizeThread( packetizer_t *p_pack ) if( !p_pack->p_sout_input ) { /* add a input for the stream ouput */ - WAVEFORMATEX *p_wf; - - p_wf = malloc( sizeof( WAVEFORMATEX ) ); - p_pack->output_format.p_format = (void*)p_wf; - - p_wf->wFormatTag = WAVE_FORMAT_MPEG; - p_wf->nChannels = i_channels; - p_wf->nSamplesPerSec = i_samplerate; - p_wf->nAvgBytesPerSec = 0; - p_wf->nBlockAlign = 1; - p_wf->wBitsPerSample = 0; - p_wf->cbSize = 0; // FIXME there are more field for mpegaudio + p_pack->output_format.i_sample_rate = i_samplerate; + p_pack->output_format.i_channels = i_channels; + p_pack->output_format.i_block_align = 1; + p_pack->output_format.i_bitrate = 0; p_pack->p_sout_input = sout_InputNew( p_pack->p_fifo, diff --git a/modules/packetizer/mpegvideo.c b/modules/packetizer/mpegvideo.c index 8e3a6ec4c2..dac33d8ef1 100644 --- a/modules/packetizer/mpegvideo.c +++ b/modules/packetizer/mpegvideo.c @@ -2,7 +2,7 @@ * mpegvideo.c ***************************************************************************** * Copyright (C) 2001, 2002 VideoLAN - * $Id: mpegvideo.c,v 1.11 2003/03/31 03:46:11 fenrir Exp $ + * $Id: mpegvideo.c,v 1.12 2003/04/13 20:00:21 fenrir Exp $ * * Authors: Laurent Aimar * Eric Petit @@ -45,7 +45,7 @@ typedef struct packetizer_s /* Output properties */ sout_packetizer_input_t *p_sout_input; - sout_packet_format_t output_format; + sout_format_t output_format; mtime_t i_last_dts; mtime_t i_last_ref_pts; @@ -157,6 +157,11 @@ static int InitThread( packetizer_t *p_pack ) p_pack->output_format.i_cat = VIDEO_ES; p_pack->output_format.i_fourcc = VLC_FOURCC( 'm', 'p', 'g', 'v'); + p_pack->output_format.i_width = 0; + p_pack->output_format.i_height = 0; + p_pack->output_format.i_bitrate= 0; + p_pack->output_format.i_extra_data = 0; + p_pack->output_format.p_extra_data = NULL; p_pack->p_sout_input = NULL; @@ -228,10 +233,7 @@ static void PacketizeThread( packetizer_t *p_pack ) byte_t p_temp[512];/* 150 bytes is the maximal size of a sequence_header + sequence_extension */ int i_frame_rate_code; - BITMAPINFOHEADER *p_bih; - p_bih = malloc( sizeof( BITMAPINFOHEADER ) ); - p_pack->output_format.p_format = (void*)p_bih; /* skip data until we find a sequence_header_code */ /* TODO: store skipped somewhere so can send it to the mux @@ -250,21 +252,12 @@ static void PacketizeThread( packetizer_t *p_pack ) i_pos = 0; GetChunk( &p_pack->bit_stream, p_temp, 4 ); i_pos += 4; - p_bih->biSize = sizeof( BITMAPINFOHEADER ); /* horizontal_size_value */ - p_bih->biWidth = ShowBits( &p_pack->bit_stream, 12 ); + p_pack->output_format.i_width = ShowBits( &p_pack->bit_stream, 12 ); /* vertical_size_value */ - p_bih->biHeight = ShowBits( &p_pack->bit_stream, 24 ) & 0xFFF; + p_pack->output_format.i_height= ShowBits( &p_pack->bit_stream, 24 ) & 0xFFF; /* frame_rate_code */ i_frame_rate_code = ShowBits( &p_pack->bit_stream, 32 ) & 0xF; - p_bih->biPlanes = 1; - p_bih->biBitCount = 0; - p_bih->biCompression = VLC_FOURCC( 'm', 'p', 'g', '2' ); - p_bih->biSizeImage = 0; - p_bih->biXPelsPerMeter = 0; - p_bih->biYPelsPerMeter = 0; - p_bih->biClrUsed = 0; - p_bih->biClrImportant = 0; /* copy headers */ GetChunk( &p_pack->bit_stream, p_temp + i_pos, 7 ); i_pos += 7; @@ -313,7 +306,9 @@ static void PacketizeThread( packetizer_t *p_pack ) msg_Warn( p_pack->p_fifo, "creating input (image size %dx%d, frame rate %.2f)", - p_bih->biWidth, p_bih->biHeight, p_pack->d_frame_rate ); + p_pack->output_format.i_width, + p_pack->output_format.i_height, + p_pack->d_frame_rate ); /* now we have informations to create the input */ p_pack->p_sout_input = sout_InputNew( p_pack->p_fifo, @@ -365,7 +360,8 @@ static void PacketizeThread( packetizer_t *p_pack ) } p_pack->i_last_ref_pts = - p_pack->i_last_dts + 40000; /* FIXME */ + p_pack->i_last_dts + + (mtime_t)( 1000000 / p_pack->d_frame_rate); /* FIXME */ CopyUntilNextStartCode( p_pack, p_sout_buffer, &i_pos ); } else if( i_code == 0x100 ) /* Picture */ @@ -437,16 +433,21 @@ static void PacketizeThread( packetizer_t *p_pack ) return; } +#if 1 if( i_dts > 0 ) { - p_pack->i_last_dts = i_dts; - } - if( i_pts > 0 ) - { - p_pack->i_last_ref_pts = - i_pts - i_temporal_ref * - (mtime_t)( 1000000 / p_pack->d_frame_rate ); + //if( i_dts - p_pack->i_last_dts > 200000 || + // i_dts - p_pack->i_last_dts < 200000 ) + { + p_pack->i_last_dts = i_dts; + if( i_pts > 0 ) + { + p_pack->i_last_ref_pts = i_pts - + i_temporal_ref * (mtime_t)( 1000000 / p_pack->d_frame_rate ); + } + } } +#endif p_sout_buffer->i_dts = p_pack->i_last_dts; p_sout_buffer->i_pts = p_pack->i_last_ref_pts + diff --git a/modules/stream_out/Modules.am b/modules/stream_out/Modules.am new file mode 100644 index 0000000000..8c0464f27b --- /dev/null +++ b/modules/stream_out/Modules.am @@ -0,0 +1,6 @@ +SOURCES_stream_out_dummy = modules/stream_out/dummy.c +SOURCES_stream_out_standard = modules/stream_out/standard.c +SOURCES_stream_out_transcode = modules/stream_out/transcode.c +SOURCES_stream_out_duplicate = modules/stream_out/duplicate.c +SOURCES_stream_out_es = modules/stream_out/es.c +SOURCES_stream_out_display = modules/stream_out/display.c diff --git a/modules/stream_out/display.c b/modules/stream_out/display.c new file mode 100644 index 0000000000..edd9948e76 --- /dev/null +++ b/modules/stream_out/display.c @@ -0,0 +1,285 @@ +/***************************************************************************** + * display.c + ***************************************************************************** + * Copyright (C) 2001, 2002 VideoLAN + * $Id: display.c,v 1.1 2003/04/13 20:00:21 fenrir Exp $ + * + * Authors: Laurent Aimar + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + *****************************************************************************/ + +/***************************************************************************** + * Preamble + *****************************************************************************/ +#include +#include + +#include +#include +#include + +#include "codecs.h" + +/***************************************************************************** + * Exported prototypes + *****************************************************************************/ +static int Open ( vlc_object_t * ); +static void Close ( vlc_object_t * ); + +static sout_stream_id_t *Add ( sout_stream_t *, sout_format_t * ); +static int Del ( sout_stream_t *, sout_stream_id_t * ); +static int Send( sout_stream_t *, sout_stream_id_t *, sout_buffer_t* ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( _("Display stream") ); + set_capability( "sout stream", 50 ); + add_shortcut( "display" ); + set_callbacks( Open, Close ); +vlc_module_end(); + +struct sout_stream_sys_t +{ + input_thread_t *p_input; + + vlc_bool_t b_audio; + vlc_bool_t b_video; + + mtime_t i_delay; +}; + +/***************************************************************************** + * Open: + *****************************************************************************/ +static int Open( vlc_object_t *p_this ) +{ + sout_stream_t *p_stream = (sout_stream_t*)p_this; + sout_stream_sys_t *p_sys; + char *val; + p_sys = malloc( sizeof( sout_stream_sys_t ) ); + p_sys->p_input = vlc_object_find( p_stream, VLC_OBJECT_INPUT, FIND_ANYWHERE ); + if( !p_sys->p_input ) + { + msg_Err( p_stream, "cannot find p_input" ); + free( p_sys ); + return VLC_EGENERIC; + } + + p_sys->b_audio = VLC_TRUE; + p_sys->b_video = VLC_TRUE; + p_sys->i_delay = 100*1000; + if( sout_cfg_find( p_stream->p_cfg, "noaudio" ) ) + { + p_sys->b_audio = VLC_FALSE; + } + if( sout_cfg_find( p_stream->p_cfg, "novideo" ) ) + { + p_sys->b_video = VLC_FALSE; + } + if( ( val = sout_cfg_find_value( p_stream->p_cfg, "delay" ) ) ) + { + p_sys->i_delay = (mtime_t)atoi( val ) * (mtime_t)1000; + } + + p_stream->pf_add = Add; + p_stream->pf_del = Del; + p_stream->pf_send = Send; + + p_stream->p_sys = p_sys; + + return VLC_SUCCESS; +} + +/***************************************************************************** + * Close: + *****************************************************************************/ + +static void Close( vlc_object_t * p_this ) +{ + sout_stream_t *p_stream = (sout_stream_t*)p_this; + sout_stream_sys_t *p_sys = p_stream->p_sys; + + vlc_object_release( p_sys->p_input ); + + free( p_sys ); +} + +struct sout_stream_id_t +{ + es_descriptor_t *p_es; +}; + + +static sout_stream_id_t * Add ( sout_stream_t *p_stream, sout_format_t *p_fmt ) +{ + sout_stream_sys_t *p_sys = p_stream->p_sys; + sout_stream_id_t *id; + + if( ( p_fmt->i_cat == AUDIO_ES && !p_sys->b_audio )|| + ( p_fmt->i_cat == VIDEO_ES && !p_sys->b_video ) ) + { + return NULL; + } + + id = malloc( sizeof( sout_stream_id_t ) ); + + vlc_mutex_lock( &p_sys->p_input->stream.stream_lock ); + id->p_es = input_AddES( p_sys->p_input, + NULL, /* no program */ + 12, /* es_id */ + 0 ); /* no extra data */ + + if( !id->p_es ) + { + vlc_mutex_unlock( &p_sys->p_input->stream.stream_lock ); + + msg_Err( p_stream, "cannot create es" ); + free( id ); + return NULL; + } + id->p_es->i_stream_id = 1; + id->p_es->i_cat = UNKNOWN_ES; //p_fmt->i_cat; + id->p_es->i_fourcc = p_fmt->i_fourcc; + id->p_es->b_force_decoder = VLC_TRUE; + switch( p_fmt->i_cat ) + { + case AUDIO_ES: + id->p_es->p_bitmapinfoheader = NULL; + id->p_es->p_waveformatex = + malloc( sizeof( WAVEFORMATEX ) + p_fmt->i_extra_data ); +#define p_wf ((WAVEFORMATEX*)id->p_es->p_waveformatex) + p_wf->wFormatTag = WAVE_FORMAT_UNKNOWN; + p_wf->nChannels = p_fmt->i_channels; + p_wf->nSamplesPerSec = p_fmt->i_sample_rate; + p_wf->nAvgBytesPerSec= p_fmt->i_bitrate / 8; + p_wf->nBlockAlign = p_fmt->i_block_align; + p_wf->wBitsPerSample = 0; + p_wf->cbSize = p_fmt->i_extra_data; + if( p_fmt->i_extra_data > 0 ) + { + memcpy( &p_wf[1], + p_fmt->p_extra_data, + p_fmt->i_extra_data ); + } +#undef p_wf + break; + case VIDEO_ES: + id->p_es->p_waveformatex = NULL; + id->p_es->p_bitmapinfoheader = malloc( sizeof( BITMAPINFOHEADER ) + p_fmt->i_extra_data ); +#define p_bih ((BITMAPINFOHEADER*)id->p_es->p_bitmapinfoheader) + p_bih->biSize = sizeof( BITMAPINFOHEADER ) + p_fmt->i_extra_data; + p_bih->biWidth = p_fmt->i_width; + p_bih->biHeight = p_fmt->i_height; + p_bih->biPlanes = 0; + p_bih->biBitCount = 0; + p_bih->biCompression = 0; + p_bih->biSizeImage = 0; + p_bih->biXPelsPerMeter = 0; + p_bih->biYPelsPerMeter = 0; + p_bih->biClrUsed = 0; + p_bih->biClrImportant = 0; + if( p_fmt->i_extra_data > 0 ) + { + memcpy( &p_bih[1], + p_fmt->p_extra_data, + p_fmt->i_extra_data ); + } +#undef p_bih + break; + default: + msg_Err( p_stream, "unknown es type" ); + free( id ); + return NULL; + } + + if( input_SelectES( p_sys->p_input, id->p_es ) ) + { + input_DelES( p_sys->p_input, id->p_es ); + vlc_mutex_unlock( &p_sys->p_input->stream.stream_lock ); + + msg_Err( p_stream, "cannot select es" ); + free( id ); + return NULL; + } + vlc_mutex_unlock( &p_sys->p_input->stream.stream_lock ); + + return id; +} + +static int Del ( sout_stream_t *p_stream, sout_stream_id_t *id ) +{ + sout_stream_sys_t *p_sys = p_stream->p_sys; + + input_DelES( p_sys->p_input, id->p_es ); + + free( id ); + + return VLC_SUCCESS; +} + +static int Send ( sout_stream_t *p_stream, sout_stream_id_t *id, sout_buffer_t *p_buffer ) +{ + sout_stream_sys_t *p_sys = p_stream->p_sys; + + while( p_buffer ) + { + sout_buffer_t *p_next; + pes_packet_t *p_pes; + data_packet_t *p_data; + + if( p_buffer->i_size > 0 ) + { + if( !( p_pes = input_NewPES( p_sys->p_input->p_method_data ) ) ) + { + msg_Err( p_stream, "cannot allocate new PES" ); + return VLC_EGENERIC; + } + if( !( p_data = input_NewPacket( p_sys->p_input->p_method_data, p_buffer->i_size ) ) ) + { + msg_Err( p_stream, "cannot allocate new data_packet" ); + return VLC_EGENERIC; + } + p_pes->i_dts = p_buffer->i_dts + p_sys->i_delay; + p_pes->i_pts = p_buffer->i_pts + p_sys->i_delay; + p_pes->p_first = p_pes->p_last = p_data; + p_pes->i_nb_data = 1; + p_pes->i_pes_size = p_buffer->i_size; + + p_stream->p_vlc->pf_memcpy( p_data->p_payload_start, + p_buffer->p_buffer, + p_buffer->i_size ); + + if( id->p_es->p_decoder_fifo ) + { + input_DecodePES( id->p_es->p_decoder_fifo, p_pes ); + } + else + { + input_DeletePES( p_sys->p_input->p_method_data, p_pes ); + } + } + + /* *** go to next buffer *** */ + p_next = p_buffer->p_next; + sout_BufferDelete( p_stream->p_sout, p_buffer ); + p_buffer = p_next; + } + + return VLC_SUCCESS; +} + diff --git a/modules/stream_out/dummy.c b/modules/stream_out/dummy.c new file mode 100644 index 0000000000..8b27502cbf --- /dev/null +++ b/modules/stream_out/dummy.c @@ -0,0 +1,116 @@ +/***************************************************************************** + * dummy.c + ***************************************************************************** + * Copyright (C) 2001, 2002 VideoLAN + * $Id: dummy.c,v 1.1 2003/04/13 20:00:21 fenrir Exp $ + * + * Authors: Laurent Aimar + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + *****************************************************************************/ + +/***************************************************************************** + * Preamble + *****************************************************************************/ +#include +#include + +#include +#include + +/***************************************************************************** + * Exported prototypes + *****************************************************************************/ +static int Open ( vlc_object_t * ); +static void Close ( vlc_object_t * ); + +static sout_stream_id_t *Add ( sout_stream_t *, sout_format_t * ); +static int Del ( sout_stream_t *, sout_stream_id_t * ); +static int Send( sout_stream_t *, sout_stream_id_t *, sout_buffer_t* ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( _("Dummy stream") ); + set_capability( "sout stream", 50 ); + add_shortcut( "dummy" ); + set_callbacks( Open, Close ); +vlc_module_end(); + +/***************************************************************************** + * Open: + *****************************************************************************/ +static int Open( vlc_object_t *p_this ) +{ + sout_stream_t *p_stream = (sout_stream_t*)p_this; + + p_stream->pf_add = Add; + p_stream->pf_del = Del; + p_stream->pf_send = Send; + + p_stream->p_sys = NULL; + + return VLC_SUCCESS; +} + +/***************************************************************************** + * Close: + *****************************************************************************/ + +static void Close( vlc_object_t * p_this ) +{ + sout_stream_t *p_stream = (sout_stream_t*)p_this; + +} + +struct sout_stream_id_t +{ + int i_d_u_m_m_y; +}; + + +static sout_stream_id_t * Add ( sout_stream_t *p_stream, sout_format_t *p_fmt ) +{ + sout_stream_id_t *id; + + id = malloc( sizeof( sout_stream_id_t ) ); + id->i_d_u_m_m_y = 0; + + return id; +} + +static int Del ( sout_stream_t *p_stream, sout_stream_id_t *id ) +{ + free( id ); + + return VLC_SUCCESS; +} + +static int Send ( sout_stream_t *p_stream, sout_stream_id_t *id, sout_buffer_t *p_buffer ) +{ + sout_buffer_t *p_next; + + while( p_buffer ) + { + p_next = p_buffer->p_next; + + sout_BufferDelete( p_stream->p_sout, p_buffer ); + p_buffer = p_next; + } + + return VLC_SUCCESS; +} + diff --git a/modules/stream_out/duplicate.c b/modules/stream_out/duplicate.c new file mode 100644 index 0000000000..f74a3553c6 --- /dev/null +++ b/modules/stream_out/duplicate.c @@ -0,0 +1,211 @@ +/***************************************************************************** + * duplicate.c + ***************************************************************************** + * Copyright (C) 2001, 2002 VideoLAN + * $Id: duplicate.c,v 1.1 2003/04/13 20:00:21 fenrir Exp $ + * + * Authors: Laurent Aimar + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + *****************************************************************************/ + +/***************************************************************************** + * Preamble + *****************************************************************************/ +#include +#include + +#include +#include + +/***************************************************************************** + * Exported prototypes + *****************************************************************************/ +static int Open ( vlc_object_t * ); +static void Close ( vlc_object_t * ); + +static sout_stream_id_t *Add ( sout_stream_t *, sout_format_t * ); +static int Del ( sout_stream_t *, sout_stream_id_t * ); +static int Send( sout_stream_t *, sout_stream_id_t *, sout_buffer_t* ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( _("Duplicate stream") ); + set_capability( "sout stream", 50 ); + add_shortcut( "duplicate" ); + add_shortcut( "dup" ); + set_callbacks( Open, Close ); +vlc_module_end(); + + +struct sout_stream_sys_t +{ + int i_nb_streams; + sout_stream_t **pp_streams; +}; + +struct sout_stream_id_t +{ + int i_nb_ids; + void **pp_ids; +}; + +/***************************************************************************** + * Open: + *****************************************************************************/ +static int Open( vlc_object_t *p_this ) +{ + sout_stream_t *p_stream = (sout_stream_t*)p_this; + sout_stream_sys_t *p_sys; + sout_cfg_t *p_cfg; + + msg_Dbg( p_stream, "creating a duplication" ); + + p_sys = malloc( sizeof( sout_stream_sys_t ) ); + p_sys->i_nb_streams = 0; + p_sys->pp_streams = NULL; + + for( p_cfg = p_stream->p_cfg; p_cfg != NULL; p_cfg = p_cfg->p_next ) + { + if( !strncmp( p_cfg->psz_name, "dst", strlen( "dst" ) ) ) + { + sout_stream_t *s; + + msg_Dbg( p_stream, " * adding `%s'", p_cfg->psz_value ); + s = sout_stream_new( p_stream->p_sout, p_cfg->psz_value ); + + TAB_APPEND( p_sys->i_nb_streams, p_sys->pp_streams, s ); + } + } + + if( p_sys->i_nb_streams == 0 ) + { + msg_Err( p_stream, "no destination given" ); + free( p_sys ); + + return VLC_EGENERIC; + } + + p_stream->pf_add = Add; + p_stream->pf_del = Del; + p_stream->pf_send = Send; + + p_stream->p_sys = p_sys; + + return VLC_SUCCESS; +} + +/***************************************************************************** + * Close: + *****************************************************************************/ + +static void Close( vlc_object_t * p_this ) +{ + sout_stream_t *p_stream = (sout_stream_t*)p_this; + sout_stream_sys_t *p_sys = p_stream->p_sys; + + int i; + + msg_Dbg( p_stream, "closing a duplication" ); + for( i = 0; i < p_sys->i_nb_streams; i++ ) + { + sout_stream_delete( p_sys->pp_streams[i] ); + } + free( p_sys->pp_streams ); + + free( p_sys ); +} + + + +static sout_stream_id_t * Add ( sout_stream_t *p_stream, sout_format_t *p_fmt ) +{ + sout_stream_sys_t *p_sys = p_stream->p_sys; + sout_stream_id_t *id; + int i_stream; + + id = malloc( sizeof( sout_stream_id_t ) ); + id->i_nb_ids = 0; + id->pp_ids = NULL; + + for( i_stream = 0; i_stream < p_sys->i_nb_streams; i_stream++ ) + { + void *id_new; + + /* XXX not the same sout_stream_id_t definition ... */ + id_new = (void*)p_sys->pp_streams[i_stream]->pf_add( p_sys->pp_streams[i_stream], p_fmt ); + TAB_APPEND( id->i_nb_ids, id->pp_ids, id_new ); + } + + if( id->i_nb_ids <= 0 ) + { + free( id ); + return NULL; + } + + return id; +} + +static int Del ( sout_stream_t *p_stream, sout_stream_id_t *id ) +{ + sout_stream_sys_t *p_sys = p_stream->p_sys; + int i_stream; + + for( i_stream = 0; i_stream < p_sys->i_nb_streams; i_stream++ ) + { + if( id->pp_ids[i_stream] ) + { + p_sys->pp_streams[i_stream]->pf_del( p_sys->pp_streams[i_stream], + id->pp_ids[i_stream] ); + } + } + + free( id->pp_ids ); + free( id ); + return VLC_SUCCESS; +} + +static int Send ( sout_stream_t *p_stream, sout_stream_id_t *id, sout_buffer_t *p_buffer ) +{ + sout_stream_sys_t *p_sys = p_stream->p_sys; + int i_stream; + + for( i_stream = 0; i_stream < p_sys->i_nb_streams - 1; i_stream++ ) + { + sout_buffer_t *p_dup; + + if( id->pp_ids[i_stream] ) + { + p_dup = sout_BufferDuplicate( p_stream->p_sout, p_buffer ); + + p_sys->pp_streams[i_stream]->pf_send( p_sys->pp_streams[i_stream], + id->pp_ids[i_stream], + p_dup ); + } + } + + i_stream = p_sys->i_nb_streams - 1; + if( id->pp_ids[i_stream] ) + { + p_sys->pp_streams[i_stream]->pf_send( p_sys->pp_streams[i_stream], + id->pp_ids[i_stream], + p_buffer); + } + + return VLC_SUCCESS; +} + diff --git a/modules/stream_out/es.c b/modules/stream_out/es.c new file mode 100644 index 0000000000..0ddac410af --- /dev/null +++ b/modules/stream_out/es.c @@ -0,0 +1,326 @@ +/***************************************************************************** + * es.c + ***************************************************************************** + * Copyright (C) 2001, 2002 VideoLAN + * $Id: es.c,v 1.1 2003/04/13 20:00:21 fenrir Exp $ + * + * Authors: Laurent Aimar + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + *****************************************************************************/ + +/***************************************************************************** + * Preamble + *****************************************************************************/ +#include +#include + +#include +#include +#include + +#define FREE( p ) if( p ) { free( p ); (p) = NULL; } +/***************************************************************************** + * Exported prototypes + *****************************************************************************/ +static int Open ( vlc_object_t * ); +static void Close ( vlc_object_t * ); + +static sout_stream_id_t *Add ( sout_stream_t *, sout_format_t * ); +static int Del ( sout_stream_t *, sout_stream_id_t * ); +static int Send( sout_stream_t *, sout_stream_id_t *, sout_buffer_t* ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( _("ES stream") ); + set_capability( "sout stream", 50 ); + add_shortcut( "es" ); + add_shortcut( "es" ); + set_callbacks( Open, Close ); +vlc_module_end(); + +struct sout_stream_sys_t +{ + int i_count_audio; + int i_count_video; + int i_count; + + char *psz_mux; + char *psz_mux_audio; + char *psz_mux_video; + + char *psz_access; + char *psz_access_audio; + char *psz_access_video; + + char *psz_url; + char *psz_url_audio; + char *psz_url_video; +}; + +/***************************************************************************** + * Open: + *****************************************************************************/ +static int Open( vlc_object_t *p_this ) +{ + sout_stream_t *p_stream = (sout_stream_t*)p_this; + sout_stream_sys_t *p_sys; + + //p_sout->i_preheader = __MAX( p_sout->i_preheader, p_mux->i_preheader ); + + p_sys = malloc( sizeof( sout_stream_sys_t ) ); + + p_sys->i_count = 0; + p_sys->i_count_audio = 0; + p_sys->i_count_video = 0; + + p_sys->psz_access = sout_cfg_find_value( p_stream->p_cfg, "access" ); + p_sys->psz_access_audio = sout_cfg_find_value( p_stream->p_cfg, "acesss_audio" ); + p_sys->psz_access_video = sout_cfg_find_value( p_stream->p_cfg, "access_video" ); + + + p_sys->psz_mux = sout_cfg_find_value( p_stream->p_cfg, "mux" ); + p_sys->psz_mux_audio = sout_cfg_find_value( p_stream->p_cfg, "mux_audio" ); + p_sys->psz_mux_video = sout_cfg_find_value( p_stream->p_cfg, "mux_video" ); + + p_sys->psz_url = sout_cfg_find_value( p_stream->p_cfg, "url" ); + p_sys->psz_url_audio = sout_cfg_find_value( p_stream->p_cfg, "url_audio" ); + p_sys->psz_url_video = sout_cfg_find_value( p_stream->p_cfg, "url_video" ); + + p_stream->pf_add = Add; + p_stream->pf_del = Del; + p_stream->pf_send = Send; + + p_stream->p_sys = p_sys; + + return VLC_SUCCESS; +} + +/***************************************************************************** + * Close: + *****************************************************************************/ + +static void Close( vlc_object_t * p_this ) +{ + sout_stream_t *p_stream = (sout_stream_t*)p_this; + sout_stream_sys_t *p_sys = p_stream->p_sys; + + free( p_sys ); +} + +struct sout_stream_id_t +{ + sout_input_t *p_input; + sout_mux_t *p_mux; +}; + +static char * es_print_url( char *psz_fmt, vlc_fourcc_t i_fourcc, int i_count, char *psz_access, char *psz_mux ) +{ + char *psz_url, *p; + + if( psz_fmt == NULL || !*psz_fmt ) + { + psz_fmt = "stream-%n-%c.%m"; + } + + p = psz_url = malloc( 4096 ); + memset( p, 0, 4096 ); + for( ;; ) + { + if( *psz_fmt == '\0' ) + { + *p = '\0'; + break; + } + + if( *psz_fmt != '%' ) + { + *p++ = *psz_fmt++; + } + else + { + if( psz_fmt[1] == 'n' ) + { + p += sprintf( p, "%d", i_count ); + } + else if( psz_fmt[1] == 'c' ) + { + p += sprintf( p, "%4.4s", (char*)&i_fourcc ); + } + else if( psz_fmt[1] == 'm' ) + { + p += sprintf( p, "%s", psz_mux ); + } + else if( psz_fmt[1] == 'a' ) + { + p += sprintf( p, "%s", psz_access ); + } + else if( psz_fmt[1] != '\0' ) + { + p += sprintf( p, "%c%c", psz_fmt[0], psz_fmt[1] ); + } + else + { + p += sprintf( p, "%c", psz_fmt[0] ); + *p++ = '\0'; + break; + } + psz_fmt += 2; + } + } + + return( psz_url ); +} + +static sout_stream_id_t * Add ( sout_stream_t *p_stream, sout_format_t *p_fmt ) +{ + sout_stream_sys_t *p_sys = p_stream->p_sys; + sout_instance_t *p_sout = p_stream->p_sout; + sout_stream_id_t *id; + + char *psz_access; + char *psz_mux; + char *psz_url; + + sout_access_out_t *p_access; + sout_mux_t *p_mux; + + /* *** get access name *** */ + if( p_fmt->i_cat == AUDIO_ES && p_sys->psz_access_audio ) + { + psz_access = p_sys->psz_access_audio; + } + else if( p_fmt->i_cat == VIDEO_ES && p_sys->psz_access_video ) + { + psz_access = p_sys->psz_access_video; + } + else + { + psz_access = p_sys->psz_access; + } + + /* *** get mux name *** */ + if( p_fmt->i_cat == AUDIO_ES && p_sys->psz_mux_audio ) + { + psz_mux = p_sys->psz_mux_audio; + } + else if( p_fmt->i_cat == VIDEO_ES && p_sys->psz_mux_video ) + { + psz_mux = p_sys->psz_mux_video; + } + else + { + psz_mux = p_sys->psz_mux; + } + + /* *** get url (%d expanded as a codec count, %c expanded as codec fcc ) *** */ + if( p_fmt->i_cat == AUDIO_ES && p_sys->psz_url_audio ) + { + psz_url = es_print_url( p_sys->psz_url_audio, p_fmt->i_fourcc, p_sys->i_count_audio, psz_access, psz_mux ); + } + else if( p_fmt->i_cat == VIDEO_ES && p_sys->psz_url_video ) + { + psz_url = es_print_url( p_sys->psz_url_video, p_fmt->i_fourcc, p_sys->i_count_video, psz_access, psz_mux ); + } + else + { + int i_count; + if( p_fmt->i_cat == VIDEO_ES ) + { + i_count = p_sys->i_count_video; + } + else if( p_fmt->i_cat == AUDIO_ES ) + { + i_count = p_sys->i_count_audio; + } + else + { + i_count = p_sys->i_count; + } + + psz_url = es_print_url( p_sys->psz_url, p_fmt->i_fourcc, i_count, psz_access, psz_mux ); + } + + p_sys->i_count++; + if( p_fmt->i_cat == VIDEO_ES ) + { + p_sys->i_count_video++; + } + else if( p_fmt->i_cat == AUDIO_ES ) + { + p_sys->i_count_audio++; + } + msg_Dbg( p_stream, "creating `%s/%s://%s'", + psz_access, psz_mux, psz_url ); + + /* *** find and open appropriate access module *** */ + p_access = sout_AccessOutNew( p_sout, psz_access, psz_url ); + if( p_access == NULL ) + { + msg_Err( p_stream, "no suitable sout access module for `%s/%s://%s'", + psz_access, psz_mux, psz_url ); + return( NULL ); + } + + /* *** find and open appropriate mux module *** */ + p_mux = sout_MuxNew( p_sout, psz_mux, p_access ); + if( p_mux == NULL ) + { + msg_Err( p_stream, "no suitable sout mux module for `%s/%s://%s'", + psz_access, psz_mux, psz_url ); + sout_AccessOutDelete( p_access ); + return( NULL ); + } + + /* XXX beurk */ + p_sout->i_preheader = __MAX( p_sout->i_preheader, p_mux->i_preheader ); + + id = malloc( sizeof( sout_stream_id_t ) ); + id->p_mux = p_mux; + id->p_input = sout_MuxAddStream( p_mux, p_fmt ); + + if( id->p_input == NULL ) + { + free( id ); + + sout_MuxDelete( p_mux ); + sout_AccessOutDelete( p_access ); + free( id ); + return NULL; + } + + return id; +} + +static int Del ( sout_stream_t *p_stream, sout_stream_id_t *id ) +{ + sout_access_out_t *p_access = id->p_mux->p_access; + + sout_MuxDeleteStream( id->p_mux, id->p_input ); + sout_AccessOutDelete( p_access ); + + free( id ); + return VLC_SUCCESS; +} + +static int Send ( sout_stream_t *p_stream, sout_stream_id_t *id, sout_buffer_t *p_buffer ) +{ + sout_MuxSendBuffer( id->p_mux, id->p_input, p_buffer ); + + return VLC_SUCCESS; +} + diff --git a/modules/stream_out/standard.c b/modules/stream_out/standard.c new file mode 100644 index 0000000000..9cb5664ffe --- /dev/null +++ b/modules/stream_out/standard.c @@ -0,0 +1,174 @@ +/***************************************************************************** + * standard.c + ***************************************************************************** + * Copyright (C) 2001, 2002 VideoLAN + * $Id: standard.c,v 1.1 2003/04/13 20:00:21 fenrir Exp $ + * + * Authors: Laurent Aimar + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + *****************************************************************************/ + +/***************************************************************************** + * Preamble + *****************************************************************************/ +#include +#include + +#include +#include + +/***************************************************************************** + * Exported prototypes + *****************************************************************************/ +static int Open ( vlc_object_t * ); +static void Close ( vlc_object_t * ); + +static sout_stream_id_t *Add ( sout_stream_t *, sout_format_t * ); +static int Del ( sout_stream_t *, sout_stream_id_t * ); +static int Send( sout_stream_t *, sout_stream_id_t *, sout_buffer_t* ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( _("Standard stream") ); + set_capability( "sout stream", 50 ); + add_shortcut( "standard" ); + add_shortcut( "std" ); + set_callbacks( Open, Close ); +vlc_module_end(); + +struct sout_stream_sys_t +{ + sout_mux_t *p_mux; +}; + +/***************************************************************************** + * Open: + *****************************************************************************/ +static int Open( vlc_object_t *p_this ) +{ + sout_stream_t *p_stream = (sout_stream_t*)p_this; + sout_instance_t *p_sout = p_stream->p_sout; + sout_stream_sys_t *p_sys; + + char *psz_mux = sout_cfg_find_value( p_stream->p_cfg, "mux" ); + char *psz_access = sout_cfg_find_value( p_stream->p_cfg, "access" ); + char *psz_url = sout_cfg_find_value( p_stream->p_cfg, "url" ); + + sout_access_out_t *p_access; + sout_mux_t *p_mux; + + msg_Dbg( p_this, "creating `%s/%s://%s'", + psz_access, psz_mux, psz_url ); + + /* *** find and open appropriate access module *** */ + p_access = sout_AccessOutNew( p_sout, psz_access, psz_url ); + if( p_access == NULL ) + { + msg_Err( p_stream, "no suitable sout access module for `%s/%s://%s'", + psz_access, psz_mux, psz_url ); + return( VLC_EGENERIC ); + } + msg_Dbg( p_stream, "access opened" ); + + /* *** find and open appropriate mux module *** */ + p_mux = sout_MuxNew( p_sout, psz_mux, p_access ); + if( p_mux == NULL ) + { + msg_Err( p_stream, "no suitable sout mux module for `%s/%s://%s'", + psz_access, psz_mux, psz_url ); + + sout_AccessOutDelete( p_access ); + return( VLC_EGENERIC ); + } + msg_Dbg( p_stream, "mux opened" ); + + /* XXX beurk */ + p_sout->i_preheader = __MAX( p_sout->i_preheader, p_mux->i_preheader ); + + p_sys = malloc( sizeof( sout_stream_sys_t ) ); + p_sys->p_mux = p_mux; + + p_stream->pf_add = Add; + p_stream->pf_del = Del; + p_stream->pf_send = Send; + + p_stream->p_sys = p_sys; + + return VLC_SUCCESS; +} + +/***************************************************************************** + * Close: + *****************************************************************************/ + +static void Close( vlc_object_t * p_this ) +{ + sout_stream_t *p_stream = (sout_stream_t*)p_this; + sout_stream_sys_t *p_sys = p_stream->p_sys; + + sout_access_out_t *p_access = p_sys->p_mux->p_access; + + + sout_MuxDelete( p_sys->p_mux ); + sout_AccessOutDelete( p_access ); + + free( p_sys ); +} + +struct sout_stream_id_t +{ + sout_input_t *p_input; +}; + + +static sout_stream_id_t * Add ( sout_stream_t *p_stream, sout_format_t *p_fmt ) +{ + sout_stream_sys_t *p_sys = p_stream->p_sys; + sout_stream_id_t *id; + + id = malloc( sizeof( sout_stream_id_t ) ); + if( ( id->p_input = sout_MuxAddStream( p_sys->p_mux, p_fmt ) ) == NULL ) + { + free( id ); + + return NULL; + } + + return id; +} + +static int Del ( sout_stream_t *p_stream, sout_stream_id_t *id ) +{ + sout_stream_sys_t *p_sys = p_stream->p_sys; + + sout_MuxDeleteStream( p_sys->p_mux, id->p_input ); + + free( id ); + + return VLC_SUCCESS; +} + +static int Send ( sout_stream_t *p_stream, sout_stream_id_t *id, sout_buffer_t *p_buffer ) +{ + sout_stream_sys_t *p_sys = p_stream->p_sys; + + sout_MuxSendBuffer( p_sys->p_mux, id->p_input, p_buffer ); + + return VLC_SUCCESS; +} + diff --git a/modules/stream_out/transcode.c b/modules/stream_out/transcode.c new file mode 100644 index 0000000000..ded022d608 --- /dev/null +++ b/modules/stream_out/transcode.c @@ -0,0 +1,940 @@ +/***************************************************************************** + * transcode.c + ***************************************************************************** + * Copyright (C) 2001, 2002 VideoLAN + * $Id: transcode.c,v 1.1 2003/04/13 20:00:21 fenrir Exp $ + * + * Authors: Laurent Aimar + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + *****************************************************************************/ + +/***************************************************************************** + * Preamble + *****************************************************************************/ +#include +#include + +#include +#include +#include + +#include "/home/fenrir/videolan/ffmpeg/libavcodec/avcodec.h" + +/***************************************************************************** + * Exported prototypes + *****************************************************************************/ +static int Open ( vlc_object_t * ); +static void Close ( vlc_object_t * ); + +static sout_stream_id_t *Add ( sout_stream_t *, sout_format_t * ); +static int Del ( sout_stream_t *, sout_stream_id_t * ); +static int Send( sout_stream_t *, sout_stream_id_t *, sout_buffer_t* ); + +static int transcode_audio_ffmpeg_new ( sout_stream_t *, sout_stream_id_t * ); +static void transcode_audio_ffmpeg_close ( sout_stream_t *, sout_stream_id_t * ); +static int transcode_audio_ffmpeg_process( sout_stream_t *, sout_stream_id_t *, sout_buffer_t *, sout_buffer_t ** ); + +static int transcode_video_ffmpeg_new ( sout_stream_t *, sout_stream_id_t * ); +static void transcode_video_ffmpeg_close ( sout_stream_t *, sout_stream_id_t * ); +static int transcode_video_ffmpeg_process( sout_stream_t *, sout_stream_id_t *, sout_buffer_t *, sout_buffer_t ** ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +vlc_module_begin(); + set_description( _("Transcode stream") ); + set_capability( "sout stream", 50 ); + add_shortcut( "transcode" ); + set_callbacks( Open, Close ); +vlc_module_end(); + +struct sout_stream_sys_t +{ + sout_stream_t *p_out; + + vlc_fourcc_t i_acodec; // codec audio (0 if not transcode) + int i_sample_rate; + int i_channels; + int i_abitrate; + + vlc_fourcc_t i_vcodec; // " video " " " " + int i_vbitrate; + int i_width; + int i_height; + vlc_bool_t b_deinterlace; + + int i_crop_top; + int i_crop_bottom; + int i_crop_right; + int i_crop_left; +}; + +/***************************************************************************** + * Open: + *****************************************************************************/ +static int Open( vlc_object_t *p_this ) +{ + sout_stream_t *p_stream = (sout_stream_t*)p_this; + sout_stream_sys_t *p_sys; + char *codec; + + p_sys = malloc( sizeof( sout_stream_sys_t ) ); + p_sys->p_out = sout_stream_new( p_stream->p_sout, p_stream->psz_next ); + + p_sys->i_acodec = 0; + p_sys->i_sample_rate = 0; + p_sys->i_channels = 0; + p_sys->i_abitrate = 0; + + p_sys->i_vcodec = 0; + p_sys->i_vbitrate = 0; + p_sys->i_width = 0; + p_sys->i_height = 0; + p_sys->b_deinterlace= VLC_FALSE; + + p_sys->i_crop_top = 0; + p_sys->i_crop_bottom= 0; + p_sys->i_crop_right = 0; + p_sys->i_crop_left = 0; + + if( ( codec = sout_cfg_find_value( p_stream->p_cfg, "acodec" ) ) ) + { + char fcc[4] = " "; + char *val; + + memcpy( fcc, codec, strlen( codec ) ); + + p_sys->i_acodec = VLC_FOURCC( fcc[0], fcc[1], fcc[2], fcc[3] ); + + if( ( val = sout_cfg_find_value( p_stream->p_cfg, "samplerate" ) ) ) + { + p_sys->i_sample_rate = atoi( val ); + } + if( ( val = sout_cfg_find_value( p_stream->p_cfg, "channels" ) ) ) + { + p_sys->i_channels = atoi( val ); + } + if( ( val = sout_cfg_find_value( p_stream->p_cfg, "ab" ) ) ) + { + p_sys->i_abitrate = atoi( val ); + } + + msg_Dbg( p_stream, "codec audio=%4.4s %dHz %d channels %dKb/s", + fcc, + p_sys->i_sample_rate, p_sys->i_channels, + p_sys->i_abitrate / 1024 ); + } + + if( ( codec = sout_cfg_find_value( p_stream->p_cfg, "vcodec" ) ) ) + { + char fcc[4] = " "; + char *val; + + memcpy( fcc, codec, strlen( codec ) ); + + p_sys->i_vcodec = VLC_FOURCC( fcc[0], fcc[1], fcc[2], fcc[3] ); + + if( ( val = sout_cfg_find_value( p_stream->p_cfg, "width" ) ) ) + { + p_sys->i_width = atoi( val ); + } + if( ( val = sout_cfg_find_value( p_stream->p_cfg, "height" ) ) ) + { + p_sys->i_height = atoi( val ); + } + if( ( val = sout_cfg_find_value( p_stream->p_cfg, "vb" ) ) ) + { + p_sys->i_vbitrate = atoi( val ); + } + if( sout_cfg_find( p_stream->p_cfg, "deinterlace" ) ) + { + p_sys->b_deinterlace = VLC_TRUE; + } + /* crop */ + if( ( val = sout_cfg_find_value( p_stream->p_cfg, "croptop" ) ) ) + { + p_sys->i_crop_top = atoi( val ); + } + if( ( val = sout_cfg_find_value( p_stream->p_cfg, "cropbottom" ) ) ) + { + p_sys->i_crop_bottom = atoi( val ); + } + if( ( val = sout_cfg_find_value( p_stream->p_cfg, "cropleft" ) ) ) + { + p_sys->i_crop_left = atoi( val ); + } + if( ( val = sout_cfg_find_value( p_stream->p_cfg, "cropright" ) ) ) + { + p_sys->i_crop_right = atoi( val ); + } + + msg_Dbg( p_stream, "codec video=%4.4s %dx%d %dkb/s", + fcc, + p_sys->i_width, p_sys->i_height, + p_sys->i_vbitrate / 1024 ); + } + + if( !p_sys->p_out ) + { + msg_Err( p_stream, "cannot create chain" ); + free( p_sys ); + return VLC_EGENERIC; + } + p_stream->pf_add = Add; + p_stream->pf_del = Del; + p_stream->pf_send = Send; + + p_stream->p_sys = p_sys; + + avcodec_init(); + avcodec_register_all(); + + return VLC_SUCCESS; +} + +/***************************************************************************** + * Close: + *****************************************************************************/ + +static void Close( vlc_object_t * p_this ) +{ + sout_stream_t *p_stream = (sout_stream_t*)p_this; + sout_stream_sys_t *p_sys = p_stream->p_sys; + + sout_stream_delete( p_sys->p_out ); + free( p_sys ); +} + +struct sout_stream_id_t +{ + vlc_fourcc_t b_transcode; + sout_format_t f_src; // only if transcoding + sout_format_t f_dst; // " " " + + /* id of the out stream */ + void *id; + + /* ffmpeg part */ + AVCodec *ff_dec; + AVCodecContext *ff_dec_c; + + + vlc_fourcc_t b_enc_inited; + AVCodec *ff_enc; + AVCodecContext *ff_enc_c; + + mtime_t i_dts; + mtime_t i_length; + + int i_buffer_in; + int i_buffer_in_pos; + uint8_t *p_buffer_in; + + int i_buffer; + int i_buffer_pos; + uint8_t *p_buffer; + + int i_buffer_out; + int i_buffer_out_pos; + uint8_t *p_buffer_out; + + AVFrame *p_ff_pic; + AVFrame *p_ff_pic_tmp0; // to do deinterlace + AVFrame *p_ff_pic_tmp1; // to do pix conversion + AVFrame *p_ff_pic_tmp2; // to do resample + + ImgReSampleContext *p_vresample; +}; + + +static sout_stream_id_t * Add ( sout_stream_t *p_stream, sout_format_t *p_fmt ) +{ + sout_stream_sys_t *p_sys = p_stream->p_sys; + sout_stream_id_t *id; + + id = malloc( sizeof( sout_stream_id_t ) ); + id->i_dts = 0; + if( p_fmt->i_cat == AUDIO_ES && p_sys->i_acodec != 0 ) + { + msg_Dbg( p_stream, + "creating audio transcoding from fcc=`%4.4s' to fcc=`%4.4s'", + (char*)&p_fmt->i_fourcc, + (char*)&p_sys->i_acodec ); + + /* src format */ + memcpy( &id->f_src, p_fmt, sizeof( sout_format_t ) ); + + /* create dst format */ + id->f_dst.i_cat = AUDIO_ES; + id->f_dst.i_fourcc = p_sys->i_acodec; + id->f_dst.i_sample_rate = p_sys->i_sample_rate > 0 ? p_sys->i_sample_rate : id->f_src.i_sample_rate; + id->f_dst.i_channels = p_sys->i_channels > 0 ? p_sys->i_channels : id->f_src.i_channels; + id->f_dst.i_bitrate = p_sys->i_abitrate > 0 ? p_sys->i_abitrate : 64000; + id->f_dst.i_block_align = 0; + id->f_dst.i_extra_data = 0; + id->f_dst.p_extra_data = NULL; + + /* build decoder -> filter -> encoder */ + if( transcode_audio_ffmpeg_new( p_stream, id ) ) + { + msg_Err( p_stream, "cannot create audio chain" ); + free( id ); + return NULL; + } + + /* open output stream */ + id->id = p_sys->p_out->pf_add( p_sys->p_out, &id->f_dst ); + id->b_transcode = VLC_TRUE; + } + else if( p_fmt->i_cat == VIDEO_ES && p_sys->i_vcodec != 0 ) + { + msg_Dbg( p_stream, + "creating video transcoding from fcc=`%4.4s' to fcc=`%4.4s'", + (char*)&p_fmt->i_fourcc, + (char*)&p_sys->i_vcodec ); + + memcpy( &id->f_src, p_fmt, sizeof( sout_format_t ) ); + + /* create dst format */ + id->f_dst.i_cat = VIDEO_ES; + id->f_dst.i_fourcc = p_sys->i_vcodec; + id->f_dst.i_width = p_sys->i_width ; //> 0 ? p_sys->i_width : id->f_src.i_width; + id->f_dst.i_height = p_sys->i_height; // > 0 ? p_sys->i_height: id->f_src.i_height; + id->f_dst.i_bitrate = p_sys->i_vbitrate > 0 ? p_sys->i_vbitrate : 800*1000; + id->f_dst.i_extra_data = 0; + id->f_dst.p_extra_data = NULL; + + /* build decoder -> filter -> encoder */ + if( transcode_video_ffmpeg_new( p_stream, id ) ) + { + msg_Err( p_stream, "cannot create video chain" ); + free( id ); + return NULL; + } + + /* open output stream */ + id->id = p_sys->p_out->pf_add( p_sys->p_out, &id->f_dst ); + id->b_transcode = VLC_TRUE; + } + else + { + msg_Dbg( p_stream, "not transcoding a stream (fcc=`%4.4s')", (char*)&p_fmt->i_fourcc ); + id->id = p_sys->p_out->pf_add( p_sys->p_out, p_fmt ); + id->b_transcode = VLC_FALSE; + + if( id->id == NULL ) + { + free( id ); + return NULL; + } + } + + return id; +} + +static int Del ( sout_stream_t *p_stream, sout_stream_id_t *id ) +{ + sout_stream_sys_t *p_sys = p_stream->p_sys; + + if( id->b_transcode ) + { + if( id->f_src.i_cat == AUDIO_ES ) + { + transcode_audio_ffmpeg_close( p_stream, id ); + } + else if( id->f_src.i_cat == VIDEO_ES ) + { + transcode_video_ffmpeg_close( p_stream, id ); + } + } + + p_sys->p_out->pf_del( p_sys->p_out, id->id ); + free( id ); + + return VLC_SUCCESS; +} + +static int Send ( sout_stream_t *p_stream, sout_stream_id_t *id, sout_buffer_t *p_buffer ) +{ + sout_stream_sys_t *p_sys = p_stream->p_sys; + + if( id->b_transcode ) + { + sout_buffer_t *p_buffer_out; + if( id->f_src.i_cat == AUDIO_ES ) + { + transcode_audio_ffmpeg_process( p_stream, id, p_buffer, &p_buffer_out ); + } + else if( id->f_src.i_cat == VIDEO_ES ) + { + transcode_video_ffmpeg_process( p_stream, id, p_buffer, &p_buffer_out ); + } + sout_BufferDelete( p_stream->p_sout, p_buffer ); + + if( p_buffer_out ) + { + return p_sys->p_out->pf_send( p_sys->p_out, id->id, p_buffer_out ); + } + return VLC_SUCCESS; + } + else + { + return p_sys->p_out->pf_send( p_sys->p_out, id->id, p_buffer ); + } +} + +/**************************************************************************** + * ffmpeg decoder reencocdr part + ****************************************************************************/ + +static struct +{ + vlc_fourcc_t i_fcc; + int i_ff_codec; +} fourcc_to_ff_code[] = +{ + /* audio */ + { VLC_FOURCC( 'm', 'p', 'g', 'a' ), CODEC_ID_MP2 }, + { VLC_FOURCC( 'a', '5', '2', ' ' ), CODEC_ID_AC3 }, + { VLC_FOURCC( 'a', 'c', '3', ' ' ), CODEC_ID_AC3 }, + { VLC_FOURCC( 'w', 'm', 'a', '1' ), CODEC_ID_WMAV1 }, + { VLC_FOURCC( 'w', 'm', 'a', '2' ), CODEC_ID_WMAV2 }, + + /* video */ + { VLC_FOURCC( 'm', 'p', '4', 'v'), CODEC_ID_MPEG4 }, + { VLC_FOURCC( 'm', 'p', 'g', 'v' ), CODEC_ID_MPEG1VIDEO }, + { VLC_FOURCC( 'D', 'I', 'V', '1' ), CODEC_ID_MSMPEG4V1 }, + { VLC_FOURCC( 'D', 'I', 'V', '2' ), CODEC_ID_MSMPEG4V2 }, + { VLC_FOURCC( 'D', 'I', 'V', '3' ), CODEC_ID_MSMPEG4V3 }, + { VLC_FOURCC( 'H', '2', '6', '3' ), CODEC_ID_H263 }, + { VLC_FOURCC( 'I', '2', '6', '3' ), CODEC_ID_H263I }, + { VLC_FOURCC( 'W', 'M', 'V', '1' ), CODEC_ID_WMV1 }, + { VLC_FOURCC( 'W', 'M', 'V', '2' ), CODEC_ID_WMV2 }, + { VLC_FOURCC( 'M', 'J', 'P', 'G' ), CODEC_ID_MJPEG }, + { VLC_FOURCC( 'm', 'j', 'p', 'b' ), CODEC_ID_MJPEGB }, + { VLC_FOURCC( 'd', 'v', 's', 'l' ), CODEC_ID_DVVIDEO }, + { VLC_FOURCC( 'S', 'V', 'Q', '1' ), CODEC_ID_SVQ1 }, + + { VLC_FOURCC( 0, 0, 0, 0 ), 0 } +}; + +static inline int get_ff_codec( vlc_fourcc_t i_fcc ) +{ + int i; + + for( i = 0; fourcc_to_ff_code[i].i_fcc != 0; i++ ) + { + if( fourcc_to_ff_code[i].i_fcc == i_fcc ) + { + return fourcc_to_ff_code[i].i_ff_codec; + } + } + + return 0; +} + +static int transcode_audio_ffmpeg_new ( sout_stream_t *p_stream, sout_stream_id_t *id ) +{ + int i_ff_codec; + + /* find decoder */ + + i_ff_codec = get_ff_codec( id->f_src.i_fourcc ); + if( i_ff_codec == 0 ) + { + msg_Err( p_stream, "cannot find decoder" ); + return VLC_EGENERIC; + } + + id->ff_dec = avcodec_find_decoder( i_ff_codec ); + if( !id->ff_dec ) + { + msg_Err( p_stream, "cannot find decoder" ); + return VLC_EGENERIC; + } + + id->ff_dec_c = avcodec_alloc_context(); + id->ff_dec_c->sample_rate = id->f_src.i_sample_rate; + id->ff_dec_c->channels = id->f_src.i_channels; + id->ff_dec_c->block_align = id->f_src.i_block_align; + id->ff_dec_c->bit_rate = id->f_src.i_bitrate; + + id->ff_dec_c->extradata_size = id->f_src.i_extra_data; + id->ff_dec_c->extradata = id->f_src.p_extra_data; + if( avcodec_open( id->ff_dec_c, id->ff_dec ) ) + { + msg_Err( p_stream, "cannot open decoder" ); + return VLC_EGENERIC; + } + + /* find encoder */ + i_ff_codec = get_ff_codec( id->f_dst.i_fourcc ); + if( i_ff_codec == 0 ) + { + msg_Err( p_stream, "cannot find encoder" ); + return VLC_EGENERIC; + } + + id->ff_enc = avcodec_find_encoder( i_ff_codec ); + if( !id->ff_enc ) + { + msg_Err( p_stream, "cannot find encoder" ); + return VLC_EGENERIC; + } + + id->ff_enc_c = avcodec_alloc_context(); + id->ff_enc_c->bit_rate = id->f_dst.i_bitrate; + id->ff_enc_c->sample_rate = id->f_dst.i_sample_rate; + id->ff_enc_c->channels = id->f_dst.i_channels; + + if( avcodec_open( id->ff_enc_c, id->ff_enc ) ) + { + msg_Err( p_stream, "cannot open encoder" ); + return VLC_EGENERIC; + } + + + id->i_buffer_in = AVCODEC_MAX_AUDIO_FRAME_SIZE; + id->i_buffer_in_pos = 0; + id->p_buffer_in = malloc( id->i_buffer_in ); + + id->i_buffer = AVCODEC_MAX_AUDIO_FRAME_SIZE; + id->i_buffer_pos = 0; + id->p_buffer = malloc( id->i_buffer ); + + id->i_buffer_out = AVCODEC_MAX_AUDIO_FRAME_SIZE; + id->i_buffer_out_pos = 0; + id->p_buffer_out = malloc( id->i_buffer_out ); + + return VLC_SUCCESS; +} + +static void transcode_audio_ffmpeg_close ( sout_stream_t *p_stream, sout_stream_id_t *id ) +{ + avcodec_close( id->ff_dec_c ); + avcodec_close( id->ff_enc_c ); + + free( id->ff_dec_c ); + free( id->ff_enc_c ); + + free( id->p_buffer ); +} + +static int transcode_audio_ffmpeg_process( sout_stream_t *p_stream, sout_stream_id_t *id, + sout_buffer_t *in, sout_buffer_t **out ) +{ + *out = NULL; + + /* gather data into p_buffer_in */ + id->i_dts = in->i_dts - + (mtime_t)1000000 * + (mtime_t)(id->i_buffer_pos / 2 / id->ff_enc_c->channels )/ + (mtime_t)id->ff_enc_c->sample_rate; + + memcpy( &id->p_buffer_in[id->i_buffer_in_pos], + in->p_buffer, + in->i_size ); + id->i_buffer_in_pos += in->i_size; + + /* decode as many data as possible */ + for( ;; ) + { + int i_buffer_size; + int i_used; + + i_buffer_size = id->i_buffer - id->i_buffer_pos; + + i_used = avcodec_decode_audio( id->ff_dec_c, + (int16_t*)&id->p_buffer[id->i_buffer_pos], &i_buffer_size, + id->p_buffer_in, id->i_buffer_in_pos ); + + //msg_Warn( p_stream, "avcodec_decode_audio: %d used", i_used ); + id->i_buffer_pos += i_buffer_size; + + if( i_used < 0 ) + { + msg_Warn( p_stream, "error"); + id->i_buffer_in_pos = 0; + break; + } + else if( i_used < id->i_buffer_in_pos ) + { + memmove( id->p_buffer_in, + &id->p_buffer_in[i_used], + id->i_buffer_in - i_used ); + id->i_buffer_in_pos -= i_used; + } + else + { + id->i_buffer_in_pos = 0; + break; + } + } + + /* encode as many data as possible */ + for( ;; ) + { + int i_frame_size = id->ff_enc_c->frame_size * 2 * id->ff_enc_c->channels; + int i_out_size; + sout_buffer_t *p_out; + + if( id->i_buffer_pos < i_frame_size ) + { + break; + } + + //msg_Warn( p_stream, "avcodec_encode_audio: frame size%d", i_frame_size); + i_out_size = avcodec_encode_audio( id->ff_enc_c, + id->p_buffer_out, id->i_buffer_out, + (int16_t*)id->p_buffer ); + + if( i_out_size <= 0 ) + { + break; + } + memmove( id->p_buffer, + &id->p_buffer[i_frame_size], + id->i_buffer - i_frame_size ); + id->i_buffer_pos -= i_frame_size; + + p_out = sout_BufferNew( p_stream->p_sout, i_out_size ); + memcpy( p_out->p_buffer, id->p_buffer_out, i_out_size ); + p_out->i_size = i_out_size; + p_out->i_length = (mtime_t)1000000 * (mtime_t)id->ff_enc_c->frame_size / (mtime_t)id->ff_enc_c->sample_rate; + /* FIXME */ + p_out->i_dts = id->i_dts; + p_out->i_pts = id->i_dts; + + /* update dts */ + id->i_dts += p_out->i_length; + + //msg_Warn( p_stream, "frame dts=%lld len %lld out=%d", p_out->i_dts, p_out->i_length, i_out_size ); + sout_BufferChain( out, p_out ); + } + + return VLC_SUCCESS; +} + + +/* + * video + */ +static int transcode_video_ffmpeg_new ( sout_stream_t *p_stream, sout_stream_id_t *id ) +{ + int i_ff_codec; + + /* find decoder */ + i_ff_codec = get_ff_codec( id->f_src.i_fourcc ); + if( i_ff_codec == 0 ) + { + msg_Err( p_stream, "cannot find decoder" ); + return VLC_EGENERIC; + } + + id->ff_dec = avcodec_find_decoder( i_ff_codec ); + if( !id->ff_dec ) + { + msg_Err( p_stream, "cannot find decoder" ); + return VLC_EGENERIC; + } + + id->ff_dec_c = avcodec_alloc_context(); + id->ff_dec_c->width = id->f_src.i_width; + id->ff_dec_c->height = id->f_src.i_height; + //id->ff_dec_c->bit_rate = id->f_src.i_bitrate; + id->ff_dec_c->extradata_size= id->f_src.i_extra_data; + id->ff_dec_c->extradata = id->f_src.p_extra_data; + id->ff_dec_c->workaround_bugs = FF_BUG_AUTODETECT; + id->ff_dec_c->error_resilience= -1; + if( id->ff_dec->capabilities & CODEC_CAP_TRUNCATED ) + { + id->ff_dec_c->flags |= CODEC_FLAG_TRUNCATED; + } + + if( avcodec_open( id->ff_dec_c, id->ff_dec ) < 0 ) + { + msg_Err( p_stream, "cannot open decoder" ); + return VLC_EGENERIC; + } +#if 1 + if( i_ff_codec == CODEC_ID_MPEG4 && id->ff_dec_c->extradata_size > 0 ) + { + int b_gotpicture; + AVFrame frame; + + avcodec_decode_video( id->ff_dec_c, &frame, + &b_gotpicture, + id->ff_dec_c->extradata, id->ff_dec_c->extradata_size ); + } +#endif + + /* find encoder */ + i_ff_codec = get_ff_codec( id->f_dst.i_fourcc ); + if( i_ff_codec == 0 ) + { + msg_Err( p_stream, "cannot find encoder" ); + return VLC_EGENERIC; + } + + id->ff_enc = avcodec_find_encoder( i_ff_codec ); + if( !id->ff_enc ) + { + msg_Err( p_stream, "cannot find encoder" ); + return VLC_EGENERIC; + } + + id->ff_enc_c = avcodec_alloc_context(); + id->ff_enc_c->width = id->f_dst.i_width; + id->ff_enc_c->height = id->f_dst.i_height; + id->ff_enc_c->bit_rate = id->f_dst.i_bitrate; + id->ff_enc_c->frame_rate = 25 ; // FIXME as it break mpeg + id->ff_enc_c->frame_rate_base= 1; + id->ff_enc_c->gop_size = 25; + id->ff_enc_c->qmin = 2; + id->ff_enc_c->qmax = 31; +#if 0 + /* XXX open it when we have the first frame */ + if( avcodec_open( id->ff_enc_c, id->ff_enc ) ) + { + msg_Err( p_stream, "cannot open encoder" ); + return VLC_EGENERIC; + } +#endif + id->b_enc_inited = VLC_FALSE; + id->i_buffer_in = 0; + id->i_buffer_in_pos = 0; + id->p_buffer_in = NULL; + + id->i_buffer = 3*1024*1024; + id->i_buffer_pos = 0; + id->p_buffer = malloc( id->i_buffer ); + + id->i_buffer_out = 0; + id->i_buffer_out_pos = 0; + id->p_buffer_out = NULL; + + id->p_ff_pic = avcodec_alloc_frame(); + id->p_ff_pic_tmp0 = NULL; + id->p_ff_pic_tmp1 = NULL; + id->p_ff_pic_tmp2 = NULL; + id->p_vresample = NULL; + return VLC_SUCCESS; +} + +static void transcode_video_ffmpeg_close ( sout_stream_t *p_stream, sout_stream_id_t *id ) +{ + avcodec_close( id->ff_dec_c ); + if( id->b_enc_inited ) + { + avcodec_close( id->ff_enc_c ); + } + + if( id->p_ff_pic) + { + free( id->p_ff_pic ); + } + + if( id->p_ff_pic_tmp0 ) + { + free( id->p_ff_pic_tmp0->data[0] ); + free( id->p_ff_pic_tmp0 ); + } + if( id->p_ff_pic_tmp1) + { + free( id->p_ff_pic_tmp1->data[0] ); + free( id->p_ff_pic_tmp1 ); + } + if( id->p_ff_pic_tmp2) + { + free( id->p_ff_pic_tmp2->data[0] ); + free( id->p_ff_pic_tmp2 ); + } + if( id->p_vresample ) + { + free( id->p_vresample ); + } + + free( id->ff_dec_c ); + free( id->ff_enc_c ); + + free( id->p_buffer ); +} + +static int transcode_video_ffmpeg_process( sout_stream_t *p_stream, sout_stream_id_t *id, + sout_buffer_t *in, sout_buffer_t **out ) +{ + int i_used; + int i_out; + int b_gotpicture; + AVFrame *frame; + + int i_data; + uint8_t *p_data; + + *out = NULL; + + i_data = in->i_size; + p_data = in->p_buffer; + + for( ;; ) + { + /* decode frame */ + frame = id->p_ff_pic; + i_used = avcodec_decode_video( id->ff_dec_c, frame, + &b_gotpicture, + p_data, i_data ); + + if( i_used < 0 ) + { + msg_Warn( p_stream, "error"); + return VLC_EGENERIC; + } + i_data -= i_used; + p_data += i_used; + + if( !b_gotpicture ) + { + return VLC_SUCCESS; + } + + if( !id->b_enc_inited ) + { + /* XXX hack because of copy packetizer and mpeg4video that can failed + detecting size */ + if( id->ff_enc_c->width == 0 || id->ff_enc_c->height == 0 ) + { + id->ff_enc_c->width = id->ff_dec_c->width; + id->ff_enc_c->height = id->ff_dec_c->height; + } + + if( avcodec_open( id->ff_enc_c, id->ff_enc ) ) + { + msg_Err( p_stream, "cannot open encoder" ); + return VLC_EGENERIC; + } + id->b_enc_inited = VLC_TRUE; + } + + + /* deinterlace */ + if( p_stream->p_sys->b_deinterlace ) + { + if( id->p_ff_pic_tmp0 == NULL ) + { + int i_size; + uint8_t *buf; + id->p_ff_pic_tmp0 = avcodec_alloc_frame(); + i_size = avpicture_get_size( id->ff_dec_c->pix_fmt, + id->ff_dec_c->width, id->ff_dec_c->height ); + + buf = malloc( i_size ); + + avpicture_fill( (AVPicture*)id->p_ff_pic_tmp0, buf, + id->ff_enc_c->pix_fmt, + id->ff_dec_c->width, id->ff_dec_c->height ); + } + + avpicture_deinterlace( (AVPicture*)id->p_ff_pic_tmp0, (AVPicture*)frame, + id->ff_dec_c->pix_fmt, + id->ff_dec_c->width, id->ff_dec_c->height ); + + frame = id->p_ff_pic_tmp0; + } + + /* convert pix format */ + if( id->ff_dec_c->pix_fmt != id->ff_enc_c->pix_fmt ) + { + if( id->p_ff_pic_tmp1 == NULL ) + { + int i_size; + uint8_t *buf; + id->p_ff_pic_tmp1 = avcodec_alloc_frame(); + i_size = avpicture_get_size( id->ff_enc_c->pix_fmt, + id->ff_dec_c->width, id->ff_dec_c->height ); + + buf = malloc( i_size ); + + avpicture_fill( (AVPicture*)id->p_ff_pic_tmp1, buf, + id->ff_enc_c->pix_fmt, + id->ff_dec_c->width, id->ff_dec_c->height ); + } + + img_convert( (AVPicture*)id->p_ff_pic_tmp1, id->ff_enc_c->pix_fmt, + (AVPicture*)frame, id->ff_dec_c->pix_fmt, + id->ff_dec_c->width, id->ff_dec_c->height ); + + frame = id->p_ff_pic_tmp1; + } + + /* convert size and crop */ + if( ( id->ff_dec_c->width != id->ff_enc_c->width ) || + ( id->ff_dec_c->height != id->ff_enc_c->height ) ) + { + if( id->p_ff_pic_tmp2 == NULL ) + { + int i_size; + uint8_t *buf; + id->p_ff_pic_tmp2 = avcodec_alloc_frame(); + i_size = avpicture_get_size( id->ff_enc_c->pix_fmt, + id->ff_enc_c->width, id->ff_enc_c->height ); + + buf = malloc( i_size ); + + avpicture_fill( (AVPicture*)id->p_ff_pic_tmp2, buf, + id->ff_enc_c->pix_fmt, + id->ff_enc_c->width, id->ff_enc_c->height ); + + id->p_vresample = + img_resample_full_init( id->ff_enc_c->width, id->ff_enc_c->height, + id->ff_dec_c->width, id->ff_dec_c->height, + p_stream->p_sys->i_crop_top, + p_stream->p_sys->i_crop_bottom, + p_stream->p_sys->i_crop_left, + p_stream->p_sys->i_crop_right ); + } + + img_resample( id->p_vresample, (AVPicture*)id->p_ff_pic_tmp2, (AVPicture*)frame ); + + frame = id->p_ff_pic_tmp2; + } + + /* encode frame */ + i_out = avcodec_encode_video( id->ff_enc_c, id->p_buffer, id->i_buffer, frame ); + + if( i_out > 0 ) + { + sout_buffer_t *p_out; + p_out = sout_BufferNew( p_stream->p_sout, i_out ); + + memcpy( p_out->p_buffer, id->p_buffer, i_out ); + + p_out->i_size = i_out; + p_out->i_length = in->i_length; + p_out->i_dts = in->i_dts; + p_out->i_pts = in->i_dts; /* FIXME */ + + sout_BufferChain( out, p_out ); + } + + if( i_data <= 0 ) + { + return VLC_SUCCESS; + } + } + + return VLC_SUCCESS; +} + diff --git a/src/input/input_dec.c b/src/input/input_dec.c index 7489d7aa7c..0ee1d03a66 100644 --- a/src/input/input_dec.c +++ b/src/input/input_dec.c @@ -2,7 +2,7 @@ * input_dec.c: Functions for the management of decoders ***************************************************************************** * Copyright (C) 1999-2001 VideoLAN - * $Id: input_dec.c,v 1.59 2003/03/04 13:21:19 massiot Exp $ + * $Id: input_dec.c,v 1.60 2003/04/13 20:00:21 fenrir Exp $ * * Authors: Christophe Massiot * @@ -58,10 +58,9 @@ decoder_fifo_t * input_RunDecoder( input_thread_t * p_input, } p_fifo->p_module = NULL; - /* If we are in sout mode, search first for packetizer module then - * codec to do transcoding */ + /* If we are in sout mode, search for packetizer module */ psz_sout = config_GetPsz( p_input, "sout" ); - if( psz_sout != NULL && *psz_sout != 0 ) + if( !p_es->b_force_decoder && psz_sout != NULL && *psz_sout != 0 ) { vlc_bool_t b_sout = VLC_TRUE; @@ -76,40 +75,8 @@ decoder_fifo_t * input_RunDecoder( input_thread_t * p_input, if( b_sout ) { - vlc_bool_t b_reencode = VLC_FALSE; - - if( p_es->i_cat == AUDIO_ES ) - { - char *psz_sout_acodec = config_GetPsz( p_input, "sout-acodec" ); - if( psz_sout_acodec != NULL && *psz_sout_acodec != '\0' ) - { - msg_Dbg( p_input, "audio reencoding requested -> unsupported" ); - b_reencode = VLC_TRUE; - } - } - else if( p_es->i_cat == VIDEO_ES ) - { - char *psz_sout_vcodec = config_GetPsz( p_input, "sout-vcodec" ); - if( psz_sout_vcodec != NULL && *psz_sout_vcodec != '\0' ) - { - msg_Dbg( p_input, "video reencoding requested" ); - /* force encoder video output */ - config_PutPsz( p_input, "vout", "encoder" ); - b_reencode = VLC_TRUE; - } - } - - if( !b_reencode ) - { - /* we don't want to reencode so search for a packetizer */ - p_fifo->p_module = - module_Need( p_fifo, "packetizer", "$packetizer" ); - } - else - { - /* get a suitable decoder module to do reencoding*/ - p_fifo->p_module = module_Need( p_fifo, "decoder", "$codec" ); - } + p_fifo->p_module = + module_Need( p_fifo, "packetizer", "$packetizer" ); } } else @@ -118,6 +85,11 @@ decoder_fifo_t * input_RunDecoder( input_thread_t * p_input, p_fifo->p_module = module_Need( p_fifo, "decoder", "$codec" ); } + if( psz_sout ) + { + free( psz_sout ); + } + if( p_fifo->p_module == NULL ) { msg_Err( p_fifo, "no suitable decoder module for fourcc `%4.4s'.\nVLC probably does not support this sound or video format.", diff --git a/src/input/input_programs.c b/src/input/input_programs.c index 838e236b01..cc66a62692 100644 --- a/src/input/input_programs.c +++ b/src/input/input_programs.c @@ -2,7 +2,7 @@ * input_programs.c: es_descriptor_t, pgrm_descriptor_t management ***************************************************************************** * Copyright (C) 1999-2002 VideoLAN - * $Id: input_programs.c,v 1.103 2003/03/12 05:26:46 sam Exp $ + * $Id: input_programs.c,v 1.104 2003/04/13 20:00:21 fenrir Exp $ * * Authors: Christophe Massiot * @@ -524,6 +524,7 @@ es_descriptor_t * input_AddES( input_thread_t * p_input, p_es->i_demux_fd = 0; p_es->c_packets = 0; p_es->c_invalid_packets = 0; + p_es->b_force_decoder = VLC_FALSE; if( i_data_len ) { diff --git a/src/stream_output/stream_output.c b/src/stream_output/stream_output.c index e578f69b17..92cb1ac4ad 100644 --- a/src/stream_output/stream_output.c +++ b/src/stream_output/stream_output.c @@ -2,7 +2,7 @@ * stream_output.c : stream output module ***************************************************************************** * Copyright (C) 2002 VideoLAN - * $Id: stream_output.c,v 1.23 2003/03/31 03:46:11 fenrir Exp $ + * $Id: stream_output.c,v 1.24 2003/04/13 20:00:21 fenrir Exp $ * * Authors: Christophe Massiot * Laurent Aimar @@ -37,55 +37,17 @@ /***************************************************************************** * Local prototypes *****************************************************************************/ -static int InstanceNewOutput ( sout_instance_t *, char * ); -static int InstanceMuxNew ( sout_instance_t *, - char *, char *, char * ); - -static sout_mux_t * MuxNew ( sout_instance_t*, - char *, sout_access_out_t * ); -static sout_input_t *MuxAddStream ( sout_mux_t *, sout_packet_format_t * ); -static void MuxDeleteStream ( sout_mux_t *, sout_input_t * ); -static void MuxDelete ( sout_mux_t * ); - -#if 0 -typedef struct -{ - /* if muxer doesn't support adding stream at any time then we first wait - * for stream then we refuse all stream and start muxing */ - vlc_bool_t b_add_stream_any_time; - vlc_bool_t b_waiting_stream; - - /* we wait one second after first stream added */ - mtime_t i_add_stream_start; - -} sout_instance_sys_mux_t; -#endif - -struct sout_instance_sys_t -{ - int i_d_u_m_m_y; -}; - +static char *sout_stream_chain_to_str( char * ); /* * Generic MRL parser * */ -/* {options}/{options}:// */ -typedef struct mrl_option_s -{ - struct mrl_option_s *p_next; - - char *psz_name; - char *psz_value; -} mrl_option_t; typedef struct { char *psz_access; - mrl_option_t *p_access_options; char *psz_way; - mrl_option_t *p_way_options; char *psz_name; } mrl_t; @@ -95,54 +57,6 @@ static int mrl_Parse( mrl_t *p_mrl, char *psz_mrl ); /* mrl_Clean: clean p_mrl after a call to mrl_Parse */ static void mrl_Clean( mrl_t *p_mrl ); -/* some macro */ -#define TAB_APPEND( count, tab, p ) \ - if( (count) > 0 ) \ - { \ - (tab) = realloc( (tab), sizeof( void ** ) * ( (count) + 1 ) ); \ - } \ - else \ - { \ - (tab) = malloc( sizeof( void ** ) ); \ - } \ - (void**)(tab)[(count)] = (void*)(p); \ - (count)++ - -#define TAB_FIND( count, tab, p, index ) \ - { \ - int _i_; \ - (index) = -1; \ - for( _i_ = 0; _i_ < (count); _i_++ ) \ - { \ - if((void**)(tab)[_i_]==(void*)(p)) \ - { \ - (index) = _i_; \ - break; \ - } \ - } \ - } - -#define TAB_REMOVE( count, tab, p ) \ - { \ - int i_index; \ - TAB_FIND( count, tab, p, i_index ); \ - if( i_index >= 0 ) \ - { \ - if( count > 1 ) \ - { \ - memmove( ((void**)tab + i_index), \ - ((void**)tab + i_index+1), \ - ( (count) - i_index - 1 ) * sizeof( void* ) );\ - } \ - else \ - { \ - free( tab ); \ - (tab) = NULL; \ - } \ - (count)--; \ - } \ - } - #define FREE( p ) if( p ) { free( p ); (p) = NULL; } /***************************************************************************** @@ -152,9 +66,8 @@ sout_instance_t * __sout_NewInstance ( vlc_object_t *p_parent, char * psz_dest ) { sout_instance_t *p_sout; - char *psz_dup, *psz_parser, *psz_pos; - /* Allocate descriptor */ + /* *** Allocate descriptor *** */ p_sout = vlc_object_create( p_parent, VLC_OBJECT_SOUT ); if( p_sout == NULL ) { @@ -162,50 +75,30 @@ sout_instance_t * __sout_NewInstance ( vlc_object_t *p_parent, return NULL; } - p_sout->psz_sout = NULL; - - p_sout->i_nb_dest = 0; - p_sout->ppsz_dest = NULL; - + /* *** init descriptor *** */ + p_sout->psz_sout = strdup( psz_dest ); p_sout->i_preheader = 0; - p_sout->i_nb_mux = 0; - p_sout->pp_mux = 0; + p_sout->p_sys = NULL; vlc_mutex_init( p_sout, &p_sout->lock ); - p_sout->i_nb_inputs = 0; - p_sout->pp_inputs = NULL; - - p_sout->p_sys = malloc( sizeof( sout_instance_sys_t ) ); - - /* now parse psz_sout */ - psz_dup = strdup( psz_dest ); - psz_parser = psz_dup; - - while( ( psz_pos = strchr( psz_parser, '#' ) ) != NULL ) + if( psz_dest && psz_dest[0] == '#' ) { - *psz_pos++ = '\0'; - - if( InstanceNewOutput( p_sout, psz_parser ) ) - { - msg_Err( p_sout, "adding `%s' failed", psz_parser ); - } - - psz_parser = psz_pos; + p_sout->psz_chain = strdup( &psz_dest[1] ); } - - if( *psz_parser ) + else { - if( InstanceNewOutput( p_sout, psz_parser ) ) - { - msg_Err( p_sout, "adding `%s' failed", psz_parser ); - } + p_sout->psz_chain = sout_stream_chain_to_str( psz_dest ); } - free( psz_dup ); + p_sout->p_stream = sout_stream_new( p_sout, p_sout->psz_chain ); - if( p_sout->i_nb_dest <= 0 ) + if( p_sout->p_stream == NULL ) { - msg_Err( p_sout, "all sout failed" ); + msg_Err( p_sout, "stream chained failed for `%s'", p_sout->psz_chain ); + + FREE( p_sout->psz_sout ); + FREE( p_sout->psz_chain ); + vlc_object_destroy( p_sout ); return( NULL ); } @@ -219,221 +112,114 @@ sout_instance_t * __sout_NewInstance ( vlc_object_t *p_parent, *****************************************************************************/ void sout_DeleteInstance( sout_instance_t * p_sout ) { - int i; /* Unlink object */ vlc_object_detach( p_sout ); /* *** free all string *** */ FREE( p_sout->psz_sout ); + FREE( p_sout->psz_chain ); - for( i = 0; i < p_sout->i_nb_dest; i++ ) - { - FREE( p_sout->ppsz_dest[i] ); - } - FREE( p_sout->ppsz_dest ); - - /* *** there shouldn't be any input ** */ - if( p_sout->i_nb_inputs > 0 ) - { - msg_Err( p_sout, "i_nb_inputs=%d > 0 !!!!!!", p_sout->i_nb_inputs ); - msg_Err( p_sout, "mmmh I have a bad feeling..." ); - } + sout_stream_delete( p_sout->p_stream ); vlc_mutex_destroy( &p_sout->lock ); - /* *** remove all muxer *** */ - for( i = 0; i < p_sout->i_nb_mux; i++ ) - { - sout_access_out_t *p_access; -#define p_mux p_sout->pp_mux[i] - - p_access = p_mux->p_access; - - MuxDelete( p_mux ); - sout_AccessOutDelete( p_access ); -#undef p_mux - } - FREE( p_sout->pp_mux ); - -#if 0 - for( i = 0; i < p_sout->p_sys->i_nb_mux; i++ ) - { - FREE( p_sout->p_sys->pp_mux[i] ); - } - FREE( p_sout->p_sys->pp_mux ); -#endif - - /* Free structure */ + /* *** free structure *** */ vlc_object_destroy( p_sout ); } - - /***************************************************************************** - * InitInstance: opens appropriate modules + * Packetizer/Input *****************************************************************************/ -static int InstanceNewOutput (sout_instance_t *p_sout, char *psz_dest ) +sout_packetizer_input_t *__sout_InputNew( vlc_object_t *p_this, + sout_format_t *p_fmt ) { - mrl_t mrl; - char * psz_dup; -#if 0 - /* Parse dest string. Syntax : [[][/]:][] */ - /* This code is identical to input.c:InitThread. FIXME : factorize it ? */ + sout_instance_t *p_sout = NULL; + sout_packetizer_input_t *p_input; - char * psz_dup = strdup( psz_dest ); - char * psz_parser = psz_dup; - char * psz_access = ""; - char * psz_mux = ""; - char * psz_name = ""; - /* *** first parse psz_dest */ - while( *psz_parser && *psz_parser != ':' ) - { - psz_parser++; - } -#if defined( WIN32 ) || defined( UNDER_CE ) - if( psz_parser - psz_dup == 1 ) - { - msg_Warn( p_sout, "drive letter %c: found in source string", - *psz_dup ) ; - psz_parser = ""; - } -#endif + int i_try; - if( !*psz_parser ) - { - psz_access = psz_mux = ""; - psz_name = psz_dup; - } - else + /* search an stream output */ + for( i_try = 0; i_try < 12; i_try++ ) { - *psz_parser++ = '\0'; - - /* let's skip '//' */ - if( psz_parser[0] == '/' && psz_parser[1] == '/' ) + p_sout = vlc_object_find( p_this, VLC_OBJECT_SOUT, FIND_ANYWHERE ); + if( p_sout ) { - psz_parser += 2 ; + break; } - psz_name = psz_parser ; - - /* Come back to parse the access and mux plug-ins */ - psz_parser = psz_dup; + msleep( 100*1000 ); + msg_Dbg( p_this, "waiting for sout" ); + } - if( !*psz_parser ) - { - /* No access */ - psz_access = ""; - } - else if( *psz_parser == '/' ) - { - /* No access */ - psz_access = ""; - psz_parser++; - } - else - { - psz_access = psz_parser; + if( !p_sout ) + { + msg_Err( p_this, "cannot find any stream ouput" ); + return( NULL ); + } - while( *psz_parser && *psz_parser != '/' ) - { - psz_parser++; - } + msg_Dbg( p_sout, "adding a new input" ); - if( *psz_parser == '/' ) - { - *psz_parser++ = '\0'; - } - } + /* *** create a packetizer input *** */ + p_input = malloc( sizeof( sout_packetizer_input_t ) ); + p_input->p_sout = p_sout; + p_input->p_fmt = p_fmt; - if( !*psz_parser ) - { - /* No mux */ - psz_mux = ""; - } - else - { - psz_mux = psz_parser; - } + if( p_fmt->i_fourcc == VLC_FOURCC( 'n', 'u', 'l', 'l' ) ) + { + vlc_object_release( p_sout ); + return p_input; } - msg_Dbg( p_sout, "access `%s', mux `%s', name `%s'", - psz_access, psz_mux, psz_name ); -#endif - - mrl_Parse( &mrl, psz_dest ); - msg_Dbg( p_sout, "access `%s', mux `%s', name `%s'", - mrl.psz_access, mrl.psz_way, mrl.psz_name ); - + /* *** add it to the stream chain */ vlc_mutex_lock( &p_sout->lock ); - /* *** create mux *** */ - - if( InstanceMuxNew( p_sout, mrl.psz_way, mrl.psz_access, mrl.psz_name ) ) - { - msg_Err( p_sout, "cannot create sout chain for %s/%s://%s", - mrl.psz_access, mrl.psz_way, mrl.psz_name ); + p_input->id = p_sout->p_stream->pf_add( p_sout->p_stream, + p_fmt ); + vlc_mutex_unlock( &p_sout->lock ); - mrl_Clean( &mrl ); - vlc_mutex_unlock( &p_sout->lock ); - return( VLC_EGENERIC ); - } - mrl_Clean( &mrl ); + vlc_object_release( p_sout ); - /* *** finish all setup *** */ - if( p_sout->psz_sout ) - { - p_sout->psz_sout = - realloc( p_sout->psz_sout, - strlen( p_sout->psz_sout ) +2+1+ strlen( psz_dest ) ); - strcat( p_sout->psz_sout, "#" ); - strcat( p_sout->psz_sout, psz_dest ); - } - else + if( p_input->id == NULL ) { - p_sout->psz_sout = strdup( psz_dest ); + free( p_input ); + return( NULL ); } - psz_dup = strdup( psz_dest ); - TAB_APPEND( p_sout->i_nb_dest, p_sout->ppsz_dest, psz_dup ); - vlc_mutex_unlock( &p_sout->lock ); - - msg_Dbg( p_sout, "complete sout `%s'", p_sout->psz_sout ); - return VLC_SUCCESS; + return( p_input ); } -static int InstanceMuxNew ( sout_instance_t *p_sout, - char *psz_mux, char *psz_access, char *psz_name ) + +int sout_InputDelete( sout_packetizer_input_t *p_input ) { - sout_access_out_t *p_access; - sout_mux_t *p_mux; + sout_instance_t *p_sout = p_input->p_sout; + + msg_Dbg( p_sout, "removing an input" ); - /* *** find and open appropriate access module *** */ - p_access = - sout_AccessOutNew( p_sout, psz_access, psz_name ); - if( p_access == NULL ) + if( p_input->p_fmt->i_fourcc != VLC_FOURCC( 'n', 'u', 'l', 'l' ) ) { - msg_Err( p_sout, "no suitable sout access module for `%s/%s://%s'", - psz_access, psz_mux, psz_name ); - return( VLC_EGENERIC ); + vlc_mutex_lock( &p_sout->lock ); + p_sout->p_stream->pf_del( p_sout->p_stream, p_input->id ); + vlc_mutex_unlock( &p_sout->lock ); } - /* *** find and open appropriate mux module *** */ - p_mux = MuxNew( p_sout, psz_mux, p_access ); - if( p_mux == NULL ) - { - msg_Err( p_sout, "no suitable sout mux module for `%s/%s://%s'", - psz_access, psz_mux, psz_name ); + free( p_input ); - sout_AccessOutDelete( p_access ); - return( VLC_EGENERIC ); - } + return( VLC_SUCCESS); +} - p_sout->i_preheader = __MAX( p_sout->i_preheader, - p_mux->i_preheader ); - TAB_APPEND( p_sout->i_nb_mux, p_sout->pp_mux, p_mux ); +int sout_InputSendBuffer( sout_packetizer_input_t *p_input, sout_buffer_t *p_buffer ) +{ + sout_instance_t *p_sout = p_input->p_sout; + + if( p_input->p_fmt->i_fourcc == VLC_FOURCC( 'n', 'u', 'l', 'l' ) ) + { + sout_BufferDelete( p_input->p_sout, p_buffer ); + return VLC_SUCCESS; + } - return VLC_SUCCESS; + return( p_sout->p_stream->pf_send( p_sout->p_stream, p_input->id, p_buffer ) ); } + /***************************************************************************** * sout_AccessOutNew: allocate a new access out *****************************************************************************/ @@ -501,43 +287,12 @@ int sout_AccessOutWrite( sout_access_out_t *p_access, sout_buffer_t *p_buffer ) } - -static sout_input_t *SoutInputCreate( sout_instance_t *p_sout, - sout_packet_format_t *p_format ) -{ - sout_input_t *p_input; - - p_input = malloc( sizeof( sout_input_t ) ); - - p_input->p_sout = p_sout; - memcpy( &p_input->input_format, - p_format, - sizeof( sout_packet_format_t ) ); - p_input->p_fifo = sout_FifoCreate( p_sout ); - p_input->p_sys = NULL; - - return p_input; -} - -static void SoutInputDestroy( sout_instance_t *p_sout, - sout_input_t *p_input ) -{ - sout_FifoDestroy( p_sout, p_input->p_fifo ); - free( p_input ); -} - -/***************************************************************************** - * Mux*: create/destroy/manipulate muxer. - * XXX: for now they are private, but I will near export them - * to allow muxer creating private muxer (ogg in avi, flexmux in ts/ps) - *****************************************************************************/ - /***************************************************************************** * MuxNew: allocate a new mux *****************************************************************************/ -static sout_mux_t * MuxNew ( sout_instance_t *p_sout, - char *psz_mux, - sout_access_out_t *p_access ) +sout_mux_t * sout_MuxNew ( sout_instance_t *p_sout, + char *psz_mux, + sout_access_out_t *p_access ) { sout_mux_t *p_mux; @@ -605,7 +360,7 @@ static sout_mux_t * MuxNew ( sout_instance_t *p_sout, return p_mux; } -static void MuxDelete ( sout_mux_t *p_mux ) +void sout_MuxDelete ( sout_mux_t *p_mux ) { if( p_mux->p_module ) { @@ -616,8 +371,8 @@ static void MuxDelete ( sout_mux_t *p_mux ) vlc_object_destroy( p_mux ); } -static sout_input_t *MuxAddStream ( sout_mux_t *p_mux, - sout_packet_format_t *p_format ) +sout_input_t *sout_MuxAddStream( sout_mux_t *p_mux, + sout_format_t *p_fmt ) { sout_input_t *p_input; @@ -633,22 +388,27 @@ static sout_input_t *MuxAddStream ( sout_mux_t *p_mux, } msg_Dbg( p_mux, "adding a new input" ); + /* create a new sout input */ - p_input = SoutInputCreate( p_mux->p_sout, p_format ); + p_input = malloc( sizeof( sout_input_t ) ); + p_input->p_sout = p_mux->p_sout; + p_input->p_fmt = p_fmt; + p_input->p_fifo = sout_FifoCreate( p_mux->p_sout ); + p_input->p_sys = NULL; TAB_APPEND( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input ); if( p_mux->pf_addstream( p_mux, p_input ) < 0 ) { msg_Err( p_mux, "cannot add this stream" ); - MuxDeleteStream( p_mux, p_input ); + sout_MuxDeleteStream( p_mux, p_input ); return( NULL ); } return( p_input ); } -static void MuxDeleteStream ( sout_mux_t *p_mux, - sout_input_t *p_input ) +void sout_MuxDeleteStream ( sout_mux_t *p_mux, + sout_input_t *p_input ) { int i_index; @@ -668,13 +428,14 @@ static void MuxDeleteStream ( sout_mux_t *p_mux, msg_Warn( p_mux, "no more input stream for this mux" ); } - SoutInputDestroy( p_mux->p_sout, p_input ); + sout_FifoDestroy( p_mux->p_sout, p_input->p_fifo ); + free( p_input ); } } -static void MuxSendBuffer ( sout_mux_t *p_mux, - sout_input_t *p_input, - sout_buffer_t *p_buffer ) +void sout_MuxSendBuffer ( sout_mux_t *p_mux, + sout_input_t *p_input, + sout_buffer_t *p_buffer ) { sout_FifoPut( p_input->p_fifo, p_buffer ); @@ -694,155 +455,7 @@ static void MuxSendBuffer ( sout_mux_t *p_mux, p_mux->pf_mux( p_mux ); } -/***************************************************************************** - * - *****************************************************************************/ -sout_packetizer_input_t *__sout_InputNew( vlc_object_t *p_this, - sout_packet_format_t *p_format ) -{ - sout_instance_t *p_sout = NULL; - sout_packetizer_input_t *p_input; - int i_try; - int i_mux; - vlc_bool_t b_accepted = VLC_FALSE; - - /* search an stream output */ - for( i_try = 0; i_try < 12; i_try++ ) - { - p_sout = vlc_object_find( p_this, VLC_OBJECT_SOUT, FIND_ANYWHERE ); - if( !p_sout ) - { - msleep( 100*1000 ); - msg_Dbg( p_this, "waiting for sout" ); - } - else - { - break; - } - } - - if( !p_sout ) - { - msg_Err( p_this, "cannot find any stream ouput" ); - return( NULL ); - } - msg_Dbg( p_sout, "adding a new input" ); - - /* *** create a packetizer input *** */ - p_input = malloc( sizeof( sout_packetizer_input_t ) ); - p_input->p_sout = p_sout; - p_input->i_nb_inputs = 0; - p_input->pp_inputs = NULL; - p_input->i_nb_mux = 0; - p_input->pp_mux = NULL; - memcpy( &p_input->input_format, - p_format, - sizeof( sout_packet_format_t ) ); - - if( p_format->i_fourcc == VLC_FOURCC( 'n', 'u', 'l', 'l' ) ) - { - vlc_object_release( p_sout ); - return p_input; - } - - vlc_mutex_lock( &p_sout->lock ); - /* *** add this input to all muxers *** */ - for( i_mux = 0; i_mux < p_sout->i_nb_mux; i_mux++ ) - { - sout_input_t *p_mux_input; -#define p_mux p_sout->pp_mux[i_mux] - - p_mux_input = MuxAddStream( p_mux, p_format ); - if( p_mux_input ) - { - TAB_APPEND( p_input->i_nb_inputs, p_input->pp_inputs, p_mux_input ); - TAB_APPEND( p_input->i_nb_mux, p_input->pp_mux, p_mux ); - - b_accepted = VLC_TRUE; - } -#undef p_mux - } - - if( !b_accepted ) - { - /* all muxer refuse this stream, so delete it */ - free( p_input ); - - vlc_mutex_unlock( &p_sout->lock ); - vlc_object_release( p_sout ); - return( NULL ); - } - - TAB_APPEND( p_sout->i_nb_inputs, p_sout->pp_inputs, p_input ); - vlc_mutex_unlock( &p_sout->lock ); - - vlc_object_release( p_sout ); - - return( p_input ); -} - - -int sout_InputDelete( sout_packetizer_input_t *p_input ) -{ - sout_instance_t *p_sout = p_input->p_sout; - int i_input; - - msg_Dbg( p_sout, "removing an input" ); - - vlc_mutex_lock( &p_sout->lock ); - - /* *** remove this input to all muxers *** */ - for( i_input = 0; i_input < p_input->i_nb_inputs; i_input++ ) - { - MuxDeleteStream( p_input->pp_mux[i_input], p_input->pp_inputs[i_input] ); - } - - TAB_REMOVE( p_sout->i_nb_inputs, p_sout->pp_inputs, p_input ); - - free( p_input->pp_inputs ); - free( p_input->pp_mux ); - - free( p_input ); - - vlc_mutex_unlock( &p_sout->lock ); - return( 0 ); -} - -int sout_InputSendBuffer( sout_packetizer_input_t *p_input, sout_buffer_t *p_buffer ) -{ -// sout_instance_sys_t *p_sys = p_input->p_sout->p_sys; -/* msg_Dbg( p_input->p_sout, - "send buffer, size:%d", p_buffer->i_size ); */ - - if( p_input->input_format.i_fourcc != VLC_FOURCC( 'n', 'u', 'l', 'l' ) && - p_input->i_nb_inputs > 0 ) - { - int i; - - vlc_mutex_lock( &p_input->p_sout->lock ); - for( i = 0; i < p_input->i_nb_inputs - 1; i++ ) - { - sout_buffer_t *p_dup; - - p_dup = sout_BufferDuplicate( p_input->p_sout, p_buffer ); - - MuxSendBuffer( p_input->pp_mux[i], - p_input->pp_inputs[i], - p_dup ); - } - MuxSendBuffer( p_input->pp_mux[p_input->i_nb_inputs-1], - p_input->pp_inputs[p_input->i_nb_inputs-1], - p_buffer ); - - vlc_mutex_unlock( &p_input->p_sout->lock ); - } - else - { - sout_BufferDelete( p_input->p_sout, p_buffer ); - } - return( 0 ); -} sout_fifo_t *sout_FifoCreate( sout_instance_t *p_sout ) { @@ -1085,78 +698,6 @@ void sout_BufferChain( sout_buffer_t **pp_chain, } } -#if 0 -static int mrl_ParseOptions( mrl_option_t **pp_opt, char *psz_options ) -{ - mrl_option_t **pp_last = pp_opt; - - char *psz_parser = strdup( psz_options ); - - *pp_last = NULL; - - if( *psz_parser == '=' ) - { - free( psz_parser ); - return( VLC_EGENERIC ); - } - if( *psz_parser == '{' ) - { - free( psz_parser ); - } - - for( ;; ) - { - char *psz_end; - mrl_option_t opt; - - /* skip space */ - while( *psz_parser && ( *psz_parser == ' ' || *psz_parser == '\t' || *psz_parser == ';' ) ) - { - psz_parser++; - } - - if( ( psz_end = strchr( psz_parser, '=' ) ) != NULL ) - { - opt.p_next = NULL; - - while( psz_end > psz_parser && ( *psz_end == ' ' || *psz_end == '\t' ) ) - { - psz_end--; - } - - if( psz_end - psz_parser <= 0 ) - { - return( VLC_EGENERIC ); - } - - *psz_end = '\0'; - opt.psz_name = strdup( psz_parser ); - - psz_parser = psz_end + 1; - if( ( psz_end = strchr( psz_parser, ';' ) ) == NULL && - ( psz_end = strchr( psz_parser, '}' ) ) == NULL ) - { - psz_end = psz_parser + strlen( psz_parser ) + 1; - } - - opt.psz_value = strdup( psz_parser ); - - fprintf( stderr, "option: name=`%s' value=`%s'\n", - opt.psz_name, - opt.psz_value ); - psz_parser = psz_end + 1; - - *pp_last = malloc( sizeof( mrl_option_t ) ); - **pp_last = opt; - } - else - { - break; - } - } -} -#endif - static int mrl_Parse( mrl_t *p_mrl, char *psz_mrl ) { char * psz_dup = strdup( psz_mrl ); @@ -1264,23 +805,6 @@ static int mrl_Parse( mrl_t *p_mrl, char *psz_mrl ) } } -#if 0 - if( ( psz_parser = strchr( psz_access, '{' ) ) != NULL ) - { - mrl_ParseOptions( &p_mrl->p_access_options, psz_parser ); - *psz_parser = '\0'; - } - - if( ( psz_parser = strchr( psz_way, '{' ) ) != NULL ) - { - mrl_ParseOptions( &p_mrl->p_way_options, psz_parser ); - *psz_parser = '\0'; - } -#endif - - p_mrl->p_access_options = NULL; - p_mrl->p_way_options = NULL; - p_mrl->psz_access = strdup( psz_access ); p_mrl->psz_way = strdup( psz_way ); p_mrl->psz_name = strdup( psz_name ); @@ -1299,4 +823,332 @@ static void mrl_Clean( mrl_t *p_mrl ) } +/**************************************************************************** + **************************************************************************** + ** + ** + ** + **************************************************************************** + ****************************************************************************/ + +/* create a complete chain */ +/* chain format: + module{option=*:option=*}[:module{option=*:...}] + */ + +static char *_strndup( char *str, int i_len ) +{ + char *p; + + p = malloc( i_len + 1 ); + strncpy( p, str, i_len ); + p[i_len] = '\0'; + + return( p ); +} + +/* + * parse module{options=str, option="str "}: + * return a pointer on the rest + * XXX: psz_chain is modified + */ +#define SKIPSPACE( p ) { while( *p && ( *p == ' ' || *p == '\t' ) ) p++; } +/* go accross " " and { } */ +static char *_get_chain_end( char *str ) +{ + char *p = str; + + SKIPSPACE( p ); + + for( ;; ) + { + if( *p == '{' || *p == '"' || *p == '\'') + { + char c; + + if( *p == '{' ) + { + c = '}'; + } + else + { + c = *p; + } + p++; + + for( ;; ) + { + if( *p == '\0' ) + { + return p; + } + + if( *p == c ) + { + p++; + return p; + } + else if( *p == '{' && c == '}' ) + { + p = _get_chain_end( p ); + } + else + { + p++; + } + } + } + else if( *p == '\0' || *p == ',' || *p == '}' || *p == ' ' || *p == '\t' ) + { + return p; + } + else + { + p++; + } + } +} + +char * sout_cfg_parser( char **ppsz_name, sout_cfg_t **pp_cfg, char *psz_chain ) +{ + sout_cfg_t *p_cfg = NULL; + char *p = psz_chain; + + *ppsz_name = NULL; + *pp_cfg = NULL; + + SKIPSPACE( p ); + + while( *p && *p != '{' && *p != ':' && *p != ' ' && *p != '\t' ) + { + p++; + } + + if( p == psz_chain ) + { + return NULL; + } + + *ppsz_name = _strndup( psz_chain, p - psz_chain ); + + //fprintf( stderr, "name=%s - rest=%s\n", *ppsz_name, p ); + + SKIPSPACE( p ); + + if( *p == '{' ) + { + char *psz_name; + + p++; + + for( ;; ) + { + sout_cfg_t cfg; + + SKIPSPACE( p ); + + psz_name = p; + + while( *p && *p != '=' && *p != ',' && *p != '}' && *p != ' ' && *p != '\t' ) + { + p++; + } + + //fprintf( stderr, "name=%s - rest=%s\n", psz_name, p ); + if( p == psz_name ) + { + fprintf( stderr, "invalid options (empty)" ); + break; + } + + cfg.psz_name = _strndup( psz_name, p - psz_name ); + + SKIPSPACE( p ); + + if( *p == '=' ) + { + char *end; + + p++; +#if 0 + SKIPSPACE( p ); + + if( *p == '"' ) + { + char *end; + + p++; + end = strchr( p, '"' ); + + if( end ) + { +// fprintf( stderr, "##%s -- %s\n", p, end ); + cfg.psz_value = _strndup( p, end - p ); + p = end + 1; + } + else + { + cfg.psz_value = strdup( p ); + p += strlen( p ); + } + + } + else + { + psz_value = p; + while( *p && *p != ',' && *p != '}' && *p != ' ' && *p != '\t' ) + { + p++; + } + cfg.psz_value = _strndup( psz_value, p - psz_value ); + } +#endif + end = _get_chain_end( p ); + if( end <= p ) + { + cfg.psz_value = NULL; + } + else + { + if( *p == '\'' || *p =='"' || *p == '{' ) + { + p++; + end--; + } + if( end <= p ) + { + cfg.psz_value = NULL; + } + else + { + cfg.psz_value = _strndup( p, end - p ); + } + } + + p = end; + SKIPSPACE( p ); + } + else + { + cfg.psz_value = NULL; + } + + cfg.p_next = NULL; + if( p_cfg ) + { + p_cfg->p_next = malloc( sizeof( sout_cfg_t ) ); + memcpy( p_cfg->p_next, &cfg, sizeof( sout_cfg_t ) ); + + p_cfg = p_cfg->p_next; + } + else + { + p_cfg = malloc( sizeof( sout_cfg_t ) ); + memcpy( p_cfg, &cfg, sizeof( sout_cfg_t ) ); + + *pp_cfg = p_cfg; + } + + if( *p == ',' ) + { + p++; + } + + if( *p == '}' ) + { + p++; + + break; + } + } + } + + if( *p == ':' ) + { + return( strdup( p + 1 ) ); + } + + return( NULL ); +} + + + + + +/* + * XXX name and p_cfg are used (-> do NOT free them) + */ +sout_stream_t *sout_stream_new( sout_instance_t *p_sout, + char *psz_chain ) +{ + sout_stream_t *p_stream; + + p_stream = vlc_object_create( p_sout, sizeof( sout_stream_t ) ); + + if( !p_stream ) + { + msg_Err( p_sout, "out of memory" ); + return NULL; + } + + p_stream->p_sout = p_sout; + p_stream->p_sys = NULL; + + p_stream->psz_next = sout_cfg_parser( &p_stream->psz_name, &p_stream->p_cfg, psz_chain); + msg_Dbg( p_sout, "stream=`%s'", p_stream->psz_name ); + + p_stream->p_module = + module_Need( p_stream, "sout stream", p_stream->psz_name ); + + if( !p_stream->p_module ) + { + /* FIXME */ + vlc_object_destroy( p_stream ); + return NULL; + } + + return p_stream; +} + +void sout_stream_delete( sout_stream_t *p_stream ) +{ + sout_cfg_t *p_cfg; + + msg_Dbg( p_stream, "destroying chain... (name=%s)", p_stream->psz_name ); + module_Unneed( p_stream, p_stream->p_module ); + + FREE( p_stream->psz_name ); + FREE( p_stream->psz_next ); + + p_cfg = p_stream->p_cfg; + while( p_cfg != NULL ) + { + sout_cfg_t *p_next; + + p_next = p_cfg->p_next; + + FREE( p_cfg->psz_name ); + FREE( p_cfg->psz_value ); + free( p_cfg ); + + p_cfg = p_next; + } + + msg_Dbg( p_stream, "destroying chain done" ); + vlc_object_destroy( p_stream ); +} + +static char *sout_stream_chain_to_str( char *psz_url ) +{ + mrl_t mrl; + char *psz_chain; + + mrl_Parse( &mrl, psz_url ); + + psz_chain = malloc( 100 + strlen( mrl.psz_way ) + strlen( mrl.psz_access ) + strlen( mrl.psz_name ) ); + + sprintf( psz_chain, "std{mux=%s,access=%s,url=\"%s\"", mrl.psz_way, mrl.psz_access, mrl.psz_name ); + + return( psz_chain ); +} -- 2.39.2