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

Zhao, Gang gang.zhao.42 at gmail.com
Sun Sep 13 04:22:07 CEST 2020


On Sat, Sep 12, 2020 at 11:57 PM Sean McGovern <gseanmcg at gmail.com> wrote:

> Nit: you spelled "parsing" correctly in the title but not in the commit
> text.
>
> Thanks for pointing out this. Fixed in v2.


> Sean McGovern
>
> On Sat., Sep. 12, 2020, 10:09 Zhao, Gang, <gang.zhao.42 at gmail.com> wrote:
>
>> Paring 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 that the code successfully got and saved meta data in the four
>> test wav files.
>>
>>  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 "";
>> +
>> +    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 );
>>
>>          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
>
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/vlc-devel/attachments/20200913/1ddad60d/attachment.html>


More information about the vlc-devel mailing list