[vlc-commits] codec: spudec: handle palette updates (fix #23137)

Francois Cartegnie git at videolan.org
Sat Jan 4 21:02:58 CET 2020


vlc | branch: master | Francois Cartegnie <fcvlcdev at free.fr> | Thu Dec 19 19:31:42 2019 +0100| [7f316163a656e49ec175ce7baaa426dc46573cf0] | committer: Francois Cartegnie

codec: spudec: handle palette updates (fix #23137)

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=7f316163a656e49ec175ce7baaa426dc46573cf0
---

 modules/codec/spudec/parse.c | 99 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 98 insertions(+), 1 deletion(-)

diff --git a/modules/codec/spudec/parse.c b/modules/codec/spudec/parse.c
index 3e04088478..ca9a5ed7bb 100644
--- a/modules/codec/spudec/parse.c
+++ b/modules/codec/spudec/parse.c
@@ -57,6 +57,9 @@ typedef struct
     bool b_palette;
     uint8_t    pi_alpha[4];
     uint8_t    pi_yuv[4][3];
+    /* PXCTLI commands storage */
+    const uint8_t *p_pxctli;
+    size_t i_pxclti;
 
     /* Auto crop fullscreen subtitles */
     bool b_auto_crop;
@@ -101,6 +104,88 @@ static void CLUTIdxToYUV(const struct subs_format_t *subs,
     }
 }
 
+static void ParsePXCTLI( decoder_t *p_dec, const subpicture_data_t *p_spu_data,
+                         subpicture_t *p_spu )
+{
+    plane_t *p_plane = &p_spu->p_region->p_picture->p[0];
+    video_palette_t *p_palette = p_spu->p_region->fmt.p_palette;
+
+    for( size_t i=0;i<p_spu_data->i_pxclti; i++ )
+    {
+        uint16_t i_col = GetWBE(&p_spu_data->p_pxctli[i*6 + 0]);
+        uint16_t i_color = GetWBE(&p_spu_data->p_pxctli[i*6 + 2]);
+        uint16_t i_contrast = GetWBE(&p_spu_data->p_pxctli[i*6 + 4]);
+
+        if(p_palette->i_entries +4 >= VIDEO_PALETTE_COLORS_MAX)
+            break;
+
+        if( p_dec->fmt_in.subs.spu.palette[0] == SPU_PALETTE_DEFINED )
+        {
+            /* Lookup the CLUT palette for the YUV values */
+            uint8_t idx[4];
+            uint8_t yuv[4][3];
+            uint8_t alpha[4];
+            idx[0] = (i_color >> 12)&0x0f;
+            idx[1] = (i_color >>  8)&0x0f;
+            idx[2] = (i_color >>  4)&0x0f;
+            idx[3] = i_color&0x0f;
+            CLUTIdxToYUV( &p_dec->fmt_in.subs, idx, yuv );
+
+            /* Process the contrast */
+            alpha[3] = (i_contrast >> 12)&0x0f;
+            alpha[2] = (i_contrast >>  8)&0x0f;
+            alpha[1] = (i_contrast >>  4)&0x0f;
+            alpha[0] = i_contrast&0x0f;
+
+            /* Create a new YUVA palette entries for the picture */
+            int index_map[4];
+            for( int j=0; j<4; j++ )
+            {
+                uint8_t yuvaentry[4];
+                yuvaentry[0] = yuv[j][0];
+                yuvaentry[1] = yuv[j][1];
+                yuvaentry[2] = yuv[j][2];
+                yuvaentry[3] = alpha[j] * 0x11;
+                int i_index = VIDEO_PALETTE_COLORS_MAX;
+                for( int k = p_palette->i_entries; k > 0; k-- )
+                {
+                    if( !memcmp( &p_palette->palette[k], yuvaentry, sizeof(uint8_t [4]) ) )
+                    {
+                        i_index = VIDEO_PALETTE_COLORS_MAX;
+                        break;
+                    }
+                }
+
+                /* Add an entry in out palette */
+                if( i_index == VIDEO_PALETTE_COLORS_MAX )
+                {
+                    if(p_palette->i_entries == VIDEO_PALETTE_COLORS_MAX)
+                    {
+                        msg_Warn( p_dec, "Cannot create new color, skipping PXCTLI" );
+                        return;
+                    }
+                    i_index = p_palette->i_entries++;
+                    memcpy( p_palette->palette[ i_index ], yuvaentry, sizeof(uint8_t [4]) );
+                }
+                index_map[j] = i_index;
+            }
+
+            if( p_spu->p_region->i_x >= i_col )
+                i_col -= p_spu->p_region->i_x;
+
+            for( int j=0; j<p_plane->i_visible_lines; j++ )
+            {
+                uint8_t *p_line = &p_plane->p_pixels[j * p_plane->i_pitch];
+                /* Extends to end of the line */
+                for( int k=i_col; k<p_plane->i_visible_pitch; k++ )
+                {
+                    if( p_line[k] < 4 ) /* can forge write-again */
+                        p_line[k] = index_map[ p_line[k] ];
+                }
+            }
+        }
+    }
+}
 
 /*****************************************************************************
  * OutputPicture:
@@ -164,6 +249,9 @@ static void OutputPicture( decoder_t *p_dec,
     Render( p_dec, p_spu, p_pixeldata, &render_spu_data, p_spu_properties );
     free( p_pixeldata );
 
+    if( p_spu_data->p_pxctli && p_spu )
+        ParsePXCTLI( p_dec, p_spu_data, p_spu );
+
     pf_queue( p_dec, p_spu );
 }
 
@@ -421,12 +509,21 @@ static int ParseControlSeq( decoder_t *p_dec, vlc_tick_t i_pts,
             break;
 
         case SPU_CMD_SET_COLCON:
-            if( i_index + 3 > p_sys->i_spu_size )
+            if( i_index + 7 > p_sys->i_spu_size )
             {
                 msg_Err( p_dec, "overflow in SPU command" );
                 return VLC_EGENERIC;
             }
 
+            spu_properties.i_start = i_pts + date;
+
+            if( p_sys->i_spu_size >
+                i_index + 3 + 4 + (p_sys->buffer[i_index+5] >> 4) )
+            {
+                spu_data.p_pxctli = &p_sys->buffer[i_index+3 + 4];
+                spu_data.i_pxclti = p_sys->buffer[i_index+5] >> 4;
+            }
+
             i_index += 1 + GetWBE(&p_sys->buffer[i_index+1]);
             break;
 



More information about the vlc-commits mailing list