* ./src/misc/modules_plugin.h: exported input_ClockManageRef for fenrir.
[vlc.git] / src / video_output / vout_subpictures.c
blob0e9cebd32bba92e7767614cb778ee9c56f1a6cb6
1 /*****************************************************************************
2 * vout_subpictures.c : subpicture management functions
3 *****************************************************************************
4 * Copyright (C) 2000 VideoLAN
5 * $Id: vout_subpictures.c,v 1.13 2002/04/25 21:52:42 sam Exp $
7 * Authors: Vincent Seguin <seguin@via.ecp.fr>
8 * Samuel Hocevar <sam@zoy.org>
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.
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.
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 *****************************************************************************/
25 /*****************************************************************************
26 * Preamble
27 *****************************************************************************/
28 #include <errno.h> /* ENOMEM */
29 #include <stdlib.h> /* free() */
30 #include <stdio.h> /* sprintf() */
31 #include <string.h> /* strerror() */
33 #include <videolan/vlc.h>
35 #include "video.h"
36 #include "video_output.h"
38 /*****************************************************************************
39 * vout_DisplaySubPicture: display a subpicture unit
40 *****************************************************************************
41 * Remove the reservation flag of a subpicture, which will cause it to be
42 * ready for display.
43 *****************************************************************************/
44 void vout_DisplaySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic )
46 int i_margin;
48 /* Check if status is valid */
49 if( p_subpic->i_status != RESERVED_SUBPICTURE )
51 intf_ErrMsg( "vout error: subpicture %p has invalid status #%d",
52 p_subpic, p_subpic->i_status );
55 /* If the user requested an SPU margin, we force the position after
56 * having checked that it was a valid value. */
57 i_margin = config_GetIntVariable( "spumargin" );
59 if( i_margin >= 0 )
61 if( p_subpic->i_height + i_margin <= p_vout->output.i_height )
63 p_subpic->i_y = p_vout->output.i_height
64 - i_margin - p_subpic->i_height;
68 /* Remove reservation flag */
69 p_subpic->i_status = READY_SUBPICTURE;
72 /*****************************************************************************
73 * vout_CreateSubPicture: allocate a subpicture in the video output heap.
74 *****************************************************************************
75 * This function create a reserved subpicture in the video output heap.
76 * A null pointer is returned if the function fails. This method provides an
77 * already allocated zone of memory in the spu data fields. It needs locking
78 * since several pictures can be created by several producers threads.
79 *****************************************************************************/
80 subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type,
81 int i_size )
83 int i_subpic; /* subpicture index */
84 subpicture_t * p_free_subpic = NULL; /* first free subpicture */
85 subpicture_t * p_destroyed_subpic = NULL; /* first destroyed subpic */
87 /* Get lock */
88 vlc_mutex_lock( &p_vout->subpicture_lock );
91 * Look for an empty place
93 for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ )
95 if( p_vout->p_subpicture[i_subpic].i_status == DESTROYED_SUBPICTURE )
97 /* Subpicture is marked for destruction, but is still allocated */
98 if( (p_vout->p_subpicture[i_subpic].i_type == i_type) &&
99 (p_vout->p_subpicture[i_subpic].i_size >= i_size) )
101 /* Memory size do match or is smaller : memory will not be
102 * reallocated, and function can end immediately - this is
103 * the best possible case, since no memory allocation needs
104 * to be done */
105 p_vout->p_subpicture[i_subpic].i_status = RESERVED_SUBPICTURE;
106 vlc_mutex_unlock( &p_vout->subpicture_lock );
107 return( &p_vout->p_subpicture[i_subpic] );
109 else if( p_destroyed_subpic == NULL )
111 /* Memory size do not match, but subpicture index will be kept
112 * in case we find no other place */
113 p_destroyed_subpic = &p_vout->p_subpicture[i_subpic];
116 else if( (p_free_subpic == NULL) &&
117 (p_vout->p_subpicture[i_subpic].i_status == FREE_SUBPICTURE ))
119 /* Subpicture is empty and ready for allocation */
120 p_free_subpic = &p_vout->p_subpicture[i_subpic];
124 /* If no free subpictures are available, use a destroyed subpicture */
125 if( (p_free_subpic == NULL) && (p_destroyed_subpic != NULL ) )
127 /* No free subpicture or matching destroyed subpictures have been
128 * found, but a destroyed subpicture is still available */
129 free( p_destroyed_subpic->p_sys_orig );
130 p_free_subpic = p_destroyed_subpic;
133 /* If no free or destroyed subpicture could be found */
134 if( p_free_subpic == NULL )
136 intf_ErrMsg( "vout error: subpicture heap is full" );
137 vlc_mutex_unlock( &p_vout->subpicture_lock );
138 return( NULL );
141 p_free_subpic->p_sys =
142 vlc_memalign( &p_free_subpic->p_sys_orig, 16, i_size );
144 if( p_free_subpic->p_sys != NULL )
146 /* Copy subpicture information, set some default values */
147 p_free_subpic->i_type = i_type;
148 p_free_subpic->i_status = RESERVED_SUBPICTURE;
149 p_free_subpic->i_size = i_size;
150 p_free_subpic->i_x = 0;
151 p_free_subpic->i_y = 0;
152 p_free_subpic->i_width = 0;
153 p_free_subpic->i_height = 0;
155 else
157 /* Memory allocation failed : set subpicture as empty */
158 p_free_subpic->i_type = EMPTY_SUBPICTURE;
159 p_free_subpic->i_status = FREE_SUBPICTURE;
160 p_free_subpic = NULL;
161 intf_ErrMsg( "vout error: spu allocation returned %s",
162 strerror( ENOMEM ) );
165 vlc_mutex_unlock( &p_vout->subpicture_lock );
167 return( p_free_subpic );
170 /*****************************************************************************
171 * vout_DestroySubPicture: remove a subpicture from the heap
172 *****************************************************************************
173 * This function frees a previously reserved subpicture.
174 * It is meant to be used when the construction of a picture aborted.
175 * This function does not need locking since reserved subpictures are ignored
176 * by the output thread.
177 *****************************************************************************/
178 void vout_DestroySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic )
180 /* Check if status is valid */
181 if( ( p_subpic->i_status != RESERVED_SUBPICTURE )
182 && ( p_subpic->i_status != READY_SUBPICTURE ) )
184 intf_ErrMsg( "vout error: subpicture %p has invalid status %d",
185 p_subpic, p_subpic->i_status );
188 p_subpic->i_status = DESTROYED_SUBPICTURE;
191 /*****************************************************************************
192 * vout_RenderSubPictures: render a subpicture list
193 *****************************************************************************
194 * This function renders all sub picture units in the list.
195 *****************************************************************************/
196 void vout_RenderSubPictures( vout_thread_t *p_vout, picture_t *p_pic,
197 subpicture_t *p_subpic )
199 while( p_subpic != NULL )
201 p_subpic->pf_render( p_vout, p_pic, p_subpic );
202 p_subpic = p_subpic->p_next;
206 /*****************************************************************************
207 * vout_SortSubPictures: find the subpictures to display
208 *****************************************************************************
209 * This function parses all subpictures and decides which ones need to be
210 * displayed. This operation does not need lock, since only READY_SUBPICTURE
211 * are handled. If no picture has been selected, display_date will depend on
212 * the subpicture.
213 * We also check for ephemer DVD subpictures (subpictures that have
214 * to be removed if a newer one is available), which makes it a lot
215 * more difficult to guess if a subpicture has to be rendered or not.
216 *****************************************************************************/
217 subpicture_t *vout_SortSubPictures( vout_thread_t *p_vout,
218 mtime_t display_date )
220 int i_index;
221 subpicture_t *p_subpic = NULL;
222 subpicture_t *p_ephemer = NULL;
223 mtime_t ephemer_date = 0;
225 /* We get an easily parsable chained list of subpictures which
226 * ends with NULL since p_subpic was initialized to NULL. */
227 for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++ )
229 if( p_vout->p_subpicture[i_index].i_status == READY_SUBPICTURE )
231 /* If it is a DVD subpicture, check its date */
232 if( p_vout->p_subpicture[i_index].i_type == MEMORY_SUBPICTURE )
234 if( display_date > p_vout->p_subpicture[i_index].i_stop )
236 /* Too late, destroy the subpic */
237 vout_DestroySubPicture( p_vout,
238 &p_vout->p_subpicture[i_index] );
239 continue;
242 if( display_date < p_vout->p_subpicture[i_index].i_start )
244 /* Too early, come back next monday */
245 continue;
248 /* If this is an ephemer subpic, see if it's the
249 * youngest we have */
250 if( p_vout->p_subpicture[i_index].b_ephemer )
252 if( p_ephemer == NULL )
254 p_ephemer = &p_vout->p_subpicture[i_index];
255 continue;
258 if( p_vout->p_subpicture[i_index].i_start
259 < p_ephemer->i_start )
261 /* Link the previous ephemer subpicture and
262 * replace it with the current one */
263 p_ephemer->p_next = p_subpic;
264 p_subpic = p_ephemer;
265 p_ephemer = &p_vout->p_subpicture[i_index];
267 /* If it's the 2nd youngest subpicture,
268 * register its date */
269 if( !ephemer_date
270 || ephemer_date > p_subpic->i_start )
272 ephemer_date = p_subpic->i_start;
275 continue;
279 p_vout->p_subpicture[i_index].p_next = p_subpic;
280 p_subpic = &p_vout->p_subpicture[i_index];
282 /* If it's the 2nd youngest subpicture, register its date */ if( !ephemer_date || ephemer_date > p_subpic->i_start )
284 ephemer_date = p_subpic->i_start;
287 /* If it's not a DVD subpicture, just register it */
288 else
290 p_vout->p_subpicture[i_index].p_next = p_subpic;
291 p_subpic = &p_vout->p_subpicture[i_index];
296 /* If we found an ephemer subpicture, check if it has to be
297 * displayed */
298 if( p_ephemer != NULL )
300 if( p_ephemer->i_start < ephemer_date )
302 /* Ephemer subpicture has lived too long */
303 vout_DestroySubPicture( p_vout, p_ephemer );
305 else
307 /* Ephemer subpicture can still live a bit */
308 p_ephemer->p_next = p_subpic;
309 return p_ephemer;
313 return p_subpic;