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