]> git.sesse.net Git - vlc/blobdiff - src/video_output/vout_subpictures.c
AVI: fix track names character set (fixes #2334)
[vlc] / src / video_output / vout_subpictures.c
index bb6b98300d2945d70d78dd664d14c884d012545a..d20d4e04543ff3ffbf0337d83cb631ec8fa32bf3 100644 (file)
@@ -36,6 +36,7 @@
 #include <vlc_filter.h>
 #include <vlc_osd.h>
 #include "../libvlc.h"
+#include "vout_internal.h"
 
 #include <assert.h>
 #include <limits.h>
@@ -43,6 +44,9 @@
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
+/* Number of simultaneous subpictures */
+#define VOUT_MAX_SUBPICTURES (VOUT_MAX_PICTURES)
+
 #define VLC_FOURCC_YUVP VLC_FOURCC('Y','U','V','P')
 #define VLC_FOURCC_YUVA VLC_FOURCC('Y','U','V','A')
 #define VLC_FOURCC_RGBA VLC_FOURCC('R','G','B','A')
@@ -85,8 +89,11 @@ struct spu_private_t
     bool b_force_palette;             /**< force palette of subpicture */
     uint8_t palette[4][4];                               /**< forced palette */
 
-    /* Supciture filters */
+    /* Subpiture filters */
     filter_chain_t *p_chain;
+
+    /* */
+    mtime_t i_last_sort_date;
 };
 
 /* */
