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
2835998a
Commit
2835998a
authored
Mar 11, 2010
by
Alexey Rusakov
Browse files
Options
Browse Files
Download
Plain Diff
Merge commit 'release-0.15.8' into alt
parents
eaff52fa
760569fc
Hide whitespace changes
Inline
Side-by-side
Showing
37 changed files
with
660 additions
and
316 deletions
+660
-316
Makefile.am
Makefile.am
+7
-1
NEWS
NEWS
+51
-0
configure.ac
configure.ac
+3
-4
bz2_plugin.c
src/archive/bz2_plugin.c
+4
-2
iso_plugin.c
src/archive/iso_plugin.c
+4
-1
zip_plugin.c
src/archive/zip_plugin.c
+4
-1
archive_api.h
src/archive_api.h
+3
-0
dbUtils.c
src/dbUtils.c
+4
-2
_flac_common.c
src/decoder/_flac_common.c
+3
-3
ffmpeg_plugin.c
src/decoder/ffmpeg_plugin.c
+67
-17
flac_plugin.c
src/decoder/flac_plugin.c
+16
-16
oggflac_plugin.c
src/decoder/oggflac_plugin.c
+11
-1
vorbis_plugin.c
src/decoder/vorbis_plugin.c
+6
-1
wavpack_plugin.c
src/decoder/wavpack_plugin.c
+3
-4
decoder_api.c
src/decoder_api.c
+5
-1
decoder_control.h
src/decoder_control.h
+0
-3
decoder_thread.c
src/decoder_thread.c
+10
-5
archive_input_plugin.c
src/input/archive_input_plugin.c
+1
-0
curl_input_plugin.c
src/input/curl_input_plugin.c
+22
-181
curl_input_plugin.h
src/input/curl_input_plugin.h
+10
-0
file_input_plugin.c
src/input/file_input_plugin.c
+3
-18
lastfm_input_plugin.c
src/input/lastfm_input_plugin.c
+1
-1
rewind_input_plugin.c
src/input/rewind_input_plugin.c
+238
-0
rewind_input_plugin.h
src/input/rewind_input_plugin.h
+49
-0
input_stream.c
src/input_stream.c
+3
-0
mapper.c
src/mapper.c
+9
-4
mapper.h
src/mapper.h
+2
-0
mixer_control.c
src/mixer_control.c
+4
-0
output_thread.c
src/output_thread.c
+9
-0
playlist_save.c
src/playlist_save.c
+4
-1
queue.c
src/queue.c
+2
-2
song_save.c
src/song_save.c
+7
-3
sticker.c
src/sticker.c
+4
-0
stored_playlist.c
src/stored_playlist.c
+24
-6
tag_id3.c
src/tag_id3.c
+2
-2
update.c
src/update.c
+5
-1
run_input.c
test/run_input.c
+60
-35
No files found.
Makefile.am
View file @
2835998a
...
...
@@ -75,6 +75,7 @@ mpd_headers = \
src/input_stream.h
\
src/input/file_input_plugin.h
\
src/input/curl_input_plugin.h
\
src/input/rewind_input_plugin.h
\
src/input/lastfm_input_plugin.h
\
src/input/mms_input_plugin.h
\
src/icy_server.h
\
...
...
@@ -467,7 +468,9 @@ INPUT_SRC = \
src/input/file_input_plugin.c
if
HAVE_CURL
INPUT_SRC
+=
src/input/curl_input_plugin.c src/icy_metadata.c
INPUT_SRC
+=
src/input/curl_input_plugin.c
\
src/input/rewind_input_plugin.c
\
src/icy_metadata.c
endif
if
ENABLE_LASTFM
...
...
@@ -637,6 +640,7 @@ test_run_decoder_SOURCES = test/run_decoder.c \
src/tag.c src/tag_pool.c
\
src/replay_gain.c
\
src/uri.c
\
src/timer.c
\
$(ARCHIVE_SRC)
\
$(INPUT_SRC)
\
$(TAG_SRC)
\
...
...
@@ -656,6 +660,7 @@ test_read_tags_SOURCES = test/read_tags.c \
src/tag.c src/tag_pool.c
\
src/replay_gain.c
\
src/uri.c
\
src/timer.c
\
$(ARCHIVE_SRC)
\
$(INPUT_SRC)
\
$(TAG_SRC)
\
...
...
@@ -748,6 +753,7 @@ DOCBOOK_HTML =
endif
doc/api/html/index.html
:
doc/doxygen.conf
@
mkdir
-p
$
(
@D
)
$(DOXYGEN)
$<
all-local
:
$(DOCBOOK_HTML) doc/api/html/index.html
...
...
NEWS
View file @
2835998a
ver 0.15.8 (2010/01/17)
* input:
- curl: allow rewinding with Icy-Metadata
* decoders:
- ffmpeg, flac, vorbis: added more flac/vorbis MIME types
- ffmpeg: enabled libavformat's file name extension detection
* dbUtils: return empty tag value only if no value was found
* decoder_thread: fix CUE track playback
* queue: don't repeat current song in consume mode
ver 0.15.7 (2009/12/27)
* archive:
- close archive when stream is closed
- iso, zip: fixed memory leak in destructor
* input:
- file: don't fall back to parent directory
- archive: fixed memory leak in error handler
* tags:
- id3: fix ID3v1 charset conversion
* decoders:
- eliminate jitter after seek failure
- ffmpeg: don't try to force stereo
- wavpack: allow fine-grained seeking
* mixer: explicitly close all mixers on shutdown
* mapper: fix memory leak when playlist_directory is not set
* mapper: apply filesystem_charset to playlists
* command: verify playlist name in the "rm" command
* database: return multiple tag values per song
ver 0.15.6 (2009/11/18)
* input:
- lastfm: fixed variable name in GLib<2.16 code path
- input/mms: require libmms 0.4
* archive:
- zzip: require libzzip 0.13
* tags:
- id3: allow 4 MB RIFF/AIFF tags
* decoders:
- ffmpeg: convert metadata
- ffmpeg: align the output buffer
- oggflac: rewind stream after FLAC detection
- flac: fixed CUE seeking range check
- flac: fixed NULL pointer dereference in CUE code
* output_thread: check again if output is open on PAUSE
* update: delete ignored symlinks from database
* database: increased maximum line length to 32 kB
* sticker: added fallback for sqlite3_prepare_v2()
ver 0.15.5 (2009/10/18)
* input:
- curl: don't abort if a packet has only metadata
...
...
configure.ac
View file @
2835998a
AC_PREREQ(2.60)
AC_INIT(mpd, 0.15.
5
, musicpd-dev-team@lists.sourceforge.net)
AC_INIT(mpd, 0.15.
8
, 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)
...
...
@@ -303,7 +303,7 @@ AC_ARG_ENABLE(mms,
[enable the MMS protocol with libmms]),,
[enable_mms=auto])
MPD_AUTO_PKG(mms, MMS, [libmms],
MPD_AUTO_PKG(mms, MMS, [libmms
>= 0.4
],
[libmms mms:// protocol support], [libmms not found])
if test x$enable_mms = xyes; then
AC_DEFINE(ENABLE_MMS, 1,
...
...
@@ -339,7 +339,7 @@ AC_ARG_ENABLE(zip,
[enable zip archive support (default: disabled)]),,
enable_zip=no)
MPD_AUTO_PKG(zip, ZZIP, [zziplib],
MPD_AUTO_PKG(zip, ZZIP, [zziplib
>= 0.13
],
[libzzip archive library], [libzzip not found])
AM_CONDITIONAL(HAVE_ZIP, test x$enable_zip = xyes)
...
...
@@ -1139,7 +1139,6 @@ then
MPD_CHECK_FLAG([-Wextra])
MPD_CHECK_FLAG([-Wno-deprecated-declarations])
MPD_CHECK_FLAG([-Wmissing-prototypes])
MPD_CHECK_FLAG([-Wdeclaration-after-statement])
MPD_CHECK_FLAG([-Wshadow])
MPD_CHECK_FLAG([-Wpointer-arith])
MPD_CHECK_FLAG([-Wstrict-prototypes])
...
...
src/archive/bz2_plugin.c
View file @
2835998a
...
...
@@ -140,8 +140,8 @@ static void
bz2_close
(
struct
archive_file
*
file
)
{
bz2_context
*
context
=
(
bz2_context
*
)
file
;
if
(
context
->
name
)
g_free
(
context
->
name
);
g_free
(
context
->
name
);
input_stream_close
(
&
context
->
istream
);
g_free
(
context
);
...
...
@@ -173,6 +173,8 @@ bz2_is_close(struct input_stream *is)
bz2_context
*
context
=
(
bz2_context
*
)
is
->
data
;
bz2_destroy
(
context
);
is
->
data
=
NULL
;
bz2_close
((
struct
archive_file
*
)
context
);
}
static
int
...
...
src/archive/iso_plugin.c
View file @
2835998a
...
...
@@ -132,7 +132,8 @@ iso_close(struct archive_file *file)
}
//close archive
iso9660_close
(
context
->
iso
);
context
->
iso
=
NULL
;
g_free
(
context
);
}
/* single archive handling */
...
...
@@ -165,6 +166,8 @@ iso_is_close(struct input_stream *is)
{
iso_context
*
context
=
(
iso_context
*
)
is
->
data
;
g_free
(
context
->
statbuf
);
iso_close
((
struct
archive_file
*
)
context
);
}
...
...
src/archive/zip_plugin.c
View file @
2835998a
...
...
@@ -99,7 +99,8 @@ zip_close(struct archive_file *file)
}
//close archive
zzip_dir_close
(
context
->
dir
);
context
->
dir
=
NULL
;
g_free
(
context
);
}
/* single archive handling */
...
...
@@ -133,6 +134,8 @@ zip_is_close(struct input_stream *is)
{
zip_context
*
context
=
(
zip_context
*
)
is
->
data
;
zzip_file_close
(
context
->
file
);
zip_close
((
struct
archive_file
*
)
context
);
}
static
size_t
...
...
src/archive_api.h
View file @
2835998a
...
...
@@ -73,6 +73,9 @@ struct archive_plugin {
/**
* Opens an input_stream of a file within the archive.
*
* If this function succeeds, then the #input_stream "owns"
* the archive file and will automatically close it.
*
* @param path the path within the archive
*/
bool
(
*
open_stream
)(
struct
archive_file
*
,
struct
input_stream
*
is
,
...
...
src/dbUtils.c
View file @
2835998a
...
...
@@ -234,6 +234,7 @@ visitTag(struct client *client, struct strset *set,
struct
song
*
song
,
enum
tag_type
tagType
)
{
struct
tag
*
tag
=
song
->
tag
;
bool
found
=
false
;
if
(
tagType
==
LOCATE_TAG_FILE_TYPE
)
{
song_print_url
(
client
,
song
);
...
...
@@ -246,11 +247,12 @@ visitTag(struct client *client, struct strset *set,
for
(
unsigned
i
=
0
;
i
<
tag
->
num_items
;
i
++
)
{
if
(
tag
->
items
[
i
]
->
type
==
tagType
)
{
strset_add
(
set
,
tag
->
items
[
i
]
->
value
);
return
;
found
=
true
;
}
}
strset_add
(
set
,
""
);
if
(
!
found
)
strset_add
(
set
,
""
);
}
struct
list_tags_data
{
...
...
src/decoder/_flac_common.c
View file @
2835998a
...
...
@@ -415,11 +415,11 @@ flac_vtrack_tnum(const char* fname)
* another/better way would be to use tag struct
*/
char
*
ptr
=
strrchr
(
fname
,
'_'
);
if
(
ptr
==
NULL
)
return
0
;
// copy ascii tracknumber to int
char
vtrack
[
4
];
g_strlcpy
(
vtrack
,
++
ptr
,
4
);
return
(
unsigned
int
)
strtol
(
vtrack
,
NULL
,
10
);
return
(
unsigned
int
)
strtol
(
++
ptr
,
NULL
,
10
);
}
#endif
/* FLAC_API_VERSION_CURRENT >= 7 */
src/decoder/ffmpeg_plugin.c
View file @
2835998a
...
...
@@ -55,7 +55,7 @@ struct ffmpeg_context {
struct
ffmpeg_stream
{
/** hack - see url_to_struct() */
char
url
[
8
];
char
url
[
64
];
struct
decoder
*
decoder
;
struct
input_stream
*
input
;
...
...
@@ -140,8 +140,28 @@ 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
)
{
assert
(
stream
!=
NULL
);
assert
(
uri
!=
NULL
);
char
*
base
=
g_path_get_basename
(
uri
);
const
char
*
suffix
=
strrchr
(
base
,
'.'
);
if
(
suffix
!=
NULL
&&
suffix
[
1
]
!=
0
)
g_strlcat
(
stream
->
url
,
suffix
,
sizeof
(
stream
->
url
));
g_free
(
base
);
}
static
bool
ffmpeg_helper
(
struct
input_stream
*
input
,
ffmpeg_helper
(
const
char
*
uri
,
struct
input_stream
*
input
,
bool
(
*
callback
)(
struct
ffmpeg_context
*
ctx
),
struct
ffmpeg_context
*
ctx
)
{
...
...
@@ -154,6 +174,9 @@ ffmpeg_helper(struct input_stream *input,
};
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 ?
...
...
@@ -209,6 +232,21 @@ ffmpeg_helper(struct input_stream *input,
return
ret
;
}
/**
* On some platforms, libavcodec wants the output buffer aligned to 16
* bytes (because it uses SSE/Altivec internally). This function
* returns the aligned version of the specified buffer, and corrects
* the buffer size.
*/
static
void
*
align16
(
void
*
p
,
size_t
*
length_p
)
{
unsigned
add
=
16
-
(
size_t
)
p
%
16
;
*
length_p
-=
add
;
return
(
char
*
)
p
+
add
;
}
static
enum
decoder_command
ffmpeg_send_packet
(
struct
decoder
*
decoder
,
struct
input_stream
*
is
,
const
AVPacket
*
packet
,
...
...
@@ -217,7 +255,9 @@ ffmpeg_send_packet(struct decoder *decoder, struct input_stream *is,
{
enum
decoder_command
cmd
=
DECODE_COMMAND_NONE
;
int
position
;
uint8_t
audio_buf
[(
AVCODEC_MAX_AUDIO_FRAME_SIZE
*
3
)
/
2
];
uint8_t
audio_buf
[(
AVCODEC_MAX_AUDIO_FRAME_SIZE
*
3
)
/
2
+
16
];
int16_t
*
aligned_buffer
;
size_t
buffer_size
;
int
len
,
audio_size
;
uint8_t
*
packet_data
;
int
packet_size
;
...
...
@@ -225,11 +265,13 @@ ffmpeg_send_packet(struct decoder *decoder, struct input_stream *is,
packet_data
=
packet
->
data
;
packet_size
=
packet
->
size
;
buffer_size
=
sizeof
(
audio_buf
);
aligned_buffer
=
align16
(
audio_buf
,
&
buffer_size
);
while
((
packet_size
>
0
)
&&
(
cmd
==
DECODE_COMMAND_NONE
))
{
audio_size
=
sizeof
(
audio_buf
)
;
audio_size
=
buffer_size
;
len
=
avcodec_decode_audio2
(
codec_context
,
(
int16_t
*
)
audio_buf
,
&
audio_size
,
aligned_buffer
,
&
audio_size
,
packet_data
,
packet_size
);
if
(
len
<
0
)
{
...
...
@@ -250,7 +292,7 @@ ffmpeg_send_packet(struct decoder *decoder, struct input_stream *is,
:
0
;
cmd
=
decoder_data
(
decoder
,
is
,
a
udio_buf
,
audio_size
,
a
ligned_buffer
,
audio_size
,
position
,
codec_context
->
bit_rate
/
1000
,
NULL
);
}
...
...
@@ -270,10 +312,6 @@ ffmpeg_decode_internal(struct ffmpeg_context *ctx)
total_time
=
0
;
if
(
codec_context
->
channels
>
2
)
{
codec_context
->
channels
=
2
;
}
#if LIBAVCODEC_VERSION_INT >= ((51<<16)+(41<<8)+0)
audio_format
.
bits
=
(
uint8_t
)
av_get_bits_per_sample_format
(
codec_context
->
sample_fmt
);
#else
...
...
@@ -334,7 +372,8 @@ ffmpeg_decode(struct decoder *decoder, struct input_stream *input)
ctx
.
input
=
input
;
ctx
.
decoder
=
decoder
;
ffmpeg_helper
(
input
,
ffmpeg_decode_internal
,
&
ctx
);
ffmpeg_helper
(
decoder_get_uri
(
decoder
),
input
,
ffmpeg_decode_internal
,
&
ctx
);
}
#if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(31<<8)+0)
...
...
@@ -352,17 +391,17 @@ ffmpeg_copy_metadata(struct tag *tag, AVMetadata *m,
static
bool
ffmpeg_tag_internal
(
struct
ffmpeg_context
*
ctx
)
{
struct
tag
*
tag
=
(
struct
tag
*
)
ctx
->
tag
;
const
AVFormatContext
*
f
=
ctx
->
format_context
;
AVFormatContext
*
f
=
ctx
->
format_context
;
tag
->
time
=
0
;
if
(
f
->
duration
!=
(
int64_t
)
AV_NOPTS_VALUE
)
tag
->
time
=
f
->
duration
/
AV_TIME_BASE
;
#if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(31<<8)+0)
av_metadata_conv
(
f
,
NULL
,
f
->
iformat
->
metadata_conv
);
ffmpeg_copy_metadata
(
tag
,
f
->
metadata
,
TAG_ITEM_TITLE
,
"title"
);
if
(
!
ffmpeg_copy_metadata
(
tag
,
f
->
metadata
,
TAG_ITEM_ARTIST
,
"author"
))
ffmpeg_copy_metadata
(
tag
,
f
->
metadata
,
TAG_ITEM_ARTIST
,
"artist"
);
ffmpeg_copy_metadata
(
tag
,
f
->
metadata
,
TAG_ITEM_ARTIST
,
"author"
);
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"
);
...
...
@@ -411,7 +450,7 @@ static struct tag *ffmpeg_tag(const char *file)
ctx
.
decoder
=
NULL
;
ctx
.
tag
=
tag_new
();
ret
=
ffmpeg_helper
(
&
input
,
ffmpeg_tag_internal
,
&
ctx
);
ret
=
ffmpeg_helper
(
file
,
&
input
,
ffmpeg_tag_internal
,
&
ctx
);
if
(
!
ret
)
{
tag_free
(
ctx
.
tag
);
ctx
.
tag
=
NULL
;
...
...
@@ -447,25 +486,31 @@ static const char *const ffmpeg_suffixes[] = {
};
static
const
char
*
const
ffmpeg_mime_types
[]
=
{
"application/m4a"
,
"application/mp4"
,
"application/octet-stream"
,
"application/ogg"
,
"application/x-ms-wmz"
,
"application/x-ms-wmd"
,
"application/x-ogg"
,
"application/x-shockwave-flash"
,
"application/x-shorten"
,
"audio/8svx"
,
"audio/16sv"
,
"audio/aac"
,
"audio/ac3"
,
"audio/aiff"
"audio/amr"
,
"audio/basic"
,
"audio/flac"
,
"audio/m4a"
,
"audio/mp4"
,
"audio/mpeg"
,
"audio/musepack"
,
"audio/ogg"
,
"audio/qcelp"
,
"audio/vorbis"
,
"audio/vorbis+ogg"
,
"audio/x-8svx"
,
"audio/x-16sv"
,
"audio/x-aac"
,
...
...
@@ -478,15 +523,20 @@ static const char *const ffmpeg_mime_types[] = {
"audio/x-flac"
,
"audio/x-gsm"
,
"audio/x-mace"
,
"audio/x-matroska"
,
"audio/x-monkeys-audio"
,
"audio/x-mpeg"
,
"audio/x-ms-wma"
,
"audio/x-ms-wax"
,
"audio/x-musepack"
,
"audio/x-ogg"
,
"audio/x-vorbis"
,
"audio/x-vorbis+ogg"
,
"audio/x-pn-realaudio"
,
"audio/x-pn-multirate-realaudio"
,
"audio/x-speex"
,
"audio/x-tta"
"audio/x-voc"
,
"audio/x-wav"
,
"audio/x-wma"
,
"audio/x-wv"
,
...
...
src/decoder/flac_plugin.c
View file @
2835998a
...
...
@@ -629,21 +629,15 @@ flac_container_decode(struct decoder* decoder,
FLAC__uint64
seek_sample
=
t_start
+
(
decoder_seek_where
(
decoder
)
*
data
.
audio_format
.
sample_rate
);
//if (seek_sample >= t_start && seek_sample <= t_end && data.total_time > 30)
if
(
seek_sample
>=
t_start
&&
seek_sample
<=
t_end
)
{
if
(
flac_seek_absolute
(
flac_dec
,
(
FLAC__uint64
)
seek_sample
))
{
data
.
time
=
(
float
)(
seek_sample
-
t_start
)
/
data
.
audio_format
.
sample_rate
;
data
.
position
=
0
;
if
(
seek_sample
>=
t_start
&&
seek_sample
<=
t_end
&&
flac_seek_absolute
(
flac_dec
,
(
FLAC__uint64
)
seek_sample
))
{
data
.
time
=
(
float
)(
seek_sample
-
t_start
)
/
data
.
audio_format
.
sample_rate
;
data
.
position
=
0
;
decoder_command_finished
(
decoder
);
}
else
decoder_seek_error
(
decoder
);
//decoder_command_finished(decoder);
}
decoder_command_finished
(
decoder
);
}
else
decoder_seek_error
(
decoder
);
}
else
if
(
flac_get_state
(
flac_dec
)
==
flac_decoder_eof
)
break
;
...
...
@@ -877,9 +871,11 @@ oggflac_decode(struct decoder *decoder, struct input_stream *input_stream)
static
const
char
*
const
oggflac_suffixes
[]
=
{
"ogg"
,
"oga"
,
NULL
};
static
const
char
*
const
oggflac_mime_types
[]
=
{
"audio/x-flac+ogg"
,
"application/ogg"
,
"application/x-ogg"
,
"audio/ogg"
,
"audio/x-flac+ogg"
,
"audio/x-ogg"
,
NULL
};
...
...
@@ -900,7 +896,11 @@ const struct decoder_plugin oggflac_decoder_plugin = {
static
const
char
*
const
flac_suffixes
[]
=
{
"flac"
,
NULL
};
static
const
char
*
const
flac_mime_types
[]
=
{
"audio/x-flac"
,
"application/x-flac"
,
NULL
"application/flac"
,
"application/x-flac"
,
"audio/flac"
,
"audio/x-flac"
,
NULL
};
const
struct
decoder_plugin
flac_decoder_plugin
=
{
...
...
src/decoder/oggflac_plugin.c
View file @
2835998a
...
...
@@ -272,6 +272,10 @@ oggflac_tag_dup(const char *file)
return
NULL
;
}
/* rewind the stream, because ogg_stream_type_detect() has
moved it */
input_stream_seek
(
&
input_stream
,
0
,
SEEK_SET
);
flac_data_init
(
&
data
,
NULL
,
&
input_stream
);
data
.
tag
=
tag_new
();
...
...
@@ -300,6 +304,10 @@ oggflac_decode(struct decoder * mpd_decoder, struct input_stream *input_stream)
if
(
ogg_stream_type_detect
(
input_stream
)
!=
FLAC
)
return
;
/* rewind the stream, because ogg_stream_type_detect() has
moved it */
input_stream_seek
(
input_stream
,
0
,
SEEK_SET
);
flac_data_init
(
&
data
,
mpd_decoder
,
input_stream
);
if
(
!
(
decoder
=
full_decoder_init_and_read_metadata
(
&
data
,
0
)))
{
...
...
@@ -349,9 +357,11 @@ fail:
static
const
char
*
const
oggflac_suffixes
[]
=
{
"ogg"
,
"oga"
,
NULL
};
static
const
char
*
const
oggflac_mime_types
[]
=
{
"audio/x-flac+ogg"
,
"application/ogg"
,
"application/x-ogg"
,
"audio/ogg"
,
"audio/x-ogg"
,
"audio/x-flac+ogg"
,
NULL
};
...
...
src/decoder/vorbis_plugin.c
View file @
2835998a
...
...
@@ -405,8 +405,13 @@ static const char *const vorbis_suffixes[] = {
static
const
char
*
const
vorbis_mime_types
[]
=
{
"application/ogg"
,
"audio/x-vorbis+ogg"
,
"application/x-ogg"
,
"audio/ogg"
,
"audio/vorbis"
,
"audio/vorbis+ogg"
,
"audio/x-ogg"
,
"audio/x-vorbis"
,
"audio/x-vorbis+ogg"
,
NULL
};
...
...
src/decoder/wavpack_plugin.c
View file @
2835998a
...
...
@@ -72,7 +72,7 @@ format_samples_int(int bytes_per_sample, void *buffer, uint32_t count)
switch
(
bytes_per_sample
)
{
case
1
:
{
uchar
*
dst
=
buffer
;
int8_t
*
dst
=
buffer
;
/*
* The asserts like the following one are because we do the
* formatting of samples within a single buffer. The size
...
...
@@ -185,10 +185,9 @@ wavpack_decode(struct decoder *decoder, WavpackContext *wpc, bool can_seek,
do
{
if
(
decoder_get_command
(
decoder
)
==
DECODE_COMMAND_SEEK
)
{
if
(
can_seek
)
{
int
where
;
unsigned
where
=
decoder_seek_where
(
decoder
)
*
audio_format
.
sample_rate
;
where
=
decoder_seek_where
(
decoder
);
where
*=
audio_format
.
sample_rate
;
if
(
WavpackSeekSample
(
wpc
,
where
))
{
position
=
where
;
decoder_command_finished
(
decoder
);
...
...
src/decoder_api.c
View file @
2835998a
...
...
@@ -93,7 +93,9 @@ void decoder_command_finished(G_GNUC_UNUSED struct decoder * decoder)
dc
.
seek_error
||
decoder
->
seeking
);
assert
(
dc
.
pipe
!=
NULL
);
if
(
dc
.
command
==
DECODE_COMMAND_SEEK
)
{
if
(
decoder
->
seeking
)
{
decoder
->
seeking
=
false
;
/* delete frames from the old song position */
if
(
decoder
->
chunk
!=
NULL
)
{
...
...
@@ -124,6 +126,8 @@ void decoder_seek_error(struct decoder * decoder)
assert
(
dc
.
pipe
!=
NULL
);
dc
.
seek_error
=
true
;
decoder
->
seeking
=
false
;
decoder_command_finished
(
decoder
);
}
...
...
src/decoder_control.h
View file @
2835998a
...
...
@@ -26,9 +26,6 @@
#include <assert.h>
#define DECODE_TYPE_FILE 0
#define DECODE_TYPE_URL 1
enum
decoder_state
{
DECODE_STATE_STOP
=
0
,
DECODE_STATE_START
,
...
...
src/decoder_thread.c
View file @
2835998a
...
...
@@ -89,7 +89,8 @@ static void decoder_run_song(const struct song *song, const char *uri)
struct
input_stream
input_stream
;
const
struct
decoder_plugin
*
plugin
;
if
(
!
input_stream_open
(
&
input_stream
,
uri
))
{
close_instream
=
input_stream_open
(
&
input_stream
,
uri
);
if
(
!
close_instream
&&
!
song_is_file
(
song
))
{
dc
.
state
=
DECODE_STATE_ERROR
;
return
;
}
...
...
@@ -108,7 +109,7 @@ static void decoder_run_song(const struct song *song, const char *uri)
/* wait for the input stream to become ready; its metadata
will be available then */
while
(
!
input_stream
.
ready
)
{
while
(
close_instream
&&
!
input_stream
.
ready
)
{
if
(
dc
.
command
==
DECODE_COMMAND_STOP
)
{
input_stream_close
(
&
input_stream
);
dc
.
state
=
DECODE_STATE_STOP
;
...
...
@@ -124,7 +125,8 @@ static void decoder_run_song(const struct song *song, const char *uri)
}
if
(
dc
.
command
==
DECODE_COMMAND_STOP
)
{
input_stream_close
(
&
input_stream
);
if
(
close_instream
)
input_stream_close
(
&
input_stream
);
dc
.
state
=
DECODE_STATE_STOP
;
return
;
}
...
...
@@ -179,8 +181,11 @@ static void decoder_run_song(const struct song *song, const char *uri)
const
char
*
s
=
uri_get_suffix
(
uri
);
while
((
plugin
=
decoder_plugin_from_suffix
(
s
,
next
++
)))
{
if
(
plugin
->
file_decode
!=
NULL
)
{
input_stream_close
(
&
input_stream
);
close_instream
=
false
;
if
(
close_instream
)
{
input_stream_close
(
&
input_stream
);
close_instream
=
false
;
}
ret
=
decoder_file_decode
(
plugin
,
&
decoder
,
uri
);
if
(
ret
)
...
...
src/input/archive_input_plugin.c
View file @
2835998a
...
...
@@ -66,6 +66,7 @@ input_archive_open(struct input_stream *is, const char *pathname)
if
(
!
opened
)
{
g_warning
(
"open inarchive file %s failed
\n\n
"
,
filename
);
arplug
->
close
(
file
);
}
else
{
is
->
ready
=
true
;
}
...
...
src/input/curl_input_plugin.c
View file @
2835998a
...
...
@@ -41,9 +41,6 @@
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "input_curl"
/** rewinding is possible after up to 64 kB */
static
const
off_t
max_rewind_size
=
64
*
1024
;
/**
* Buffers created by input_curl_writefunction().
*/
...
...
@@ -78,9 +75,6 @@ struct input_curl {
/** did libcurl tell us the we're at the end of the response body? */
bool
eof
;
/** limited list of old buffers, for rewinding */
GQueue
*
rewind
;
/** error message provided by libcurl */
char
error
[
CURL_ERROR_SIZE
];
...
...
@@ -176,11 +170,6 @@ input_curl_easy_free(struct input_curl *c)
g_queue_foreach
(
c
->
buffers
,
buffer_free_callback
,
NULL
);
g_queue_clear
(
c
->
buffers
);
if
(
c
->
rewind
!=
NULL
)
{
g_queue_foreach
(
c
->
rewind
,
buffer_free_callback
,
NULL
);
g_queue_clear
(
c
->
rewind
);
}
}
/**
...
...
@@ -201,8 +190,6 @@ input_curl_free(struct input_stream *is)
curl_multi_cleanup
(
c
->
multi
);
g_queue_free
(
c
->
buffers
);
if
(
c
->
rewind
!=
NULL
)
g_queue_free
(
c
->
rewind
);
g_free
(
c
->
url
);
g_free
(
c
);
...
...
@@ -322,7 +309,7 @@ fill_buffer(struct input_stream *is)
* Mark a part of the buffer object as consumed.
*/
static
struct
buffer
*
consume_buffer
(
struct
buffer
*
buffer
,
size_t
length
,
GQueue
*
rewind_buffers
)
consume_buffer
(
struct
buffer
*
buffer
,
size_t
length
)
{
assert
(
buffer
!=
NULL
);
assert
(
buffer
->
consumed
<
buffer
->
size
);
...
...
@@ -333,19 +320,14 @@ consume_buffer(struct buffer *buffer, size_t length, GQueue *rewind_buffers)
assert
(
buffer
->
consumed
==
buffer
->
size
);
if
(
rewind_buffers
!=
NULL
)
/* append this buffer to the rewind buffer list */
g_queue_push_tail
(
rewind_buffers
,
buffer
);
else
g_free
(
buffer
);
g_free
(
buffer
);
return
NULL
;
}
static
size_t
read_from_buffer
(
struct
icy_metadata
*
icy_metadata
,
GQueue
*
buffers
,
void
*
dest0
,
size_t
length
,
GQueue
*
rewind_buffers
)
void
*
dest0
,
size_t
length
)
{
struct
buffer
*
buffer
=
g_queue_pop_head
(
buffers
);
uint8_t
*
dest
=
dest0
;
...
...
@@ -364,7 +346,7 @@ read_from_buffer(struct icy_metadata *icy_metadata, GQueue *buffers,
if
(
chunk
>
0
)
{
memcpy
(
dest
,
buffer
->
data
+
buffer
->
consumed
,
chunk
);
buffer
=
consume_buffer
(
buffer
,
chunk
,
rewind_buffers
);
buffer
=
consume_buffer
(
buffer
,
chunk
);
nbytes
+=
chunk
;
dest
+=
chunk
;
...
...
@@ -379,7 +361,7 @@ read_from_buffer(struct icy_metadata *icy_metadata, GQueue *buffers,
chunk
=
icy_meta
(
icy_metadata
,
buffer
->
data
+
buffer
->
consumed
,
length
);
if
(
chunk
>
0
)
{
buffer
=
consume_buffer
(
buffer
,
chunk
,
rewind_buffers
);
buffer
=
consume_buffer
(
buffer
,
chunk
);
length
-=
chunk
;
...
...
@@ -418,31 +400,9 @@ input_curl_read(struct input_stream *is, void *ptr, size_t size)
{
struct
input_curl
*
c
=
is
->
data
;
bool
success
;
GQueue
*
rewind_buffers
;
size_t
nbytes
=
0
;
char
*
dest
=
ptr
;
#ifndef NDEBUG
if
(
c
->
rewind
!=
NULL
&&
(
!
g_queue_is_empty
(
c
->
rewind
)
||
is
->
offset
==
0
))
{
off_t
offset
=
0
;
struct
buffer
*
buffer
;
for
(
GList
*
list
=
g_queue_peek_head_link
(
c
->
rewind
);
list
!=
NULL
;
list
=
g_list_next
(
list
))
{
buffer
=
list
->
data
;
offset
+=
buffer
->
consumed
;
assert
(
offset
<=
is
->
offset
);
}
buffer
=
g_queue_peek_head
(
c
->
buffers
);
if
(
buffer
!=
NULL
)
offset
+=
buffer
->
consumed
;
assert
(
offset
==
is
->
offset
);
}
#endif
do
{
/* fill the buffer */
...
...
@@ -452,19 +412,9 @@ input_curl_read(struct input_stream *is, void *ptr, size_t size)
/* send buffer contents */
if
(
c
->
rewind
!=
NULL
&&
(
!
g_queue_is_empty
(
c
->
rewind
)
||
is
->
offset
==
0
))
/* at the beginning or already writing the rewind
buffer list */
rewind_buffers
=
c
->
rewind
;
else
/* we don't need the rewind buffers anymore */
rewind_buffers
=
NULL
;
while
(
size
>
0
&&
!
g_queue_is_empty
(
c
->
buffers
))
{
size_t
copy
=
read_from_buffer
(
&
c
->
icy_metadata
,
c
->
buffers
,
dest
+
nbytes
,
size
,
rewind_buffers
);
dest
+
nbytes
,
size
);
nbytes
+=
copy
;
size
-=
copy
;
...
...
@@ -476,33 +426,6 @@ input_curl_read(struct input_stream *is, void *ptr, size_t size)
is
->
offset
+=
(
off_t
)
nbytes
;
#ifndef NDEBUG
if
(
rewind_buffers
!=
NULL
)
{
off_t
offset
=
0
;
struct
buffer
*
buffer
;
for
(
GList
*
list
=
g_queue_peek_head_link
(
c
->
rewind
);
list
!=
NULL
;
list
=
g_list_next
(
list
))
{
buffer
=
list
->
data
;
offset
+=
buffer
->
consumed
;
assert
(
offset
<=
is
->
offset
);
}
buffer
=
g_queue_peek_head
(
c
->
buffers
);
if
(
buffer
!=
NULL
)
offset
+=
buffer
->
consumed
;
assert
(
offset
==
is
->
offset
);
}
#endif
if
(
rewind_buffers
!=
NULL
&&
is
->
offset
>
max_rewind_size
)
{
/* drop the rewind buffer, it has grown too large */
g_queue_foreach
(
c
->
rewind
,
buffer_free_callback
,
NULL
);
g_queue_clear
(
c
->
rewind
);
}
return
nbytes
;
}
...
...
@@ -635,15 +558,6 @@ input_curl_headerfunction(void *ptr, size_t size, size_t nmemb, void *stream)
/* a stream with icy-metadata is not
seekable */
is
->
seekable
=
false
;
if
(
c
->
rewind
!=
NULL
)
{
/* rewinding with icy-metadata is too
hairy for me .. */
assert
(
g_queue_is_empty
(
c
->
rewind
));
g_queue_free
(
c
->
rewind
);
c
->
rewind
=
NULL
;
}
}
}
...
...
@@ -732,6 +646,18 @@ input_curl_easy_init(struct input_stream *is)
return
true
;
}
void
input_curl_reinit
(
struct
input_stream
*
is
)
{
struct
input_curl
*
c
=
is
->
data
;
assert
(
is
->
plugin
==
&
input_plugin_curl
);
assert
(
c
->
easy
!=
NULL
);
curl_easy_setopt
(
c
->
easy
,
CURLOPT_WRITEHEADER
,
is
);
curl_easy_setopt
(
c
->
easy
,
CURLOPT_WRITEDATA
,
is
);
}
static
bool
input_curl_send_request
(
struct
input_curl
*
c
)
{
...
...
@@ -752,72 +678,6 @@ input_curl_send_request(struct input_curl *c)
}
static
bool
input_curl_can_rewind
(
struct
input_stream
*
is
)
{
struct
input_curl
*
c
=
is
->
data
;
struct
buffer
*
buffer
;
if
(
c
->
rewind
==
NULL
)
return
false
;
if
(
!
g_queue_is_empty
(
c
->
rewind
))
/* the rewind buffer hasn't been wiped yet */
return
true
;
if
(
g_queue_is_empty
(
c
->
buffers
))
/* there are no buffers at all - cheap rewind not
possible */
return
false
;
/* rewind is possible if this is the very first buffer of the
resource */
buffer
=
(
struct
buffer
*
)
g_queue_peek_head
(
c
->
buffers
);
return
(
off_t
)
buffer
->
consumed
==
is
->
offset
;
}
static
void
input_curl_rewind
(
struct
input_stream
*
is
)
{
struct
input_curl
*
c
=
is
->
data
;
#ifndef NDEBUG
off_t
offset
=
0
;
#endif
assert
(
c
->
rewind
!=
NULL
);
/* rewind the current buffer */
if
(
!
g_queue_is_empty
(
c
->
buffers
))
{
struct
buffer
*
buffer
=
(
struct
buffer
*
)
g_queue_peek_head
(
c
->
buffers
);
#ifndef NDEBUG
offset
+=
buffer
->
consumed
;
#endif
buffer
->
consumed
=
0
;
}
/* reset and move all rewind buffers back to the regular buffer list */
while
(
!
g_queue_is_empty
(
c
->
rewind
))
{
struct
buffer
*
buffer
=
(
struct
buffer
*
)
g_queue_pop_tail
(
c
->
rewind
);
#ifndef NDEBUG
offset
+=
buffer
->
consumed
;
#endif
buffer
->
consumed
=
0
;
g_queue_push_head
(
c
->
buffers
,
buffer
);
}
assert
(
offset
==
is
->
offset
);
is
->
offset
=
0
;
/* rewind the icy_metadata object */
icy_reset
(
&
c
->
icy_metadata
);
}
static
bool
input_curl_seek
(
struct
input_stream
*
is
,
off_t
offset
,
int
whence
)
{
struct
input_curl
*
c
=
is
->
data
;
...
...
@@ -825,17 +685,9 @@ input_curl_seek(struct input_stream *is, off_t offset, int whence)
assert
(
is
->
ready
);
if
(
whence
==
SEEK_SET
&&
offset
==
0
)
{
if
(
is
->
offset
==
0
)
/* no-op */
return
true
;
if
(
input_curl_can_rewind
(
is
))
{
/* we have enough rewind buffers left */
input_curl_rewind
(
is
);
return
true
;
}
}
if
(
whence
==
SEEK_SET
&&
offset
==
is
->
offset
)
/* no-op */
return
true
;
if
(
!
is
->
seekable
)
return
false
;
...
...
@@ -868,26 +720,16 @@ input_curl_seek(struct input_stream *is, off_t offset, int whence)
/* check if we can fast-forward the buffer */
while
(
offset
>
is
->
offset
&&
!
g_queue_is_empty
(
c
->
buffers
))
{
GQueue
*
rewind_buffers
;
struct
buffer
*
buffer
;
size_t
length
;
if
(
c
->
rewind
!=
NULL
&&
(
!
g_queue_is_empty
(
c
->
rewind
)
||
is
->
offset
==
0
))
/* at the beginning or already writing the rewind
buffer list */
rewind_buffers
=
c
->
rewind
;
else
/* we don't need the rewind buffers anymore */
rewind_buffers
=
NULL
;
buffer
=
(
struct
buffer
*
)
g_queue_pop_head
(
c
->
buffers
);
length
=
buffer
->
size
-
buffer
->
consumed
;
if
(
offset
-
is
->
offset
<
(
off_t
)
length
)
length
=
offset
-
is
->
offset
;
buffer
=
consume_buffer
(
buffer
,
length
,
rewind_buffers
);
buffer
=
consume_buffer
(
buffer
,
length
);
if
(
buffer
!=
NULL
)
g_queue_push_head
(
c
->
buffers
,
buffer
);
...
...
@@ -940,7 +782,6 @@ input_curl_open(struct input_stream *is, const char *url)
c
=
g_new0
(
struct
input_curl
,
1
);
c
->
url
=
g_strdup
(
url
);
c
->
buffers
=
g_queue_new
();
c
->
rewind
=
g_queue_new
();
is
->
plugin
=
&
input_plugin_curl
;
is
->
data
=
c
;
...
...
src/input/curl_input_plugin.h
View file @
2835998a
...
...
@@ -20,6 +20,16 @@
#ifndef MPD_INPUT_CURL_H
#define MPD_INPUT_CURL_H
struct
input_stream
;
extern
const
struct
input_plugin
input_plugin_curl
;
/**
* This is a workaround for an input_stream API deficiency; after
* exchanging the input_stream pointer in input_rewind_open(), this
* function is called to reinitialize CURL's data pointers.
*/
void
input_curl_reinit
(
struct
input_stream
*
is
);
#endif
src/input/file_input_plugin.c
View file @
2835998a
...
...
@@ -36,25 +36,14 @@ input_file_open(struct input_stream *is, const char *filename)
int
fd
,
ret
;
struct
stat
st
;
char
*
pathname
=
g_strdup
(
filename
);
if
(
filename
[
0
]
!=
'/'
)
{
g_free
(
pathname
);
return
false
;
}
if
(
stat
(
filename
,
&
st
)
<
0
)
{
char
*
slash
=
strrchr
(
pathname
,
'/'
);
*
slash
=
'\0'
;
}
fd
=
open
(
pathname
,
O_RDONLY
);
fd
=
open
(
filename
,
O_RDONLY
);
if
(
fd
<
0
)
{
is
->
error
=
errno
;
g_debug
(
"Failed to open
\"
%s
\"
: %s"
,
pathname
,
g_strerror
(
errno
));
g_free
(
pathname
);
filename
,
g_strerror
(
errno
));
return
false
;
}
...
...
@@ -64,15 +53,13 @@ input_file_open(struct input_stream *is, const char *filename)
if
(
ret
<
0
)
{
is
->
error
=
errno
;
close
(
fd
);
g_free
(
pathname
);
return
false
;
}
if
(
!
S_ISREG
(
st
.
st_mode
))
{
g_debug
(
"Not a regular file: %s"
,
path
name
);
g_debug
(
"Not a regular file: %s"
,
file
name
);
is
->
error
=
EINVAL
;
close
(
fd
);
g_free
(
pathname
);
return
false
;
}
...
...
@@ -86,8 +73,6 @@ input_file_open(struct input_stream *is, const char *filename)
is
->
data
=
GINT_TO_POINTER
(
fd
);
is
->
ready
=
true
;
g_free
(
pathname
);
return
true
;
}
...
...
src/input/lastfm_input_plugin.c
View file @
2835998a
...
...
@@ -112,7 +112,7 @@ lastfm_input_open(struct input_stream *is, const char *url)
#if GLIB_CHECK_VERSION(2,16,0)
q
=
g_uri_escape_string
(
lastfm_user
,
NULL
,
false
);
#else
q
=
g_strdup
(
lastfm_user
name
);
q
=
g_strdup
(
lastfm_user
);
#endif
#if GLIB_CHECK_VERSION(2,16,0)
...
...
src/input/rewind_input_plugin.c
0 → 100644
View file @
2835998a
/*
* Copyright (C) 2003-2009 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.
*/
#include "config.h"
#include "input/rewind_input_plugin.h"
#include "input/curl_input_plugin.h"
#include "input_plugin.h"
#include "tag.h"
#include <glib.h>
#include <assert.h>
#include <stdio.h>
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "input_rewind"
struct
input_rewind
{
struct
input_stream
input
;
/**
* The read position within the buffer. Undefined as long as
* reading_from_buffer() returns false.
*/
size_t
head
;
/**
* The write/append position within the buffer.
*/
size_t
tail
;
/**
* The size of this buffer is the maximum number of bytes
* which can be rewinded cheaply without passing the "seek"
* call to CURL.
*
* The origin of this buffer is always the beginning of the
* stream (offset 0).
*/
char
buffer
[
64
*
1024
];
};
/**
* Are we currently reading from the buffer, and does the buffer
* contain more data for the next read operation?
*/
static
bool
reading_from_buffer
(
const
struct
input_stream
*
is
)
{
const
struct
input_rewind
*
r
=
is
->
data
;
return
r
->
tail
>
0
&&
is
->
offset
<
r
->
input
.
offset
;
}
/**
* Copy public attributes from the underlying input stream to the
* "rewind" input stream. This function is called when a method of
* the underlying stream has returned, which may have modified these
* attributes.
*/
static
void
copy_attributes
(
struct
input_stream
*
dest
)
{
const
struct
input_rewind
*
r
=
dest
->
data
;
const
struct
input_stream
*
src
=
&
r
->
input
;
dest
->
ready
=
src
->
ready
;
dest
->
seekable
=
src
->
seekable
;
dest
->
error
=
src
->
error
;
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() */
dest
->
mime
=
g_strdup
(
src
->
mime
);
}
static
void
input_rewind_close
(
struct
input_stream
*
is
)
{
struct
input_rewind
*
r
=
is
->
data
;
input_stream_close
(
&
r
->
input
);
g_free
(
r
);
}
static
struct
tag
*
input_rewind_tag
(
struct
input_stream
*
is
)
{
struct
input_rewind
*
r
=
is
->
data
;
return
input_stream_tag
(
&
r
->
input
);
}
static
int
input_rewind_buffer
(
struct
input_stream
*
is
)
{
struct
input_rewind
*
r
=
is
->
data
;
int
ret
=
input_stream_buffer
(
&
r
->
input
);
if
(
ret
<
0
||
!
reading_from_buffer
(
is
))
copy_attributes
(
is
);
return
ret
;
}
static
size_t
input_rewind_read
(
struct
input_stream
*
is
,
void
*
ptr
,
size_t
size
)
{
struct
input_rewind
*
r
=
is
->
data
;
if
(
reading_from_buffer
(
is
))
{
/* buffered read */
assert
(
r
->
head
==
(
size_t
)
is
->
offset
);
assert
(
r
->
tail
==
(
size_t
)
r
->
input
.
offset
);
if
(
size
>
r
->
tail
-
r
->
head
)
size
=
r
->
tail
-
r
->
head
;
memcpy
(
ptr
,
r
->
buffer
+
r
->
head
,
size
);
r
->
head
+=
size
;
is
->
offset
+=
size
;
return
size
;
}
else
{
/* pass method call to underlying stream */
size_t
nbytes
=
input_stream_read
(
&
r
->
input
,
ptr
,
size
);
if
(
r
->
input
.
offset
>
(
off_t
)
sizeof
(
r
->
buffer
))
/* disable buffering */
r
->
tail
=
0
;
else
if
(
r
->
tail
==
(
size_t
)
is
->
offset
)
{
/* append to buffer */
memcpy
(
r
->
buffer
+
r
->
tail
,
ptr
,
nbytes
);
r
->
tail
+=
nbytes
;
assert
(
r
->
tail
==
(
size_t
)
r
->
input
.
offset
);
}
copy_attributes
(
is
);
return
nbytes
;
}
}
static
bool
input_rewind_eof
(
G_GNUC_UNUSED
struct
input_stream
*
is
)
{
struct
input_rewind
*
r
=
is
->
data
;
return
!
reading_from_buffer
(
is
)
&&
input_stream_eof
(
&
r
->
input
);
}
static
bool
input_rewind_seek
(
struct
input_stream
*
is
,
off_t
offset
,
int
whence
)
{
struct
input_rewind
*
r
=
is
->
data
;
assert
(
is
->
ready
);
if
(
whence
==
SEEK_SET
&&
r
->
tail
>
0
&&
offset
<=
(
off_t
)
r
->
tail
)
{
/* buffered seek */
assert
(
!
reading_from_buffer
(
is
)
||
r
->
head
==
(
size_t
)
is
->
offset
);
assert
(
r
->
tail
==
(
size_t
)
r
->
input
.
offset
);
r
->
head
=
(
size_t
)
offset
;
is
->
offset
=
offset
;
return
true
;
}
else
{
bool
success
=
input_stream_seek
(
&
r
->
input
,
offset
,
whence
);
copy_attributes
(
is
);
/* disable the buffer, because r->input has left the
buffered range now */
r
->
tail
=
0
;
return
success
;
}
}
static
const
struct
input_plugin
rewind_input_plugin
=
{
.
close
=
input_rewind_close
,
.
tag
=
input_rewind_tag
,
.
buffer
=
input_rewind_buffer
,
.
read
=
input_rewind_read
,
.
eof
=
input_rewind_eof
,
.
seek
=
input_rewind_seek
,
};
void
input_rewind_open
(
struct
input_stream
*
is
)
{
struct
input_rewind
*
c
;
assert
(
is
!=
NULL
);
assert
(
is
->
offset
==
0
);
if
(
is
->
plugin
!=
&
input_plugin_curl
)
/* due to limitations in the input_plugin API, we only
(explicitly) support the CURL input plugin */
return
;
c
=
g_new
(
struct
input_rewind
,
1
);
c
->
tail
=
0
;
/* move the CURL input stream to c->input */
c
->
input
=
*
is
;
input_curl_reinit
(
&
c
->
input
);
/* convert the existing input_stream pointer to a "rewind"
input stream */
is
->
plugin
=
&
rewind_input_plugin
;
is
->
data
=
c
;
}
src/input/rewind_input_plugin.h
0 → 100644
View file @
2835998a
/*
* Copyright (C) 2003-2009 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.
*/
/** \file
*
* A wrapper for an input_stream object which allows cheap buffered
* rewinding. This is useful while detecting the stream codec (let
* each decoder plugin peek a portion from the stream).
*/
#ifndef MPD_INPUT_REWIND_H
#define MPD_INPUT_REWIND_H
#include "config.h"
struct
input_stream
;
#ifdef HAVE_CURL
void
input_rewind_open
(
struct
input_stream
*
is
);
#else
static
inline
void
input_rewind_open
(
struct
input_stream
*
is
)
{
(
void
)
is
;
}
#endif
#endif
src/input_stream.c
View file @
2835998a
...
...
@@ -22,6 +22,7 @@
#include "conf.h"
#include "input/file_input_plugin.h"
#include "input/rewind_input_plugin.h"
#ifdef ENABLE_ARCHIVE
#include "input/archive_input_plugin.h"
...
...
@@ -131,6 +132,8 @@ input_stream_open(struct input_stream *is, const char *url)
assert
(
is
->
plugin
->
eof
!=
NULL
);
assert
(
!
is
->
seekable
||
is
->
plugin
->
seek
!=
NULL
);
input_rewind_open
(
is
);
return
true
;
}
}
...
...
src/mapper.c
View file @
2835998a
...
...
@@ -221,14 +221,19 @@ map_spl_path(void)
char
*
map_spl_utf8_to_fs
(
const
char
*
name
)
{
char
*
filename
=
g_strconcat
(
name
,
PLAYLIST_FILE_SUFFIX
,
NULL
);
char
*
path
;
char
*
filename_utf8
,
*
filename_fs
,
*
path
;
if
(
playlist_dir
==
NULL
)
return
NULL
;
path
=
g_build_filename
(
playlist_dir
,
filename
,
NULL
);
g_free
(
filename
);
filename_utf8
=
g_strconcat
(
name
,
PLAYLIST_FILE_SUFFIX
,
NULL
);
filename_fs
=
utf8_to_fs_charset
(
filename_utf8
);
g_free
(
filename_utf8
);
if
(
filename_fs
==
NULL
)
return
NULL
;
path
=
g_build_filename
(
playlist_dir
,
filename_fs
,
NULL
);
g_free
(
filename_fs
);
return
path
;
}
src/mapper.h
View file @
2835998a
...
...
@@ -99,6 +99,8 @@ map_spl_path(void);
* Maps a playlist name (without the ".m3u" suffix) to a file system
* path. The return value is allocated on the heap and must be freed
* with g_free().
*
* @return the path in file system encoding, or NULL if mapping failed
*/
char
*
map_spl_utf8_to_fs
(
const
char
*
name
);
...
...
src/mixer_control.c
View file @
2835998a
...
...
@@ -62,6 +62,10 @@ mixer_free(struct mixer *mixer)
assert
(
mixer
->
plugin
!=
NULL
);
assert
(
mixer
->
mutex
!=
NULL
);
/* mixers with the "global" flag set might still be open at
this point (see mixer_auto_close()) */
mixer_close
(
mixer
);
g_mutex_free
(
mixer
->
mutex
);
mixer
->
plugin
->
finish
(
mixer
);
...
...
src/output_thread.c
View file @
2835998a
...
...
@@ -248,6 +248,15 @@ static gpointer audio_output_task(gpointer arg)
break
;
case
AO_COMMAND_PAUSE
:
if
(
!
ao
->
open
)
{
/* the output has failed after
audio_output_all_pause() has
submitted the PAUSE command; bail
out */
ao_command_finished
(
ao
);
break
;
}
ao_pause
(
ao
);
/* don't "break" here: this might cause
ao_play() to be called when command==CLOSE
...
...
src/playlist_save.c
View file @
2835998a
...
...
@@ -71,12 +71,15 @@ spl_save_queue(const char *name_utf8, const struct queue *queue)
char
*
path_fs
;
FILE
*
file
;
if
(
map_spl_path
()
==
NULL
)
return
PLAYLIST_RESULT_DISABLED
;
if
(
!
spl_valid_name
(
name_utf8
))
return
PLAYLIST_RESULT_BAD_NAME
;
path_fs
=
map_spl_utf8_to_fs
(
name_utf8
);
if
(
path_fs
==
NULL
)
return
PLAYLIST_RESULT_
DISABLED
;
return
PLAYLIST_RESULT_
BAD_NAME
;
if
(
g_file_test
(
path_fs
,
G_FILE_TEST_EXISTS
))
{
g_free
(
path_fs
);
...
...
src/queue.c
View file @
2835998a
...
...
@@ -45,14 +45,14 @@ queue_next_order(const struct queue *queue, unsigned order)
if
(
queue
->
single
)
{
if
(
queue
->
repeat
)
if
(
queue
->
repeat
&&
!
queue
->
consume
)
return
order
;
else
return
-
1
;
}
if
(
order
+
1
<
queue
->
length
)
return
order
+
1
;
else
if
(
queue
->
repeat
)
else
if
(
queue
->
repeat
&&
(
order
>
0
||
!
queue
->
consume
)
)
/* restart at first song */
return
0
;
else
...
...
src/song_save.c
View file @
2835998a
...
...
@@ -21,7 +21,6 @@
#include "song.h"
#include "tag_save.h"
#include "directory.h"
#include "path.h"
#include "tag.h"
#include <glib.h>
...
...
@@ -113,12 +112,15 @@ matchesAnMpdTagItemKey(char *buffer, enum tag_type *itemType)
void
readSongInfoIntoList
(
FILE
*
fp
,
struct
songvec
*
sv
,
struct
directory
*
parent
)
{
char
buffer
[
MPD_PATH_MAX
+
1024
];
enum
{
buffer_size
=
32768
,
};
char
*
buffer
=
g_malloc
(
buffer_size
);
struct
song
*
song
=
NULL
;
enum
tag_type
itemType
;
const
char
*
value
;
while
(
fgets
(
buffer
,
sizeof
(
buffer
)
,
fp
)
&&
while
(
fgets
(
buffer
,
buffer_size
,
fp
)
&&
!
g_str_has_prefix
(
buffer
,
SONG_END
))
{
g_strchomp
(
buffer
);
...
...
@@ -156,6 +158,8 @@ void readSongInfoIntoList(FILE *fp, struct songvec *sv,
g_error
(
"unknown line in db: %s"
,
buffer
);
}
g_free
(
buffer
);
if
(
song
)
insertSongIntoList
(
sv
,
song
);
}
src/sticker.c
View file @
2835998a
...
...
@@ -27,6 +27,10 @@
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "sticker"
#if SQLITE_VERSION_NUMBER < 3003009
#define sqlite3_prepare_v2 sqlite3_prepare
#endif
struct
sticker
{
GHashTable
*
table
;
};
...
...
src/stored_playlist.c
View file @
2835998a
...
...
@@ -152,9 +152,12 @@ spl_save(GPtrArray *list, const char *utf8path)
assert
(
utf8path
!=
NULL
);
if
(
map_spl_path
()
==
NULL
)
return
PLAYLIST_RESULT_DISABLED
;
path_fs
=
map_spl_utf8_to_fs
(
utf8path
);
if
(
path_fs
==
NULL
)
return
PLAYLIST_RESULT_
DISABLED
;
return
PLAYLIST_RESULT_
BAD_NAME
;
while
(
!
(
file
=
fopen
(
path_fs
,
"w"
))
&&
errno
==
EINTR
);
g_free
(
path_fs
);
...
...
@@ -178,7 +181,7 @@ spl_load(const char *utf8path)
char
buffer
[
MPD_PATH_MAX
];
char
*
path_fs
;
if
(
!
spl_valid_name
(
utf8path
))
if
(
!
spl_valid_name
(
utf8path
)
||
map_spl_path
()
==
NULL
)
return
NULL
;
path_fs
=
map_spl_utf8_to_fs
(
utf8path
);
...
...
@@ -299,12 +302,15 @@ spl_clear(const char *utf8path)
char
*
path_fs
;
FILE
*
file
;
if
(
map_spl_path
()
==
NULL
)
return
PLAYLIST_RESULT_DISABLED
;
if
(
!
spl_valid_name
(
utf8path
))
return
PLAYLIST_RESULT_BAD_NAME
;
path_fs
=
map_spl_utf8_to_fs
(
utf8path
);
if
(
path_fs
==
NULL
)
return
PLAYLIST_RESULT_
DISABLED
;
return
PLAYLIST_RESULT_
BAD_NAME
;
while
(
!
(
file
=
fopen
(
path_fs
,
"w"
))
&&
errno
==
EINTR
);
g_free
(
path_fs
);
...
...
@@ -323,9 +329,15 @@ spl_delete(const char *name_utf8)
char
*
path_fs
;
int
ret
;
if
(
map_spl_path
()
==
NULL
)
return
PLAYLIST_RESULT_DISABLED
;
if
(
!
spl_valid_name
(
name_utf8
))
return
PLAYLIST_RESULT_BAD_NAME
;
path_fs
=
map_spl_utf8_to_fs
(
name_utf8
);
if
(
path_fs
==
NULL
)
return
PLAYLIST_RESULT_
DISABLED
;
return
PLAYLIST_RESULT_
BAD_NAME
;
ret
=
unlink
(
path_fs
);
g_free
(
path_fs
);
...
...
@@ -370,12 +382,15 @@ spl_append_song(const char *utf8path, struct song *song)
struct
stat
st
;
char
*
path_fs
;
if
(
map_spl_path
()
==
NULL
)
return
PLAYLIST_RESULT_DISABLED
;
if
(
!
spl_valid_name
(
utf8path
))
return
PLAYLIST_RESULT_BAD_NAME
;
path_fs
=
map_spl_utf8_to_fs
(
utf8path
);
if
(
path_fs
==
NULL
)
return
PLAYLIST_RESULT_
DISABLED
;
return
PLAYLIST_RESULT_
BAD_NAME
;
while
(
!
(
file
=
fopen
(
path_fs
,
"a"
))
&&
errno
==
EINTR
);
g_free
(
path_fs
);
...
...
@@ -445,6 +460,9 @@ spl_rename(const char *utf8from, const char *utf8to)
char
*
from_path_fs
,
*
to_path_fs
;
static
enum
playlist_result
ret
;
if
(
map_spl_path
()
==
NULL
)
return
PLAYLIST_RESULT_DISABLED
;
if
(
!
spl_valid_name
(
utf8from
)
||
!
spl_valid_name
(
utf8to
))
return
PLAYLIST_RESULT_BAD_NAME
;
...
...
@@ -454,7 +472,7 @@ spl_rename(const char *utf8from, const char *utf8to)
if
(
from_path_fs
!=
NULL
&&
to_path_fs
!=
NULL
)
ret
=
spl_rename_internal
(
from_path_fs
,
to_path_fs
);
else
ret
=
PLAYLIST_RESULT_
DISABLED
;
ret
=
PLAYLIST_RESULT_
BAD_NAME
;
g_free
(
from_path_fs
);
g_free
(
to_path_fs
);
...
...
src/tag_id3.c
View file @
2835998a
...
...
@@ -90,7 +90,7 @@ static id3_utf8_t * processID3FieldString (int is_id3v1, const id3_ucs4_t *ucs4,
utf8
=
(
id3_utf8_t
*
)
g_convert_with_fallback
((
const
char
*
)
isostr
,
-
1
,
encoding
,
"utf-8"
,
"utf-8"
,
encoding
,
NULL
,
NULL
,
NULL
,
NULL
);
if
(
utf8
==
NULL
)
{
g_debug
(
"Unable to convert %s string to UTF-8: '%s'"
,
...
...
@@ -481,7 +481,7 @@ tag_id3_riff_aiff_load(FILE *file)
if
(
size
==
0
)
return
NULL
;
if
(
size
>
256
*
1024
)
if
(
size
>
4
*
1024
*
1024
)
/* too large, don't allocate so much memory */
return
NULL
;
...
...
src/update.c
View file @
2835998a
...
...
@@ -672,7 +672,11 @@ updateDirectory(struct directory *directory, const struct stat *st)
continue
;
utf8
=
fs_charset_to_utf8
(
ent
->
d_name
);
if
(
utf8
==
NULL
||
skip_symlink
(
directory
,
utf8
))
{
if
(
utf8
==
NULL
)
continue
;
if
(
skip_symlink
(
directory
,
utf8
))
{
delete_name_in
(
directory
,
utf8
);
g_free
(
utf8
);
continue
;
}
...
...
test/run_input.c
View file @
2835998a
...
...
@@ -17,11 +17,16 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include "input_stream.h"
#include "tag_pool.h"
#include "tag_save.h"
#include "conf.h"
#ifdef ENABLE_ARCHIVE
#include "archive_list.h"
#endif
#include <glib.h>
#include <unistd.h>
...
...
@@ -36,40 +41,17 @@ my_log_func(const gchar *log_domain, G_GNUC_UNUSED GLogLevelFlags log_level,
g_printerr
(
"%s
\n
"
,
message
);
}
int
main
(
int
argc
,
char
**
argv
)
static
int
dump_input_stream
(
struct
input_stream
*
is
)
{
struct
input_stream
is
;
bool
success
;
char
buffer
[
4096
];
size_t
num_read
;
ssize_t
num_written
;
if
(
argc
!=
2
)
{
g_printerr
(
"Usage: run_input URI
\n
"
);
return
1
;
}
/* initialize GLib */
g_thread_init
(
NULL
);
g_log_set_default_handler
(
my_log_func
,
NULL
);
/* initialize MPD */
/* wait until the stream becomes ready */
tag_pool_init
();
config_global_init
();
input_stream_global_init
();
/* open the stream and wait until it becomes ready */
success
=
input_stream_open
(
&
is
,
argv
[
1
]);
if
(
!
success
)
{
g_printerr
(
"input_stream_open() failed
\n
"
);
return
2
;
}
while
(
!
is
.
ready
)
{
int
ret
=
input_stream_buffer
(
&
is
);
while
(
!
is
->
ready
)
{
int
ret
=
input_stream_buffer
(
is
);
if
(
ret
<
0
)
/* error */
return
2
;
...
...
@@ -81,20 +63,20 @@ int main(int argc, char **argv)
/* print meta data */
if
(
is
.
mime
!=
NULL
)
g_printerr
(
"MIME type: %s
\n
"
,
is
.
mime
);
if
(
is
->
mime
!=
NULL
)
g_printerr
(
"MIME type: %s
\n
"
,
is
->
mime
);
/* read data and tags from the stream */
while
(
!
input_stream_eof
(
&
is
))
{
struct
tag
*
tag
=
input_stream_tag
(
&
is
);
while
(
!
input_stream_eof
(
is
))
{
struct
tag
*
tag
=
input_stream_tag
(
is
);
if
(
tag
!=
NULL
)
{
g_printerr
(
"Received a tag:
\n
"
);
tag_save
(
stderr
,
tag
);
tag_free
(
tag
);
}
num_read
=
input_stream_read
(
&
is
,
buffer
,
sizeof
(
buffer
));
num_read
=
input_stream_read
(
is
,
buffer
,
sizeof
(
buffer
));
if
(
num_read
==
0
)
break
;
...
...
@@ -103,12 +85,55 @@ int main(int argc, char **argv)
break
;
}
return
0
;
}
int
main
(
int
argc
,
char
**
argv
)
{
struct
input_stream
is
;
int
ret
;
if
(
argc
!=
2
)
{
g_printerr
(
"Usage: run_input URI
\n
"
);
return
1
;
}
/* initialize GLib */
g_thread_init
(
NULL
);
g_log_set_default_handler
(
my_log_func
,
NULL
);
/* initialize MPD */
tag_pool_init
();
config_global_init
();
#ifdef ENABLE_ARCHIVE
archive_plugin_init_all
();
#endif
input_stream_global_init
();
/* open the stream and dump it */
if
(
input_stream_open
(
&
is
,
argv
[
1
]))
{
ret
=
dump_input_stream
(
&
is
);
input_stream_close
(
&
is
);
}
else
{
g_printerr
(
"input_stream_open() failed
\n
"
);
ret
=
2
;
}
/* deinitialize everything */
input_stream_close
(
&
is
);
input_stream_global_finish
();
#ifdef ENABLE_ARCHIVE
archive_plugin_deinit_all
();
#endif
config_global_finish
();
tag_pool_deinit
();
return
0
;
return
ret
;
}
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