static void transcode_video_filter_init( sout_stream_t *p_stream, sout_stream_id_t *id ) { id->p_f_chain = filter_chain_New( p_stream, "video filter2", false, transcode_video_filter_allocation_init, transcode_video_filter_allocation_clear, p_stream->p_sys ); /* Deinterlace */ if( p_stream->p_sys->b_deinterlace ) { filter_chain_AppendFilter( id->p_f_chain, p_stream->p_sys->psz_deinterlace, p_stream->p_sys->p_deinterlace_cfg, &id->p_decoder->fmt_out, &id->p_decoder->fmt_out ); } /* Take care of the scaling and chroma conversions */ if( ( id->p_decoder->fmt_out.video.i_chroma != id->p_encoder->fmt_in.video.i_chroma ) || ( id->p_decoder->fmt_out.video.i_width != id->p_encoder->fmt_in.video.i_width ) || ( id->p_decoder->fmt_out.video.i_height != id->p_encoder->fmt_in.video.i_height ) ) { filter_chain_AppendFilter( id->p_f_chain, NULL, NULL, &id->p_decoder->fmt_out, &id->p_encoder->fmt_in ); } if( p_stream->p_sys->psz_vf2 ) { const es_format_t *p_fmt_out; id->p_uf_chain = filter_chain_New( p_stream, "video filter2", true, transcode_video_filter_allocation_init, transcode_video_filter_allocation_clear, p_stream->p_sys ); filter_chain_Reset( id->p_uf_chain, &id->p_encoder->fmt_in, &id->p_encoder->fmt_in ); filter_chain_AppendFromString( id->p_uf_chain, p_stream->p_sys->psz_vf2 ); p_fmt_out = filter_chain_GetFmtOut( id->p_uf_chain ); es_format_Copy( &id->p_encoder->fmt_in, p_fmt_out ); id->p_encoder->fmt_out.video.i_width = id->p_encoder->fmt_in.video.i_width; id->p_encoder->fmt_out.video.i_height = id->p_encoder->fmt_in.video.i_height; id->p_encoder->fmt_out.video.i_sar_num = id->p_encoder->fmt_in.video.i_sar_num; id->p_encoder->fmt_out.video.i_sar_den = id->p_encoder->fmt_in.video.i_sar_den; } }
static void transcode_video_filter_init( sout_stream_t *p_stream, sout_stream_id_t *id ) { es_format_t *p_fmt_out = &id->p_decoder->fmt_out; id->p_encoder->fmt_in.video.i_chroma = id->p_encoder->fmt_in.i_codec; id->p_f_chain = filter_chain_New( p_stream, "video filter2", false, transcode_video_filter_allocation_init, transcode_video_filter_allocation_clear, p_stream->p_sys ); filter_chain_Reset( id->p_f_chain, p_fmt_out, p_fmt_out ); /* Deinterlace */ if( p_stream->p_sys->b_deinterlace ) { filter_chain_AppendFilter( id->p_f_chain, p_stream->p_sys->psz_deinterlace, p_stream->p_sys->p_deinterlace_cfg, &id->p_decoder->fmt_out, &id->p_decoder->fmt_out ); p_fmt_out = filter_chain_GetFmtOut( id->p_f_chain ); } /* Check that we have visible_width/height*/ if( !p_fmt_out->video.i_visible_height ) p_fmt_out->video.i_visible_height = p_fmt_out->video.i_height; if( !p_fmt_out->video.i_visible_width ) p_fmt_out->video.i_visible_width = p_fmt_out->video.i_width; if( p_stream->p_sys->psz_vf2 ) { id->p_uf_chain = filter_chain_New( p_stream, "video filter2", true, transcode_video_filter_allocation_init, transcode_video_filter_allocation_clear, p_stream->p_sys ); filter_chain_Reset( id->p_uf_chain, p_fmt_out, &id->p_encoder->fmt_in ); filter_chain_AppendFromString( id->p_uf_chain, p_stream->p_sys->psz_vf2 ); p_fmt_out = filter_chain_GetFmtOut( id->p_uf_chain ); es_format_Copy( &id->p_encoder->fmt_in, p_fmt_out ); id->p_encoder->fmt_out.video.i_width = id->p_encoder->fmt_in.video.i_width; id->p_encoder->fmt_out.video.i_height = id->p_encoder->fmt_in.video.i_height; id->p_encoder->fmt_out.video.i_sar_num = id->p_encoder->fmt_in.video.i_sar_num; id->p_encoder->fmt_out.video.i_sar_den = id->p_encoder->fmt_in.video.i_sar_den; } }
/***************************************************************************** * Activate: allocate a chroma function ***************************************************************************** * This function allocates and initializes a chroma function *****************************************************************************/ static int Activate( vlc_object_t *p_this ) { filter_t *p_filter = (filter_t *)p_this; filter_sys_t *p_sys; int i_ret; const bool b_chroma = p_filter->fmt_in.video.i_chroma != p_filter->fmt_out.video.i_chroma; const bool b_resize = p_filter->fmt_in.video.i_width != p_filter->fmt_out.video.i_width || p_filter->fmt_in.video.i_height != p_filter->fmt_out.video.i_height; const bool b_transform = p_filter->fmt_in.video.orientation != p_filter->fmt_out.video.orientation; if( !b_chroma && !b_resize && !b_transform) return VLC_EGENERIC; p_sys = p_filter->p_sys = calloc( 1, sizeof( *p_sys ) ); if( !p_sys ) return VLC_ENOMEM; p_sys->p_chain = filter_chain_New( p_filter, "video filter2", false, BufferAllocationInit, NULL, p_filter ); if( !p_sys->p_chain ) { free( p_sys ); return VLC_EGENERIC; } if( b_transform ) i_ret = BuildTransformChain( p_filter ); else if( b_chroma && b_resize ) i_ret = BuildChromaResize( p_filter ); else if( b_chroma ) i_ret = BuildChromaChain( p_filter ); else i_ret = VLC_EGENERIC; if( i_ret ) { /* Hum ... looks like this really isn't going to work. Too bad. */ filter_chain_Delete( p_sys->p_chain ); free( p_sys ); return VLC_EGENERIC; } /* */ p_filter->pf_video_filter = Chain; return VLC_SUCCESS; }
int transcode_audio_new( sout_stream_t *p_stream, sout_stream_id_t *id ) { sout_stream_sys_t *p_sys = p_stream->p_sys; es_format_t fmt_last; /* * Open decoder */ /* Initialization of decoder structures */ id->p_decoder->fmt_out = id->p_decoder->fmt_in; id->p_decoder->fmt_out.i_extra = 0; id->p_decoder->fmt_out.p_extra = 0; id->p_decoder->pf_decode_audio = NULL; id->p_decoder->pf_aout_buffer_new = audio_new_buffer; id->p_decoder->pf_aout_buffer_del = audio_del_buffer; /* id->p_decoder->p_cfg = p_sys->p_audio_cfg; */ id->p_decoder->p_module = module_need( id->p_decoder, "decoder", "$codec", false ); if( !id->p_decoder->p_module ) { msg_Err( p_stream, "cannot find audio decoder" ); return VLC_EGENERIC; } id->p_decoder->fmt_out.audio.i_bitspersample = aout_BitsPerSample( id->p_decoder->fmt_out.i_codec ); fmt_last = id->p_decoder->fmt_out; /* Fix AAC SBR changing number of channels and sampling rate */ if( !(id->p_decoder->fmt_in.i_codec == VLC_CODEC_MP4A && fmt_last.audio.i_rate != id->p_encoder->fmt_in.audio.i_rate && fmt_last.audio.i_channels != id->p_encoder->fmt_in.audio.i_channels) ) fmt_last.audio.i_rate = id->p_decoder->fmt_in.audio.i_rate; /* * Open encoder */ /* Initialization of encoder format structures */ es_format_Init( &id->p_encoder->fmt_in, id->p_decoder->fmt_in.i_cat, id->p_decoder->fmt_out.i_codec ); id->p_encoder->fmt_in.audio.i_format = id->p_decoder->fmt_out.i_codec; id->p_encoder->fmt_in.audio.i_rate = id->p_encoder->fmt_out.audio.i_rate; id->p_encoder->fmt_in.audio.i_physical_channels = id->p_encoder->fmt_out.audio.i_physical_channels; id->p_encoder->fmt_in.audio.i_original_channels = id->p_encoder->fmt_out.audio.i_original_channels; id->p_encoder->fmt_in.audio.i_channels = id->p_encoder->fmt_out.audio.i_channels; id->p_encoder->fmt_in.audio.i_bitspersample = aout_BitsPerSample( id->p_encoder->fmt_in.i_codec ); id->p_encoder->p_cfg = p_stream->p_sys->p_audio_cfg; id->p_encoder->p_module = module_need( id->p_encoder, "encoder", p_sys->psz_aenc, true ); if( !id->p_encoder->p_module ) { msg_Err( p_stream, "cannot find audio encoder (module:%s fourcc:%4.4s)", p_sys->psz_aenc ? p_sys->psz_aenc : "any", (char *)&p_sys->i_acodec ); module_unneed( id->p_decoder, id->p_decoder->p_module ); id->p_decoder->p_module = NULL; return VLC_EGENERIC; } id->p_encoder->fmt_in.audio.i_format = id->p_encoder->fmt_in.i_codec; id->p_encoder->fmt_in.audio.i_bitspersample = aout_BitsPerSample( id->p_encoder->fmt_in.i_codec ); /* Load user specified audio filters */ if( p_sys->psz_af ) { es_format_t fmt_fl32 = fmt_last; fmt_fl32.i_codec = fmt_fl32.audio.i_format = VLC_CODEC_FL32; id->p_uf_chain = filter_chain_New( p_stream, "audio filter", false, transcode_audio_filter_allocation_init, NULL, NULL ); filter_chain_Reset( id->p_uf_chain, &fmt_last, &fmt_fl32 ); if( transcode_audio_filter_chain_build( p_stream, id->p_uf_chain, &fmt_fl32, &fmt_last ) ) { transcode_audio_close( id ); return VLC_EGENERIC; } fmt_last = fmt_fl32; if( filter_chain_AppendFromString( id->p_uf_chain, p_sys->psz_af ) > 0 ) fmt_last = *filter_chain_GetFmtOut( id->p_uf_chain ); } /* Load conversion filters */ id->p_f_chain = filter_chain_New( p_stream, "audio filter", true, transcode_audio_filter_allocation_init, NULL, NULL ); filter_chain_Reset( id->p_f_chain, &fmt_last, &id->p_encoder->fmt_in ); if( transcode_audio_filter_chain_build( p_stream, id->p_f_chain, &id->p_encoder->fmt_in, &fmt_last ) ) { transcode_audio_close( id ); return VLC_EGENERIC; } fmt_last = id->p_encoder->fmt_in; /* */ id->p_encoder->fmt_out.i_codec = vlc_fourcc_GetCodec( AUDIO_ES, id->p_encoder->fmt_out.i_codec ); return VLC_SUCCESS; }
static int Activate( vlc_object_t *p_this ) { filter_t *p_filter = (filter_t *)p_this; unsigned i_canvas_width; /* width of output canvas */ unsigned i_canvas_height; /* height of output canvas */ unsigned i_canvas_aspect; /* canvas PictureAspectRatio */ es_format_t fmt; /* target format after up/down conversion */ char psz_croppadd[100]; int i_padd,i_offset; char *psz_aspect, *psz_parser; bool b_padd; unsigned i_fmt_in_aspect; if( !p_filter->b_allow_fmt_out_change ) { msg_Err( p_filter, "Picture format change isn't allowed" ); return VLC_EGENERIC; } if( p_filter->fmt_in.video.i_chroma != p_filter->fmt_out.video.i_chroma ) { msg_Err( p_filter, "Input and output chromas don't match" ); return VLC_EGENERIC; } config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options, p_filter->p_cfg ); i_canvas_width = var_CreateGetInteger( p_filter, CFG_PREFIX "width" ); i_canvas_height = var_CreateGetInteger( p_filter, CFG_PREFIX "height" ); if( i_canvas_width == 0 || i_canvas_height == 0 ) { msg_Err( p_filter, "Width and height options must be set" ); return VLC_EGENERIC; } if( i_canvas_width & 1 || i_canvas_height & 1 ) { /* If this restriction were ever relaxed, it is very important to * get the field polatiry correct */ msg_Err( p_filter, "Width and height options must be even integers" ); return VLC_EGENERIC; } i_fmt_in_aspect = (int64_t)p_filter->fmt_in.video.i_sar_num * p_filter->fmt_in.video.i_width * VOUT_ASPECT_FACTOR / p_filter->fmt_in.video.i_sar_den / p_filter->fmt_in.video.i_height; psz_aspect = var_CreateGetNonEmptyString( p_filter, CFG_PREFIX "aspect" ); if( psz_aspect ) { psz_parser = strchr( psz_aspect, ':' ); int numerator = atoi( psz_aspect ); int denominator = psz_parser ? atoi( psz_parser+1 ) : 0; denominator = denominator == 0 ? 1 : denominator; i_canvas_aspect = numerator * VOUT_ASPECT_FACTOR / denominator; free( psz_aspect ); if( numerator <= 0 || denominator < 0 ) { msg_Err( p_filter, "Aspect ratio must be strictly positive" ); return VLC_EGENERIC; } } else { /* if there is no user supplied aspect ratio, assume the canvas * has the same sample aspect ratio as the subpicture */ /* aspect = subpic_sar * canvas_width / canvas_height * where subpic_sar = subpic_ph * subpic_par / subpic_pw */ i_canvas_aspect = (uint64_t) p_filter->fmt_in.video.i_height * i_fmt_in_aspect * i_canvas_width / (i_canvas_height * p_filter->fmt_in.video.i_width); } b_padd = var_CreateGetBool( p_filter, CFG_PREFIX "padd" ); filter_sys_t *p_sys = (filter_sys_t *)malloc( sizeof( filter_sys_t ) ); if( !p_sys ) return VLC_ENOMEM; p_filter->p_sys = p_sys; p_sys->p_chain = filter_chain_New( p_filter, "video filter2", true, alloc_init, NULL, p_filter ); if( !p_sys->p_chain ) { msg_Err( p_filter, "Could not allocate filter chain" ); free( p_sys ); return VLC_EGENERIC; } es_format_Copy( &fmt, &p_filter->fmt_in ); /* one dimension will end up with one of the following: */ fmt.video.i_width = i_canvas_width; fmt.video.i_height = i_canvas_height; if( b_padd ) { /* Padd */ if( i_canvas_aspect > i_fmt_in_aspect ) { /* The canvas has a wider aspect than the subpicture: * ie, pillarbox the [scaled] subpicture */ /* The following is derived form: * width = upconverted_subpic_height * subpic_par / canvas_sar * where canvas_sar = canvas_width / (canvas_height * canvas_par) * then simplify */ fmt.video.i_width = i_canvas_width * i_fmt_in_aspect / i_canvas_aspect; if( fmt.video.i_width & 1 ) fmt.video.i_width -= 1; i_padd = (i_canvas_width - fmt.video.i_width) / 2; i_offset = (i_padd & 1); _snprintf( psz_croppadd, 100, "croppadd{paddleft=%d,paddright=%d}", i_padd - i_offset, i_padd + i_offset ); // sunqueen modify } else { /* The canvas has a taller aspect than the subpicture: * ie, letterbox the [scaled] subpicture */ fmt.video.i_height = i_canvas_height * i_canvas_aspect / i_fmt_in_aspect; if( fmt.video.i_height & 1 ) fmt.video.i_height -= 1; i_padd = (i_canvas_height - fmt.video.i_height ) / 2; i_offset = (i_padd & 1); _snprintf( psz_croppadd, 100, "croppadd{paddtop=%d,paddbottom=%d}", i_padd - i_offset, i_padd + i_offset ); // sunqueen modify } } else { /* Crop */ if( i_canvas_aspect < i_fmt_in_aspect ) { /* The canvas has a narrower aspect than the subpicture: * ie, crop the [scaled] subpicture horizontally */ fmt.video.i_width = i_canvas_width * i_fmt_in_aspect / i_canvas_aspect; if( fmt.video.i_width & 1 ) fmt.video.i_width -= 1; i_padd = (fmt.video.i_width - i_canvas_width) / 2; i_offset = (i_padd & 1); _snprintf( psz_croppadd, 100, "croppadd{cropleft=%d,cropright=%d}", i_padd - i_offset, i_padd + i_offset ); // sunqueen modify } else { /* The canvas has a shorter aspect than the subpicture: * ie, crop the [scaled] subpicture vertically */ fmt.video.i_height = i_canvas_height * i_canvas_aspect / i_fmt_in_aspect; if( fmt.video.i_height & 1 ) fmt.video.i_height -= 1; i_padd = (fmt.video.i_height - i_canvas_height) / 2; i_offset = (i_padd & 1); _snprintf( psz_croppadd, 100, "croppadd{croptop=%d,cropbottom=%d}", i_padd - i_offset, i_padd + i_offset ); // sunqueen modify } } /* xxx, should the clean area include the letter-boxing? * probably not, as some codecs can make use of that information * and it should be a scaled version of the input clean area * -- davidf */ fmt.video.i_visible_width = fmt.video.i_width; fmt.video.i_visible_height = fmt.video.i_height; filter_chain_Reset( p_sys->p_chain, &p_filter->fmt_in, &fmt ); /* Append scaling module */ filter_chain_AppendFilter( p_sys->p_chain, NULL, NULL, NULL, NULL ); /* Append padding module */ filter_chain_AppendFromString( p_sys->p_chain, psz_croppadd ); fmt = *filter_chain_GetFmtOut( p_sys->p_chain ); es_format_Copy( &p_filter->fmt_out, &fmt ); p_filter->fmt_out.video.i_sar_num = i_canvas_aspect * p_filter->fmt_out.video.i_height; p_filter->fmt_out.video.i_sar_den = VOUT_ASPECT_FACTOR * p_filter->fmt_out.video.i_width; if( p_filter->fmt_out.video.i_width != i_canvas_width || p_filter->fmt_out.video.i_height != i_canvas_height ) { msg_Warn( p_filter, "Looks like something went wrong. " "Output size is %dx%d while we asked for %dx%d", p_filter->fmt_out.video.i_width, p_filter->fmt_out.video.i_height, i_canvas_width, i_canvas_height ); } p_filter->pf_video_filter = Filter; return VLC_SUCCESS; }
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; bridge_t *p_bridge; bridged_es_t *p_es; char *psz_chain; int i; if( p_sys->b_inited || p_fmt->i_cat != VIDEO_ES ) return NULL; /* Create decoder object */ p_sys->p_decoder = vlc_object_create( p_stream, sizeof( decoder_t ) ); if( !p_sys->p_decoder ) return NULL; p_sys->p_decoder->p_module = NULL; p_sys->p_decoder->fmt_in = *p_fmt; p_sys->p_decoder->b_pace_control = false; p_sys->p_decoder->fmt_out = p_sys->p_decoder->fmt_in; p_sys->p_decoder->fmt_out.i_extra = 0; p_sys->p_decoder->fmt_out.p_extra = 0; p_sys->p_decoder->pf_decode_video = 0; p_sys->p_decoder->pf_vout_buffer_new = video_new_buffer_decoder; p_sys->p_decoder->pf_vout_buffer_del = video_del_buffer_decoder; p_sys->p_decoder->pf_picture_link = video_link_picture_decoder; p_sys->p_decoder->pf_picture_unlink = video_unlink_picture_decoder; p_sys->p_decoder->p_owner = malloc( sizeof(decoder_owner_sys_t) ); if( !p_sys->p_decoder->p_owner ) { vlc_object_release( p_sys->p_decoder ); return NULL; } p_sys->p_decoder->p_owner->video = p_fmt->video; //p_sys->p_decoder->p_cfg = p_sys->p_video_cfg; p_sys->p_decoder->p_module = module_need( p_sys->p_decoder, "decoder", "$codec", false ); if( !p_sys->p_decoder->p_module || !p_sys->p_decoder->pf_decode_video ) { if( p_sys->p_decoder->p_module ) { msg_Err( p_stream, "instanciated a non video decoder" ); module_unneed( p_sys->p_decoder, p_sys->p_decoder->p_module ); } else { msg_Err( p_stream, "cannot find decoder" ); } free( p_sys->p_decoder->p_owner ); vlc_object_release( p_sys->p_decoder ); return NULL; } p_sys->b_inited = true; vlc_global_lock( VLC_MOSAIC_MUTEX ); p_bridge = GetBridge( p_stream ); if ( p_bridge == NULL ) { vlc_object_t *p_libvlc = VLC_OBJECT( p_stream->p_libvlc ); vlc_value_t val; p_bridge = xmalloc( sizeof( bridge_t ) ); var_Create( p_libvlc, "mosaic-struct", VLC_VAR_ADDRESS ); val.p_address = p_bridge; var_Set( p_libvlc, "mosaic-struct", val ); p_bridge->i_es_num = 0; p_bridge->pp_es = NULL; } for ( i = 0; i < p_bridge->i_es_num; i++ ) { if ( p_bridge->pp_es[i]->b_empty ) break; } if ( i == p_bridge->i_es_num ) { p_bridge->pp_es = xrealloc( p_bridge->pp_es, (p_bridge->i_es_num + 1) * sizeof(bridged_es_t *) ); p_bridge->i_es_num++; p_bridge->pp_es[i] = xmalloc( sizeof(bridged_es_t) ); } p_sys->p_es = p_es = p_bridge->pp_es[i]; p_es->i_alpha = var_GetInteger( p_stream, CFG_PREFIX "alpha" ); p_es->i_x = var_GetInteger( p_stream, CFG_PREFIX "x" ); p_es->i_y = var_GetInteger( p_stream, CFG_PREFIX "y" ); //p_es->fmt = *p_fmt; p_es->psz_id = p_sys->psz_id; p_es->p_picture = NULL; p_es->pp_last = &p_es->p_picture; p_es->b_empty = false; vlc_global_unlock( VLC_MOSAIC_MUTEX ); if ( p_sys->i_height || p_sys->i_width ) { p_sys->p_image = image_HandlerCreate( p_stream ); } else { p_sys->p_image = NULL; } msg_Dbg( p_stream, "mosaic bridge id=%s pos=%d", p_es->psz_id, i ); /* Create user specified video filters */ psz_chain = var_GetNonEmptyString( p_stream, CFG_PREFIX "vfilter" ); msg_Dbg( p_stream, "psz_chain: %s", psz_chain ); if( psz_chain ) { p_sys->p_vf2 = filter_chain_New( p_stream, "video filter2", false, video_filter_buffer_allocation_init, NULL, p_sys->p_decoder->p_owner ); es_format_t fmt; es_format_Copy( &fmt, &p_sys->p_decoder->fmt_out ); if( p_sys->i_chroma ) fmt.video.i_chroma = p_sys->i_chroma; filter_chain_Reset( p_sys->p_vf2, &fmt, &fmt ); filter_chain_AppendFromString( p_sys->p_vf2, psz_chain ); free( psz_chain ); } else { p_sys->p_vf2 = NULL; } return (sout_stream_id_t *)p_sys; }