1 /*****************************************************************************
2 * picture.c : picture management functions
3 *****************************************************************************
4 * Copyright (C) 2000-2010 the VideoLAN team
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
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 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 General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, 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>
42 * Allocate a new picture in the heap.
44 * This function allocates a fake direct buffer in memory, which can be
45 * used exactly like a video buffer. The video output thread then manages
46 * how it gets displayed.
48 static int vout_AllocatePicture( picture_t
*p_pic
,
49 vlc_fourcc_t i_chroma
,
50 int i_width
, int i_height
,
51 int i_sar_num
, int i_sar_den
)
53 /* Make sure the real dimensions are a multiple of 16 */
54 if( picture_Setup( p_pic
, i_chroma
, i_width
, i_height
,
55 i_sar_num
, i_sar_den
) != VLC_SUCCESS
)
58 /* Calculate how big the new image should be */
60 for( int i
= 0; i
< p_pic
->i_planes
; i
++ )
62 const plane_t
*p
= &p_pic
->p
[i
];
64 if( p
->i_pitch
<= 0 || p
->i_lines
<= 0 ||
65 p
->i_pitch
> (SIZE_MAX
- i_bytes
)/p
->i_lines
)
70 i_bytes
+= p
->i_pitch
* p
->i_lines
;
73 uint8_t *p_data
= vlc_memalign( &p_pic
->p_data_orig
, 16, i_bytes
);
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 *****************************************************************************/
94 static void PictureReleaseCallback( picture_t
*p_picture
)
96 if( --p_picture
->i_refcount
> 0 )
98 picture_Delete( p_picture
);
101 /*****************************************************************************
103 *****************************************************************************/
104 void picture_Reset( picture_t
*p_picture
)
107 p_picture
->date
= VLC_TS_INVALID
;
108 p_picture
->b_force
= false;
109 p_picture
->b_progressive
= false;
110 p_picture
->i_nb_fields
= 0;
111 p_picture
->b_top_field_first
= false;
112 picture_CleanupQuant( p_picture
);
115 /*****************************************************************************
117 *****************************************************************************/
118 static int LCM( int a
, int b
)
120 return a
* b
/ GCD( a
, b
);
123 int picture_Setup( picture_t
*p_picture
, vlc_fourcc_t i_chroma
,
124 int i_width
, int i_height
, int i_sar_num
, int i_sar_den
)
126 /* Store default values */
127 p_picture
->i_planes
= 0;
128 for( unsigned i
= 0; i
< VOUT_MAX_PLANES
; i
++ )
130 plane_t
*p
= &p_picture
->p
[i
];
132 p
->i_pixel_pitch
= 0;
135 p_picture
->pf_release
= NULL
;
136 p_picture
->p_release_sys
= NULL
;
137 p_picture
->i_refcount
= 0;
139 p_picture
->i_qtype
= QTYPE_NONE
;
140 p_picture
->i_qstride
= 0;
141 p_picture
->p_q
= NULL
;
143 video_format_Setup( &p_picture
->format
, i_chroma
, i_width
, i_height
,
144 i_sar_num
, i_sar_den
);
146 const vlc_chroma_description_t
*p_dsc
=
147 vlc_fourcc_GetChromaDescription( p_picture
->format
.i_chroma
);
151 /* We want V (width/height) to respect:
152 (V * p_dsc->p[i].w.i_num) % p_dsc->p[i].w.i_den == 0
153 (V * p_dsc->p[i].w.i_num/p_dsc->p[i].w.i_den * p_dsc->i_pixel_size) % 16 == 0
154 Which is respected if you have
155 V % lcm( p_dsc->p[0..planes].w.i_den * 16) == 0
160 for( unsigned i
= 0; i
< p_dsc
->plane_count
; i
++ )
162 i_modulo_w
= LCM( i_modulo_w
, 16 * p_dsc
->p
[i
].w
.den
);
163 i_modulo_h
= LCM( i_modulo_h
, 16 * p_dsc
->p
[i
].h
.den
);
164 if( i_ratio_h
< p_dsc
->p
[i
].h
.den
)
165 i_ratio_h
= p_dsc
->p
[i
].h
.den
;
168 const int i_width_aligned
= ( i_width
+ i_modulo_w
- 1 ) / i_modulo_w
* i_modulo_w
;
169 const int i_height_aligned
= ( i_height
+ i_modulo_h
- 1 ) / i_modulo_h
* i_modulo_h
;
170 const int i_height_extra
= 2 * i_ratio_h
; /* This one is a hack for some ASM functions */
171 for( unsigned i
= 0; i
< p_dsc
->plane_count
; i
++ )
173 plane_t
*p
= &p_picture
->p
[i
];
175 p
->i_lines
= (i_height_aligned
+ i_height_extra
) * p_dsc
->p
[i
].h
.num
/ p_dsc
->p
[i
].h
.den
;
176 p
->i_visible_lines
= i_height
* p_dsc
->p
[i
].h
.num
/ p_dsc
->p
[i
].h
.den
;
177 p
->i_pitch
= i_width_aligned
* p_dsc
->p
[i
].w
.num
/ p_dsc
->p
[i
].w
.den
* p_dsc
->pixel_size
;
178 p
->i_visible_pitch
= i_width
* p_dsc
->p
[i
].w
.num
/ p_dsc
->p
[i
].w
.den
* p_dsc
->pixel_size
;
179 p
->i_pixel_pitch
= p_dsc
->pixel_size
;
181 assert( (p
->i_pitch
% 16) == 0 );
183 p_picture
->i_planes
= p_dsc
->plane_count
;
188 /*****************************************************************************
190 *****************************************************************************/
191 picture_t
*picture_NewFromResource( const video_format_t
*p_fmt
, const picture_resource_t
*p_resource
)
193 video_format_t fmt
= *p_fmt
;
195 /* It is needed to be sure all information are filled */
196 video_format_Setup( &fmt
, p_fmt
->i_chroma
,
197 p_fmt
->i_width
, p_fmt
->i_height
,
198 p_fmt
->i_sar_num
, p_fmt
->i_sar_den
);
199 if( p_fmt
->i_x_offset
< p_fmt
->i_width
&&
200 p_fmt
->i_y_offset
< p_fmt
->i_height
&&
201 p_fmt
->i_visible_width
> 0 && p_fmt
->i_x_offset
+ p_fmt
->i_visible_width
<= p_fmt
->i_width
&&
202 p_fmt
->i_visible_height
> 0 && p_fmt
->i_y_offset
+ p_fmt
->i_visible_height
<= p_fmt
->i_height
)
203 video_format_CopyCrop( &fmt
, p_fmt
);
206 picture_t
*p_picture
= calloc( 1, sizeof(*p_picture
) );
212 if( picture_Setup( p_picture
, fmt
.i_chroma
, fmt
.i_width
, fmt
.i_height
,
213 fmt
.i_sar_num
, fmt
.i_sar_den
) )
218 p_picture
->p_sys
= p_resource
->p_sys
;
220 for( int i
= 0; i
< p_picture
->i_planes
; i
++ )
222 p_picture
->p
[i
].p_pixels
= p_resource
->p
[i
].p_pixels
;
223 p_picture
->p
[i
].i_lines
= p_resource
->p
[i
].i_lines
;
224 p_picture
->p
[i
].i_pitch
= p_resource
->p
[i
].i_pitch
;
229 if( vout_AllocatePicture( p_picture
,
230 fmt
.i_chroma
, fmt
.i_width
, fmt
.i_height
,
231 fmt
.i_sar_num
, fmt
.i_sar_den
) )
238 p_picture
->format
= fmt
;
239 p_picture
->i_refcount
= 1;
240 p_picture
->pf_release
= PictureReleaseCallback
;
244 picture_t
*picture_NewFromFormat( const video_format_t
*p_fmt
)
246 return picture_NewFromResource( p_fmt
, NULL
);
248 picture_t
*picture_New( vlc_fourcc_t i_chroma
, int i_width
, int i_height
, int i_sar_num
, int i_sar_den
)
252 memset( &fmt
, 0, sizeof(fmt
) );
253 video_format_Setup( &fmt
, i_chroma
, i_width
, i_height
,
254 i_sar_num
, i_sar_den
);
256 return picture_NewFromFormat( &fmt
);
259 /*****************************************************************************
261 *****************************************************************************/
262 void picture_Delete( picture_t
*p_picture
)
264 assert( p_picture
&& p_picture
->i_refcount
== 0 );
265 assert( p_picture
->p_release_sys
== NULL
);
267 free( p_picture
->p_q
);
268 free( p_picture
->p_data_orig
);
269 free( p_picture
->p_sys
);
273 /*****************************************************************************
275 *****************************************************************************/
276 void picture_CopyPixels( picture_t
*p_dst
, const picture_t
*p_src
)
280 for( i
= 0; i
< p_src
->i_planes
; i
++ )
281 plane_CopyPixels( p_dst
->p
+i
, p_src
->p
+i
);
284 void plane_CopyPixels( plane_t
*p_dst
, const plane_t
*p_src
)
286 const unsigned i_width
= __MIN( p_dst
->i_visible_pitch
,
287 p_src
->i_visible_pitch
);
288 const unsigned i_height
= __MIN( p_dst
->i_visible_lines
,
289 p_src
->i_visible_lines
);
291 if( p_src
->i_pitch
== p_dst
->i_pitch
)
293 /* There are margins, but with the same width : perfect ! */
294 vlc_memcpy( p_dst
->p_pixels
, p_src
->p_pixels
,
295 p_src
->i_pitch
* i_height
);
299 /* We need to proceed line by line */
300 uint8_t *p_in
= p_src
->p_pixels
;
301 uint8_t *p_out
= p_dst
->p_pixels
;
307 for( i_line
= i_height
; i_line
--; )
309 vlc_memcpy( p_out
, p_in
, i_width
);
310 p_in
+= p_src
->i_pitch
;
311 p_out
+= p_dst
->i_pitch
;
316 /*****************************************************************************
318 *****************************************************************************/
319 int picture_Export( vlc_object_t
*p_obj
,
321 video_format_t
*p_fmt
,
322 picture_t
*p_picture
,
323 vlc_fourcc_t i_format
,
324 int i_override_width
, int i_override_height
)
327 video_format_t fmt_in
= p_picture
->format
;
328 if( fmt_in
.i_sar_num
<= 0 || fmt_in
.i_sar_den
<= 0 )
331 fmt_in
.i_sar_den
= 1;
335 video_format_t fmt_out
;
336 memset( &fmt_out
, 0, sizeof(fmt_out
) );
338 fmt_out
.i_sar_den
= 1;
339 fmt_out
.i_chroma
= i_format
;
341 /* compute original width/height */
342 unsigned int i_original_width
;
343 unsigned int i_original_height
;
344 if( fmt_in
.i_sar_num
>= fmt_in
.i_sar_den
)
346 i_original_width
= (int64_t)fmt_in
.i_width
* fmt_in
.i_sar_num
/ fmt_in
.i_sar_den
;
347 i_original_height
= fmt_in
.i_height
;
351 i_original_width
= fmt_in
.i_width
;
352 i_original_height
= (int64_t)fmt_in
.i_height
* fmt_in
.i_sar_den
/ fmt_in
.i_sar_num
;
356 fmt_out
.i_width
= ( i_override_width
< 0 ) ?
357 i_original_width
: i_override_width
;
358 fmt_out
.i_height
= ( i_override_height
< 0 ) ?
359 i_original_height
: i_override_height
;
361 /* scale if only one direction is provided */
362 if( fmt_out
.i_height
== 0 && fmt_out
.i_width
> 0 )
364 fmt_out
.i_height
= fmt_in
.i_height
* fmt_out
.i_width
365 * fmt_in
.i_sar_den
/ fmt_in
.i_width
/ fmt_in
.i_sar_num
;
367 else if( fmt_out
.i_width
== 0 && fmt_out
.i_height
> 0 )
369 fmt_out
.i_width
= fmt_in
.i_width
* fmt_out
.i_height
370 * fmt_in
.i_sar_num
/ fmt_in
.i_height
/ fmt_in
.i_sar_den
;
373 image_handler_t
*p_image
= image_HandlerCreate( p_obj
);
375 block_t
*p_block
= image_Write( p_image
, p_picture
, &fmt_in
, &fmt_out
);
377 image_HandlerDelete( p_image
);
383 p_block
->i_dts
= p_picture
->date
;
392 void picture_BlendSubpicture(picture_t
*dst
,
393 filter_t
*blend
, subpicture_t
*src
)
395 assert(blend
&& dst
&& blend
->fmt_out
.video
.i_chroma
== dst
->format
.i_chroma
);
396 assert(src
&& !src
->b_fade
&& src
->b_absolute
);
398 for (subpicture_region_t
*r
= src
->p_region
; r
!= NULL
; r
= r
->p_next
) {
399 assert(r
->p_picture
&& r
->i_align
== 0);
400 if (filter_ConfigureBlend(blend
, dst
->format
.i_width
, dst
->format
.i_height
,
402 filter_Blend(blend
, dst
,
403 r
->i_x
, r
->i_y
, r
->p_picture
,
404 src
->i_alpha
* r
->i_alpha
/ 255)) {
405 msg_Err(blend
, "blending %4.4s to %4.4s failed",
406 (char *)&blend
->fmt_in
.video
.i_chroma
,
407 (char *)&blend
->fmt_out
.video
.i_chroma
);