X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fstream_out%2Ftranscode%2Fvideo.c;h=19591e14fe510dabbf2b3c1a1dad6d292d393d1c;hb=20ce6b1fbbbb735b6274d0d5f21d1819719bbe30;hp=c4e38d69ebb19e208646113b6d103f34fbadbcc2;hpb=61466e069f0bd8803e12515e6439bbdb72cb5527;p=vlc diff --git a/modules/stream_out/transcode/video.c b/modules/stream_out/transcode/video.c index c4e38d69eb..19591e14fe 100644 --- a/modules/stream_out/transcode/video.c +++ b/modules/stream_out/transcode/video.c @@ -30,6 +30,7 @@ #include "transcode.h" +#include #include #include #include @@ -42,27 +43,14 @@ struct decoder_owner_sys_t sout_stream_sys_t *p_sys; }; -static void video_del_buffer_decoder( decoder_t *p_decoder, picture_t *p_pic ) +static int video_update_format_decoder( decoder_t *p_dec ) { - VLC_UNUSED(p_decoder); - picture_Release( p_pic ); -} - -static void video_link_picture_decoder( decoder_t *p_dec, picture_t *p_pic ) -{ - VLC_UNUSED(p_dec); - picture_Hold( p_pic ); -} - -static void video_unlink_picture_decoder( decoder_t *p_dec, picture_t *p_pic ) -{ - VLC_UNUSED(p_dec); - picture_Release( p_pic ); + p_dec->fmt_out.video.i_chroma = p_dec->fmt_out.i_codec; + return 0; } static picture_t *video_new_buffer_decoder( decoder_t *p_dec ) { - p_dec->fmt_out.video.i_chroma = p_dec->fmt_out.i_codec; return picture_NewFromFormat( &p_dec->fmt_out.video ); } @@ -77,94 +65,60 @@ static picture_t *transcode_video_filter_buffer_new( filter_t *p_filter ) p_filter->fmt_out.video.i_chroma = p_filter->fmt_out.i_codec; return picture_NewFromFormat( &p_filter->fmt_out.video ); } -static void transcode_video_filter_buffer_del( filter_t *p_filter, picture_t *p_pic ) -{ - VLC_UNUSED(p_filter); - picture_Release( p_pic ); -} - -static int transcode_video_filter_allocation_init( filter_t *p_filter, - void *p_data ) -{ - VLC_UNUSED(p_data); - p_filter->pf_video_buffer_new = transcode_video_filter_buffer_new; - p_filter->pf_video_buffer_del = transcode_video_filter_buffer_del; - return VLC_SUCCESS; -} - -static void transcode_video_filter_allocation_clear( filter_t *p_filter ) -{ - VLC_UNUSED(p_filter); -} static void* EncoderThread( void *obj ) { sout_stream_sys_t *p_sys = (sout_stream_sys_t*)obj; - sout_stream_id_t *id = p_sys->id_video; + sout_stream_id_sys_t *id = p_sys->id_video; picture_t *p_pic = NULL; int canc = vlc_savecancel (); block_t *p_block = NULL; + vlc_mutex_lock( &p_sys->lock_out ); + for( ;; ) { - - vlc_mutex_lock( &p_sys->lock_out ); while( !p_sys->b_abort && (p_pic = picture_fifo_Pop( p_sys->pp_pics )) == NULL ) vlc_cond_wait( &p_sys->cond, &p_sys->lock_out ); - if( p_sys->b_abort && !p_pic ) - { - vlc_mutex_unlock( &p_sys->lock_out ); - break; - } - vlc_mutex_unlock( &p_sys->lock_out ); - if( p_pic ) { + /* release lock while encoding */ + vlc_mutex_unlock( &p_sys->lock_out ); p_block = id->p_encoder->pf_encode_video( id->p_encoder, p_pic ); - + picture_Release( p_pic ); vlc_mutex_lock( &p_sys->lock_out ); - block_ChainAppend( &p_sys->p_buffers, p_block ); - vlc_mutex_unlock( &p_sys->lock_out ); - picture_Release( p_pic ); + block_ChainAppend( &p_sys->p_buffers, p_block ); } - vlc_mutex_lock( &p_sys->lock_out ); if( p_sys->b_abort ) - { - vlc_mutex_unlock( &p_sys->lock_out ); break; - } - vlc_mutex_unlock( &p_sys->lock_out ); } /*Encode what we have in the buffer on closing*/ - vlc_mutex_lock( &p_sys->lock_out ); while( (p_pic = picture_fifo_Pop( p_sys->pp_pics )) != NULL ) { p_block = id->p_encoder->pf_encode_video( id->p_encoder, p_pic ); - - block_ChainAppend( &p_sys->p_buffers, p_block ); - picture_Release( p_pic ); + block_ChainAppend( &p_sys->p_buffers, p_block ); } /*Now flush encoder*/ do { - p_block = id->p_encoder->pf_encode_video(id->p_encoder, NULL ); - block_ChainAppend( &p_sys->p_buffers, p_block ); + p_block = id->p_encoder->pf_encode_video(id->p_encoder, NULL ); + block_ChainAppend( &p_sys->p_buffers, p_block ); } while( p_block ); vlc_mutex_unlock( &p_sys->lock_out ); - vlc_restorecancel (canc); + return NULL; } -int transcode_video_new( sout_stream_t *p_stream, sout_stream_id_t *id ) +int transcode_video_new( sout_stream_t *p_stream, sout_stream_id_sys_t *id ) { sout_stream_sys_t *p_sys = p_stream->p_sys; @@ -177,10 +131,8 @@ int transcode_video_new( sout_stream_t *p_stream, sout_stream_id_t *id ) id->p_decoder->pf_decode_video = NULL; id->p_decoder->pf_get_cc = NULL; id->p_decoder->pf_get_cc = 0; + id->p_decoder->pf_vout_format_update = video_update_format_decoder; id->p_decoder->pf_vout_buffer_new = video_new_buffer_decoder; - id->p_decoder->pf_vout_buffer_del = video_del_buffer_decoder; - id->p_decoder->pf_picture_link = video_link_picture_decoder; - id->p_decoder->pf_picture_unlink = video_unlink_picture_decoder; id->p_decoder->p_owner = malloc( sizeof(decoder_owner_sys_t) ); if( !id->p_decoder->p_owner ) return VLC_EGENERIC; @@ -232,8 +184,6 @@ int transcode_video_new( sout_stream_t *p_stream, sout_stream_id_t *id ) ? id->p_encoder->fmt_out.video.i_visible_height : id->p_decoder->fmt_in.video.i_visible_height ? id->p_decoder->fmt_in.video.i_visible_height : id->p_encoder->fmt_in.video.i_height; - id->p_encoder->fmt_in.video.i_frame_rate = id->p_decoder->fmt_out.video.i_frame_rate; - id->p_encoder->fmt_in.video.i_frame_rate_base = id->p_decoder->fmt_out.video.i_frame_rate_base; id->p_encoder->i_threads = p_sys->i_threads; id->p_encoder->p_cfg = p_sys->p_video_cfg; @@ -262,76 +212,156 @@ int transcode_video_new( sout_stream_t *p_stream, sout_stream_id_t *id ) } id->p_encoder->p_module = NULL; - if( p_sys->i_threads >= 1 ) + if( p_sys->i_threads <= 0 ) + return VLC_SUCCESS; + + int i_priority = p_sys->b_high_priority ? VLC_THREAD_PRIORITY_OUTPUT : + VLC_THREAD_PRIORITY_VIDEO; + p_sys->id_video = id; + p_sys->pp_pics = picture_fifo_New(); + if( p_sys->pp_pics == NULL ) { - int i_priority = p_sys->b_high_priority ? VLC_THREAD_PRIORITY_OUTPUT : - VLC_THREAD_PRIORITY_VIDEO; - p_sys->id_video = id; - vlc_mutex_init( &p_sys->lock_out ); - vlc_cond_init( &p_sys->cond ); - p_sys->pp_pics = picture_fifo_New(); - if( p_sys->pp_pics == NULL ) - { - msg_Err( p_stream, "cannot create picture fifo" ); - vlc_mutex_destroy( &p_sys->lock_out ); - vlc_cond_destroy( &p_sys->cond ); - module_unneed( id->p_decoder, id->p_decoder->p_module ); - id->p_decoder->p_module = NULL; - free( id->p_decoder->p_owner ); - return VLC_ENOMEM; - } - p_sys->p_buffers = NULL; - p_sys->b_abort = false; - if( vlc_clone( &p_sys->thread, EncoderThread, p_sys, i_priority ) ) - { - msg_Err( p_stream, "cannot spawn encoder thread" ); - vlc_mutex_destroy( &p_sys->lock_out ); - vlc_cond_destroy( &p_sys->cond ); - picture_fifo_Delete( p_sys->pp_pics ); - module_unneed( id->p_decoder, id->p_decoder->p_module ); - id->p_decoder->p_module = NULL; - free( id->p_decoder->p_owner ); - return VLC_EGENERIC; - } + msg_Err( p_stream, "cannot create picture fifo" ); + module_unneed( id->p_decoder, id->p_decoder->p_module ); + id->p_decoder->p_module = NULL; + free( id->p_decoder->p_owner ); + return VLC_ENOMEM; + } + vlc_mutex_init( &p_sys->lock_out ); + vlc_cond_init( &p_sys->cond ); + p_sys->p_buffers = NULL; + p_sys->b_abort = false; + if( vlc_clone( &p_sys->thread, EncoderThread, p_sys, i_priority ) ) + { + msg_Err( p_stream, "cannot spawn encoder thread" ); + vlc_mutex_destroy( &p_sys->lock_out ); + vlc_cond_destroy( &p_sys->cond ); + picture_fifo_Delete( p_sys->pp_pics ); + module_unneed( id->p_decoder, id->p_decoder->p_module ); + id->p_decoder->p_module = NULL; + free( id->p_decoder->p_owner ); + return VLC_EGENERIC; } return VLC_SUCCESS; } +static filter_t *AppendDeinterlaceFilter( sout_stream_t *p_stream, + filter_chain_t *p_chain, + const char *psz_name, + config_chain_t *p_cfg, + const es_format_t *p_fmt_in, + const es_format_t *p_fmt_out ) +{ + filter_t *p_filter = + filter_chain_AppendFilter( p_chain, psz_name, p_cfg, p_fmt_in, p_fmt_out ); + if( p_filter ) + return p_filter; + + msg_Dbg( p_stream, "deinterlace init failed, trying colorspace conversion" ); + + /* Most likely the filter failed due to wrong (e.g. non-planar) input format. + * Try converting to a different color space and try again. + * + * We use the recommended fallback formats in order, to get a conversion that's + * as cheap (both CPU-wise and quality-wise) as possible. + */ + for( const vlc_fourcc_t *fourcc = vlc_fourcc_GetYUVFallback( p_fmt_out->video.i_chroma ); + *fourcc != 0; + ++fourcc ) + { + msg_Dbg( p_stream, "trying deinterlace through colorspace conversion to %4.4s", (char *)fourcc ); + + es_format_t p_new_fmt; + es_format_Copy( &p_new_fmt, p_fmt_in ); + p_new_fmt.video.i_chroma = *fourcc; // XXX: is this enough? + + filter_chain_Reset( p_chain, NULL, NULL ); + + p_filter = filter_chain_AppendFilter( p_chain, + NULL, NULL, + p_fmt_in, + &p_new_fmt ); + if( !p_filter ) + continue; + + p_filter = filter_chain_AppendFilter( p_chain, + psz_name, + p_cfg, + &p_new_fmt, + &p_new_fmt ); + if( p_filter ) + { + msg_Dbg( p_stream, "deinterlace through colorspace conversion to %4.4s succeeded", (char *)fourcc ); + return p_filter; + } + } + + msg_Err( p_stream, "deinterlace init failed, even with colorspace conversion" ); + return NULL; +} + static void transcode_video_filter_init( sout_stream_t *p_stream, - sout_stream_id_t *id ) + sout_stream_id_sys_t *id ) { - const 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; + filter_owner_t owner = { + .sys = p_stream->p_sys, + .video = { + .buffer_new = transcode_video_filter_buffer_new, + }, + }; + es_format_t *p_fmt_out = &id->p_decoder->fmt_out; - 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 ); + id->p_encoder->fmt_in.video.i_chroma = id->p_encoder->fmt_in.i_codec; + id->p_f_chain = filter_chain_NewVideo( p_stream, false, &owner ); filter_chain_Reset( id->p_f_chain, p_fmt_out, p_fmt_out ); /* Deinterlace */ if( p_stream->p_sys->b_deinterlace ) + { + filter_t *p_filter = + AppendDeinterlaceFilter( p_stream, + id->p_f_chain, + p_stream->p_sys->psz_deinterlace, + p_stream->p_sys->p_deinterlace_cfg, + p_fmt_out, + p_fmt_out ); + if( !p_filter ) + { + msg_Err( p_stream, "deinterlace init failed, even with colorspace conversion" ); + return; + } + + p_fmt_out = filter_chain_GetFmtOut( id->p_f_chain ); + } + if( p_stream->p_sys->b_master_sync ) { 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 ); + "fps", + NULL, + p_fmt_out, + &id->p_encoder->fmt_in ); 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 ) { - 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_uf_chain = filter_chain_NewVideo( p_stream, true, &owner ); + filter_chain_Reset( id->p_uf_chain, p_fmt_out, &id->p_encoder->fmt_in ); + if( p_fmt_out->video.i_chroma != id->p_encoder->fmt_in.video.i_chroma ) + { + filter_chain_AppendFilter( id->p_uf_chain, + NULL, NULL, + 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 ); @@ -348,11 +378,12 @@ static void transcode_video_filter_init( sout_stream_t *p_stream, } /* Take care of the scaling and chroma conversions. */ -static void conversion_video_filter_append( sout_stream_id_t *id ) +static void conversion_video_filter_append( sout_stream_id_sys_t *id ) { const es_format_t *p_fmt_out = &id->p_decoder->fmt_out; if( id->p_f_chain ) p_fmt_out = filter_chain_GetFmtOut( id->p_f_chain ); + if( id->p_uf_chain ) p_fmt_out = filter_chain_GetFmtOut( id->p_uf_chain ); @@ -360,7 +391,7 @@ static void conversion_video_filter_append( sout_stream_id_t *id ) ( p_fmt_out->video.i_width != id->p_encoder->fmt_in.video.i_width ) || ( p_fmt_out->video.i_height != id->p_encoder->fmt_in.video.i_height ) ) { - filter_chain_AppendFilter( id->p_f_chain, + filter_chain_AppendFilter( id->p_uf_chain ? id->p_uf_chain : id->p_f_chain, NULL, NULL, p_fmt_out, &id->p_encoder->fmt_in ); @@ -368,7 +399,7 @@ static void conversion_video_filter_append( sout_stream_id_t *id ) } static void transcode_video_encoder_init( sout_stream_t *p_stream, - sout_stream_id_t *id ) + sout_stream_id_sys_t *id ) { sout_stream_sys_t *p_sys = p_stream->p_sys; @@ -401,15 +432,15 @@ static void transcode_video_encoder_init( sout_stream_t *p_stream, p_fmt_out->video.i_sar_den / p_fmt_out->video.i_height; - msg_Dbg( p_stream, "decoder aspect is %f:1", f_aspect ); + msg_Dbg( p_stream, "decoder aspect is %f:1", (double) f_aspect ); /* Change f_aspect from source frame to source pixel */ f_aspect = f_aspect * i_src_visible_height / i_src_visible_width; - msg_Dbg( p_stream, "source pixel aspect is %f:1", f_aspect ); + msg_Dbg( p_stream, "source pixel aspect is %f:1", (double) f_aspect ); /* Calculate scaling factor for specified parameters */ - if( id->p_encoder->fmt_out.video.i_width <= 0 && - id->p_encoder->fmt_out.video.i_height <= 0 && p_sys->f_scale ) + if( id->p_encoder->fmt_out.video.i_visible_width <= 0 && + id->p_encoder->fmt_out.video.i_visible_height <= 0 && p_sys->f_scale ) { /* Global scaling. Make sure width will remain a factor of 16 */ float f_real_scale; @@ -428,26 +459,26 @@ static void transcode_video_encoder_init( sout_stream_t *p_stream, f_scale_width = f_real_scale; f_scale_height = (float) i_new_height / (float) i_src_visible_height; } - else if( id->p_encoder->fmt_out.video.i_width > 0 && - id->p_encoder->fmt_out.video.i_height <= 0 ) + else if( id->p_encoder->fmt_out.video.i_visible_width > 0 && + id->p_encoder->fmt_out.video.i_visible_height <= 0 ) { /* Only width specified */ - f_scale_width = (float)id->p_encoder->fmt_out.video.i_width/i_src_visible_width; + f_scale_width = (float)id->p_encoder->fmt_out.video.i_visible_width/i_src_visible_width; f_scale_height = f_scale_width; } - else if( id->p_encoder->fmt_out.video.i_width <= 0 && - id->p_encoder->fmt_out.video.i_height > 0 ) + else if( id->p_encoder->fmt_out.video.i_visible_width <= 0 && + id->p_encoder->fmt_out.video.i_visible_height > 0 ) { /* Only height specified */ - f_scale_height = (float)id->p_encoder->fmt_out.video.i_height/i_src_visible_height; + f_scale_height = (float)id->p_encoder->fmt_out.video.i_visible_height/i_src_visible_height; f_scale_width = f_scale_height; } - else if( id->p_encoder->fmt_out.video.i_width > 0 && - id->p_encoder->fmt_out.video.i_height > 0 ) + else if( id->p_encoder->fmt_out.video.i_visible_width > 0 && + id->p_encoder->fmt_out.video.i_visible_height > 0 ) { /* Width and height specified */ - f_scale_width = (float)id->p_encoder->fmt_out.video.i_width/i_src_visible_width; - f_scale_height = (float)id->p_encoder->fmt_out.video.i_height/i_src_visible_height; + f_scale_width = (float)id->p_encoder->fmt_out.video.i_visible_width/i_src_visible_width; + f_scale_height = (float)id->p_encoder->fmt_out.video.i_visible_height/i_src_visible_height; } /* check maxwidth and maxheight */ @@ -466,17 +497,17 @@ static void transcode_video_encoder_init( sout_stream_t *p_stream, /* Change aspect ratio from source pixel to scaled pixel */ f_aspect = f_aspect * f_scale_height / f_scale_width; - msg_Dbg( p_stream, "scaled pixel aspect is %f:1", f_aspect ); + msg_Dbg( p_stream, "scaled pixel aspect is %f:1", (double) f_aspect ); /* f_scale_width and f_scale_height are now final */ /* Calculate width, height from scaling * Make sure its multiple of 2 */ /* width/height of output stream */ - int i_dst_visible_width = 2 * (int)(f_scale_width*i_src_visible_width/2+0.5); - int i_dst_visible_height = 2 * (int)(f_scale_height*i_src_visible_height/2+0.5); - int i_dst_width = 2 * (int)(f_scale_width*p_fmt_out->video.i_width/2+0.5); - int i_dst_height = 2 * (int)(f_scale_height*p_fmt_out->video.i_height/2+0.5); + int i_dst_visible_width = 2 * lroundf(f_scale_width*i_src_visible_width/2); + int i_dst_visible_height = 2 * lroundf(f_scale_height*i_src_visible_height/2); + int i_dst_width = 2 * lroundf(f_scale_width*p_fmt_out->video.i_width/2); + int i_dst_height = 2 * lroundf(f_scale_height*p_fmt_out->video.i_height/2); /* Change aspect ratio from scaled pixel to output frame */ f_aspect = f_aspect * i_dst_visible_width / i_dst_visible_height; @@ -517,6 +548,10 @@ static void transcode_video_encoder_init( sout_stream_t *p_stream, } } + id->p_encoder->fmt_in.video.orientation = + id->p_encoder->fmt_out.video.orientation = + id->p_decoder->fmt_in.video.orientation; + id->p_encoder->fmt_in.video.i_frame_rate = id->p_encoder->fmt_out.video.i_frame_rate; id->p_encoder->fmt_in.video.i_frame_rate_base = @@ -533,17 +568,6 @@ static void transcode_video_encoder_init( sout_stream_t *p_stream, id->p_encoder->fmt_in.video.i_frame_rate, id->p_encoder->fmt_in.video.i_frame_rate_base ); - id->i_output_frame_interval = id->p_encoder->fmt_out.video.i_frame_rate_base * CLOCK_FREQ / id->p_encoder->fmt_out.video.i_frame_rate; - id->i_input_frame_interval = id->p_decoder->fmt_out.video.i_frame_rate_base * CLOCK_FREQ / id->p_decoder->fmt_out.video.i_frame_rate; - msg_Info( p_stream, "input interval %d (base %d) output interval %d (base %d)", id->i_input_frame_interval, id->p_decoder->fmt_out.video.i_frame_rate_base, - id->i_output_frame_interval, id->p_encoder->fmt_in.video.i_frame_rate_base ); - - date_Init( &id->interpolated_pts, - id->p_decoder->fmt_out.video.i_frame_rate, - 1 ); - date_Init( &id->next_output_pts, - id->p_encoder->fmt_in.video.i_frame_rate, - 1 ); /* Check whether a particular aspect ratio was requested */ if( id->p_encoder->fmt_out.video.i_sar_num <= 0 || @@ -576,7 +600,7 @@ static void transcode_video_encoder_init( sout_stream_t *p_stream, } static int transcode_video_encoder_open( sout_stream_t *p_stream, - sout_stream_id_t *id ) + sout_stream_id_sys_t *id ) { sout_stream_sys_t *p_sys = p_stream->p_sys; @@ -612,9 +636,9 @@ static int transcode_video_encoder_open( sout_stream_t *p_stream, } void transcode_video_close( sout_stream_t *p_stream, - sout_stream_id_t *id ) + sout_stream_id_sys_t *id ) { - if( p_stream->p_sys->i_threads >= 1 ) + if( p_stream->p_sys->i_threads >= 1 && !p_stream->p_sys->b_abort ) { vlc_mutex_lock( &p_stream->p_sys->lock_out ); p_stream->p_sys->b_abort = true; @@ -622,14 +646,14 @@ void transcode_video_close( sout_stream_t *p_stream, vlc_mutex_unlock( &p_stream->p_sys->lock_out ); vlc_join( p_stream->p_sys->thread, NULL ); - vlc_mutex_destroy( &p_stream->p_sys->lock_out ); - vlc_cond_destroy( &p_stream->p_sys->cond ); picture_fifo_Delete( p_stream->p_sys->pp_pics ); block_ChainRelease( p_stream->p_sys->p_buffers ); - p_stream->p_sys->pp_pics = NULL; } + vlc_mutex_destroy( &p_stream->p_sys->lock_out ); + vlc_cond_destroy( &p_stream->p_sys->cond ); + /* Close decoder */ if( id->p_decoder->p_module ) module_unneed( id->p_decoder, id->p_decoder->p_module ); @@ -649,25 +673,10 @@ void transcode_video_close( sout_stream_t *p_stream, filter_chain_Delete( id->p_uf_chain ); } -static void OutputFrame( sout_stream_sys_t *p_sys, picture_t *p_pic, sout_stream_t *p_stream, sout_stream_id_t *id, block_t **out ) +static void OutputFrame( sout_stream_t *p_stream, picture_t *p_pic, sout_stream_id_sys_t *id, block_t **out ) { - + sout_stream_sys_t *p_sys = p_stream->p_sys; picture_t *p_pic2 = NULL; - bool b_need_duplicate=false; - /* If input pts + input_frame_interval is lower than next_output_pts - output_frame_interval - * Then the future input frame should fit better and we can drop this one - * - * Duplication need is checked in OutputFrame */ - if( ( p_pic->date + (mtime_t)id->i_input_frame_interval ) < - ( date_Get( &id->next_output_pts ) ) ) - { -#if 0 - msg_Dbg( p_stream, "dropping frame (%"PRId64" + %"PRId64" vs %"PRId64")", - p_pic->date, id->i_input_frame_interval, date_Get(&id->next_output_pts) ); -#endif - picture_Release( p_pic ); - return; - } /* * Encoding @@ -684,7 +693,8 @@ static void OutputFrame( sout_stream_sys_t *p_sys, picture_t *p_pic, sout_stream fmt.i_y_offset = 0; } - subpicture_t *p_subpic = spu_Render( p_sys->p_spu, NULL, &fmt, &fmt, + subpicture_t *p_subpic = spu_Render( p_sys->p_spu, NULL, &fmt, + &id->p_decoder->fmt_out.video, p_pic->date, p_pic->date, false ); /* Overlay subpicture */ @@ -709,8 +719,6 @@ static void OutputFrame( sout_stream_sys_t *p_sys, picture_t *p_pic, sout_stream subpicture_Delete( p_subpic ); } } - /*This pts is handled, increase clock to next one*/ - date_Increment( &id->next_output_pts, id->p_encoder->fmt_in.video.i_frame_rate_base ); if( p_sys->i_threads == 0 ) { @@ -720,63 +728,21 @@ static void OutputFrame( sout_stream_sys_t *p_sys, picture_t *p_pic, sout_stream block_ChainAppend( out, p_block ); } - /* we need to duplicate while next_output_pts + output_frame_interval < input_pts (next input pts)*/ - b_need_duplicate = ( date_Get( &id->next_output_pts ) + id->i_output_frame_interval ) < - ( date_Get( &id->interpolated_pts ) ); - if( p_sys->i_threads ) { - if( p_sys->b_master_sync ) - { - p_pic2 = video_new_buffer_encoder( id->p_encoder ); - if( likely( p_pic2 != NULL ) ) - picture_Copy( p_pic2, p_pic ); - } vlc_mutex_lock( &p_sys->lock_out ); picture_fifo_Push( p_sys->pp_pics, p_pic ); vlc_cond_signal( &p_sys->cond ); vlc_mutex_unlock( &p_sys->lock_out ); } - while( (p_sys->b_master_sync && b_need_duplicate )) - { - if( p_sys->i_threads >= 1 ) - { - picture_t *p_tmp = NULL; - /* We can't modify the picture, we need to duplicate it */ - p_tmp = video_new_buffer_encoder( id->p_encoder ); - if( likely( p_tmp != NULL ) ) - { - picture_Copy( p_tmp, p_pic2 ); - p_tmp->date = date_Get( &id->next_output_pts ); - vlc_mutex_lock( &p_sys->lock_out ); - picture_fifo_Push( p_sys->pp_pics, p_tmp ); - vlc_cond_signal( &p_sys->cond ); - vlc_mutex_unlock( &p_sys->lock_out ); - } - } - else - { - block_t *p_block; - p_pic->date = date_Get( &id->next_output_pts ); - p_block = id->p_encoder->pf_encode_video(id->p_encoder, p_pic); - block_ChainAppend( out, p_block ); - } -#if 0 - msg_Dbg( p_stream, "duplicated frame"); -#endif - date_Increment( &id->next_output_pts, id->p_encoder->fmt_in.video.i_frame_rate_base ); - b_need_duplicate = ( date_Get( &id->next_output_pts ) + id->i_output_frame_interval ) < - ( date_Get( &id->interpolated_pts ) ); - } - if( p_sys->i_threads && p_pic2 ) picture_Release( p_pic2 ); else if ( p_sys->i_threads == 0 ) picture_Release( p_pic ); } -int transcode_video_process( sout_stream_t *p_stream, sout_stream_id_t *id, +int transcode_video_process( sout_stream_t *p_stream, sout_stream_id_sys_t *id, block_t *in, block_t **out ) { sout_stream_sys_t *p_sys = p_stream->p_sys; @@ -816,27 +782,15 @@ int transcode_video_process( sout_stream_t *p_stream, sout_stream_id_t *id, while( (p_pic = id->p_decoder->pf_decode_video( id->p_decoder, &in )) ) { - if( p_stream->p_sout->i_out_pace_nocontrol && p_sys->b_hurry_up ) - { - mtime_t current_date = mdate(); - if( unlikely( (current_date - 50000) > p_pic->date ) ) - { - msg_Dbg( p_stream, "late picture skipped (%"PRId64")", - current_date - 50000 - p_pic->date ); - picture_Release( p_pic ); - continue; - } - } - if( unlikely ( id->p_encoder->p_module && - !video_format_IsSimilar( &p_sys->fmt_input_video, &id->p_decoder->fmt_out.video ) + !video_format_IsSimilar( &id->fmt_input_video, &id->p_decoder->fmt_out.video ) ) ) { msg_Info( p_stream, "aspect-ratio changed, reiniting. %i -> %i : %i -> %i.", - p_sys->fmt_input_video.i_sar_num, id->p_decoder->fmt_out.video.i_sar_num, - p_sys->fmt_input_video.i_sar_den, id->p_decoder->fmt_out.video.i_sar_den + id->fmt_input_video.i_sar_num, id->p_decoder->fmt_out.video.i_sar_num, + id->fmt_input_video.i_sar_den, id->p_decoder->fmt_out.video.i_sar_den ); /* Close filters */ if( id->p_f_chain ) @@ -847,14 +801,14 @@ int transcode_video_process( sout_stream_t *p_stream, sout_stream_id_t *id, id->p_uf_chain = NULL; /* Reinitialize filters */ - id->p_encoder->fmt_out.video.i_width = p_sys->i_width & ~1; - id->p_encoder->fmt_out.video.i_height = p_sys->i_height & ~1; + id->p_encoder->fmt_out.video.i_visible_width = p_sys->i_width & ~1; + id->p_encoder->fmt_out.video.i_visible_height = p_sys->i_height & ~1; id->p_encoder->fmt_out.video.i_sar_num = id->p_encoder->fmt_out.video.i_sar_den = 0; transcode_video_filter_init( p_stream, id ); transcode_video_encoder_init( p_stream, id ); conversion_video_filter_append( id ); - memcpy( &p_sys->fmt_input_video, &id->p_decoder->fmt_out.video, sizeof(video_format_t)); + memcpy( &id->fmt_input_video, &id->p_decoder->fmt_out.video, sizeof(video_format_t)); } @@ -869,7 +823,7 @@ int transcode_video_process( sout_stream_t *p_stream, sout_stream_id_t *id, transcode_video_filter_init( p_stream, id ); transcode_video_encoder_init( p_stream, id ); conversion_video_filter_append( id ); - memcpy( &p_sys->fmt_input_video, &id->p_decoder->fmt_out.video, sizeof(video_format_t)); + memcpy( &id->fmt_input_video, &id->p_decoder->fmt_out.video, sizeof(video_format_t)); if( transcode_video_encoder_open( p_stream, id ) != VLC_SUCCESS ) { @@ -880,63 +834,6 @@ int transcode_video_process( sout_stream_t *p_stream, sout_stream_id_t *id, } } - /*Input lipsync and drop check */ - if( p_sys->b_master_sync ) - { - /* How much audio has drifted */ - mtime_t i_master_drift = p_sys->i_master_drift; - - /* This is the pts input should have now with constant frame rate */ - mtime_t i_pts = date_Get( &id->interpolated_pts ); - - /* How much input pts has drifted */ - mtime_t i_video_drift = p_pic->date - i_pts; - - /* Check that we are having lipsync with input here */ - if( unlikely ( ( (i_video_drift - i_master_drift ) > MASTER_SYNC_MAX_DRIFT - || (i_video_drift + i_master_drift ) < -MASTER_SYNC_MAX_DRIFT ) ) ) - { - msg_Warn( p_stream, - "video drift too big, resetting sync %"PRId64" to %"PRId64, - (i_video_drift + i_master_drift), - p_pic->date - ); - date_Set( &id->interpolated_pts, p_pic->date ); - date_Set( &id->next_output_pts, p_pic->date ); - i_pts = date_Get( &id->interpolated_pts ); - } - - /* Set the pts of the frame being encoded */ - p_pic->date = i_pts; - - /* now take next input pts, pts dates are only enabled if p_module is set*/ - date_Increment( &id->interpolated_pts, id->p_decoder->fmt_out.video.i_frame_rate_base ); - - - /* If input pts + input_frame_interval is lower than next_output_pts - output_frame_interval - * Then the future input frame should fit better and we can drop this one - * - * Duplication need is checked in OutputFrame */ - if( ( p_pic->date + (mtime_t)id->i_input_frame_interval ) < - ( date_Get( &id->next_output_pts ) ) ) - { -#if 0 - msg_Dbg( p_stream, "dropping frame (%"PRId64" + %"PRId64" vs %"PRId64")", - p_pic->date, id->i_input_frame_interval, date_Get(&id->next_output_pts) ); -#endif - picture_Release( p_pic ); - continue; - } -#if 0 - msg_Dbg( p_stream, "not dropping frame"); -#endif - - /* input calculated pts isn't necessary what pts output should be, so use output pts*/ - p_pic->date = date_Get( &id->next_output_pts ); - - - } - /* Run the filter and output chains; first with the picture, * and then with NULL as many times as we need until they * stop outputting frames. @@ -959,7 +856,7 @@ int transcode_video_process( sout_stream_t *p_stream, sout_stream_id_t *id, if( !p_user_filtered_pic ) break; - OutputFrame( p_sys, p_user_filtered_pic, p_stream, id, out ); + OutputFrame( p_stream, p_user_filtered_pic, id, out ); p_filtered_pic = NULL; } @@ -980,8 +877,8 @@ int transcode_video_process( sout_stream_t *p_stream, sout_stream_id_t *id, return VLC_SUCCESS; } -bool transcode_video_add( sout_stream_t *p_stream, es_format_t *p_fmt, - sout_stream_id_t *id ) +bool transcode_video_add( sout_stream_t *p_stream, const es_format_t *p_fmt, + sout_stream_id_sys_t *id ) { sout_stream_sys_t *p_sys = p_stream->p_sys; @@ -991,8 +888,8 @@ bool transcode_video_add( sout_stream_t *p_stream, es_format_t *p_fmt, /* Complete destination format */ id->p_encoder->fmt_out.i_codec = p_sys->i_vcodec; - id->p_encoder->fmt_out.video.i_width = p_sys->i_width & ~1; - id->p_encoder->fmt_out.video.i_height = p_sys->i_height & ~1; + id->p_encoder->fmt_out.video.i_visible_width = p_sys->i_width & ~1; + id->p_encoder->fmt_out.video.i_visible_height = p_sys->i_height & ~1; id->p_encoder->fmt_out.i_bitrate = p_sys->i_vbitrate; /* Build decoder -> filter -> encoder chain */ @@ -1006,10 +903,10 @@ bool transcode_video_add( sout_stream_t *p_stream, es_format_t *p_fmt, * all the characteristics of the decoded stream yet */ id->b_transcode = true; - if( p_sys->f_fps > 0 ) + if( p_sys->fps_num ) { - id->p_encoder->fmt_out.video.i_frame_rate = (p_sys->f_fps * ENC_FRAMERATE_BASE); - id->p_encoder->fmt_out.video.i_frame_rate_base = ENC_FRAMERATE_BASE; + id->p_encoder->fmt_in.video.i_frame_rate = id->p_encoder->fmt_out.video.i_frame_rate = (p_sys->fps_num ); + id->p_encoder->fmt_in.video.i_frame_rate_base = id->p_encoder->fmt_out.video.i_frame_rate_base = (p_sys->fps_den ? p_sys->fps_den : 1); } return true;