1 /*****************************************************************************
2 * vout_subpictures.c : subpicture management functions
3 *****************************************************************************
4 * Copyright (C) 2000 VideoLAN
5 * $Id: vout_subpictures.c,v 1.1 2001/12/09 17:01:37 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 /*****************************************************************************
27 *****************************************************************************/
30 #include <errno.h> /* ENOMEM */
31 #include <stdlib.h> /* free() */
32 #include <stdio.h> /* sprintf() */
33 #include <string.h> /* strerror() */
41 #include "video_output.h"
43 /*****************************************************************************
45 *****************************************************************************/
46 static void vout_RenderRGBSPU( picture_t *p_pic, const subpicture_t *p_spu );
47 static void vout_RenderYUVSPU( picture_t *p_pic, const subpicture_t *p_spu );
49 /* FIXME: fake palette - the real one has to be sought in the .IFO */
50 static int p_palette[4] = { 0x0000, 0x0000, 0xffff, 0x8888 };
52 /*****************************************************************************
53 * vout_DisplaySubPicture: display a subpicture unit
54 *****************************************************************************
55 * Remove the reservation flag of a subpicture, which will cause it to be ready
56 * for display. The picture does not need to be locked, since it is ignored by
57 * the output thread if is reserved.
58 *****************************************************************************/
59 void vout_DisplaySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic )
62 char psz_start[ MSTRTIME_MAX_SIZE ]; /* buffer for date string */
63 char psz_stop[ MSTRTIME_MAX_SIZE ]; /* buffer for date string */
67 /* Check if status is valid */
68 if( p_subpic->i_status != RESERVED_SUBPICTURE )
70 intf_ErrMsg("error: subpicture %p has invalid status %d", p_subpic,
75 /* Remove reservation flag */
76 p_subpic->i_status = READY_SUBPICTURE;
79 /* Send subpicture information */
80 intf_DbgMsg("subpicture %p: type=%d, begin date=%s, end date=%s",
81 p_subpic, p_subpic->i_type,
82 mstrtime( psz_start, p_subpic->i_start ),
83 mstrtime( psz_stop, p_subpic->i_stop ) );
87 /*****************************************************************************
88 * vout_CreateSubPicture: allocate a subpicture in the video output heap.
89 *****************************************************************************
90 * This function create a reserved subpicture in the video output heap.
91 * A null pointer is returned if the function fails. This method provides an
92 * already allocated zone of memory in the spu data fields. It needs locking
93 * since several pictures can be created by several producers threads.
94 *****************************************************************************/
95 subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type,
98 int i_subpic; /* subpicture index */
99 subpicture_t * p_free_subpic = NULL; /* first free subpicture */
100 subpicture_t * p_destroyed_subpic = NULL; /* first destroyed subpic */
103 vlc_mutex_lock( &p_vout->subpicture_lock );
106 * Look for an empty place
108 for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ )
110 if( p_vout->p_subpicture[i_subpic].i_status == DESTROYED_SUBPICTURE )
112 /* Subpicture is marked for destruction, but is still allocated */
113 if( (p_vout->p_subpicture[i_subpic].i_type == i_type) &&
114 (p_vout->p_subpicture[i_subpic].i_size >= i_size) )
116 /* Memory size do match or is smaller : memory will not be
117 * reallocated, and function can end immediately - this is
118 * the best possible case, since no memory allocation needs
120 p_vout->p_subpicture[i_subpic].i_status = RESERVED_SUBPICTURE;
122 intf_DbgMsg("subpicture %p (in destroyed subpicture slot)",
123 &p_vout->p_subpicture[i_subpic] );
125 vlc_mutex_unlock( &p_vout->subpicture_lock );
126 return( &p_vout->p_subpicture[i_subpic] );
128 else if( p_destroyed_subpic == NULL )
130 /* Memory size do not match, but subpicture index will be kept
131 * in case we find no other place */
132 p_destroyed_subpic = &p_vout->p_subpicture[i_subpic];
135 else if( (p_free_subpic == NULL) &&
136 (p_vout->p_subpicture[i_subpic].i_status == FREE_SUBPICTURE ))
138 /* Subpicture is empty and ready for allocation */
139 p_free_subpic = &p_vout->p_subpicture[i_subpic];
143 /* If no free subpictures are available, use a destroyed subpicture */
144 if( (p_free_subpic == NULL) && (p_destroyed_subpic != NULL ) )
146 /* No free subpicture or matching destroyed subpictures have been
147 * found, but a destroyed subpicture is still avalaible */
148 free( p_destroyed_subpic->p_data );
149 p_free_subpic = p_destroyed_subpic;
155 if( p_free_subpic != NULL )
157 /* Allocate memory */
160 case TEXT_SUBPICTURE: /* text subpicture */
161 p_free_subpic->p_data = memalign( 16, i_size + 1 );
163 case DVD_SUBPICTURE: /* DVD subpicture unit */
164 p_free_subpic->p_data = memalign( 16, i_size );
168 intf_ErrMsg("error: unknown subpicture type %d", i_type );
169 p_free_subpic->p_data = NULL;
174 if( p_free_subpic->p_data != NULL )
176 /* Copy subpicture information, set some default values */
177 p_free_subpic->i_type = i_type;
178 p_free_subpic->i_status = RESERVED_SUBPICTURE;
179 p_free_subpic->i_size = i_size;
180 p_free_subpic->i_x = 0;
181 p_free_subpic->i_y = 0;
182 p_free_subpic->i_width = 0;
183 p_free_subpic->i_height = 0;
184 p_free_subpic->i_horizontal_align = CENTER_RALIGN;
185 p_free_subpic->i_vertical_align = CENTER_RALIGN;
189 /* Memory allocation failed : set subpicture as empty */
190 p_free_subpic->i_type = EMPTY_SUBPICTURE;
191 p_free_subpic->i_status = FREE_SUBPICTURE;
192 p_free_subpic = NULL;
193 intf_ErrMsg( "vout error: spu allocation returned %s",
194 strerror( ENOMEM ) );
198 intf_DbgMsg("subpicture %p (in free subpicture slot)", p_free_subpic );
200 vlc_mutex_unlock( &p_vout->subpicture_lock );
201 return( p_free_subpic );
204 /* No free or destroyed subpicture could be found */
205 intf_DbgMsg( "warning: subpicture heap is full" );
206 vlc_mutex_unlock( &p_vout->subpicture_lock );
210 /*****************************************************************************
211 * vout_DestroySubPicture: remove a subpicture from the heap
212 *****************************************************************************
213 * This function frees a previously reserved subpicture.
214 * It is meant to be used when the construction of a picture aborted.
215 * This function does not need locking since reserved subpictures are ignored
216 * by the output thread.
217 *****************************************************************************/
218 void vout_DestroySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic )
221 /* Check if status is valid */
222 if( p_subpic->i_status != RESERVED_SUBPICTURE )
224 intf_ErrMsg("error: subpicture %p has invalid status %d",
225 p_subpic, p_subpic->i_status );
229 p_subpic->i_status = DESTROYED_SUBPICTURE;
232 intf_DbgMsg("subpicture %p", p_subpic);
236 /*****************************************************************************
237 * vout_RenderSubPictures: render a subpicture list
238 *****************************************************************************
239 * This function renders a sub picture unit.
240 *****************************************************************************/
241 void vout_RenderSubPictures( picture_t *p_pic, subpicture_t *p_subpic )
244 p_vout_font_t p_font; /* text font */
245 int i_width, i_height; /* subpicture dimensions */
248 while( p_subpic != NULL )
250 switch( p_subpic->i_type )
252 case DVD_SUBPICTURE: /* DVD subpicture unit */
253 vout_RenderRGBSPU( p_pic, p_subpic );
254 vout_RenderYUVSPU( p_pic, p_subpic );
258 case TEXT_SUBPICTURE: /* single line text */
259 /* Select default font if not specified */
260 p_font = p_subpic->type.text.p_font;
263 p_font = p_vout->p_default_font;
266 /* Compute text size (width and height fields are ignored)
268 vout_TextSize( p_font, p_subpic->type.text.i_style,
269 p_subpic->p_data, &i_width, &i_height );
270 if( !Align( p_vout, &p_subpic->i_x, &p_subpic->i_y,
271 i_width, i_height, p_subpic->i_horizontal_align,
272 p_subpic->i_vertical_align ) )
275 p_vout->p_buffer[ p_vout->i_buffer_index ].p_data +
276 p_subpic->i_x * p_vout->i_bytes_per_pixel +
277 p_subpic->i_y * p_vout->i_bytes_per_line,
278 p_vout->i_bytes_per_pixel, p_vout->i_bytes_per_line, p_subpic->type.text.i_char_color,
279 p_subpic->type.text.i_border_color,
280 p_subpic->type.text.i_bg_color,
281 p_subpic->type.text.i_style, p_subpic->p_data, 100 );
282 SetBufferArea( p_vout, p_subpic->i_x, p_subpic->i_y,
290 intf_ErrMsg( "error: unknown subpicture %p type %d",
291 p_subpic, p_subpic->i_type );
296 p_subpic = p_subpic->p_next;
300 /*****************************************************************************
301 * vout_SortSubPictures: find the subpictures to display
302 *****************************************************************************
303 * This function parses all subpictures and decides which ones need to be
304 * displayed. This operation does not need lock, since only READY_SUBPICTURE
305 * are handled. If no picture has been selected, display_date will depend on
307 * We also check for ephemer DVD subpictures (subpictures that have
308 * to be removed if a newer one is available), which makes it a lot
309 * more difficult to guess if a subpicture has to be rendered or not.
310 *****************************************************************************/
311 subpicture_t *vout_SortSubPictures( vout_thread_t *p_vout,
312 mtime_t display_date )
315 subpicture_t *p_subpic = NULL;
316 subpicture_t *p_ephemer = NULL;
317 mtime_t ephemer_date = 0;
319 /* We get an easily parsable chained list of subpictures which
320 * ends with NULL since p_subpic was initialized to NULL. */
321 for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++ )
323 if( p_vout->p_subpicture[i_index].i_status == READY_SUBPICTURE )
325 /* If it is a DVD subpicture, check its date */
326 if( p_vout->p_subpicture[i_index].i_type == DVD_SUBPICTURE )
328 if( display_date > p_vout->p_subpicture[i_index].i_stop )
330 /* Too late, destroy the subpic */
331 vout_DestroySubPicture( p_vout,
332 &p_vout->p_subpicture[i_index] );
336 if( display_date < p_vout->p_subpicture[i_index].i_start )
338 /* Too early, come back next monday */
342 /* If this is an ephemer subpic, see if it's the
343 * youngest we have */
344 if( p_vout->p_subpicture[i_index].b_ephemer )
346 if( p_ephemer == NULL )
348 p_ephemer = &p_vout->p_subpicture[i_index];
352 if( p_vout->p_subpicture[i_index].i_start
353 < p_ephemer->i_start )
355 /* Link the previous ephemer subpicture and
356 * replace it with the current one */
357 p_ephemer->p_next = p_subpic;
358 p_subpic = p_ephemer;
359 p_ephemer = &p_vout->p_subpicture[i_index];
361 /* If it's the 2nd youngest subpicture,
362 * register its date */
364 || ephemer_date > p_subpic->i_start )
366 ephemer_date = p_subpic->i_start;
373 p_vout->p_subpicture[i_index].p_next = p_subpic;
374 p_subpic = &p_vout->p_subpicture[i_index];
376 /* If it's the 2nd youngest subpicture, register its date */ if( !ephemer_date || ephemer_date > p_subpic->i_start )
378 ephemer_date = p_subpic->i_start;
381 /* If it's not a DVD subpicture, just register it */
384 p_vout->p_subpicture[i_index].p_next = p_subpic;
385 p_subpic = &p_vout->p_subpicture[i_index];
390 /* If we found an ephemer subpicture, check if it has to be
392 if( p_ephemer != NULL )
394 if( p_ephemer->i_start < ephemer_date )
396 /* Ephemer subpicture has lived too long */
397 vout_DestroySubPicture( p_vout, p_ephemer );
401 /* Ephemer subpicture can still live a bit */
402 p_ephemer->p_next = p_subpic;
410 /*****************************************************************************
411 * vout_RenderRGBSPU: draw an SPU on a picture
412 *****************************************************************************
413 * This is a fast implementation of the subpicture drawing code. The data
414 * has been preprocessed once in spu_decoder.c, so we don't need to parse the
415 * RLE buffer again and again. Most sanity checks are done in spu_decoder.c
416 * so that this routine can be as fast as possible.
417 *****************************************************************************/
418 static void vout_RenderRGBSPU( picture_t *p_pic, const subpicture_t *p_spu )
422 u16 *p_source = (u16 *)p_spu->p_data;
424 int i_xscale = ( p_buffer->i_pic_width << 6 ) / p_pic->i_width;
425 int i_yscale = ( p_buffer->i_pic_height << 6 ) / p_pic->i_height;
427 int i_width = p_spu->i_width * i_xscale;
428 int i_height = p_spu->i_height * i_yscale;
430 int i_x, i_y, i_ytmp, i_yreal, i_ynext;
432 u8 *p_dest = p_buffer->p_data + ( i_width >> 6 ) * i_bytes_per_pixel
433 /* Add the picture coordinates and the SPU coordinates */
434 + ( p_buffer->i_pic_x + ((p_spu->i_x * i_xscale) >> 6))
436 + ( p_buffer->i_pic_y + ((p_spu->i_y * i_yscale) >> 6))
439 /* Draw until we reach the bottom of the subtitle */
442 while( i_y < i_height )
447 /* Check whether we need to draw one line or more than one */
448 if( i_ytmp + 1 >= ( i_y >> 6 ) )
450 /* Just one line : we precalculate i_y >> 6 */
451 i_yreal = i_bytes_per_line * i_ytmp;
453 /* Draw until we reach the end of the line */
458 /* Get the RLE part */
459 i_color = *p_source & 0x3;
464 i_len = i_xscale * ( *p_source++ >> 2 );
466 memset( p_dest - i_bytes_per_pixel * ( i_x >> 6 )
468 p_palette[ i_color ],
469 i_bytes_per_pixel * ( ( i_len >> 6 ) + 1 ) );
475 i_x -= i_xscale * ( *p_source++ >> 2 );
480 i_yreal = i_bytes_per_line * i_ytmp;
481 i_ynext = i_bytes_per_line * i_y >> 6;
483 /* Draw until we reach the end of the line */
488 /* Get the RLE part */
489 i_color = *p_source & 0x3;
491 /* Draw as many lines as needed */
494 i_len = i_xscale * ( *p_source++ >> 2 );
496 for( i_ytmp = i_yreal ;
498 i_ytmp += i_bytes_per_line )
500 memset( p_dest - i_bytes_per_pixel * ( i_x >> 6 )
502 p_palette[ i_color ],
503 i_bytes_per_pixel * ( ( i_len >> 6 ) + 1 ) );
510 i_x -= i_xscale * ( *p_source++ >> 2 );
517 /*****************************************************************************
518 * vout_RenderYUVSPU: draw an SPU on an YUV overlay
519 *****************************************************************************
520 * This is a fast implementation of the subpicture drawing code. The data
521 * has been preprocessed once in spu_decoder.c, so we don't need to parse the
522 * RLE buffer again and again. Most sanity checks are done in spu_decoder.c
523 * so that this routine can be as fast as possible.
524 *****************************************************************************/
525 static void vout_RenderYUVSPU( picture_t *p_pic, const subpicture_t *p_spu )
528 u16 *p_source = (u16 *)p_spu->p_data;
532 u8 *p_dest = p_pic->planes[ Y_PLANE ].p_data + p_spu->i_x + p_spu->i_width
533 + p_pic->i_width * ( p_spu->i_y + p_spu->i_height );
535 /* Draw until we reach the bottom of the subtitle */
536 i_y = p_spu->i_height * p_pic->i_width;
540 /* Draw until we reach the end of the line */
541 i_x = p_spu->i_width;
545 /* Draw the line if needed */
546 i_color = *p_source & 0x3;
550 i_len = *p_source++ >> 2;
551 memset( p_dest - i_x - i_y, p_palette[ i_color ], i_len );
556 i_x -= *p_source++ >> 2;
559 i_y -= p_pic->i_width;