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 *****************************************************************************/
36 #include <vlc_common.h>
38 #include <vlc_image.h>
39 #include <vlc_block.h>
41 #define PICTURE_SW_SIZE_MAX (1<<28) /* 256MB: 8K * 8K * 4*/
44 * Allocate a new picture in the heap.
46 * This function allocates a fake direct buffer in memory, which can be
47 * used exactly like a video buffer. The video output thread then manages
48 * how it gets displayed.
50 static int AllocatePicture( picture_t
*p_pic
)
52 /* Calculate how big the new image should be */
54 for( int i
= 0; i
< p_pic
->i_planes
; i
++ )
56 const plane_t
*p
= &p_pic
->p
[i
];
58 if( p
->i_pitch
< 0 || p
->i_lines
<= 0 ||
59 (size_t)p
->i_pitch
> (SIZE_MAX
- i_bytes
)/p
->i_lines
)
64 i_bytes
+= p
->i_pitch
* p
->i_lines
;
67 if( i_bytes
>= PICTURE_SW_SIZE_MAX
)
73 uint8_t *p_data
= aligned_alloc( 16, i_bytes
);
74 if( i_bytes
> 0 && p_data
== NULL
)
80 /* Fill the p_pixels field for each plane */
81 p_pic
->p
[0].p_pixels
= p_data
;
82 for( int i
= 1; i
< p_pic
->i_planes
; i
++ )
84 p_pic
->p
[i
].p_pixels
= &p_pic
->p
[i
-1].p_pixels
[ p_pic
->p
[i
-1].i_lines
*
85 p_pic
->p
[i
-1].i_pitch
];
91 /*****************************************************************************
93 *****************************************************************************/
95 static void PictureDestroyContext( picture_t
*p_picture
)
97 picture_context_t
*ctx
= p_picture
->context
;
101 p_picture
->context
= NULL
;
106 * Destroys a picture allocated by picture_NewFromResource() but without
107 * a custom destruction callback.
109 static void picture_DestroyFromResource( picture_t
*p_picture
)
111 free( p_picture
->p_sys
);
116 * Destroys a picture allocated with picture_NewFromFormat()
117 * (and thus AllocatePicture()).
119 static void picture_Destroy( picture_t
*p_picture
)
121 aligned_free( p_picture
->p
[0].p_pixels
);
125 /*****************************************************************************
127 *****************************************************************************/
128 void picture_Reset( picture_t
*p_picture
)
131 p_picture
->date
= VLC_TS_INVALID
;
132 p_picture
->b_force
= false;
133 p_picture
->b_progressive
= false;
134 p_picture
->i_nb_fields
= 2;
135 p_picture
->b_top_field_first
= false;
136 PictureDestroyContext( p_picture
);
139 /*****************************************************************************
141 *****************************************************************************/
142 static int LCM( int a
, int b
)
144 return a
* b
/ GCD( a
, b
);
147 int picture_Setup( picture_t
*p_picture
, const video_format_t
*restrict fmt
)
149 /* Store default values */
150 p_picture
->i_planes
= 0;
151 for( unsigned i
= 0; i
< VOUT_MAX_PLANES
; i
++ )
153 plane_t
*p
= &p_picture
->p
[i
];
155 p
->i_pixel_pitch
= 0;
158 p_picture
->i_nb_fields
= 2;
160 video_format_Setup( &p_picture
->format
, fmt
->i_chroma
, fmt
->i_width
, fmt
->i_height
,
161 fmt
->i_visible_width
, fmt
->i_visible_height
,
162 fmt
->i_sar_num
, fmt
->i_sar_den
);
164 const vlc_chroma_description_t
*p_dsc
=
165 vlc_fourcc_GetChromaDescription( p_picture
->format
.i_chroma
);
169 /* We want V (width/height) to respect:
170 (V * p_dsc->p[i].w.i_num) % p_dsc->p[i].w.i_den == 0
171 (V * p_dsc->p[i].w.i_num/p_dsc->p[i].w.i_den * p_dsc->i_pixel_size) % 16 == 0
172 Which is respected if you have
173 V % lcm( p_dsc->p[0..planes].w.i_den * 16) == 0
177 unsigned int i_ratio_h
= 1;
178 for( unsigned i
= 0; i
< p_dsc
->plane_count
; i
++ )
180 i_modulo_w
= LCM( i_modulo_w
, 16 * p_dsc
->p
[i
].w
.den
);
181 i_modulo_h
= LCM( i_modulo_h
, 16 * p_dsc
->p
[i
].h
.den
);
182 if( i_ratio_h
< p_dsc
->p
[i
].h
.den
)
183 i_ratio_h
= p_dsc
->p
[i
].h
.den
;
185 i_modulo_h
= LCM( i_modulo_h
, 32 );
187 const int i_width_aligned
= ( fmt
->i_width
+ i_modulo_w
- 1 ) / i_modulo_w
* i_modulo_w
;
188 const int i_height_aligned
= ( fmt
->i_height
+ i_modulo_h
- 1 ) / i_modulo_h
* i_modulo_h
;
189 const int i_height_extra
= 2 * i_ratio_h
; /* This one is a hack for some ASM functions */
190 for( unsigned i
= 0; i
< p_dsc
->plane_count
; i
++ )
192 plane_t
*p
= &p_picture
->p
[i
];
194 p
->i_lines
= (i_height_aligned
+ i_height_extra
) * p_dsc
->p
[i
].h
.num
/ p_dsc
->p
[i
].h
.den
;
195 p
->i_visible_lines
= fmt
->i_visible_height
* p_dsc
->p
[i
].h
.num
/ p_dsc
->p
[i
].h
.den
;
196 p
->i_pitch
= i_width_aligned
* p_dsc
->p
[i
].w
.num
/ p_dsc
->p
[i
].w
.den
* p_dsc
->pixel_size
;
197 p
->i_visible_pitch
= fmt
->i_visible_width
* p_dsc
->p
[i
].w
.num
/ p_dsc
->p
[i
].w
.den
* p_dsc
->pixel_size
;
198 p
->i_pixel_pitch
= p_dsc
->pixel_size
;
200 assert( (p
->i_pitch
% 16) == 0 );
202 p_picture
->i_planes
= p_dsc
->plane_count
;
207 /*****************************************************************************
209 *****************************************************************************/
210 picture_t
*picture_NewFromResource( const video_format_t
*p_fmt
, const picture_resource_t
*p_resource
)
212 video_format_t fmt
= *p_fmt
;
214 /* It is needed to be sure all information are filled */
215 video_format_Setup( &fmt
, p_fmt
->i_chroma
,
216 p_fmt
->i_width
, p_fmt
->i_height
,
217 p_fmt
->i_visible_width
, p_fmt
->i_visible_height
,
218 p_fmt
->i_sar_num
, p_fmt
->i_sar_den
);
219 if( p_fmt
->i_x_offset
< p_fmt
->i_width
&&
220 p_fmt
->i_y_offset
< p_fmt
->i_height
&&
221 p_fmt
->i_visible_width
> 0 && p_fmt
->i_x_offset
+ p_fmt
->i_visible_width
<= p_fmt
->i_width
&&
222 p_fmt
->i_visible_height
> 0 && p_fmt
->i_y_offset
+ p_fmt
->i_visible_height
<= p_fmt
->i_height
)
223 video_format_CopyCrop( &fmt
, p_fmt
);
226 picture_priv_t
*priv
= malloc( sizeof (*priv
) );
227 if( unlikely(priv
== NULL
) )
230 picture_t
*p_picture
= &priv
->picture
;
232 memset( p_picture
, 0, sizeof( *p_picture
) );
233 p_picture
->format
= fmt
;
235 /* Make sure the real dimensions are a multiple of 16 */
236 if( picture_Setup( p_picture
, &fmt
) )
242 atomic_init( &priv
->gc
.refs
, 1 );
243 priv
->gc
.opaque
= NULL
;
247 p_picture
->p_sys
= p_resource
->p_sys
;
249 if( p_resource
->pf_destroy
!= NULL
)
250 priv
->gc
.destroy
= p_resource
->pf_destroy
;
252 priv
->gc
.destroy
= picture_DestroyFromResource
;
254 for( int i
= 0; i
< p_picture
->i_planes
; i
++ )
256 p_picture
->p
[i
].p_pixels
= p_resource
->p
[i
].p_pixels
;
257 p_picture
->p
[i
].i_lines
= p_resource
->p
[i
].i_lines
;
258 p_picture
->p
[i
].i_pitch
= p_resource
->p
[i
].i_pitch
;
263 if( AllocatePicture( p_picture
) )
268 priv
->gc
.destroy
= picture_Destroy
;
274 picture_t
*picture_NewFromFormat( const video_format_t
*p_fmt
)
276 return picture_NewFromResource( p_fmt
, NULL
);
279 picture_t
*picture_New( vlc_fourcc_t i_chroma
, int i_width
, int i_height
, int i_sar_num
, int i_sar_den
)
283 video_format_Init( &fmt
, 0 );
284 video_format_Setup( &fmt
, i_chroma
, i_width
, i_height
,
285 i_width
, i_height
, i_sar_num
, i_sar_den
);
287 return picture_NewFromFormat( &fmt
);
290 /*****************************************************************************
292 *****************************************************************************/
294 picture_t
*picture_Hold( picture_t
*p_picture
)
296 assert( p_picture
!= NULL
);
298 picture_priv_t
*priv
= (picture_priv_t
*)p_picture
;
299 uintptr_t refs
= atomic_fetch_add( &priv
->gc
.refs
, 1 );
304 void picture_Release( picture_t
*p_picture
)
306 assert( p_picture
!= NULL
);
308 picture_priv_t
*priv
= (picture_priv_t
*)p_picture
;
309 uintptr_t refs
= atomic_fetch_sub( &priv
->gc
.refs
, 1 );
314 PictureDestroyContext( p_picture
);
315 assert( priv
->gc
.destroy
!= NULL
);
316 priv
->gc
.destroy( p_picture
);
319 /*****************************************************************************
321 *****************************************************************************/
322 void plane_CopyPixels( plane_t
*p_dst
, const plane_t
*p_src
)
324 const unsigned i_width
= __MIN( p_dst
->i_visible_pitch
,
325 p_src
->i_visible_pitch
);
326 const unsigned i_height
= __MIN( p_dst
->i_visible_lines
,
327 p_src
->i_visible_lines
);
329 /* The 2x visible pitch check does two things:
330 1) Makes field plane_t's work correctly (see the deinterlacer module)
331 2) Moves less data if the pitch and visible pitch differ much.
333 if( p_src
->i_pitch
== p_dst
->i_pitch
&&
334 p_src
->i_pitch
< 2*p_src
->i_visible_pitch
)
336 /* There are margins, but with the same width : perfect ! */
337 memcpy( p_dst
->p_pixels
, p_src
->p_pixels
,
338 p_src
->i_pitch
* i_height
);
342 /* We need to proceed line by line */
343 uint8_t *p_in
= p_src
->p_pixels
;
344 uint8_t *p_out
= p_dst
->p_pixels
;
349 for( int i_line
= i_height
; i_line
--; )
351 memcpy( p_out
, p_in
, i_width
);
352 p_in
+= p_src
->i_pitch
;
353 p_out
+= p_dst
->i_pitch
;
358 void picture_CopyProperties( picture_t
*p_dst
, const picture_t
*p_src
)
360 p_dst
->date
= p_src
->date
;
361 p_dst
->b_force
= p_src
->b_force
;
363 p_dst
->b_progressive
= p_src
->b_progressive
;
364 p_dst
->i_nb_fields
= p_src
->i_nb_fields
;
365 p_dst
->b_top_field_first
= p_src
->b_top_field_first
;
368 void picture_CopyPixels( picture_t
*p_dst
, const picture_t
*p_src
)
370 for( int i
= 0; i
< p_src
->i_planes
; i
++ )
371 plane_CopyPixels( p_dst
->p
+i
, p_src
->p
+i
);
373 assert( p_dst
->context
== NULL
);
375 if( p_src
->context
!= NULL
)
376 p_dst
->context
= p_src
->context
->copy( p_src
->context
);
379 void picture_Copy( picture_t
*p_dst
, const picture_t
*p_src
)
381 picture_CopyPixels( p_dst
, p_src
);
382 picture_CopyProperties( p_dst
, p_src
);
385 static void picture_DestroyClone(picture_t
*clone
)
387 picture_t
*picture
= ((picture_priv_t
*)clone
)->gc
.opaque
;
390 picture_Release(picture
);
393 picture_t
*picture_Clone(picture_t
*picture
)
395 /* TODO: merge common code with picture_pool_ClonePicture(). */
396 picture_resource_t res
= {
397 .p_sys
= picture
->p_sys
,
398 .pf_destroy
= picture_DestroyClone
,
401 for (int i
= 0; i
< picture
->i_planes
; i
++) {
402 res
.p
[i
].p_pixels
= picture
->p
[i
].p_pixels
;
403 res
.p
[i
].i_lines
= picture
->p
[i
].i_lines
;
404 res
.p
[i
].i_pitch
= picture
->p
[i
].i_pitch
;
407 picture_t
*clone
= picture_NewFromResource(&picture
->format
, &res
);
408 if (likely(clone
!= NULL
)) {
409 ((picture_priv_t
*)clone
)->gc
.opaque
= picture
;
410 picture_Hold(picture
);
412 if (picture
->context
!= NULL
)
413 clone
->context
= picture
->context
->copy(picture
->context
);
418 /*****************************************************************************
420 *****************************************************************************/
421 int picture_Export( vlc_object_t
*p_obj
,
423 video_format_t
*p_fmt
,
424 picture_t
*p_picture
,
425 vlc_fourcc_t i_format
,
426 int i_override_width
, int i_override_height
)
429 video_format_t fmt_in
= p_picture
->format
;
430 if( fmt_in
.i_sar_num
<= 0 || fmt_in
.i_sar_den
<= 0 )
433 fmt_in
.i_sar_den
= 1;
437 video_format_t fmt_out
;
438 memset( &fmt_out
, 0, sizeof(fmt_out
) );
440 fmt_out
.i_sar_den
= 1;
441 fmt_out
.i_chroma
= i_format
;
443 /* compute original width/height */
444 unsigned int i_width
, i_height
, i_original_width
, i_original_height
;
445 if( fmt_in
.i_visible_width
> 0 && fmt_in
.i_visible_height
> 0 )
447 i_width
= fmt_in
.i_visible_width
;
448 i_height
= fmt_in
.i_visible_height
;
452 i_width
= fmt_in
.i_width
;
453 i_height
= fmt_in
.i_height
;
455 if( fmt_in
.i_sar_num
>= fmt_in
.i_sar_den
)
457 i_original_width
= (int64_t)i_width
* fmt_in
.i_sar_num
/ fmt_in
.i_sar_den
;
458 i_original_height
= i_height
;
462 i_original_width
= i_width
;
463 i_original_height
= i_height
* fmt_in
.i_sar_den
/ fmt_in
.i_sar_num
;
467 fmt_out
.i_width
= ( i_override_width
< 0 ) ?
468 i_original_width
: (unsigned)i_override_width
;
469 fmt_out
.i_height
= ( i_override_height
< 0 ) ?
470 i_original_height
: (unsigned)i_override_height
;
472 /* scale if only one direction is provided */
473 if( fmt_out
.i_height
== 0 && fmt_out
.i_width
> 0 )
475 fmt_out
.i_height
= i_height
* fmt_out
.i_width
476 * fmt_in
.i_sar_den
/ fmt_in
.i_width
/ fmt_in
.i_sar_num
;
478 else if( fmt_out
.i_width
== 0 && fmt_out
.i_height
> 0 )
480 fmt_out
.i_width
= i_width
* fmt_out
.i_height
481 * fmt_in
.i_sar_num
/ fmt_in
.i_height
/ fmt_in
.i_sar_den
;
484 image_handler_t
*p_image
= image_HandlerCreate( p_obj
);
488 block_t
*p_block
= image_Write( p_image
, p_picture
, &fmt_in
, &fmt_out
);
490 image_HandlerDelete( p_image
);
496 p_block
->i_dts
= p_picture
->date
;