From 924e05dc3db078d17e8435ec427f8f4863b8f11d Mon Sep 17 00:00:00 2001 From: Gildas Bazin Date: Sun, 8 Aug 2004 21:14:38 +0000 Subject: [PATCH] * modules/stream_out/transcode.c: added support for subtitles overlaying when transcoding (no resizing yet). * include/vlc_common.h: added a b_force member that is set when a module is forced (ie. module specified in module_Need()). --- include/vlc_codec.h | 2 +- include/vlc_common.h | 1 + modules/stream_out/transcode.c | 540 ++++++++++++++++++++++++++++++++- src/misc/modules.c | 4 + src/misc/objects.c | 1 + 5 files changed, 533 insertions(+), 15 deletions(-) diff --git a/include/vlc_codec.h b/include/vlc_codec.h index 01a7d93010..753634c24e 100644 --- a/include/vlc_codec.h +++ b/include/vlc_codec.h @@ -101,11 +101,11 @@ struct encoder_t /* Module properties */ module_t * p_module; encoder_sys_t * p_sys; - vlc_bool_t b_force; block_t * ( * pf_header )( encoder_t * ); block_t * ( * pf_encode_video )( encoder_t *, picture_t * ); block_t * ( * pf_encode_audio )( encoder_t *, aout_buffer_t * ); + block_t * ( * pf_encode_sub )( encoder_t *, subpicture_t * ); /* Properties of the input data fed to the encoder */ es_format_t fmt_in; diff --git a/include/vlc_common.h b/include/vlc_common.h index a55d2be869..c330482765 100644 --- a/include/vlc_common.h +++ b/include/vlc_common.h @@ -414,6 +414,7 @@ typedef int ( * vlc_callback_t ) ( vlc_object_t *, /* variable's object */ volatile vlc_bool_t b_die; /**< set by the outside */ \ volatile vlc_bool_t b_dead; /**< set by the object */ \ volatile vlc_bool_t b_attached; /**< set by the object */ \ + vlc_bool_t b_force; /**< set by the outside (eg. module_Need()) */ \ \ /* Object variables */ \ vlc_mutex_t var_lock; \ diff --git a/modules/stream_out/transcode.c b/modules/stream_out/transcode.c index 89b65215b7..4d815e51da 100644 --- a/modules/stream_out/transcode.c +++ b/modules/stream_out/transcode.c @@ -5,7 +5,7 @@ * $Id$ * * Authors: Laurent Aimar - * Gildas Bazin + * Gildas Bazin * * 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 @@ -33,6 +33,8 @@ #include #include #include +#include "vlc_filter.h" +#include "osd.h" /* ffmpeg header */ #ifdef HAVE_FFMPEG_AVCODEC_H @@ -107,6 +109,15 @@ "Allows you to specify the number of audio channels used for the " \ "streaming output." ) +#define SENC_TEXT N_("Subtitles encoder") +#define SENC_LONGTEXT N_( \ + "Allows you to specify the subtitles encoder to use and its associated " \ + "options." ) +#define SCODEC_TEXT N_("Destination subtitles codec") +#define SCODEC_LONGTEXT N_( \ + "Allows you to specify the destination subtitles codec used for the " \ + "streaming output." ) + #define THREADS_TEXT N_("Number of threads") #define THREADS_LONGTEXT N_( \ "Allows you to specify the number of threads used for the transcoding." ) @@ -157,6 +168,13 @@ vlc_module_begin(); add_integer( SOUT_CFG_PREFIX "samplerate", 0, NULL, ARATE_TEXT, ARATE_LONGTEXT, VLC_TRUE ); + add_string( SOUT_CFG_PREFIX "senc", NULL, NULL, SENC_TEXT, + SENC_LONGTEXT, VLC_FALSE ); + add_string( SOUT_CFG_PREFIX "scodec", NULL, NULL, SCODEC_TEXT, + SCODEC_LONGTEXT, VLC_FALSE ); + add_bool( SOUT_CFG_PREFIX "soverlay", 0, NULL, SCODEC_TEXT, + SCODEC_LONGTEXT, VLC_FALSE ); + add_integer( SOUT_CFG_PREFIX "threads", 0, NULL, THREADS_TEXT, THREADS_LONGTEXT, VLC_TRUE ); vlc_module_end(); @@ -164,7 +182,8 @@ vlc_module_end(); static const char *ppsz_sout_options[] = { "venc", "vcodec", "vb", "croptop", "cropbottom", "cropleft", "cropright", "scale", "width", "height", "deinterlace", "threads", - "aenc", "acodec", "ab", "samplerate", "channels", NULL + "aenc", "acodec", "ab", "samplerate", "channels", + "senc", "scodec", "soverlay", NULL }; /***************************************************************************** @@ -184,6 +203,13 @@ static int transcode_video_ffmpeg_process( sout_stream_t *, sout_stream_id_t *, static int transcode_video_ffmpeg_getframebuf( struct AVCodecContext *, AVFrame *); +static int transcode_spu_new ( sout_stream_t *, sout_stream_id_t * ); +static void transcode_spu_close ( sout_stream_t *, sout_stream_id_t * ); +static int transcode_spu_process( sout_stream_t *, sout_stream_id_t *, + block_t *, block_t ** ); +static subpicture_t *transcode_spu_get( sout_stream_t *, sout_stream_id_t *, + mtime_t ); + static int EncoderThread( struct sout_stream_sys_t * p_sys ); static int pi_channels_maps[6] = @@ -198,6 +224,7 @@ static int pi_channels_maps[6] = }; #define PICTURE_RING_SIZE 64 +#define SUBPICTURE_RING_SIZE 20 struct sout_stream_sys_t { @@ -211,6 +238,7 @@ struct sout_stream_sys_t picture_t * pp_pics[PICTURE_RING_SIZE]; int i_first_pic, i_last_pic; + /* Audio */ vlc_fourcc_t i_acodec; /* codec audio (0 if not transcode) */ char *psz_aenc; sout_cfg_t *p_audio_cfg; @@ -218,7 +246,8 @@ struct sout_stream_sys_t int i_channels; int i_abitrate; - vlc_fourcc_t i_vcodec; /* " video " " " " */ + /* Video */ + vlc_fourcc_t i_vcodec; /* codec video (0 if not transcode) */ char *psz_venc; sout_cfg_t *p_video_cfg; int i_vbitrate; @@ -238,6 +267,16 @@ struct sout_stream_sys_t vlc_bool_t b_input_has_b_frames; mtime_t i_output_pts; + + /* SPU */ + vlc_fourcc_t i_scodec; /* codec spu (0 if not transcode) */ + char *psz_senc; + vlc_bool_t b_soverlay; + sout_cfg_t *p_spu_cfg; + subpicture_t *pp_subpics[SUBPICTURE_RING_SIZE]; + + /* Filters */ + filter_t *p_filter_blend; }; /***************************************************************************** @@ -248,6 +287,7 @@ 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; + int i; p_sys = vlc_object_create( p_this, sizeof( sout_stream_sys_t ) ); @@ -363,6 +403,43 @@ static int Open( vlc_object_t *p_this ) p_sys->f_scale, p_sys->i_vbitrate / 1000 ); } + /* Subpictures transcoding parameters */ + var_Get( p_stream, SOUT_CFG_PREFIX "senc", &val ); + p_sys->psz_senc = NULL; + p_sys->p_spu_cfg = NULL; + if( val.psz_string && *val.psz_string ) + { + char *psz_next; + psz_next = sout_CfgCreate( &p_sys->psz_senc, &p_sys->p_spu_cfg, + val.psz_string ); + if( psz_next ) free( psz_next ); + } + if( val.psz_string ) free( val.psz_string ); + + var_Get( p_stream, SOUT_CFG_PREFIX "scodec", &val ); + p_sys->i_scodec = 0; + if( val.psz_string && *val.psz_string ) + { + char fcc[4] = " "; + memcpy( fcc, val.psz_string, __MIN( strlen( val.psz_string ), 4 ) ); + p_sys->i_scodec = VLC_FOURCC( fcc[0], fcc[1], fcc[2], fcc[3] ); + } + if( val.psz_string ) free( val.psz_string ); + + if( p_sys->i_scodec ) + { + msg_Dbg( p_stream, "codec spu=%4.4s", (char *)&p_sys->i_acodec ); + } + + var_Get( p_stream, SOUT_CFG_PREFIX "soverlay", &val ); + p_sys->b_soverlay = val.b_bool; + p_sys->p_filter_blend = 0; + + for( i = 0; i < SUBPICTURE_RING_SIZE; i++ ) + { + p_sys->pp_subpics[i] = 0; + } + p_stream->pf_add = Add; p_stream->pf_del = Del; p_stream->pf_send = Send; @@ -412,6 +489,30 @@ static void Close( vlc_object_t * p_this ) } if( p_sys->psz_venc ) free( p_sys->psz_venc ); + while( p_sys->p_spu_cfg != NULL ) + { + sout_cfg_t *p_next = p_sys->p_spu_cfg->p_next; + + if( p_sys->p_spu_cfg->psz_name ) + free( p_sys->p_spu_cfg->psz_name ); + if( p_sys->p_spu_cfg->psz_value ) + free( p_sys->p_spu_cfg->psz_value ); + free( p_sys->p_spu_cfg ); + + p_sys->p_spu_cfg = p_next; + } + if( p_sys->psz_senc ) free( p_sys->psz_senc ); + + if( p_sys->p_filter_blend ) + { + if( p_sys->p_filter_blend->p_module ) + module_Unneed( p_sys->p_filter_blend, + p_sys->p_filter_blend->p_module ); + + vlc_object_detach( p_sys->p_filter_blend ); + vlc_object_destroy( p_sys->p_filter_blend ); + } + vlc_object_destroy( p_sys ); } @@ -425,6 +526,9 @@ struct sout_stream_id_t /* id of the out stream */ void *id; + /* Decoder */ + decoder_t *p_decoder; + /* Encoder */ encoder_t *p_encoder; vlc_fourcc_t b_enc_inited; @@ -444,19 +548,21 @@ struct sout_stream_id_t 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 */ + AVFrame *p_ff_pic_tmp3; /* to do subpicture overlay */ ImgReSampleContext *p_vresample; }; -static sout_stream_id_t * Add( sout_stream_t *p_stream, es_format_t *p_fmt ) +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; + 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; id->id = NULL; + id->p_decoder = NULL; id->p_encoder = NULL; if( p_fmt->i_cat == AUDIO_ES && (p_sys->i_acodec || p_sys->psz_aenc) ) @@ -536,6 +642,60 @@ static sout_stream_id_t * Add( sout_stream_t *p_stream, es_format_t *p_fmt ) #endif id->b_transcode = VLC_TRUE; } + else if( p_fmt->i_cat == SPU_ES && (p_sys->i_scodec || p_sys->psz_senc) ) + { + msg_Dbg( p_stream, "creating subtitles transcoding from fcc=`%4.4s' " + "to fcc=`%4.4s'", (char*)&p_fmt->i_codec, + (char*)&p_sys->i_scodec ); + + /* src format */ + memcpy( &id->f_src, p_fmt, sizeof( es_format_t ) ); + + /* create dst format */ + es_format_Init( &id->f_dst, SPU_ES, p_sys->i_scodec ); + id->f_dst.i_id = id->f_src.i_id; + id->f_dst.i_group = id->f_src.i_group; + if( id->f_src.psz_language ) + id->f_dst.psz_language = strdup( id->f_src.psz_language ); + id->f_dst.i_extra = 0; + id->f_dst.p_extra = NULL; + + /* build decoder -> filter -> encoder */ + if( transcode_spu_new( p_stream, id ) ) + { + msg_Err( p_stream, "cannot create subtitles 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; + + if( id->id == NULL ) + { + free( id ); + return NULL; + } + } + else if( p_fmt->i_cat == SPU_ES && p_sys->b_soverlay ) + { + msg_Dbg( p_stream, "subtitles (fcc=`%4.4s') overlaying", + (char*)&p_fmt->i_codec ); + + id->b_transcode = VLC_TRUE; + + /* src format */ + memcpy( &id->f_src, p_fmt, sizeof( es_format_t ) ); + + /* build decoder -> filter -> encoder */ + if( transcode_spu_new( p_stream, id ) ) + { + msg_Err( p_stream, "cannot create subtitles chain" ); + free( id ); + return NULL; + } + } else { msg_Dbg( p_stream, "not transcoding a stream (fcc=`%4.4s')", @@ -553,7 +713,7 @@ static sout_stream_id_t * Add( sout_stream_t *p_stream, es_format_t *p_fmt ) return id; } -static int Del ( sout_stream_t *p_stream, sout_stream_id_t *id ) +static int Del( sout_stream_t *p_stream, sout_stream_id_t *id ) { sout_stream_sys_t *p_sys = p_stream->p_sys; @@ -567,6 +727,10 @@ static int Del ( sout_stream_t *p_stream, sout_stream_id_t *id ) { transcode_video_ffmpeg_close( p_stream, id ); } + else if( id->f_src.i_cat == SPU_ES ) + { + transcode_spu_close( p_stream, id ); + } } if( id->id ) p_sys->p_out->pf_del( p_sys->p_out, id->id ); @@ -597,6 +761,7 @@ static int Send( sout_stream_t *p_stream, sout_stream_id_t *id, { transcode_audio_ffmpeg_process( p_stream, id, p_buffer, &p_buffer_out ); + block_Release( p_buffer ); } else if( id->f_src.i_cat == VIDEO_ES ) { @@ -606,8 +771,20 @@ static int Send( sout_stream_t *p_stream, sout_stream_id_t *id, block_Release( p_buffer ); return VLC_EGENERIC; } + block_Release( p_buffer ); + } + else if( id->f_src.i_cat == SPU_ES ) + { + if( transcode_spu_process( p_stream, id, p_buffer, + &p_buffer_out ) != VLC_SUCCESS ) + { + return VLC_EGENERIC; + } + } + else + { + block_Release( p_buffer ); } - block_Release( p_buffer ); if( p_buffer_out ) { @@ -670,6 +847,9 @@ static struct { VLC_FOURCC( 'S', 'V', 'Q', '3' ), CODEC_ID_SVQ3 }, { VLC_FOURCC( 'h', '2', '6', '4' ), CODEC_ID_H264 }, #endif +#if LIBAVCODEC_BUILD >= 4719 + { VLC_FOURCC( 'S', 'N', 'O', 'W' ), CODEC_ID_SNOW }, +#endif /* raw video code, only used for 'encoding' */ { VLC_FOURCC( 'I', '4', '2', '0' ), CODEC_ID_RAWVIDEO }, @@ -839,8 +1019,6 @@ static int transcode_audio_ffmpeg_new( sout_stream_t *p_stream, id->p_encoder->fmt_out.i_bitrate = id->f_dst.i_bitrate; id->p_encoder->p_cfg = p_stream->p_sys->p_audio_cfg; - if( p_stream->p_sys->psz_aenc && - *p_stream->p_sys->psz_aenc ) id->p_encoder->b_force = VLC_TRUE; /* Attach object to parent so object variables inheritance works */ vlc_object_attach( id->p_encoder, p_stream ); @@ -1293,11 +1471,10 @@ static int transcode_video_ffmpeg_new( sout_stream_t *p_stream, id->p_ff_pic_tmp0 = NULL; id->p_ff_pic_tmp1 = NULL; id->p_ff_pic_tmp2 = NULL; + id->p_ff_pic_tmp3 = NULL; id->p_vresample = NULL; id->p_encoder->p_cfg = p_sys->p_video_cfg; - if( p_stream->p_sys->psz_venc && - *p_stream->p_sys->psz_venc ) id->p_encoder->b_force = VLC_TRUE; /* Attach object to parent so object variables inheritance works */ vlc_object_attach( id->p_encoder, p_stream ); @@ -1380,16 +1557,21 @@ static void transcode_video_ffmpeg_close ( sout_stream_t *p_stream, free( id->p_ff_pic_tmp0->data[0] ); free( id->p_ff_pic_tmp0 ); } - if( id->p_ff_pic_tmp1) + 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) + if( id->p_ff_pic_tmp2 ) { free( id->p_ff_pic_tmp2->data[0] ); free( id->p_ff_pic_tmp2 ); } + if( id->p_ff_pic_tmp3 ) + { + free( id->p_ff_pic_tmp3->data[0] ); + free( id->p_ff_pic_tmp3 ); + } if( id->p_vresample ) { img_resample_close( id->p_vresample ); @@ -1417,6 +1599,7 @@ static int transcode_video_ffmpeg_process( sout_stream_t *p_stream, block_t *p_block; picture_t * p_pic; int i_plane; + subpicture_t *p_subpic = 0; /* decode frame */ frame = id->p_ff_pic; @@ -1680,6 +1863,44 @@ static int transcode_video_ffmpeg_process( sout_stream_t *p_stream, id->f_dst.video.i_width * VOUT_ASPECT_FACTOR / id->f_dst.video.i_height ); + /* Check if we have a subpicture to overlay */ + if( p_sys->p_filter_blend ) + { + p_subpic = transcode_spu_get( p_stream, id, p_sys->i_output_pts ); + + if( p_subpic && frame != id->p_ff_pic_tmp0 && + frame != id->p_ff_pic_tmp1 && frame != id->p_ff_pic_tmp2 ) + { + if( id->p_ff_pic_tmp3 == NULL ) + { + uint8_t *buf = malloc( frame->linesize[0] * + p_pic->p[0].i_lines * 3 ); + id->p_ff_pic_tmp3 = avcodec_alloc_frame(); + *id->p_ff_pic_tmp3 = *frame; + id->p_ff_pic_tmp3->data[0] = buf; + id->p_ff_pic_tmp3->data[1] = id->p_ff_pic_tmp3->data[0] + + frame->linesize[0] * p_pic->p[0].i_lines; + id->p_ff_pic_tmp3->data[2] = id->p_ff_pic_tmp3->data[1] + + frame->linesize[1] * p_pic->p[1].i_lines; + } + + for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ ) + { + p_stream->p_vlc->pf_memcpy( + id->p_ff_pic_tmp3->data[i_plane], + frame->data[i_plane], + p_pic->p[i_plane].i_lines * frame->linesize[i_plane] ); + } + + id->p_ff_pic_tmp3->repeat_pict = frame->repeat_pict; +#if LIBAVCODEC_BUILD >= 4685 + id->p_ff_pic_tmp3->interlaced_frame = frame->interlaced_frame; + id->p_ff_pic_tmp3->top_field_first = frame->top_field_first; +#endif + frame = id->p_ff_pic_tmp3; + } + } + for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ ) { p_pic->p[i_plane].i_pitch = frame->linesize[i_plane]; @@ -1714,6 +1935,71 @@ static int transcode_video_ffmpeg_process( sout_stream_t *p_stream, id->ff_dec_c->frame_rate_base / (2 * id->ff_dec_c->frame_rate); } + /* Overlay subpicture */ + if( p_subpic ) + { + int i_width, i_height; + + p_sys->p_filter_blend->fmt_out = id->p_encoder->fmt_in; + p_sys->p_filter_blend->fmt_out.video.i_visible_width = + p_sys->p_filter_blend->fmt_out.video.i_width; + p_sys->p_filter_blend->fmt_out.video.i_visible_height = + p_sys->p_filter_blend->fmt_out.video.i_height; + p_sys->p_filter_blend->fmt_out.video.i_chroma = + VLC_FOURCC('I','4','2','0'); + + i_width = id->p_encoder->fmt_in.video.i_width; + i_height = id->p_encoder->fmt_in.video.i_height; + + while( p_subpic != NULL ) + { + subpicture_region_t *p_region = p_subpic->p_region; + + while( p_region && p_sys->p_filter_blend && + p_sys->p_filter_blend->pf_video_blend ) + { + int i_x_offset = p_region->i_x + p_subpic->i_x; + int i_y_offset = p_region->i_y + p_subpic->i_y; + + if( p_subpic->i_flags & OSD_ALIGN_BOTTOM ) + { + i_y_offset = i_height - p_region->fmt.i_height - + p_subpic->i_y; + } + else if ( !(p_subpic->i_flags & OSD_ALIGN_TOP) ) + { + i_y_offset = i_height / 2 - p_region->fmt.i_height / 2; + } + + if( p_subpic->i_flags & OSD_ALIGN_RIGHT ) + { + i_x_offset = i_width - p_region->fmt.i_width - + p_subpic->i_x; + } + else if ( !(p_subpic->i_flags & OSD_ALIGN_LEFT) ) + { + i_x_offset = i_width / 2 - p_region->fmt.i_width / 2; + } + + if( p_subpic->b_absolute ) + { + i_x_offset = p_region->i_x + p_subpic->i_x; + i_y_offset = p_region->i_y + p_subpic->i_y; + } + + p_sys->p_filter_blend->fmt_in.video = p_region->fmt; + + p_sys->p_filter_blend->pf_video_blend( + p_sys->p_filter_blend, p_pic, p_pic, + &p_region->picture, i_x_offset, i_y_offset ); + + p_region = p_region->p_next; + } + + p_subpic = p_subpic->p_next; + } + } + if ( p_sys->i_threads >= 1 ) { vlc_mutex_lock( &p_sys->lock_out ); @@ -1836,3 +2122,229 @@ static int transcode_video_ffmpeg_getframebuf(struct AVCodecContext *p_context, return avcodec_default_get_buffer( p_context, p_frame ); } + +/* + * SPU + */ +static subpicture_t *spu_new_buffer( decoder_t * ); +static void spu_del_buffer( decoder_t *, subpicture_t * ); + +static int transcode_spu_new( sout_stream_t *p_stream, sout_stream_id_t *id ) +{ + sout_stream_sys_t *p_sys = p_stream->p_sys; + + /* Open decoder */ + id->p_decoder = vlc_object_create( p_stream, VLC_OBJECT_DECODER ); + + /* Initialization of decoder format structures */ + id->p_decoder->fmt_in = id->f_src; + id->p_decoder->pf_spu_buffer_new = spu_new_buffer; + id->p_decoder->pf_spu_buffer_del = spu_del_buffer; + //id->p_decoder->p_cfg = p_sys->p_spu_cfg; + + /* Attach object to parent so object variables inheritance works */ + vlc_object_attach( id->p_decoder, p_stream ); + + id->p_decoder->p_module = + module_Need( id->p_decoder, "decoder", "$codec", VLC_TRUE ); + + if( !id->p_decoder->p_module ) + { + vlc_object_detach( id->p_decoder ); + vlc_object_destroy( id->p_decoder ); + msg_Err( p_stream, "cannot find decoder" ); + return VLC_EGENERIC; + } + + if( !p_sys->b_soverlay ) + { + /* Open encoder */ + id->p_encoder = vlc_object_create( p_stream, VLC_OBJECT_ENCODER ); + + /* Initialization of encoder format structures */ + es_format_Init( &id->p_encoder->fmt_in, + id->f_src.i_cat, id->f_src.i_codec ); + + id->p_encoder->fmt_out = id->p_encoder->fmt_in; + id->p_encoder->fmt_out.i_codec = id->f_dst.i_codec; + id->p_encoder->fmt_out.i_bitrate = id->f_dst.i_bitrate; + + id->p_encoder->p_cfg = p_sys->p_spu_cfg; + + /* Attach object to parent so object variables inheritance works */ + vlc_object_attach( id->p_encoder, p_stream ); + + id->p_encoder->p_module = + module_Need( id->p_encoder, "encoder", p_sys->psz_senc, VLC_TRUE ); + + if( !id->p_encoder->p_module ) + { + module_Unneed( id->p_decoder, id->p_decoder->p_module ); + vlc_object_detach( id->p_decoder ); + vlc_object_destroy( id->p_decoder ); + + vlc_object_detach( id->p_encoder ); + vlc_object_destroy( id->p_encoder ); + msg_Err( p_stream, "cannot find encoder" ); + return VLC_EGENERIC; + } + } + else + { + p_sys->p_filter_blend = + vlc_object_create( p_stream, sizeof(filter_t) ); + vlc_object_attach( p_sys->p_filter_blend, p_stream ); + p_sys->p_filter_blend->fmt_out.video.i_chroma = + VLC_FOURCC('I','4','2','0'); + p_sys->p_filter_blend->fmt_in.video.i_chroma = + VLC_FOURCC('Y','U','V','A'); + p_sys->p_filter_blend->p_module = + module_Need( p_sys->p_filter_blend, "video blending", 0, 0 ); + } + + return VLC_SUCCESS; +} + +static void transcode_spu_close( sout_stream_t *p_stream, sout_stream_id_t *id) +{ + sout_stream_sys_t *p_sys = p_stream->p_sys; + int i; + + /* Close decoder */ + if( id->p_decoder->p_module ) + module_Unneed( id->p_decoder, id->p_decoder->p_module ); + vlc_object_detach( id->p_decoder ); + vlc_object_destroy( id->p_decoder ); + + /* Close encoder */ + if( id->p_encoder ) + { + if( id->p_encoder->p_module ) + module_Unneed( id->p_encoder, id->p_encoder->p_module ); + vlc_object_detach( id->p_encoder ); + vlc_object_destroy( id->p_encoder ); + } + + /* Free subpictures */ + for( i = 0; i < SUBPICTURE_RING_SIZE; i++ ) + { + if( !p_sys->pp_subpics[i] ) continue; + + spu_del_buffer( id->p_decoder, p_sys->pp_subpics[i] ); + p_sys->pp_subpics[i] = NULL; + } +} + +static int transcode_spu_process( sout_stream_t *p_stream, + sout_stream_id_t *id, + block_t *in, block_t **out ) +{ + sout_stream_sys_t *p_sys = p_stream->p_sys; + subpicture_t *p_subpic; + + p_subpic = id->p_decoder->pf_decode_sub( id->p_decoder, &in ); + if( p_subpic && p_sys->b_soverlay ) + { + int i; + + /* Find a free slot in our supictures ring buffer */ + for( i = 0; i < SUBPICTURE_RING_SIZE; i++ ) + { + if( !p_sys->pp_subpics[i] ) + { + p_sys->pp_subpics[i] = p_subpic; + break; + } + } + if( i == SUBPICTURE_RING_SIZE ) + { + spu_del_buffer( id->p_decoder, p_subpic ); + } + } + + if( !p_sys->b_soverlay && p_subpic ) + { + block_t *p_block; + p_block = id->p_encoder->pf_encode_sub( id->p_encoder, p_subpic ); + if( p_block ) block_ChainAppend( out, p_block ); + return VLC_SUCCESS; + } + + return VLC_EGENERIC; +} + +static subpicture_t *transcode_spu_get( sout_stream_t *p_stream, + sout_stream_id_t *id, + mtime_t display_date ) +{ + sout_stream_sys_t *p_sys = p_stream->p_sys; + subpicture_t *p_subpic = 0; + subpicture_t *p_ephemer = 0; + subpicture_t **pp_subpic = &p_subpic; + int i; + + /* Find current subpictures and remove old ones */ + for( i = 0; i < SUBPICTURE_RING_SIZE; i++ ) + { + if( !p_sys->pp_subpics[i] ) continue; + + if( !p_sys->pp_subpics[i]->b_ephemer && + p_sys->pp_subpics[i]->i_stop < display_date ) + { + spu_del_buffer( id->p_decoder, p_sys->pp_subpics[i] ); + p_sys->pp_subpics[i] = NULL; + continue; + } + + if( p_sys->pp_subpics[i]->i_start > display_date ) continue; + + if( p_sys->pp_subpics[i]->b_ephemer && !p_ephemer ) + { + p_ephemer = p_sys->pp_subpics[i]; + } + else if( p_sys->pp_subpics[i]->b_ephemer ) + { + if( p_ephemer->i_start < p_sys->pp_subpics[i]->i_start ) + { + subpicture_t tmp; + tmp = *p_ephemer; + *p_ephemer = *p_sys->pp_subpics[i]; + *p_sys->pp_subpics[i] = tmp; + } + + spu_del_buffer( id->p_decoder, p_sys->pp_subpics[i] ); + p_sys->pp_subpics[i] = NULL; + continue; + } + + /* Add subpicture to the list */ + *pp_subpic = p_sys->pp_subpics[i]; + pp_subpic = &p_sys->pp_subpics[i]->p_next; + } + + return p_subpic; +} + +static subpicture_t *spu_new_buffer( decoder_t *p_dec ) +{ + subpicture_t *p_subpic = (subpicture_t *)malloc(sizeof(subpicture_t)); + memset( p_subpic, 0, sizeof(subpicture_t) ); + p_subpic->b_absolute = VLC_TRUE; + + p_subpic->pf_create_region = __spu_CreateRegion; + p_subpic->pf_destroy_region = __spu_DestroyRegion; + + return p_subpic; +} + +static void spu_del_buffer( decoder_t *p_dec, subpicture_t *p_subpic ) +{ + while( p_subpic->p_region ) + { + subpicture_region_t *p_region = p_subpic->p_region; + p_subpic->p_region = p_region->p_next; + p_subpic->pf_destroy_region( VLC_OBJECT(p_dec), p_region ); + } + + free( p_subpic ); +} diff --git a/src/misc/modules.c b/src/misc/modules.c index d7076bba66..cc0457224b 100644 --- a/src/misc/modules.c +++ b/src/misc/modules.c @@ -328,6 +328,7 @@ module_t * __module_Need( vlc_object_t *p_this, const char *psz_capability, { module_t *p_module; int i_score; + vlc_bool_t b_force; module_list_t *p_next; }; @@ -501,6 +502,7 @@ module_t * __module_Need( vlc_object_t *p_this, const char *psz_capability, /* Store this new module */ p_list[ i_index ].p_module = p_module; p_list[ i_index ].i_score = p_module->i_score + i_shortcut_bonus; + p_list[ i_index ].b_force = !!i_shortcut_bonus; /* Add it to the modules-to-probe list */ if( i_index == 0 ) @@ -571,6 +573,7 @@ module_t * __module_Need( vlc_object_t *p_this, const char *psz_capability, } #endif + p_this->b_force = p_tmp->b_force; if( p_tmp->p_module->pf_activate && p_tmp->p_module->pf_activate( p_this ) == VLC_SUCCESS ) { @@ -600,6 +603,7 @@ module_t * __module_Need( vlc_object_t *p_this, const char *psz_capability, } free( p_list ); + p_this->b_force = VLC_FALSE; if( p_module != NULL ) { diff --git a/src/misc/objects.c b/src/misc/objects.c index f127a7f518..314c463fad 100644 --- a/src/misc/objects.c +++ b/src/misc/objects.c @@ -212,6 +212,7 @@ void * __vlc_object_create( vlc_object_t *p_this, int i_type ) p_new->b_error = VLC_FALSE; p_new->b_dead = VLC_FALSE; p_new->b_attached = VLC_FALSE; + p_new->b_force = VLC_FALSE; p_new->i_vars = 0; p_new->p_vars = (variable_t *)malloc( 16 * sizeof( variable_t ) ); -- 2.39.5