]> git.sesse.net Git - vlc/blob - src/video_output/vout_pictures.c
* ./plugins/dummy/dummy.c: added --dummy-chroma option.
[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.24 2002/05/20 19:02:22 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  * Local prototypes
40  *****************************************************************************/
41 static void vout_CopyPicture( picture_t *p_src, picture_t *p_dest );
42
43 /*****************************************************************************
44  * vout_DisplayPicture: display a picture
45  *****************************************************************************
46  * Remove the reservation flag of a picture, which will cause it to be ready for
47  * display. The picture won't be displayed until vout_DatePicture has been
48  * called.
49  *****************************************************************************/
50 void vout_DisplayPicture( vout_thread_t *p_vout, picture_t *p_pic )
51 {
52     vlc_mutex_lock( &p_vout->picture_lock );
53     switch( p_pic->i_status )
54     {
55     case RESERVED_PICTURE:
56         p_pic->i_status = RESERVED_DISP_PICTURE;
57         break;
58     case RESERVED_DATED_PICTURE:
59         p_pic->i_status = READY_PICTURE;
60         break;
61     default:
62         intf_ErrMsg( "error: picture %p has invalid status %d",
63                      p_pic, p_pic->i_status );
64         break;
65     }
66
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     vlc_mutex_lock( &p_vout->picture_lock );
81     p_pic->date = date;
82     switch( p_pic->i_status )
83     {
84     case RESERVED_PICTURE:
85         p_pic->i_status = RESERVED_DATED_PICTURE;
86         break;
87     case RESERVED_DISP_PICTURE:
88         p_pic->i_status = READY_PICTURE;
89         break;
90     default:
91         intf_ErrMsg( "error: picture %p has invalid status %d",
92                      p_pic, p_pic->i_status );
93         break;
94     }
95
96     vlc_mutex_unlock( &p_vout->picture_lock );
97 }
98
99 /*****************************************************************************
100  * vout_CreatePicture: allocate a picture in the video output heap.
101  *****************************************************************************
102  * This function creates a reserved image in the video output heap.
103  * A null pointer is returned if the function fails. This method provides an
104  * already allocated zone of memory in the picture data fields. It needs locking
105  * since several pictures can be created by several producers threads.
106  *****************************************************************************/
107 picture_t *vout_CreatePicture( vout_thread_t *p_vout,
108                                boolean_t b_progressive,
109                                boolean_t b_top_field_first,
110                                boolean_t b_repeat_first_field )
111 {
112     int         i_pic;                                      /* picture index */
113     picture_t * p_pic;
114     picture_t * p_freepic = NULL;                      /* first free picture */
115
116     /* Get lock */
117     vlc_mutex_lock( &p_vout->picture_lock );
118
119     /*
120      * Look for an empty place. We start at 1 because the first
121      * directbuffer is reserved for memcpy()ed pictures.
122      */
123     for( i_pic = 0; i_pic < I_RENDERPICTURES && p_freepic == NULL; i_pic++ )
124     {
125         p_pic = PP_RENDERPICTURE[ i_pic ];
126
127         /* If the picture we found is a memory buffer, and we have enough
128          * pictures in the stack, and we might have enough room later for
129          * a direct buffer, skip it. If no other pictures are found, the
130          * video decoder will try again later. */
131         if( p_vout->b_direct && ( p_vout->output.i_pictures > 5 )
132              && ( p_pic->i_type != DIRECT_PICTURE ) )
133         {
134             break;
135         }
136
137         switch( p_pic->i_status )
138         {
139             case DESTROYED_PICTURE:
140                 /* Memory will not be reallocated, and function can end
141                  * immediately - this is the best possible case, since no
142                  * memory allocation needs to be done */
143                 p_pic->i_status   = RESERVED_PICTURE;
144                 p_pic->i_refcount = 0;
145
146                 p_pic->b_progressive        = b_progressive;
147                 p_pic->b_repeat_first_field = b_repeat_first_field;
148                 p_pic->b_top_field_first    = b_top_field_first;
149
150                 p_vout->i_heap_size++;
151                 vlc_mutex_unlock( &p_vout->picture_lock );
152                 return( p_pic );
153
154             case FREE_PICTURE:
155                 /* Picture is empty and ready for allocation */
156                 p_freepic = p_pic;
157                 break;
158
159             default:
160                 break;
161         }
162     }
163
164     /*
165      * Prepare picture
166      */
167     if( p_freepic != NULL )
168     {
169         vout_AllocatePicture( p_freepic,
170                               p_vout->render.i_width, p_vout->render.i_height,
171                               p_vout->render.i_chroma );
172
173         if( p_freepic->i_planes )
174         {
175             /* Copy picture information, set some default values */
176             p_freepic->i_status   = RESERVED_PICTURE;
177             p_freepic->i_type     = MEMORY_PICTURE;
178
179             p_freepic->i_refcount = 0;
180
181             p_freepic->b_progressive        = b_progressive;
182             p_freepic->b_repeat_first_field = b_repeat_first_field;
183             p_freepic->b_top_field_first    = b_top_field_first;
184
185             p_freepic->i_matrix_coefficients = 1;
186
187             p_vout->i_heap_size++;
188         }
189         else
190         {
191             /* Memory allocation failed : set picture as empty */
192             p_freepic->i_status = FREE_PICTURE;
193             p_freepic = NULL;
194
195             intf_ErrMsg( "vout error: picture allocation failed" );
196         }
197
198         vlc_mutex_unlock( &p_vout->picture_lock );
199
200         return( p_freepic );
201     }
202
203     /* No free or destroyed picture could be found, but the decoder
204      * will try again in a while. */
205     vlc_mutex_unlock( &p_vout->picture_lock );
206
207     return( NULL );
208 }
209
210 /*****************************************************************************
211  * vout_DestroyPicture: remove a permanent or reserved picture from the heap
212  *****************************************************************************
213  * This function frees a previously reserved picture or a permanent
214  * picture. It is meant to be used when the construction of a picture aborted.
215  * Note that the picture will be destroyed even if it is linked !
216  *****************************************************************************/
217 void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_pic )
218 {
219     vlc_mutex_lock( &p_vout->picture_lock );
220
221 #ifdef DEBUG
222     /* Check if picture status is valid */
223     if( (p_pic->i_status != RESERVED_PICTURE) &&
224         (p_pic->i_status != RESERVED_DATED_PICTURE) &&
225         (p_pic->i_status != RESERVED_DISP_PICTURE) )
226     {
227         intf_ErrMsg( "error: picture %p has invalid status %d",
228                      p_pic, p_pic->i_status );
229     }
230 #endif
231
232     p_pic->i_status = DESTROYED_PICTURE;
233     p_vout->i_heap_size--;
234
235     vlc_mutex_unlock( &p_vout->picture_lock );
236 }
237
238 /*****************************************************************************
239  * vout_LinkPicture: increment reference counter of a picture
240  *****************************************************************************
241  * This function increments the reference counter of a picture in the video
242  * heap. It needs a lock since several producer threads can access the picture.
243  *****************************************************************************/
244 void vout_LinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
245 {
246     vlc_mutex_lock( &p_vout->picture_lock );
247     p_pic->i_refcount++;
248     vlc_mutex_unlock( &p_vout->picture_lock );
249 }
250
251 /*****************************************************************************
252  * vout_UnlinkPicture: decrement reference counter of a picture
253  *****************************************************************************
254  * This function decrement the reference counter of a picture in the video heap.
255  *****************************************************************************/
256 void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
257 {
258     vlc_mutex_lock( &p_vout->picture_lock );
259     p_pic->i_refcount--;
260
261     if( p_pic->i_refcount < 0 )
262     {
263         intf_ErrMsg( "vout error: picture refcount is %i", p_pic->i_refcount );
264         p_pic->i_refcount = 0;
265     }
266
267     if( ( p_pic->i_refcount == 0 ) &&
268         ( p_pic->i_status == DISPLAYED_PICTURE ) )
269     {
270         p_pic->i_status = DESTROYED_PICTURE;
271         p_vout->i_heap_size--;
272     }
273
274     vlc_mutex_unlock( &p_vout->picture_lock );
275 }
276
277 /*****************************************************************************
278  * vout_RenderPicture: render a picture
279  *****************************************************************************
280  * This function chooses whether the current picture needs to be copied
281  * before rendering, does the subpicture magic, and tells the video output
282  * thread which direct buffer needs to be displayed.
283  *****************************************************************************/
284 picture_t * vout_RenderPicture( vout_thread_t *p_vout, picture_t *p_pic,
285                                                        subpicture_t *p_subpic )
286 {
287     if( p_pic == NULL )
288     {
289         /* XXX: subtitles */
290
291         return NULL;
292     }
293
294     if( p_pic->i_type == DIRECT_PICTURE )
295     {
296         if( p_pic->i_refcount )
297         {
298             /* Picture is in a direct buffer and is still in use,
299              * we need to copy it to another direct buffer before
300              * displaying it if there are subtitles. */
301             if( p_subpic != NULL )
302             {
303                 /* We have subtitles. First copy the picture to
304                  * the spare direct buffer, then render the
305                  * subtitles. */
306                 vout_CopyPicture( p_pic, PP_OUTPUTPICTURE[0] );
307
308                 vout_RenderSubPictures( p_vout, PP_OUTPUTPICTURE[0], p_subpic );
309
310                 return PP_OUTPUTPICTURE[0];
311             }
312
313             /* No subtitles, picture is in a directbuffer so
314              * we can display it directly even if it is still
315              * in use. */
316             return p_pic;
317         }
318
319         /* Picture is in a direct buffer but isn't used by the
320          * decoder. We can safely render subtitles on it and
321          * display it. */
322         vout_RenderSubPictures( p_vout, p_pic, p_subpic );
323
324         return p_pic;
325     }
326
327     /* Not a direct buffer. We either need to copy it to a direct buffer,
328      * or render it if the chroma isn't the same. */
329     if( p_vout->b_direct )
330     {
331         /* Picture is not in a direct buffer, but is exactly the
332          * same size as the direct buffers. A memcpy() is enough,
333          * then render the subtitles. */
334         vout_CopyPicture( p_pic, PP_OUTPUTPICTURE[0] );
335
336         vout_RenderSubPictures( p_vout, PP_OUTPUTPICTURE[0], p_subpic );
337
338         return PP_OUTPUTPICTURE[0];
339     }
340
341     /* Picture is not in a direct buffer, and needs to be converted to
342      * another size/chroma. Then the subtitles need to be rendered as
343      * well. This usually means software YUV, or hardware YUV with a
344      * different chroma. */
345
346     /* Convert image to the first direct buffer */
347     p_vout->chroma.pf_convert( p_vout, p_pic, &p_vout->p_picture[0] );
348
349     /* Render subpictures on the first direct buffer */
350     vout_RenderSubPictures( p_vout, &p_vout->p_picture[0], p_subpic );
351
352     return &p_vout->p_picture[0];
353 }
354
355 /*****************************************************************************
356  * vout_PlacePicture: calculate image window coordinates
357  *****************************************************************************
358  * This function will be accessed by plugins. It calculates the relative
359  * position of the output window and the image window.
360  *****************************************************************************/
361 void vout_PlacePicture( vout_thread_t *p_vout, int i_width, int i_height,
362                         int *pi_x, int *pi_y, int *pi_width, int *pi_height )
363 {
364     if( (i_width <= 0) || (i_height <=0) )
365     {
366         *pi_width = *pi_height = *pi_x = *pi_y = 0;
367
368         return;
369     }
370
371     if( p_vout->b_scale )
372     {
373         *pi_width = i_width;
374         *pi_height = i_height;
375     }
376     else
377     {
378         *pi_width = __MIN( i_width, p_vout->render.i_width );
379         *pi_height = __MIN( i_height, p_vout->render.i_height );
380     }
381
382     if( VOUT_ASPECT_FACTOR * *pi_width / *pi_height < p_vout->render.i_aspect )
383     {
384         *pi_width = *pi_height * p_vout->render.i_aspect / VOUT_ASPECT_FACTOR;
385     }
386     else
387     {
388         *pi_height = *pi_width * VOUT_ASPECT_FACTOR / p_vout->render.i_aspect;
389     }
390
391     if( *pi_width > i_width )
392     {
393         *pi_width = i_width;
394         *pi_height = VOUT_ASPECT_FACTOR * *pi_width / p_vout->render.i_aspect;
395     }
396
397     if( *pi_height > i_height )
398     {
399         *pi_height = i_height;
400         *pi_width = *pi_height * p_vout->render.i_aspect / VOUT_ASPECT_FACTOR;
401     }
402
403     *pi_x = ( i_width - *pi_width ) / 2;
404     *pi_y = ( i_height - *pi_height ) / 2;
405 }
406
407 /*****************************************************************************
408  * vout_AllocatePicture: allocate a new picture in the heap.
409  *****************************************************************************
410  * This function allocates a fake direct buffer in memory, which can be
411  * used exactly like a video buffer. The video output thread then manages
412  * how it gets displayed.
413  *****************************************************************************/
414 void vout_AllocatePicture( picture_t *p_pic,
415                            int i_width, int i_height, u32 i_chroma )
416 {
417     int i_bytes, i_index;
418
419     /* Store default values */
420     for( i_index = 0; i_index < VOUT_MAX_PLANES; i_index++ )
421     {
422         p_pic->p[i_index].p_pixels = NULL;
423         p_pic->p[i_index].b_margin = 0;
424         p_pic->p[i_index].i_pixel_bytes = 1;
425     }
426
427     /* Calculate coordinates */
428     switch( i_chroma )
429     {
430         case FOURCC_YV12:
431         case FOURCC_I420:
432         case FOURCC_IYUV:
433             p_pic->p[ Y_PLANE ].i_lines = i_height;
434             p_pic->p[ Y_PLANE ].i_pitch = i_width;
435             p_pic->p[ Y_PLANE ].i_visible_bytes = p_pic->p[ Y_PLANE ].i_pitch;
436             p_pic->p[ U_PLANE ].i_lines = i_height / 2;
437             p_pic->p[ U_PLANE ].i_pitch = i_width / 2;
438             p_pic->p[ U_PLANE ].i_visible_bytes = p_pic->p[ U_PLANE ].i_pitch;
439             p_pic->p[ V_PLANE ].i_lines = i_height / 2;
440             p_pic->p[ V_PLANE ].i_pitch = i_width / 2;
441             p_pic->p[ V_PLANE ].i_visible_bytes = p_pic->p[ V_PLANE ].i_pitch;
442             p_pic->i_planes = 3;
443             break;
444
445         case FOURCC_I422:
446             p_pic->p[ Y_PLANE ].i_lines = i_height;
447             p_pic->p[ Y_PLANE ].i_pitch = i_width;
448             p_pic->p[ Y_PLANE ].i_visible_bytes = p_pic->p[ Y_PLANE ].i_pitch;
449             p_pic->p[ U_PLANE ].i_lines = i_height;
450             p_pic->p[ U_PLANE ].i_pitch = i_width / 2;
451             p_pic->p[ U_PLANE ].i_visible_bytes = p_pic->p[ U_PLANE ].i_pitch;
452             p_pic->p[ V_PLANE ].i_lines = i_height;
453             p_pic->p[ V_PLANE ].i_pitch = i_width / 2;
454             p_pic->p[ V_PLANE ].i_visible_bytes = p_pic->p[ V_PLANE ].i_pitch;
455             p_pic->i_planes = 3;
456             break;
457
458         case FOURCC_I444:
459             p_pic->p[ Y_PLANE ].i_lines = i_height;
460             p_pic->p[ Y_PLANE ].i_pitch = i_width;
461             p_pic->p[ Y_PLANE ].i_visible_bytes = p_pic->p[ Y_PLANE ].i_pitch;
462             p_pic->p[ U_PLANE ].i_lines = i_height;
463             p_pic->p[ U_PLANE ].i_pitch = i_width;
464             p_pic->p[ U_PLANE ].i_visible_bytes = p_pic->p[ U_PLANE ].i_pitch;
465             p_pic->p[ V_PLANE ].i_lines = i_height;
466             p_pic->p[ V_PLANE ].i_pitch = i_width;
467             p_pic->p[ V_PLANE ].i_visible_bytes = p_pic->p[ V_PLANE ].i_pitch;
468             p_pic->i_planes = 3;
469             break;
470
471         case FOURCC_Y211:
472             p_pic->p->i_lines = i_height;
473             p_pic->p->i_pitch = i_width;
474             p_pic->p->i_visible_bytes = p_pic->p->i_pitch;
475             p_pic->p->i_pixel_bytes = 4;
476             p_pic->i_planes = 1;
477             break;
478
479         case FOURCC_YUY2:
480             p_pic->p->i_lines = i_height;
481             p_pic->p->i_pitch = i_width * 2;
482             p_pic->p->i_visible_bytes = p_pic->p->i_pitch;
483             p_pic->p->i_pixel_bytes = 4;
484             p_pic->i_planes = 1;
485             break;
486
487         case FOURCC_RV15:
488             p_pic->p->i_lines = i_height;
489             p_pic->p->i_pitch = i_width * 2;
490             p_pic->p->i_visible_bytes = p_pic->p->i_pitch;
491             p_pic->p->i_pixel_bytes = 2;
492             p_pic->p_heap->i_rmask = 0x001f;
493             p_pic->p_heap->i_gmask = 0x03e0;
494             p_pic->p_heap->i_bmask = 0x7c00;
495             p_pic->i_planes = 1;
496             break;
497
498         case FOURCC_RV16:
499             p_pic->p->i_lines = i_height;
500             p_pic->p->i_pitch = i_width * 2;
501             p_pic->p->i_visible_bytes = p_pic->p->i_pitch;
502             p_pic->p->i_pixel_bytes = 2;
503             p_pic->p_heap->i_rmask = 0x001f;
504             p_pic->p_heap->i_gmask = 0x07e0;
505             p_pic->p_heap->i_bmask = 0xf800;
506             p_pic->i_planes = 1;
507             break;
508
509         case FOURCC_RV32:
510             p_pic->p->i_lines = i_height;
511             p_pic->p->i_pitch = i_width * 4;
512             p_pic->p->i_visible_bytes = p_pic->p->i_pitch;
513             p_pic->p->i_pixel_bytes = 4;
514             p_pic->p_heap->i_rmask = 0xff0000;
515             p_pic->p_heap->i_gmask = 0x00ff00;
516             p_pic->p_heap->i_bmask = 0x0000ff;
517             p_pic->i_planes = 1;
518             break;
519
520         default:
521             intf_ErrMsg( "vout error: unknown chroma type 0x%.8x (%4.4s)",
522                          i_chroma, (char*)&i_chroma );
523             p_pic->i_planes = 0;
524             return;
525     }
526
527     /* Calculate how big the new image should be */
528     for( i_bytes = 0, i_index = 0; i_index < p_pic->i_planes; i_index++ )
529     {
530         i_bytes += p_pic->p[ i_index ].i_lines * p_pic->p[ i_index ].i_pitch;
531     }
532
533     p_pic->p_data = vlc_memalign( &p_pic->p_data_orig, 16, i_bytes );
534
535     if( p_pic->p_data == NULL )
536     {
537         p_pic->i_planes = 0;
538         return;
539     }
540
541     /* Fill the p_pixels field for each plane */
542     p_pic->p[ 0 ].p_pixels = p_pic->p_data;
543
544     for( i_index = 1; i_index < p_pic->i_planes; i_index++ )
545     {
546         p_pic->p[i_index].p_pixels = p_pic->p[i_index-1].p_pixels
547                                           + p_pic->p[i_index-1].i_lines
548                                              * p_pic->p[i_index-1].i_pitch;
549     }
550 }
551
552 /* Following functions are local */
553
554 /*****************************************************************************
555  * vout_CopyPicture: copy a picture to another one
556  *****************************************************************************
557  * This function takes advantage of the image format, and reduces the
558  * number of calls to memcpy() to the minimum. Source and destination
559  * images must have same width, height, and chroma.
560  *****************************************************************************/
561 static void vout_CopyPicture( picture_t *p_src, picture_t *p_dest )
562 {
563     int i;
564
565     for( i = 0; i < p_src->i_planes ; i++ )
566     {
567         if( p_src->p[i].i_pitch == p_dest->p[i].i_pitch )
568         {
569             if( p_src->p[i].b_margin )
570             {
571                 /* If p_src->b_margin is set, p_dest->b_margin must be set */
572                 if( p_dest->p[i].b_hidden )
573                 {
574                     /* There are margins, but they are hidden : perfect ! */
575                     FAST_MEMCPY( p_dest->p[i].p_pixels, p_src->p[i].p_pixels,
576                                  p_src->p[i].i_pitch * p_src->p[i].i_lines );
577                     continue;
578                 }
579                 else
580                 {
581                     /* We can't directly copy the margin. Too bad. */
582                 }
583             }
584             else
585             {
586                 /* Same pitch, no margins : perfect ! */
587                 FAST_MEMCPY( p_dest->p[i].p_pixels, p_src->p[i].p_pixels,
588                              p_src->p[i].i_pitch * p_src->p[i].i_lines );
589                 continue;
590             }
591         }
592         else
593         {
594             /* Pitch values are different */
595         }
596
597         /* We need to proceed line by line */
598         {
599             u8 *p_in = p_src->p[i].p_pixels, *p_out = p_dest->p[i].p_pixels;
600             int i_line;
601
602             for( i_line = p_src->p[i].i_lines; i_line--; )
603             {
604                 FAST_MEMCPY( p_out, p_in, p_src->p[i].i_visible_bytes );
605                 p_in += p_src->p[i].i_pitch;
606                 p_out += p_dest->p[i].i_pitch;
607             }
608         }
609     }
610 }
611