+#ifdef DEBUG_VIDEO
+ /* Send subpicture informations */
+ intf_DbgMsg("subpicture %p: type=%d, begin date=%s, end date=%s\n",
+ p_subpic, p_subpic->i_type,
+ mstrtime( psz_begin_date, p_subpic->begin_date ),
+ mstrtime( psz_end_date, p_subpic->end_date ) );
+#endif
+}
+
+/*****************************************************************************
+ * vout_CreateSubPicture: allocate an subpicture in the video output heap.
+ *****************************************************************************
+ * This function create a reserved subpicture in the video output heap.
+ * A null pointer is returned if the function fails. This method provides an
+ * already allocated zone of memory in the spu data fields. It needs locking
+ * since several pictures can be created by several producers threads.
+ *****************************************************************************/
+subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type,
+ int i_size )
+{
+ int i_subpic; /* subpicture index */
+ subpicture_t * p_free_subpic = NULL; /* first free subpicture */
+ subpicture_t * p_destroyed_subpic = NULL; /* first destroyed subpic */
+
+ /* Get lock */
+ vlc_mutex_lock( &p_vout->subpicture_lock );
+
+ /*
+ * Look for an empty place
+ */
+ for( i_subpic = 0; i_subpic < VOUT_MAX_PICTURES; i_subpic++ )
+ {
+ if( p_vout->p_subpicture[i_subpic].i_status == DESTROYED_SUBPICTURE )
+ {
+ /* Subpicture is marked for destruction, but is still allocated */
+ if( (p_vout->p_subpicture[i_subpic].i_type == i_type) &&
+ (p_vout->p_subpicture[i_subpic].i_size >= i_size) )
+ {
+ /* Memory size do match or is smaller : memory will not be reallocated,
+ * and function can end immediately - this is the best possible case,
+ * since no memory allocation needs to be done */
+ p_vout->p_subpicture[i_subpic].i_status = RESERVED_SUBPICTURE;
+#ifdef DEBUG_VIDEO
+ intf_DbgMsg("subpicture %p (in destroyed subpicture slot)\n",
+ &p_vout->p_subpicture[i_subpic] );
+#endif
+ vlc_mutex_unlock( &p_vout->subpicture_lock );
+ return( &p_vout->p_subpicture[i_subpic] );
+ }
+ else if( p_destroyed_subpic == NULL )
+ {
+ /* Memory size do not match, but subpicture index will be kept in
+ * case no other place are left */
+ p_destroyed_subpic = &p_vout->p_subpicture[i_subpic];
+ }
+ }
+ else if( (p_free_subpic == NULL) &&
+ (p_vout->p_subpicture[i_subpic].i_status == FREE_SUBPICTURE ))
+ {
+ /* Subpicture is empty and ready for allocation */
+ p_free_subpic = &p_vout->p_subpicture[i_subpic];
+ }
+ }
+
+ /* If no free subpicture is available, use a destroyed subpicture */
+ if( (p_free_subpic == NULL) && (p_destroyed_subpic != NULL ) )
+ {
+ /* No free subpicture or matching destroyed subpicture has been found, but
+ * a destroyed subpicture is still avalaible */
+ free( p_destroyed_subpic->p_data );
+ p_free_subpic = p_destroyed_subpic;
+ }
+
+ /*
+ * Prepare subpicture
+ */
+ if( p_free_subpic != NULL )
+ {
+ /* Allocate memory */
+ switch( i_type )
+ {
+ case TEXT_SUBPICTURE: /* text subpicture */
+ p_free_subpic->p_data = malloc( i_size + 1 );
+ break;
+#ifdef DEBUG
+ default:
+ intf_DbgMsg("error: unknown subpicture type %d\n", i_type );
+ p_free_subpic->p_data = NULL;
+ break;
+#endif
+ }
+
+ if( p_free_subpic->p_data != NULL )
+ { /* Copy subpicture informations, set some default values */
+ p_free_subpic->i_type = i_type;
+ p_free_subpic->i_status = RESERVED_SUBPICTURE;
+ p_free_subpic->i_size = i_size;
+ p_free_subpic->i_x = 0;
+ p_free_subpic->i_y = 0;
+ p_free_subpic->i_width = 0;
+ p_free_subpic->i_height = 0;
+ p_free_subpic->i_horizontal_align = CENTER_RALIGN;
+ p_free_subpic->i_vertical_align = CENTER_RALIGN;
+ }
+ else
+ {
+ /* Memory allocation failed : set subpicture as empty */
+ p_free_subpic->i_type = EMPTY_SUBPICTURE;
+ p_free_subpic->i_status = FREE_SUBPICTURE;
+ p_free_subpic = NULL;
+ intf_ErrMsg("warning: %s\n", strerror( ENOMEM ) );
+ }
+
+#ifdef DEBUG_VIDEO
+ intf_DbgMsg("subpicture %p (in free subpicture slot)\n", p_free_subpic );
+#endif
+ vlc_mutex_unlock( &p_vout->subpicture_lock );
+ return( p_free_subpic );
+ }
+
+ /* No free or destroyed subpicture could be found */
+ intf_DbgMsg( "warning: heap is full\n" );
+ vlc_mutex_unlock( &p_vout->subpicture_lock );
+ return( NULL );
+}
+
+/*****************************************************************************
+ * vout_DestroySubPicture: remove a subpicture from the heap
+ *****************************************************************************
+ * This function frees a previously reserved subpicture.
+ * It is meant to be used when the construction of a picture aborted.
+ * This function does not need locking since reserved subpictures are ignored
+ * by the output thread.
+ *****************************************************************************/
+void vout_DestroySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic )
+{
+#ifdef DEBUG
+ /* Check if status is valid */
+ if( p_subpic->i_status != RESERVED_SUBPICTURE )
+ {
+ intf_DbgMsg("error: subpicture %p has invalid status %d\n",
+ p_subpic, p_subpic->i_status );
+ }
+#endif
+
+ p_subpic->i_status = DESTROYED_SUBPICTURE;
+
+#ifdef DEBUG_VIDEO
+ intf_DbgMsg("subpicture %p\n", p_subpic);
+#endif
+}
+
+/*****************************************************************************
+ * vout_DisplayPicture: display a picture
+ *****************************************************************************
+ * Remove the reservation flag of a picture, which will cause it to be ready for
+ * display. The picture won't be displayed until vout_DatePicture has been
+ * called.
+ *****************************************************************************/
+void vout_DisplayPicture( vout_thread_t *p_vout, picture_t *p_pic )
+{
+ vlc_mutex_lock( &p_vout->picture_lock );
+ switch( p_pic->i_status )
+ {
+ case RESERVED_PICTURE:
+ p_pic->i_status = RESERVED_DISP_PICTURE;
+ break;
+ case RESERVED_DATED_PICTURE:
+ p_pic->i_status = READY_PICTURE;
+ break;
+#ifdef DEBUG
+ default:
+ intf_DbgMsg("error: picture %p has invalid status %d\n", p_pic, p_pic->i_status );
+ break;
+#endif
+ }
+
+#ifdef DEBUG_VIDEO
+ intf_DbgMsg("picture %p\n", p_pic);
+#endif
+ vlc_mutex_unlock( &p_vout->picture_lock );
+}
+
+/*****************************************************************************
+ * vout_DatePicture: date a picture
+ *****************************************************************************
+ * Remove the reservation flag of a picture, which will cause it to be ready for
+ * display. The picture won't be displayed until vout_DisplayPicture has been
+ * called.
+ *****************************************************************************/
+void vout_DatePicture( vout_thread_t *p_vout, picture_t *p_pic, mtime_t date )
+{
+#ifdef DEBUG_VIDEO
+ char psz_date[MSTRTIME_MAX_SIZE]; /* date */
+#endif
+
+ vlc_mutex_lock( &p_vout->picture_lock );
+ p_pic->date = date;
+ switch( p_pic->i_status )
+ {
+ case RESERVED_PICTURE:
+ p_pic->i_status = RESERVED_DATED_PICTURE;
+ break;
+ case RESERVED_DISP_PICTURE:
+ p_pic->i_status = READY_PICTURE;
+ break;
+#ifdef DEBUG
+ default:
+ intf_DbgMsg("error: picture %p has invalid status %d\n", p_pic, p_pic->i_status );
+ break;