static decoder_t *CreateDecoder( vlc_object_t *p_this, video_format_t *fmt ) { decoder_t *p_dec; p_dec = vlc_custom_create( p_this, sizeof( *p_dec ), "image decoder" ); if( p_dec == NULL ) return NULL; p_dec->p_module = NULL; es_format_Init( &p_dec->fmt_in, VIDEO_ES, fmt->i_chroma ); es_format_Init( &p_dec->fmt_out, VIDEO_ES, 0 ); p_dec->fmt_in.video = *fmt; p_dec->b_frame_drop_allowed = false; p_dec->pf_vout_format_update = video_update_format; p_dec->pf_vout_buffer_new = video_new_buffer; /* Find a suitable decoder module */ p_dec->p_module = module_need( p_dec, "decoder", "$codec", false ); if( !p_dec->p_module ) { msg_Err( p_dec, "no suitable decoder module for fourcc `%4.4s'. " "VLC probably does not support this image format.", (char*)&p_dec->fmt_in.i_codec ); DeleteDecoder( p_dec ); return NULL; } return p_dec; }
/** * Delete the image_handler_t instance * */ void image_HandlerDelete( image_handler_t *p_image ) { if( !p_image ) return; if( p_image->p_dec ) DeleteDecoder( p_image->p_dec ); if( p_image->p_enc ) DeleteEncoder( p_image->p_enc ); if( p_image->p_filter ) DeleteFilter( p_image->p_filter ); free( p_image ); p_image = NULL; }
static picture_t *ImageRead( image_handler_t *p_image, block_t *p_block, video_format_t *p_fmt_in, video_format_t *p_fmt_out ) { picture_t *p_pic = NULL, *p_tmp; /* Check if we can reuse the current decoder */ if( p_image->p_dec && p_image->p_dec->fmt_in.i_codec != p_fmt_in->i_chroma ) { DeleteDecoder( p_image->p_dec ); p_image->p_dec = 0; } /* Start a decoder */ if( !p_image->p_dec ) { p_image->p_dec = CreateDecoder( p_image->p_parent, p_fmt_in ); if( !p_image->p_dec ) { block_Release(p_block); return NULL; } } p_block->i_pts = p_block->i_dts = mdate(); while( (p_tmp = p_image->p_dec->pf_decode_video( p_image->p_dec, &p_block )) != NULL ) { if( p_pic != NULL ) picture_Release( p_pic ); p_pic = p_tmp; } if( p_pic == NULL ) { msg_Warn( p_image->p_parent, "no image decoded" ); return 0; } if( !p_fmt_out->i_chroma ) p_fmt_out->i_chroma = p_image->p_dec->fmt_out.video.i_chroma; if( !p_fmt_out->i_width && p_fmt_out->i_height ) p_fmt_out->i_width = (int64_t)p_image->p_dec->fmt_out.video.i_width * p_image->p_dec->fmt_out.video.i_sar_num * p_fmt_out->i_height / p_image->p_dec->fmt_out.video.i_height / p_image->p_dec->fmt_out.video.i_sar_den; if( !p_fmt_out->i_height && p_fmt_out->i_width ) p_fmt_out->i_height = (int64_t)p_image->p_dec->fmt_out.video.i_height * p_image->p_dec->fmt_out.video.i_sar_den * p_fmt_out->i_width / p_image->p_dec->fmt_out.video.i_width / p_image->p_dec->fmt_out.video.i_sar_num; if( !p_fmt_out->i_width ) p_fmt_out->i_width = p_image->p_dec->fmt_out.video.i_width; if( !p_fmt_out->i_height ) p_fmt_out->i_height = p_image->p_dec->fmt_out.video.i_height; if( !p_fmt_out->i_visible_width ) p_fmt_out->i_visible_width = p_fmt_out->i_width; if( !p_fmt_out->i_visible_height ) p_fmt_out->i_visible_height = p_fmt_out->i_height; /* Check if we need chroma conversion or resizing */ if( p_image->p_dec->fmt_out.video.i_chroma != p_fmt_out->i_chroma || p_image->p_dec->fmt_out.video.i_width != p_fmt_out->i_width || p_image->p_dec->fmt_out.video.i_height != p_fmt_out->i_height ) { if( p_image->p_filter ) if( p_image->p_filter->fmt_in.video.i_chroma != p_image->p_dec->fmt_out.video.i_chroma || p_image->p_filter->fmt_out.video.i_chroma != p_fmt_out->i_chroma ) { /* We need to restart a new filter */ DeleteFilter( p_image->p_filter ); p_image->p_filter = 0; } /* Start a filter */ if( !p_image->p_filter ) { p_image->p_filter = CreateFilter( p_image->p_parent, &p_image->p_dec->fmt_out, p_fmt_out ); if( !p_image->p_filter ) { picture_Release( p_pic ); return NULL; } } else { /* Filters should handle on-the-fly size changes */ p_image->p_filter->fmt_in = p_image->p_dec->fmt_out; p_image->p_filter->fmt_out = p_image->p_dec->fmt_out; p_image->p_filter->fmt_out.i_codec = p_fmt_out->i_chroma; p_image->p_filter->fmt_out.video = *p_fmt_out; } p_pic = p_image->p_filter->pf_video_filter( p_image->p_filter, p_pic ); *p_fmt_out = p_image->p_filter->fmt_out.video; } else *p_fmt_out = p_image->p_dec->fmt_out.video; return p_pic; }
static picture_t *ImageRead( image_handler_t *p_image, block_t *p_block, const video_format_t *p_fmt_in, video_format_t *p_fmt_out ) { picture_t *p_pic = NULL; /* Check if we can reuse the current decoder */ if( p_image->p_dec && p_image->p_dec->fmt_in.i_codec != p_fmt_in->i_chroma ) { DeleteDecoder( p_image->p_dec ); p_image->p_dec = 0; } /* Start a decoder */ if( !p_image->p_dec ) { p_image->p_dec = CreateDecoder( p_image->p_parent, p_fmt_in ); if( !p_image->p_dec ) { block_Release(p_block); return NULL; } if( p_image->p_dec->fmt_out.i_cat != VIDEO_ES ) { DeleteDecoder( p_image->p_dec ); p_image->p_dec = NULL; block_Release(p_block); return NULL; } p_image->p_dec->pf_queue_video = ImageQueueVideo; p_image->p_dec->p_queue_ctx = p_image; } p_block->i_pts = p_block->i_dts = mdate(); int ret = p_image->p_dec->pf_decode( p_image->p_dec, p_block ); if( ret == VLCDEC_SUCCESS ) { /* Drain */ p_image->p_dec->pf_decode( p_image->p_dec, NULL ); p_pic = picture_fifo_Pop( p_image->outfifo ); unsigned lostcount = 0; picture_t *lostpic; while( ( lostpic = picture_fifo_Pop( p_image->outfifo ) ) != NULL ) { picture_Release( lostpic ); lostcount++; } if( lostcount > 0 ) msg_Warn( p_image->p_parent, "Image decoder output more than one " "picture (%d)", lostcount ); } if( p_pic == NULL ) { msg_Warn( p_image->p_parent, "no image decoded" ); return 0; } if( !p_fmt_out->i_chroma ) p_fmt_out->i_chroma = p_image->p_dec->fmt_out.video.i_chroma; if( !p_fmt_out->i_width && p_fmt_out->i_height ) p_fmt_out->i_width = (int64_t)p_image->p_dec->fmt_out.video.i_width * p_image->p_dec->fmt_out.video.i_sar_num * p_fmt_out->i_height / p_image->p_dec->fmt_out.video.i_height / p_image->p_dec->fmt_out.video.i_sar_den; if( !p_fmt_out->i_height && p_fmt_out->i_width ) p_fmt_out->i_height = (int64_t)p_image->p_dec->fmt_out.video.i_height * p_image->p_dec->fmt_out.video.i_sar_den * p_fmt_out->i_width / p_image->p_dec->fmt_out.video.i_width / p_image->p_dec->fmt_out.video.i_sar_num; if( !p_fmt_out->i_width ) p_fmt_out->i_width = p_image->p_dec->fmt_out.video.i_width; if( !p_fmt_out->i_height ) p_fmt_out->i_height = p_image->p_dec->fmt_out.video.i_height; if( !p_fmt_out->i_visible_width ) p_fmt_out->i_visible_width = p_fmt_out->i_width; if( !p_fmt_out->i_visible_height ) p_fmt_out->i_visible_height = p_fmt_out->i_height; /* Check if we need chroma conversion or resizing */ if( p_image->p_dec->fmt_out.video.i_chroma != p_fmt_out->i_chroma || p_image->p_dec->fmt_out.video.i_width != p_fmt_out->i_width || p_image->p_dec->fmt_out.video.i_height != p_fmt_out->i_height ) { if( p_image->p_filter ) if( p_image->p_filter->fmt_in.video.i_chroma != p_image->p_dec->fmt_out.video.i_chroma || p_image->p_filter->fmt_out.video.i_chroma != p_fmt_out->i_chroma ) { /* We need to restart a new filter */ DeleteFilter( p_image->p_filter ); p_image->p_filter = 0; } /* Start a filter */ if( !p_image->p_filter ) { p_image->p_filter = CreateFilter( p_image->p_parent, &p_image->p_dec->fmt_out, p_fmt_out ); if( !p_image->p_filter ) { picture_Release( p_pic ); return NULL; } } else { /* Filters should handle on-the-fly size changes */ p_image->p_filter->fmt_in = p_image->p_dec->fmt_out; p_image->p_filter->fmt_out = p_image->p_dec->fmt_out; p_image->p_filter->fmt_out.i_codec = p_fmt_out->i_chroma; p_image->p_filter->fmt_out.video = *p_fmt_out; } p_pic = p_image->p_filter->pf_video_filter( p_image->p_filter, p_pic ); video_format_Clean( p_fmt_out ); video_format_Copy( p_fmt_out, &p_image->p_filter->fmt_out.video ); } else { video_format_Clean( p_fmt_out ); video_format_Copy( p_fmt_out, &p_image->p_dec->fmt_out.video ); } return p_pic; }