]> git.sesse.net Git - vlc/blob - src/video_output/vout_pictures.c
Removed now useless vout_CountPictureAvailable.
[vlc] / src / video_output / vout_pictures.c
1 /*****************************************************************************
2  * vout_pictures.c : picture management functions
3  *****************************************************************************
4  * Copyright (C) 2000-2004 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Vincent Seguin <seguin@via.ecp.fr>
8  *          Samuel Hocevar <sam@zoy.org>
9  *
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.
14  *
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.
19  *
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  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32 #include <assert.h>
33
34 #include <vlc_common.h>
35 #include <libvlc.h>
36 #include <vlc_vout.h>
37 #include <vlc_osd.h>
38 #include <vlc_filter.h>
39 #include <vlc_image.h>
40 #include <vlc_block.h>
41 #include <vlc_picture_fifo.h>
42 #include <vlc_picture_pool.h>
43
44 #include "vout_pictures.h"
45 #include "vout_internal.h"
46
47 /**
48  * Display a picture
49  *
50  * Remove the reservation flag of a picture, which will cause it to be ready
51  * for display.
52  */
53 void vout_DisplayPicture( vout_thread_t *p_vout, picture_t *p_pic )
54 {
55     vlc_mutex_lock( &p_vout->p->picture_lock );
56
57     p_pic->p_next = NULL;
58     picture_fifo_Push(p_vout->p->decoder_fifo, p_pic);
59
60     vlc_cond_signal( &p_vout->p->picture_wait );
61     vlc_mutex_unlock( &p_vout->p->picture_lock );
62 }
63
64 /**
65  * Allocate a picture in the video output heap.
66  *
67  * This function creates a reserved image in the video output heap.
68  * A null pointer is returned if the function fails. This method provides an
69  * already allocated zone of memory in the picture data fields.
70  * It needs locking since several pictures can be created by several producers
71  * threads.
72  */
73 picture_t *vout_CreatePicture( vout_thread_t *p_vout,
74                                bool b_progressive,
75                                bool b_top_field_first,
76                                unsigned int i_nb_fields )
77 {
78 #warning "TODO remove unused vout_CreatePicture parameters"
79     /* Get lock */
80     vlc_mutex_lock( &p_vout->p->picture_lock );
81     picture_t *p_pic = picture_pool_Get(p_vout->p->decoder_pool);
82     if (p_pic) {
83         picture_Reset(p_pic);
84         p_pic->p_next = NULL; // FIXME put it in picture_Reset ?
85     }
86     vlc_mutex_unlock( &p_vout->p->picture_lock );
87
88     return p_pic;
89 }
90
91 /* */
92 void vout_DropPicture( vout_thread_t *p_vout, picture_t *p_pic  )
93 {
94     vlc_mutex_lock( &p_vout->p->picture_lock );
95
96     picture_Release( p_pic );
97
98     vlc_cond_signal( &p_vout->p->picture_wait );
99     vlc_mutex_unlock( &p_vout->p->picture_lock );
100 }
101
102 void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_pic )
103 {
104     vout_DropPicture( p_vout, p_pic );
105 }
106
107
108 /**
109  * Increment reference counter of a picture
110  *
111  * This function increments the reference counter of a picture in the video
112  * heap. It needs a lock since several producer threads can access the picture.
113  */
114 void vout_LinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
115 {
116     vlc_mutex_lock( &p_vout->p->picture_lock );
117     picture_Hold( p_pic );
118     vlc_mutex_unlock( &p_vout->p->picture_lock );
119 }
120
121 /**
122  * Decrement reference counter of a picture
123  *
124  * This function decrement the reference counter of a picture in the video heap
125  */
126 void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
127 {
128     vlc_mutex_lock( &p_vout->p->picture_lock );
129     picture_Release( p_pic );
130
131     vlc_cond_signal( &p_vout->p->picture_wait );
132     vlc_mutex_unlock( &p_vout->p->picture_lock );
133 }
134
135 /**
136  * Allocate a new picture in the heap.
137  *
138  * This function allocates a fake direct buffer in memory, which can be
139  * used exactly like a video buffer. The video output thread then manages
140  * how it gets displayed.
141  */
142 static int vout_AllocatePicture( picture_t *p_pic,
143                                  vlc_fourcc_t i_chroma,
144                                  int i_width, int i_height,
145                                  int i_sar_num, int i_sar_den )
146 {
147     /* Make sure the real dimensions are a multiple of 16 */
148     if( picture_Setup( p_pic, i_chroma, i_width, i_height,
149                        i_sar_num, i_sar_den ) != VLC_SUCCESS )
150         return VLC_EGENERIC;
151
152     /* Calculate how big the new image should be */
153     size_t i_bytes = 0;
154     for( int i = 0; i < p_pic->i_planes; i++ )
155     {
156         const plane_t *p = &p_pic->p[i];
157
158         if( p->i_pitch <= 0 || p->i_lines <= 0 ||
159             p->i_pitch > (SIZE_MAX - i_bytes)/p->i_lines )
160         {
161             p_pic->i_planes = 0;
162             return VLC_ENOMEM;
163         }
164         i_bytes += p->i_pitch * p->i_lines;
165     }
166
167     p_pic->p_data = vlc_memalign( &p_pic->p_data_orig, 16, i_bytes );
168     if( p_pic->p_data == NULL )
169     {
170         p_pic->i_planes = 0;
171         return VLC_EGENERIC;
172     }
173
174     /* Fill the p_pixels field for each plane */
175     p_pic->p[0].p_pixels = p_pic->p_data;
176     for( int i = 1; i < p_pic->i_planes; i++ )
177     {
178         p_pic->p[i].p_pixels = &p_pic->p[i-1].p_pixels[ p_pic->p[i-1].i_lines *
179                                                         p_pic->p[i-1].i_pitch ];
180     }
181
182     return VLC_SUCCESS;
183 }
184
185 /*****************************************************************************
186  *
187  *****************************************************************************/
188 static void PictureReleaseCallback( picture_t *p_picture )
189 {
190     if( --p_picture->i_refcount > 0 )
191         return;
192     picture_Delete( p_picture );
193 }
194
195 /*****************************************************************************
196  *
197  *****************************************************************************/
198 void picture_Reset( picture_t *p_picture )
199 {
200     /* */
201     p_picture->date = VLC_TS_INVALID;
202     p_picture->b_force = false;
203     p_picture->b_progressive = false;
204     p_picture->i_nb_fields = 0;
205     p_picture->b_top_field_first = false;
206     picture_CleanupQuant( p_picture );
207 }
208
209 /*****************************************************************************
210  *
211  *****************************************************************************/
212 typedef struct
213 {
214     unsigned     i_plane_count;
215     struct
216     {
217         struct
218         {
219             unsigned i_num;
220             unsigned i_den;
221         } w;
222         struct
223         {
224             unsigned i_num;
225             unsigned i_den;
226         } h;
227     } p[VOUT_MAX_PLANES];
228     unsigned i_pixel_size;
229
230 } chroma_description_t;
231
232 #define PLANAR(n, w_den, h_den) \
233     { n, { {{1,1}, {1,1}}, {{1,w_den}, {1,h_den}}, {{1,w_den}, {1,h_den}}, {{1,1}, {1,1}} }, 1 }
234 #define PACKED(size) \
235     { 1, { {{1,1}, {1,1}} }, size }
236
237 static const struct
238 {
239     vlc_fourcc_t            p_fourcc[5];
240     chroma_description_t    description;
241 } p_chromas[] = {
242     { { VLC_CODEC_I411, 0 },                                 PLANAR(3, 4, 1) },
243     { { VLC_CODEC_I410, VLC_CODEC_YV9, 0 },                  PLANAR(3, 4, 4) },
244     { { VLC_CODEC_YV12, VLC_CODEC_I420, VLC_CODEC_J420, 0 }, PLANAR(3, 2, 2) },
245     { { VLC_CODEC_I422, VLC_CODEC_J422, 0 },                 PLANAR(3, 2, 1) },
246     { { VLC_CODEC_I440, VLC_CODEC_J440, 0 },                 PLANAR(3, 1, 2) },
247     { { VLC_CODEC_I444, VLC_CODEC_J444, 0 },                 PLANAR(3, 1, 1) },
248     { { VLC_CODEC_YUVA, 0 },                                 PLANAR(4, 1, 1) },
249
250     { { VLC_CODEC_UYVY, VLC_CODEC_VYUY, VLC_CODEC_YUYV, VLC_CODEC_YVYU, 0 }, PACKED(2) },
251     { { VLC_CODEC_RGB8, VLC_CODEC_GREY, VLC_CODEC_YUVP, VLC_CODEC_RGBP, 0 }, PACKED(1) },
252     { { VLC_CODEC_RGB16, VLC_CODEC_RGB15, 0 },                               PACKED(2) },
253     { { VLC_CODEC_RGB24, 0 },                                                PACKED(3) },
254     { { VLC_CODEC_RGB32, VLC_CODEC_RGBA, 0 },                                PACKED(4) },
255
256     { { VLC_CODEC_Y211, 0 }, { 1, { {{1,4}, {1,1}} }, 4 } },
257
258     { {0}, { 0, {}, 0 } }
259 };
260
261 #undef PACKED
262 #undef PLANAR
263
264 static const chroma_description_t *vlc_fourcc_GetChromaDescription( vlc_fourcc_t i_fourcc )
265 {
266     for( unsigned i = 0; p_chromas[i].p_fourcc[0]; i++ )
267     {
268         const vlc_fourcc_t *p_fourcc = p_chromas[i].p_fourcc;
269         for( unsigned j = 0; p_fourcc[j]; j++ )
270         {
271             if( p_fourcc[j] == i_fourcc )
272                 return &p_chromas[i].description;
273         }
274     }
275     return NULL;
276 }
277
278 static int LCM( int a, int b )
279 {
280     return a * b / GCD( a, b );
281 }
282
283 int picture_Setup( picture_t *p_picture, vlc_fourcc_t i_chroma,
284                    int i_width, int i_height, int i_sar_num, int i_sar_den )
285 {
286     /* Store default values */
287     p_picture->i_planes = 0;
288     for( unsigned i = 0; i < VOUT_MAX_PLANES; i++ )
289     {
290         plane_t *p = &p_picture->p[i];
291         p->p_pixels = NULL;
292         p->i_pixel_pitch = 0;
293     }
294
295     p_picture->pf_release = NULL;
296     p_picture->p_release_sys = NULL;
297     p_picture->i_refcount = 0;
298
299     p_picture->i_qtype = QTYPE_NONE;
300     p_picture->i_qstride = 0;
301     p_picture->p_q = NULL;
302
303     video_format_Setup( &p_picture->format, i_chroma, i_width, i_height,
304                         i_sar_num, i_sar_den );
305
306     const chroma_description_t *p_dsc =
307         vlc_fourcc_GetChromaDescription( p_picture->format.i_chroma );
308     if( !p_dsc )
309         return VLC_EGENERIC;
310
311     /* We want V (width/height) to respect:
312         (V * p_dsc->p[i].w.i_num) % p_dsc->p[i].w.i_den == 0
313         (V * p_dsc->p[i].w.i_num/p_dsc->p[i].w.i_den * p_dsc->i_pixel_size) % 16 == 0
314        Which is respected if you have
315        V % lcm( p_dsc->p[0..planes].w.i_den * 16) == 0
316     */
317     int i_modulo_w = 1;
318     int i_modulo_h = 1;
319     int i_ratio_h  = 1;
320     for( unsigned i = 0; i < p_dsc->i_plane_count; i++ )
321     {
322         i_modulo_w = LCM( i_modulo_w, 16 * p_dsc->p[i].w.i_den );
323         i_modulo_h = LCM( i_modulo_h, 16 * p_dsc->p[i].h.i_den );
324         if( i_ratio_h < p_dsc->p[i].h.i_den )
325             i_ratio_h = p_dsc->p[i].h.i_den;
326     }
327
328     const int i_width_aligned  = ( i_width  + i_modulo_w - 1 ) / i_modulo_w * i_modulo_w;
329     const int i_height_aligned = ( i_height + i_modulo_h - 1 ) / i_modulo_h * i_modulo_h;
330     const int i_height_extra   = 2 * i_ratio_h; /* This one is a hack for some ASM functions */
331     for( unsigned i = 0; i < p_dsc->i_plane_count; i++ )
332     {
333         plane_t *p = &p_picture->p[i];
334
335         p->i_lines         = (i_height_aligned + i_height_extra ) * p_dsc->p[i].h.i_num / p_dsc->p[i].h.i_den;
336         p->i_visible_lines = i_height * p_dsc->p[i].h.i_num / p_dsc->p[i].h.i_den;
337         p->i_pitch         = i_width_aligned * p_dsc->p[i].w.i_num / p_dsc->p[i].w.i_den * p_dsc->i_pixel_size;
338         p->i_visible_pitch = i_width * p_dsc->p[i].w.i_num / p_dsc->p[i].w.i_den * p_dsc->i_pixel_size;
339         p->i_pixel_pitch   = p_dsc->i_pixel_size;
340
341         assert( (p->i_pitch % 16) == 0 );
342     }
343     p_picture->i_planes  = p_dsc->i_plane_count;
344
345     return VLC_SUCCESS;
346 }
347
348 /*****************************************************************************
349  *
350  *****************************************************************************/
351 picture_t *picture_NewFromResource( const video_format_t *p_fmt, const picture_resource_t *p_resource )
352 {
353     video_format_t fmt = *p_fmt;
354
355     /* It is needed to be sure all informations are filled */
356     video_format_Setup( &fmt, p_fmt->i_chroma,
357                               p_fmt->i_width, p_fmt->i_height,
358                               p_fmt->i_sar_num, p_fmt->i_sar_den );
359
360     /* */
361     picture_t *p_picture = calloc( 1, sizeof(*p_picture) );
362     if( !p_picture )
363         return NULL;
364
365     if( p_resource )
366     {
367         if( picture_Setup( p_picture, fmt.i_chroma, fmt.i_width, fmt.i_height,
368                            fmt.i_sar_num, fmt.i_sar_den ) )
369         {
370             free( p_picture );
371             return NULL;
372         }
373         p_picture->p_sys = p_resource->p_sys;
374
375         for( int i = 0; i < p_picture->i_planes; i++ )
376         {
377             p_picture->p[i].p_pixels = p_resource->p[i].p_pixels;
378             p_picture->p[i].i_lines  = p_resource->p[i].i_lines;
379             p_picture->p[i].i_pitch  = p_resource->p[i].i_pitch;
380         }
381     }
382     else
383     {
384         if( vout_AllocatePicture( p_picture,
385                                   fmt.i_chroma, fmt.i_width, fmt.i_height,
386                                   fmt.i_sar_num, fmt.i_sar_den ) )
387         {
388             free( p_picture );
389             return NULL;
390         }
391     }
392     /* */
393     p_picture->format = fmt;
394     p_picture->i_refcount = 1;
395     p_picture->pf_release = PictureReleaseCallback;
396     p_picture->i_status = RESERVED_PICTURE;
397
398     return p_picture;
399 }
400 picture_t *picture_NewFromFormat( const video_format_t *p_fmt )
401 {
402     return picture_NewFromResource( p_fmt, NULL );
403 }
404 picture_t *picture_New( vlc_fourcc_t i_chroma, int i_width, int i_height, int i_sar_num, int i_sar_den )
405 {
406     video_format_t fmt;
407
408     memset( &fmt, 0, sizeof(fmt) );
409     video_format_Setup( &fmt, i_chroma, i_width, i_height,
410                         i_sar_num, i_sar_den );
411
412     return picture_NewFromFormat( &fmt );
413 }
414
415 /*****************************************************************************
416  *
417  *****************************************************************************/
418 void picture_Delete( picture_t *p_picture )
419 {
420     assert( p_picture && p_picture->i_refcount == 0 );
421     assert( p_picture->p_release_sys == NULL );
422
423     free( p_picture->p_q );
424     free( p_picture->p_data_orig );
425     free( p_picture->p_sys );
426     free( p_picture );
427 }
428
429 /*****************************************************************************
430  *
431  *****************************************************************************/
432 void picture_CopyPixels( picture_t *p_dst, const picture_t *p_src )
433 {
434     int i;
435
436     for( i = 0; i < p_src->i_planes ; i++ )
437         plane_CopyPixels( p_dst->p+i, p_src->p+i );
438 }
439
440 void plane_CopyPixels( plane_t *p_dst, const plane_t *p_src )
441 {
442     const unsigned i_width  = __MIN( p_dst->i_visible_pitch,
443                                      p_src->i_visible_pitch );
444     const unsigned i_height = __MIN( p_dst->i_visible_lines,
445                                      p_src->i_visible_lines );
446
447     if( p_src->i_pitch == p_dst->i_pitch )
448     {
449         /* There are margins, but with the same width : perfect ! */
450         vlc_memcpy( p_dst->p_pixels, p_src->p_pixels,
451                     p_src->i_pitch * i_height );
452     }
453     else
454     {
455         /* We need to proceed line by line */
456         uint8_t *p_in = p_src->p_pixels;
457         uint8_t *p_out = p_dst->p_pixels;
458         int i_line;
459
460         assert( p_in );
461         assert( p_out );
462
463         for( i_line = i_height; i_line--; )
464         {
465             vlc_memcpy( p_out, p_in, i_width );
466             p_in += p_src->i_pitch;
467             p_out += p_dst->i_pitch;
468         }
469     }
470 }
471
472 /*****************************************************************************
473  *
474  *****************************************************************************/
475 int picture_Export( vlc_object_t *p_obj,
476                     block_t **pp_image,
477                     video_format_t *p_fmt,
478                     picture_t *p_picture,
479                     vlc_fourcc_t i_format,
480                     int i_override_width, int i_override_height )
481 {
482     /* */
483     video_format_t fmt_in = p_picture->format;
484     if( fmt_in.i_sar_num <= 0 || fmt_in.i_sar_den <= 0 )
485     {
486         fmt_in.i_sar_num =
487         fmt_in.i_sar_den = 1;
488     }
489
490     /* */
491     video_format_t fmt_out;
492     memset( &fmt_out, 0, sizeof(fmt_out) );
493     fmt_out.i_sar_num =
494     fmt_out.i_sar_den = 1;
495     fmt_out.i_chroma  = i_format;
496
497     /* compute original width/height */
498     unsigned int i_original_width;
499     unsigned int i_original_height;
500     if( fmt_in.i_sar_num >= fmt_in.i_sar_den )
501     {
502         i_original_width = fmt_in.i_width * fmt_in.i_sar_num / fmt_in.i_sar_den;
503         i_original_height = fmt_in.i_height;
504     }
505     else
506     {
507         i_original_width =  fmt_in.i_width;
508         i_original_height = fmt_in.i_height * fmt_in.i_sar_den / fmt_in.i_sar_num;
509     }
510
511     /* */
512     fmt_out.i_width  = ( i_override_width < 0 ) ?
513                        i_original_width : i_override_width;
514     fmt_out.i_height = ( i_override_height < 0 ) ?
515                        i_original_height : i_override_height;
516
517     /* scale if only one direction is provided */
518     if( fmt_out.i_height == 0 && fmt_out.i_width > 0 )
519     {
520         fmt_out.i_height = fmt_in.i_height * fmt_out.i_width
521                      * fmt_in.i_sar_den / fmt_in.i_width / fmt_in.i_sar_num;
522     }
523     else if( fmt_out.i_width == 0 && fmt_out.i_height > 0 )
524     {
525         fmt_out.i_width  = fmt_in.i_width * fmt_out.i_height
526                      * fmt_in.i_sar_num / fmt_in.i_height / fmt_in.i_sar_den;
527     }
528
529     image_handler_t *p_image = image_HandlerCreate( p_obj );
530
531     block_t *p_block = image_Write( p_image, p_picture, &fmt_in, &fmt_out );
532
533     image_HandlerDelete( p_image );
534
535     if( !p_block )
536         return VLC_EGENERIC;
537
538     p_block->i_pts =
539     p_block->i_dts = p_picture->date;
540
541     if( p_fmt )
542         *p_fmt = fmt_out;
543     *pp_image = p_block;
544
545     return VLC_SUCCESS;
546 }
547