]> git.sesse.net Git - vlc/blob - src/video_output/vout_pictures.c
94d0e8fc68fc09045a33bef99969b7968bc0deb8
[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.1 2001/12/09 17:01:37 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 "defs.h"
29
30 #include <errno.h>                                                 /* ENOMEM */
31 #include <stdlib.h>                                                /* free() */
32 #include <stdio.h>                                              /* sprintf() */
33 #include <string.h>                                            /* strerror() */
34
35 #include "common.h"
36 #include "intf_msg.h"
37 #include "threads.h"
38 #include "mtime.h"
39
40 #include "video.h"
41 #include "video_output.h"
42
43 /*****************************************************************************
44  * Local prototypes
45  *****************************************************************************/
46 static void     NewPicture        ( picture_t *, int, int, int );
47
48 /*****************************************************************************
49  * vout_DisplayPicture: display a picture
50  *****************************************************************************
51  * Remove the reservation flag of a picture, which will cause it to be ready for
52  * display. The picture won't be displayed until vout_DatePicture has been
53  * called.
54  *****************************************************************************/
55 void vout_DisplayPicture( vout_thread_t *p_vout, picture_t *p_picture )
56 {
57     vlc_mutex_lock( &p_vout->picture_lock );
58     switch( p_picture->i_status )
59     {
60     case RESERVED_PICTURE:
61         p_picture->i_status = RESERVED_DISP_PICTURE;
62         break;
63     case RESERVED_DATED_PICTURE:
64         p_picture->i_status = READY_PICTURE;
65         break;
66 #ifdef DEBUG
67     default:
68         intf_ErrMsg("error: picture %p has invalid status %d", p_picture, p_picture->i_status );
69         break;
70 #endif
71     }
72
73 #ifdef TRACE_VOUT
74     intf_DbgMsg("picture %p", p_picture);
75 #endif
76     vlc_mutex_unlock( &p_vout->picture_lock );
77 }
78
79 /*****************************************************************************
80  * vout_DatePicture: date a picture
81  *****************************************************************************
82  * Remove the reservation flag of a picture, which will cause it to be ready
83  * for display. The picture won't be displayed until vout_DisplayPicture has
84  * been called.
85  *****************************************************************************/
86 void vout_DatePicture( vout_thread_t *p_vout,
87                        picture_t *p_picture, mtime_t date )
88 {
89 #ifdef TRACE_VOUT
90     char        psz_date[ MSTRTIME_MAX_SIZE ];                       /* date */
91 #endif
92
93     vlc_mutex_lock( &p_vout->picture_lock );
94     p_picture->date = date;
95     switch( p_picture->i_status )
96     {
97     case RESERVED_PICTURE:
98         p_picture->i_status = RESERVED_DATED_PICTURE;
99         break;
100     case RESERVED_DISP_PICTURE:
101         p_picture->i_status = READY_PICTURE;
102         break;
103 #ifdef DEBUG
104     default:
105         intf_ErrMsg("error: picture %p has invalid status %d", p_picture, p_picture->i_status );
106         break;
107 #endif
108     }
109
110 #ifdef TRACE_VOUT
111     intf_DbgMsg("picture %p, display date: %s", p_picture, mstrtime( psz_date, p_picture->date) );
112 #endif
113     vlc_mutex_unlock( &p_vout->picture_lock );
114 }
115
116 /*****************************************************************************
117  * vout_CreatePicture: allocate a picture in the video output heap.
118  *****************************************************************************
119  * This function creates a reserved image in the video output heap.
120  * A null pointer is returned if the function fails. This method provides an
121  * already allocated zone of memory in the picture data fields. It needs locking
122  * since several pictures can be created by several producers threads.
123  *****************************************************************************/
124 picture_t *vout_CreatePicture( vout_thread_t *p_vout,
125                                int i_width, int i_height,
126                                int i_chroma, int i_aspect_ratio )
127 {
128     int         i_picture;                                  /* picture index */
129     picture_t * p_picture;
130     picture_t * p_free_picture = NULL;                 /* first free picture */
131     picture_t * p_destroyed_picture = NULL;       /* first destroyed picture */
132
133     /* Get lock */
134     vlc_mutex_lock( &p_vout->picture_lock );
135
136     /*
137      * Look for an empty place. XXX: we start at 1 because the first
138      * directbuffer is reserved for memcpy()ed pictures.
139      */
140     for( i_picture = 1; i_picture < VOUT_MAX_PICTURES; i_picture++ )
141     {
142         p_picture = p_vout->p_picture + i_picture;
143
144         if( p_picture->i_status == DESTROYED_PICTURE )
145         {
146             /* Picture is marked for destruction, but is still allocated.
147              * Note that if width and type are the same for two pictures,
148              * chroma_width should also be the same */
149             if( ( p_picture->i_chroma == i_chroma ) &&
150                 ( p_picture->i_height == i_height ) &&
151                 ( p_picture->i_width  == i_width ) )
152             {
153                 /* Memory size do match : memory will not be reallocated,
154                  * and function can end immediately - this is the best
155                  * possible case, since no memory allocation needs to be
156                  * done */
157                 p_picture->i_status = RESERVED_PICTURE;
158                 p_vout->i_pictures++;
159
160                 vlc_mutex_unlock( &p_vout->picture_lock );
161
162                 return( p_picture );
163             }
164             else if( ( p_destroyed_picture == NULL )
165                      && !p_picture->b_directbuffer )
166             {
167                 /* Memory size do not match, but picture index will be kept in
168                  * case no other place are left */
169                 p_destroyed_picture = p_picture;
170             }
171         }
172         else if( ( p_free_picture == NULL )
173                  && ( p_picture->i_status == FREE_PICTURE ) )
174         {
175             /* Picture is empty and ready for allocation */
176             p_free_picture = p_picture;
177         }
178     }
179
180     /* If no free picture is available, use a destroyed picture */
181     if( ( p_free_picture == NULL ) && ( p_destroyed_picture != NULL ) )
182     {
183         /* No free picture or matching destroyed picture has been found, but
184          * a destroyed picture is still avalaible */
185         free( p_destroyed_picture->planes[0].p_data );
186         p_destroyed_picture->i_planes = 0;
187         p_free_picture = p_destroyed_picture;
188     }
189
190     /*
191      * Prepare picture
192      */
193     if( p_free_picture != NULL )
194     {
195         NewPicture( p_free_picture, i_chroma, i_width, i_height );
196
197         if( p_free_picture->i_planes != 0 )
198         {
199             /* Copy picture information, set some default values */
200             p_free_picture->i_width               = i_width;
201             p_free_picture->i_height              = i_height;
202             p_free_picture->i_chroma              = i_chroma;
203             p_free_picture->i_aspect_ratio        = i_aspect_ratio;
204             p_free_picture->i_status              = RESERVED_PICTURE;
205             p_free_picture->i_matrix_coefficients = 1;
206             p_free_picture->i_refcount            = 0;
207             p_vout->i_pictures++;
208         }
209         else
210         {
211             /* Memory allocation failed : set picture as empty */
212             p_free_picture->i_chroma =  EMPTY_PICTURE;
213             p_free_picture->i_status =  FREE_PICTURE;
214             p_free_picture =            NULL;
215
216             intf_ErrMsg( "vout error: picture allocation failed" );
217         }
218
219         vlc_mutex_unlock( &p_vout->picture_lock );
220
221         /* Initialize mutex */
222         vlc_mutex_init( &(p_free_picture->lock_deccount) );
223
224         return( p_free_picture );
225     }
226
227     /* No free or destroyed picture could be found, but the decoder
228      * will try again in a while. */
229     vlc_mutex_unlock( &p_vout->picture_lock );
230
231     return( NULL );
232 }
233
234 /*****************************************************************************
235  * vout_DestroyPicture: remove a permanent or reserved picture from the heap
236  *****************************************************************************
237  * This function frees a previously reserved picture or a permanent
238  * picture. It is meant to be used when the construction of a picture aborted.
239  * Note that the picture will be destroyed even if it is linked !
240  *****************************************************************************/
241 void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_picture )
242 {
243     vlc_mutex_lock( &p_vout->picture_lock );
244
245 #ifdef DEBUG
246     /* Check if picture status is valid */
247     if( (p_picture->i_status != RESERVED_PICTURE) &&
248         (p_picture->i_status != RESERVED_DATED_PICTURE) &&
249         (p_picture->i_status != RESERVED_DISP_PICTURE) )
250     {
251         intf_ErrMsg( "error: picture %p has invalid status %d",
252                      p_picture, p_picture->i_status );
253     }
254 #endif
255
256     p_picture->i_status = DESTROYED_PICTURE;
257     p_vout->i_pictures--;
258
259     /* destroy the lock that had been initialized in CreatePicture */
260     vlc_mutex_destroy( &(p_picture->lock_deccount) );
261
262     vlc_mutex_unlock( &p_vout->picture_lock );
263 }
264
265 /*****************************************************************************
266  * vout_LinkPicture: increment reference counter of a picture
267  *****************************************************************************
268  * This function increments the reference counter of a picture in the video
269  * heap. It needs a lock since several producer threads can access the picture.
270  *****************************************************************************/
271 void vout_LinkPicture( vout_thread_t *p_vout, picture_t *p_picture )
272 {
273     vlc_mutex_lock( &p_vout->picture_lock );
274     p_picture->i_refcount++;
275
276 #ifdef TRACE_VOUT
277     intf_DbgMsg( "picture %p refcount=%d", p_picture, p_picture->i_refcount );
278 #endif
279
280     vlc_mutex_unlock( &p_vout->picture_lock );
281 }
282
283 /*****************************************************************************
284  * vout_UnlinkPicture: decrement reference counter of a picture
285  *****************************************************************************
286  * This function decrement the reference counter of a picture in the video heap.
287  *****************************************************************************/
288 void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_picture )
289 {
290     vlc_mutex_lock( &p_vout->picture_lock );
291     p_picture->i_refcount--;
292
293 #ifdef TRACE_VOUT
294     if( p_picture->i_refcount < 0 )
295     {
296         intf_DbgMsg( "error: refcount < 0" );
297         p_picture->i_refcount = 0;
298     }
299 #endif
300
301     if( ( p_picture->i_refcount == 0 ) &&
302         ( p_picture->i_status == DISPLAYED_PICTURE ) )
303     {
304         p_picture->i_status = DESTROYED_PICTURE;
305         p_vout->i_pictures--;
306     }
307
308 #ifdef TRACE_VOUT
309     intf_DbgMsg( "picture %p refcount=%d", p_picture, p_picture->i_refcount );
310 #endif
311
312     vlc_mutex_unlock( &p_vout->picture_lock );
313 }
314
315 /*****************************************************************************
316  * vout_RenderPicture: render a picture
317  *****************************************************************************
318  * This function chooses whether the current picture needs to be copied
319  * before rendering, does the subpicture magic, and tells the video output
320  * thread which direct buffer needs to be displayed.
321  *****************************************************************************/
322 picture_t * vout_RenderPicture( vout_thread_t *p_vout, picture_t *p_picture,
323                                                        subpicture_t *p_subpic )
324 {
325     int i_index;
326
327     if( p_picture == NULL )
328     {
329         /* XXX: subtitles */
330
331         return NULL;
332     }
333
334     if( p_picture->b_directbuffer )
335     {
336         if( p_picture->i_refcount )
337         {
338             /* Picture is in a direct buffer and is still in use,
339              * we need to copy it to another direct buffer before
340              * displaying it if there are subtitles. */
341             if( p_subpic != NULL )
342             {
343                 /* We have subtitles. First copy the picture to
344                  * the spare direct buffer, then render the
345                  * subtitles. */
346                 for( i_index = 0 ; i_index < p_picture->i_planes ; i_index++ )
347                 {
348                     p_main->fast_memcpy(
349                         p_vout->p_picture[0].planes[ i_index ].p_data,
350                         p_picture->planes[ i_index ].p_data,
351                         p_picture->planes[ i_index ].i_bytes );
352                 }
353
354                 vout_RenderSubPictures( &p_vout->p_picture[0], p_subpic );
355
356                 return &p_vout->p_picture[0];
357             }
358
359             /* No subtitles, picture is in a directbuffer so
360              * we can display it directly even if it is still
361              * in use. */
362             return p_picture;
363         }
364
365         /* Picture is in a direct buffer but isn't used by the
366          * decoder. We can safely render subtitles on it and
367          * display it. */
368         vout_RenderSubPictures( p_picture, p_subpic );
369
370         return p_picture;
371     }
372
373     /* Not a direct buffer. We either need to copy it to a direct buffer,
374      * or render it if the chroma isn't the same. */
375     if( ( p_picture->i_chroma == p_vout->p_picture[0].i_chroma ) &&
376         ( p_picture->i_height == p_vout->p_picture[0].i_height ) &&
377         ( p_picture->i_width  == p_vout->p_picture[0].i_width ) )
378     {
379         /* Picture is not in a direct buffer, but is exactly the
380          * same size as the direct buffers. A memcpy() is enough,
381          * then render the subtitles. */
382         for( i_index = 0; i_index < p_picture->i_planes; i_index++ )
383         {
384             p_main->fast_memcpy( p_vout->p_picture[0].planes[ i_index ].p_data,
385                                  p_picture->planes[ i_index ].p_data,
386                                  p_picture->planes[ i_index ].i_bytes );
387         }
388
389         vout_RenderSubPictures( &p_vout->p_picture[0], p_subpic );
390
391         return &p_vout->p_picture[0];
392     }
393
394     /* Picture is not in a direct buffer, and needs to be converted to
395      * another size/chroma. Then the subtitles need to be rendered as
396      * well. */
397
398     /* This usually means software YUV, or hardware YUV with a
399      * different chroma. */
400
401     /* XXX: render to direct buffer */
402
403     vout_RenderSubPictures( p_picture, p_subpic );
404
405     return &p_vout->p_picture[0];
406 }
407
408 /* Following functions are local */
409
410 /*****************************************************************************
411  * NewPicture: allocate a new picture in the heap.
412  *****************************************************************************
413  * This function allocates a fake direct buffer in memory, which can be
414  * used exactly like a video buffer. The video output thread then manages
415  * how it gets displayed.
416  *****************************************************************************/
417 static void NewPicture( picture_t *p_picture, int i_chroma,
418                         int i_width, int i_height )
419 {
420     int i_data_size = 0;
421
422     p_picture->i_size = i_width * i_height;
423
424     /* Calculate coordinates */
425     switch( i_chroma )
426     {
427         case YUV_420_PICTURE:        /* YUV 420: 1,1/4,1/4 samples per pixel */
428             p_picture->i_chroma_size = p_picture->i_size / 4;
429             p_picture->i_chroma_width = i_width / 2;
430             break;
431
432         case YUV_422_PICTURE:        /* YUV 422: 1,1/2,1/2 samples per pixel */
433             p_picture->i_chroma_size = p_picture->i_size / 2;
434             p_picture->i_chroma_width = i_width / 2;
435             break;
436
437         case YUV_444_PICTURE:            /* YUV 444: 1,1,1 samples per pixel */
438             p_picture->i_chroma_size = p_picture->i_size;
439             p_picture->i_chroma_width = i_width;
440             break;
441
442         default:
443             intf_ErrMsg("error: unknown chroma type %d", i_chroma );
444             p_picture->i_planes = 0;
445             return;
446     }
447
448     /* Allocate memory */
449     switch( i_chroma )
450     {
451         case YUV_420_PICTURE:        /* YUV 420: 1,1/4,1/4 samples per pixel */
452         case YUV_422_PICTURE:        /* YUV 422: 1,1/2,1/2 samples per pixel */
453         case YUV_444_PICTURE:            /* YUV 444: 1,1,1 samples per pixel */
454
455             i_data_size = p_picture->i_size + 2 * p_picture->i_chroma_size;
456
457             /* The Y plane */
458             p_picture->planes[ Y_PLANE ].i_bytes =
459                  p_picture->i_size * sizeof(pixel_data_t);
460             p_picture->planes[ Y_PLANE ].p_data =
461                  memalign( 16, i_data_size * sizeof(pixel_data_t) * 4 );
462             /* The U plane */
463             p_picture->planes[ U_PLANE ].i_bytes =
464                  p_picture->i_chroma_size * sizeof(pixel_data_t);
465             p_picture->planes[ U_PLANE ].p_data =
466                  p_picture->planes[ Y_PLANE ].p_data + p_picture->i_size;
467             /* The V plane */
468             p_picture->planes[ V_PLANE ].i_bytes =
469                  p_picture->i_chroma_size * sizeof(pixel_data_t);
470             p_picture->planes[ V_PLANE ].p_data =
471                  p_picture->planes[ U_PLANE ].p_data + p_picture->i_chroma_size;
472
473             p_picture->i_planes = 3;
474
475             break;
476
477         default:
478             p_picture->i_planes = 0;
479
480             break;
481     }
482 }
483