1 /*****************************************************************************
2 * vout_subpictures.c : subpicture management functions
3 *****************************************************************************
4 * Copyright (C) 2000-2004 VideoLAN
7 * Authors: Vincent Seguin <seguin@via.ecp.fr>
8 * Samuel Hocevar <sam@zoy.org>
9 * Gildas Bazin <gbazin@videolan.org>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
24 *****************************************************************************/
26 /*****************************************************************************
28 *****************************************************************************/
29 #include <stdlib.h> /* free() */
30 #include <stdio.h> /* sprintf() */
31 #include <string.h> /* strerror() */
35 #include "vlc_block.h"
36 #include "vlc_video.h"
37 #include "video_output.h"
39 #include "vlc_filter.h"
42 /*****************************************************************************
44 *****************************************************************************/
45 static void UpdateSPU ( spu_t *, vlc_object_t * );
46 static int CropCallback( vlc_object_t *, char const *,
47 vlc_value_t, vlc_value_t, void * );
49 static subpicture_t *spu_new_buffer( filter_t * );
50 static void spu_del_buffer( filter_t *, subpicture_t * );
51 static picture_t *spu_new_video_buffer( filter_t * );
52 static void spu_del_video_buffer( filter_t *, picture_t * );
55 * Initialise the subpicture unit
57 * \param p_this the parent object which creates the subpicture unit
59 spu_t *__spu_Init( vlc_object_t *p_this )
62 spu_t *p_spu = vlc_object_create( p_this, VLC_OBJECT_SPU );
64 for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++)
66 p_spu->p_subpicture[i_index].i_status = FREE_SUBPICTURE;
67 p_spu->p_subpicture[i_index].i_type = EMPTY_SUBPICTURE;
70 p_spu->p_blend = NULL;
72 p_spu->p_scale = NULL;
74 /* Register the default subpicture channel */
77 vlc_mutex_init( p_this, &p_spu->subpicture_lock );
79 vlc_object_attach( p_spu, p_this );
81 /* If the user requested an SPU margin, we force the position. */
82 p_spu->i_margin = config_GetInt( p_spu, "spumargin" );
88 * Destroy the subpicture unit
90 * \param p_this the parent object which destroys the subpicture unit
92 void spu_Destroy( spu_t *p_spu )
96 vlc_object_detach( p_spu );
98 /* Destroy all remaining subpictures */
99 for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++ )
101 if( p_spu->p_subpicture[i_index].i_status != FREE_SUBPICTURE )
103 spu_DestroySubpicture( p_spu, &p_spu->p_subpicture[i_index] );
109 if( p_spu->p_blend->p_module )
110 module_Unneed( p_spu->p_blend, p_spu->p_blend->p_module );
112 vlc_object_detach( p_spu->p_blend );
113 vlc_object_destroy( p_spu->p_blend );
118 if( p_spu->p_text->p_module )
119 module_Unneed( p_spu->p_text, p_spu->p_text->p_module );
121 vlc_object_detach( p_spu->p_text );
122 vlc_object_destroy( p_spu->p_text );
127 if( p_spu->p_scale->p_module )
128 module_Unneed( p_spu->p_scale, p_spu->p_scale->p_module );
130 vlc_object_detach( p_spu->p_scale );
131 vlc_object_destroy( p_spu->p_scale );
134 vlc_mutex_destroy( &p_spu->subpicture_lock );
135 vlc_object_destroy( p_spu );
139 * Attach/Detach the SPU from any input
141 * \param p_this the object in which to destroy the subpicture unit
142 * \param b_attach to select attach or detach
144 void spu_Attach( spu_t *p_spu, vlc_object_t *p_this, vlc_bool_t b_attach )
146 vlc_object_t *p_input;
148 p_input = vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_PARENT );
149 if( !p_input ) return;
153 UpdateSPU( p_spu, VLC_OBJECT(p_input) );
154 var_AddCallback( p_input, "highlight", CropCallback, p_spu );
155 vlc_object_release( p_input );
159 /* Delete callback */
160 var_DelCallback( p_input, "highlight", CropCallback, p_spu );
161 vlc_object_release( p_input );
166 * Create a subpicture region
168 * \param p_this vlc_object_t
169 * \param p_fmt the format that this subpicture region should have
171 static void RegionPictureRelease( picture_t *p_pic )
173 if( p_pic->p_data_orig ) free( p_pic->p_data_orig );
175 subpicture_region_t *__spu_CreateRegion( vlc_object_t *p_this,
176 video_format_t *p_fmt )
178 subpicture_region_t *p_region = malloc( sizeof(subpicture_region_t) );
179 memset( p_region, 0, sizeof(subpicture_region_t) );
180 p_region->p_next = 0;
181 p_region->p_cache = 0;
182 p_region->fmt = *p_fmt;
183 p_region->psz_text = 0;
185 if( p_fmt->i_chroma == VLC_FOURCC('Y','U','V','P') )
186 p_fmt->p_palette = p_region->fmt.p_palette =
187 malloc( sizeof(video_palette_t) );
188 else p_fmt->p_palette = p_region->fmt.p_palette = NULL;
190 p_region->picture.p_data_orig = 0;
192 if( p_fmt->i_chroma == VLC_FOURCC('T','E','X','T') ) return p_region;
194 vout_AllocatePicture( p_this, &p_region->picture, p_fmt->i_chroma,
195 p_fmt->i_width, p_fmt->i_height, p_fmt->i_aspect );
197 if( !p_region->picture.i_planes )
200 free( p_fmt->p_palette );
204 p_region->picture.pf_release = RegionPictureRelease;
210 * Destroy a subpicture region
212 * \param p_this vlc_object_t
213 * \param p_region the subpicture region to destroy
215 void __spu_DestroyRegion( vlc_object_t *p_this, subpicture_region_t *p_region )
217 if( !p_region ) return;
218 if( p_region->picture.pf_release )
219 p_region->picture.pf_release( &p_region->picture );
220 if( p_region->fmt.p_palette ) free( p_region->fmt.p_palette );
221 if( p_region->psz_text ) free( p_region->psz_text );
222 if( p_region->p_cache ) __spu_DestroyRegion( p_this, p_region->p_cache );
227 * Display a subpicture
229 * Remove the reservation flag of a subpicture, which will cause it to be
231 * \param p_spu the subpicture unit object
232 * \param p_subpic the subpicture to display
234 void spu_DisplaySubpicture( spu_t *p_spu, subpicture_t *p_subpic )
236 /* Check if status is valid */
237 if( p_subpic->i_status != RESERVED_SUBPICTURE )
239 msg_Err( p_spu, "subpicture %p has invalid status #%d",
240 p_subpic, p_subpic->i_status );
243 /* Remove reservation flag */
244 p_subpic->i_status = READY_SUBPICTURE;
246 if( p_subpic->i_channel == DEFAULT_CHAN )
248 p_subpic->i_channel = 0xFFFF;
249 spu_Control( p_spu, SPU_CHANNEL_CLEAR, DEFAULT_CHAN );
250 p_subpic->i_channel = DEFAULT_CHAN;
255 * Allocate a subpicture in the spu heap.
257 * This function create a reserved subpicture in the spu heap.
258 * A null pointer is returned if the function fails. This method provides an
259 * already allocated zone of memory in the spu data fields. It needs locking
260 * since several pictures can be created by several producers threads.
261 * \param p_spu the subpicture unit in which to create the subpicture
262 * \return NULL on error, a reserved subpicture otherwise
264 subpicture_t *spu_CreateSubpicture( spu_t *p_spu )
266 int i_subpic; /* subpicture index */
267 subpicture_t * p_subpic = NULL; /* first free subpicture */
270 vlc_mutex_lock( &p_spu->subpicture_lock );
273 * Look for an empty place
276 for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ )
278 if( p_spu->p_subpicture[i_subpic].i_status == FREE_SUBPICTURE )
280 /* Subpicture is empty and ready for allocation */
281 p_subpic = &p_spu->p_subpicture[i_subpic];
282 p_spu->p_subpicture[i_subpic].i_status = RESERVED_SUBPICTURE;
287 /* If no free subpicture could be found */
288 if( p_subpic == NULL )
290 msg_Err( p_spu, "subpicture heap is full" );
291 vlc_mutex_unlock( &p_spu->subpicture_lock );
295 /* Copy subpicture information, set some default values */
296 memset( p_subpic, 0, sizeof(subpicture_t) );
297 p_subpic->i_type = MEMORY_SUBPICTURE;
298 p_subpic->i_status = RESERVED_SUBPICTURE;
299 p_subpic->b_absolute = VLC_TRUE;
300 p_subpic->pf_render = 0;
301 p_subpic->pf_destroy = 0;
304 vlc_mutex_unlock( &p_spu->subpicture_lock );
306 p_subpic->pf_create_region = __spu_CreateRegion;
307 p_subpic->pf_destroy_region = __spu_DestroyRegion;
313 * Remove a subpicture from the heap
315 * This function frees a previously reserved subpicture.
316 * It is meant to be used when the construction of a picture aborted.
317 * This function does not need locking since reserved subpictures are ignored
320 void spu_DestroySubpicture( spu_t *p_spu, subpicture_t *p_subpic )
323 vlc_mutex_lock( &p_spu->subpicture_lock );
325 /* There can be race conditions so we need to check the status */
326 if( p_subpic->i_status == FREE_SUBPICTURE )
328 vlc_mutex_unlock( &p_spu->subpicture_lock );
332 /* Check if status is valid */
333 if( ( p_subpic->i_status != RESERVED_SUBPICTURE )
334 && ( p_subpic->i_status != READY_SUBPICTURE ) )
336 msg_Err( p_spu, "subpicture %p has invalid status %d",
337 p_subpic, p_subpic->i_status );
340 while( p_subpic->p_region )
342 subpicture_region_t *p_region = p_subpic->p_region;
343 p_subpic->p_region = p_region->p_next;
344 spu_DestroyRegion( p_spu, p_region );
347 if( p_subpic->pf_destroy )
349 p_subpic->pf_destroy( p_subpic );
352 p_subpic->i_status = FREE_SUBPICTURE;
354 vlc_mutex_unlock( &p_spu->subpicture_lock );
357 /*****************************************************************************
358 * spu_RenderSubpictures: render a subpicture list
359 *****************************************************************************
360 * This function renders all sub picture units in the list.
361 *****************************************************************************/
362 void spu_RenderSubpictures( spu_t *p_spu, video_format_t *p_fmt,
363 picture_t *p_pic_dst, picture_t *p_pic_src,
364 subpicture_t *p_subpic,
365 int i_scale_width, int i_scale_height )
368 vlc_mutex_lock( &p_spu->subpicture_lock );
370 /* Check i_status again to make sure spudec hasn't destroyed the subpic */
371 while( p_subpic != NULL && p_subpic->i_status != FREE_SUBPICTURE )
373 subpicture_region_t *p_region = p_subpic->p_region;
375 /* Load the blending module */
376 if( !p_spu->p_blend && p_region )
378 p_spu->p_blend = vlc_object_create( p_spu, sizeof(filter_t) );
379 vlc_object_attach( p_spu->p_blend, p_spu );
380 p_spu->p_blend->fmt_out.video.i_x_offset =
381 p_spu->p_blend->fmt_out.video.i_y_offset = 0;
382 p_spu->p_blend->fmt_out.video.i_aspect = p_fmt->i_aspect;
383 p_spu->p_blend->fmt_out.video.i_chroma = p_fmt->i_chroma;
385 p_spu->p_blend->fmt_in.video.i_chroma = VLC_FOURCC('Y','U','V','P');
387 p_spu->p_blend->p_module =
388 module_Need( p_spu->p_blend, "video blending", 0, 0 );
391 /* Load the text rendering module */
392 if( !p_spu->p_text && p_region )
394 p_spu->p_text = vlc_object_create( p_spu, sizeof(filter_t) );
395 vlc_object_attach( p_spu->p_text, p_spu );
397 p_spu->p_text->fmt_out.video.i_width =
398 p_spu->p_text->fmt_out.video.i_visible_width =
400 p_spu->p_text->fmt_out.video.i_height =
401 p_spu->p_text->fmt_out.video.i_visible_height =
404 p_spu->p_text->pf_spu_buffer_new = spu_new_buffer;
405 p_spu->p_text->pf_spu_buffer_del = spu_del_buffer;
407 p_spu->p_text->p_module =
408 module_Need( p_spu->p_text, "text renderer", 0, 0 );
411 /* Load the scaling module */
412 if( !p_spu->p_scale && (i_scale_width != 1000 ||
413 i_scale_height != 1000) )
415 p_spu->p_scale = vlc_object_create( p_spu, VLC_OBJECT_FILTER );
416 vlc_object_attach( p_spu->p_scale, p_spu );
417 p_spu->p_scale->fmt_out.video.i_chroma =
418 p_spu->p_scale->fmt_in.video.i_chroma =
419 VLC_FOURCC('Y','U','V','P');
420 p_spu->p_scale->fmt_in.video.i_width =
421 p_spu->p_scale->fmt_in.video.i_height = 32;
422 p_spu->p_scale->fmt_out.video.i_width =
423 p_spu->p_scale->fmt_out.video.i_height = 16;
425 p_spu->p_scale->pf_vout_buffer_new = spu_new_video_buffer;
426 p_spu->p_scale->pf_vout_buffer_del = spu_del_video_buffer;
427 p_spu->p_scale->p_module =
428 module_Need( p_spu->p_scale, "video filter2", 0, 0 );
431 if( p_subpic->pf_render )
433 /* HACK to remove when the ogt subpic decoder is gone */
434 if( p_spu->p_parent &&
435 p_spu->p_parent->i_object_type == VLC_OBJECT_VOUT )
437 vout_thread_t *p_vout = (vout_thread_t *)p_spu->p_parent;
438 p_subpic->pf_render( p_vout, p_pic_dst, p_subpic );
441 else while( p_region && p_spu->p_blend &&
442 p_spu->p_blend->pf_video_blend )
444 int i_x_offset = p_region->i_x + p_subpic->i_x;
445 int i_y_offset = p_region->i_y + p_subpic->i_y;
447 if( p_region->fmt.i_chroma == VLC_FOURCC('T','E','X','T') )
449 if( p_spu->p_text && p_spu->p_text->p_module &&
450 p_spu->p_text->pf_render_string )
452 /* TODO: do it in a less hacky way
453 * (modify text renderer API) */
454 subpicture_t *p_subpic_tmp;
455 subpicture_region_t tmp_region;
456 block_t *p_new_block =
457 block_New( p_spu, strlen(p_region->psz_text) + 1 );
461 memcpy( p_new_block->p_buffer, p_region->psz_text,
462 p_new_block->i_buffer );
463 p_new_block->i_pts = p_new_block->i_dts =
465 p_new_block->i_length =
466 p_subpic->i_start - p_subpic->i_stop;
467 p_subpic_tmp = p_spu->p_text->pf_render_string(
468 p_spu->p_text, p_new_block );
472 tmp_region = *p_region;
473 *p_region = *p_subpic_tmp->p_region;
474 p_region->p_next = tmp_region.p_next;
475 *p_subpic_tmp->p_region = tmp_region;
476 p_spu->p_text->pf_spu_buffer_del( p_spu->p_text,
483 if( p_subpic->i_flags & OSD_ALIGN_BOTTOM )
485 i_y_offset = p_fmt->i_height - p_region->fmt.i_height -
488 else if ( !(p_subpic->i_flags & OSD_ALIGN_TOP) )
490 i_y_offset = p_fmt->i_height / 2 - p_region->fmt.i_height / 2;
493 if( p_subpic->i_flags & OSD_ALIGN_RIGHT )
495 i_x_offset = p_fmt->i_width - p_region->fmt.i_width -
498 else if ( !(p_subpic->i_flags & OSD_ALIGN_LEFT) )
500 i_x_offset = p_fmt->i_width / 2 - p_region->fmt.i_width / 2;
503 if( p_subpic->b_absolute )
505 i_x_offset = p_region->i_x + p_subpic->i_x;
506 i_y_offset = p_region->i_y + p_subpic->i_y;
508 if( p_spu->i_margin >= 0 )
510 if( p_subpic->i_height + (unsigned int)p_spu->i_margin <=
513 i_y_offset = p_fmt->i_height -
514 p_spu->i_margin - p_subpic->i_height;
519 /* Force cropping if requested */
520 if( p_spu->b_force_crop )
522 video_format_t *p_fmt = &p_spu->p_blend->fmt_in.video;
524 /* Find the intersection */
525 if( p_spu->i_crop_x + p_spu->i_crop_width <= i_x_offset ||
526 i_x_offset + (int)p_fmt->i_visible_width <
528 p_spu->i_crop_y + p_spu->i_crop_height <= i_y_offset ||
529 i_y_offset + (int)p_fmt->i_visible_height <
532 /* No intersection */
533 p_fmt->i_visible_width = p_fmt->i_visible_height = 0;
537 int i_x, i_y, i_x_end, i_y_end;
538 i_x = __MAX( p_spu->i_crop_x, i_x_offset );
539 i_y = __MAX( p_spu->i_crop_y, i_y_offset );
540 i_x_end = __MIN( p_spu->i_crop_x + p_spu->i_crop_width,
541 i_x_offset + (int)p_fmt->i_visible_width );
542 i_y_end = __MIN( p_spu->i_crop_y + p_spu->i_crop_height,
543 i_y_offset + (int)p_fmt->i_visible_height );
545 p_fmt->i_x_offset = i_x - i_x_offset;
546 p_fmt->i_y_offset = i_y - i_y_offset;
547 p_fmt->i_visible_width = i_x_end - i_x;
548 p_fmt->i_visible_height = i_y_end - i_y;
555 /* Force palette if requested */
556 if( p_spu->b_force_alpha && VLC_FOURCC('Y','U','V','P') ==
557 p_spu->p_blend->fmt_in.video.i_chroma )
559 p_spu->p_blend->fmt_in.video.p_palette->palette[0][3] =
561 p_spu->p_blend->fmt_in.video.p_palette->palette[1][3] =
563 p_spu->p_blend->fmt_in.video.p_palette->palette[2][3] =
565 p_spu->p_blend->fmt_in.video.p_palette->palette[3][3] =
569 /* Scale SPU if necessary */
570 if( p_region->p_cache )
572 if( i_scale_width * p_region->fmt.i_width / 1000 !=
573 p_region->p_cache->fmt.i_width ||
574 i_scale_height * p_region->fmt.i_height / 1000 !=
575 p_region->p_cache->fmt.i_height )
577 p_subpic->pf_destroy_region( VLC_OBJECT(p_spu),
579 p_region->p_cache = 0;
582 if( (i_scale_width != 1000 || i_scale_height != 1000) &&
583 p_spu->p_scale && !p_region->p_cache )
587 p_spu->p_scale->fmt_in.video = p_region->fmt;
588 p_spu->p_scale->fmt_out.video = p_region->fmt;
591 p_subpic->pf_create_region( VLC_OBJECT(p_spu),
592 &p_spu->p_scale->fmt_out.video );
593 if( p_spu->p_scale->fmt_out.video.p_palette )
594 *p_spu->p_scale->fmt_out.video.p_palette =
595 *p_region->fmt.p_palette;
596 p_region->p_cache->p_next = p_region->p_next;
598 vout_CopyPicture( p_spu, &p_region->p_cache->picture,
599 &p_region->picture );
601 p_spu->p_scale->fmt_out.video.i_width =
602 p_region->fmt.i_width * i_scale_width / 1000;
603 p_spu->p_scale->fmt_out.video.i_visible_width =
604 p_region->fmt.i_visible_width * i_scale_width / 1000;
605 p_spu->p_scale->fmt_out.video.i_height =
606 p_region->fmt.i_height * i_scale_height / 1000;
607 p_spu->p_scale->fmt_out.video.i_visible_height =
608 p_region->fmt.i_visible_height * i_scale_height / 1000;
609 p_region->p_cache->fmt = p_spu->p_scale->fmt_out.video;
611 p_pic = p_spu->p_scale->pf_video_filter(
612 p_spu->p_scale, &p_region->p_cache->picture );
615 picture_t p_pic_tmp = p_region->p_cache->picture;
616 p_region->p_cache->picture = *p_pic;
621 if( (i_scale_width != 1000 || i_scale_height != 1000) &&
622 p_spu->p_scale && p_region->p_cache )
624 p_region = p_region->p_cache;
627 if( p_subpic->b_absolute )
629 i_x_offset = i_x_offset * i_scale_width / 1000;
630 i_y_offset = i_y_offset * i_scale_height / 1000;
633 p_spu->p_blend->fmt_in.video = p_region->fmt;
635 /* Update the output picture size */
636 p_spu->p_blend->fmt_out.video.i_width =
637 p_spu->p_blend->fmt_out.video.i_visible_width =
639 p_spu->p_blend->fmt_out.video.i_height =
640 p_spu->p_blend->fmt_out.video.i_visible_height =
643 p_spu->p_blend->pf_video_blend( p_spu->p_blend, p_pic_dst,
644 p_pic_src, &p_region->picture, i_x_offset, i_y_offset );
646 p_region = p_region->p_next;
649 p_subpic = p_subpic->p_next;
652 vlc_mutex_unlock( &p_spu->subpicture_lock );
655 /*****************************************************************************
656 * spu_SortSubpictures: find the subpictures to display
657 *****************************************************************************
658 * This function parses all subpictures and decides which ones need to be
659 * displayed. This operation does not need lock, since only READY_SUBPICTURE
660 * are handled. If no picture has been selected, display_date will depend on
662 * We also check for ephemer DVD subpictures (subpictures that have
663 * to be removed if a newer one is available), which makes it a lot
664 * more difficult to guess if a subpicture has to be rendered or not.
665 *****************************************************************************/
666 subpicture_t *spu_SortSubpictures( spu_t *p_spu, mtime_t display_date )
669 subpicture_t *p_subpic = NULL;
670 subpicture_t *p_ephemer = NULL;
671 mtime_t ephemer_date = 0;
673 /* We get an easily parsable chained list of subpictures which
674 * ends with NULL since p_subpic was initialized to NULL. */
675 for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++ )
677 if( p_spu->p_subpicture[i_index].i_status == READY_SUBPICTURE )
679 /* If it is a DVD subpicture, check its date */
680 if( p_spu->p_subpicture[i_index].i_type == MEMORY_SUBPICTURE )
682 if( !p_spu->p_subpicture[i_index].b_ephemer
683 && display_date > p_spu->p_subpicture[i_index].i_stop )
685 /* Too late, destroy the subpic */
686 spu_DestroySubpicture(p_spu,&p_spu->p_subpicture[i_index]);
691 && display_date < p_spu->p_subpicture[i_index].i_start )
693 /* Too early, come back next monday */
697 /* If this is an ephemer subpic, see if it's the
698 * youngest we have */
699 if( p_spu->p_subpicture[i_index].b_ephemer )
701 if( p_ephemer == NULL )
703 p_ephemer = &p_spu->p_subpicture[i_index];
707 if( p_spu->p_subpicture[i_index].i_start
708 < p_ephemer->i_start )
710 /* Link the previous ephemer subpicture and
711 * replace it with the current one */
712 p_ephemer->p_next = p_subpic;
713 p_subpic = p_ephemer;
714 p_ephemer = &p_spu->p_subpicture[i_index];
716 /* If it's the 2nd youngest subpicture,
717 * register its date */
719 || ephemer_date > p_subpic->i_start )
721 ephemer_date = p_subpic->i_start;
728 p_spu->p_subpicture[i_index].p_next = p_subpic;
729 p_subpic = &p_spu->p_subpicture[i_index];
731 /* If it's the 2nd youngest subpicture, register its date */
732 if( !ephemer_date || ephemer_date > p_subpic->i_start )
734 ephemer_date = p_subpic->i_start;
737 /* If it's not a DVD subpicture, just register it */
740 p_spu->p_subpicture[i_index].p_next = p_subpic;
741 p_subpic = &p_spu->p_subpicture[i_index];
746 /* If we found an ephemer subpicture, check if it has to be
748 if( p_ephemer != NULL )
750 if( p_ephemer->i_start <= ephemer_date )
752 /* Ephemer subpicture has lived too long */
753 spu_DestroySubpicture( p_spu, p_ephemer );
757 /* Ephemer subpicture can still live a bit */
758 p_ephemer->p_next = p_subpic;
766 /*****************************************************************************
767 * SpuClearChannel: clear an spu channel
768 *****************************************************************************
769 * This function destroys the subpictures which belong to the spu channel
770 * corresponding to i_channel_id.
771 *****************************************************************************/
772 static void SpuClearChannel( spu_t *p_spu, int i_channel )
774 int i_subpic; /* subpicture index */
775 subpicture_t * p_subpic = NULL; /* first free subpicture */
777 vlc_mutex_lock( &p_spu->subpicture_lock );
779 for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ )
781 p_subpic = &p_spu->p_subpicture[i_subpic];
782 if( p_subpic->i_status == FREE_SUBPICTURE
783 || ( p_subpic->i_status != RESERVED_SUBPICTURE
784 && p_subpic->i_status != READY_SUBPICTURE ) )
789 if( p_subpic->i_channel == i_channel )
791 while( p_subpic->p_region )
793 subpicture_region_t *p_region = p_subpic->p_region;
794 p_subpic->p_region = p_region->p_next;
795 spu_DestroyRegion( p_spu, p_region );
798 if( p_subpic->pf_destroy ) p_subpic->pf_destroy( p_subpic );
799 p_subpic->i_status = FREE_SUBPICTURE;
803 vlc_mutex_unlock( &p_spu->subpicture_lock );
806 /*****************************************************************************
807 * spu_ControlDefault: default methods for the subpicture unit control.
808 *****************************************************************************/
809 int spu_vaControlDefault( spu_t *p_spu, int i_query, va_list args )
815 case SPU_CHANNEL_REGISTER:
816 pi = (int *)va_arg( args, int * );
818 if( pi ) *pi = p_spu->i_channel;
819 msg_Dbg( p_spu, "Registering subpicture channel, ID: %i",
823 case SPU_CHANNEL_CLEAR:
824 i = (int)va_arg( args, int );
825 SpuClearChannel( p_spu, i );
829 msg_Dbg( p_spu, "control query not supported" );
836 /*****************************************************************************
837 * Object variables callbacks
838 *****************************************************************************/
840 /*****************************************************************************
841 * UpdateSPU: update subpicture settings
842 *****************************************************************************
843 * This function is called from CropCallback and at initialization time, to
844 * retrieve crop information from the input.
845 *****************************************************************************/
846 static void UpdateSPU( spu_t *p_spu, vlc_object_t *p_object )
850 p_spu->b_force_alpha = VLC_FALSE;
851 p_spu->b_force_crop = VLC_FALSE;
853 if( var_Get( p_object, "highlight", &val ) || !val.b_bool ) return;
855 p_spu->b_force_crop = VLC_TRUE;
856 var_Get( p_object, "x-start", &val );
857 p_spu->i_crop_x = val.i_int;
858 var_Get( p_object, "y-start", &val );
859 p_spu->i_crop_y = val.i_int;
860 var_Get( p_object, "x-end", &val );
861 p_spu->i_crop_width = val.i_int - p_spu->i_crop_x;
862 var_Get( p_object, "y-end", &val );
863 p_spu->i_crop_height = val.i_int - p_spu->i_crop_y;
866 if( var_Get( p_object, "color", &val ) == VLC_SUCCESS )
869 for( i = 0; i < 4; i++ )
871 p_spu->pi_color[i] = ((uint8_t *)val.p_address)[i];
876 if( var_Get( p_object, "contrast", &val ) == VLC_SUCCESS )
879 for( i = 0; i < 4; i++ )
881 p_spu->pi_alpha[i] = ((uint8_t *)val.p_address)[i];
882 p_spu->pi_alpha[i] = p_spu->pi_alpha[i] == 0xf ?
883 0xff : p_spu->pi_alpha[i] << 4;
885 p_spu->b_force_alpha = VLC_TRUE;
888 msg_Dbg( p_object, "crop: %i,%i,%i,%i, alpha: %i",
889 p_spu->i_crop_x, p_spu->i_crop_y,
890 p_spu->i_crop_width, p_spu->i_crop_height, p_spu->b_force_alpha );
893 /*****************************************************************************
894 * CropCallback: called when the highlight properties are changed
895 *****************************************************************************
896 * This callback is called from the input thread when we need cropping
897 *****************************************************************************/
898 static int CropCallback( vlc_object_t *p_object, char const *psz_var,
899 vlc_value_t oldval, vlc_value_t newval, void *p_data )
901 UpdateSPU( (spu_t *)p_data, p_object );
905 /*****************************************************************************
906 * Buffers allocation callbacks for the filters
907 *****************************************************************************/
908 static subpicture_t *spu_new_buffer( filter_t *p_filter )
910 subpicture_t *p_subpic = (subpicture_t *)malloc(sizeof(subpicture_t));
911 memset( p_subpic, 0, sizeof(subpicture_t) );
912 p_subpic->b_absolute = VLC_TRUE;
914 p_subpic->pf_create_region = __spu_CreateRegion;
915 p_subpic->pf_destroy_region = __spu_DestroyRegion;
920 static void spu_del_buffer( filter_t *p_filter, subpicture_t *p_subpic )
922 while( p_subpic->p_region )
924 subpicture_region_t *p_region = p_subpic->p_region;
925 p_subpic->p_region = p_region->p_next;
926 p_subpic->pf_destroy_region( VLC_OBJECT(p_filter), p_region );
932 static picture_t *spu_new_video_buffer( filter_t *p_filter )
934 picture_t *p_picture = malloc( sizeof(picture_t) );
936 if( vout_AllocatePicture( p_filter, p_picture,
937 p_filter->fmt_out.video.i_chroma,
938 p_filter->fmt_out.video.i_width,
939 p_filter->fmt_out.video.i_height,
940 p_filter->fmt_out.video.i_aspect )
947 p_picture->pf_release = RegionPictureRelease;
952 static void spu_del_video_buffer( filter_t *p_filter, picture_t *p_pic )
954 if( p_pic && p_pic->p_data_orig ) free( p_pic->p_data_orig );
955 if( p_pic ) free( p_pic );