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