Commit 30815340 authored by Laurent Aimar's avatar Laurent Aimar

Parse meta data at ogg level.

It will allows to remove ugly hack in decoder.
parent 3d7cbf17
......@@ -37,6 +37,7 @@
#include <vlc_codec.h>
#include <assert.h>
#include <vlc_charset.h>
#include "vorbis.h"
/*****************************************************************************
* Module descriptor
......@@ -567,88 +568,12 @@ static void ParseSeekTable( demux_t *p_demux, const uint8_t *p_data, int i_data,
static void ParseComment( demux_t *p_demux, const uint8_t *p_data, int i_data )
{
demux_sys_t *p_sys = p_demux->p_sys;
int n;
int i_comment;
if( i_data < 8 )
return;
RM(4);
n = GetDWLE(p_data); RM(4);
if( n < 0 || n > i_data )
return;
#if 0
if( n > 0 )
{
/* TODO report vendor string ? */
char *psz_vendor = psz_vendor = strndup( p_data, n );
msg_Dbg( p_demux, "FLAC: COMMENT vendor length=%d vendor=%s\n", n, psz_vendor );
free( psz_vendor );
}
#endif
RM(n);
if( i_data < 4 )
return;
i_comment = GetDWLE(p_data); RM(4);
if( i_comment <= 0 )
return;
p_sys->p_meta = vlc_meta_New();
vorbis_ParseComment( &p_sys->p_meta, &p_data[4], i_data - 4 );
for( ; i_comment > 0; i_comment-- )
{
char *psz;
if( i_data < 4 )
break;
n = GetDWLE(p_data); RM(4);
if( n > i_data )
break;
if( n <= 0 )
continue;
psz = strndup( (const char*)p_data, n );
RM(n);
EnsureUTF8( psz );
#define IF_EXTRACT(txt,var) \
if( !strncasecmp(psz, txt, strlen(txt)) ) \
{ \
const char *oldval = vlc_meta_Get( p_sys->p_meta, vlc_meta_ ## var ); \
if( oldval ) \
{ \
char * newval; \
if( asprintf( &newval, "%s,%s", oldval, &psz[strlen(txt)] ) == -1 ) \
newval = NULL; \
vlc_meta_Set( p_sys->p_meta, vlc_meta_ ## var, newval ); \
free( newval ); \
} \
else \
vlc_meta_Set( p_sys->p_meta, vlc_meta_ ## var, &psz[strlen(txt)] ); \
}
IF_EXTRACT("TITLE=", Title )
else IF_EXTRACT("ALBUM=", Album )
else IF_EXTRACT("TRACKNUMBER=", TrackNumber )
else IF_EXTRACT("ARTIST=", Artist )
else IF_EXTRACT("COPYRIGHT=", Copyright )
else IF_EXTRACT("DESCRIPTION=", Description )
else IF_EXTRACT("GENRE=", Genre )
else IF_EXTRACT("DATE=", Date )
else if( strchr( psz, '=' ) )
{
/* generic (PERFORMER/LICENSE/ORGANIZATION/LOCATION/CONTACT/ISRC,
* undocumented tags and replay gain ) */
char *p = strchr( psz, '=' );
*p++ = '\0';
vlc_meta_AddExtra( p_sys->p_meta, psz, p );
}
#undef IF_EXTRACT
free( psz );
}
#undef RM
}
static void ParsePicture( demux_t *p_demux, const uint8_t *p_data, int i_data )
......
......@@ -39,6 +39,8 @@
#include <vlc_codecs.h>
#include <vlc_bits.h>
#include <vlc_charset.h>
#include "vorbis.h"
/*****************************************************************************
* Module descriptor
......@@ -119,6 +121,9 @@ struct demux_sys_t
/* after reading all headers, the first data page is stuffed into the relevant stream, ready to use */
bool b_page_waiting;
/* */
vlc_meta_t *p_meta;
};
/* OggDS headers for the new header format (used in ogm files) */
......@@ -188,6 +193,9 @@ static void Ogg_EndOfStream( demux_t *p_demux );
static void Ogg_LogicalStreamDelete( demux_t *p_demux, logical_stream_t *p_stream );
static bool Ogg_LogicalStreamResetEsFormat( demux_t *p_demux, logical_stream_t *p_stream );
/* */
static void Ogg_ExtractMeta( demux_t *p_demux, vlc_fourcc_t i_codec, const uint8_t *p_headers, int i_headers );
/* Logical bitstream headers */
static void Ogg_ReadTheoraHeader( logical_stream_t *, ogg_packet * );
static void Ogg_ReadVorbisHeader( logical_stream_t *, ogg_packet * );
......@@ -234,6 +242,9 @@ static int Open( vlc_object_t * p_this )
ogg_sync_init( &p_sys->oy );
p_sys->b_page_waiting = false;
/* */
p_sys->p_meta = NULL;
return VLC_SUCCESS;
}
......@@ -426,12 +437,19 @@ static int Demux( demux_t * p_demux )
static int Control( demux_t *p_demux, int i_query, va_list args )
{
demux_sys_t *p_sys = p_demux->p_sys;
vlc_meta_t *p_meta;
int64_t *pi64;
bool *pb_bool;
int i;
switch( i_query )
{
case DEMUX_GET_META:
p_meta = (vlc_meta_t *)va_arg( args, vlc_meta_t* );
if( p_sys->p_meta )
vlc_meta_Merge( p_meta, p_sys->p_meta );
return VLC_SUCCESS;
case DEMUX_HAS_UNSUPPORTED_META:
pb_bool = (bool*)va_arg( args, bool* );
*pb_bool = true;
......@@ -674,6 +692,10 @@ static void Ogg_DecodePacket( demux_t *p_demux,
es_out_Control( p_demux->out, ES_OUT_SET_ES_FMT,
p_stream->p_es, &p_stream->fmt );
if( p_stream->i_headers > 0 )
Ogg_ExtractMeta( p_demux, p_stream->fmt.i_codec,
p_stream->p_headers, p_stream->i_headers );
/* we're not at BOS anymore for this logical stream */
p_ogg->i_bos--;
}
......@@ -1396,6 +1418,11 @@ static void Ogg_EndOfStream( demux_t *p_demux )
p_ogg->i_bitrate = 0;
p_ogg->i_streams = 0;
p_ogg->pp_stream = NULL;
/* */
if( p_ogg->p_meta )
vlc_meta_Delete( p_ogg->p_meta );
p_ogg->p_meta = NULL;
}
/**
......@@ -1463,6 +1490,66 @@ static bool Ogg_LogicalStreamResetEsFormat( demux_t *p_demux, logical_stream_t *
return !b_compatible;
}
static void Ogg_ExtractXiphMeta( demux_t *p_demux, const uint8_t *p_headers, int i_headers, int i_skip )
{
demux_sys_t *p_ogg = p_demux->p_sys;
if( i_headers <= 2 )
return;
/* Skip first packet */
const int i_tmp = GetWBE( &p_headers[0] );
if( i_tmp > i_headers-2 )
return;
p_headers += 2 + i_tmp;
i_headers -= 2 + i_tmp;
if( i_headers <= 2 )
return;
/* */
int i_comment = GetWBE( &p_headers[0] );
const uint8_t *p_comment = &p_headers[2];
if( i_comment > i_headers - 2 )
return;
if( i_comment <= i_skip )
return;
/* TODO how to handle multiple comments properly ? */
vorbis_ParseComment( &p_ogg->p_meta, &p_comment[i_skip], i_comment - i_skip );
}
static void Ogg_ExtractMeta( demux_t *p_demux, vlc_fourcc_t i_codec, const uint8_t *p_headers, int i_headers )
{
demux_sys_t *p_ogg = p_demux->p_sys;
switch( i_codec )
{
/* 3 headers with the 2 one being the comments */
case VLC_FOURCC( 'v','o','r','b' ):
Ogg_ExtractXiphMeta( p_demux, p_headers, i_headers, 1+6 );
break;
case VLC_FOURCC( 't','h','e','o' ):
Ogg_ExtractXiphMeta( p_demux, p_headers, i_headers, 1+6 );
break;
case VLC_FOURCC( 's','p','x',' ' ):
Ogg_ExtractXiphMeta( p_demux, p_headers, i_headers, 0 );
break;
/* TODO */
case VLC_FOURCC( 'k','a','t','e' ):
case VLC_FOURCC( 'f','l','a','c' ):
case VLC_FOURCC( 'c','m','m','l' ):
msg_Warn( p_demux, "Ogg_ExtractMeta does not support %4.4s", (const char*)&i_codec );
break;
/* No meta data */
case VLC_FOURCC( 'd','r','a','c' ):
default:
break;
}
if( p_ogg->p_meta )
p_demux->info.i_update |= INPUT_UPDATE_META;
}
static void Ogg_ReadTheoraHeader( logical_stream_t *p_stream,
ogg_packet *p_oggpacket )
......
/*****************************************************************************
* vorbis.h: Vorbis Comment parser
*****************************************************************************
* Copyright (C) 2008 the VideoLAN team
* $Id$
*
* Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
static inline void vorbis_ParseComment( vlc_meta_t **pp_meta, const uint8_t *p_data, int i_data )
{
int n;
int i_comment;
if( i_data < 8 )
return;
#define RM(x) do { i_data -= (x); p_data += (x); } while(0)
n = GetDWLE(p_data); RM(4);
if( n < 0 || n > i_data )
return;
#if 0
if( n > 0 )
{
/* TODO report vendor string ? */
char *psz_vendor = psz_vendor = strndup( p_data, n );
free( psz_vendor );
}
#endif
RM(n);
if( i_data < 4 )
return;
i_comment = GetDWLE(p_data); RM(4);
if( i_comment <= 0 )
return;
/* */
vlc_meta_t *p_meta = *pp_meta;
if( !p_meta )
*pp_meta = p_meta = vlc_meta_New();
if( !p_meta )
return;
for( ; i_comment > 0; i_comment-- )
{
char *psz;
if( i_data < 4 )
break;
n = GetDWLE(p_data); RM(4);
if( n > i_data )
break;
if( n <= 0 )
continue;
psz = strndup( (const char*)p_data, n );
RM(n);
EnsureUTF8( psz );
#define IF_EXTRACT(txt,var) \
if( !strncasecmp(psz, txt, strlen(txt)) ) \
{ \
const char *oldval = vlc_meta_Get( p_meta, vlc_meta_ ## var ); \
if( oldval ) \
{ \
char * newval; \
if( asprintf( &newval, "%s,%s", oldval, &psz[strlen(txt)] ) == -1 ) \
newval = NULL; \
vlc_meta_Set( p_meta, vlc_meta_ ## var, newval ); \
free( newval ); \
} \
else \
vlc_meta_Set( p_meta, vlc_meta_ ## var, &psz[strlen(txt)] ); \
}
IF_EXTRACT("TITLE=", Title )
else IF_EXTRACT("ALBUM=", Album )
else IF_EXTRACT("TRACKNUMBER=", TrackNumber )
else IF_EXTRACT("ARTIST=", Artist )
else IF_EXTRACT("COPYRIGHT=", Copyright )
else IF_EXTRACT("DESCRIPTION=", Description )
else IF_EXTRACT("GENRE=", Genre )
else IF_EXTRACT("DATE=", Date )
else if( strchr( psz, '=' ) )
{
/* generic (PERFORMER/LICENSE/ORGANIZATION/LOCATION/CONTACT/ISRC,
* undocumented tags and replay gain ) */
char *p = strchr( psz, '=' );
*p++ = '\0';
vlc_meta_AddExtra( p_meta, psz, p );
}
#undef IF_EXTRACT
free( psz );
}
#undef RM
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment