]> git.sesse.net Git - vlc/blob - src/video_output/vout_pictures.c
* ./BUGS: added a list of known bugs. Please add your findings!
[vlc] / src / video_output / vout_pictures.c
1 /*****************************************************************************
2  * vout_pictures.c : picture management functions
3  *****************************************************************************
4  * Copyright (C) 2000 VideoLAN
5  * $Id: vout_pictures.c,v 1.8 2002/01/04 14:01:35 sam Exp $
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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <errno.h>                                                 /* ENOMEM */
29 #include <stdlib.h>                                                /* free() */
30 #include <stdio.h>                                              /* sprintf() */
31 #include <string.h>                                            /* strerror() */
32
33 #include <videolan/vlc.h>
34
35 #include "video.h"
36 #include "video_output.h"
37
38 /*****************************************************************************
39  * vout_DisplayPicture: display a picture
40  *****************************************************************************
41  * Remove the reservation flag of a picture, which will cause it to be ready for
42  * display. The picture won't be displayed until vout_DatePicture has been
43  * called.
44  *****************************************************************************/
45 void vout_DisplayPicture( vout_thread_t *p_vout, picture_t *p_pic )
46 {
47     vlc_mutex_lock( &p_vout->picture_lock );
48     switch( p_pic->i_status )
49     {
50     case RESERVED_PICTURE:
51         p_pic->i_status = RESERVED_DISP_PICTURE;
52         break;
53     case RESERVED_DATED_PICTURE:
54         p_pic->i_status = READY_PICTURE;
55         break;
56 #ifdef DEBUG
57     default:
58         intf_ErrMsg( "error: picture %p has invalid status %d",
59                      p_pic, p_pic->i_status );
60         break;
61 #endif
62     }
63
64 #ifdef TRACE_VOUT
65     intf_DbgMsg("picture %p", p_pic);
66 #endif
67     vlc_mutex_unlock( &p_vout->picture_lock );
68 }
69
70 /*****************************************************************************
71  * vout_DatePicture: date a picture
72  *****************************************************************************
73  * Remove the reservation flag of a picture, which will cause it to be ready
74  * for display. The picture won't be displayed until vout_DisplayPicture has
75  * been called.
76  *****************************************************************************/
77 void vout_DatePicture( vout_thread_t *p_vout,
78                        picture_t *p_pic, mtime_t date )
79 {
80 #ifdef TRACE_VOUT
81     char        psz_date[ MSTRTIME_MAX_SIZE ];                       /* date */
82 #endif
83
84     vlc_mutex_lock( &p_vout->picture_lock );
85     p_pic->date = date;
86     switch( p_pic->i_status )
87     {
88     case RESERVED_PICTURE:
89         p_pic->i_status = RESERVED_DATED_PICTURE;
90         break;
91     case RESERVED_DISP_PICTURE:
92         p_pic->i_status = READY_PICTURE;
93         break;
94 #ifdef DEBUG
95     default:
96         intf_ErrMsg( "error: picture %p has invalid status %d",
97                      p_pic, p_pic->i_status );
98         break;
99 #endif
100     }
101
102 #ifdef TRACE_VOUT
103     intf_DbgMsg( "picture %p, display date: %s",
104                  p_pic, mstrtime( psz_date, p_pic->date) );
105 #endif
106     vlc_mutex_unlock( &p_vout->picture_lock );
107 }
108
109 /*****************************************************************************
110  * vout_CreatePicture: allocate a picture in the video output heap.
111  *****************************************************************************
112  * This function creates a reserved image in the video output heap.
113  * A null pointer is returned if the function fails. This method provides an
114  * already allocated zone of memory in the picture data fields. It needs locking
115  * since several pictures can be created by several producers threads.
116  *****************************************************************************/
117 picture_t *vout_CreatePicture( vout_thread_t *p_vout,
118                                boolean_t b_progressive,
119                                boolean_t b_top_field_first,
120                                boolean_t b_repeat_first_field )
121 {
122     int         i_pic;                                      /* picture index */
123     picture_t * p_pic;
124     picture_t * p_freepic = NULL;                      /* first free picture */
125
126     /* Get lock */
127     vlc_mutex_lock( &p_vout->picture_lock );
128
129     /*
130      * Look for an empty place. We start at 1 because the first
131      * directbuffer is reserved for memcpy()ed pictures.
132      */
133     for( i_pic = 0; i_pic < I_RENDERPICTURES && p_freepic == NULL; i_pic++ )
134     {
135         p_pic = PP_RENDERPICTURE[ i_pic ];
136
137         /* If the picture we found is a memory buffer, and we might have
138          * enough room later for a direct buffer, skip it. If no other
139          * pictures are found, the video decoder will try again later. */
140         if( p_vout->b_direct && ( p_vout->output.i_pictures > 3 )
141              && ( p_pic->i_type != DIRECT_PICTURE ) )
142         {
143             break;
144         }
145
146         switch( p_pic->i_status )
147         {
148             case DESTROYED_PICTURE:
149                 /* Memory will not be reallocated, and function can end
150                  * immediately - this is the best possible case, since no
151                  * memory allocation needs to be done */
152                 p_pic->i_status   = RESERVED_PICTURE;
153                 p_pic->i_refcount = 0;
154
155                 p_pic->b_progressive        = b_progressive;
156                 p_pic->b_repeat_first_field = b_repeat_first_field;
157                 p_pic->b_top_field_first    = b_top_field_first;
158
159                 p_vout->i_heap_size++;
160                 vlc_mutex_unlock( &p_vout->picture_lock );
161                 return( p_pic );
162
163             case FREE_PICTURE:
164                 /* Picture is empty and ready for allocation */
165                 p_freepic = p_pic;
166                 break;
167
168             default:
169                 break;
170         }
171     }
172
173     /*
174      * Prepare picture
175      */
176     if( p_freepic != NULL )
177     {
178         vout_AllocatePicture( p_freepic,
179                               p_vout->render.i_width, p_vout->render.i_height,
180                               p_vout->render.i_chroma );
181
182         if( p_freepic->i_planes )
183         {
184             /* Copy picture information, set some default values */
185             p_freepic->i_status   = RESERVED_PICTURE;
186             p_freepic->i_type     = MEMORY_PICTURE;
187
188             p_freepic->i_refcount = 0;
189
190             p_freepic->b_progressive        = b_progressive;
191             p_freepic->b_repeat_first_field = b_repeat_first_field;
192             p_freepic->b_top_field_first    = b_top_field_first;
193
194             p_freepic->i_matrix_coefficients = 1;
195
196             p_vout->i_heap_size++;
197         }
198         else
199         {
200             /* Memory allocation failed : set picture as empty */
201             p_freepic->i_status = FREE_PICTURE;
202             p_freepic = NULL;
203
204             intf_ErrMsg( "vout error: picture allocation failed" );
205         }
206
207         vlc_mutex_unlock( &p_vout->picture_lock );
208
209         /* Initialize mutex */
210         vlc_mutex_init( &(p_freepic->lock_deccount) );
211
212         return( p_freepic );
213     }
214
215     /* No free or destroyed picture could be found, but the decoder
216      * will try again in a while. */
217     vlc_mutex_unlock( &p_vout->picture_lock );
218
219     return( NULL );
220 }
221
222 /*****************************************************************************
223  * vout_DestroyPicture: remove a permanent or reserved picture from the heap
224  *****************************************************************************
225  * This function frees a previously reserved picture or a permanent
226  * picture. It is meant to be used when the construction of a picture aborted.
227  * Note that the picture will be destroyed even if it is linked !
228  *****************************************************************************/
229 void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_pic )
230 {
231     vlc_mutex_lock( &p_vout->picture_lock );
232
233 #ifdef DEBUG
234     /* Check if picture status is valid */
235     if( (p_pic->i_status != RESERVED_PICTURE) &&
236         (p_pic->i_status != RESERVED_DATED_PICTURE) &&
237         (p_pic->i_status != RESERVED_DISP_PICTURE) )
238     {
239         intf_ErrMsg( "error: picture %p has invalid status %d",
240                      p_pic, p_pic->i_status );
241     }
242 #endif
243
244     p_pic->i_status = DESTROYED_PICTURE;
245     p_vout->i_heap_size--;
246
247     /* destroy the lock that had been initialized in CreatePicture */
248     vlc_mutex_destroy( &(p_pic->lock_deccount) );
249
250     vlc_mutex_unlock( &p_vout->picture_lock );
251 }
252
253 /*****************************************************************************
254  * vout_LinkPicture: increment reference counter of a picture
255  *****************************************************************************
256  * This function increments the reference counter of a picture in the video
257  * heap. It needs a lock since several producer threads can access the picture.
258  *****************************************************************************/
259 void vout_LinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
260 {
261     vlc_mutex_lock( &p_vout->picture_lock );
262     p_pic->i_refcount++;
263
264 #ifdef TRACE_VOUT
265     intf_DbgMsg( "picture %p refcount=%d", p_pic, p_pic->i_refcount );
266 #endif
267
268     vlc_mutex_unlock( &p_vout->picture_lock );
269 }
270
271 /*****************************************************************************
272  * vout_UnlinkPicture: decrement reference counter of a picture
273  *****************************************************************************
274  * This function decrement the reference counter of a picture in the video heap.
275  *****************************************************************************/
276 void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
277 {
278     vlc_mutex_lock( &p_vout->picture_lock );
279     p_pic->i_refcount--;
280
281 #ifdef TRACE_VOUT
282     if( p_pic->i_refcount < 0 )
283     {
284         intf_DbgMsg( "error: refcount < 0" );
285         p_pic->i_refcount = 0;
286     }
287 #endif
288
289     if( ( p_pic->i_refcount == 0 ) &&
290         ( p_pic->i_status == DISPLAYED_PICTURE ) )
291     {
292         p_pic->i_status = DESTROYED_PICTURE;
293         p_vout->i_heap_size--;
294     }
295
296 #ifdef TRACE_VOUT
297     intf_DbgMsg( "picture %p refcount=%d", p_pic, p_pic->i_refcount );
298 #endif
299
300     vlc_mutex_unlock( &p_vout->picture_lock );
301 }
302
303 /*****************************************************************************
304  * vout_RenderPicture: render a picture
305  *****************************************************************************
306  * This function chooses whether the current picture needs to be copied
307  * before rendering, does the subpicture magic, and tells the video output
308  * thread which direct buffer needs to be displayed.
309  *****************************************************************************/
310 picture_t * vout_RenderPicture( vout_thread_t *p_vout, picture_t *p_pic,
311                                                        subpicture_t *p_subpic )
312 {
313     if( p_pic == NULL )
314     {
315         /* XXX: subtitles */
316
317         return NULL;
318     }
319
320     if( p_pic->i_type == DIRECT_PICTURE )
321     {
322         if( p_pic->i_refcount )
323         {
324             /* Picture is in a direct buffer and is still in use,
325              * we need to copy it to another direct buffer before
326              * displaying it if there are subtitles. */
327             if( p_subpic != NULL )
328             {
329                     //printf("memcpy (refcount != 0)\n");
330                 /* We have subtitles. First copy the picture to
331                  * the spare direct buffer, then render the
332                  * subtitles. */
333                 vout_CopyPicture( p_pic, PP_OUTPUTPICTURE[0] );
334
335                 vout_RenderSubPictures( p_vout, PP_OUTPUTPICTURE[0], p_subpic );
336
337                 return PP_OUTPUTPICTURE[0];
338             }
339
340             /* No subtitles, picture is in a directbuffer so
341              * we can display it directly even if it is still
342              * in use. */
343                     //printf("direct (refcount == 0)\n");
344             return p_pic;
345         }
346
347         /* Picture is in a direct buffer but isn't used by the
348          * decoder. We can safely render subtitles on it and
349          * display it. */
350                     //printf("direct (refcount == 0)\n");
351         vout_RenderSubPictures( p_vout, p_pic, p_subpic );
352
353         return p_pic;
354     }
355
356     /* Not a direct buffer. We either need to copy it to a direct buffer,
357      * or render it if the chroma isn't the same. */
358     if( p_vout->b_direct )
359     {
360         /* Picture is not in a direct buffer, but is exactly the
361          * same size as the direct buffers. A memcpy() is enough,
362          * then render the subtitles. */
363                     //printf("memcpy (not a direct buffer)\n");
364         vout_CopyPicture( p_pic, PP_OUTPUTPICTURE[0] );
365
366         vout_RenderSubPictures( p_vout, PP_OUTPUTPICTURE[0], p_subpic );
367
368         return PP_OUTPUTPICTURE[0];
369     }
370
371     /* Picture is not in a direct buffer, and needs to be converted to
372      * another size/chroma. Then the subtitles need to be rendered as
373      * well. */
374
375     /* This usually means software YUV, or hardware YUV with a
376      * different chroma. */
377
378     /* XXX: render to the first direct buffer */
379                     //printf("render (not a direct buffer)\n");
380     p_vout->chroma.pf_convert( p_vout, p_pic, &p_vout->p_picture[0] );
381
382     vout_RenderSubPictures( p_vout, p_pic, p_subpic );
383
384     return &p_vout->p_picture[0];
385 }
386
387 /*****************************************************************************
388  * vout_PlacePicture: calculate image window coordinates
389  *****************************************************************************
390  * This function will be accessed by plugins. It calculates the relative
391  * position of the output window and the image window.
392  *****************************************************************************/
393 void vout_PlacePicture( vout_thread_t *p_vout, int i_width, int i_height,
394                         int *pi_x, int *pi_y, int *pi_width, int *pi_height )
395 {
396     if( p_vout->b_scale )
397     {
398         *pi_width = i_width;
399         *pi_height = i_height;
400     }
401     else
402     {
403         *pi_width = MIN( i_width, p_vout->render.i_width );
404         *pi_height = MIN( i_height, p_vout->render.i_height );
405     }
406
407     if( VOUT_ASPECT_FACTOR * *pi_width / *pi_height < p_vout->render.i_aspect )
408     {
409         *pi_width = *pi_height * p_vout->render.i_aspect / VOUT_ASPECT_FACTOR;
410     }
411     else
412     {
413         *pi_height = *pi_width * VOUT_ASPECT_FACTOR / p_vout->render.i_aspect;
414     }
415
416     if( *pi_width > i_width )
417     {
418         *pi_width = i_width;
419         *pi_height = VOUT_ASPECT_FACTOR * *pi_width / p_vout->render.i_aspect;
420     }
421
422     if( *pi_height > i_height )
423     {
424         *pi_height = i_height;
425         *pi_width = *pi_height * p_vout->render.i_aspect / VOUT_ASPECT_FACTOR;
426     }
427
428     *pi_x = ( i_width - *pi_width ) / 2;
429     *pi_y = ( i_height - *pi_height ) / 2;
430 }
431
432 /*****************************************************************************
433  * vout_AllocatePicture: allocate a new picture in the heap.
434  *****************************************************************************
435  * This function allocates a fake direct buffer in memory, which can be
436  * used exactly like a video buffer. The video output thread then manages
437  * how it gets displayed.
438  *****************************************************************************/
439 void vout_AllocatePicture( picture_t *p_pic,
440                            int i_width, int i_height, u32 i_chroma )
441 {
442     int i_bytes, i_index;
443
444     /* Store default values */
445     for( i_index = 0; i_index < VOUT_MAX_PLANES; i_index++ )
446     {
447         p_pic->p[i_index].p_pixels = NULL;
448         p_pic->p[i_index].b_margin = 0;
449         p_pic->p[i_index].i_pixel_bytes = 1;
450     }
451
452     /* Calculate coordinates */
453     switch( i_chroma )
454     {
455         case FOURCC_YV12:
456         case FOURCC_I420:
457         case FOURCC_IYUV:
458             p_pic->p[ Y_PLANE ].i_lines = i_height;
459             p_pic->p[ Y_PLANE ].i_pitch = i_width;
460             p_pic->p[ U_PLANE ].i_lines = i_height / 2;
461             p_pic->p[ U_PLANE ].i_pitch = i_width / 2;
462             p_pic->p[ V_PLANE ].i_lines = i_height / 2;
463             p_pic->p[ V_PLANE ].i_pitch = i_width / 2;
464             p_pic->i_planes = 3;
465             break;
466
467         case FOURCC_I422:
468             p_pic->p[ Y_PLANE ].i_lines = i_height;
469             p_pic->p[ Y_PLANE ].i_pitch = i_width;
470             p_pic->p[ U_PLANE ].i_lines = i_height;
471             p_pic->p[ U_PLANE ].i_pitch = i_width / 2;
472             p_pic->p[ V_PLANE ].i_lines = i_height;
473             p_pic->p[ V_PLANE ].i_pitch = i_width / 2;
474             p_pic->i_planes = 3;
475             break;
476
477         case FOURCC_I444:
478             p_pic->p[ Y_PLANE ].i_lines = i_height;
479             p_pic->p[ Y_PLANE ].i_pitch = i_width;
480             p_pic->p[ U_PLANE ].i_lines = i_height;
481             p_pic->p[ U_PLANE ].i_pitch = i_width;
482             p_pic->p[ V_PLANE ].i_lines = i_height;
483             p_pic->p[ V_PLANE ].i_pitch = i_width;
484             p_pic->i_planes = 3;
485             break;
486
487         case FOURCC_Y211:
488             p_pic->p->i_lines = i_height;
489             p_pic->p->i_pitch = i_width;
490             p_pic->i_planes = 1;
491             break;
492
493         case FOURCC_RV15:
494             p_pic->p->i_lines = i_height;
495             p_pic->p->i_pitch = i_width * 2;
496             p_pic->p->i_pixel_bytes = 2;
497             p_pic->p->i_red_mask =   0x001f;
498             p_pic->p->i_green_mask = 0x03e0;
499             p_pic->p->i_blue_mask =  0x7c00;
500             p_pic->i_planes = 1;
501             break;
502
503         case FOURCC_RV16:
504             p_pic->p->i_lines = i_height;
505             p_pic->p->i_pitch = i_width * 2;
506             p_pic->p->i_pixel_bytes = 2;
507             p_pic->p->i_red_mask =   0x001f;
508             p_pic->p->i_green_mask = 0x07e0;
509             p_pic->p->i_blue_mask =  0xf800;
510             p_pic->i_planes = 1;
511             break;
512
513         default:
514             intf_ErrMsg( "vout error: unknown chroma type %.8x", i_chroma );
515             p_pic->i_planes = 0;
516             return;
517     }
518
519     /* Calculate how big the new image should be */
520     for( i_bytes = 0, i_index = 0; i_index < p_pic->i_planes; i_index++ )
521     {
522         i_bytes += p_pic->p[ i_index ].i_lines * p_pic->p[ i_index ].i_pitch;
523     }
524
525     p_pic->p_data = memalign( 16, i_bytes );
526
527     if( p_pic->p_data == NULL )
528     {
529         p_pic->i_planes = 0;
530         return;
531     }
532
533     /* Fill the p_pixels field for each plane */
534     p_pic->p[ 0 ].p_pixels = p_pic->p_data;
535
536     for( i_index = 1; i_index < p_pic->i_planes; i_index++ )
537     {
538         p_pic->p[i_index].p_pixels = p_pic->p[i_index-1].p_pixels
539                                           + p_pic->p[i_index-1].i_lines
540                                              * p_pic->p[i_index-1].i_pitch;
541     }
542 }
543