1 /*****************************************************************************
2 * vout_pictures.c : picture management functions
3 *****************************************************************************
4 * Copyright (C) 2000-2004 the VideoLAN team
7 * Authors: Vincent Seguin <seguin@via.ecp.fr>
8 * Samuel Hocevar <sam@zoy.org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
34 #include <vlc_common.h>
37 #include <vlc_filter.h>
38 #include <vlc_image.h>
39 #include <vlc_block.h>
40 #include <vlc_picture_fifo.h>
41 #include <vlc_picture_pool.h>
43 #include "vout_internal.h"
46 * It retreives a picture from the vout or NULL if no pictures are
49 * You MUST call vout_PutPicture or vout_ReleasePicture on it.
51 * You may use vout_HoldPicture(paired with vout_ReleasePicture) to keep a
52 * read-only reference.
54 picture_t
*vout_GetPicture( vout_thread_t
*p_vout
)
57 vlc_mutex_lock( &p_vout
->p
->picture_lock
);
58 picture_t
*p_pic
= picture_pool_Get(p_vout
->p
->decoder_pool
);
63 vlc_mutex_unlock( &p_vout
->p
->picture_lock
);
69 * It gives to the vout a picture to be displayed.
71 * The given picture MUST comes from vout_GetPicture.
73 * Becareful, after vout_PutPicture is called, picture_t::p_next cannot be
76 void vout_PutPicture( vout_thread_t
*p_vout
, picture_t
*p_pic
)
78 vlc_mutex_lock( &p_vout
->p
->picture_lock
);
81 picture_fifo_Push(p_vout
->p
->decoder_fifo
, p_pic
);
83 vlc_mutex_unlock( &p_vout
->p
->picture_lock
);
85 vout_control_Wake( &p_vout
->p
->control
);
89 * It releases a picture retreived by vout_GetPicture.
91 void vout_ReleasePicture( vout_thread_t
*p_vout
, picture_t
*p_pic
)
93 vlc_mutex_lock( &p_vout
->p
->picture_lock
);
95 picture_Release( p_pic
);
97 vlc_mutex_unlock( &p_vout
->p
->picture_lock
);
99 vout_control_Wake( &p_vout
->p
->control
);
103 * It increment the reference counter of a picture retreived by
106 void vout_HoldPicture( vout_thread_t
*p_vout
, picture_t
*p_pic
)
108 vlc_mutex_lock( &p_vout
->p
->picture_lock
);
110 picture_Hold( p_pic
);
112 vlc_mutex_unlock( &p_vout
->p
->picture_lock
);
116 * Allocate a new picture in the heap.
118 * This function allocates a fake direct buffer in memory, which can be
119 * used exactly like a video buffer. The video output thread then manages
120 * how it gets displayed.
122 static int vout_AllocatePicture( picture_t
*p_pic
,
123 vlc_fourcc_t i_chroma
,
124 int i_width
, int i_height
,
125 int i_sar_num
, int i_sar_den
)
127 /* Make sure the real dimensions are a multiple of 16 */
128 if( picture_Setup( p_pic
, i_chroma
, i_width
, i_height
,
129 i_sar_num
, i_sar_den
) != VLC_SUCCESS
)
132 /* Calculate how big the new image should be */
134 for( int i
= 0; i
< p_pic
->i_planes
; i
++ )
136 const plane_t
*p
= &p_pic
->p
[i
];
138 if( p
->i_pitch
<= 0 || p
->i_lines
<= 0 ||
139 p
->i_pitch
> (SIZE_MAX
- i_bytes
)/p
->i_lines
)
144 i_bytes
+= p
->i_pitch
* p
->i_lines
;
147 uint8_t *p_data
= vlc_memalign( &p_pic
->p_data_orig
, 16, i_bytes
);
154 /* Fill the p_pixels field for each plane */
155 p_pic
->p
[0].p_pixels
= p_data
;
156 for( int i
= 1; i
< p_pic
->i_planes
; i
++ )
158 p_pic
->p
[i
].p_pixels
= &p_pic
->p
[i
-1].p_pixels
[ p_pic
->p
[i
-1].i_lines
*
159 p_pic
->p
[i
-1].i_pitch
];
165 /*****************************************************************************
167 *****************************************************************************/
168 static void PictureReleaseCallback( picture_t
*p_picture
)
170 if( --p_picture
->i_refcount
> 0 )
172 picture_Delete( p_picture
);
175 /*****************************************************************************
177 *****************************************************************************/
178 void picture_Reset( picture_t
*p_picture
)
181 p_picture
->date
= VLC_TS_INVALID
;
182 p_picture
->b_force
= false;
183 p_picture
->b_progressive
= false;
184 p_picture
->i_nb_fields
= 0;
185 p_picture
->b_top_field_first
= false;
186 picture_CleanupQuant( p_picture
);
189 /*****************************************************************************
191 *****************************************************************************/
192 static int LCM( int a
, int b
)
194 return a
* b
/ GCD( a
, b
);
197 int picture_Setup( picture_t
*p_picture
, vlc_fourcc_t i_chroma
,
198 int i_width
, int i_height
, int i_sar_num
, int i_sar_den
)
200 /* Store default values */
201 p_picture
->i_planes
= 0;
202 for( unsigned i
= 0; i
< VOUT_MAX_PLANES
; i
++ )
204 plane_t
*p
= &p_picture
->p
[i
];
206 p
->i_pixel_pitch
= 0;
209 p_picture
->pf_release
= NULL
;
210 p_picture
->p_release_sys
= NULL
;
211 p_picture
->i_refcount
= 0;
213 p_picture
->i_qtype
= QTYPE_NONE
;
214 p_picture
->i_qstride
= 0;
215 p_picture
->p_q
= NULL
;
217 video_format_Setup( &p_picture
->format
, i_chroma
, i_width
, i_height
,
218 i_sar_num
, i_sar_den
);
220 const vlc_chroma_description_t
*p_dsc
=
221 vlc_fourcc_GetChromaDescription( p_picture
->format
.i_chroma
);
225 /* We want V (width/height) to respect:
226 (V * p_dsc->p[i].w.i_num) % p_dsc->p[i].w.i_den == 0
227 (V * p_dsc->p[i].w.i_num/p_dsc->p[i].w.i_den * p_dsc->i_pixel_size) % 16 == 0
228 Which is respected if you have
229 V % lcm( p_dsc->p[0..planes].w.i_den * 16) == 0
234 for( unsigned i
= 0; i
< p_dsc
->plane_count
; i
++ )
236 i_modulo_w
= LCM( i_modulo_w
, 16 * p_dsc
->p
[i
].w
.den
);
237 i_modulo_h
= LCM( i_modulo_h
, 16 * p_dsc
->p
[i
].h
.den
);
238 if( i_ratio_h
< p_dsc
->p
[i
].h
.den
)
239 i_ratio_h
= p_dsc
->p
[i
].h
.den
;
242 const int i_width_aligned
= ( i_width
+ i_modulo_w
- 1 ) / i_modulo_w
* i_modulo_w
;
243 const int i_height_aligned
= ( i_height
+ i_modulo_h
- 1 ) / i_modulo_h
* i_modulo_h
;
244 const int i_height_extra
= 2 * i_ratio_h
; /* This one is a hack for some ASM functions */
245 for( unsigned i
= 0; i
< p_dsc
->plane_count
; i
++ )
247 plane_t
*p
= &p_picture
->p
[i
];
249 p
->i_lines
= (i_height_aligned
+ i_height_extra
) * p_dsc
->p
[i
].h
.num
/ p_dsc
->p
[i
].h
.den
;
250 p
->i_visible_lines
= i_height
* p_dsc
->p
[i
].h
.num
/ p_dsc
->p
[i
].h
.den
;
251 p
->i_pitch
= i_width_aligned
* p_dsc
->p
[i
].w
.num
/ p_dsc
->p
[i
].w
.den
* p_dsc
->pixel_size
;
252 p
->i_visible_pitch
= i_width
* p_dsc
->p
[i
].w
.num
/ p_dsc
->p
[i
].w
.den
* p_dsc
->pixel_size
;
253 p
->i_pixel_pitch
= p_dsc
->pixel_size
;
255 assert( (p
->i_pitch
% 16) == 0 );
257 p_picture
->i_planes
= p_dsc
->plane_count
;
262 /*****************************************************************************
264 *****************************************************************************/
265 picture_t
*picture_NewFromResource( const video_format_t
*p_fmt
, const picture_resource_t
*p_resource
)
267 video_format_t fmt
= *p_fmt
;
269 /* It is needed to be sure all information are filled */
270 video_format_Setup( &fmt
, p_fmt
->i_chroma
,
271 p_fmt
->i_width
, p_fmt
->i_height
,
272 p_fmt
->i_sar_num
, p_fmt
->i_sar_den
);
275 picture_t
*p_picture
= calloc( 1, sizeof(*p_picture
) );
281 if( picture_Setup( p_picture
, fmt
.i_chroma
, fmt
.i_width
, fmt
.i_height
,
282 fmt
.i_sar_num
, fmt
.i_sar_den
) )
287 p_picture
->p_sys
= p_resource
->p_sys
;
289 for( int i
= 0; i
< p_picture
->i_planes
; i
++ )
291 p_picture
->p
[i
].p_pixels
= p_resource
->p
[i
].p_pixels
;
292 p_picture
->p
[i
].i_lines
= p_resource
->p
[i
].i_lines
;
293 p_picture
->p
[i
].i_pitch
= p_resource
->p
[i
].i_pitch
;
298 if( vout_AllocatePicture( p_picture
,
299 fmt
.i_chroma
, fmt
.i_width
, fmt
.i_height
,
300 fmt
.i_sar_num
, fmt
.i_sar_den
) )
307 p_picture
->format
= fmt
;
308 p_picture
->i_refcount
= 1;
309 p_picture
->pf_release
= PictureReleaseCallback
;
313 picture_t
*picture_NewFromFormat( const video_format_t
*p_fmt
)
315 return picture_NewFromResource( p_fmt
, NULL
);
317 picture_t
*picture_New( vlc_fourcc_t i_chroma
, int i_width
, int i_height
, int i_sar_num
, int i_sar_den
)
321 memset( &fmt
, 0, sizeof(fmt
) );
322 video_format_Setup( &fmt
, i_chroma
, i_width
, i_height
,
323 i_sar_num
, i_sar_den
);
325 return picture_NewFromFormat( &fmt
);
328 /*****************************************************************************
330 *****************************************************************************/
331 void picture_Delete( picture_t
*p_picture
)
333 assert( p_picture
&& p_picture
->i_refcount
== 0 );
334 assert( p_picture
->p_release_sys
== NULL
);
336 free( p_picture
->p_q
);
337 free( p_picture
->p_data_orig
);
338 free( p_picture
->p_sys
);
342 /*****************************************************************************
344 *****************************************************************************/
345 void picture_CopyPixels( picture_t
*p_dst
, const picture_t
*p_src
)
349 for( i
= 0; i
< p_src
->i_planes
; i
++ )
350 plane_CopyPixels( p_dst
->p
+i
, p_src
->p
+i
);
353 void plane_CopyPixels( plane_t
*p_dst
, const plane_t
*p_src
)
355 const unsigned i_width
= __MIN( p_dst
->i_visible_pitch
,
356 p_src
->i_visible_pitch
);
357 const unsigned i_height
= __MIN( p_dst
->i_visible_lines
,
358 p_src
->i_visible_lines
);
360 if( p_src
->i_pitch
== p_dst
->i_pitch
)
362 /* There are margins, but with the same width : perfect ! */
363 vlc_memcpy( p_dst
->p_pixels
, p_src
->p_pixels
,
364 p_src
->i_pitch
* i_height
);
368 /* We need to proceed line by line */
369 uint8_t *p_in
= p_src
->p_pixels
;
370 uint8_t *p_out
= p_dst
->p_pixels
;
376 for( i_line
= i_height
; i_line
--; )
378 vlc_memcpy( p_out
, p_in
, i_width
);
379 p_in
+= p_src
->i_pitch
;
380 p_out
+= p_dst
->i_pitch
;
385 /*****************************************************************************
387 *****************************************************************************/
388 int picture_Export( vlc_object_t
*p_obj
,
390 video_format_t
*p_fmt
,
391 picture_t
*p_picture
,
392 vlc_fourcc_t i_format
,
393 int i_override_width
, int i_override_height
)
396 video_format_t fmt_in
= p_picture
->format
;
397 if( fmt_in
.i_sar_num
<= 0 || fmt_in
.i_sar_den
<= 0 )
400 fmt_in
.i_sar_den
= 1;
404 video_format_t fmt_out
;
405 memset( &fmt_out
, 0, sizeof(fmt_out
) );
407 fmt_out
.i_sar_den
= 1;
408 fmt_out
.i_chroma
= i_format
;
410 /* compute original width/height */
411 unsigned int i_original_width
;
412 unsigned int i_original_height
;
413 if( fmt_in
.i_sar_num
>= fmt_in
.i_sar_den
)
415 i_original_width
= fmt_in
.i_width
* fmt_in
.i_sar_num
/ fmt_in
.i_sar_den
;
416 i_original_height
= fmt_in
.i_height
;
420 i_original_width
= fmt_in
.i_width
;
421 i_original_height
= fmt_in
.i_height
* fmt_in
.i_sar_den
/ fmt_in
.i_sar_num
;
425 fmt_out
.i_width
= ( i_override_width
< 0 ) ?
426 i_original_width
: i_override_width
;
427 fmt_out
.i_height
= ( i_override_height
< 0 ) ?
428 i_original_height
: i_override_height
;
430 /* scale if only one direction is provided */
431 if( fmt_out
.i_height
== 0 && fmt_out
.i_width
> 0 )
433 fmt_out
.i_height
= fmt_in
.i_height
* fmt_out
.i_width
434 * fmt_in
.i_sar_den
/ fmt_in
.i_width
/ fmt_in
.i_sar_num
;
436 else if( fmt_out
.i_width
== 0 && fmt_out
.i_height
> 0 )
438 fmt_out
.i_width
= fmt_in
.i_width
* fmt_out
.i_height
439 * fmt_in
.i_sar_num
/ fmt_in
.i_height
/ fmt_in
.i_sar_den
;
442 image_handler_t
*p_image
= image_HandlerCreate( p_obj
);
444 block_t
*p_block
= image_Write( p_image
, p_picture
, &fmt_in
, &fmt_out
);
446 image_HandlerDelete( p_image
);
452 p_block
->i_dts
= p_picture
->date
;