the only demuxer supported is mpga, other demuxers should be updated if they demux files that can have id3v2 tags
fix some bugs in flac & ogg demuxers
typedef struct stream_t stream_t;
typedef struct stream_sys_t stream_sys_t;
typedef struct demux_t demux_t;
+typedef struct demux_meta_t demux_meta_t;
typedef struct demux_sys_t demux_sys_t;
typedef struct es_out_t es_out_t;
typedef struct es_out_id_t es_out_id_t;
demux_sys_t *p_sys;
};
+
+/* demux_meta_t is returned by "meta reader" module to the demuxer */
+struct demux_meta_t
+{
+ vlc_meta_t *p_meta; /**< meta data */
+
+ int i_attachments; /**< number of attachments */
+ input_attachment_t **attachments; /**< array of attachments */
+};
+
enum demux_query_e
{
/* I. Common queries to access_demux and demux */
input_thread_t *p_input = (input_thread_t *)vlc_object_find( p_demux, VLC_OBJECT_INPUT, FIND_PARENT );
if( p_input )
{
+ p_demux->p_private = malloc( sizeof( demux_meta_t ) );
+ if( !p_demux->p_private )
+ {
+ vlc_object_release( p_input );
+ return VLC_ENOMEM;
+ }
module_t *p_meta = module_Need( p_demux, "meta reader", NULL, 0 );
if( p_meta )
{
- vlc_meta_Merge( input_GetItem(p_input)->p_meta, (vlc_meta_t*)(p_demux->p_private ) );
+ demux_meta_t *p_demux_meta = (demux_meta_t *)p_demux->p_private;
+ vlc_meta_Merge( input_GetItem(p_input)->p_meta,
+ p_demux_meta->p_meta );
+ vlc_meta_Delete( p_demux_meta->p_meta );
module_Unneed( p_demux, p_meta );
+ TAB_CLEAN( p_demux_meta->i_attachments,
+ p_demux_meta->attachments );
}
vlc_object_release( p_input );
+ free( p_demux->p_private );
}
return VLC_SUCCESS;
seekpoint_t **seekpoint;
/* */
- int i_attachment;
- input_attachment_t **attachment;
+ int i_attachments;
+ input_attachment_t **attachments;
int i_cover_idx;
int i_cover_score;
};
p_sys->i_pts_start = 0;
p_sys->p_es = NULL;
TAB_INIT( p_sys->i_seekpoint, p_sys->seekpoint );
- TAB_INIT( p_sys->i_attachment, p_sys->attachment );
+ TAB_INIT( p_sys->i_attachments, p_sys->attachments);
p_sys->i_cover_idx = 0;
p_sys->i_cover_score = 0;
}
/* Parse possible id3 header */
+ p_demux->p_private = malloc( sizeof( demux_meta_t ) );
+ if( !p_demux->p_private )
+ return VLC_ENOMEM;
if( ( p_id3 = module_Need( p_demux, "meta reader", NULL, 0 ) ) )
{
- vlc_meta_t *p_meta = (vlc_meta_t *)p_demux->p_private;
+ demux_meta_t *p_demux_meta = (demux_meta_t *)p_demux->p_private;
+ vlc_meta_t *p_meta = p_demux_meta->p_meta;
if( !p_sys->p_meta )
{
}
p_demux->p_private = NULL;
module_Unneed( p_demux, p_id3 );
+ int i;
+ for( i = 0; i < p_demux_meta->i_attachments; i++ )
+ TAB_APPEND_CAST( (input_attachment_t**),
+ p_sys->i_attachments, p_sys->attachments,
+ p_demux_meta->attachments[p_demux_meta->i_attachments] );
+
+ TAB_CLEAN( p_demux_meta->i_attachments, p_demux_meta->attachments );
}
+ free( p_demux->p_private );
- if( p_sys->i_cover_idx < p_sys->i_attachment )
+ if( p_sys->i_cover_idx < p_sys->i_attachments )
{
char psz_url[128];
if( !p_sys->p_meta )
p_sys->p_meta = vlc_meta_New();
snprintf( psz_url, sizeof(psz_url), "attachment://%s",
- p_sys->attachment[p_sys->i_cover_idx]->psz_name );
+ p_sys->attachments[p_sys->i_cover_idx]->psz_name );
vlc_meta_Set( p_sys->p_meta, vlc_meta_ArtworkURL, psz_url );
}
vlc_audio_replay_gain_MergeFromMeta( &p_sys->replay_gain, p_sys->p_meta );
demux_t *p_demux = (demux_t*)p_this;
demux_sys_t *p_sys = p_demux->p_sys;
+ TAB_CLEAN( p_sys->i_seekpoint, p_sys->seekpoint );
+ TAB_CLEAN( p_sys->i_attachments, p_sys->attachments);
+
/* Unneed module */
module_Unneed( p_sys->p_packetizer, p_sys->p_packetizer->p_module );
int *pi_int = (int*)va_arg( args, int * );
int i;
- if( p_sys->i_attachment <= 0 )
+ if( p_sys->i_attachments <= 0 )
return VLC_EGENERIC;
- *pi_int = p_sys->i_attachment;;
- *ppp_attach = malloc( sizeof(input_attachment_t**) * p_sys->i_attachment );
- for( i = 0; i < p_sys->i_attachment; i++ )
- *(ppp_attach)[i] = vlc_input_attachment_Duplicate( p_sys->attachment[i] );
+ *pi_int = p_sys->i_attachments;;
+ *ppp_attach = malloc( sizeof(input_attachment_t**) * p_sys->i_attachments );
+ for( i = 0; i < p_sys->i_attachments; i++ )
+ (*ppp_attach)[i] = vlc_input_attachment_Duplicate( p_sys->attachments[i] );
return VLC_SUCCESS;
}
s->i_byte_offset = 0;
TAB_APPEND( p_sys->i_seekpoint, p_sys->seekpoint, s );
-
-
b_last = (*pp_streaminfo)[4]&0x80;
while( !b_last )
{
msg_Dbg( p_demux, "FLAC: Picture type=%d mime=%s description='%s' file length=%d",
i_type, psz_mime, psz_description, i_len );
- snprintf( psz_name, sizeof(psz_name), "picture%d", p_sys->i_attachment );
+ snprintf( psz_name, sizeof(psz_name), "picture%d", p_sys->i_attachments );
if( !strcasecmp( psz_mime, "image/jpeg" ) )
strcat( psz_name, ".jpg" );
else if( !strcasecmp( psz_mime, "image/png" ) )
p_attachment = vlc_input_attachment_New( psz_name, psz_mime, psz_description,
p_data, i_data );
- TAB_APPEND( p_sys->i_attachment, p_sys->attachment, p_attachment );
+ TAB_APPEND( p_sys->i_attachments, p_sys->attachments, p_attachment );
if( i_type >= 0 && i_type < sizeof(pi_cover_score)/sizeof(pi_cover_score[0]) &&
p_sys->i_cover_score < pi_cover_score[i_type] )
{
- p_sys->i_cover_idx = p_sys->i_attachment-1;
+ p_sys->i_cover_idx = p_sys->i_attachments-1;
p_sys->i_cover_score = pi_cover_score[i_type];
}
error:
}
/* Parse possible id3 header */
+ p_demux->p_private = malloc( sizeof( demux_meta_t ) );
+ if( !p_demux->p_private )
+ return VLC_ENOMEM;
if( ( p_id3 = module_Need( p_demux, "meta reader", NULL, 0 ) ) )
{
- p_sys->p_meta = (vlc_meta_t *)p_demux->p_private;
- p_demux->p_private = NULL;
+ demux_meta_t *p_demux_meta = (demux_meta_t *)p_demux->p_private;
+ p_sys->p_meta = p_demux_meta->p_meta;
module_Unneed( p_demux, p_id3 );
+ TAB_CLEAN( p_demux_meta->i_attachments, p_demux_meta->attachments );
}
+ free( p_demux->p_private );
if( !p_sys->p_meta )
p_sys->p_meta = vlc_meta_New();
LOAD_PACKETIZER_OR_FAIL( p_sys->p_packetizer, "mp4 audio" );
/* Parse possible id3 header */
+ p_demux->p_private = malloc( sizeof( demux_meta_t ) );
+ if( !p_demux->p_private )
+ return VLC_ENOMEM;
if( ( p_id3 = module_Need( p_demux, "meta reader", NULL, 0 ) ) )
{
- p_sys->meta = (vlc_meta_t *)p_demux->p_private;
+ demux_meta_t *p_demux_meta = (demux_meta_t *)p_demux->p_private;
+ p_sys->meta = p_demux_meta->p_meta;
p_demux->p_private = NULL;
module_Unneed( p_demux, p_id3 );
+ TAB_CLEAN( p_demux_meta->i_attachments, p_demux_meta->attachments );
}
+ free( p_demux->p_private );
return VLC_SUCCESS;
}
int i_xing_bitrate_avg;
int i_xing_frame_samples;
block_t *p_block_in, *p_block_out;
+
+ int i_attachments;
+ input_attachment_t **attachments;
};
static int HeaderCheck( uint32_t h )
p_sys->p_block_out = p_block_out;
/* Parse possible id3 header */
+ p_demux->p_private = malloc( sizeof( demux_meta_t ) );
+ if( !p_demux->p_private )
+ return VLC_ENOMEM;
if( ( p_id3 = module_Need( p_demux, "meta reader", NULL, 0 ) ) )
{
- p_sys->meta = (vlc_meta_t *)p_demux->p_private;
+ demux_meta_t *p_demux_meta = (demux_meta_t *)p_demux->p_private;
+ p_sys->meta = p_demux_meta->p_meta;
p_demux->p_private = NULL;
module_Unneed( p_demux, p_id3 );
+ p_sys->i_attachments = p_demux_meta->i_attachments;
+ p_sys->attachments = p_demux_meta->attachments;
}
+ free( p_demux->p_private );
/* */
p_sys->p_packetizer->fmt_out.b_packetized = VLC_TRUE;
if( p_sys->meta ) vlc_meta_Delete( p_sys->meta );
if( p_sys->p_block_out ) block_Release( p_sys->p_block_out );
+ TAB_CLEAN( p_sys->i_attachments, p_sys->attachments);
+
free( p_sys );
}
vlc_meta_t *p_meta;
int i_ret;
+ input_attachment_t ***ppp_attach;
+ int *pi_int, i;
+
switch( i_query )
{
case DEMUX_GET_META:
vlc_meta_Merge( p_meta, p_sys->meta );
return VLC_SUCCESS;
+ case DEMUX_GET_ATTACHMENTS:
+ ppp_attach =
+ (input_attachment_t***)va_arg( args, input_attachment_t*** );
+ pi_int = (int*)va_arg( args, int * );
+
+ if( p_sys->i_attachments <= 0 )
+ return VLC_EGENERIC;
+
+ *pi_int = p_sys->i_attachments;
+ *ppp_attach = malloc( sizeof(input_attachment_t**) * p_sys->i_attachments );
+ for( i = 0; i < p_sys->i_attachments; i++ )
+ (*ppp_attach)[i] = vlc_input_attachment_Duplicate( p_sys->attachments[i] );
+ return VLC_SUCCESS;
+
case DEMUX_GET_TIME:
pi64 = (int64_t*)va_arg( args, int64_t * );
*pi64 = p_sys->i_pts + p_sys->i_time_offset;
p_input = (input_thread_t *)vlc_object_find( p_demux, VLC_OBJECT_INPUT, FIND_PARENT );
if( p_input )
{
+ p_demux->p_private = malloc( sizeof( demux_meta_t ) );
+ if( !p_demux->p_private )
+ {
+ vlc_object_release( p_input );
+ return VLC_ENOMEM;
+ }
module_t *p_meta = module_Need( p_demux, "meta reader", NULL, 0 );
if( p_meta )
{
- vlc_meta_Merge( input_GetItem(p_input)->p_meta, (vlc_meta_t*)(p_demux->p_private ) );
+ demux_meta_t *p_demux_meta = (demux_meta_t *)p_demux->p_private;
+ vlc_meta_Merge( input_GetItem(p_input)->p_meta,
+ p_demux_meta->p_meta );
+ vlc_meta_Delete( p_demux_meta->p_meta );
module_Unneed( p_demux, p_meta );
+ TAB_CLEAN( p_demux_meta->i_attachments, p_demux_meta->attachments );
}
vlc_object_release( p_input );
- return VLC_SUCCESS;
+ free( p_demux->p_private );
}
- if( p_input )
- vlc_object_release( p_input );
/* Initialize the Ogg physical bitstream parser */
ogg_sync_init( &p_sys->oy );
p_demux->pf_demux = Demux;
p_demux->pf_control = Control;
p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) );
-
+
/* Read the metadata */
es_format_Init( &fmt, AUDIO_ES, VLC_FOURCC( 'T', 'T', 'A', '1' ) );
fmt.audio.i_channels = GetWLE( &p_header[6] );
p_sys->p_es = es_out_Add( p_demux->out, &fmt );
free( p_seektable );
p_sys->i_start = stream_Tell( p_demux->s );
-
+
#if 0
/* Parse possible id3 header */
+ p_demux->p_private = malloc( sizeof( demux_meta_t ) );
+ if( !p_demux->p_private )
+ return VLC_ENOMEM;
if( ( p_id3 = module_Need( p_demux, "meta reader", NULL, 0 ) ) )
{
- p_sys->p_meta = (vlc_meta_t *)p_demux->p_private;
+ demux_meta_t *p_demux_meta = (demux_meta_t *)p_demux->p_private;
+ p_sys->p_meta = p_demux_meta->p_meta;
p_demux->p_private = NULL;
module_Unneed( p_demux, p_id3 );
+ TAB_CLEAN( p_demux_meta->i_attachments, p_demux_meta->attachments );
}
+ free( p_demux->p_private );
if( !p_sys->p_meta )
p_sys->p_meta = vlc_meta_New();
{
struct id3_tag *p_id3_tag;
struct id3_frame *p_frame;
- vlc_meta_t *p_meta = (vlc_meta_t *)p_demux->p_private;
+ demux_meta_t *p_demux_meta = p_demux->p_private;
+ vlc_meta_t *p_meta;
int i;
+ TAB_INIT( p_demux_meta->i_attachments, p_demux_meta->attachments );
+ p_demux_meta->p_meta = NULL;
+
p_id3_tag = id3_tag_parse( p_data, i_size );
if( !p_id3_tag )
return;
- if( !p_meta )
- p_demux->p_private = p_meta = vlc_meta_New();
+ p_demux_meta->p_meta = p_meta = vlc_meta_New();
#define ID_IS( a ) (!strcmp( p_frame->id, a ))
#define DESCR_IS( a) strstr( (char*)p_frame->description, a )
#include <tbytevector.h>
#include <mpegfile.h>
#include <flacfile.h>
+#include <attachedpictureframe.h>
#if 0
#include <oggflacfile.h>
#endif
set_callbacks( WriteMeta, NULL );
vlc_module_end();
-static bool checkID3Image( const TagLib::ID3v2::Tag *p_tag )
-{
- TagLib::ID3v2::FrameList l = p_tag->frameListMap()[ "APIC" ];
- return !l.isEmpty();
-}
-
/* Try detecting embedded art */
-static void DetectImage( TagLib::FileRef f, vlc_meta_t *p_meta )
+static void DetectImage( TagLib::FileRef f, demux_t *p_demux )
{
+ demux_meta_t *p_demux_meta = (demux_meta_t *)p_demux->p_private;
+ vlc_meta_t *p_meta = p_demux_meta->p_meta;
+ TagLib::ID3v2::Tag *p_tag;
+ int i_score = -1;
+
+ /* Preferred type of image
+ * The 21 types are defined in id3v2 standard:
+ * http://www.id3.org/id3v2.4.0-frames */
+ static const int pi_cover_score[] = {
+ 0, /* Other */
+ 5, /* 32x32 PNG image that should be used as the file icon */
+ 4, /* File icon of a different size or format. */
+ 20, /* Front cover image of the album. */
+ 19, /* Back cover image of the album. */
+ 13, /* Inside leaflet page of the album. */
+ 18, /* Image from the album itself. */
+ 17, /* Picture of the lead artist or soloist. */
+ 16, /* Picture of the artist or performer. */
+ 14, /* Picture of the conductor. */
+ 15, /* Picture of the band or orchestra. */
+ 9, /* Picture of the composer. */
+ 8, /* Picture of the lyricist or text writer. */
+ 7, /* Picture of the recording location or studio. */
+ 10, /* Picture of the artists during recording. */
+ 11, /* Picture of the artists during performance. */
+ 6, /* Picture from a movie or video related to the track. */
+ 1, /* Picture of a large, coloured fish. */
+ 12, /* Illustration related to the track. */
+ 3, /* Logo of the band or performer. */
+ 2 /* Logo of the publisher (record company). */
+ };
+
if( TagLib::MPEG::File *mpeg =
dynamic_cast<TagLib::MPEG::File *>(f.file() ) )
{
- if( mpeg->ID3v2Tag() && checkID3Image( mpeg->ID3v2Tag() ) )
- vlc_meta_SetArtURL( p_meta, "APIC" );
+ p_tag = mpeg->ID3v2Tag();
+ if( !p_tag )
+ return;
+ TagLib::ID3v2::FrameList list = p_tag->frameListMap()[ "APIC" ];
+ if( list.isEmpty() )
+ return;
+ input_thread_t *p_input = (input_thread_t *)
+ vlc_object_find( p_demux,VLC_OBJECT_INPUT, FIND_PARENT );
+ if( !p_input )
+ return;
+ input_item_t *p_item = input_GetItem( p_input );
+ TagLib::ID3v2::AttachedPictureFrame *p_apic;
+
+ TAB_INIT( p_demux_meta->i_attachments, p_demux_meta->attachments );
+ for( TagLib::ID3v2::FrameList::Iterator iter = list.begin();
+ iter != list.end(); iter++ )
+ {
+ p_apic = dynamic_cast<TagLib::ID3v2::AttachedPictureFrame*>(*iter);
+ input_attachment_t *p_attachment;
+
+ const char *psz_name, *psz_mime, *psz_description;
+ TagLib::ByteVector p_data_taglib; const char *p_data; int i_data;
+
+ psz_mime = p_apic->mimeType().toCString(true);
+ psz_description = p_apic->description().toCString(true);
+ psz_name = psz_description;
+
+ p_data_taglib = p_apic->picture();
+ p_data = p_data_taglib.data();
+ i_data = p_data_taglib.size();
+
+ msg_Dbg( p_demux, "Found embedded art: %s (%s) is %i bytes",
+ psz_name, psz_mime, i_data );
+
+ p_attachment = vlc_input_attachment_New( psz_name, psz_mime,
+ psz_description, p_data, i_data );
+ TAB_APPEND_CAST( (input_attachment_t**),
+ p_demux_meta->i_attachments, p_demux_meta->attachments,
+ p_attachment );
+
+ if( pi_cover_score[p_apic->type()] > i_score )
+ {
+ i_score = pi_cover_score[p_apic->type()];
+ char *psz_url;
+ if( asprintf( &psz_url, "attachment://%s",
+ p_attachment->psz_name ) == -1 )
+ {
+ vlc_object_release( p_input );
+ return;
+ }
+ vlc_meta_SetArtURL( p_meta, psz_url );
+ free( psz_url );
+ }
+ }
+ vlc_object_release( p_input );
}
+#if 0
+ //flac embedded images are extracted in the flac demuxer
else if( TagLib::FLAC::File *flac =
dynamic_cast<TagLib::FLAC::File *>(f.file() ) )
{
- if( flac->ID3v2Tag() && checkID3Image( flac->ID3v2Tag() ) )
+ p_tag = flac->ID3v2Tag();
+ if( p_tag )
+ return;
+ TagLib::ID3v2::FrameList l = p_tag->frameListMap()[ "APIC" ];
+ if( l.isEmpty() )
+ return;
vlc_meta_SetArtURL( p_meta, "APIC" );
}
+#endif
#if 0
/* This needs special additions to taglib */
* else if( TagLib::MP4::File *mp4 =
static int ReadMeta( vlc_object_t *p_this )
{
- demux_t *p_demux = (demux_t *)p_this;
+ demux_t *p_demux = (demux_t *)p_this;
+ demux_meta_t *p_demux_meta = (demux_meta_t*)p_demux->p_private;
+ vlc_meta_t *p_meta = p_demux_meta->p_meta;
- if( strncmp( p_demux->psz_access, "file", 4 ) )
- return VLC_EGENERIC;
+ TAB_INIT( p_demux_meta->i_attachments, p_demux_meta->attachments );
+ p_demux_meta->p_meta = NULL;
TagLib::FileRef f( p_demux->psz_path );
if( f.isNull() )
if ( !f.tag() || f.tag()->isEmpty() )
return VLC_EGENERIC;
- if( !p_demux->p_private )
- p_demux->p_private = (void*)vlc_meta_New();
- vlc_meta_t *p_meta = (vlc_meta_t *)(p_demux->p_private );
+ p_demux_meta->p_meta = p_meta = vlc_meta_New();
TagLib::Tag *p_tag = f.tag();
if( TagLib::MPEG::File *p_mpeg =
(mtime_t) i_ogg_v_length * 1000000 );
vlc_object_release( p_input );
}
-
+
}
#if 0 /* at this moment, taglib is unable to detect ogg/flac files
* becauses type detection is based on file extension:
#undef SET
#undef SETINT
- DetectImage( f, p_meta );
+ DetectImage( f, p_demux );
return VLC_SUCCESS;
}
playlist_t *p_playlist = (playlist_t *)p_this;
meta_export_t *p_export = (meta_export_t *)p_playlist->p_private;
input_item_t *p_item = p_export->p_item;
-
+
if( p_item == NULL )
{
msg_Err( p_this, "Can't save meta data of an empty input" );
WRITE( Copyright, "TCOP" );
WRITE( EncodedBy, "TENC" );
WRITE( Language, "TLAN" );
-
+
#undef WRITE
}