X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fvideo_output%2Fvout_pictures.c;h=318646ef471cce08daaca51788ef93d5d2c77646;hb=d475b82a023d7016dba778ea1110999c8c953277;hp=de99ead698fad7bb1905bccda0433306c32a0a4e;hpb=14047fa106514c9839987c24c925cae340520019;p=vlc diff --git a/src/video_output/vout_pictures.c b/src/video_output/vout_pictures.c index de99ead698..318646ef47 100644 --- a/src/video_output/vout_pictures.c +++ b/src/video_output/vout_pictures.c @@ -1,8 +1,8 @@ /***************************************************************************** * vout_pictures.c : picture management functions ***************************************************************************** - * Copyright (C) 2000 VideoLAN - * $Id: vout_pictures.c,v 1.4 2001/12/16 16:18:36 sam Exp $ + * Copyright (C) 2000-2004 the VideoLAN team + * $Id$ * * Authors: Vincent Seguin * Samuel Hocevar @@ -19,516 +19,442 @@ * * 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ /***************************************************************************** * Preamble *****************************************************************************/ -#include "defs.h" -#include /* ENOMEM */ -#include /* free() */ -#include /* sprintf() */ -#include /* strerror() */ - -#include "common.h" -#include "intf_msg.h" -#include "threads.h" -#include "mtime.h" - -#include "video.h" -#include "video_output.h" - -/***************************************************************************** - * Local prototypes - *****************************************************************************/ -static void NewPicture ( vout_thread_t *, picture_t * ); - -/***************************************************************************** - * vout_DisplayPicture: display a picture - ***************************************************************************** - * Remove the reservation flag of a picture, which will cause it to be ready for - * display. The picture won't be displayed until vout_DatePicture has been - * called. - *****************************************************************************/ -void vout_DisplayPicture( vout_thread_t *p_vout, picture_t *p_picture ) -{ - vlc_mutex_lock( &p_vout->picture_lock ); - switch( p_picture->i_status ) - { - case RESERVED_PICTURE: - p_picture->i_status = RESERVED_DISP_PICTURE; - break; - case RESERVED_DATED_PICTURE: - p_picture->i_status = READY_PICTURE; - break; -#ifdef DEBUG - default: - intf_ErrMsg("error: picture %p has invalid status %d", p_picture, p_picture->i_status ); - break; +#ifdef HAVE_CONFIG_H +# include "config.h" #endif +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vout_internal.h" + +/** + * It retreives a picture from the vout or NULL if no pictures are + * available yet. + * + * You MUST call vout_PutPicture or vout_ReleasePicture on it. + * + * You may use vout_HoldPicture(paired with vout_ReleasePicture) to keep a + * read-only reference. + */ +picture_t *vout_GetPicture( vout_thread_t *p_vout ) +{ + /* Get lock */ + vlc_mutex_lock( &p_vout->p->picture_lock ); + picture_t *p_pic = picture_pool_Get(p_vout->p->decoder_pool); + if (p_pic) { + picture_Reset(p_pic); + p_pic->p_next = NULL; } + vlc_mutex_unlock( &p_vout->p->picture_lock ); -#ifdef TRACE_VOUT - intf_DbgMsg("picture %p", p_picture); -#endif - vlc_mutex_unlock( &p_vout->picture_lock ); + return p_pic; } -/***************************************************************************** - * vout_DatePicture: date a picture - ***************************************************************************** - * Remove the reservation flag of a picture, which will cause it to be ready - * for display. The picture won't be displayed until vout_DisplayPicture has - * been called. - *****************************************************************************/ -void vout_DatePicture( vout_thread_t *p_vout, - picture_t *p_picture, mtime_t date ) +/** + * It gives to the vout a picture to be displayed. + * + * The given picture MUST comes from vout_GetPicture. + * + * Becareful, after vout_PutPicture is called, picture_t::p_next cannot be + * read/used. + */ +void vout_PutPicture( vout_thread_t *p_vout, picture_t *p_pic ) { -#ifdef TRACE_VOUT - char psz_date[ MSTRTIME_MAX_SIZE ]; /* date */ -#endif + vlc_mutex_lock( &p_vout->p->picture_lock ); - vlc_mutex_lock( &p_vout->picture_lock ); - p_picture->date = date; - switch( p_picture->i_status ) - { - case RESERVED_PICTURE: - p_picture->i_status = RESERVED_DATED_PICTURE; - break; - case RESERVED_DISP_PICTURE: - p_picture->i_status = READY_PICTURE; - break; -#ifdef DEBUG - default: - intf_ErrMsg("error: picture %p has invalid status %d", p_picture, p_picture->i_status ); - break; -#endif - } + p_pic->p_next = NULL; + picture_fifo_Push(p_vout->p->decoder_fifo, p_pic); -#ifdef TRACE_VOUT - intf_DbgMsg("picture %p, display date: %s", p_picture, mstrtime( psz_date, p_picture->date) ); -#endif - vlc_mutex_unlock( &p_vout->picture_lock ); + vlc_mutex_unlock( &p_vout->p->picture_lock ); + + vout_control_Wake( &p_vout->p->control); } -/***************************************************************************** - * vout_CreatePicture: allocate a picture in the video output heap. - ***************************************************************************** - * This function creates a reserved image in the video output heap. - * A null pointer is returned if the function fails. This method provides an - * already allocated zone of memory in the picture data fields. It needs locking - * since several pictures can be created by several producers threads. - *****************************************************************************/ -picture_t *vout_CreatePicture( vout_thread_t *p_vout, - boolean_t b_progressive, - boolean_t b_top_field_first, - boolean_t b_repeat_first_field ) +/** + * It releases a picture retreived by vout_GetPicture. + */ +void vout_ReleasePicture( vout_thread_t *p_vout, picture_t *p_pic ) { - int i_picture; /* picture index */ - picture_t * p_picture; - picture_t * p_free_picture = NULL; /* first free picture */ - - /* Get lock */ - vlc_mutex_lock( &p_vout->picture_lock ); - - /* - * Look for an empty place. We start at 1 because the first - * directbuffer is reserved for memcpy()ed pictures. - */ - for( i_picture = 0; - i_picture < I_RENDERPICTURES && p_free_picture == NULL; - i_picture++ ) - { - p_picture = PP_RENDERPICTURE[ i_picture ]; - - /* If the picture we found is a memory buffer, and we might have - * enough room later for a direct buffer, skip it. If no other - * pictures are found, the video decoder will try again later. */ - if( p_vout->b_direct && ( p_vout->output.i_pictures > 3 ) - && ( p_picture->i_type != DIRECT_PICTURE ) ) - { - break; - } + vlc_mutex_lock( &p_vout->p->picture_lock ); - switch( p_picture->i_status ) - { - case DESTROYED_PICTURE: - /* Memory will not be reallocated, and function can end - * immediately - this is the best possible case, since no - * memory allocation needs to be done */ - p_picture->i_status = RESERVED_PICTURE; - p_picture->i_refcount = 0; + picture_Release( p_pic ); - p_picture->b_progressive = b_progressive; - p_picture->b_repeat_first_field = b_repeat_first_field; - p_picture->b_top_field_first = b_top_field_first; + vlc_mutex_unlock( &p_vout->p->picture_lock ); - p_vout->i_heap_size++; + vout_control_Wake( &p_vout->p->control); +} - vlc_mutex_unlock( &p_vout->picture_lock ); - return( p_picture ); +/** + * It increment the reference counter of a picture retreived by + * vout_GetPicture. + */ +void vout_HoldPicture( vout_thread_t *p_vout, picture_t *p_pic ) +{ + vlc_mutex_lock( &p_vout->p->picture_lock ); - case FREE_PICTURE: - /* Picture is empty and ready for allocation */ - p_free_picture = p_picture; - break; + picture_Hold( p_pic ); - default: - break; - } - } + vlc_mutex_unlock( &p_vout->p->picture_lock ); +} - /* - * Prepare picture - */ - if( p_free_picture != NULL ) +/** + * Allocate a new picture in the heap. + * + * This function allocates a fake direct buffer in memory, which can be + * used exactly like a video buffer. The video output thread then manages + * how it gets displayed. + */ +static int vout_AllocatePicture( picture_t *p_pic, + vlc_fourcc_t i_chroma, + int i_width, int i_height, + int i_sar_num, int i_sar_den ) +{ + /* Make sure the real dimensions are a multiple of 16 */ + if( picture_Setup( p_pic, i_chroma, i_width, i_height, + i_sar_num, i_sar_den ) != VLC_SUCCESS ) + return VLC_EGENERIC; + + /* Calculate how big the new image should be */ + size_t i_bytes = 0; + for( int i = 0; i < p_pic->i_planes; i++ ) { - NewPicture( p_vout, p_free_picture ); - - if( p_free_picture->i_planes ) - { - /* Copy picture information, set some default values */ - p_free_picture->i_status = RESERVED_PICTURE; - p_free_picture->i_refcount = 0; - - p_free_picture->b_progressive = b_progressive; - p_free_picture->b_repeat_first_field = b_repeat_first_field; - p_free_picture->b_top_field_first = b_top_field_first; - - p_free_picture->i_matrix_coefficients = 1; + const plane_t *p = &p_pic->p[i]; - p_vout->i_heap_size++; - } - else + if( p->i_pitch <= 0 || p->i_lines <= 0 || + p->i_pitch > (SIZE_MAX - i_bytes)/p->i_lines ) { - /* Memory allocation failed : set picture as empty */ - p_free_picture->i_status = FREE_PICTURE; - p_free_picture = NULL; - - intf_ErrMsg( "vout error: picture allocation failed" ); + p_pic->i_planes = 0; + return VLC_ENOMEM; } + i_bytes += p->i_pitch * p->i_lines; + } - vlc_mutex_unlock( &p_vout->picture_lock ); - - /* Initialize mutex */ - vlc_mutex_init( &(p_free_picture->lock_deccount) ); - - return( p_free_picture ); + uint8_t *p_data = vlc_memalign( &p_pic->p_data_orig, 16, i_bytes ); + if( !p_data ) + { + p_pic->i_planes = 0; + return VLC_EGENERIC; } - /* No free or destroyed picture could be found, but the decoder - * will try again in a while. */ - vlc_mutex_unlock( &p_vout->picture_lock ); + /* Fill the p_pixels field for each plane */ + p_pic->p[0].p_pixels = p_data; + for( int i = 1; i < p_pic->i_planes; i++ ) + { + p_pic->p[i].p_pixels = &p_pic->p[i-1].p_pixels[ p_pic->p[i-1].i_lines * + p_pic->p[i-1].i_pitch ]; + } - return( NULL ); + return VLC_SUCCESS; } /***************************************************************************** - * vout_DestroyPicture: remove a permanent or reserved picture from the heap - ***************************************************************************** - * This function frees a previously reserved picture or a permanent - * picture. It is meant to be used when the construction of a picture aborted. - * Note that the picture will be destroyed even if it is linked ! + * *****************************************************************************/ -void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_picture ) +static void PictureReleaseCallback( picture_t *p_picture ) { - vlc_mutex_lock( &p_vout->picture_lock ); - -#ifdef DEBUG - /* Check if picture status is valid */ - if( (p_picture->i_status != RESERVED_PICTURE) && - (p_picture->i_status != RESERVED_DATED_PICTURE) && - (p_picture->i_status != RESERVED_DISP_PICTURE) ) - { - intf_ErrMsg( "error: picture %p has invalid status %d", - p_picture, p_picture->i_status ); - } -#endif - - p_picture->i_status = DESTROYED_PICTURE; - p_vout->i_heap_size--; - - /* destroy the lock that had been initialized in CreatePicture */ - vlc_mutex_destroy( &(p_picture->lock_deccount) ); - - vlc_mutex_unlock( &p_vout->picture_lock ); + if( --p_picture->i_refcount > 0 ) + return; + picture_Delete( p_picture ); } /***************************************************************************** - * vout_LinkPicture: increment reference counter of a picture - ***************************************************************************** - * This function increments the reference counter of a picture in the video - * heap. It needs a lock since several producer threads can access the picture. + * *****************************************************************************/ -void vout_LinkPicture( vout_thread_t *p_vout, picture_t *p_picture ) +void picture_Reset( picture_t *p_picture ) { - vlc_mutex_lock( &p_vout->picture_lock ); - p_picture->i_refcount++; - -#ifdef TRACE_VOUT - intf_DbgMsg( "picture %p refcount=%d", p_picture, p_picture->i_refcount ); -#endif - - vlc_mutex_unlock( &p_vout->picture_lock ); + /* */ + p_picture->date = VLC_TS_INVALID; + p_picture->b_force = false; + p_picture->b_progressive = false; + p_picture->i_nb_fields = 0; + p_picture->b_top_field_first = false; + picture_CleanupQuant( p_picture ); } /***************************************************************************** - * vout_UnlinkPicture: decrement reference counter of a picture - ***************************************************************************** - * This function decrement the reference counter of a picture in the video heap. + * *****************************************************************************/ -void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_picture ) +static int LCM( int a, int b ) { - vlc_mutex_lock( &p_vout->picture_lock ); - p_picture->i_refcount--; + return a * b / GCD( a, b ); +} -#ifdef TRACE_VOUT - if( p_picture->i_refcount < 0 ) +int picture_Setup( picture_t *p_picture, vlc_fourcc_t i_chroma, + int i_width, int i_height, int i_sar_num, int i_sar_den ) +{ + /* Store default values */ + p_picture->i_planes = 0; + for( unsigned i = 0; i < VOUT_MAX_PLANES; i++ ) { - intf_DbgMsg( "error: refcount < 0" ); - p_picture->i_refcount = 0; + plane_t *p = &p_picture->p[i]; + p->p_pixels = NULL; + p->i_pixel_pitch = 0; } -#endif - if( ( p_picture->i_refcount == 0 ) && - ( p_picture->i_status == DISPLAYED_PICTURE ) ) + p_picture->pf_release = NULL; + p_picture->p_release_sys = NULL; + p_picture->i_refcount = 0; + + p_picture->i_qtype = QTYPE_NONE; + p_picture->i_qstride = 0; + p_picture->p_q = NULL; + + video_format_Setup( &p_picture->format, i_chroma, i_width, i_height, + i_sar_num, i_sar_den ); + + const vlc_chroma_description_t *p_dsc = + vlc_fourcc_GetChromaDescription( p_picture->format.i_chroma ); + if( !p_dsc ) + return VLC_EGENERIC; + + /* We want V (width/height) to respect: + (V * p_dsc->p[i].w.i_num) % p_dsc->p[i].w.i_den == 0 + (V * p_dsc->p[i].w.i_num/p_dsc->p[i].w.i_den * p_dsc->i_pixel_size) % 16 == 0 + Which is respected if you have + V % lcm( p_dsc->p[0..planes].w.i_den * 16) == 0 + */ + int i_modulo_w = 1; + int i_modulo_h = 1; + int i_ratio_h = 1; + for( unsigned i = 0; i < p_dsc->plane_count; i++ ) { - p_picture->i_status = DESTROYED_PICTURE; - p_vout->i_heap_size--; + i_modulo_w = LCM( i_modulo_w, 16 * p_dsc->p[i].w.den ); + i_modulo_h = LCM( i_modulo_h, 16 * p_dsc->p[i].h.den ); + if( i_ratio_h < p_dsc->p[i].h.den ) + i_ratio_h = p_dsc->p[i].h.den; } -#ifdef TRACE_VOUT - intf_DbgMsg( "picture %p refcount=%d", p_picture, p_picture->i_refcount ); -#endif + const int i_width_aligned = ( i_width + i_modulo_w - 1 ) / i_modulo_w * i_modulo_w; + const int i_height_aligned = ( i_height + i_modulo_h - 1 ) / i_modulo_h * i_modulo_h; + const int i_height_extra = 2 * i_ratio_h; /* This one is a hack for some ASM functions */ + for( unsigned i = 0; i < p_dsc->plane_count; i++ ) + { + plane_t *p = &p_picture->p[i]; + + p->i_lines = (i_height_aligned + i_height_extra ) * p_dsc->p[i].h.num / p_dsc->p[i].h.den; + p->i_visible_lines = i_height * p_dsc->p[i].h.num / p_dsc->p[i].h.den; + p->i_pitch = i_width_aligned * p_dsc->p[i].w.num / p_dsc->p[i].w.den * p_dsc->pixel_size; + p->i_visible_pitch = i_width * p_dsc->p[i].w.num / p_dsc->p[i].w.den * p_dsc->pixel_size; + p->i_pixel_pitch = p_dsc->pixel_size; - vlc_mutex_unlock( &p_vout->picture_lock ); + assert( (p->i_pitch % 16) == 0 ); + } + p_picture->i_planes = p_dsc->plane_count; + + return VLC_SUCCESS; } /***************************************************************************** - * vout_RenderPicture: render a picture - ***************************************************************************** - * This function chooses whether the current picture needs to be copied - * before rendering, does the subpicture magic, and tells the video output - * thread which direct buffer needs to be displayed. + * *****************************************************************************/ -picture_t * vout_RenderPicture( vout_thread_t *p_vout, picture_t *p_picture, - subpicture_t *p_subpic ) +picture_t *picture_NewFromResource( const video_format_t *p_fmt, const picture_resource_t *p_resource ) { - int i_index; + video_format_t fmt = *p_fmt; - if( p_picture == NULL ) - { - /* XXX: subtitles */ + /* It is needed to be sure all information are filled */ + video_format_Setup( &fmt, p_fmt->i_chroma, + p_fmt->i_width, p_fmt->i_height, + p_fmt->i_sar_num, p_fmt->i_sar_den ); + /* */ + picture_t *p_picture = calloc( 1, sizeof(*p_picture) ); + if( !p_picture ) return NULL; - } - if( p_picture->i_type == DIRECT_PICTURE ) + if( p_resource ) { - if( p_picture->i_refcount ) + if( picture_Setup( p_picture, fmt.i_chroma, fmt.i_width, fmt.i_height, + fmt.i_sar_num, fmt.i_sar_den ) ) { - /* Picture is in a direct buffer and is still in use, - * we need to copy it to another direct buffer before - * displaying it if there are subtitles. */ - if( p_subpic != NULL ) - { - //printf("memcpy (refcount != 0)\n"); - /* We have subtitles. First copy the picture to - * the spare direct buffer, then render the - * subtitles. */ - for( i_index = 0 ; i_index < p_picture->i_planes ; i_index++ ) - { - p_main->fast_memcpy( - PP_OUTPUTPICTURE[0]->planes[ i_index ].p_data, - p_picture->planes[ i_index ].p_data, - p_picture->planes[ i_index ].i_bytes ); - } - - vout_RenderSubPictures( p_vout, PP_OUTPUTPICTURE[0], p_subpic ); - - return PP_OUTPUTPICTURE[0]; - } - - /* No subtitles, picture is in a directbuffer so - * we can display it directly even if it is still - * in use. */ - //printf("direct (refcount == 0)\n"); - return p_picture; + free( p_picture ); + return NULL; } + p_picture->p_sys = p_resource->p_sys; - /* Picture is in a direct buffer but isn't used by the - * decoder. We can safely render subtitles on it and - * display it. */ - //printf("direct (refcount == 0)\n"); - vout_RenderSubPictures( p_vout, p_picture, p_subpic ); - - return p_picture; + for( int i = 0; i < p_picture->i_planes; i++ ) + { + p_picture->p[i].p_pixels = p_resource->p[i].p_pixels; + p_picture->p[i].i_lines = p_resource->p[i].i_lines; + p_picture->p[i].i_pitch = p_resource->p[i].i_pitch; + } } - - /* Not a direct buffer. We either need to copy it to a direct buffer, - * or render it if the chroma isn't the same. */ - if( p_vout->b_direct ) + else { - /* Picture is not in a direct buffer, but is exactly the - * same size as the direct buffers. A memcpy() is enough, - * then render the subtitles. */ - //printf("memcpy (not a direct buffer)\n"); - for( i_index = 0; i_index < p_picture->i_planes; i_index++ ) + if( vout_AllocatePicture( p_picture, + fmt.i_chroma, fmt.i_width, fmt.i_height, + fmt.i_sar_num, fmt.i_sar_den ) ) { - p_main->fast_memcpy( PP_OUTPUTPICTURE[0]->planes[ i_index ].p_data, - p_picture->planes[ i_index ].p_data, - p_picture->planes[ i_index ].i_bytes ); + free( p_picture ); + return NULL; } - - vout_RenderSubPictures( p_vout, PP_OUTPUTPICTURE[0], p_subpic ); - - return PP_OUTPUTPICTURE[0]; } + /* */ + p_picture->format = fmt; + p_picture->i_refcount = 1; + p_picture->pf_release = PictureReleaseCallback; - /* Picture is not in a direct buffer, and needs to be converted to - * another size/chroma. Then the subtitles need to be rendered as - * well. */ + return p_picture; +} +picture_t *picture_NewFromFormat( const video_format_t *p_fmt ) +{ + return picture_NewFromResource( p_fmt, NULL ); +} +picture_t *picture_New( vlc_fourcc_t i_chroma, int i_width, int i_height, int i_sar_num, int i_sar_den ) +{ + video_format_t fmt; - /* This usually means software YUV, or hardware YUV with a - * different chroma. */ + memset( &fmt, 0, sizeof(fmt) ); + video_format_Setup( &fmt, i_chroma, i_width, i_height, + i_sar_num, i_sar_den ); - //printf("render (not a direct buffer)\n"); - /* XXX: render to direct buffer */ + return picture_NewFromFormat( &fmt ); +} - vout_RenderSubPictures( p_vout, p_picture, p_subpic ); +/***************************************************************************** + * + *****************************************************************************/ +void picture_Delete( picture_t *p_picture ) +{ + assert( p_picture && p_picture->i_refcount == 0 ); + assert( p_picture->p_release_sys == NULL ); - return &p_vout->p_picture[0]; + free( p_picture->p_q ); + free( p_picture->p_data_orig ); + free( p_picture->p_sys ); + free( p_picture ); } /***************************************************************************** - * vout_PlacePicture: calculate image window coordinates - ***************************************************************************** - * This function will be accessed by plugins. It calculates the relative - * position of the output window and the image window. + * *****************************************************************************/ -void vout_PlacePicture( vout_thread_t *p_vout, int i_width, int i_height, - int *pi_x, int *pi_y, int *pi_width, int *pi_height ) +void picture_CopyPixels( picture_t *p_dst, const picture_t *p_src ) { - if( p_vout->b_scale ) + int i; + + for( i = 0; i < p_src->i_planes ; i++ ) + plane_CopyPixels( p_dst->p+i, p_src->p+i ); +} + +void plane_CopyPixels( plane_t *p_dst, const plane_t *p_src ) +{ + const unsigned i_width = __MIN( p_dst->i_visible_pitch, + p_src->i_visible_pitch ); + const unsigned i_height = __MIN( p_dst->i_visible_lines, + p_src->i_visible_lines ); + + if( p_src->i_pitch == p_dst->i_pitch ) { - *pi_width = i_width; - *pi_height = i_height; + /* There are margins, but with the same width : perfect ! */ + vlc_memcpy( p_dst->p_pixels, p_src->p_pixels, + p_src->i_pitch * i_height ); } else { - *pi_width = MIN( i_width, p_vout->render.i_width ); - *pi_height = MIN( i_height, p_vout->render.i_height ); + /* We need to proceed line by line */ + uint8_t *p_in = p_src->p_pixels; + uint8_t *p_out = p_dst->p_pixels; + int i_line; + + assert( p_in ); + assert( p_out ); + + for( i_line = i_height; i_line--; ) + { + vlc_memcpy( p_out, p_in, i_width ); + p_in += p_src->i_pitch; + p_out += p_dst->i_pitch; + } + } +} + +/***************************************************************************** + * + *****************************************************************************/ +int picture_Export( vlc_object_t *p_obj, + block_t **pp_image, + video_format_t *p_fmt, + picture_t *p_picture, + vlc_fourcc_t i_format, + int i_override_width, int i_override_height ) +{ + /* */ + video_format_t fmt_in = p_picture->format; + if( fmt_in.i_sar_num <= 0 || fmt_in.i_sar_den <= 0 ) + { + fmt_in.i_sar_num = + fmt_in.i_sar_den = 1; } - if( VOUT_ASPECT_FACTOR * *pi_width / *pi_height < p_vout->render.i_aspect ) + /* */ + video_format_t fmt_out; + memset( &fmt_out, 0, sizeof(fmt_out) ); + fmt_out.i_sar_num = + fmt_out.i_sar_den = 1; + fmt_out.i_chroma = i_format; + + /* compute original width/height */ + unsigned int i_original_width; + unsigned int i_original_height; + if( fmt_in.i_sar_num >= fmt_in.i_sar_den ) { - *pi_width = *pi_height * p_vout->render.i_aspect / VOUT_ASPECT_FACTOR; + i_original_width = fmt_in.i_width * fmt_in.i_sar_num / fmt_in.i_sar_den; + i_original_height = fmt_in.i_height; } else { - *pi_height = *pi_width * VOUT_ASPECT_FACTOR / p_vout->render.i_aspect; + i_original_width = fmt_in.i_width; + i_original_height = fmt_in.i_height * fmt_in.i_sar_den / fmt_in.i_sar_num; } - if( *pi_width > i_width ) + /* */ + fmt_out.i_width = ( i_override_width < 0 ) ? + i_original_width : i_override_width; + fmt_out.i_height = ( i_override_height < 0 ) ? + i_original_height : i_override_height; + + /* scale if only one direction is provided */ + if( fmt_out.i_height == 0 && fmt_out.i_width > 0 ) { - *pi_width = i_width; - *pi_height = VOUT_ASPECT_FACTOR * *pi_width / p_vout->render.i_aspect; + fmt_out.i_height = fmt_in.i_height * fmt_out.i_width + * fmt_in.i_sar_den / fmt_in.i_width / fmt_in.i_sar_num; } - - if( *pi_height > i_height ) + else if( fmt_out.i_width == 0 && fmt_out.i_height > 0 ) { - *pi_height = i_height; - *pi_width = *pi_height * p_vout->render.i_aspect / VOUT_ASPECT_FACTOR; + fmt_out.i_width = fmt_in.i_width * fmt_out.i_height + * fmt_in.i_sar_num / fmt_in.i_height / fmt_in.i_sar_den; } - *pi_x = ( i_width - *pi_width ) / 2; - *pi_y = ( i_height - *pi_height ) / 2; -} + image_handler_t *p_image = image_HandlerCreate( p_obj ); -/* Following functions are local */ + block_t *p_block = image_Write( p_image, p_picture, &fmt_in, &fmt_out ); -/***************************************************************************** - * NewPicture: allocate a new picture in the heap. - ***************************************************************************** - * This function allocates a fake direct buffer in memory, which can be - * used exactly like a video buffer. The video output thread then manages - * how it gets displayed. - *****************************************************************************/ -static void NewPicture( vout_thread_t *p_vout, picture_t *p_picture ) -{ - int i_data_size = 0; + image_HandlerDelete( p_image ); - p_picture->i_size = p_vout->render.i_width - * p_vout->render.i_height; + if( !p_block ) + return VLC_EGENERIC; - /* Calculate coordinates */ - switch( p_vout->render.i_chroma ) - { - case YUV_420_PICTURE: /* YUV 420: 1,1/4,1/4 samples per pixel */ - p_picture->i_chroma_size = p_picture->i_size / 4; - p_picture->i_chroma_width = p_vout->render.i_width / 2; - break; - - case YUV_422_PICTURE: /* YUV 422: 1,1/2,1/2 samples per pixel */ - p_picture->i_chroma_size = p_picture->i_size / 2; - p_picture->i_chroma_width = p_vout->render.i_width / 2; - break; - - case YUV_444_PICTURE: /* YUV 444: 1,1,1 samples per pixel */ - p_picture->i_chroma_size = p_picture->i_size; - p_picture->i_chroma_width = p_vout->render.i_width; - break; - - default: - intf_ErrMsg( "vout error: unknown chroma type %d", - p_vout->render.i_chroma ); - p_picture->i_planes = 0; - return; - } + p_block->i_pts = + p_block->i_dts = p_picture->date; - p_picture->i_type = MEMORY_PICTURE; + if( p_fmt ) + *p_fmt = fmt_out; + *pp_image = p_block; - /* Allocate memory */ - switch( p_vout->render.i_chroma ) - { - case YUV_420_PICTURE: /* YUV 420: 1,1/4,1/4 samples per pixel */ - case YUV_422_PICTURE: /* YUV 422: 1,1/2,1/2 samples per pixel */ - case YUV_444_PICTURE: /* YUV 444: 1,1,1 samples per pixel */ - - i_data_size = p_picture->i_size + 2 * p_picture->i_chroma_size; - - /* The Y plane */ - p_picture->planes[ Y_PLANE ].i_bytes = - p_picture->i_size * sizeof(pixel_data_t); - p_picture->planes[ Y_PLANE ].i_line_bytes = - p_vout->render.i_width * sizeof(pixel_data_t); - p_picture->planes[ Y_PLANE ].p_data = - memalign( 16, i_data_size * sizeof(pixel_data_t) * 4 ); - /* The U plane */ - p_picture->planes[ U_PLANE ].i_bytes = - p_picture->i_chroma_size * sizeof(pixel_data_t); - p_picture->planes[ U_PLANE ].i_line_bytes = - p_picture->i_chroma_width * sizeof(pixel_data_t); - p_picture->planes[ U_PLANE ].p_data = - p_picture->planes[ Y_PLANE ].p_data + p_picture->i_size; - /* The V plane */ - p_picture->planes[ V_PLANE ].i_bytes = - p_picture->i_chroma_size * sizeof(pixel_data_t); - p_picture->planes[ V_PLANE ].i_line_bytes = - p_picture->i_chroma_width * sizeof(pixel_data_t); - p_picture->planes[ V_PLANE ].p_data = - p_picture->planes[ U_PLANE ].p_data + p_picture->i_chroma_size; - - p_picture->i_planes = 3; - - break; - - default: - p_picture->i_planes = 0; - - break; - } + return VLC_SUCCESS; }