Fortunes about QT and "hearing" video codecs
[vlc.git] / src / misc / picture.c
blob569ff474e081a3ae206b2f18e7d80f16e72cbca6
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_DestroyDummy( picture_t *p_picture )
58 (void) p_picture;
61 /**
62 * Destroys a picture allocated with picture_NewFromFormat().
64 static void picture_DestroyFromFormat(picture_t *pic)
66 picture_buffer_t *res = pic->p_sys;
68 if (res != NULL)
69 picture_Deallocate(res->fd, res->base, res->size);
72 VLC_WEAK void *picture_Allocate(int *restrict fdp, size_t size)
74 assert((size % 64) == 0);
75 *fdp = -1;
76 return aligned_alloc(64, size);
79 VLC_WEAK void picture_Deallocate(int fd, void *base, size_t size)
81 assert(fd == -1);
82 aligned_free(base);
83 assert((size % 64) == 0);
86 /*****************************************************************************
88 *****************************************************************************/
89 void picture_Reset( picture_t *p_picture )
91 /* */
92 p_picture->date = VLC_TICK_INVALID;
93 p_picture->b_force = false;
94 p_picture->b_still = false;
95 p_picture->b_progressive = false;
96 p_picture->i_nb_fields = 2;
97 p_picture->b_top_field_first = false;
98 PictureDestroyContext( p_picture );
101 /*****************************************************************************
103 *****************************************************************************/
104 static int LCM( int a, int b )
106 return a * b / GCD( a, b );
109 int picture_Setup( picture_t *p_picture, const video_format_t *restrict fmt )
111 const vlc_chroma_description_t *p_dsc =
112 vlc_fourcc_GetChromaDescription( fmt->i_chroma );
113 if( unlikely(!p_dsc) )
114 return VLC_EGENERIC;
116 /* Store default values */
117 p_picture->i_planes = 0;
118 for( unsigned i = 0; i < VOUT_MAX_PLANES; i++ )
120 plane_t *p = &p_picture->p[i];
121 p->p_pixels = NULL;
122 p->i_pixel_pitch = 0;
125 p_picture->i_nb_fields = 2;
127 video_format_Setup( &p_picture->format, fmt->i_chroma, fmt->i_width, fmt->i_height,
128 fmt->i_visible_width, fmt->i_visible_height,
129 fmt->i_sar_num, fmt->i_sar_den );
130 if( fmt->i_x_offset < fmt->i_width &&
131 fmt->i_y_offset < fmt->i_height &&
132 fmt->i_visible_width > 0 && fmt->i_x_offset + fmt->i_visible_width <= fmt->i_width &&
133 fmt->i_visible_height > 0 && fmt->i_y_offset + fmt->i_visible_height <= fmt->i_height )
134 video_format_CopyCrop( &p_picture->format, fmt );
136 /* We want V (width/height) to respect:
137 (V * p_dsc->p[i].w.i_num) % p_dsc->p[i].w.i_den == 0
138 (V * p_dsc->p[i].w.i_num/p_dsc->p[i].w.i_den * p_dsc->i_pixel_size) % 16 == 0
139 Which is respected if you have
140 V % lcm( p_dsc->p[0..planes].w.i_den * 16) == 0
142 unsigned i_modulo_w = 1;
143 unsigned i_modulo_h = 1;
144 unsigned i_ratio_h = 1;
146 for( unsigned i = 0; i < p_dsc->plane_count; i++ )
148 i_modulo_w = LCM( i_modulo_w, 16 * p_dsc->p[i].w.den );
149 i_modulo_h = LCM( i_modulo_h, 16 * p_dsc->p[i].h.den );
150 if( i_ratio_h < p_dsc->p[i].h.den )
151 i_ratio_h = p_dsc->p[i].h.den;
153 i_modulo_h = LCM( i_modulo_h, 32 );
155 unsigned width, height;
157 if (unlikely(add_overflow(fmt->i_width, i_modulo_w - 1, &width))
158 || unlikely(add_overflow(fmt->i_height, i_modulo_h - 1, &height)))
159 return VLC_EGENERIC;
161 width = width / i_modulo_w * i_modulo_w;
162 height = height / i_modulo_h * i_modulo_h;
164 /* plane_t uses 'int'. */
165 if (unlikely(width > INT_MAX) || unlikely(height > INT_MAX))
166 return VLC_EGENERIC;
168 for( unsigned i = 0; i < p_dsc->plane_count; i++ )
170 plane_t *p = &p_picture->p[i];
171 const vlc_rational_t *h = &p_dsc->p[i].h;
172 const vlc_rational_t *w = &p_dsc->p[i].w;
174 /* A plane cannot be over-sampled. This could lead to overflow. */
175 assert(h->den >= h->num);
176 assert(w->den >= w->num);
178 p->i_lines = height * h->num / h->den;
179 p->i_visible_lines = (fmt->i_visible_height + (h->den - 1)) / h->den * h->num;
181 p->i_pitch = width * w->num / w->den * p_dsc->pixel_size;
182 p->i_visible_pitch = (fmt->i_visible_width + (w->den - 1)) / w->den * w->num
183 * p_dsc->pixel_size;
184 p->i_pixel_pitch = p_dsc->pixel_size;
186 assert( (p->i_pitch % 16) == 0 );
188 p_picture->i_planes = p_dsc->plane_count;
190 return VLC_SUCCESS;
193 /*****************************************************************************
195 *****************************************************************************/
197 static picture_priv_t *picture_NewPrivate(const video_format_t *restrict p_fmt,
198 size_t extra)
200 /* */
201 picture_priv_t *priv = malloc(sizeof (*priv) + extra);
202 if( unlikely(priv == NULL) )
203 return NULL;
205 picture_t *p_picture = &priv->picture;
207 memset( p_picture, 0, sizeof( *p_picture ) );
209 p_picture->format = *p_fmt;
210 /* Make sure the real dimensions are a multiple of 16 */
211 if( picture_Setup( p_picture, p_fmt ) )
213 free( p_picture );
214 return NULL;
217 atomic_init(&p_picture->refs, 1);
218 priv->gc.opaque = NULL;
220 return priv;
223 picture_t *picture_NewFromResource( const video_format_t *p_fmt, const picture_resource_t *p_resource )
225 assert(p_resource != NULL);
227 picture_priv_t *priv = picture_NewPrivate(p_fmt, 0);
228 if (unlikely(priv == NULL))
229 return NULL;
231 picture_t *p_picture = &priv->picture;
233 p_picture->p_sys = p_resource->p_sys;
235 if( p_resource->pf_destroy != NULL )
236 priv->gc.destroy = p_resource->pf_destroy;
237 else
238 priv->gc.destroy = picture_DestroyDummy;
240 for( int i = 0; i < p_picture->i_planes; i++ )
242 p_picture->p[i].p_pixels = p_resource->p[i].p_pixels;
243 p_picture->p[i].i_lines = p_resource->p[i].i_lines;
244 p_picture->p[i].i_pitch = p_resource->p[i].i_pitch;
247 return p_picture;
250 #define PICTURE_SW_SIZE_MAX (UINT32_C(1) << 28) /* 256MB: 8K * 8K * 4*/
252 picture_t *picture_NewFromFormat(const video_format_t *restrict fmt)
254 picture_priv_t *priv = picture_NewPrivate(fmt, sizeof (picture_buffer_t));
255 if (unlikely(priv == NULL))
256 return NULL;
258 priv->gc.destroy = picture_DestroyFromFormat;
260 picture_t *pic = &priv->picture;
261 if (pic->i_planes == 0) {
262 pic->p_sys = NULL;
263 return pic;
266 /* Calculate how big the new image should be */
267 size_t plane_sizes[PICTURE_PLANE_MAX];
268 size_t pic_size = 0;
270 for (int i = 0; i < pic->i_planes; i++)
272 const plane_t *p = &pic->p[i];
274 if (unlikely(mul_overflow(p->i_pitch, p->i_lines, &plane_sizes[i]))
275 || unlikely(add_overflow(pic_size, plane_sizes[i], &pic_size)))
276 goto error;
279 if (unlikely(pic_size >= PICTURE_SW_SIZE_MAX))
280 goto error;
282 picture_buffer_t *res = (void *)priv->extra;
284 unsigned char *buf = picture_Allocate(&res->fd, pic_size);
285 if (unlikely(buf == NULL))
286 goto error;
288 res->base = buf;
289 res->size = pic_size;
290 res->offset = 0;
291 pic->p_sys = res;
293 /* Fill the p_pixels field for each plane */
294 for (int i = 0; i < pic->i_planes; i++)
296 pic->p[i].p_pixels = buf;
297 buf += plane_sizes[i];
300 return pic;
301 error:
302 free(pic);
303 return NULL;
306 picture_t *picture_New( vlc_fourcc_t i_chroma, int i_width, int i_height, int i_sar_num, int i_sar_den )
308 video_format_t fmt;
310 video_format_Init( &fmt, 0 );
311 video_format_Setup( &fmt, i_chroma, i_width, i_height,
312 i_width, i_height, i_sar_num, i_sar_den );
314 return picture_NewFromFormat( &fmt );
317 /*****************************************************************************
319 *****************************************************************************/
321 void picture_Destroy(picture_t *picture)
323 /* See changes from other threads */
324 atomic_thread_fence(memory_order_acquire);
325 assert(atomic_load_explicit(&picture->refs, memory_order_relaxed) == 0);
327 PictureDestroyContext(picture);
329 picture_priv_t *priv = container_of(picture, picture_priv_t, picture);
330 assert(priv->gc.destroy != NULL);
331 priv->gc.destroy(picture);
332 free(priv);
335 /*****************************************************************************
337 *****************************************************************************/
338 void plane_CopyPixels( plane_t *p_dst, const plane_t *p_src )
340 const unsigned i_width = __MIN( p_dst->i_visible_pitch,
341 p_src->i_visible_pitch );
342 const unsigned i_height = __MIN( p_dst->i_visible_lines,
343 p_src->i_visible_lines );
345 /* The 2x visible pitch check does two things:
346 1) Makes field plane_t's work correctly (see the deinterlacer module)
347 2) Moves less data if the pitch and visible pitch differ much.
349 if( p_src->i_pitch == p_dst->i_pitch &&
350 p_src->i_pitch < 2*p_src->i_visible_pitch )
352 /* There are margins, but with the same width : perfect ! */
353 memcpy( p_dst->p_pixels, p_src->p_pixels,
354 p_src->i_pitch * i_height );
356 else
358 /* We need to proceed line by line */
359 uint8_t *p_in = p_src->p_pixels;
360 uint8_t *p_out = p_dst->p_pixels;
362 assert( p_in );
363 assert( p_out );
365 for( int i_line = i_height; i_line--; )
367 memcpy( p_out, p_in, i_width );
368 p_in += p_src->i_pitch;
369 p_out += p_dst->i_pitch;
374 void picture_CopyProperties( picture_t *p_dst, const picture_t *p_src )
376 p_dst->date = p_src->date;
377 p_dst->b_force = p_src->b_force;
378 p_dst->b_still = p_src->b_still;
380 p_dst->b_progressive = p_src->b_progressive;
381 p_dst->i_nb_fields = p_src->i_nb_fields;
382 p_dst->b_top_field_first = p_src->b_top_field_first;
385 void picture_CopyPixels( picture_t *p_dst, const picture_t *p_src )
387 for( int i = 0; i < p_src->i_planes ; i++ )
388 plane_CopyPixels( p_dst->p+i, p_src->p+i );
390 assert( p_dst->context == NULL );
392 if( p_src->context != NULL )
393 p_dst->context = p_src->context->copy( p_src->context );
396 void picture_Copy( picture_t *p_dst, const picture_t *p_src )
398 picture_CopyPixels( p_dst, p_src );
399 picture_CopyProperties( p_dst, p_src );
402 static void picture_DestroyClone(picture_t *clone)
404 picture_t *picture = ((picture_priv_t *)clone)->gc.opaque;
406 picture_Release(picture);
409 picture_t *picture_Clone(picture_t *picture)
411 /* TODO: merge common code with picture_pool_ClonePicture(). */
412 picture_resource_t res = {
413 .p_sys = picture->p_sys,
414 .pf_destroy = picture_DestroyClone,
417 for (int i = 0; i < picture->i_planes; i++) {
418 res.p[i].p_pixels = picture->p[i].p_pixels;
419 res.p[i].i_lines = picture->p[i].i_lines;
420 res.p[i].i_pitch = picture->p[i].i_pitch;
423 picture_t *clone = picture_NewFromResource(&picture->format, &res);
424 if (likely(clone != NULL)) {
425 ((picture_priv_t *)clone)->gc.opaque = picture;
426 picture_Hold(picture);
428 if (picture->context != NULL)
429 clone->context = picture->context->copy(picture->context);
431 return clone;
434 /*****************************************************************************
436 *****************************************************************************/
437 int picture_Export( vlc_object_t *p_obj,
438 block_t **pp_image,
439 video_format_t *p_fmt,
440 picture_t *p_picture,
441 vlc_fourcc_t i_format,
442 int i_override_width, int i_override_height )
444 /* */
445 video_format_t fmt_in = p_picture->format;
446 if( fmt_in.i_sar_num <= 0 || fmt_in.i_sar_den <= 0 )
448 fmt_in.i_sar_num =
449 fmt_in.i_sar_den = 1;
452 /* */
453 video_format_t fmt_out;
454 memset( &fmt_out, 0, sizeof(fmt_out) );
455 fmt_out.i_sar_num =
456 fmt_out.i_sar_den = 1;
457 fmt_out.i_chroma = i_format;
459 /* compute original width/height */
460 unsigned int i_width, i_height, i_original_width, i_original_height;
461 if( fmt_in.i_visible_width > 0 && fmt_in.i_visible_height > 0 )
463 i_width = fmt_in.i_visible_width;
464 i_height = fmt_in.i_visible_height;
466 else
468 i_width = fmt_in.i_width;
469 i_height = fmt_in.i_height;
471 if( fmt_in.i_sar_num >= fmt_in.i_sar_den )
473 i_original_width = (int64_t)i_width * fmt_in.i_sar_num / fmt_in.i_sar_den;
474 i_original_height = i_height;
476 else
478 i_original_width = i_width;
479 i_original_height = i_height * fmt_in.i_sar_den / fmt_in.i_sar_num;
482 /* */
483 fmt_out.i_width = ( i_override_width < 0 ) ?
484 i_original_width : (unsigned)i_override_width;
485 fmt_out.i_height = ( i_override_height < 0 ) ?
486 i_original_height : (unsigned)i_override_height;
488 /* scale if only one direction is provided */
489 if( fmt_out.i_height == 0 && fmt_out.i_width > 0 )
491 fmt_out.i_height = i_height * fmt_out.i_width
492 * fmt_in.i_sar_den / fmt_in.i_width / fmt_in.i_sar_num;
494 else if( fmt_out.i_width == 0 && fmt_out.i_height > 0 )
496 fmt_out.i_width = i_width * fmt_out.i_height
497 * fmt_in.i_sar_num / fmt_in.i_height / fmt_in.i_sar_den;
500 image_handler_t *p_image = image_HandlerCreate( p_obj );
501 if( !p_image )
502 return VLC_ENOMEM;
504 block_t *p_block = image_Write( p_image, p_picture, &fmt_in, &fmt_out );
506 image_HandlerDelete( p_image );
508 if( !p_block )
509 return VLC_EGENERIC;
511 p_block->i_pts =
512 p_block->i_dts = p_picture->date;
514 if( p_fmt )
515 *p_fmt = fmt_out;
516 *pp_image = p_block;
518 return VLC_SUCCESS;