It will allows to remove ugly hack in decoder.
#include <vlc_codec.h>
#include <assert.h>
#include <vlc_charset.h>
+#include "vorbis.h"
/*****************************************************************************
* Module descriptor
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 )
#include <vlc_codecs.h>
#include <vlc_bits.h>
+#include <vlc_charset.h>
+#include "vorbis.h"
/*****************************************************************************
* Module descriptor
/* 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) */
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 * );
ogg_sync_init( &p_sys->oy );
p_sys->b_page_waiting = false;
+ /* */
+ p_sys->p_meta = NULL;
+
return VLC_SUCCESS;
}
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;
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--;
}
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;
}
/**
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 )
--- /dev/null
+/*****************************************************************************
+ * 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
+}
+