X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fstream_out%2Ftranscode%2Fvideo.c;h=19591e14fe510dabbf2b3c1a1dad6d292d393d1c;hb=20ce6b1fbbbb735b6274d0d5f21d1819719bbe30;hp=5e3ed9415ee761139b8051cc141f1be9fffba89e;hpb=d466fd4185ffd791413658e948205e2676d2f470;p=vlc diff --git a/modules/stream_out/transcode/video.c b/modules/stream_out/transcode/video.c index 5e3ed9415e..19591e14fe 100644 --- a/modules/stream_out/transcode/video.c +++ b/modules/stream_out/transcode/video.c @@ -1,7 +1,7 @@ /***************************************************************************** * video.c: transcoding stream output module (video) ***************************************************************************** - * Copyright (C) 2003-2009 the VideoLAN team + * Copyright (C) 2003-2009 VLC authors and VideoLAN * $Id$ * * Authors: Laurent Aimar @@ -9,19 +9,19 @@ * Jean-Paul Saman * Antoine Cellerier * - * 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 + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 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. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser 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. + * You should have received a copy of the GNU Lesser 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. *****************************************************************************/ /***************************************************************************** @@ -30,10 +30,12 @@ #include "transcode.h" +#include #include -#include +#include +#include -#define ENC_FRAMERATE (25 * 1000 + .5) +#define ENC_FRAMERATE (25 * 1000) #define ENC_FRAMERATE_BASE 1000 struct decoder_owner_sys_t @@ -41,62 +43,21 @@ struct decoder_owner_sys_t sout_stream_sys_t *p_sys; }; -static inline void video_timer_start( encoder_t * p_encoder ) +static int video_update_format_decoder( decoder_t *p_dec ) { - stats_TimerStart( p_encoder, "encoding video frame", - STATS_TIMER_VIDEO_FRAME_ENCODING ); -} - -static inline void video_timer_stop( encoder_t * p_encoder ) -{ - stats_TimerStop( p_encoder, STATS_TIMER_VIDEO_FRAME_ENCODING ); -} - -static inline void video_timer_close( encoder_t * p_encoder ) -{ - stats_TimerDump( p_encoder, STATS_TIMER_VIDEO_FRAME_ENCODING ); - stats_TimerClean( p_encoder, STATS_TIMER_VIDEO_FRAME_ENCODING ); -} - -static void video_del_buffer_decoder( decoder_t *p_decoder, picture_t *p_pic ) -{ - VLC_UNUSED(p_decoder); - picture_Release( p_pic ); + p_dec->fmt_out.video.i_chroma = p_dec->fmt_out.i_codec; + return 0; } -static void video_link_picture_decoder( decoder_t *p_dec, picture_t *p_pic ) +static picture_t *video_new_buffer_decoder( decoder_t *p_dec ) { - VLC_UNUSED(p_dec); - picture_Hold( p_pic ); + return picture_NewFromFormat( &p_dec->fmt_out.video ); } -static void video_unlink_picture_decoder( decoder_t *p_dec, picture_t *p_pic ) +static picture_t *video_new_buffer_encoder( encoder_t *p_enc ) { - VLC_UNUSED(p_dec); - picture_Release( p_pic ); -} - -static picture_t *video_new_buffer_decoder( decoder_t *p_dec ) -{ - sout_stream_sys_t *p_ssys = p_dec->p_owner->p_sys; - if( p_ssys->i_threads >= 1 ) - { - int i_first_pic = p_ssys->i_first_pic; - - if( p_ssys->i_first_pic != p_ssys->i_last_pic ) - { - /* Encoder still has stuff to encode, wait to clear-up the list */ - while( p_ssys->i_first_pic == i_first_pic ) - { -#warning THERE IS DEFINITELY A BUG! LOCKING IS INSUFFICIENT! - msleep( 10000 ); - barrier (); - } - } - } - - p_dec->fmt_out.video.i_chroma = p_dec->fmt_out.i_codec; - return picture_NewFromFormat( &p_dec->fmt_out.video ); + p_enc->fmt_in.video.i_chroma = p_enc->fmt_in.i_codec; + return picture_NewFromFormat( &p_enc->fmt_in.video ); } static picture_t *transcode_video_filter_buffer_new( filter_t *p_filter ) @@ -104,77 +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_vout_buffer_new = transcode_video_filter_buffer_new; - p_filter->pf_vout_buffer_del = transcode_video_filter_buffer_del; - return VLC_SUCCESS; -} -static void transcode_video_filter_allocation_clear( filter_t *p_filter ) +static void* EncoderThread( void *obj ) { - VLC_UNUSED(p_filter); -} - -static void* EncoderThread( vlc_object_t* p_this ) -{ - sout_stream_sys_t *p_sys = (sout_stream_sys_t*)p_this; - sout_stream_id_t *id = p_sys->id_video; - picture_t *p_pic; + sout_stream_sys_t *p_sys = (sout_stream_sys_t*)obj; + sout_stream_id_sys_t *id = p_sys->id_video; + picture_t *p_pic = NULL; int canc = vlc_savecancel (); + block_t *p_block = NULL; - while( vlc_object_alive (p_sys) && !p_sys->b_error ) - { - block_t *p_block; + vlc_mutex_lock( &p_sys->lock_out ); - vlc_mutex_lock( &p_sys->lock_out ); - while( p_sys->i_last_pic == p_sys->i_first_pic ) - { + for( ;; ) + { + 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( !vlc_object_alive (p_sys) || p_sys->b_error ) break; - } - if( !vlc_object_alive (p_sys) || p_sys->b_error ) + + if( p_pic ) { + /* release lock while encoding */ vlc_mutex_unlock( &p_sys->lock_out ); - break; - } - - p_pic = p_sys->pp_pics[p_sys->i_first_pic++]; - p_sys->i_first_pic %= PICTURE_RING_SIZE; - vlc_mutex_unlock( &p_sys->lock_out ); - - video_timer_start( id->p_encoder ); - p_block = id->p_encoder->pf_encode_video( id->p_encoder, p_pic ); - video_timer_stop( id->p_encoder ); + p_block = id->p_encoder->pf_encode_video( id->p_encoder, p_pic ); + picture_Release( p_pic ); + vlc_mutex_lock( &p_sys->lock_out ); - vlc_mutex_lock( &p_sys->lock_out ); - block_ChainAppend( &p_sys->p_buffers, p_block ); + block_ChainAppend( &p_sys->p_buffers, p_block ); + } - vlc_mutex_unlock( &p_sys->lock_out ); - picture_Release( p_pic ); + if( p_sys->b_abort ) + break; } - while( p_sys->i_last_pic != p_sys->i_first_pic ) + /*Encode what we have in the buffer on closing*/ + while( (p_pic = picture_fifo_Pop( p_sys->pp_pics )) != NULL ) { - p_pic = p_sys->pp_pics[p_sys->i_first_pic++]; - p_sys->i_first_pic %= PICTURE_RING_SIZE; + p_block = id->p_encoder->pf_encode_video( id->p_encoder, p_pic ); picture_Release( p_pic ); + block_ChainAppend( &p_sys->p_buffers, p_block ); } - block_ChainRelease( p_sys->p_buffers ); + + /*Now flush encoder*/ + do { + 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; @@ -187,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 +174,16 @@ int transcode_video_new( sout_stream_t *p_stream, sout_stream_id_t *id ) ? id->p_encoder->fmt_out.video.i_height : id->p_decoder->fmt_in.video.i_height ? id->p_decoder->fmt_in.video.i_height : 16; - id->p_encoder->fmt_in.video.i_frame_rate = ENC_FRAMERATE; - id->p_encoder->fmt_in.video.i_frame_rate_base = ENC_FRAMERATE_BASE; + id->p_encoder->fmt_in.video.i_visible_width = + id->p_encoder->fmt_out.video.i_visible_width + ? id->p_encoder->fmt_out.video.i_visible_width + : id->p_decoder->fmt_in.video.i_visible_width + ? id->p_decoder->fmt_in.video.i_visible_width : id->p_encoder->fmt_in.video.i_width; + id->p_encoder->fmt_in.video.i_visible_height = + id->p_encoder->fmt_out.video.i_visible_height + ? 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->i_threads = p_sys->i_threads; id->p_encoder->p_cfg = p_sys->p_video_cfg; @@ -242,7 +192,7 @@ int transcode_video_new( sout_stream_t *p_stream, sout_stream_id_t *id ) module_need( id->p_encoder, "encoder", p_sys->psz_venc, true ); if( !id->p_encoder->p_module ) { - msg_Err( p_stream, "cannot find video encoder (module:%s fourcc:%4.4s)", + msg_Err( p_stream, "cannot find video encoder (module:%s fourcc:%4.4s). Take a look few lines earlier to see possible reason.", p_sys->psz_venc ? p_sys->psz_venc : "any", (char *)&p_sys->i_vcodec ); module_unneed( id->p_decoder, id->p_decoder->p_module ); @@ -262,157 +212,333 @@ 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 ); - memset( p_sys->pp_pics, 0, sizeof(p_sys->pp_pics) ); - p_sys->i_first_pic = 0; - p_sys->i_last_pic = 0; - p_sys->p_buffers = NULL; - p_sys->b_die = p_sys->b_error = 0; - if( vlc_thread_create( p_sys, "encoder", EncoderThread, i_priority ) ) + 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_Err( p_stream, "cannot spawn encoder thread" ); - module_unneed( id->p_decoder, id->p_decoder->p_module ); - id->p_decoder->p_module = 0; - free( id->p_decoder->p_owner ); - return VLC_EGENERIC; + msg_Dbg( p_stream, "deinterlace through colorspace conversion to %4.4s succeeded", (char *)fourcc ); + return p_filter; } } - return VLC_SUCCESS; + + 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_sys_t *id ) +{ + 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_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, + "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 ) + { + 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 ); + 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; + } + +} + +/* Take care of the scaling and chroma conversions. */ +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 ); + + if( ( p_fmt_out->video.i_chroma != id->p_encoder->fmt_in.video.i_chroma ) || + ( 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_uf_chain ? id->p_uf_chain : id->p_f_chain, + NULL, NULL, + p_fmt_out, + &id->p_encoder->fmt_in ); + } } + 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; + 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 ); + } + /* Calculate scaling * width/height of source */ - int i_src_width = id->p_decoder->fmt_out.video.i_width; - int i_src_height = id->p_decoder->fmt_out.video.i_height; + int i_src_visible_width = p_fmt_out->video.i_visible_width; + int i_src_visible_height = p_fmt_out->video.i_visible_height; + + if (i_src_visible_width == 0) + i_src_visible_width = p_fmt_out->video.i_width; + if (i_src_visible_height == 0) + i_src_visible_height = p_fmt_out->video.i_height; + /* with/height scaling */ float f_scale_width = 1; float f_scale_height = 1; - /* width/height of output stream */ - int i_dst_width; - int i_dst_height; - /* aspect ratio */ - float f_aspect = (double)id->p_decoder->fmt_out.video.i_sar_num * - id->p_decoder->fmt_out.video.i_width / - id->p_decoder->fmt_out.video.i_sar_den / - id->p_decoder->fmt_out.video.i_height; + float f_aspect = (double)p_fmt_out->video.i_sar_num * + p_fmt_out->video.i_width / + 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_height / i_src_width; - msg_Dbg( p_stream, "source pixel aspect is %f:1", f_aspect ); + f_aspect = f_aspect * i_src_visible_height / i_src_visible_width; + 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; int i_new_height; - int i_new_width = i_src_width * p_sys->f_scale; + int i_new_width = i_src_visible_width * p_sys->f_scale; if( i_new_width % 16 <= 7 && i_new_width >= 16 ) i_new_width -= i_new_width % 16; else i_new_width += 16 - i_new_width % 16; - f_real_scale = (float)( i_new_width ) / (float) i_src_width; + f_real_scale = (float)( i_new_width ) / (float) i_src_visible_width; - i_new_height = __MAX( 16, i_src_height * (float)f_real_scale ); + i_new_height = __MAX( 16, i_src_visible_height * (float)f_real_scale ); f_scale_width = f_real_scale; - f_scale_height = (float) i_new_height / (float) i_src_height; + 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_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_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_width; - f_scale_height = (float)id->p_encoder->fmt_out.video.i_height/i_src_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 */ if( p_sys->i_maxwidth && f_scale_width > (float)p_sys->i_maxwidth / - i_src_width ) + i_src_visible_width ) { - f_scale_width = (float)p_sys->i_maxwidth / i_src_width; + f_scale_width = (float)p_sys->i_maxwidth / i_src_visible_width; } if( p_sys->i_maxheight && f_scale_height > (float)p_sys->i_maxheight / - i_src_height ) + i_src_visible_height ) { - f_scale_height = (float)p_sys->i_maxheight / i_src_height; + f_scale_height = (float)p_sys->i_maxheight / i_src_visible_height; } /* 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 */ - i_dst_width = 2 * (int)(f_scale_width*i_src_width/2+0.5); - i_dst_height = 2 * (int)(f_scale_height*i_src_height/2+0.5); + /* width/height of output stream */ + 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_width / i_dst_height; + f_aspect = f_aspect * i_dst_visible_width / i_dst_visible_height; /* Store calculated values */ - id->p_encoder->fmt_out.video.i_width = - id->p_encoder->fmt_out.video.i_visible_width = i_dst_width; - id->p_encoder->fmt_out.video.i_height = - id->p_encoder->fmt_out.video.i_visible_height = i_dst_height; + id->p_encoder->fmt_out.video.i_width = i_dst_width; + id->p_encoder->fmt_out.video.i_visible_width = i_dst_visible_width; + id->p_encoder->fmt_out.video.i_height = i_dst_height; + id->p_encoder->fmt_out.video.i_visible_height = i_dst_visible_height; - id->p_encoder->fmt_in.video.i_width = - id->p_encoder->fmt_in.video.i_visible_width = i_dst_width; - id->p_encoder->fmt_in.video.i_height = - id->p_encoder->fmt_in.video.i_visible_height = i_dst_height; + id->p_encoder->fmt_in.video.i_width = i_dst_width; + id->p_encoder->fmt_in.video.i_visible_width = i_dst_visible_width; + id->p_encoder->fmt_in.video.i_height = i_dst_height; + id->p_encoder->fmt_in.video.i_visible_height = i_dst_visible_height; msg_Dbg( p_stream, "source %ix%i, destination %ix%i", - i_src_width, i_src_height, - i_dst_width, i_dst_height + i_src_visible_width, i_src_visible_height, + i_dst_visible_width, i_dst_visible_height ); /* Handle frame rate conversion */ if( !id->p_encoder->fmt_out.video.i_frame_rate || !id->p_encoder->fmt_out.video.i_frame_rate_base ) { - if( id->p_decoder->fmt_out.video.i_frame_rate && - id->p_decoder->fmt_out.video.i_frame_rate_base ) + if( p_fmt_out->video.i_frame_rate && + p_fmt_out->video.i_frame_rate_base ) { id->p_encoder->fmt_out.video.i_frame_rate = - id->p_decoder->fmt_out.video.i_frame_rate; + p_fmt_out->video.i_frame_rate; id->p_encoder->fmt_out.video.i_frame_rate_base = - id->p_decoder->fmt_out.video.i_frame_rate_base; + p_fmt_out->video.i_frame_rate_base; } else { @@ -422,24 +548,46 @@ 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 = id->p_encoder->fmt_out.video.i_frame_rate_base; - date_Init( &id->interpolated_pts, - id->p_encoder->fmt_out.video.i_frame_rate, - id->p_encoder->fmt_out.video.i_frame_rate_base ); + vlc_ureduce( &id->p_encoder->fmt_in.video.i_frame_rate, + &id->p_encoder->fmt_in.video.i_frame_rate_base, + id->p_encoder->fmt_in.video.i_frame_rate, + id->p_encoder->fmt_in.video.i_frame_rate_base, + 0 ); + msg_Dbg( p_stream, "source fps %d/%d, destination %d/%d", + id->p_decoder->fmt_out.video.i_frame_rate, + id->p_decoder->fmt_out.video.i_frame_rate_base, + id->p_encoder->fmt_in.video.i_frame_rate, + id->p_encoder->fmt_in.video.i_frame_rate_base ); + /* Check whether a particular aspect ratio was requested */ if( id->p_encoder->fmt_out.video.i_sar_num <= 0 || id->p_encoder->fmt_out.video.i_sar_den <= 0 ) { - id->p_encoder->fmt_out.video.i_sar_num = - f_aspect * id->p_encoder->fmt_out.video.i_height + 0.5; - id->p_encoder->fmt_out.video.i_sar_num = - VOUT_ASPECT_FACTOR * id->p_encoder->fmt_out.video.i_width; + vlc_ureduce( &id->p_encoder->fmt_out.video.i_sar_num, + &id->p_encoder->fmt_out.video.i_sar_den, + (uint64_t)p_fmt_out->video.i_sar_num * i_src_visible_width * i_dst_visible_height, + (uint64_t)p_fmt_out->video.i_sar_den * i_src_visible_height * i_dst_visible_width, + 0 ); + } + else + { + vlc_ureduce( &id->p_encoder->fmt_out.video.i_sar_num, + &id->p_encoder->fmt_out.video.i_sar_den, + id->p_encoder->fmt_out.video.i_sar_num, + id->p_encoder->fmt_out.video.i_sar_den, + 0 ); } + id->p_encoder->fmt_in.video.i_sar_num = id->p_encoder->fmt_out.video.i_sar_num; id->p_encoder->fmt_in.video.i_sar_den = @@ -449,11 +597,10 @@ static void transcode_video_encoder_init( sout_stream_t *p_stream, id->p_encoder->fmt_out.video.i_sar_num * id->p_encoder->fmt_out.video.i_width, id->p_encoder->fmt_out.video.i_sar_den * id->p_encoder->fmt_out.video.i_height ); - id->p_encoder->fmt_in.video.i_chroma = id->p_encoder->fmt_in.i_codec; } 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; @@ -478,8 +625,7 @@ static int transcode_video_encoder_open( sout_stream_t *p_stream, id->p_encoder->fmt_out.i_codec = vlc_fourcc_GetCodec( VIDEO_ES, id->p_encoder->fmt_out.i_codec ); - id->id = sout_StreamIdAdd( p_stream->p_sys->p_out, - &id->p_encoder->fmt_out ); + id->id = sout_StreamIdAdd( p_stream->p_next, &id->p_encoder->fmt_out ); if( !id->id ) { msg_Err( p_stream, "cannot add this stream" ); @@ -490,20 +636,23 @@ 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 ); - vlc_object_kill( p_stream->p_sys ); + p_stream->p_sys->b_abort = true; vlc_cond_signal( &p_stream->p_sys->cond ); vlc_mutex_unlock( &p_stream->p_sys->lock_out ); - vlc_thread_join( p_stream->p_sys ); - vlc_mutex_destroy( &p_stream->p_sys->lock_out ); - vlc_cond_destroy( &p_stream->p_sys->cond ); + + vlc_join( p_stream->p_sys->thread, NULL ); + + picture_fifo_Delete( p_stream->p_sys->pp_pics ); + block_ChainRelease( p_stream->p_sys->p_buffers ); } - video_timer_close( id->p_encoder ); + 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 ) @@ -524,265 +673,212 @@ void transcode_video_close( sout_stream_t *p_stream, filter_chain_Delete( id->p_uf_chain ); } -int transcode_video_process( sout_stream_t *p_stream, sout_stream_id_t *id, - block_t *in, 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; - int i_duplicate = 1; - picture_t *p_pic, *p_pic2 = NULL; - *out = NULL; + picture_t *p_pic2 = NULL; - while( (p_pic = id->p_decoder->pf_decode_video( id->p_decoder, &in )) ) + /* + * Encoding + */ + /* Check if we have a subpicture to overlay */ + if( p_sys->p_spu ) { - subpicture_t *p_subpic = NULL; - - sout_UpdateStatistic( p_stream->p_sout, SOUT_STATISTIC_DECODED_VIDEO, 1 ); - - if( p_stream->p_sout->i_out_pace_nocontrol && p_sys->b_hurry_up ) - { - mtime_t current_date = mdate(); - if( 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( p_sys->b_master_sync ) - { - mtime_t i_video_drift; - mtime_t i_master_drift = p_sys->i_master_drift; - mtime_t i_pts; - - i_pts = date_Get( &id->interpolated_pts ) + 1; - if ( p_pic->date - i_pts > MASTER_SYNC_MAX_DRIFT - || p_pic->date - i_pts < -MASTER_SYNC_MAX_DRIFT ) - { - msg_Dbg( p_stream, "drift is too high, resetting master sync" ); - date_Set( &id->interpolated_pts, p_pic->date ); - i_pts = p_pic->date + 1; - } - i_video_drift = p_pic->date - i_pts; - i_duplicate = 1; - - /* Set the pts of the frame being encoded */ - p_pic->date = i_pts; - - if( i_video_drift < (i_master_drift - 50000) ) - { -#if 0 - msg_Dbg( p_stream, "dropping frame (%i)", - (int)(i_video_drift - i_master_drift) ); -#endif - picture_Release( p_pic ); - continue; - } - else if( i_video_drift > (i_master_drift + 50000) ) - { -#if 0 - msg_Dbg( p_stream, "adding frame (%i)", - (int)(i_video_drift - i_master_drift) ); -#endif - i_duplicate = 2; - } - } - - if( !id->p_encoder->p_module ) + video_format_t fmt = id->p_encoder->fmt_in.video; + if( fmt.i_visible_width <= 0 || fmt.i_visible_height <= 0 ) { - transcode_video_encoder_init( p_stream, 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_sys->psz_deinterlace, - 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_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_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; - } - - if( transcode_video_encoder_open( p_stream, id ) != VLC_SUCCESS ) - { - picture_Release( p_pic ); - transcode_video_close( p_stream, id ); - id->b_transcode = false; - return VLC_EGENERIC; - } + fmt.i_visible_width = fmt.i_width; + fmt.i_visible_height = fmt.i_height; + fmt.i_x_offset = 0; + fmt.i_y_offset = 0; } - /* Run filter chain */ - if( id->p_f_chain ) - p_pic = filter_chain_VideoFilter( id->p_f_chain, p_pic ); - - /* - * Encoding - */ - - /* Check if we have a subpicture to overlay */ - if( p_sys->p_spu ) - { - p_subpic = spu_SortSubpictures( p_sys->p_spu, p_pic->date, false ); - /* TODO: get another pic */ - } + 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 */ if( p_subpic ) { - video_format_t fmt; - if( picture_IsReferenced( p_pic ) && !filter_chain_GetLength( id->p_f_chain ) ) { - /* We can't modify the picture, we need to duplicate it */ - picture_t *p_tmp = video_new_buffer_decoder( id->p_decoder ); - if( p_tmp ) + /* We can't modify the picture, we need to duplicate it, + * in this point the picture is already p_encoder->fmt.in format*/ + picture_t *p_tmp = video_new_buffer_encoder( id->p_encoder ); + if( likely( p_tmp ) ) { picture_Copy( p_tmp, p_pic ); picture_Release( p_pic ); p_pic = p_tmp; } } + if( unlikely( !p_sys->p_spu_blend ) ) + p_sys->p_spu_blend = filter_NewBlend( VLC_OBJECT( p_sys->p_spu ), &fmt ); + if( likely( p_sys->p_spu_blend ) ) + picture_BlendSubpicture( p_pic, p_sys->p_spu_blend, p_subpic ); + subpicture_Delete( p_subpic ); + } + } - if( filter_chain_GetLength( id->p_f_chain ) > 0 ) - fmt = filter_chain_GetFmtOut( id->p_f_chain )->video; - else - fmt = id->p_decoder->fmt_out.video; + if( p_sys->i_threads == 0 ) + { + block_t *p_block; - /* FIXME the mdate() seems highly suspicious */ - spu_RenderSubpictures( p_sys->p_spu, p_pic, &fmt, - p_subpic, &id->p_decoder->fmt_out.video, mdate() ); - } + p_block = id->p_encoder->pf_encode_video( id->p_encoder, p_pic ); + block_ChainAppend( out, p_block ); + } + + if( p_sys->i_threads ) + { + 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 ); + } + + if( p_sys->i_threads && p_pic2 ) + picture_Release( p_pic2 ); + else if ( p_sys->i_threads == 0 ) + picture_Release( p_pic ); +} - /* Run user specified filter chain */ - if( id->p_uf_chain ) - p_pic = filter_chain_VideoFilter( id->p_uf_chain, p_pic ); +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; + picture_t *p_pic = NULL; + *out = NULL; + if( unlikely( in == NULL ) ) + { if( p_sys->i_threads == 0 ) { block_t *p_block; + do { + p_block = id->p_encoder->pf_encode_video(id->p_encoder, NULL ); + block_ChainAppend( out, p_block ); + } while( p_block ); + } + else + { + msg_Dbg( p_stream, "Flushing thread and waiting that"); + vlc_mutex_lock( &p_stream->p_sys->lock_out ); + p_stream->p_sys->b_abort = true; + vlc_cond_signal( &p_stream->p_sys->cond ); + vlc_mutex_unlock( &p_stream->p_sys->lock_out ); - video_timer_start( id->p_encoder ); - p_block = id->p_encoder->pf_encode_video( id->p_encoder, p_pic ); - video_timer_stop( id->p_encoder ); + vlc_join( p_stream->p_sys->thread, NULL ); + vlc_mutex_lock( &p_sys->lock_out ); + *out = p_sys->p_buffers; + p_sys->p_buffers = NULL; + vlc_mutex_unlock( &p_sys->lock_out ); - block_ChainAppend( out, p_block ); + msg_Dbg( p_stream, "Flushing done"); } + return VLC_SUCCESS; + } + + + while( (p_pic = id->p_decoder->pf_decode_video( id->p_decoder, &in )) ) + { - if( p_sys->b_master_sync ) + if( unlikely ( + id->p_encoder->p_module && + !video_format_IsSimilar( &id->fmt_input_video, &id->p_decoder->fmt_out.video ) + ) + ) { - mtime_t i_pts = date_Get( &id->interpolated_pts ) + 1; - if ( p_pic->date - i_pts > MASTER_SYNC_MAX_DRIFT - || p_pic->date - i_pts < -MASTER_SYNC_MAX_DRIFT ) - { - msg_Dbg( p_stream, "drift is too high, resetting master sync" ); - date_Set( &id->interpolated_pts, p_pic->date ); - i_pts = p_pic->date + 1; - } - date_Increment( &id->interpolated_pts, 1 ); + msg_Info( p_stream, "aspect-ratio changed, reiniting. %i -> %i : %i -> %i.", + 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 ) + filter_chain_Delete( id->p_f_chain ); + id->p_f_chain = NULL; + if( id->p_uf_chain ) + filter_chain_Delete( id->p_uf_chain ); + id->p_uf_chain = NULL; + + /* Reinitialize filters */ + 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( &id->fmt_input_video, &id->p_decoder->fmt_out.video, sizeof(video_format_t)); } - if( p_sys->b_master_sync && i_duplicate > 1 ) + + if( unlikely( !id->p_encoder->p_module ) ) { - mtime_t i_pts = date_Get( &id->interpolated_pts ) + 1; - if( (p_pic->date - i_pts > MASTER_SYNC_MAX_DRIFT) - || ((p_pic->date - i_pts) < -MASTER_SYNC_MAX_DRIFT) ) - { - msg_Dbg( p_stream, "drift is too high, resetting master sync" ); - date_Set( &id->interpolated_pts, p_pic->date ); - i_pts = p_pic->date + 1; - } - date_Increment( &id->interpolated_pts, 1 ); + if( id->p_f_chain ) + filter_chain_Delete( id->p_f_chain ); + if( id->p_uf_chain ) + filter_chain_Delete( id->p_uf_chain ); + id->p_f_chain = id->p_uf_chain = NULL; - if( p_sys->i_threads >= 1 ) - { - /* We can't modify the picture, we need to duplicate it */ - p_pic2 = video_new_buffer_decoder( id->p_decoder ); - if( p_pic2 != NULL ) - { - picture_Copy( p_pic2, p_pic ); - p_pic2->date = i_pts; - } - } - else + transcode_video_filter_init( p_stream, id ); + transcode_video_encoder_init( p_stream, id ); + conversion_video_filter_append( id ); + 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 ) { - block_t *p_block; - p_pic->date = i_pts; - video_timer_start( id->p_encoder ); - p_block = id->p_encoder->pf_encode_video(id->p_encoder, p_pic); - video_timer_stop( id->p_encoder ); - block_ChainAppend( out, p_block ); + picture_Release( p_pic ); + transcode_video_close( p_stream, id ); + id->b_transcode = false; + return VLC_EGENERIC; } } - if( p_sys->i_threads == 0 ) - { - picture_Release( p_pic ); - } - else - { - vlc_mutex_lock( &p_sys->lock_out ); - p_sys->pp_pics[p_sys->i_last_pic++] = p_pic; - p_sys->i_last_pic %= PICTURE_RING_SIZE; - *out = p_sys->p_buffers; - p_sys->p_buffers = NULL; - if( p_pic2 != NULL ) - { - p_sys->pp_pics[p_sys->i_last_pic++] = p_pic2; - p_sys->i_last_pic %= PICTURE_RING_SIZE; + /* 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. + */ + for ( ;; ) { + picture_t *p_filtered_pic = p_pic; + + /* Run filter chain */ + if( id->p_f_chain ) + p_filtered_pic = filter_chain_VideoFilter( id->p_f_chain, p_filtered_pic ); + if( !p_filtered_pic ) + break; + + for ( ;; ) { + picture_t *p_user_filtered_pic = p_filtered_pic; + + /* Run user specified filter chain */ + if( id->p_uf_chain ) + p_user_filtered_pic = filter_chain_VideoFilter( id->p_uf_chain, p_user_filtered_pic ); + if( !p_user_filtered_pic ) + break; + + OutputFrame( p_stream, p_user_filtered_pic, id, out ); + + p_filtered_pic = NULL; } - vlc_cond_signal( &p_sys->cond ); - vlc_mutex_unlock( &p_sys->lock_out ); + + p_pic = NULL; } } + if( p_sys->i_threads >= 1 ) + { + /* Pick up any return data the encoder thread wants to output. */ + vlc_mutex_lock( &p_sys->lock_out ); + *out = p_sys->p_buffers; + p_sys->p_buffers = NULL; + vlc_mutex_unlock( &p_sys->lock_out ); + } + 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; @@ -792,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 */ @@ -807,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 * 1000) + 0.5; - 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;