📄 switcher.c
字号:
/***************************************************************************** * switcher.c: MPEG2 video switcher module ***************************************************************************** * Copyright (C) 2004 the VideoLAN team * $Id$ * * Authors: Christophe Massiot <massiot@via.ecp.fr> * * 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************//***************************************************************************** * Preamble *****************************************************************************/#include <math.h>#ifdef HAVE_CONFIG_H# include "config.h"#endif#include <vlc_common.h>#include <vlc_plugin.h>#include <vlc_sout.h>#include <vlc_vout.h>#include <vlc_charset.h>#include <vlc_network.h>#define HAVE_MMX#ifdef HAVE_LIBAVCODEC_AVCODEC_H# include <libavcodec/avcodec.h>#elif defined(HAVE_FFMPEG_AVCODEC_H)# include <ffmpeg/avcodec.h>#else# include <avcodec.h>#endif#ifdef HAVE_POSTPROC_POSTPROCESS_H# include <postproc/postprocess.h>#else# include <libpostproc/postprocess.h>#endif#define SOUT_CFG_PREFIX "sout-switcher-"#define MAX_PICTURES 10#define MAX_AUDIO 30#define MAX_THRESHOLD 99999999/***************************************************************************** * Local prototypes *****************************************************************************/static int Open ( vlc_object_t * );static void Close ( vlc_object_t * );static sout_stream_id_t *Add( sout_stream_t *, es_format_t * );static int Del( sout_stream_t *, sout_stream_id_t * );static int Send( sout_stream_t *, sout_stream_id_t *, block_t * );static mtime_t Process( sout_stream_t *p_stream, sout_stream_id_t *id, mtime_t i_max_dts );static int UnpackFromFile( sout_stream_t *p_stream, const char *psz_file, int i_width, int i_height, picture_t *p_pic );static void NetCommand( sout_stream_t *p_stream );static mtime_t VideoCommand( sout_stream_t *p_stream, sout_stream_id_t *id );static block_t *VideoGetBuffer( sout_stream_t *p_stream, sout_stream_id_t *id, block_t *p_buffer );static block_t *AudioGetBuffer( sout_stream_t *p_stream, sout_stream_id_t *id, block_t *p_buffer );/***************************************************************************** * Module descriptor *****************************************************************************/#define FILES_TEXT N_("Files")#define FILES_LONGTEXT N_( \ "Full paths of the files separated by colons." )#define SIZES_TEXT N_("Sizes")#define SIZES_LONGTEXT N_( \ "List of sizes separated by colons (720x576:480x576)." )#define RATIO_TEXT N_("Aspect ratio")#define RATIO_LONGTEXT N_( \ "Aspect ratio (4:3, 16:9)." )#define PORT_TEXT N_("Command UDP port")#define PORT_LONGTEXT N_( \ "UDP port to listen to for commands." )#define COMMAND_TEXT N_("Command")#define COMMAND_LONGTEXT N_( \ "Initial command to execute." )#define GOP_TEXT N_("GOP size")#define GOP_LONGTEXT N_( \ "Number of P frames between two I frames." )#define QSCALE_TEXT N_("Quantizer scale")#define QSCALE_LONGTEXT N_( \ "Fixed quantizer scale to use." )#define AUDIO_TEXT N_("Mute audio")#define AUDIO_LONGTEXT N_( \ "Mute audio when command is not 0." )vlc_module_begin(); set_description( N_("MPEG2 video switcher stream output") ); set_capability( "sout stream", 50 ); add_shortcut( "switcher" ); set_callbacks( Open, Close ); add_string( SOUT_CFG_PREFIX "files", "", NULL, FILES_TEXT, FILES_LONGTEXT, false ); add_string( SOUT_CFG_PREFIX "sizes", "", NULL, SIZES_TEXT, SIZES_LONGTEXT, false ); add_string( SOUT_CFG_PREFIX "aspect-ratio", "4:3", NULL, RATIO_TEXT, RATIO_LONGTEXT, false ); add_integer( SOUT_CFG_PREFIX "port", 5001, NULL, PORT_TEXT, PORT_LONGTEXT, true ); add_integer( SOUT_CFG_PREFIX "command", 0, NULL, COMMAND_TEXT, COMMAND_LONGTEXT, true ); add_integer( SOUT_CFG_PREFIX "gop", 8, NULL, GOP_TEXT, GOP_LONGTEXT, true ); add_integer( SOUT_CFG_PREFIX "qscale", 5, NULL, QSCALE_TEXT, QSCALE_LONGTEXT, true ); add_bool( SOUT_CFG_PREFIX "mute-audio", 1, NULL, AUDIO_TEXT, AUDIO_LONGTEXT, true );vlc_module_end();static const char *const ppsz_sout_options[] = { "files", "sizes", "aspect-ratio", "port", "command", "gop", "qscale", "mute-audio", NULL};struct sout_stream_sys_t{ sout_stream_t *p_out; int i_gop; int i_qscale; int i_aspect; sout_stream_id_t *pp_audio_ids[MAX_AUDIO]; bool b_audio; /* Pictures */ picture_t p_pictures[MAX_PICTURES]; int i_nb_pictures; /* Command */ int i_fd; int i_cmd, i_old_cmd;};struct sout_stream_id_t{ void *id; bool b_switcher_video; bool b_switcher_audio; es_format_t f_src; block_t *p_queued; /* ffmpeg part */ AVCodec *ff_enc; AVCodecContext *ff_enc_c; AVFrame *p_frame; uint8_t *p_buffer_out; int i_nb_pred; int16_t *p_samples;};/***************************************************************************** * 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; vlc_value_t val; char *psz_files, *psz_sizes; int i_height = 0, i_width = 0; p_sys = malloc( sizeof(sout_stream_sys_t) ); memset( p_sys, 0, sizeof(sout_stream_sys_t) ); p_sys->p_out = sout_StreamNew( p_stream->p_sout, p_stream->psz_next ); if( !p_sys->p_out ) { msg_Err( p_stream, "cannot create chain" ); free( p_sys ); return VLC_EGENERIC; } config_ChainParse( p_stream, SOUT_CFG_PREFIX, ppsz_sout_options, p_stream->p_cfg ); var_Get( p_stream, SOUT_CFG_PREFIX "files", &val ); psz_files = val.psz_string; var_Get( p_stream, SOUT_CFG_PREFIX "sizes", &val ); psz_sizes = val.psz_string; p_sys->i_nb_pictures = 0; while ( psz_files && *psz_files ) { char * psz_file = psz_files; char * psz_size = psz_sizes; while ( *psz_files && *psz_files != ':' ) psz_files++; if ( *psz_files == ':' ) *psz_files++ = '\0'; if ( *psz_sizes ) { while ( *psz_sizes && *psz_sizes != ':' ) psz_sizes++; if ( *psz_sizes == ':' ) *psz_sizes++ = '\0'; if ( sscanf( psz_size, "%dx%d", &i_width, &i_height ) != 2 ) { msg_Err( p_stream, "bad size %s for file %s", psz_size, psz_file ); free( p_sys ); return VLC_EGENERIC; } } if ( UnpackFromFile( p_stream, psz_file, i_width, i_height, &p_sys->p_pictures[p_sys->i_nb_pictures] ) < 0 ) { free( p_sys ); return VLC_EGENERIC; } p_sys->i_nb_pictures++; } var_Get( p_stream, SOUT_CFG_PREFIX "aspect-ratio", &val ); if ( val.psz_string ) { char *psz_parser = strchr( val.psz_string, ':' ); if( psz_parser ) { *psz_parser++ = '\0'; p_sys->i_aspect = atoi( val.psz_string ) * VOUT_ASPECT_FACTOR / atoi( psz_parser ); } else { msg_Warn( p_stream, "bad aspect ratio %s", val.psz_string ); p_sys->i_aspect = 4 * VOUT_ASPECT_FACTOR / 3; } free( val.psz_string ); } else { p_sys->i_aspect = 4 * VOUT_ASPECT_FACTOR / 3; } var_Get( p_stream, SOUT_CFG_PREFIX "port", &val ); p_sys->i_fd = net_ListenUDP1( p_stream, NULL, val.i_int ); if ( p_sys->i_fd < 0 ) { free( p_sys ); return VLC_EGENERIC; } var_Get( p_stream, SOUT_CFG_PREFIX "command", &val ); p_sys->i_cmd = val.i_int; p_sys->i_old_cmd = 0; var_Get( p_stream, SOUT_CFG_PREFIX "gop", &val ); p_sys->i_gop = val.i_int; var_Get( p_stream, SOUT_CFG_PREFIX "qscale", &val ); p_sys->i_qscale = val.i_int; var_Get( p_stream, SOUT_CFG_PREFIX "mute-audio", &val ); p_sys->b_audio = val.b_bool; 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_StreamDelete( p_sys->p_out ); free( p_sys );}/***************************************************************************** * Add: Add an input elementary stream *****************************************************************************/static sout_stream_id_t *Add( sout_stream_t *p_stream, es_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 ) ); memset( id, 0, sizeof( sout_stream_id_t ) ); id->id = NULL; if ( p_fmt->i_cat == VIDEO_ES && (p_fmt->i_codec == VLC_FOURCC('m', 'p', 'g', 'v') || p_fmt->i_codec == VLC_FOURCC('f', 'a', 'k', 'e')) ) { id->b_switcher_video = true; p_fmt->i_codec = VLC_FOURCC('m', 'p', 'g', 'v'); msg_Dbg( p_stream, "creating video switcher for fcc=`%4.4s' cmd:%d", (char*)&p_fmt->i_codec, p_sys->i_cmd ); } else if ( p_fmt->i_cat == AUDIO_ES && p_fmt->i_codec == VLC_FOURCC('m', 'p', 'g', 'a') && p_sys->b_audio ) { int i_ff_codec = CODEC_ID_MP2; int i; id->b_switcher_audio = true; msg_Dbg( p_stream, "creating audio switcher for fcc=`%4.4s' cmd:%d", (char*)&p_fmt->i_codec, p_sys->i_cmd ); /* Allocate the encoder right now. */ if( i_ff_codec == 0 ) { msg_Err( p_stream, "cannot find encoder" ); return NULL; } id->ff_enc = avcodec_find_encoder( i_ff_codec ); if( !id->ff_enc ) { msg_Err( p_stream, "cannot find encoder (avcodec)" ); return NULL; } id->ff_enc_c = avcodec_alloc_context(); /* Set CPU capabilities */ unsigned i_cpu = vlc_CPU(); id->ff_enc_c->dsp_mask = 0; if( !(i_cpu & CPU_CAPABILITY_MMX) ) { id->ff_enc_c->dsp_mask |= FF_MM_MMX; } if( !(i_cpu & CPU_CAPABILITY_MMXEXT) ) { id->ff_enc_c->dsp_mask |= FF_MM_MMXEXT; } if( !(i_cpu & CPU_CAPABILITY_3DNOW) ) { id->ff_enc_c->dsp_mask |= FF_MM_3DNOW; } if( !(i_cpu & CPU_CAPABILITY_SSE) ) { id->ff_enc_c->dsp_mask |= FF_MM_SSE; id->ff_enc_c->dsp_mask |= FF_MM_SSE2; } id->ff_enc_c->sample_rate = p_fmt->audio.i_rate; id->ff_enc_c->channels = p_fmt->audio.i_channels; id->ff_enc_c->bit_rate = p_fmt->i_bitrate; if( avcodec_open( id->ff_enc_c, id->ff_enc ) ) { msg_Err( p_stream, "cannot open encoder" ); return NULL; } id->p_buffer_out = malloc( AVCODEC_MAX_AUDIO_FRAME_SIZE * 2 ); id->p_samples = malloc( id->ff_enc_c->frame_size * p_fmt->audio.i_channels * sizeof(int16_t) ); memset( id->p_samples, 0, id->ff_enc_c->frame_size * p_fmt->audio.i_channels * sizeof(int16_t) ); for ( i = 0; i < MAX_AUDIO; i++ ) { if ( p_sys->pp_audio_ids[i] == NULL ) { p_sys->pp_audio_ids[i] = id; break; } } if ( i == MAX_AUDIO ) { msg_Err( p_stream, "too many audio streams!" ); free( id ); return NULL; } } else { msg_Dbg( p_stream, "do not know what to do when switching (fcc=`%4.4s')", (char*)&p_fmt->i_codec ); } /* src format */ memcpy( &id->f_src, p_fmt, sizeof( es_format_t ) ); /* open output stream */ id->id = p_sys->p_out->pf_add( p_sys->p_out, p_fmt ); if ( id->id == NULL ) { free( id ); return NULL; } return id;}/***************************************************************************** * Del: Del an elementary stream *****************************************************************************/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_switcher_audio ) { int i; for ( i = 0; i < MAX_AUDIO; i++ ) { if ( p_sys->pp_audio_ids[i] == id ) { p_sys->pp_audio_ids[i] = NULL; break; } } } if ( id->ff_enc ) { avcodec_close( id->ff_enc_c ); av_free( id->ff_enc_c ); av_free( id->p_frame ); free( id->p_buffer_out ); } if ( id->id ) { p_sys->p_out->pf_del( p_sys->p_out, id->id ); } free( id ); return VLC_SUCCESS;}/***************************************************************************** * Send: Process an input packet *****************************************************************************/static int Send( sout_stream_t *p_stream, sout_stream_id_t *id, block_t *p_buffer ){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -