static void Display(vout_display_t *vd, picture_t *picture, subpicture_t *subpicture) { vout_display_sys_t *sys = vd->sys; assert(!picture_IsReferenced(picture)); if (sys->display != NULL) sys->display(sys->opaque, picture->p_sys->id); picture_Release(picture); VLC_UNUSED(subpicture); }
static void Unlock(void *data, picture_t *pic) { vout_display_sys_t *sys = data; picture_sys_t *picsys = pic->p_sys; void *planes[PICTURE_PLANE_MAX]; assert(!picture_IsReferenced(pic)); for (int i = 0; i < pic->i_planes; i++) planes[i] = pic->p[i].p_pixels; if (sys->unlock != NULL) sys->unlock(sys->opaque, picsys->id, planes); }
int transcode_video_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; bool b_need_duplicate = false; picture_t *p_pic, *p_pic2 = NULL; *out = NULL; if( in == NULL ) { if( p_sys->i_threads == 0 ) { block_t *p_block; do { video_timer_start( id->p_encoder ); p_block = id->p_encoder->pf_encode_video(id->p_encoder, NULL ); video_timer_stop( id->p_encoder ); block_ChainAppend( out, p_block ); } while( p_block ); } else { /* * FIXME: we need EncoderThread() to flush buffers and signal us * when it's done so we can send the last frames to the chain */ } return VLC_SUCCESS; } 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( 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; b_need_duplicate = false; /* 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 b_need_duplicate = true; } } if( unlikely( !id->p_encoder->p_module ) ) { transcode_video_encoder_init( p_stream, id ); transcode_video_filter_init( p_stream, id ); 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; } } /* 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 ) { video_format_t fmt; 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; subpicture_t *p_subpic = spu_Render( p_sys->p_spu, NULL, &fmt, &fmt, p_pic->date, p_pic->date, false ); /* Overlay subpicture */ if( p_subpic ) { 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 ) { picture_Copy( p_tmp, p_pic ); picture_Release( p_pic ); p_pic = p_tmp; } } if( !p_sys->p_spu_blend ) p_sys->p_spu_blend = filter_NewBlend( VLC_OBJECT( p_sys->p_spu ), &fmt ); if( p_sys->p_spu_blend ) picture_BlendSubpicture( p_pic, p_sys->p_spu_blend, p_subpic ); subpicture_Delete( p_subpic ); } } /* Run user specified filter chain */ if( id->p_uf_chain ) p_pic = filter_chain_VideoFilter( id->p_uf_chain, p_pic ); if( p_sys->i_threads == 0 ) { block_t *p_block; 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 ); } if( p_sys->b_master_sync ) { 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( unlikely( b_need_duplicate ) ) { 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 { 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 ); } } } 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; } vlc_cond_signal( &p_sys->cond ); vlc_mutex_unlock( &p_sys->lock_out ); } } return VLC_SUCCESS; }
static void OutputFrame( sout_stream_sys_t *p_sys, picture_t *p_pic, bool b_need_duplicate, sout_stream_t *p_stream, sout_stream_id_t *id, block_t **out ) { picture_t *p_pic2 = NULL; /* * Encoding */ /* Check if we have a subpicture to overlay */ if( p_sys->p_spu ) { video_format_t fmt = id->p_encoder->fmt_in.video; if( fmt.i_visible_width <= 0 || fmt.i_visible_height <= 0 ) { fmt.i_visible_width = fmt.i_width; fmt.i_visible_height = fmt.i_height; fmt.i_x_offset = 0; fmt.i_y_offset = 0; } subpicture_t *p_subpic = spu_Render( p_sys->p_spu, NULL, &fmt, &fmt, p_pic->date, p_pic->date, false ); /* Overlay subpicture */ if( p_subpic ) { if( picture_IsReferenced( p_pic ) && !filter_chain_GetLength( id->p_f_chain ) ) { /* 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( p_sys->i_threads == 0 ) { block_t *p_block; p_block = id->p_encoder->pf_encode_video( id->p_encoder, p_pic ); block_ChainAppend( out, p_block ); } if( p_sys->b_master_sync ) { mtime_t i_pts = date_Get( &id->interpolated_pts ) + 1; mtime_t i_video_drift = p_pic->date - i_pts; if (unlikely ( i_video_drift > MASTER_SYNC_MAX_DRIFT || i_video_drift < -MASTER_SYNC_MAX_DRIFT ) ) { msg_Dbg( p_stream, "drift is too high (%"PRId64"), resetting master sync", i_video_drift ); date_Set( &id->interpolated_pts, p_pic->date ); i_pts = p_pic->date + 1; } date_Increment( &id->interpolated_pts, 1 ); if( unlikely( b_need_duplicate ) ) { if( p_sys->i_threads >= 1 ) { /* We can't modify the picture, we need to duplicate it */ p_pic2 = video_new_buffer_encoder( id->p_encoder ); if( likely( p_pic2 != NULL ) ) { picture_Copy( p_pic2, p_pic ); p_pic2->date = i_pts; } } else { block_t *p_block; p_pic->date = i_pts; p_block = id->p_encoder->pf_encode_video(id->p_encoder, p_pic); block_ChainAppend( out, p_block ); } } } if( p_sys->i_threads == 0 ) { picture_Release( p_pic ); } else { vlc_mutex_lock( &p_sys->lock_out ); picture_fifo_Push( p_sys->pp_pics, p_pic ); if( p_pic2 != NULL ) { picture_fifo_Push( p_sys->pp_pics, p_pic2 ); } vlc_cond_signal( &p_sys->cond ); vlc_mutex_unlock( &p_sys->lock_out ); } }
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 ) { 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 */ /* Check if we have a subpicture to overlay */ if( p_sys->p_spu ) { video_format_t fmt = id->p_encoder->fmt_in.video; if( fmt.i_visible_width <= 0 || fmt.i_visible_height <= 0 ) { fmt.i_visible_width = fmt.i_width; fmt.i_visible_height = fmt.i_height; fmt.i_x_offset = 0; fmt.i_y_offset = 0; } subpicture_t *p_subpic = spu_Render( p_sys->p_spu, NULL, &fmt, &fmt, p_pic->date, p_pic->date, false ); /* Overlay subpicture */ if( p_subpic ) { if( picture_IsReferenced( p_pic ) && !filter_chain_GetLength( id->p_f_chain ) ) { /* 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 ); } } /*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 ) { block_t *p_block; p_block = id->p_encoder->pf_encode_video( id->p_encoder, p_pic ); 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 ); }