Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
M
mpd
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Иван Мажукин
mpd
Commits
8c743fd3
Commit
8c743fd3
authored
Oct 24, 2010
by
Alexey Morsov
Browse files
Options
Browse Files
Download
Plain Diff
Merge commit 'release-0.15.13' into alt
parents
2835998a
b552e9a1
Hide whitespace changes
Inline
Side-by-side
Showing
31 changed files
with
513 additions
and
216 deletions
+513
-216
Makefile.am
Makefile.am
+1
-0
NEWS
NEWS
+51
-0
configure.ac
configure.ac
+7
-10
cue_tag.c
src/cue/cue_tag.c
+1
-21
ffmpeg_plugin.c
src/decoder/ffmpeg_plugin.c
+103
-75
mad_plugin.c
src/decoder/mad_plugin.c
+35
-20
mikmod_plugin.c
src/decoder/mikmod_plugin.c
+4
-2
mp4ff_plugin.c
src/decoder/mp4ff_plugin.c
+20
-18
mpcdec_plugin.c
src/decoder/mpcdec_plugin.c
+9
-1
vorbis_plugin.c
src/decoder/vorbis_plugin.c
+12
-7
wildmidi_plugin.c
src/decoder/wildmidi_plugin.c
+4
-0
directory_print.c
src/directory_print.c
+2
-6
directory_print.h
src/directory_print.h
+1
-1
icy_server.c
src/icy_server.c
+1
-0
curl_input_plugin.c
src/input/curl_input_plugin.c
+17
-2
mms_input_plugin.c
src/input/mms_input_plugin.c
+3
-0
rewind_input_plugin.c
src/input/rewind_input_plugin.c
+14
-5
listen.c
src/listen.c
+7
-1
locate.c
src/locate.c
+3
-3
notify.c
src/notify.c
+7
-0
notify.h
src/notify.h
+5
-0
httpd_output_plugin.c
src/output/httpd_output_plugin.c
+1
-1
output_thread.c
src/output_thread.c
+10
-0
pcm_buffer.h
src/pcm_buffer.h
+1
-1
player_thread.c
src/player_thread.c
+27
-0
playlist.c
src/playlist.c
+2
-1
playlist_control.c
src/playlist_control.c
+3
-0
tag.c
src/tag.c
+57
-9
tag.h
src/tag.h
+25
-0
tag_ape.c
src/tag_ape.c
+37
-32
tag_table.h
src/tag_table.h
+43
-0
No files found.
Makefile.am
View file @
8c743fd3
...
...
@@ -142,6 +142,7 @@ mpd_headers = \
src/tag.h
\
src/tag_internal.h
\
src/tag_pool.h
\
src/tag_table.h
\
src/tag_ape.h
\
src/tag_id3.h
\
src/tag_print.h
\
...
...
NEWS
View file @
8c743fd3
ver 0.15.13 (2010/10/10)
* output_thread: fix race condition after CANCEL command
* output:
- httpd: fix random data in stream title
- httpd: MIME type audio/ogg for Ogg Vorbis
* input:
- rewind: update MIME not only once
- rewind: enable for MMS
ver 0.15.12 (2010/07/20)
* input:
- curl: remove assertion after curl_multi_fdset()
* tags:
- rva2: set "gain", not "peak"
* decoders:
- wildmidi: support version 0.2.3
ver 0.15.11 (2010/06/14)
* tags:
- ape: support album artist
* decoders:
- mp4ff: support tags "album artist", "albumartist", "band"
- mikmod: fix memory leak
- vorbis: handle uri==NULL
- ffmpeg: fix memory leak
- ffmpeg: free AVFormatContext on error
- ffmpeg: read more metadata
- ffmpeg: fix libavformat 0.6 by using av_open_input_stream()
* playlist: emit IDLE_OPTIONS when resetting single mode
* listen: make get_remote_uid() work on BSD
ver 0.15.10 (2010/05/30)
* input:
- mms: fix memory leak in error handler
- mms: initialize the "eof" attribute
* decoders:
- mad: properly calculate ID3 size without libid3tag
ver 0.15.9 (2010/03/21)
* decoders:
- mad: fix crash when seeking at end of song
- mpcdec: fix negative shift on fixed-point samples
- mpcdec: fix replay gain formula with v8
* playlist: fix single+repeat in random mode
* player: postpone song tags during cross-fade
ver 0.15.8 (2010/01/17)
* input:
- curl: allow rewinding with Icy-Metadata
...
...
configure.ac
View file @
8c743fd3
AC_PREREQ(2.60)
AC_INIT(mpd, 0.15.
8
, musicpd-dev-team@lists.sourceforge.net)
AC_INIT(mpd, 0.15.
13
, musicpd-dev-team@lists.sourceforge.net)
AC_CONFIG_SRCDIR([src/main.c])
AM_INIT_AUTOMAKE([foreign 1.9 dist-bzip2])
AM_CONFIG_HEADER(config.h)
...
...
@@ -177,6 +177,7 @@ AC_ARG_ENABLE(un,
if test x$enable_un = xyes; then
AC_DEFINE(HAVE_UN, 1, [Define if unix domain socket support is enabled])
STRUCT_UCRED
AC_CHECK_FUNCS(getpeereid)
fi
...
...
@@ -913,18 +914,10 @@ fi
AM_CONDITIONAL(HAVE_AUDIOFILE, test x$enable_audiofile = xyes)
MPD_AUTO_PKG(ffmpeg, FFMPEG, [libavformat
libavcodec libavutil
],
MPD_AUTO_PKG(ffmpeg, FFMPEG, [libavformat
>= 52 libavcodec >= 51 libavutil >= 49
],
[ffmpeg decoder library], [libavformat+libavcodec+libavutil not found])
if test x$enable_ffmpeg = xyes; then
old_LIBS=$LIBS
LIBS="$LIBS $FFMPEG_LIBS"
AC_CHECK_LIB(avcodec, avcodec_decode_audio2,,
enable_ffmpeg=no)
LIBS=$old_LIBS
fi
if test x$enable_ffmpeg = xyes; then
# prior to ffmpeg svn12865, you had to specify include files
# without path prefix
old_CPPCFLAGS=$CPPFLAGS
...
...
@@ -957,6 +950,10 @@ if test x$enable_wildmidi = xyes; then
AC_CHECK_LIB(WildMidi, WildMidi_Init,,
AC_MSG_ERROR([libwildmidi not found]))
AC_CHECK_LIB(WildMidi, WildMidi_SampledSeek,
[AC_DEFINE(HAVE_WILDMIDI_SAMPLED_SEEK, 1,
[Defined if WildMidi_SampledSeek() is available (libwildmidi <= 0.2.2)])])
CFLAGS=$oldcflags
LIBS=$oldlibs
CPPFLAGS=$oldcppflags
...
...
src/cue/cue_tag.c
View file @
8c743fd3
...
...
@@ -173,7 +173,6 @@ cue_tag_file( FILE* fp,
{
struct
tag
*
cd_tag
=
NULL
;
struct
tag
*
track_tag
=
NULL
;
struct
tag
*
merge_tag
=
NULL
;
struct
Cd
*
cd
=
NULL
;
if
(
tnum
>
256
)
...
...
@@ -199,26 +198,7 @@ cue_tag_file( FILE* fp,
cd_delete
(
cd
);
}
if
((
cd_tag
!=
NULL
)
&&
(
track_tag
!=
NULL
))
{
merge_tag
=
tag_merge
(
cd_tag
,
track_tag
);
tag_free
(
cd_tag
);
tag_free
(
track_tag
);
return
merge_tag
;
}
else
if
(
cd_tag
!=
NULL
)
{
return
cd_tag
;
}
else
if
(
track_tag
!=
NULL
)
{
return
track_tag
;
}
else
return
NULL
;
return
tag_merge_replace
(
cd_tag
,
track_tag
);
}
struct
tag
*
...
...
src/decoder/ffmpeg_plugin.c
View file @
8c743fd3
...
...
@@ -53,48 +53,27 @@ struct ffmpeg_context {
struct
tag
*
tag
;
};
struct
ffmpeg_stream
{
/** hack - see url_to_struct() */
char
url
[
64
];
struct
mpd_ffmpeg_stream
{
struct
decoder
*
decoder
;
struct
input_stream
*
input
;
};
/**
* Convert a faked mpd:// URL to a ffmpeg_stream structure. This is a
* hack because ffmpeg does not provide a nice API for passing a
* user-defined pointer to mpdurl_open().
*/
static
struct
ffmpeg_stream
*
url_to_struct
(
const
char
*
url
)
{
union
{
const
char
*
in
;
struct
ffmpeg_stream
*
out
;
}
u
=
{
.
in
=
url
};
return
u
.
out
;
}
static
int
mpd_ffmpeg_open
(
URLContext
*
h
,
const
char
*
filename
,
G_GNUC_UNUSED
int
flags
)
{
struct
ffmpeg_stream
*
stream
=
url_to_struct
(
filename
);
h
->
priv_data
=
stream
;
h
->
is_streamed
=
stream
->
input
->
seekable
?
0
:
1
;
return
0
;
}
ByteIOContext
*
io
;
unsigned
char
buffer
[
8192
];
};
static
int
mpd_ffmpeg_read
(
URLContext
*
h
,
unsigned
char
*
buf
,
int
size
)
static
int
mpd_ffmpeg_stream_read
(
void
*
opaque
,
uint8_t
*
buf
,
int
size
)
{
struct
ffmpeg_stream
*
stream
=
(
struct
ffmpeg_stream
*
)
h
->
priv_data
;
struct
mpd_ffmpeg_stream
*
stream
=
opaque
;
return
decoder_read
(
stream
->
decoder
,
stream
->
input
,
(
void
*
)
buf
,
size
);
}
static
int64_t
mpd_ffmpeg_seek
(
URLContext
*
h
,
int64_t
pos
,
int
whence
)
static
int64_t
mpd_ffmpeg_stream_seek
(
void
*
opaque
,
int64_t
pos
,
int
whence
)
{
struct
ffmpeg_stream
*
stream
=
(
struct
ffmpeg_stream
*
)
h
->
priv_data
;
struct
mpd_ffmpeg_stream
*
stream
=
opaque
;
bool
ret
;
if
(
whence
==
AVSEEK_SIZE
)
...
...
@@ -107,25 +86,36 @@ static int64_t mpd_ffmpeg_seek(URLContext *h, int64_t pos, int whence)
return
stream
->
input
->
offset
;
}
static
int
mpd_ffmpeg_close
(
URLContext
*
h
)
static
struct
mpd_ffmpeg_stream
*
mpd_ffmpeg_stream_open
(
struct
decoder
*
decoder
,
struct
input_stream
*
input
)
{
h
->
priv_data
=
NULL
;
return
0
;
struct
mpd_ffmpeg_stream
*
stream
=
g_new
(
struct
mpd_ffmpeg_stream
,
1
);
stream
->
decoder
=
decoder
;
stream
->
input
=
input
;
stream
->
io
=
av_alloc_put_byte
(
stream
->
buffer
,
sizeof
(
stream
->
buffer
),
false
,
stream
,
mpd_ffmpeg_stream_read
,
NULL
,
input
->
seekable
?
mpd_ffmpeg_stream_seek
:
NULL
);
if
(
stream
->
io
==
NULL
)
{
g_free
(
stream
);
return
NULL
;
}
return
stream
;
}
static
URLProtocol
mpd_ffmpeg_fileops
=
{
.
name
=
"mpd"
,
.
url_open
=
mpd_ffmpeg_open
,
.
url_read
=
mpd_ffmpeg_read
,
.
url_seek
=
mpd_ffmpeg_seek
,
.
url_close
=
mpd_ffmpeg_close
,
};
static
void
mpd_ffmpeg_stream_close
(
struct
mpd_ffmpeg_stream
*
stream
)
{
av_free
(
stream
->
io
);
g_free
(
stream
);
}
static
bool
ffmpeg_init
(
G_GNUC_UNUSED
const
struct
config_param
*
param
)
{
av_register_all
();
register_protocol
(
&
mpd_ffmpeg_fileops
);
return
true
;
}
...
...
@@ -140,64 +130,86 @@ ffmpeg_find_audio_stream(const AVFormatContext *format_context)
return
-
1
;
}
/**
* Append the suffix of the original URI to the virtual stream URI.
* Without this, libavformat cannot detect some of the codecs
* (e.g. "shorten").
*/
static
void
append_uri_suffix
(
struct
ffmpeg_stream
*
stream
,
const
char
*
uri
)
static
AVInputFormat
*
ffmpeg_probe
(
struct
decoder
*
decoder
,
struct
input_stream
*
is
,
const
char
*
uri
)
{
assert
(
stream
!=
NULL
);
assert
(
uri
!=
NULL
);
enum
{
BUFFER_SIZE
=
16384
,
PADDING
=
16
,
};
unsigned
char
*
buffer
=
g_malloc
(
BUFFER_SIZE
);
size_t
nbytes
=
decoder_read
(
decoder
,
is
,
buffer
,
BUFFER_SIZE
);
if
(
nbytes
<=
PADDING
||
!
input_stream_seek
(
is
,
0
,
SEEK_SET
))
{
g_free
(
buffer
);
return
NULL
;
}
/* some ffmpeg parsers (e.g. ac3_parser.c) read a few bytes
beyond the declared buffer limit, which makes valgrind
angry; this workaround removes some padding from the buffer
size */
nbytes
-=
PADDING
;
char
*
base
=
g_path_get_basename
(
uri
);
AVProbeData
avpd
=
{
.
buf
=
buffer
,
.
buf_size
=
nbytes
,
.
filename
=
uri
,
};
const
char
*
suffix
=
strrchr
(
base
,
'.'
);
if
(
suffix
!=
NULL
&&
suffix
[
1
]
!=
0
)
g_strlcat
(
stream
->
url
,
suffix
,
sizeof
(
stream
->
url
));
AVInputFormat
*
format
=
av_probe_input_format
(
&
avpd
,
true
);
g_free
(
buffer
);
g_free
(
base
)
;
return
format
;
}
static
bool
ffmpeg_helper
(
const
char
*
uri
,
struct
input_stream
*
input
,
ffmpeg_helper
(
const
char
*
uri
,
struct
decoder
*
decoder
,
struct
input_stream
*
input
,
bool
(
*
callback
)(
struct
ffmpeg_context
*
ctx
),
struct
ffmpeg_context
*
ctx
)
{
AVInputFormat
*
input_format
=
ffmpeg_probe
(
decoder
,
input
,
uri
);
if
(
input_format
==
NULL
)
return
false
;
g_debug
(
"detected input format '%s' (%s)"
,
input_format
->
name
,
input_format
->
long_name
);
struct
mpd_ffmpeg_stream
*
stream
=
mpd_ffmpeg_stream_open
(
decoder
,
input
);
if
(
stream
==
NULL
)
{
g_warning
(
"Failed to open stream"
);
return
false
;
}
AVFormatContext
*
format_context
;
AVCodecContext
*
codec_context
;
AVCodec
*
codec
;
int
audio_stream
;
struct
ffmpeg_stream
stream
=
{
.
url
=
"mpd://X"
,
/* only the mpd:// prefix matters */
};
bool
ret
;
if
(
uri
!=
NULL
)
append_uri_suffix
(
&
stream
,
uri
);
stream
.
input
=
input
;
if
(
ctx
&&
ctx
->
decoder
)
{
stream
.
decoder
=
ctx
->
decoder
;
//are we in decoding loop ?
}
else
{
stream
.
decoder
=
NULL
;
}
//ffmpeg works with ours "fileops" helper
if
(
av_open_input_file
(
&
format_context
,
stream
.
url
,
NULL
,
0
,
NULL
)
!=
0
)
{
if
(
av_open_input_stream
(
&
format_context
,
stream
->
io
,
uri
,
input_format
,
NULL
)
!=
0
)
{
g_warning
(
"Open failed
\n
"
);
mpd_ffmpeg_stream_close
(
stream
);
return
false
;
}
if
(
av_find_stream_info
(
format_context
)
<
0
)
{
g_warning
(
"Couldn't find stream info
\n
"
);
av_close_input_stream
(
format_context
);
mpd_ffmpeg_stream_close
(
stream
);
return
false
;
}
audio_stream
=
ffmpeg_find_audio_stream
(
format_context
);
if
(
audio_stream
==
-
1
)
{
g_warning
(
"No audio stream inside
\n
"
);
av_close_input_stream
(
format_context
);
mpd_ffmpeg_stream_close
(
stream
);
return
false
;
}
...
...
@@ -209,11 +221,15 @@ ffmpeg_helper(const char *uri, struct input_stream *input,
if
(
!
codec
)
{
g_warning
(
"Unsupported audio codec
\n
"
);
av_close_input_stream
(
format_context
);
mpd_ffmpeg_stream_close
(
stream
);
return
false
;
}
if
(
avcodec_open
(
codec_context
,
codec
)
<
0
)
{
g_warning
(
"Could not open codec
\n
"
);
av_close_input_stream
(
format_context
);
mpd_ffmpeg_stream_close
(
stream
);
return
false
;
}
...
...
@@ -227,7 +243,8 @@ ffmpeg_helper(const char *uri, struct input_stream *input,
ret
=
true
;
avcodec_close
(
codec_context
);
av_close_input_file
(
format_context
);
av_close_input_stream
(
format_context
);
mpd_ffmpeg_stream_close
(
stream
);
return
ret
;
}
...
...
@@ -372,8 +389,10 @@ ffmpeg_decode(struct decoder *decoder, struct input_stream *input)
ctx
.
input
=
input
;
ctx
.
decoder
=
decoder
;
ffmpeg_helper
(
decoder_get_uri
(
decoder
),
input
,
char
*
uri
=
decoder_get_uri
(
decoder
);
ffmpeg_helper
(
uri
,
decoder
,
input
,
ffmpeg_decode_internal
,
&
ctx
);
g_free
(
uri
);
}
#if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(31<<8)+0)
...
...
@@ -401,12 +420,21 @@ static bool ffmpeg_tag_internal(struct ffmpeg_context *ctx)
av_metadata_conv
(
f
,
NULL
,
f
->
iformat
->
metadata_conv
);
ffmpeg_copy_metadata
(
tag
,
f
->
metadata
,
TAG_ITEM_TITLE
,
"title"
);
#if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(50<<8))
ffmpeg_copy_metadata
(
tag
,
f
->
metadata
,
TAG_ITEM_ARTIST
,
"artist"
);
ffmpeg_copy_metadata
(
tag
,
f
->
metadata
,
TAG_ITEM_DATE
,
"date"
);
#else
ffmpeg_copy_metadata
(
tag
,
f
->
metadata
,
TAG_ITEM_ARTIST
,
"author"
);
ffmpeg_copy_metadata
(
tag
,
f
->
metadata
,
TAG_ITEM_DATE
,
"year"
);
#endif
ffmpeg_copy_metadata
(
tag
,
f
->
metadata
,
TAG_ITEM_ALBUM
,
"album"
);
ffmpeg_copy_metadata
(
tag
,
f
->
metadata
,
TAG_ITEM_COMMENT
,
"comment"
);
ffmpeg_copy_metadata
(
tag
,
f
->
metadata
,
TAG_ITEM_GENRE
,
"genre"
);
ffmpeg_copy_metadata
(
tag
,
f
->
metadata
,
TAG_ITEM_TRACK
,
"track"
);
ffmpeg_copy_metadata
(
tag
,
f
->
metadata
,
TAG_ITEM_DATE
,
"year"
);
ffmpeg_copy_metadata
(
tag
,
f
->
metadata
,
TAG_ITEM_ALBUM_ARTIST
,
"album_artist"
);
ffmpeg_copy_metadata
(
tag
,
f
->
metadata
,
TAG_ITEM_COMPOSER
,
"composer"
);
ffmpeg_copy_metadata
(
tag
,
f
->
metadata
,
TAG_ITEM_PERFORMER
,
"performer"
);
ffmpeg_copy_metadata
(
tag
,
f
->
metadata
,
TAG_ITEM_DISC
,
"disc"
);
#else
if
(
f
->
author
[
0
])
tag_add_item
(
tag
,
TAG_ITEM_ARTIST
,
f
->
author
);
...
...
@@ -450,7 +478,7 @@ static struct tag *ffmpeg_tag(const char *file)
ctx
.
decoder
=
NULL
;
ctx
.
tag
=
tag_new
();
ret
=
ffmpeg_helper
(
file
,
&
input
,
ffmpeg_tag_internal
,
&
ctx
);
ret
=
ffmpeg_helper
(
file
,
NULL
,
&
input
,
ffmpeg_tag_internal
,
&
ctx
);
if
(
!
ret
)
{
tag_free
(
ctx
.
tag
);
ctx
.
tag
=
NULL
;
...
...
src/decoder/mad_plugin.c
View file @
8c743fd3
...
...
@@ -209,14 +209,14 @@ mp3_fill_buffer(struct mp3_data *data)
#ifdef HAVE_ID3TAG
/* Parse mp3 RVA2 frame. Shamelessly stolen from madplay. */
static
int
parse_rva2
(
struct
id3_tag
*
tag
,
struct
replay_gain_info
*
replay_gain_info
)
static
bool
parse_rva2
(
struct
id3_tag
*
tag
,
struct
replay_gain_info
*
replay_gain_info
)
{
struct
id3_frame
const
*
frame
;
id3_latin1_t
const
*
id
;
id3_byte_t
const
*
data
;
id3_length_t
length
;
int
found
;
enum
{
CHANNEL_OTHER
=
0x00
,
...
...
@@ -230,18 +230,18 @@ static int parse_rva2(struct id3_tag * tag, struct replay_gain_info * replay_gai
CHANNEL_SUBWOOFER
=
0x08
};
found
=
0
;
/* relative volume adjustment information */
frame
=
id3_tag_findframe
(
tag
,
"RVA2"
,
0
);
if
(
!
frame
)
return
0
;
if
(
frame
==
NULL
)
return
false
;
id
=
id3_field_getlatin1
(
id3_frame_field
(
frame
,
0
));
data
=
id3_field_getbinarydata
(
id3_frame_field
(
frame
,
1
),
&
length
);
if
(
!
id
||
!
data
)
return
0
;
if
(
id
==
NULL
||
data
==
NULL
)
return
false
;
/*
* "The 'identification' string is used to identify the
...
...
@@ -277,22 +277,21 @@ static int parse_rva2(struct id3_tag * tag, struct replay_gain_info * replay_gai
voladj_float
=
(
double
)
voladj_fixed
/
512
;
replay_gain_info
->
tuples
[
REPLAY_GAIN_TRACK
].
peak
=
voladj_float
;
replay_gain_info
->
tuples
[
REPLAY_GAIN_ALBUM
].
peak
=
voladj_float
;
replay_gain_info
->
tuples
[
REPLAY_GAIN_TRACK
].
gain
=
voladj_float
;
replay_gain_info
->
tuples
[
REPLAY_GAIN_ALBUM
].
gain
=
voladj_float
;
g_debug
(
"parseRVA2: Relative Volume "
"%+.1f dB adjustment (%s)
\n
"
,
voladj_float
,
id
);
found
=
1
;
break
;
return
true
;
}
data
+=
4
+
peak_bytes
;
length
-=
4
+
peak_bytes
;
}
return
f
ound
;
return
f
alse
;
}
#endif
...
...
@@ -425,7 +424,27 @@ static void mp3_parse_id3(struct mp3_data *data, size_t tagsize,
/* This code is enabled when libid3tag is disabled. Instead
of parsing the ID3 frame, it just skips it. */
mad_stream_skip
(
&
data
->
stream
,
tagsize
);
size_t
count
=
data
->
stream
.
bufend
-
data
->
stream
.
this_frame
;
if
(
tagsize
<=
count
)
{
mad_stream_skip
(
&
data
->
stream
,
tagsize
);
}
else
{
mad_stream_skip
(
&
data
->
stream
,
count
);
while
(
count
<
tagsize
)
{
size_t
len
=
tagsize
-
count
;
char
ignored
[
1024
];
if
(
len
>
sizeof
(
ignored
))
len
=
sizeof
(
ignored
);
len
=
decoder_read
(
data
->
decoder
,
data
->
input_stream
,
ignored
,
len
);
if
(
len
==
0
)
break
;
else
count
+=
len
;
}
}
#endif
}
...
...
@@ -433,16 +452,16 @@ static void mp3_parse_id3(struct mp3_data *data, size_t tagsize,
/**
* This function emulates libid3tag when it is disabled. Instead of
* doing a real analyzation of the frame, it just checks whether the
* frame begins with the string "ID3". If so, it returns the
full
*
length
.
* frame begins with the string "ID3". If so, it returns the
length
*
of the ID3 frame
.
*/
static
signed
long
id3_tag_query
(
const
void
*
p0
,
size_t
length
)
{
const
char
*
p
=
p0
;
return
length
>
3
&&
memcmp
(
p
,
"ID3"
,
3
)
==
0
?
length
return
length
>
=
10
&&
memcmp
(
p
,
"ID3"
,
3
)
==
0
?
(
p
[
8
]
<<
7
)
+
p
[
9
]
+
10
:
0
;
}
#endif
/* !HAVE_ID3TAG */
...
...
@@ -1207,10 +1226,6 @@ mp3_decode(struct decoder *decoder, struct input_stream *input_stream)
if
(
replay_gain_info
)
replay_gain_info_free
(
replay_gain_info
);
if
(
decoder_get_command
(
decoder
)
==
DECODE_COMMAND_SEEK
&&
data
.
mute_frame
==
MUTEFRAME_SEEK
)
decoder_command_finished
(
decoder
);
mp3_data_finish
(
&
data
);
}
...
...
src/decoder/mikmod_plugin.c
View file @
8c743fd3
...
...
@@ -219,10 +219,12 @@ static struct tag *modTagDup(const char *file)
ret
->
time
=
0
;
path2
=
g_strdup
(
file
);
title
=
g_strdup
(
Player_LoadTitle
(
path2
)
);
title
=
Player_LoadTitle
(
path2
);
g_free
(
path2
);
if
(
title
)
if
(
title
)
{
tag_add_item
(
ret
,
TAG_ITEM_TITLE
,
title
);
free
(
title
);
}
return
ret
;
}
...
...
src/decoder/mp4ff_plugin.c
View file @
8c743fd3
...
...
@@ -19,6 +19,7 @@
#include "../decoder_api.h"
#include "config.h"
#include "tag_table.h"
#include <glib.h>
...
...
@@ -339,6 +340,22 @@ mp4_decode(struct decoder *mpd_decoder, struct input_stream *input_stream)
mp4ff_close
(
mp4fh
);
}
static
const
char
*
const
mp4ff_tag_names
[
TAG_NUM_OF_ITEM_TYPES
]
=
{
[
TAG_ITEM_ALBUM_ARTIST
]
=
"album artist"
,
[
TAG_ITEM_COMPOSER
]
=
"writer"
,
[
TAG_ITEM_PERFORMER
]
=
"band"
,
};
static
enum
tag_type
mp4ff_tag_name_parse
(
const
char
*
name
)
{
enum
tag_type
type
=
tag_table_lookup
(
mp4ff_tag_names
,
name
);
if
(
type
==
TAG_NUM_OF_ITEM_TYPES
)
type
=
tag_name_parse_i
(
name
);
return
type
;
}
static
struct
tag
*
mp4_tag_dup
(
const
char
*
file
)
{
...
...
@@ -394,24 +411,9 @@ mp4_tag_dup(const char *file)
mp4ff_meta_get_by_index
(
mp4fh
,
i
,
&
item
,
&
value
);
if
(
0
==
g_ascii_strcasecmp
(
"artist"
,
item
))
{
tag_add_item
(
ret
,
TAG_ITEM_ARTIST
,
value
);
}
else
if
(
0
==
g_ascii_strcasecmp
(
"title"
,
item
))
{
tag_add_item
(
ret
,
TAG_ITEM_TITLE
,
value
);
}
else
if
(
0
==
g_ascii_strcasecmp
(
"album"
,
item
))
{
tag_add_item
(
ret
,
TAG_ITEM_ALBUM
,
value
);
}
else
if
(
0
==
g_ascii_strcasecmp
(
"track"
,
item
))
{
tag_add_item
(
ret
,
TAG_ITEM_TRACK
,
value
);
}
else
if
(
0
==
g_ascii_strcasecmp
(
"disc"
,
item
))
{
/* Is that the correct id? */
tag_add_item
(
ret
,
TAG_ITEM_DISC
,
value
);
}
else
if
(
0
==
g_ascii_strcasecmp
(
"genre"
,
item
))
{
tag_add_item
(
ret
,
TAG_ITEM_GENRE
,
value
);
}
else
if
(
0
==
g_ascii_strcasecmp
(
"date"
,
item
))
{
tag_add_item
(
ret
,
TAG_ITEM_DATE
,
value
);
}
else
if
(
0
==
g_ascii_strcasecmp
(
"writer"
,
item
))
{
tag_add_item
(
ret
,
TAG_ITEM_COMPOSER
,
value
);
}
enum
tag_type
type
=
mp4ff_tag_name_parse
(
item
);
if
(
type
!=
TAG_NUM_OF_ITEM_TYPES
)
tag_add_item
(
ret
,
type
,
value
);
free
(
item
);
free
(
value
);
...
...
src/decoder/mpcdec_plugin.c
View file @
8c743fd3
...
...
@@ -24,6 +24,7 @@
#include <mpcdec/mpcdec.h>
#else
#include <mpc/mpcdec.h>
#include <math.h>
#endif
#include <glib.h>
...
...
@@ -103,7 +104,7 @@ mpc_to_mpd_sample(MPC_SAMPLE_FORMAT sample)
const
int
shift
=
bits
-
MPC_FIXED_POINT_SCALE_SHIFT
;
if
(
shift
<
0
)
val
=
sample
<<
-
shift
;
val
=
sample
>>
-
shift
;
else
val
=
sample
<<
shift
;
#else
...
...
@@ -209,10 +210,17 @@ mpcdec_decode(struct decoder *mpd_decoder, struct input_stream *is)
}
replay_gain_info
=
replay_gain_info_new
();
#ifdef MPC_IS_OLD_API
replay_gain_info
->
tuples
[
REPLAY_GAIN_ALBUM
].
gain
=
info
.
gain_album
*
0
.
01
;
replay_gain_info
->
tuples
[
REPLAY_GAIN_ALBUM
].
peak
=
info
.
peak_album
/
32767
.
0
;
replay_gain_info
->
tuples
[
REPLAY_GAIN_TRACK
].
gain
=
info
.
gain_title
*
0
.
01
;
replay_gain_info
->
tuples
[
REPLAY_GAIN_TRACK
].
peak
=
info
.
peak_title
/
32767
.
0
;
#else
replay_gain_info
->
tuples
[
REPLAY_GAIN_ALBUM
].
gain
=
MPC_OLD_GAIN_REF
-
(
info
.
gain_album
/
256
.);
replay_gain_info
->
tuples
[
REPLAY_GAIN_ALBUM
].
peak
=
pow
(
10
,
info
.
peak_album
/
256
.
/
20
)
/
32767
;
replay_gain_info
->
tuples
[
REPLAY_GAIN_TRACK
].
gain
=
MPC_OLD_GAIN_REF
-
(
info
.
gain_title
/
256
.);
replay_gain_info
->
tuples
[
REPLAY_GAIN_TRACK
].
peak
=
pow
(
10
,
info
.
peak_title
/
256
.
/
20
)
/
32767
;
#endif
decoder_initialized
(
mpd_decoder
,
&
audio_format
,
is
->
seekable
,
...
...
src/decoder/vorbis_plugin.c
View file @
8c743fd3
...
...
@@ -97,6 +97,13 @@ static long ogg_tell_cb(void *vdata)
return
(
long
)
data
->
input_stream
->
offset
;
}
static
const
ov_callbacks
vorbis_is_callbacks
=
{
.
read_func
=
ogg_read_cb
,
.
seek_func
=
ogg_seek_cb
,
.
close_func
=
ogg_close_cb
,
.
tell_func
=
ogg_tell_cb
,
};
static
const
char
*
vorbis_comment_value
(
const
char
*
comment
,
const
char
*
needle
)
{
...
...
@@ -226,6 +233,9 @@ oggvorbis_seekable(struct decoder *decoder)
bool
seekable
;
uri
=
decoder_get_uri
(
decoder
);
if
(
uri
==
NULL
)
return
false
;
/* disable seeking on remote streams, because libvorbis seeks
around like crazy, and due to being very expensive, this
delays song playback my 10 or 20 seconds */
...
...
@@ -241,7 +251,6 @@ vorbis_stream_decode(struct decoder *decoder,
struct
input_stream
*
input_stream
)
{
OggVorbis_File
vf
;
ov_callbacks
callbacks
;
OggCallbackData
data
;
struct
audio_format
audio_format
;
int
current_section
;
...
...
@@ -266,13 +275,9 @@ vorbis_stream_decode(struct decoder *decoder,
data
.
input_stream
=
input_stream
;
data
.
seekable
=
input_stream
->
seekable
&&
oggvorbis_seekable
(
decoder
);
callbacks
.
read_func
=
ogg_read_cb
;
callbacks
.
seek_func
=
ogg_seek_cb
;
callbacks
.
close_func
=
ogg_close_cb
;
callbacks
.
tell_func
=
ogg_tell_cb
;
if
((
ret
=
ov_open_callbacks
(
&
data
,
&
vf
,
NULL
,
0
,
callbacks
))
<
0
)
{
if
((
ret
=
ov_open_callbacks
(
&
data
,
&
vf
,
NULL
,
0
,
vorbis_is_callbacks
))
<
0
)
{
const
char
*
error
;
if
(
decoder_get_command
(
decoder
)
!=
DECODE_COMMAND_NONE
)
return
;
...
...
src/decoder/wildmidi_plugin.c
View file @
8c743fd3
...
...
@@ -99,7 +99,11 @@ wildmidi_file_decode(struct decoder *decoder, const char *path_fs)
unsigned
long
seek_where
=
WILDMIDI_SAMPLE_RATE
*
decoder_seek_where
(
decoder
);
#ifdef HAVE_WILDMIDI_SAMPLED_SEEK
WildMidi_SampledSeek
(
wm
,
&
seek_where
);
#else
WildMidi_FastSeek
(
wm
,
&
seek_where
);
#endif
decoder_command_finished
(
decoder
);
cmd
=
DECODE_COMMAND_NONE
;
}
...
...
src/directory_print.c
View file @
8c743fd3
...
...
@@ -22,7 +22,7 @@
#include "client.h"
#include "song_print.h"
static
int
static
void
dirvec_print
(
struct
client
*
client
,
const
struct
dirvec
*
dv
)
{
size_t
i
;
...
...
@@ -30,15 +30,11 @@ dirvec_print(struct client *client, const struct dirvec *dv)
for
(
i
=
0
;
i
<
dv
->
nr
;
++
i
)
client_printf
(
client
,
DIRECTORY_DIR
"%s
\n
"
,
directory_get_path
(
dv
->
base
[
i
]));
return
0
;
}
int
void
directory_print
(
struct
client
*
client
,
const
struct
directory
*
directory
)
{
dirvec_print
(
client
,
&
directory
->
children
);
songvec_print
(
client
,
&
directory
->
songs
);
return
0
;
}
src/directory_print.h
View file @
8c743fd3
...
...
@@ -23,7 +23,7 @@
struct
client
;
struct
directory
;
int
void
directory_print
(
struct
client
*
client
,
const
struct
directory
*
directory
);
#endif
src/icy_server.c
View file @
8c743fd3
...
...
@@ -95,6 +95,7 @@ icy_server_metadata_page(const struct tag *tag, ...)
gchar
stream_title
[(
1
+
255
-
28
)
*
16
];
// Length + Metadata -
// "StreamTitle='';StreamUrl='';"
// = 4081 - 28
stream_title
[
0
]
=
'\0'
;
last_item
=
-
1
;
...
...
src/input/curl_input_plugin.c
View file @
8c743fd3
...
...
@@ -241,7 +241,6 @@ input_curl_select(struct input_curl *c)
fd_set
rfds
,
wfds
,
efds
;
int
max_fd
,
ret
;
CURLMcode
mcode
;
/* XXX hard coded timeout value.. */
struct
timeval
timeout
=
{
.
tv_sec
=
1
,
.
tv_usec
=
0
,
...
...
@@ -260,7 +259,23 @@ input_curl_select(struct input_curl *c)
return
-
1
;
}
assert
(
max_fd
>=
0
);
#if LIBCURL_VERSION_NUM >= 0x070f04
long
timeout2
;
mcode
=
curl_multi_timeout
(
c
->
multi
,
&
timeout2
);
if
(
mcode
!=
CURLM_OK
)
{
g_warning
(
"curl_multi_timeout() failed: %s
\n
"
,
curl_multi_strerror
(
mcode
));
return
-
1
;
}
if
(
timeout2
>=
0
)
{
if
(
timeout2
>
10000
)
timeout2
=
10000
;
timeout
.
tv_sec
=
timeout2
/
1000
;
timeout
.
tv_usec
=
(
timeout2
%
1000
)
*
1000
;
}
#endif
ret
=
select
(
max_fd
+
1
,
&
rfds
,
&
wfds
,
&
efds
,
&
timeout
);
if
(
ret
<
0
)
...
...
src/input/mms_input_plugin.c
View file @
8c743fd3
...
...
@@ -49,10 +49,13 @@ input_mms_open(struct input_stream *is, const char *url)
m
=
g_new
(
struct
input_mms
,
1
);
m
->
mms
=
mmsx_connect
(
NULL
,
NULL
,
url
,
128
*
1024
);
if
(
m
->
mms
==
NULL
)
{
g_free
(
m
);
g_warning
(
"mmsx_connect() failed"
);
return
false
;
}
m
->
eof
=
false
;
/* XX is this correct? at least this selects the ffmpeg
decoder, which seems to work fine*/
is
->
mime
=
g_strdup
(
"audio/x-ms-wma"
);
...
...
src/input/rewind_input_plugin.c
View file @
8c743fd3
...
...
@@ -20,6 +20,9 @@
#include "config.h"
#include "input/rewind_input_plugin.h"
#include "input/curl_input_plugin.h"
#ifdef ENABLE_MMS
#include "input/mms_input_plugin.h"
#endif
#include "input_plugin.h"
#include "tag.h"
...
...
@@ -86,10 +89,11 @@ copy_attributes(struct input_stream *dest)
dest
->
size
=
src
->
size
;
dest
->
offset
=
src
->
offset
;
if
(
dest
->
mime
==
NULL
&&
src
->
mime
!=
NULL
)
/* this is set only once, and the duplicated pointer
is freed by input_stream_close() */
if
(
src
->
mime
!=
NULL
)
{
if
(
dest
->
mime
!=
NULL
)
g_free
(
dest
->
mime
);
dest
->
mime
=
g_strdup
(
src
->
mime
);
}
}
static
void
...
...
@@ -219,7 +223,11 @@ input_rewind_open(struct input_stream *is)
assert
(
is
!=
NULL
);
assert
(
is
->
offset
==
0
);
if
(
is
->
plugin
!=
&
input_plugin_curl
)
if
(
is
->
plugin
!=
&
input_plugin_curl
#ifdef ENABLE_MMS
&&
is
->
plugin
!=
&
input_plugin_mms
#endif
)
/* due to limitations in the input_plugin API, we only
(explicitly) support the CURL input plugin */
return
;
...
...
@@ -229,7 +237,8 @@ input_rewind_open(struct input_stream *is)
/* move the CURL input stream to c->input */
c
->
input
=
*
is
;
input_curl_reinit
(
&
c
->
input
);
if
(
is
->
plugin
==
&
input_plugin_curl
)
input_curl_reinit
(
&
c
->
input
);
/* convert the existing input_stream pointer to a "rewind"
input stream */
...
...
src/listen.c
View file @
8c743fd3
...
...
@@ -407,7 +407,13 @@ static int get_remote_uid(int fd)
return
cred
.
uid
;
#else
(
void
)
fd
;
#ifdef HAVE_GETPEEREID
uid_t
euid
;
gid_t
egid
;
if
(
getpeereid
(
fd
,
&
euid
,
&
egid
)
==
0
)
return
euid
;
#endif
return
-
1
;
#endif
}
...
...
src/locate.c
View file @
8c743fd3
...
...
@@ -42,9 +42,9 @@ locate_parse_type(const char *str)
if
(
0
==
g_ascii_strcasecmp
(
str
,
LOCATE_TAG_ANY_KEY
))
return
LOCATE_TAG_ANY_TYPE
;
for
(
i
=
0
;
i
<
TAG_NUM_OF_ITEM_TYPES
;
i
++
)
if
(
0
==
g_ascii_strcasecmp
(
str
,
tag_item_names
[
i
])
)
return
i
;
i
=
tag_name_parse_i
(
str
);
if
(
i
!=
TAG_NUM_OF_ITEM_TYPES
)
return
i
;
return
-
1
;
}
...
...
src/notify.c
View file @
8c743fd3
...
...
@@ -48,3 +48,10 @@ void notify_signal(struct notify *notify)
g_cond_signal
(
notify
->
cond
);
g_mutex_unlock
(
notify
->
mutex
);
}
void
notify_clear
(
struct
notify
*
notify
)
{
g_mutex_lock
(
notify
->
mutex
);
notify
->
pending
=
false
;
g_mutex_unlock
(
notify
->
mutex
);
}
src/notify.h
View file @
8c743fd3
...
...
@@ -45,4 +45,9 @@ void notify_wait(struct notify *notify);
*/
void
notify_signal
(
struct
notify
*
notify
);
/**
* Clears a pending notification.
*/
void
notify_clear
(
struct
notify
*
notify
);
#endif
src/output/httpd_output_plugin.c
View file @
8c743fd3
...
...
@@ -70,7 +70,7 @@ httpd_output_init(G_GNUC_UNUSED const struct audio_format *audio_format,
}
if
(
strcmp
(
encoder_name
,
"vorbis"
)
==
0
)
httpd
->
content_type
=
"a
pplication/x-
ogg"
;
httpd
->
content_type
=
"a
udio/
ogg"
;
else
if
(
strcmp
(
encoder_name
,
"lame"
)
==
0
)
httpd
->
content_type
=
"audio/mpeg"
;
else
...
...
src/output_thread.c
View file @
8c743fd3
...
...
@@ -268,6 +268,16 @@ static gpointer audio_output_task(gpointer arg)
ao
->
chunk
=
NULL
;
if
(
ao
->
open
)
ao_plugin_cancel
(
ao
->
plugin
,
ao
->
data
);
/* we must clear the notification now, because
the notify_wait() call below must wait
until audio_output_all_cancel() has cleared
the pipe; if another notification happens
to be still pending, we get a race
condition with a crash or an assertion
failure */
notify_clear
(
&
ao
->
notify
);
ao_command_finished
(
ao
);
/* the player thread will now clear our music
...
...
src/pcm_buffer.h
View file @
8c743fd3
...
...
@@ -28,7 +28,7 @@
* would put too much stress on the allocator.
*/
struct
pcm_buffer
{
char
*
buffer
;
void
*
buffer
;
size_t
size
;
};
...
...
src/player_thread.c
View file @
8c743fd3
...
...
@@ -90,6 +90,13 @@ struct player {
unsigned
cross_fade_chunks
;
/**
* The tag of the "next" song during cross-fade. It is
* postponed, and sent to the output thread when the new song
* really begins.
*/
struct
tag
*
cross_fade_tag
;
/**
* The current audio format for the audio outputs.
*/
struct
audio_format
play_audio_format
;
...
...
@@ -518,6 +525,14 @@ play_next_chunk(struct player *player)
chunk
=
music_pipe_shift
(
player
->
pipe
);
assert
(
chunk
!=
NULL
);
/* don't send the tags of the new song (which
is being faded in) yet; postpone it until
the current song is faded out */
player
->
cross_fade_tag
=
tag_merge_replace
(
player
->
cross_fade_tag
,
other_chunk
->
tag
);
other_chunk
->
tag
=
NULL
;
cross_fade_apply
(
chunk
,
other_chunk
,
&
dc
.
out_audio_format
,
cross_fade_position
,
...
...
@@ -544,6 +559,14 @@ play_next_chunk(struct player *player)
assert
(
chunk
!=
NULL
);
/* insert the postponed tag if cross-fading is finished */
if
(
player
->
xfade
!=
XFADE_ENABLED
&&
player
->
cross_fade_tag
!=
NULL
)
{
chunk
->
tag
=
tag_merge_replace
(
chunk
->
tag
,
player
->
cross_fade_tag
);
player
->
cross_fade_tag
=
NULL
;
}
/* play the current chunk */
success
=
play_chunk
(
player
->
song
,
chunk
,
&
player
->
play_audio_format
,
...
...
@@ -608,6 +631,7 @@ static void do_play(void)
.
xfade
=
XFADE_UNKNOWN
,
.
cross_fading
=
false
,
.
cross_fade_chunks
=
0
,
.
cross_fade_tag
=
NULL
,
.
size_to_time
=
0
.
0
,
};
...
...
@@ -754,6 +778,9 @@ static void do_play(void)
music_pipe_clear
(
player
.
pipe
,
player_buffer
);
music_pipe_free
(
player
.
pipe
);
if
(
player
.
cross_fade_tag
!=
NULL
)
tag_free
(
player
.
cross_fade_tag
);
pc
.
state
=
PLAYER_STATE_STOP
;
event_pipe_emit
(
PIPE_EVENT_PLAYLIST
);
}
...
...
src/playlist.c
View file @
8c743fd3
...
...
@@ -140,7 +140,8 @@ playlist_update_queued_song(struct playlist *playlist, const struct song *prev)
?
queue_next_order
(
&
playlist
->
queue
,
playlist
->
current
)
:
0
;
if
(
next_order
==
0
&&
playlist
->
queue
.
random
)
{
if
(
next_order
==
0
&&
playlist
->
queue
.
random
&&
!
playlist
->
queue
.
single
)
{
/* shuffle the song order again, so we get a different
order each time the playlist is played
completely */
...
...
src/playlist_control.c
View file @
8c743fd3
...
...
@@ -24,6 +24,7 @@
#include "playlist_internal.h"
#include "player_control.h"
#include "idle.h"
#include <glib.h>
...
...
@@ -156,6 +157,8 @@ nextSongInPlaylist(struct playlist *playlist)
if
(
next_order
<
0
)
{
/* cancel single */
playlist
->
queue
.
single
=
false
;
idle_add
(
IDLE_OPTIONS
);
/* no song after this one: stop playback */
stopPlaylist
(
playlist
);
...
...
src/tag.c
View file @
8c743fd3
...
...
@@ -64,6 +64,36 @@ const char *tag_item_names[TAG_NUM_OF_ITEM_TYPES] = {
bool
ignore_tag_items
[
TAG_NUM_OF_ITEM_TYPES
];
enum
tag_type
tag_name_parse
(
const
char
*
name
)
{
assert
(
name
!=
NULL
);
for
(
unsigned
i
=
0
;
i
<
TAG_NUM_OF_ITEM_TYPES
;
++
i
)
{
assert
(
tag_item_names
[
i
]
!=
NULL
);
if
(
strcmp
(
name
,
tag_item_names
[
i
])
==
0
)
return
(
enum
tag_type
)
i
;
}
return
TAG_NUM_OF_ITEM_TYPES
;
}
enum
tag_type
tag_name_parse_i
(
const
char
*
name
)
{
assert
(
name
!=
NULL
);
for
(
unsigned
i
=
0
;
i
<
TAG_NUM_OF_ITEM_TYPES
;
++
i
)
{
assert
(
tag_item_names
[
i
]
!=
NULL
);
if
(
g_ascii_strcasecmp
(
name
,
tag_item_names
[
i
])
==
0
)
return
(
enum
tag_type
)
i
;
}
return
TAG_NUM_OF_ITEM_TYPES
;
}
static
size_t
items_size
(
const
struct
tag
*
tag
)
{
return
tag
->
num_items
*
sizeof
(
struct
tag_item
*
);
...
...
@@ -76,7 +106,7 @@ void tag_lib_init(void)
char
*
temp
;
char
*
s
;
char
*
c
;
int
i
;
enum
tag_type
type
;
/* parse the "metadata_to_use" config parameter below */
...
...
@@ -98,16 +128,18 @@ void tag_lib_init(void)
if
(
*
s
==
'\0'
)
quit
=
1
;
*
s
=
'\0'
;
for
(
i
=
0
;
i
<
TAG_NUM_OF_ITEM_TYPES
;
i
++
)
{
if
(
g_ascii_strcasecmp
(
c
,
tag_item_names
[
i
])
==
0
)
{
ignore_tag_items
[
i
]
=
false
;
break
;
}
}
if
(
strlen
(
c
)
&&
i
==
TAG_NUM_OF_ITEM_TYPES
)
{
c
=
g_strstrip
(
c
);
if
(
*
c
==
0
)
continue
;
type
=
tag_name_parse_i
(
c
);
if
(
type
==
TAG_NUM_OF_ITEM_TYPES
)
g_error
(
"error parsing metadata item
\"
%s
\"
"
,
c
);
}
ignore_tag_items
[
type
]
=
false
;
s
++
;
c
=
s
;
}
...
...
@@ -247,6 +279,22 @@ tag_merge(const struct tag *base, const struct tag *add)
return
ret
;
}
struct
tag
*
tag_merge_replace
(
struct
tag
*
base
,
struct
tag
*
add
)
{
if
(
add
==
NULL
)
return
base
;
if
(
base
==
NULL
)
return
add
;
struct
tag
*
tag
=
tag_merge
(
base
,
add
);
tag_free
(
base
);
tag_free
(
add
);
return
tag
;
}
const
char
*
tag_get_value
(
const
struct
tag
*
tag
,
enum
tag_type
type
)
{
...
...
src/tag.h
View file @
8c743fd3
...
...
@@ -94,6 +94,22 @@ struct tag {
};
/**
* Parse the string, and convert it into a #tag_type. Returns
* #TAG_NUM_OF_ITEM_TYPES if the string could not be recognized.
*/
enum
tag_type
tag_name_parse
(
const
char
*
name
);
/**
* Parse the string, and convert it into a #tag_type. Returns
* #TAG_NUM_OF_ITEM_TYPES if the string could not be recognized.
*
* Case does not matter.
*/
enum
tag_type
tag_name_parse_i
(
const
char
*
name
);
/**
* Creates an empty #tag.
*/
struct
tag
*
tag_new
(
void
);
...
...
@@ -166,6 +182,15 @@ struct tag *
tag_merge
(
const
struct
tag
*
base
,
const
struct
tag
*
add
);
/**
* Merges the data from two tags. Any of the two may be NULL. Both
* are freed by this function.
*
* @return a newly allocated tag, which must be freed with tag_free()
*/
struct
tag
*
tag_merge_replace
(
struct
tag
*
base
,
struct
tag
*
add
);
/**
* Returns true if the tag contains no items. This ignores the "time"
* attribute.
*/
...
...
src/tag_ape.c
View file @
8c743fd3
...
...
@@ -19,12 +19,47 @@
#include "tag_ape.h"
#include "tag.h"
#include "tag_table.h"
#include <glib.h>
#include <assert.h>
#include <stdio.h>
static
const
char
*
const
ape_tag_names
[
TAG_NUM_OF_ITEM_TYPES
]
=
{
[
TAG_ITEM_ALBUM_ARTIST
]
=
"album artist"
,
[
TAG_ITEM_DATE
]
=
"year"
};
static
enum
tag_type
tag_ape_name_parse
(
const
char
*
name
)
{
enum
tag_type
type
=
tag_table_lookup
(
ape_tag_names
,
name
);
if
(
type
==
TAG_NUM_OF_ITEM_TYPES
)
type
=
tag_name_parse_i
(
name
);
return
type
;
}
static
struct
tag
*
tag_ape_import_item
(
struct
tag
*
tag
,
unsigned
long
flags
,
const
char
*
key
,
const
char
*
value
,
size_t
value_length
)
{
/* we only care about utf-8 text tags */
if
((
flags
&
(
0x3
<<
1
))
!=
0
)
return
tag
;
enum
tag_type
type
=
tag_ape_name_parse
(
key
);
if
(
type
==
TAG_NUM_OF_ITEM_TYPES
)
return
tag
;
if
(
tag
==
NULL
)
tag
=
tag_new
();
tag_add_item_n
(
tag
,
type
,
value
,
value_length
);
return
tag
;
}
struct
tag
*
tag_ape_load
(
const
char
*
file
)
{
...
...
@@ -36,7 +71,6 @@ tag_ape_load(const char *file)
size_t
tagLen
;
size_t
size
;
unsigned
long
flags
;
int
i
;
char
*
key
;
struct
{
...
...
@@ -48,26 +82,6 @@ tag_ape_load(const char *file)
unsigned
char
reserved
[
8
];
}
footer
;
const
char
*
apeItems
[
7
]
=
{
"title"
,
"artist"
,
"album"
,
"comment"
,
"genre"
,
"track"
,
"year"
};
int
tagItems
[
7
]
=
{
TAG_ITEM_TITLE
,
TAG_ITEM_ARTIST
,
TAG_ITEM_ALBUM
,
TAG_ITEM_COMMENT
,
TAG_ITEM_GENRE
,
TAG_ITEM_TRACK
,
TAG_ITEM_DATE
,
};
fp
=
fopen
(
file
,
"r"
);
if
(
!
fp
)
return
NULL
;
...
...
@@ -127,17 +141,8 @@ tag_ape_load(const char *file)
if
(
tagLen
<
size
)
goto
fail
;
/* we only care about utf-8 text tags */
if
(
!
(
flags
&
(
0x3
<<
1
)))
{
for
(
i
=
0
;
i
<
7
;
i
++
)
{
if
(
g_ascii_strcasecmp
(
key
,
apeItems
[
i
])
==
0
)
{
if
(
!
ret
)
ret
=
tag_new
();
tag_add_item_n
(
ret
,
tagItems
[
i
],
p
,
size
);
}
}
}
ret
=
tag_ape_import_item
(
ret
,
flags
,
key
,
p
,
size
);
p
+=
size
;
tagLen
-=
size
;
}
...
...
src/tag_table.h
0 → 100644
View file @
8c743fd3
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* http://www.musicpd.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.
*/
#ifndef MPD_TAG_TABLE_H
#define MPD_TAG_TABLE_H
#include "tag.h"
#include <glib.h>
/**
* Looks up a string in a tag translation table (case insensitive).
* Returns TAG_NUM_OF_ITEM_TYPES if the specified name was not found
* in the table.
*/
static
inline
enum
tag_type
tag_table_lookup
(
const
char
*
const
*
table
,
const
char
*
name
)
{
for
(
unsigned
i
=
0
;
i
<
TAG_NUM_OF_ITEM_TYPES
;
i
++
)
if
(
table
[
i
]
!=
NULL
&&
g_ascii_strcasecmp
(
name
,
table
[
i
])
==
0
)
return
(
enum
tag_type
)
i
;
return
TAG_NUM_OF_ITEM_TYPES
;
}
#endif
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment