[vlc-devel] [PATCH v2] demux: wav: support parsing INFO chunk

Thomas Guillem thomas at gllm.fr
Mon Sep 14 12:53:33 CEST 2020


Hello,

On Sun, Sep 13, 2020, at 04:20, Zhao, Gang wrote:
> Parse INFO chunk and save meta data to vlc.
> 
> Feature ticket: https://trac.videolan.org/vlc/ticket/6587
> 
> Signed-off-by: Zhao, Gang <gang.zhao.42 at gmail.com>
> ---
> Tested this patch with the four wav files in ticket 6587. It can get and save
> meta data from INFO chunk.
> 
> v2:
> Fixed a typo in commit log
> 
>  modules/demux/wav.c | 216 ++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 207 insertions(+), 9 deletions(-)
> 
> diff --git modules/demux/wav.c modules/demux/wav.c
> index 4b0623412f..75b37d5be0 100644
> --- modules/demux/wav.c
> +++ modules/demux/wav.c
> @@ -36,6 +36,8 @@
>  #include <vlc_demux.h>
>  #include <vlc_aout.h>
>  #include <vlc_codecs.h>
> +#include <vlc_charset.h>
> +#include <vlc_meta.h>
>  
>  #include "windows_audio_commons.h"
>  
> @@ -58,26 +60,96 @@ typedef struct
>      uint32_t i_channel_mask;
>      uint8_t i_chans_to_reorder;            /* do we need channel reordering */
>      uint8_t pi_chan_table[AOUT_CHAN_MAX];
> +
> +    vlc_meta_t    *p_meta;
>  } demux_sys_t;
>  
>  enum wav_chunk_id {
> +    wav_chunk_id_list,
>      wav_chunk_id_data,
>      wav_chunk_id_ds64,
>      wav_chunk_id_fmt,
> +
> +    wav_info_chunk_id_iarl,
> +    wav_info_chunk_id_iart,
> +    wav_info_chunk_id_icms,
> +    wav_info_chunk_id_icmt,
> +    wav_info_chunk_id_icop,
> +    wav_info_chunk_id_icrd,
> +    wav_info_chunk_id_icrp,
> +    wav_info_chunk_id_idim,
> +    wav_info_chunk_id_idpi,
> +    wav_info_chunk_id_ieng,
> +    wav_info_chunk_id_ignr,
> +    wav_info_chunk_id_ikey,
> +    wav_info_chunk_id_ilgt,
> +    wav_info_chunk_id_imed,
> +    wav_info_chunk_id_inam,
> +    wav_info_chunk_id_iplt,
> +    wav_info_chunk_id_iprd,
> +    wav_info_chunk_id_isbj,
> +    wav_info_chunk_id_isft,
> +    wav_info_chunk_id_ishp,
> +    wav_info_chunk_id_isrc,
> +    wav_info_chunk_id_isrf,
> +    wav_info_chunk_id_itch,
>  };
>  
> -static const struct wav_chunk_id_key
> +struct wav_chunk_id_key
>  {
>      enum wav_chunk_id id;
>      char key[5];
> -} wav_chunk_id_key_list[] =  {
> +};
> +
> +static const struct wav_chunk_id_key wav_chunk_id_key_list[] =  {
>      /* Alphabetical order */
> +    { wav_chunk_id_list, "LIST" },
>      { wav_chunk_id_data, "data" },
>      { wav_chunk_id_ds64, "ds64" },
>      { wav_chunk_id_fmt,  "fmt " },
>  };
>  static const size_t wav_chunk_id_key_count = ARRAY_SIZE(wav_chunk_id_key_list);
>  
> +static const struct wav_chunk_id_key wav_info_chunk_id_key_list[] =  {
> +    /* Alphabetical order */
> +    { wav_info_chunk_id_iarl, "IARL" },
> +    { wav_info_chunk_id_iart, "IART" },
> +    { wav_info_chunk_id_icms, "ICMS" },
> +    { wav_info_chunk_id_icmt, "ICMT" },
> +    { wav_info_chunk_id_icop, "ICOP" },
> +    { wav_info_chunk_id_icrd, "ICRD" },
> +    { wav_info_chunk_id_icrp, "ICRP" },
> +    { wav_info_chunk_id_idim, "IDIM" },
> +    { wav_info_chunk_id_idpi, "IDPI" },
> +    { wav_info_chunk_id_ieng, "IENG" },
> +    { wav_info_chunk_id_ignr, "IGNR" },
> +    { wav_info_chunk_id_ikey, "IKEY" },
> +    { wav_info_chunk_id_ilgt, "ILGT" },
> +    { wav_info_chunk_id_imed, "IMED" },
> +    { wav_info_chunk_id_inam, "INAM" },
> +    { wav_info_chunk_id_iplt, "IPLT" },
> +    { wav_info_chunk_id_iprd, "IPRD" },
> +    { wav_info_chunk_id_isbj, "ISBJ" },
> +    { wav_info_chunk_id_isft, "ISFT" },
> +    { wav_info_chunk_id_ishp, "ISHP" },
> +    { wav_info_chunk_id_isrc, "ISRC" },
> +    { wav_info_chunk_id_isrf, "ISRF" },
> +    { wav_info_chunk_id_itch, "ITCH" },
> +};
> +static const size_t wav_info_chunk_id_key_count = 
> ARRAY_SIZE(wav_info_chunk_id_key_list);
> +
> +static const char *wav_info_chunk_id_to_key(enum wav_chunk_id id)
> +{
> +    if ( id < wav_info_chunk_id_iarl || id > wav_info_chunk_id_itch )
> +        return "";

Your fonction is taking an enum in argument but is checking if the enum is out of bound. This seems weird.
You could check the validity of the id after ChunkGetNext() in ChunkParseINFO().

> +
> +    for ( int i = 0; i < wav_info_chunk_id_key_count; i++)
> +        if (wav_info_chunk_id_key_list[i].id == id)
> +            return wav_info_chunk_id_key_list[i].key;
> +
> +    return "";
> +}
> +
>  static int
>  wav_chunk_CompareCb(const void *a, const void *b)
>  {
> @@ -190,13 +262,14 @@ static int ChunkSkip( demux_t *p_demux, uint32_t 
> i_size )
>  }
>  
>  static int ChunkGetNext( demux_t *p_demux, enum wav_chunk_id *p_id,
> -                         uint32_t *pi_size )
> +                         uint32_t *pi_size,
> +                         const struct wav_chunk_id_key *id_key_list, 
> size_t count )
>  {
>  #ifndef NDEBUG
>      /* assert that keys are in alphabetical order */
> -    for( size_t i = 0; i < wav_chunk_id_key_count - 1; ++i )
> -        assert( strcmp( wav_chunk_id_key_list[i].key,
> -                        wav_chunk_id_key_list[i + 1].key ) < 0 );
> +    for( size_t i = 0; i < count - 1; ++i )
> +        assert( strcmp( id_key_list[i].key,
> +                        id_key_list[i + 1].key ) < 0 );
>  #endif
>  
>      for( ;; )
> @@ -206,8 +279,8 @@ static int ChunkGetNext( demux_t *p_demux, enum 
> wav_chunk_id *p_id,
>              return VLC_EGENERIC;
>  
>          const struct wav_chunk_id_key *id =
> -            bsearch( p_peek, wav_chunk_id_key_list, wav_chunk_id_key_count,
> -                     sizeof(*wav_chunk_id_key_list), wav_chunk_CompareCb );
> +            bsearch( p_peek, id_key_list, count,
> +                     sizeof(*id_key_list), wav_chunk_CompareCb );
>          uint32_t i_size = GetDWLE( p_peek + 4 );

This could go in a separate function to improve readability.

>  
>          if( id == NULL )
> @@ -317,6 +390,10 @@ static void Close ( vlc_object_t * p_this )
>      demux_sys_t *p_sys   = p_demux->p_sys;
>  
>      es_format_Clean( &p_sys->fmt );
> +
> +    if( p_sys->p_meta )
> +        vlc_meta_Delete( p_sys->p_meta );
> +
>      free( p_sys );
>  }
>  
> @@ -591,6 +668,114 @@ error:
>      return VLC_EGENERIC;
>  }
>  
> +static int ChunkParseINFO( demux_t *p_demux, uint32_t i_size )
> +{
> +    demux_sys_t *p_sys = p_demux->p_sys;
> +    const uint8_t *p_peek;
> +    enum wav_chunk_id id;
> +    uint32_t chunk_size;
> +    int meta_type;
> +    char *meta_value;
> +
> +    if( (p_sys->p_meta = vlc_meta_New()) == NULL )
> +    {
> +        msg_Err( p_demux, "vlc_meta_New failed" );
> +        return VLC_EGENERIC;
> +    }
> +
> +    while (i_size > 0) {
> +        int ret = ChunkGetNext( p_demux, &id, &chunk_size,
> +                                wav_info_chunk_id_key_list,
> +                                wav_info_chunk_id_key_count );
> +        if ( ret != VLC_SUCCESS )
> +            break;
> +
> +        /* chunk id(4 bytes) and chunk size(4 bytes) consumed by 
> ChunkGetNext */
> +        i_size -= 8;
> +
> +        if( chunk_size == 0 )
> +        {
> +            msg_Err( p_demux, "invalid chunk with a size 0" );
> +            return VLC_EGENERIC;
> +        }
> +
> +        if( vlc_stream_Peek( p_demux->s, &p_peek, chunk_size ) != 
> chunk_size )
> +            return VLC_EGENERIC;
> +
> +        meta_value = strndup( (const char *)p_peek, chunk_size );
> +        if (meta_value == NULL)
> +            return VLC_EGENERIC;
> +
> +        EnsureUTF8( meta_value );
> +
> +        meta_type = -1;
> +        switch( id )
> +        {
> +        case wav_info_chunk_id_iart:
> +            meta_type = vlc_meta_Artist;
> +            break;
> +        case wav_info_chunk_id_icop:
> +            meta_type = vlc_meta_Copyright;
> +            break;
> +        case wav_info_chunk_id_icrd:
> +            meta_type = vlc_meta_Date;
> +            break;
> +        case wav_info_chunk_id_ignr:
> +            meta_type = vlc_meta_Genre;
> +            break;
> +        case wav_info_chunk_id_inam:
> +            meta_type = vlc_meta_Title;
> +            break;
> +        default:
> +            /* no relevant meta type in vlc */
> +            break;
> +        }
> +
> +        msg_Dbg( p_demux, "id: %s meta_type: %d meta_value: %s\n",
> +                 wav_info_chunk_id_to_key(id), meta_type, meta_value );
> +
> +        if (meta_type != -1)
> +            vlc_meta_Set( p_sys->p_meta, meta_type, meta_value );
> +        else
> +            vlc_meta_AddExtra( p_sys->p_meta,
> +                               wav_info_chunk_id_key_list[id].key, 
> meta_value );
> +
> +        free( meta_value );
> +        if( ChunkSkip( p_demux, chunk_size ) != VLC_SUCCESS )
> +            return VLC_EGENERIC;
> +
> +        i_size -= chunk_size;
> +    }
> +
> +    return VLC_SUCCESS;
> +}
> +
> +static int ChunkParseLIST( demux_t *p_demux, uint32_t i_size )
> +{
> +    const uint8_t *p_peek;
> +
> +    /* must have four bytes list type */
> +    if( i_size < 4 )
> +    {
> +        msg_Err( p_demux, "invalid 'LIST' chunk" );
> +        return VLC_EGENERIC;
> +    }
> +
> +    if( vlc_stream_Peek( p_demux->s, &p_peek, 4 ) != 4 )
> +        return VLC_EGENERIC;
> +
> +    /* only care about INFO chunk */
> +    if ( memcmp(p_peek, "INFO", 4) != 0 ) {
> +        return ChunkSkip( p_demux, i_size );
> +    }
> +
> +    if ( vlc_stream_Read( p_demux->s, NULL, 4) != 4 )
> +        return VLC_EGENERIC;
> +
> +    i_size -= 4;
> +    return ChunkParseINFO( p_demux, i_size );
> +}
> +
>  static int Open( vlc_object_t * p_this )
>  {
>      demux_t     *p_demux = (demux_t*)p_this;
> @@ -629,8 +814,13 @@ static int Open( vlc_object_t * p_this )
>  
>      bool eof = false;
>      enum wav_chunk_id id;
> -    while( !eof && ( ChunkGetNext( p_demux, &id, &i_size ) ) == 
> VLC_SUCCESS )
> +    while( !eof )
>      {
> +        int ret = ChunkGetNext( p_demux, &id, &i_size,
> +                                wav_chunk_id_key_list, 
> wav_chunk_id_key_count );
> +        if (ret != VLC_SUCCESS )
> +            break;
> +
>          if( i_size == 0 )
>          {
>              msg_Err( p_demux, "invalid chunk with a size 0");
> @@ -676,6 +866,14 @@ static int Open( vlc_object_t * p_this )
>                  if( ChunkParseFmt( p_demux, i_size ) != VLC_SUCCESS )
>                      goto error;
>                  break;
> +            case wav_chunk_id_list:
> +                if( ChunkParseLIST( p_demux, i_size ) != VLC_SUCCESS )
> +                    goto error;
> +                break;
> +            default:
> +                if( ChunkSkip( p_demux, i_size ) != VLC_SUCCESS )
> +                    goto error;
> +                break;
>          }
>      }
>  
> -- 
> 2.25.1
> 
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel


More information about the vlc-devel mailing list