1 /*****************************************************************************
2 * picture.c : picture management functions
3 *****************************************************************************
4 * Copyright (C) 2000-2010 VLC authors and VideoLAN
5 * Copyright (C) 2009-2010 Laurent Aimar
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 /*****************************************************************************
29 *****************************************************************************/
37 #include <vlc_common.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
;
48 p_picture
->context
= NULL
;
53 * Destroys a picture allocated by picture_NewFromResource() but without
54 * a custom destruction callback.
56 static void picture_DestroyDummy( picture_t
*p_picture
)
62 * Destroys a picture allocated with picture_NewFromFormat().
64 static void picture_DestroyFromFormat(picture_t
*pic
)
66 picture_buffer_t
*res
= pic
->p_sys
;
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);
76 return aligned_alloc(64, size
);
79 VLC_WEAK
void picture_Deallocate(int fd
, void *base
, size_t size
)
83 assert((size
% 64) == 0);
86 /*****************************************************************************
88 *****************************************************************************/
89 void picture_Reset( picture_t
*p_picture
)
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
) )
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
];
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
)))
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
))
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
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
;
193 /*****************************************************************************
195 *****************************************************************************/
197 static picture_priv_t
*picture_NewPrivate(const video_format_t
*restrict p_fmt
,
201 picture_priv_t
*priv
= malloc(sizeof (*priv
) + extra
);
202 if( unlikely(priv
== 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
) )
217 atomic_init(&p_picture
->refs
, 1);
218 priv
->gc
.opaque
= NULL
;
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
))
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
;
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
;
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
))
258 priv
->gc
.destroy
= picture_DestroyFromFormat
;
260 picture_t
*pic
= &priv
->picture
;
261 if (pic
->i_planes
== 0) {
266 /* Calculate how big the new image should be */
267 size_t plane_sizes
[PICTURE_PLANE_MAX
];
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
)))
279 if (unlikely(pic_size
>= PICTURE_SW_SIZE_MAX
))
282 picture_buffer_t
*res
= (void *)priv
->extra
;
284 unsigned char *buf
= picture_Allocate(&res
->fd
, pic_size
);
285 if (unlikely(buf
== NULL
))
289 res
->size
= pic_size
;
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
];
306 picture_t
*picture_New( vlc_fourcc_t i_chroma
, int i_width
, int i_height
, int i_sar_num
, int i_sar_den
)
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
);
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
);
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
;
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
);
434 /*****************************************************************************
436 *****************************************************************************/
437 int picture_Export( vlc_object_t
*p_obj
,
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
)
445 video_format_t fmt_in
= p_picture
->format
;
446 if( fmt_in
.i_sar_num
<= 0 || fmt_in
.i_sar_den
<= 0 )
449 fmt_in
.i_sar_den
= 1;
453 video_format_t fmt_out
;
454 memset( &fmt_out
, 0, sizeof(fmt_out
) );
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
;
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
;
478 i_original_width
= i_width
;
479 i_original_height
= i_height
* fmt_in
.i_sar_den
/ fmt_in
.i_sar_num
;
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
);
504 block_t
*p_block
= image_Write( p_image
, p_picture
, &fmt_in
, &fmt_out
);
506 image_HandlerDelete( p_image
);
512 p_block
->i_dts
= p_picture
->date
;