@@ -153,7 +160,7 @@ static int  CropCallback( vlc_object_t *, char const *,
 
 static int SpuControl( spu_t *, int, va_list );
 
-static void SpuClearChannel( spu_t *p_spu, int i_channel, bool b_locked );
+static void SpuClearChannel( spu_t *p_spu, int i_channel );
 
 /* Buffer allocation for SPU filter (blend, scale, ...) */
 static subpicture_t *spu_new_buffer( filter_t * );
@@ -188,7 +195,7 @@ spu_t *__spu_Create( vlc_object_t *p_this )
 {
     spu_t *p_spu;
     spu_private_t *p_sys;
-    
     p_spu = vlc_custom_create( p_this, sizeof(spu_t) + sizeof(spu_private_t),
                                VLC_OBJECT_GENERIC, "subpicture" );
 
@@ -223,6 +230,9 @@ spu_t *__spu_Create( vlc_object_t *p_this )
     SpuRenderCreateAndLoadText( p_spu );
     SpuRenderCreateAndLoadScale( p_spu );
 
+    /* */
+    p_sys->i_last_sort_date = -1;
+
     return p_spu;
 }
 
@@ -333,7 +343,7 @@ void spu_DisplaySubpicture( spu_t *p_spu, subpicture_t *p_subpic )
 
     /* DEFAULT_CHAN always reset itself */
     if( p_subpic->i_channel == DEFAULT_CHAN )
-        SpuClearChannel( p_spu, DEFAULT_CHAN, false );
+        SpuClearChannel( p_spu, DEFAULT_CHAN );
 
     /* p_private is for spu only and cannot be non NULL here */
     for( subpicture_region_t *r = p_subpic->p_region; r != NULL; r = r->p_next )
@@ -357,7 +367,7 @@ void spu_DisplaySubpicture( spu_t *p_spu, subpicture_t *p_subpic )
 void spu_RenderSubpictures( spu_t *p_spu,
                             picture_t *p_pic_dst, const video_format_t *p_fmt_dst,
                             subpicture_t *p_subpic_list,
-                            const video_format_t *p_fmt_src )
+                            const video_format_t *p_fmt_src, bool b_paused )
 {
     spu_private_t *p_sys = p_spu->p;
 
@@ -383,10 +393,10 @@ void spu_RenderSubpictures( spu_t *p_spu,
                 p_subpic = p_subpic->p_next )
     {
         /* */
-        if( p_subpic->pf_pre_render )
+        if( !b_paused && p_subpic->pf_pre_render )
             p_subpic->pf_pre_render( p_spu, p_subpic, p_fmt_dst );
 
-        if( p_subpic->pf_update_regions )
+        if( !b_paused && p_subpic->pf_update_regions )
         {
             video_format_t fmt_org = *p_fmt_dst;
             fmt_org.i_width =
@@ -563,14 +573,21 @@ subpicture_t *spu_SortSubpictures( spu_t *p_spu, mtime_t display_date,
      * ends with NULL since p_subpic was initialized to NULL. */
     for( i_channel = 0; i_channel < p_sys->i_channel; i_channel++ )
     {
-        subpicture_t *p_ephemer = NULL;
+        subpicture_t *p_available_subpic[VOUT_MAX_SUBPICTURES];
+        bool         pb_available_late[VOUT_MAX_SUBPICTURES];
+        int          i_available = 0;
+
+        mtime_t      start_date = display_date;
         mtime_t      ephemer_date = 0;
         int i_index;
 
+        /* Select available pictures */
         for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++ )
         {
             spu_heap_entry_t *p_entry = &p_sys->heap.p_entry[i_index];
             subpicture_t *p_current = p_entry->p_subpicture;
+            bool b_stop_valid;
+            bool b_late;
 
             if( !p_current || p_entry->b_reject )
             {
@@ -594,44 +611,75 @@ subpicture_t *spu_SortSubpictures( spu_t *p_spu, mtime_t display_date,
             if( p_current->i_start > ephemer_date )
                 ephemer_date = p_current->i_start;
 
-            if( display_date > p_current->i_stop &&
-                ( !p_current->b_ephemer || p_current->i_stop > p_current->i_start ) &&
-                !( p_current->b_subtitle && b_paused ) ) /* XXX Assume that subtitle are pausable */
-            {
-                SpuHeapDeleteAt( &p_sys->heap, i_index );
-            }
-            else if( p_current->b_ephemer )
-            {
-                SubpictureChain( &p_ephemer, p_current );
-            }
-            else
-            {
-                SubpictureChain( &p_subpic, p_current );
-            }
+            b_stop_valid = ( !p_current->b_ephemer || p_current->i_stop > p_current->i_start ) &&
+                           ( !p_current->b_subtitle || !b_paused ); /* XXX Assume that subtitle are pausable */
+
+            b_late = b_stop_valid && p_current->i_stop <= display_date;
+
+            /* start_date will be used for correct automatic overlap support
+             * in case picture that should not be displayed anymore (display_time)
+             * overlap with a picture to be displayed (p_current->i_start)  */
+            if( !b_late && !p_current->b_ephemer )
+                start_date = p_current->i_start;
+
+            /* */
+            p_available_subpic[i_available] = p_current;
+            pb_available_late[i_available] = b_late;
+            i_available++;
         }
 
-        /* If we found ephemer subpictures, check if they have to be
-         * displayed or destroyed */
-        while( p_ephemer != NULL )
+        /* Only forced old picture display at the transition */
+        if( start_date < p_sys->i_last_sort_date )
+            start_date = p_sys->i_last_sort_date;
+        if( start_date <= 0 )
+            start_date = INT64_MAX;
+
+        /* Select pictures to be displayed */
+        for( i_index = 0; i_index < i_available; i_index++ )
         {
-            subpicture_t *p_tmp = p_ephemer;
-            p_ephemer = p_ephemer->p_next;
+            subpicture_t *p_current = p_available_subpic[i_index];
+            bool b_late = pb_available_late[i_index];
 
-            if( p_tmp->i_start < ephemer_date )
+            if( ( b_late && p_current->i_stop <= __MAX( start_date, p_sys->i_last_sort_date ) ) ||
+                ( p_current->b_ephemer && p_current->i_start < ephemer_date ) )
             {
-                SpuHeapDeleteSubpicture( &p_sys->heap, p_tmp );
+                /* Destroy late and obsolete ephemer subpictures */
+                SpuHeapDeleteSubpicture( &p_sys->heap, p_current );
             }
             else
             {
-                SubpictureChain( &p_subpic, p_tmp );
+                SubpictureChain( &p_subpic, p_current );
             }
         }
     }
+
+    p_sys->i_last_sort_date = display_date;
     vlc_mutex_unlock( &p_sys->lock );
 
     return p_subpic;
 }
 
+void spu_OffsetSubtitleDate( spu_t *p_spu, mtime_t i_duration )
+{
+    spu_private_t *p_sys = p_spu->p;
+
+    vlc_mutex_lock( &p_sys->lock );
+    for( int i = 0; i < VOUT_MAX_SUBPICTURES; i++ )
+    {
+        spu_heap_entry_t *p_entry = &p_sys->heap.p_entry[i];
+        subpicture_t *p_current = p_entry->p_subpicture;
+
+        if( p_current && p_current->b_subtitle )
+        {
+            if( p_current->i_start > 0 )
+                p_current->i_start += i_duration;
+            if( p_current->i_stop > 0 )
+                p_current->i_stop += i_duration;
+        }
+    }
+    vlc_mutex_unlock( &p_sys->lock );
+}
+
 /*****************************************************************************
  * subpicture_t allocation
  *****************************************************************************/
@@ -901,7 +949,7 @@ static void SpuRenderUpdateBlend( spu_t *p_spu, int i_out_width, int i_out_heigh
 
     /* */
     if( !p_blend->p_module )
-        p_blend->p_module = module_need( p_blend, "video blending", 0, 0 );
+        p_blend->p_module = module_need( p_blend, "video blending", NULL, false );
 }
 static void SpuRenderCreateAndLoadText( spu_t *p_spu )
 {
@@ -973,7 +1021,7 @@ static filter_t *CreateAndLoadScale( vlc_object_t *p_obj,
     p_scale->pf_vout_buffer_del = spu_del_video_buffer;
 
     vlc_object_attach( p_scale, p_obj );
-    p_scale->p_module = module_need( p_scale, "video filter2", 0, 0 );
+    p_scale->p_module = module_need( p_scale, "video filter2", NULL, false );
 
     return p_scale;
 }
@@ -1416,7 +1464,7 @@ static void SpuRenderRegion( spu_t *p_spu,
         }
 
         /* Scale if needed into cache */
-        if( !p_region->p_private )
+        if( !p_region->p_private && i_dst_width > 0 && i_dst_height > 0 )
         {
             filter_t *p_scale = p_sys->p_scale;
 
@@ -1556,8 +1604,11 @@ exit:
          * pre-rendered state, so the next time through everything is
          * calculated again.
          */
-        picture_Release( p_region->p_picture );
-        p_region->p_picture = NULL;
+        if( p_region->p_picture )
+        {
+            picture_Release( p_region->p_picture );
+            p_region->p_picture = NULL;
+        }
         if( p_region->p_private )
         {
             SpuRegionPrivateDelete( p_region->p_private );
@@ -1578,7 +1629,7 @@ static int IntegerCmp( int64_t i0, int64_t i1 )
     return i0 < i1 ? -1 : i0 > i1 ? 1 : 0;
 }
 /**
- * This function compares 2 subpictures using the following properties 
+ * This function compares 2 subpictures using the following properties
  * (ordered by priority)
  * 1. absolute positionning
  * 2. start time
@@ -1610,15 +1661,12 @@ static int SubpictureCmp( const void *s0, const void *s1 )
  * This function destroys the subpictures which belong to the spu channel
  * corresponding to i_channel_id.
  *****************************************************************************/
-static void SpuClearChannel( spu_t *p_spu, int i_channel, bool b_locked )
+static void SpuClearChannel( spu_t *p_spu, int i_channel )
 {
     spu_private_t *p_sys = p_spu->p;
     int          i_subpic;                               /* subpicture index */
 
-    if( !b_locked )
-        vlc_mutex_lock( &p_sys->lock );
-
-    vlc_assert_locked( &p_sys->lock );
+    vlc_mutex_lock( &p_sys->lock );
 
     for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ )
     {
@@ -1632,8 +1680,7 @@ static void SpuClearChannel( spu_t *p_spu, int i_channel, bool b_locked )
         p_entry->b_reject = true;
     }
 
-    if( !b_locked )
-        vlc_mutex_unlock( &p_sys->lock );
+    vlc_mutex_unlock( &p_sys->lock );
 }
 
 /*****************************************************************************
@@ -1656,7 +1703,7 @@ static int SpuControl( spu_t *p_spu, int i_query, va_list args )
 
     case SPU_CHANNEL_CLEAR:
         i = (int)va_arg( args, int );
-        SpuClearChannel( p_spu, i, false );
+        SpuClearChannel( p_spu, i );
         break;
 
     default:
@@ -1797,7 +1844,7 @@ static void SubFilterAllocationClean( filter_t *p_filter )
 {
     filter_owner_sys_t *p_sys = p_filter->p_owner;
 
-    SpuClearChannel( p_sys->p_spu, p_sys->i_channel, true );
+    SpuClearChannel( p_sys->p_spu, p_sys->i_channel );
     free( p_filter->p_owner );
 }