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>
37 #include <vlc_picture.h>
38 #include <vlc_image.h>
39 #include <vlc_block.h>
40 #include <vlc_atomic.h>
43 * Allocate a new picture in the heap.
45 * This function allocates a fake direct buffer in memory, which can be
46 * used exactly like a video buffer. The video output thread then manages
47 * how it gets displayed.
49 static int AllocatePicture( picture_t
*p_pic
,
50 vlc_fourcc_t i_chroma
,
51 int i_width
, int i_height
,
52 int i_sar_num
, int i_sar_den
)
54 /* Make sure the real dimensions are a multiple of 16 */
55 if( picture_Setup( p_pic
, i_chroma
, i_width
, i_height
,
56 i_sar_num
, i_sar_den
) != VLC_SUCCESS
)
59 /* Calculate how big the new image should be */
61 for( int i
= 0; i
< p_pic
->i_planes
; i
++ )
63 const plane_t
*p
= &p_pic
->p
[i
];
65 if( p
->i_pitch
<= 0 || p
->i_lines
<= 0 ||
66 (size_t)p
->i_pitch
> (SIZE_MAX
- i_bytes
)/p
->i_lines
)
71 i_bytes
+= p
->i_pitch
* p
->i_lines
;
74 uint8_t *p_data
= vlc_memalign( 16, i_bytes
);
80 p_pic
->p_data_orig
= p_data
; /* TODO: get rid of this */
82 /* Fill the p_pixels field for each plane */
83 p_pic
->p
[0].p_pixels
= p_data
;
84 for( int i
= 1; i
< p_pic
->i_planes
; i
++ )
86 p_pic
->p
[i
].p_pixels
= &p_pic
->p
[i
-1].p_pixels
[ p_pic
->p
[i
-1].i_lines
*
87 p_pic
->p
[i
-1].i_pitch
];
93 /*****************************************************************************
95 *****************************************************************************/
96 static void PictureDestroy( picture_t
*p_picture
)
99 vlc_atomic_get( &p_picture
->gc
.refcount
) == 0 &&
100 p_picture
->gc
.p_sys
== NULL
);
102 free( p_picture
->p_q
);
103 vlc_free( p_picture
->p_data_orig
);
104 free( p_picture
->p_sys
);
108 /*****************************************************************************
110 *****************************************************************************/
111 void picture_Reset( picture_t
*p_picture
)
114 p_picture
->date
= VLC_TS_INVALID
;
115 p_picture
->b_force
= false;
116 p_picture
->b_progressive
= false;
117 p_picture
->i_nb_fields
= 2;
118 p_picture
->b_top_field_first
= false;
120 free( p_picture
->p_q
);
121 p_picture
->p_q
= NULL
;
122 p_picture
->i_qstride
= 0;
123 p_picture
->i_qtype
= 0;
126 /*****************************************************************************
128 *****************************************************************************/
129 static int LCM( int a
, int b
)
131 return a
* b
/ GCD( a
, b
);
134 int picture_Setup( picture_t
*p_picture
, vlc_fourcc_t i_chroma
,
135 int i_width
, int i_height
, int i_sar_num
, int i_sar_den
)
137 /* Store default values */
138 p_picture
->i_planes
= 0;
139 for( unsigned i
= 0; i
< VOUT_MAX_PLANES
; i
++ )
141 plane_t
*p
= &p_picture
->p
[i
];
143 p
->i_pixel_pitch
= 0;
146 vlc_atomic_set( &p_picture
->gc
.refcount
, 0 );
147 p_picture
->gc
.pf_destroy
= NULL
;
148 p_picture
->gc
.p_sys
= NULL
;
150 p_picture
->i_nb_fields
= 2;
152 p_picture
->i_qtype
= QTYPE_NONE
;
153 p_picture
->i_qstride
= 0;
154 p_picture
->p_q
= NULL
;
156 video_format_Setup( &p_picture
->format
, i_chroma
, i_width
, i_height
,
157 i_sar_num
, i_sar_den
);
159 const vlc_chroma_description_t
*p_dsc
=
160 vlc_fourcc_GetChromaDescription( p_picture
->format
.i_chroma
);
164 /* We want V (width/height) to respect:
165 (V * p_dsc->p[i].w.i_num) % p_dsc->p[i].w.i_den == 0
166 (V * p_dsc->p[i].w.i_num/p_dsc->p[i].w.i_den * p_dsc->i_pixel_size) % 16 == 0
167 Which is respected if you have
168 V % lcm( p_dsc->p[0..planes].w.i_den * 16) == 0
172 unsigned int i_ratio_h
= 1;
173 for( unsigned i
= 0; i
< p_dsc
->plane_count
; i
++ )
175 i_modulo_w
= LCM( i_modulo_w
, 16 * p_dsc
->p
[i
].w
.den
);
176 i_modulo_h
= LCM( i_modulo_h
, 16 * p_dsc
->p
[i
].h
.den
);
177 if( i_ratio_h
< p_dsc
->p
[i
].h
.den
)
178 i_ratio_h
= p_dsc
->p
[i
].h
.den
;
180 i_modulo_h
= LCM( i_modulo_h
, 32 );
182 const int i_width_aligned
= ( i_width
+ i_modulo_w
- 1 ) / i_modulo_w
* i_modulo_w
;
183 const int i_height_aligned
= ( i_height
+ i_modulo_h
- 1 ) / i_modulo_h
* i_modulo_h
;
184 const int i_height_extra
= 2 * i_ratio_h
; /* This one is a hack for some ASM functions */
185 for( unsigned i
= 0; i
< p_dsc
->plane_count
; i
++ )
187 plane_t
*p
= &p_picture
->p
[i
];
189 p
->i_lines
= (i_height_aligned
+ i_height_extra
) * p_dsc
->p
[i
].h
.num
/ p_dsc
->p
[i
].h
.den
;
190 p
->i_visible_lines
= i_height
* p_dsc
->p
[i
].h
.num
/ p_dsc
->p
[i
].h
.den
;
191 p
->i_pitch
= i_width_aligned
* p_dsc
->p
[i
].w
.num
/ p_dsc
->p
[i
].w
.den
* p_dsc
->pixel_size
;
192 p
->i_visible_pitch
= i_width
* p_dsc
->p
[i
].w
.num
/ p_dsc
->p
[i
].w
.den
* p_dsc
->pixel_size
;
193 p
->i_pixel_pitch
= p_dsc
->pixel_size
;
195 assert( (p
->i_pitch
% 16) == 0 );
197 p_picture
->i_planes
= p_dsc
->plane_count
;
202 /*****************************************************************************
204 *****************************************************************************/
205 picture_t
*picture_NewFromResource( const video_format_t
*p_fmt
, const picture_resource_t
*p_resource
)
207 video_format_t fmt
= *p_fmt
;
209 /* It is needed to be sure all information are filled */
210 video_format_Setup( &fmt
, p_fmt
->i_chroma
,
211 p_fmt
->i_width
, p_fmt
->i_height
,
212 p_fmt
->i_sar_num
, p_fmt
->i_sar_den
);
213 if( p_fmt
->i_x_offset
< p_fmt
->i_width
&&
214 p_fmt
->i_y_offset
< p_fmt
->i_height
&&
215 p_fmt
->i_visible_width
> 0 && p_fmt
->i_x_offset
+ p_fmt
->i_visible_width
<= p_fmt
->i_width
&&
216 p_fmt
->i_visible_height
> 0 && p_fmt
->i_y_offset
+ p_fmt
->i_visible_height
<= p_fmt
->i_height
)
217 video_format_CopyCrop( &fmt
, p_fmt
);
220 picture_t
*p_picture
= calloc( 1, sizeof(*p_picture
) );
226 if( picture_Setup( p_picture
, fmt
.i_chroma
, fmt
.i_width
, fmt
.i_height
,
227 fmt
.i_sar_num
, fmt
.i_sar_den
) )
232 p_picture
->p_sys
= p_resource
->p_sys
;
234 for( int i
= 0; i
< p_picture
->i_planes
; i
++ )
236 p_picture
->p
[i
].p_pixels
= p_resource
->p
[i
].p_pixels
;
237 p_picture
->p
[i
].i_lines
= p_resource
->p
[i
].i_lines
;
238 p_picture
->p
[i
].i_pitch
= p_resource
->p
[i
].i_pitch
;
243 if( AllocatePicture( p_picture
,
244 fmt
.i_chroma
, fmt
.i_width
, fmt
.i_height
,
245 fmt
.i_sar_num
, fmt
.i_sar_den
) )
252 p_picture
->format
= fmt
;
254 vlc_atomic_set( &p_picture
->gc
.refcount
, 1 );
255 p_picture
->gc
.pf_destroy
= PictureDestroy
;
256 p_picture
->gc
.p_sys
= NULL
;
260 picture_t
*picture_NewFromFormat( const video_format_t
*p_fmt
)
262 return picture_NewFromResource( p_fmt
, NULL
);
264 picture_t
*picture_New( vlc_fourcc_t i_chroma
, int i_width
, int i_height
, int i_sar_num
, int i_sar_den
)
268 memset( &fmt
, 0, sizeof(fmt
) );
269 video_format_Setup( &fmt
, i_chroma
, i_width
, i_height
,
270 i_sar_num
, i_sar_den
);
272 return picture_NewFromFormat( &fmt
);
275 /*****************************************************************************
277 *****************************************************************************/
279 picture_t
*picture_Hold( picture_t
*p_picture
)
281 vlc_atomic_inc( &p_picture
->gc
.refcount
);
285 void picture_Release( picture_t
*p_picture
)
287 if( vlc_atomic_dec( &p_picture
->gc
.refcount
) == 0 &&
288 p_picture
->gc
.pf_destroy
)
289 p_picture
->gc
.pf_destroy( p_picture
);
292 bool picture_IsReferenced( picture_t
*p_picture
)
294 return vlc_atomic_get( &p_picture
->gc
.refcount
) > 1;
297 /*****************************************************************************
299 *****************************************************************************/
300 void plane_CopyPixels( plane_t
*p_dst
, const plane_t
*p_src
)
302 const unsigned i_width
= __MIN( p_dst
->i_visible_pitch
,
303 p_src
->i_visible_pitch
);
304 const unsigned i_height
= __MIN( p_dst
->i_visible_lines
,
305 p_src
->i_visible_lines
);
307 /* The 2x visible pitch check does two things:
308 1) Makes field plane_t's work correctly (see the deinterlacer module)
309 2) Moves less data if the pitch and visible pitch differ much.
311 if( p_src
->i_pitch
== p_dst
->i_pitch
&&
312 p_src
->i_pitch
< 2*p_src
->i_visible_pitch
)
314 /* There are margins, but with the same width : perfect ! */
315 memcpy( p_dst
->p_pixels
, p_src
->p_pixels
,
316 p_src
->i_pitch
* i_height
);
320 /* We need to proceed line by line */
321 uint8_t *p_in
= p_src
->p_pixels
;
322 uint8_t *p_out
= p_dst
->p_pixels
;
328 for( i_line
= i_height
; i_line
--; )
330 memcpy( p_out
, p_in
, i_width
);
331 p_in
+= p_src
->i_pitch
;
332 p_out
+= p_dst
->i_pitch
;
337 void picture_CopyProperties( picture_t
*p_dst
, const picture_t
*p_src
)
339 p_dst
->date
= p_src
->date
;
340 p_dst
->b_force
= p_src
->b_force
;
342 p_dst
->b_progressive
= p_src
->b_progressive
;
343 p_dst
->i_nb_fields
= p_src
->i_nb_fields
;
344 p_dst
->b_top_field_first
= p_src
->b_top_field_first
;
346 /* FIXME: copy ->p_q and ->p_qstride */
349 void picture_CopyPixels( picture_t
*p_dst
, const picture_t
*p_src
)
353 for( i
= 0; i
< p_src
->i_planes
; i
++ )
354 plane_CopyPixels( p_dst
->p
+i
, p_src
->p
+i
);
357 void picture_Copy( picture_t
*p_dst
, const picture_t
*p_src
)
359 picture_CopyPixels( p_dst
, p_src
);
360 picture_CopyProperties( p_dst
, p_src
);
364 /*****************************************************************************
366 *****************************************************************************/
367 int picture_Export( vlc_object_t
*p_obj
,
369 video_format_t
*p_fmt
,
370 picture_t
*p_picture
,
371 vlc_fourcc_t i_format
,
372 int i_override_width
, int i_override_height
)
375 video_format_t fmt_in
= p_picture
->format
;
376 if( fmt_in
.i_sar_num
<= 0 || fmt_in
.i_sar_den
<= 0 )
379 fmt_in
.i_sar_den
= 1;
383 video_format_t fmt_out
;
384 memset( &fmt_out
, 0, sizeof(fmt_out
) );
386 fmt_out
.i_sar_den
= 1;
387 fmt_out
.i_chroma
= i_format
;
389 /* compute original width/height */
390 unsigned int i_original_width
;
391 unsigned int i_original_height
;
392 if( fmt_in
.i_sar_num
>= fmt_in
.i_sar_den
)
394 i_original_width
= (int64_t)fmt_in
.i_width
* fmt_in
.i_sar_num
/ fmt_in
.i_sar_den
;
395 i_original_height
= fmt_in
.i_height
;
399 i_original_width
= fmt_in
.i_width
;
400 i_original_height
= (int64_t)fmt_in
.i_height
* fmt_in
.i_sar_den
/ fmt_in
.i_sar_num
;
404 fmt_out
.i_width
= ( i_override_width
< 0 ) ?
405 i_original_width
: (unsigned)i_override_width
;
406 fmt_out
.i_height
= ( i_override_height
< 0 ) ?
407 i_original_height
: (unsigned)i_override_height
;
409 /* scale if only one direction is provided */
410 if( fmt_out
.i_height
== 0 && fmt_out
.i_width
> 0 )
412 fmt_out
.i_height
= fmt_in
.i_height
* fmt_out
.i_width
413 * fmt_in
.i_sar_den
/ fmt_in
.i_width
/ fmt_in
.i_sar_num
;
415 else if( fmt_out
.i_width
== 0 && fmt_out
.i_height
> 0 )
417 fmt_out
.i_width
= fmt_in
.i_width
* fmt_out
.i_height
418 * fmt_in
.i_sar_num
/ fmt_in
.i_height
/ fmt_in
.i_sar_den
;
421 image_handler_t
*p_image
= image_HandlerCreate( p_obj
);
423 block_t
*p_block
= image_Write( p_image
, p_picture
, &fmt_in
, &fmt_out
);
425 image_HandlerDelete( p_image
);
431 p_block
->i_dts
= p_picture
->date
;
440 void picture_BlendSubpicture(picture_t
*dst
,
441 filter_t
*blend
, subpicture_t
*src
)
443 assert(src
&& !src
->b_fade
&& src
->b_absolute
);
445 for (subpicture_region_t
*r
= src
->p_region
; r
!= NULL
; r
= r
->p_next
) {
446 assert(r
->p_picture
&& r
->i_align
== 0);
447 if (filter_ConfigureBlend(blend
, dst
->format
.i_width
, dst
->format
.i_height
,
449 filter_Blend(blend
, dst
,
450 r
->i_x
, r
->i_y
, r
->p_picture
,
451 src
->i_alpha
* r
->i_alpha
/ 255)) {
452 msg_Err(blend
, "blending %4.4s to %4.4s failed",
453 (char *)&blend
->fmt_in
.video
.i_chroma
,
454 (char *)&blend
->fmt_out
.video
.i_chroma
);