sout: sdi: fix channels to pairs setup
[vlc.git] / src / misc / picture.c
blobf61e0a3d0ef3b04d420198e0892fcc7176ea02be
1 /*****************************************************************************
2 * picture.c : picture management functions
3 *****************************************************************************
4 * Copyright (C) 2000-2010 VLC authors and VideoLAN
5 * Copyright (C) 2009-2010 Laurent Aimar
6 * $Id$
8 * Authors: Vincent Seguin <seguin@via.ecp.fr>
9 * Samuel Hocevar <sam@zoy.org>
10 * Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU Lesser General Public License as published by
14 * the Free Software Foundation; either version 2.1 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public License
23 * along with this program; if not, write to the Free Software Foundation,
24 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25 *****************************************************************************/
27 /*****************************************************************************
28 * Preamble
29 *****************************************************************************/
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34 #include <assert.h>
35 #include <limits.h>
37 #include <vlc_common.h>
38 #include "picture.h"
39 #include <vlc_image.h>
40 #include <vlc_block.h>
42 static void PictureDestroyContext( picture_t *p_picture )
44 picture_context_t *ctx = p_picture->context;
45 if (ctx != NULL)
47 ctx->destroy(ctx);
48 p_picture->context = NULL;
52 /**
53 * Destroys a picture allocated by picture_NewFromResource() but without
54 * a custom destruction callback.
56 static void picture_DestroyFromResource( picture_t *p_picture )
58 free( p_picture->p_sys );
59 free( p_picture );
62 /**
63 * Destroys a picture allocated with picture_NewFromFormat().
65 static void picture_Destroy( picture_t *p_picture )
67 aligned_free( p_picture->p[0].p_pixels );
68 free( p_picture );
71 /*****************************************************************************
73 *****************************************************************************/
74 void picture_Reset( picture_t *p_picture )
76 /* */
77 p_picture->date = VLC_TICK_INVALID;
78 p_picture->b_force = false;
79 p_picture->b_progressive = false;
80 p_picture->i_nb_fields = 2;
81 p_picture->b_top_field_first = false;
82 PictureDestroyContext( p_picture );
85 /*****************************************************************************
87 *****************************************************************************/
88 static int LCM( int a, int b )
90 return a * b / GCD( a, b );
93 int picture_Setup( picture_t *p_picture, const video_format_t *restrict fmt )
95 const vlc_chroma_description_t *p_dsc =
96 vlc_fourcc_GetChromaDescription( fmt->i_chroma );
97 if( unlikely(!p_dsc) )
98 return VLC_EGENERIC;
100 /* Store default values */
101 p_picture->i_planes = 0;
102 for( unsigned i = 0; i < VOUT_MAX_PLANES; i++ )
104 plane_t *p = &p_picture->p[i];
105 p->p_pixels = NULL;
106 p->i_pixel_pitch = 0;
109 p_picture->i_nb_fields = 2;
111 video_format_Setup( &p_picture->format, fmt->i_chroma, fmt->i_width, fmt->i_height,
112 fmt->i_visible_width, fmt->i_visible_height,
113 fmt->i_sar_num, fmt->i_sar_den );
114 if( fmt->i_x_offset < fmt->i_width &&
115 fmt->i_y_offset < fmt->i_height &&
116 fmt->i_visible_width > 0 && fmt->i_x_offset + fmt->i_visible_width <= fmt->i_width &&
117 fmt->i_visible_height > 0 && fmt->i_y_offset + fmt->i_visible_height <= fmt->i_height )
118 video_format_CopyCrop( &p_picture->format, fmt );
120 /* We want V (width/height) to respect:
121 (V * p_dsc->p[i].w.i_num) % p_dsc->p[i].w.i_den == 0
122 (V * p_dsc->p[i].w.i_num/p_dsc->p[i].w.i_den * p_dsc->i_pixel_size) % 16 == 0
123 Which is respected if you have
124 V % lcm( p_dsc->p[0..planes].w.i_den * 16) == 0
126 unsigned i_modulo_w = 1;
127 unsigned i_modulo_h = 1;
128 unsigned i_ratio_h = 1;
130 for( unsigned i = 0; i < p_dsc->plane_count; i++ )
132 i_modulo_w = LCM( i_modulo_w, 16 * p_dsc->p[i].w.den );
133 i_modulo_h = LCM( i_modulo_h, 16 * p_dsc->p[i].h.den );
134 if( i_ratio_h < p_dsc->p[i].h.den )
135 i_ratio_h = p_dsc->p[i].h.den;
137 i_modulo_h = LCM( i_modulo_h, 32 );
139 unsigned width, height;
141 if (unlikely(add_overflow(fmt->i_width, i_modulo_w - 1, &width))
142 || unlikely(add_overflow(fmt->i_height, i_modulo_h - 1, &height)))
143 return VLC_EGENERIC;
145 width = width / i_modulo_w * i_modulo_w;
146 height = height / i_modulo_h * i_modulo_h;
148 /* plane_t uses 'int'. */
149 if (unlikely(width > INT_MAX) || unlikely(height > INT_MAX))
150 return VLC_EGENERIC;
152 for( unsigned i = 0; i < p_dsc->plane_count; i++ )
154 plane_t *p = &p_picture->p[i];
155 const vlc_rational_t *h = &p_dsc->p[i].h;
156 const vlc_rational_t *w = &p_dsc->p[i].w;
158 /* A plane cannot be over-sampled. This could lead to overflow. */
159 assert(h->den >= h->num);
160 assert(w->den >= w->num);
162 p->i_lines = height * h->num / h->den;
163 p->i_visible_lines = (fmt->i_visible_height + (h->den - 1)) / h->den * h->num;
165 p->i_pitch = width * w->num / w->den * p_dsc->pixel_size;
166 p->i_visible_pitch = (fmt->i_visible_width + (w->den - 1)) / w->den * w->num
167 * p_dsc->pixel_size;
168 p->i_pixel_pitch = p_dsc->pixel_size;
170 assert( (p->i_pitch % 16) == 0 );
172 p_picture->i_planes = p_dsc->plane_count;
174 return VLC_SUCCESS;
177 /*****************************************************************************
179 *****************************************************************************/
181 static picture_priv_t *picture_NewPrivate(const video_format_t *restrict p_fmt)
183 /* */
184 picture_priv_t *priv = malloc( sizeof (*priv) );
185 if( unlikely(priv == NULL) )
186 return NULL;
188 picture_t *p_picture = &priv->picture;
190 memset( p_picture, 0, sizeof( *p_picture ) );
192 p_picture->format = *p_fmt;
193 /* Make sure the real dimensions are a multiple of 16 */
194 if( picture_Setup( p_picture, p_fmt ) )
196 free( p_picture );
197 return NULL;
200 atomic_init( &priv->gc.refs, 1 );
201 priv->gc.opaque = NULL;
203 return priv;
206 picture_t *picture_NewFromResource( const video_format_t *p_fmt, const picture_resource_t *p_resource )
208 assert(p_resource != NULL);
210 picture_priv_t *priv = picture_NewPrivate(p_fmt);
211 if (unlikely(priv == NULL))
212 return NULL;
214 picture_t *p_picture = &priv->picture;
216 p_picture->p_sys = p_resource->p_sys;
218 if( p_resource->pf_destroy != NULL )
219 priv->gc.destroy = p_resource->pf_destroy;
220 else
221 priv->gc.destroy = picture_DestroyFromResource;
223 for( int i = 0; i < p_picture->i_planes; i++ )
225 p_picture->p[i].p_pixels = p_resource->p[i].p_pixels;
226 p_picture->p[i].i_lines = p_resource->p[i].i_lines;
227 p_picture->p[i].i_pitch = p_resource->p[i].i_pitch;
230 return p_picture;
233 #define PICTURE_SW_SIZE_MAX (UINT32_C(1) << 28) /* 256MB: 8K * 8K * 4*/
235 picture_t *picture_NewFromFormat(const video_format_t *restrict fmt)
237 picture_priv_t *priv = picture_NewPrivate(fmt);
238 if (unlikely(priv == NULL))
239 return NULL;
241 priv->gc.destroy = picture_Destroy;
243 picture_t *pic = &priv->picture;
244 if (pic->i_planes == 0)
245 return pic;
247 /* Calculate how big the new image should be */
248 size_t plane_sizes[PICTURE_PLANE_MAX];
249 size_t pic_size = 0;
251 for (int i = 0; i < pic->i_planes; i++)
253 const plane_t *p = &pic->p[i];
255 if (unlikely(mul_overflow(p->i_pitch, p->i_lines, &plane_sizes[i]))
256 || unlikely(add_overflow(pic_size, plane_sizes[i], &pic_size)))
257 goto error;
260 if (unlikely(pic_size >= PICTURE_SW_SIZE_MAX))
261 goto error;
263 uint8_t *buf = aligned_alloc(16, pic_size);
264 if (unlikely(buf == NULL))
265 goto error;
267 /* Fill the p_pixels field for each plane */
268 for (int i = 0; i < pic->i_planes; i++)
270 pic->p[i].p_pixels = buf;
271 buf += plane_sizes[i];
274 return pic;
275 error:
276 free(pic);
277 return NULL;
280 picture_t *picture_New( vlc_fourcc_t i_chroma, int i_width, int i_height, int i_sar_num, int i_sar_den )
282 video_format_t fmt;
284 video_format_Init( &fmt, 0 );
285 video_format_Setup( &fmt, i_chroma, i_width, i_height,
286 i_width, i_height, i_sar_num, i_sar_den );
288 return picture_NewFromFormat( &fmt );
291 /*****************************************************************************
293 *****************************************************************************/
295 picture_t *picture_Hold( picture_t *p_picture )
297 assert( p_picture != NULL );
299 picture_priv_t *priv = (picture_priv_t *)p_picture;
300 uintptr_t refs = atomic_fetch_add( &priv->gc.refs, 1 );
301 assert( refs > 0 );
302 return p_picture;
305 void picture_Release( picture_t *p_picture )
307 assert( p_picture != NULL );
309 picture_priv_t *priv = (picture_priv_t *)p_picture;
310 uintptr_t refs = atomic_fetch_sub( &priv->gc.refs, 1 );
311 assert( refs != 0 );
312 if( refs > 1 )
313 return;
315 PictureDestroyContext( p_picture );
316 assert( priv->gc.destroy != NULL );
317 priv->gc.destroy( p_picture );
320 /*****************************************************************************
322 *****************************************************************************/
323 void plane_CopyPixels( plane_t *p_dst, const plane_t *p_src )
325 const unsigned i_width = __MIN( p_dst->i_visible_pitch,
326 p_src->i_visible_pitch );
327 const unsigned i_height = __MIN( p_dst->i_visible_lines,
328 p_src->i_visible_lines );
330 /* The 2x visible pitch check does two things:
331 1) Makes field plane_t's work correctly (see the deinterlacer module)
332 2) Moves less data if the pitch and visible pitch differ much.
334 if( p_src->i_pitch == p_dst->i_pitch &&
335 p_src->i_pitch < 2*p_src->i_visible_pitch )
337 /* There are margins, but with the same width : perfect ! */
338 memcpy( p_dst->p_pixels, p_src->p_pixels,
339 p_src->i_pitch * i_height );
341 else
343 /* We need to proceed line by line */
344 uint8_t *p_in = p_src->p_pixels;
345 uint8_t *p_out = p_dst->p_pixels;
347 assert( p_in );
348 assert( p_out );
350 for( int i_line = i_height; i_line--; )
352 memcpy( p_out, p_in, i_width );
353 p_in += p_src->i_pitch;
354 p_out += p_dst->i_pitch;
359 void picture_CopyProperties( picture_t *p_dst, const picture_t *p_src )
361 p_dst->date = p_src->date;
362 p_dst->b_force = p_src->b_force;
364 p_dst->b_progressive = p_src->b_progressive;
365 p_dst->i_nb_fields = p_src->i_nb_fields;
366 p_dst->b_top_field_first = p_src->b_top_field_first;
369 void picture_CopyPixels( picture_t *p_dst, const picture_t *p_src )
371 for( int i = 0; i < p_src->i_planes ; i++ )
372 plane_CopyPixels( p_dst->p+i, p_src->p+i );
374 assert( p_dst->context == NULL );
376 if( p_src->context != NULL )
377 p_dst->context = p_src->context->copy( p_src->context );
380 void picture_Copy( picture_t *p_dst, const picture_t *p_src )
382 picture_CopyPixels( p_dst, p_src );
383 picture_CopyProperties( p_dst, p_src );
386 static void picture_DestroyClone(picture_t *clone)
388 picture_t *picture = ((picture_priv_t *)clone)->gc.opaque;
390 free(clone);
391 picture_Release(picture);
394 picture_t *picture_Clone(picture_t *picture)
396 /* TODO: merge common code with picture_pool_ClonePicture(). */
397 picture_resource_t res = {
398 .p_sys = picture->p_sys,
399 .pf_destroy = picture_DestroyClone,
402 for (int i = 0; i < picture->i_planes; i++) {
403 res.p[i].p_pixels = picture->p[i].p_pixels;
404 res.p[i].i_lines = picture->p[i].i_lines;
405 res.p[i].i_pitch = picture->p[i].i_pitch;
408 picture_t *clone = picture_NewFromResource(&picture->format, &res);
409 if (likely(clone != NULL)) {
410 ((picture_priv_t *)clone)->gc.opaque = picture;
411 picture_Hold(picture);
413 if (picture->context != NULL)
414 clone->context = picture->context->copy(picture->context);
416 return clone;
419 /*****************************************************************************
421 *****************************************************************************/
422 int picture_Export( vlc_object_t *p_obj,
423 block_t **pp_image,
424 video_format_t *p_fmt,
425 picture_t *p_picture,
426 vlc_fourcc_t i_format,
427 int i_override_width, int i_override_height )
429 /* */
430 video_format_t fmt_in = p_picture->format;
431 if( fmt_in.i_sar_num <= 0 || fmt_in.i_sar_den <= 0 )
433 fmt_in.i_sar_num =
434 fmt_in.i_sar_den = 1;
437 /* */
438 video_format_t fmt_out;
439 memset( &fmt_out, 0, sizeof(fmt_out) );
440 fmt_out.i_sar_num =
441 fmt_out.i_sar_den = 1;
442 fmt_out.i_chroma = i_format;
444 /* compute original width/height */
445 unsigned int i_width, i_height, i_original_width, i_original_height;
446 if( fmt_in.i_visible_width > 0 && fmt_in.i_visible_height > 0 )
448 i_width = fmt_in.i_visible_width;
449 i_height = fmt_in.i_visible_height;
451 else
453 i_width = fmt_in.i_width;
454 i_height = fmt_in.i_height;
456 if( fmt_in.i_sar_num >= fmt_in.i_sar_den )
458 i_original_width = (int64_t)i_width * fmt_in.i_sar_num / fmt_in.i_sar_den;
459 i_original_height = i_height;
461 else
463 i_original_width = i_width;
464 i_original_height = i_height * fmt_in.i_sar_den / fmt_in.i_sar_num;
467 /* */
468 fmt_out.i_width = ( i_override_width < 0 ) ?
469 i_original_width : (unsigned)i_override_width;
470 fmt_out.i_height = ( i_override_height < 0 ) ?
471 i_original_height : (unsigned)i_override_height;
473 /* scale if only one direction is provided */
474 if( fmt_out.i_height == 0 && fmt_out.i_width > 0 )
476 fmt_out.i_height = i_height * fmt_out.i_width
477 * fmt_in.i_sar_den / fmt_in.i_width / fmt_in.i_sar_num;
479 else if( fmt_out.i_width == 0 && fmt_out.i_height > 0 )
481 fmt_out.i_width = i_width * fmt_out.i_height
482 * fmt_in.i_sar_num / fmt_in.i_height / fmt_in.i_sar_den;
485 image_handler_t *p_image = image_HandlerCreate( p_obj );
486 if( !p_image )
487 return VLC_ENOMEM;
489 block_t *p_block = image_Write( p_image, p_picture, &fmt_in, &fmt_out );
491 image_HandlerDelete( p_image );
493 if( !p_block )
494 return VLC_EGENERIC;
496 p_block->i_pts =
497 p_block->i_dts = p_picture->date;
499 if( p_fmt )
500 *p_fmt = fmt_out;
501 *pp_image = p_block;
503 return VLC_SUCCESS;