* src/video_output/vout_pictures.c, include/video_output.h: added a vout_InitPicture...
[vlc.git] / 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.39 2003/04/27 23:16:35 gbazin 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 <stdlib.h>                                                /* free() */
29 #include <stdio.h>                                              /* sprintf() */
30 #include <string.h>                                            /* strerror() */
31
32 #include <vlc/vlc.h>
33
34 #include "video.h"
35 #include "video_output.h"
36
37 #include "vout_pictures.h"
38
39 /*****************************************************************************
40  * Local prototypes
41  *****************************************************************************/
42 static void CopyPicture( vout_thread_t *, picture_t *, picture_t * );
43
44 /*****************************************************************************
45  * vout_DisplayPicture: display a picture
46  *****************************************************************************
47  * Remove the reservation flag of a picture, which will cause it to be ready for
48  * display. The picture won't be displayed until vout_DatePicture has been
49  * called.
50  *****************************************************************************/
51 void vout_DisplayPicture( vout_thread_t *p_vout, picture_t *p_pic )
52 {
53     vlc_mutex_lock( &p_vout->picture_lock );
54     switch( p_pic->i_status )
55     {
56     case RESERVED_PICTURE:
57         p_pic->i_status = RESERVED_DISP_PICTURE;
58         break;
59     case RESERVED_DATED_PICTURE:
60         p_pic->i_status = READY_PICTURE;
61         break;
62     default:
63         msg_Err( p_vout, "picture to display %p has invalid status %d",
64                          p_pic, p_pic->i_status );
65         break;
66     }
67
68     vlc_mutex_unlock( &p_vout->picture_lock );
69 }
70
71 /*****************************************************************************
72  * vout_DatePicture: date a picture
73  *****************************************************************************
74  * Remove the reservation flag of a picture, which will cause it to be ready
75  * for display. The picture won't be displayed until vout_DisplayPicture has
76  * been called.
77  *****************************************************************************/
78 void vout_DatePicture( vout_thread_t *p_vout,
79                        picture_t *p_pic, mtime_t date )
80 {
81     vlc_mutex_lock( &p_vout->picture_lock );
82     p_pic->date = date;
83     switch( p_pic->i_status )
84     {
85     case RESERVED_PICTURE:
86         p_pic->i_status = RESERVED_DATED_PICTURE;
87         break;
88     case RESERVED_DISP_PICTURE:
89         p_pic->i_status = READY_PICTURE;
90         break;
91     default:
92         msg_Err( p_vout, "picture to date %p has invalid status %d",
93                          p_pic, p_pic->i_status );
94         break;
95     }
96
97     vlc_mutex_unlock( &p_vout->picture_lock );
98 }
99
100 /*****************************************************************************
101  * vout_CreatePicture: allocate a picture in the video output heap.
102  *****************************************************************************
103  * This function creates a reserved image in the video output heap.
104  * A null pointer is returned if the function fails. This method provides an
105  * already allocated zone of memory in the picture data fields. It needs locking
106  * since several pictures can be created by several producers threads.
107  *****************************************************************************/
108 picture_t *vout_CreatePicture( vout_thread_t *p_vout,
109                                vlc_bool_t b_progressive,
110                                vlc_bool_t b_top_field_first,
111                                vlc_bool_t b_repeat_first_field )
112 {
113     int         i_pic;                                      /* picture index */
114     picture_t * p_pic;
115     picture_t * p_freepic = NULL;                      /* first free picture */
116
117     /* Get lock */
118     vlc_mutex_lock( &p_vout->picture_lock );
119
120     /*
121      * Look for an empty place in the picture heap.
122      */
123     for( i_pic = 0; i_pic < I_RENDERPICTURES; i_pic++ )
124     {
125         p_pic = PP_RENDERPICTURE[(p_vout->render.i_last_used_pic + i_pic + 1)
126                                  % I_RENDERPICTURES];
127
128         switch( p_pic->i_status )
129         {
130             case DESTROYED_PICTURE:
131                 /* Memory will not be reallocated, and function can end
132                  * immediately - this is the best possible case, since no
133                  * memory allocation needs to be done */
134                 p_pic->i_status   = RESERVED_PICTURE;
135                 p_pic->i_refcount = 0;
136                 p_pic->b_force    = 0;
137
138                 p_pic->b_progressive        = b_progressive;
139                 p_pic->b_repeat_first_field = b_repeat_first_field;
140                 p_pic->b_top_field_first    = b_top_field_first;
141
142                 p_vout->i_heap_size++;
143                 p_vout->render.i_last_used_pic =
144                     ( p_vout->render.i_last_used_pic + i_pic + 1 )
145                     % I_RENDERPICTURES;
146                 vlc_mutex_unlock( &p_vout->picture_lock );
147                 return( p_pic );
148
149             case FREE_PICTURE:
150                 /* Picture is empty and ready for allocation */
151                 p_vout->render.i_last_used_pic =
152                     ( p_vout->render.i_last_used_pic + i_pic + 1 )
153                     % I_RENDERPICTURES;
154                 p_freepic = p_pic;
155                 break;
156
157             default:
158                 break;
159         }
160     }
161
162     /*
163      * Prepare picture
164      */
165     if( p_freepic != NULL )
166     {
167         vout_AllocatePicture( p_vout, p_freepic,
168                               p_vout->render.i_width, p_vout->render.i_height,
169                               p_vout->render.i_chroma );
170
171         if( p_freepic->i_planes )
172         {
173             /* Copy picture information, set some default values */
174             p_freepic->i_status   = RESERVED_PICTURE;
175             p_freepic->i_type     = MEMORY_PICTURE;
176
177             p_freepic->i_refcount = 0;
178             p_freepic->b_force = 0;
179
180             p_freepic->b_progressive        = b_progressive;
181             p_freepic->b_repeat_first_field = b_repeat_first_field;
182             p_freepic->b_top_field_first    = b_top_field_first;
183
184             p_freepic->i_matrix_coefficients = 1;
185
186             p_vout->i_heap_size++;
187         }
188         else
189         {
190             /* Memory allocation failed : set picture as empty */
191             p_freepic->i_status = FREE_PICTURE;
192             p_freepic = NULL;
193
194             msg_Err( p_vout, "picture allocation failed" );
195         }
196
197         vlc_mutex_unlock( &p_vout->picture_lock );
198
199         return( p_freepic );
200     }
201
202     /* No free or destroyed picture could be found, but the decoder
203      * will try again in a while. */
204     vlc_mutex_unlock( &p_vout->picture_lock );
205
206     return( NULL );
207 }
208
209 /*****************************************************************************
210  * vout_DestroyPicture: remove a permanent or reserved picture from the heap
211  *****************************************************************************
212  * This function frees a previously reserved picture or a permanent
213  * picture. It is meant to be used when the construction of a picture aborted.
214  * Note that the picture will be destroyed even if it is linked !
215  *****************************************************************************/
216 void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_pic )
217 {
218     vlc_mutex_lock( &p_vout->picture_lock );
219
220 #ifdef DEBUG
221     /* Check if picture status is valid */
222     if( (p_pic->i_status != RESERVED_PICTURE) &&
223         (p_pic->i_status != RESERVED_DATED_PICTURE) &&
224         (p_pic->i_status != RESERVED_DISP_PICTURE) )
225     {
226         msg_Err( p_vout, "picture to destroy %p has invalid status %d",
227                          p_pic, p_pic->i_status );
228     }
229 #endif
230
231     p_pic->i_status = DESTROYED_PICTURE;
232     p_vout->i_heap_size--;
233
234     vlc_mutex_unlock( &p_vout->picture_lock );
235 }
236
237 /*****************************************************************************
238  * vout_LinkPicture: increment reference counter of a picture
239  *****************************************************************************
240  * This function increments the reference counter of a picture in the video
241  * heap. It needs a lock since several producer threads can access the picture.
242  *****************************************************************************/
243 void vout_LinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
244 {
245     vlc_mutex_lock( &p_vout->picture_lock );
246     p_pic->i_refcount++;
247     vlc_mutex_unlock( &p_vout->picture_lock );
248 }
249
250 /*****************************************************************************
251  * vout_UnlinkPicture: decrement reference counter of a picture
252  *****************************************************************************
253  * This function decrement the reference counter of a picture in the video heap.
254  *****************************************************************************/
255 void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
256 {
257     vlc_mutex_lock( &p_vout->picture_lock );
258     p_pic->i_refcount--;
259
260     if( p_pic->i_refcount < 0 )
261     {
262         msg_Err( p_vout, "picture %p refcount is %i", 
263                  p_pic, 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_vout->render.b_allow_modify_pics || 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                 CopyPicture( p_vout, 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
335         if( PP_OUTPUTPICTURE[0]->pf_lock )
336             if( PP_OUTPUTPICTURE[0]->pf_lock( p_vout, PP_OUTPUTPICTURE[0] ) )
337             {
338                 if( PP_OUTPUTPICTURE[0]->pf_unlock )
339                 PP_OUTPUTPICTURE[0]->pf_unlock( p_vout, PP_OUTPUTPICTURE[0] );
340
341                 return NULL;
342             }
343
344         CopyPicture( p_vout, p_pic, PP_OUTPUTPICTURE[0] );
345
346         vout_RenderSubPictures( p_vout, PP_OUTPUTPICTURE[0], p_subpic );
347
348         if( PP_OUTPUTPICTURE[0]->pf_unlock )
349             PP_OUTPUTPICTURE[0]->pf_unlock( p_vout, PP_OUTPUTPICTURE[0] );
350
351         return PP_OUTPUTPICTURE[0];
352     }
353
354     /* Picture is not in a direct buffer, and needs to be converted to
355      * another size/chroma. Then the subtitles need to be rendered as
356      * well. This usually means software YUV, or hardware YUV with a
357      * different chroma. */
358
359     if( p_vout->p_picture[0].pf_lock )
360         if( p_vout->p_picture[0].pf_lock( p_vout, &p_vout->p_picture[0] ) )
361             return NULL;
362
363     /* Convert image to the first direct buffer */
364     p_vout->chroma.pf_convert( p_vout, p_pic, &p_vout->p_picture[0] );
365
366     /* Render subpictures on the first direct buffer */
367     vout_RenderSubPictures( p_vout, &p_vout->p_picture[0], p_subpic );
368
369     if( p_vout->p_picture[0].pf_unlock )
370         p_vout->p_picture[0].pf_unlock( p_vout, &p_vout->p_picture[0] );
371
372     return &p_vout->p_picture[0];
373 }
374
375 /*****************************************************************************
376  * vout_PlacePicture: calculate image window coordinates
377  *****************************************************************************
378  * This function will be accessed by plugins. It calculates the relative
379  * position of the output window and the image window.
380  *****************************************************************************/
381 void vout_PlacePicture( vout_thread_t *p_vout,
382                         unsigned int i_width, unsigned int i_height,
383                         unsigned int *pi_x, unsigned int *pi_y,
384                         unsigned int *pi_width, unsigned int *pi_height )
385 {
386     if( (i_width <= 0) || (i_height <=0) )
387     {
388         *pi_width = *pi_height = *pi_x = *pi_y = 0;
389
390         return;
391     }
392
393     if( p_vout->b_scale )
394     {
395         *pi_width = i_width;
396         *pi_height = i_height;
397     }
398     else
399     {
400         *pi_width = __MIN( i_width, p_vout->render.i_width );
401         *pi_height = __MIN( i_height, p_vout->render.i_height );
402     }
403
404     if( VOUT_ASPECT_FACTOR * *pi_width / *pi_height < p_vout->render.i_aspect )
405     {
406         *pi_width = *pi_height * p_vout->render.i_aspect / VOUT_ASPECT_FACTOR;
407     }
408     else
409     {
410         *pi_height = *pi_width * VOUT_ASPECT_FACTOR / p_vout->render.i_aspect;
411     }
412
413     if( *pi_width > i_width )
414     {
415         *pi_width = i_width;
416         *pi_height = VOUT_ASPECT_FACTOR * *pi_width / p_vout->render.i_aspect;
417     }
418
419     if( *pi_height > i_height )
420     {
421         *pi_height = i_height;
422         *pi_width = *pi_height * p_vout->render.i_aspect / VOUT_ASPECT_FACTOR;
423     }
424
425     *pi_x = ( i_width - *pi_width ) / 2;
426     *pi_y = ( i_height - *pi_height ) / 2;
427 }
428
429 /*****************************************************************************
430  * vout_AllocatePicture: allocate a new picture in the heap.
431  *****************************************************************************
432  * This function allocates a fake direct buffer in memory, which can be
433  * used exactly like a video buffer. The video output thread then manages
434  * how it gets displayed.
435  *****************************************************************************/
436 void vout_AllocatePicture( vout_thread_t *p_vout, picture_t *p_pic,
437                            int i_width, int i_height, vlc_fourcc_t i_chroma )
438 {
439     int i_bytes, i_index;
440
441     vout_InitPicture( VLC_OBJECT(p_vout), p_pic, i_width, i_height, i_chroma );
442
443     /* Calculate how big the new image should be */
444     for( i_bytes = 0, i_index = 0; i_index < p_pic->i_planes; i_index++ )
445     {
446         i_bytes += p_pic->p[ i_index ].i_lines * p_pic->p[ i_index ].i_pitch;
447     }
448
449     p_pic->p_data = vlc_memalign( &p_pic->p_data_orig, 16, i_bytes );
450
451     if( p_pic->p_data == NULL )
452     {
453         p_pic->i_planes = 0;
454         return;
455     }
456
457     /* Fill the p_pixels field for each plane */
458     p_pic->p[ 0 ].p_pixels = p_pic->p_data;
459
460     for( i_index = 1; i_index < p_pic->i_planes; i_index++ )
461     {
462         p_pic->p[i_index].p_pixels = p_pic->p[i_index-1].p_pixels
463                                           + p_pic->p[i_index-1].i_lines
464                                              * p_pic->p[i_index-1].i_pitch;
465     }
466 }
467
468 /*****************************************************************************
469  * vout_InitPicture: initialise the picture_t fields given chroma/size.
470  *****************************************************************************
471  * This function initializes most of the picture_t fields given a chroma and
472  * size. It makes the assumption that stride == width.
473  *****************************************************************************/
474 void vout_InitPicture( vlc_object_t *p_this, picture_t *p_pic,
475                        int i_width, int i_height, vlc_fourcc_t i_chroma )
476 {
477     int i_index;
478
479     /* Store default values */
480     for( i_index = 0; i_index < VOUT_MAX_PLANES; i_index++ )
481     {
482         p_pic->p[i_index].p_pixels = NULL;
483         p_pic->p[i_index].i_pixel_pitch = 1;
484     }
485
486     /* Calculate coordinates */
487     switch( i_chroma )
488     {
489         case FOURCC_I411:
490             p_pic->p[ Y_PLANE ].i_lines = i_height;
491             p_pic->p[ Y_PLANE ].i_pitch = i_width;
492             p_pic->p[ Y_PLANE ].i_visible_pitch = p_pic->p[ Y_PLANE ].i_pitch;
493             p_pic->p[ U_PLANE ].i_lines = i_height;
494             p_pic->p[ U_PLANE ].i_pitch = i_width / 4;
495             p_pic->p[ U_PLANE ].i_visible_pitch = p_pic->p[ U_PLANE ].i_pitch;
496             p_pic->p[ V_PLANE ].i_lines = i_height;
497             p_pic->p[ V_PLANE ].i_pitch = i_width / 4;
498             p_pic->p[ V_PLANE ].i_visible_pitch = p_pic->p[ V_PLANE ].i_pitch;
499             p_pic->i_planes = 3;
500             break;
501
502         case FOURCC_I410:
503             p_pic->p[ Y_PLANE ].i_lines = i_height;
504             p_pic->p[ Y_PLANE ].i_pitch = i_width;
505             p_pic->p[ Y_PLANE ].i_visible_pitch = p_pic->p[ Y_PLANE ].i_pitch;
506             p_pic->p[ U_PLANE ].i_lines = i_height / 4;
507             p_pic->p[ U_PLANE ].i_pitch = i_width / 4;
508             p_pic->p[ U_PLANE ].i_visible_pitch = p_pic->p[ U_PLANE ].i_pitch;
509             p_pic->p[ V_PLANE ].i_lines = i_height / 4;
510             p_pic->p[ V_PLANE ].i_pitch = i_width / 4;
511             p_pic->p[ V_PLANE ].i_visible_pitch = p_pic->p[ V_PLANE ].i_pitch;
512             p_pic->i_planes = 3;
513             break;
514
515         case FOURCC_YV12:
516         case FOURCC_I420:
517         case FOURCC_IYUV:
518             p_pic->p[ Y_PLANE ].i_lines = i_height;
519             p_pic->p[ Y_PLANE ].i_pitch = i_width;
520             p_pic->p[ Y_PLANE ].i_visible_pitch = p_pic->p[ Y_PLANE ].i_pitch;
521             p_pic->p[ U_PLANE ].i_lines = i_height / 2;
522             p_pic->p[ U_PLANE ].i_pitch = i_width / 2;
523             p_pic->p[ U_PLANE ].i_visible_pitch = p_pic->p[ U_PLANE ].i_pitch;
524             p_pic->p[ V_PLANE ].i_lines = i_height / 2;
525             p_pic->p[ V_PLANE ].i_pitch = i_width / 2;
526             p_pic->p[ V_PLANE ].i_visible_pitch = p_pic->p[ V_PLANE ].i_pitch;
527             p_pic->i_planes = 3;
528             break;
529
530         case FOURCC_I422:
531             p_pic->p[ Y_PLANE ].i_lines = i_height;
532             p_pic->p[ Y_PLANE ].i_pitch = i_width;
533             p_pic->p[ Y_PLANE ].i_visible_pitch = p_pic->p[ Y_PLANE ].i_pitch;
534             p_pic->p[ U_PLANE ].i_lines = i_height;
535             p_pic->p[ U_PLANE ].i_pitch = i_width / 2;
536             p_pic->p[ U_PLANE ].i_visible_pitch = p_pic->p[ U_PLANE ].i_pitch;
537             p_pic->p[ V_PLANE ].i_lines = i_height;
538             p_pic->p[ V_PLANE ].i_pitch = i_width / 2;
539             p_pic->p[ V_PLANE ].i_visible_pitch = p_pic->p[ V_PLANE ].i_pitch;
540             p_pic->i_planes = 3;
541             break;
542
543         case FOURCC_I444:
544             p_pic->p[ Y_PLANE ].i_lines = i_height;
545             p_pic->p[ Y_PLANE ].i_pitch = i_width;
546             p_pic->p[ Y_PLANE ].i_visible_pitch = p_pic->p[ Y_PLANE ].i_pitch;
547             p_pic->p[ U_PLANE ].i_lines = i_height;
548             p_pic->p[ U_PLANE ].i_pitch = i_width;
549             p_pic->p[ U_PLANE ].i_visible_pitch = p_pic->p[ U_PLANE ].i_pitch;
550             p_pic->p[ V_PLANE ].i_lines = i_height;
551             p_pic->p[ V_PLANE ].i_pitch = i_width;
552             p_pic->p[ V_PLANE ].i_visible_pitch = p_pic->p[ V_PLANE ].i_pitch;
553             p_pic->i_planes = 3;
554             break;
555
556         case FOURCC_Y211:
557             p_pic->p->i_lines = i_height;
558             p_pic->p->i_pitch = i_width;
559             p_pic->p->i_visible_pitch = p_pic->p->i_pitch;
560             p_pic->p->i_pixel_pitch = 4;
561             p_pic->i_planes = 1;
562             break;
563
564         case FOURCC_YUY2:
565             p_pic->p->i_lines = i_height;
566             p_pic->p->i_pitch = i_width * 2;
567             p_pic->p->i_visible_pitch = p_pic->p->i_pitch;
568             p_pic->p->i_pixel_pitch = 4;
569             p_pic->i_planes = 1;
570             break;
571
572         case FOURCC_RGB2:
573             p_pic->p->i_lines = i_height;
574             p_pic->p->i_pitch = i_width;
575             p_pic->p->i_visible_pitch = p_pic->p->i_pitch;
576             p_pic->p->i_pixel_pitch = 1;
577             p_pic->i_planes = 1;
578             break;
579
580         case FOURCC_RV15:
581             p_pic->p->i_lines = i_height;
582             p_pic->p->i_pitch = i_width * 2;
583             p_pic->p->i_visible_pitch = p_pic->p->i_pitch;
584             p_pic->p->i_pixel_pitch = 2;
585 /* FIXME: p_heap isn't always reachable
586             p_pic->p_heap->i_rmask = 0x001f;
587             p_pic->p_heap->i_gmask = 0x03e0;
588             p_pic->p_heap->i_bmask = 0x7c00; */
589             p_pic->i_planes = 1;
590             break;
591
592         case FOURCC_RV16:
593             p_pic->p->i_lines = i_height;
594             p_pic->p->i_pitch = i_width * 2;
595             p_pic->p->i_visible_pitch = p_pic->p->i_pitch;
596             p_pic->p->i_pixel_pitch = 2;
597 /* FIXME: p_heap isn't always reachable
598             p_pic->p_heap->i_rmask = 0x001f;
599             p_pic->p_heap->i_gmask = 0x07e0;
600             p_pic->p_heap->i_bmask = 0xf800; */
601             p_pic->i_planes = 1;
602             break;
603
604         case FOURCC_RV24:
605             p_pic->p->i_lines = i_height;
606             p_pic->p->i_pitch = i_width * 3;
607             p_pic->p->i_visible_pitch = p_pic->p->i_pitch;
608             p_pic->p->i_pixel_pitch = 3;
609 /* FIXME: p_heap isn't always reachable
610             p_pic->p_heap->i_rmask = 0xff0000;
611             p_pic->p_heap->i_gmask = 0x00ff00;
612             p_pic->p_heap->i_bmask = 0x0000ff; */
613             p_pic->i_planes = 1;
614             break;
615
616         case FOURCC_RV32:
617             p_pic->p->i_lines = i_height;
618             p_pic->p->i_pitch = i_width * 4;
619             p_pic->p->i_visible_pitch = p_pic->p->i_pitch;
620             p_pic->p->i_pixel_pitch = 4;
621 /* FIXME: p_heap isn't always reachable
622             p_pic->p_heap->i_rmask = 0xff0000;
623             p_pic->p_heap->i_gmask = 0x00ff00;
624             p_pic->p_heap->i_bmask = 0x0000ff; */
625             p_pic->i_planes = 1;
626             break;
627
628         default:
629             msg_Err( p_this, "unknown chroma type 0x%.8x (%4.4s)",
630                              i_chroma, (char*)&i_chroma );
631             p_pic->i_planes = 0;
632             return;
633     }
634
635 }
636
637 /*****************************************************************************
638  * vout_ChromaCmp: compare two chroma values
639  *****************************************************************************
640  * This function returns 1 if the two fourcc values given as argument are
641  * the same format (eg. UYVY / UYNV) or almost the same format (eg. I420/YV12)
642  *****************************************************************************/
643 int vout_ChromaCmp( vlc_fourcc_t i_chroma, vlc_fourcc_t i_amorhc )
644 {
645     /* If they are the same, they are the same ! */
646     if( i_chroma == i_amorhc )
647     {
648         return 1;
649     }
650
651     /* Check for equivalence classes */
652     switch( i_chroma )
653     {
654         case FOURCC_I420:
655         case FOURCC_IYUV:
656         case FOURCC_YV12:
657             switch( i_amorhc )
658             {
659                 case FOURCC_I420:
660                 case FOURCC_IYUV:
661                 case FOURCC_YV12:
662                     return 1;
663
664                 default:
665                     return 0;
666             }
667
668         case FOURCC_UYVY:
669         case FOURCC_UYNV:
670         case FOURCC_Y422:
671             switch( i_amorhc )
672             {
673                 case FOURCC_UYVY:
674                 case FOURCC_UYNV:
675                 case FOURCC_Y422:
676                     return 1;
677
678                 default:
679                     return 0;
680             }
681
682         case FOURCC_YUY2:
683         case FOURCC_YUNV:
684             switch( i_amorhc )
685             {
686                 case FOURCC_YUY2:
687                 case FOURCC_YUNV:
688                     return 1;
689
690                 default:
691                     return 0;
692             }
693
694         default:
695             return 0;
696     }
697 }
698
699 /* Following functions are local */
700
701 /*****************************************************************************
702  * CopyPicture: copy a picture to another one
703  *****************************************************************************
704  * This function takes advantage of the image format, and reduces the
705  * number of calls to memcpy() to the minimum. Source and destination
706  * images must have same width (hence i_visible_pitch), height, and chroma.
707  *****************************************************************************/
708 static void CopyPicture( vout_thread_t * p_vout,
709                          picture_t *p_src, picture_t *p_dest )
710 {
711     int i;
712
713     for( i = 0; i < p_src->i_planes ; i++ )
714     {
715         if( p_src->p[i].i_pitch == p_dest->p[i].i_pitch )
716         {
717             /* There are margins, but with the same width : perfect ! */
718             p_vout->p_vlc->pf_memcpy(
719                          p_dest->p[i].p_pixels, p_src->p[i].p_pixels,
720                          p_src->p[i].i_pitch * p_src->p[i].i_lines );
721         }
722         else
723         {
724             /* We need to proceed line by line */
725             uint8_t *p_in = p_src->p[i].p_pixels;
726             uint8_t *p_out = p_dest->p[i].p_pixels;
727             int i_line;
728
729             for( i_line = p_src->p[i].i_lines; i_line--; )
730             {
731                 p_vout->p_vlc->pf_memcpy( p_out, p_in,
732                                           p_src->p[i].i_visible_pitch );
733                 p_in += p_src->p[i].i_pitch;
734                 p_out += p_dest->p[i].i_pitch;
735             }
736         }
737     }
738     p_dest->date = p_src->date;
739 }