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
e4bbc120
Commit
e4bbc120
authored
Oct 28, 2008
by
Max Kellermann
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
mp3: no CamelCase
Renamed all functions and variables. Also removed the mp3DecodeData typedef.
parent
1f7c53e6
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
253 additions
and
254 deletions
+253
-254
mp3_plugin.c
src/decoder/mp3_plugin.c
+253
-254
No files found.
src/decoder/mp3_plugin.c
View file @
e4bbc120
...
...
@@ -50,7 +50,7 @@ enum muteframe {
#define DEFAULT_GAPLESS_MP3_PLAYBACK 1
static
int
gapless
PlaybackEnabled
;
static
int
gapless
_playback
;
static
inline
int32_t
mad_fixed_to_24_sample
(
mad_fixed_t
sample
)
...
...
@@ -89,61 +89,61 @@ mad_fixed_to_24_buffer(int32_t *dest, const struct mad_synth *synth,
static
int
mp3_plugin_init
(
void
)
{
gaplessPlaybackEnabled
=
getBoolConfigParam
(
CONF_GAPLESS_MP3_PLAYBACK
,
1
);
if
(
gaplessPlaybackEnabled
==
CONF_BOOL_UNSET
)
gaplessPlaybackEnabled
=
DEFAULT_GAPLESS_MP3_PLAYBACK
;
gapless_playback
=
getBoolConfigParam
(
CONF_GAPLESS_MP3_PLAYBACK
,
1
);
if
(
gapless_playback
==
CONF_BOOL_UNSET
)
gapless_playback
=
DEFAULT_GAPLESS_MP3_PLAYBACK
;
return
1
;
}
#define MP3_DATA_OUTPUT_BUFFER_SIZE 2048
typedef
struct
_mp3DecodeD
ata
{
struct
mp3_d
ata
{
struct
mad_stream
stream
;
struct
mad_frame
frame
;
struct
mad_synth
synth
;
mad_timer_t
timer
;
unsigned
char
readB
uffer
[
READ_BUFFER_SIZE
];
int32_t
output
B
uffer
[
MP3_DATA_OUTPUT_BUFFER_SIZE
];
float
total
T
ime
;
float
elapsed
T
ime
;
enum
muteframe
mute
F
rame
;
long
*
frame
Offset
;
unsigned
char
input_b
uffer
[
READ_BUFFER_SIZE
];
int32_t
output
_b
uffer
[
MP3_DATA_OUTPUT_BUFFER_SIZE
];
float
total
_t
ime
;
float
elapsed
_t
ime
;
enum
muteframe
mute
_f
rame
;
long
*
frame
_offsets
;
mad_timer_t
*
times
;
unsigned
long
highest
F
rame
;
unsigned
long
max
F
rames
;
unsigned
long
current
F
rame
;
unsigned
int
drop
FramesAtStart
;
unsigned
int
drop
FramesAtEnd
;
unsigned
int
drop
SamplesAtStart
;
unsigned
int
drop
SamplesAtEnd
;
int
found
X
ing
;
int
found
FirstF
rame
;
int
decoded
FirstF
rame
;
unsigned
long
bit
R
ate
;
unsigned
long
highest
_f
rame
;
unsigned
long
max
_f
rames
;
unsigned
long
current
_f
rame
;
unsigned
int
drop
_start_frames
;
unsigned
int
drop
_end_frames
;
unsigned
int
drop
_start_samples
;
unsigned
int
drop
_end_samples
;
int
found
_x
ing
;
int
found
_first_f
rame
;
int
decoded
_first_f
rame
;
unsigned
long
bit
_r
ate
;
struct
decoder
*
decoder
;
struct
input_stream
*
in
S
tream
;
struct
input_stream
*
in
put_s
tream
;
enum
mad_layer
layer
;
}
mp3DecodeData
;
};
static
void
initMp3DecodeData
(
mp3DecodeData
*
data
,
struct
decoder
*
decoder
,
struct
input_stream
*
inStream
)
static
void
mp3_data_init
(
struct
mp3_data
*
data
,
struct
decoder
*
decoder
,
struct
input_stream
*
input_stream
)
{
data
->
mute
F
rame
=
MUTEFRAME_NONE
;
data
->
highest
F
rame
=
0
;
data
->
max
F
rames
=
0
;
data
->
frame
Offset
=
NULL
;
data
->
mute
_f
rame
=
MUTEFRAME_NONE
;
data
->
highest
_f
rame
=
0
;
data
->
max
_f
rames
=
0
;
data
->
frame
_offsets
=
NULL
;
data
->
times
=
NULL
;
data
->
current
F
rame
=
0
;
data
->
drop
FramesAtStart
=
0
;
data
->
drop
FramesAtEnd
=
0
;
data
->
drop
SamplesAtStart
=
0
;
data
->
drop
SamplesAtEnd
=
0
;
data
->
found
X
ing
=
0
;
data
->
found
FirstF
rame
=
0
;
data
->
decoded
FirstF
rame
=
0
;
data
->
current
_f
rame
=
0
;
data
->
drop
_start_frames
=
0
;
data
->
drop
_end_frames
=
0
;
data
->
drop
_start_samples
=
0
;
data
->
drop
_end_samples
=
0
;
data
->
found
_x
ing
=
0
;
data
->
found
_first_f
rame
=
0
;
data
->
decoded
_first_f
rame
=
0
;
data
->
decoder
=
decoder
;
data
->
in
Stream
=
inS
tream
;
data
->
in
put_stream
=
input_s
tream
;
data
->
layer
=
0
;
mad_stream_init
(
&
data
->
stream
);
...
...
@@ -153,61 +153,61 @@ static void initMp3DecodeData(mp3DecodeData * data, struct decoder *decoder,
mad_timer_reset
(
&
data
->
timer
);
}
static
int
seekMp3InputBuffer
(
mp3DecodeData
*
data
,
long
offset
)
static
int
mp3_seek
(
struct
mp3_data
*
data
,
long
offset
)
{
if
(
!
input_stream_seek
(
data
->
in
S
tream
,
offset
,
SEEK_SET
))
if
(
!
input_stream_seek
(
data
->
in
put_s
tream
,
offset
,
SEEK_SET
))
return
-
1
;
mad_stream_buffer
(
&
data
->
stream
,
data
->
readB
uffer
,
0
);
mad_stream_buffer
(
&
data
->
stream
,
data
->
input_b
uffer
,
0
);
(
data
->
stream
).
error
=
0
;
return
0
;
}
static
int
fillMp3InputBuffer
(
mp3DecodeData
*
data
)
static
int
mp3_fill_buffer
(
struct
mp3_data
*
data
)
{
size_t
readSize
;
size_t
remaining
;
size_t
readed
;
unsigned
char
*
readStart
;
if
((
data
->
stream
).
next_frame
!=
NULL
)
{
remaining
=
(
data
->
stream
).
bufend
-
(
data
->
stream
).
next_frame
;
memmove
(
data
->
readBuffer
,
(
data
->
stream
).
next_frame
,
remaining
);
readStart
=
(
data
->
readBuffer
)
+
remaining
;
readSize
=
READ_BUFFER_SIZE
-
remaining
;
size_t
remaining
,
length
;
unsigned
char
*
dest
;
if
(
data
->
stream
.
next_frame
!=
NULL
)
{
remaining
=
data
->
stream
.
bufend
-
data
->
stream
.
next_frame
;
memmove
(
data
->
input_buffer
,
data
->
stream
.
next_frame
,
remaining
);
dest
=
(
data
->
input_buffer
)
+
remaining
;
length
=
READ_BUFFER_SIZE
-
remaining
;
}
else
{
readSize
=
READ_BUFFER_SIZE
;
readStart
=
data
->
readBuffer
,
remaining
=
0
;
remaining
=
0
;
length
=
READ_BUFFER_SIZE
;
dest
=
data
->
input_buffer
;
}
/* we've exhausted the read buffer, so give up!, these potential
* mp3 frames are way too big, and thus unlikely to be mp3 frames */
if
(
readSize
==
0
)
if
(
length
==
0
)
return
-
1
;
readed
=
decoder_read
(
data
->
decoder
,
data
->
inStream
,
readStart
,
readSize
);
if
(
readed
==
0
)
length
=
decoder_read
(
data
->
decoder
,
data
->
input_stream
,
dest
,
length
);
if
(
length
==
0
)
return
-
1
;
mad_stream_buffer
(
&
data
->
stream
,
data
->
readBuffer
,
readed
+
remaining
);
mad_stream_buffer
(
&
data
->
stream
,
data
->
input_buffer
,
length
+
remaining
);
(
data
->
stream
).
error
=
0
;
return
0
;
}
#ifdef HAVE_ID3TAG
static
ReplayGainInfo
*
parse
Id3ReplayGainI
nfo
(
struct
id3_tag
*
tag
)
static
ReplayGainInfo
*
parse
_id3_replay_gain_i
nfo
(
struct
id3_tag
*
tag
)
{
int
i
;
char
*
key
;
char
*
value
;
struct
id3_frame
*
frame
;
int
found
=
0
;
ReplayGainInfo
*
replay
GainI
nfo
;
ReplayGainInfo
*
replay
_gain_i
nfo
;
replay
GainI
nfo
=
newReplayGainInfo
();
replay
_gain_i
nfo
=
newReplayGainInfo
();
for
(
i
=
0
;
(
frame
=
id3_tag_findframe
(
tag
,
"TXXX"
,
i
));
i
++
)
{
if
(
frame
->
nfields
<
3
)
...
...
@@ -221,16 +221,16 @@ static ReplayGainInfo *parseId3ReplayGainInfo(struct id3_tag *tag)
(
&
frame
->
fields
[
2
]));
if
(
strcasecmp
(
key
,
"replaygain_track_gain"
)
==
0
)
{
replay
GainI
nfo
->
trackGain
=
atof
(
value
);
replay
_gain_i
nfo
->
trackGain
=
atof
(
value
);
found
=
1
;
}
else
if
(
strcasecmp
(
key
,
"replaygain_album_gain"
)
==
0
)
{
replay
GainI
nfo
->
albumGain
=
atof
(
value
);
replay
_gain_i
nfo
->
albumGain
=
atof
(
value
);
found
=
1
;
}
else
if
(
strcasecmp
(
key
,
"replaygain_track_peak"
)
==
0
)
{
replay
GainI
nfo
->
trackPeak
=
atof
(
value
);
replay
_gain_i
nfo
->
trackPeak
=
atof
(
value
);
found
=
1
;
}
else
if
(
strcasecmp
(
key
,
"replaygain_album_peak"
)
==
0
)
{
replay
GainI
nfo
->
albumPeak
=
atof
(
value
);
replay
_gain_i
nfo
->
albumPeak
=
atof
(
value
);
found
=
1
;
}
...
...
@@ -239,22 +239,21 @@ static ReplayGainInfo *parseId3ReplayGainInfo(struct id3_tag *tag)
}
if
(
found
)
return
replay
GainI
nfo
;
freeReplayGainInfo
(
replay
GainI
nfo
);
return
replay
_gain_i
nfo
;
freeReplayGainInfo
(
replay
_gain_i
nfo
);
return
NULL
;
}
#endif
#ifdef HAVE_ID3TAG
static
void
mp3_parseId3Tag
(
mp3DecodeData
*
data
,
size_t
tagsize
,
struct
tag
**
mpdTag
,
ReplayGainInfo
**
replayGainInfo
)
static
void
mp3_parse_id3
(
struct
mp3_data
*
data
,
size_t
tagsize
,
struct
tag
**
mpd_tag
,
ReplayGainInfo
**
replay_gain_info_r
)
{
struct
id3_tag
*
id3
T
ag
=
NULL
;
struct
id3_tag
*
id3
_t
ag
=
NULL
;
id3_length_t
count
;
id3_byte_t
const
*
id3_data
;
id3_byte_t
*
allocated
=
NULL
;
struct
tag
*
tmpMpdTag
;
ReplayGainInfo
*
tmpReplayGainInfo
;
count
=
data
->
stream
.
bufend
-
data
->
stream
.
this_frame
;
...
...
@@ -272,7 +271,7 @@ static void mp3_parseId3Tag(mp3DecodeData * data, size_t tagsize,
while
(
count
<
tagsize
)
{
size_t
len
;
len
=
decoder_read
(
data
->
decoder
,
data
->
in
S
tream
,
len
=
decoder_read
(
data
->
decoder
,
data
->
in
put_s
tream
,
allocated
+
count
,
tagsize
-
count
);
if
(
len
==
0
)
break
;
...
...
@@ -288,29 +287,29 @@ static void mp3_parseId3Tag(mp3DecodeData * data, size_t tagsize,
id3_data
=
allocated
;
}
id3
T
ag
=
id3_tag_parse
(
id3_data
,
tagsize
);
if
(
!
id3Tag
)
id3
_t
ag
=
id3_tag_parse
(
id3_data
,
tagsize
);
if
(
id3_tag
==
NULL
)
goto
fail
;
if
(
mpd
T
ag
)
{
tmpMpdTag
=
tag_id3_import
(
id3T
ag
);
if
(
tmp
MpdTag
)
{
if
(
*
mpd
Tag
)
tag_free
(
*
mpd
T
ag
);
*
mpd
Tag
=
tmpMpdT
ag
;
if
(
mpd
_t
ag
)
{
struct
tag
*
tmp_tag
=
tag_id3_import
(
id3_t
ag
);
if
(
tmp
_tag
!=
NULL
)
{
if
(
*
mpd
_tag
!=
NULL
)
tag_free
(
*
mpd
_t
ag
);
*
mpd
_tag
=
tmp_t
ag
;
}
}
if
(
replay
GainInfo
)
{
tmpReplayGainInfo
=
parseId3ReplayGainInfo
(
id3T
ag
);
if
(
tmp
ReplayGainInfo
)
{
if
(
*
replay
GainInfo
)
freeReplayGainInfo
(
*
replay
GainInfo
);
*
replay
GainInfo
=
tmpReplayGainInfo
;
if
(
replay
_gain_info_r
)
{
ReplayGainInfo
*
tmp_rgi
=
parse_id3_replay_gain_info
(
id3_t
ag
);
if
(
tmp
_rgi
!=
NULL
)
{
if
(
*
replay
_gain_info_r
)
freeReplayGainInfo
(
*
replay
_gain_info_r
);
*
replay
_gain_info_r
=
tmp_rgi
;
}
}
id3_tag_delete
(
id3
T
ag
);
id3_tag_delete
(
id3
_t
ag
);
fail:
if
(
allocated
)
free
(
allocated
);
...
...
@@ -318,14 +317,14 @@ fail:
#endif
static
enum
mp3_action
decode
NextFrameHeader
(
mp3DecodeData
*
data
,
struct
tag
**
tag
,
ReplayGainInfo
**
replayGainInfo
)
decode
_next_frame_header
(
struct
mp3_data
*
data
,
struct
tag
**
tag
,
ReplayGainInfo
**
replay_gain_info_r
)
{
enum
mad_layer
layer
;
if
((
data
->
stream
).
buffer
==
NULL
||
(
data
->
stream
).
error
==
MAD_ERROR_BUFLEN
)
{
if
(
fillMp3InputB
uffer
(
data
)
<
0
)
{
if
(
mp3_fill_b
uffer
(
data
)
<
0
)
{
return
DECODE_BREAK
;
}
}
...
...
@@ -342,8 +341,8 @@ decodeNextFrameHeader(mp3DecodeData * data, struct tag ** tag,
if
(
tagsize
>
0
)
{
if
(
tag
&&
!
(
*
tag
))
{
mp3_parse
Id3Tag
(
data
,
(
size_t
)
tagsize
,
tag
,
replayGainInfo
);
mp3_parse
_id3
(
data
,
(
size_t
)
tagsize
,
tag
,
replay_gain_info_r
);
}
else
{
mad_stream_skip
(
&
(
data
->
stream
),
tagsize
);
...
...
@@ -382,11 +381,11 @@ decodeNextFrameHeader(mp3DecodeData * data, struct tag ** tag,
}
static
enum
mp3_action
decodeNextFrame
(
mp3DecodeData
*
data
)
decodeNextFrame
(
struct
mp3_data
*
data
)
{
if
((
data
->
stream
).
buffer
==
NULL
||
(
data
->
stream
).
error
==
MAD_ERROR_BUFLEN
)
{
if
(
fillMp3InputB
uffer
(
data
)
<
0
)
{
if
(
mp3_fill_b
uffer
(
data
)
<
0
)
{
return
DECODE_BREAK
;
}
}
...
...
@@ -458,10 +457,10 @@ struct lame {
char
encoder
[
10
];
/* 9 byte encoder name/version ("LAME3.97b") */
struct
version
version
;
/* struct containing just the version */
float
peak
;
/* replaygain peak */
float
track
Gain
;
/* replaygain track gain */
float
album
Gain
;
/* replaygain album gain */
int
encoder
Delay
;
/* # of added samples at start of mp3 */
int
encoder
Padding
;
/* # of added samples at end of mp3 */
float
track
_gain
;
/* replaygain track gain */
float
album
_gain
;
/* replaygain album gain */
int
encoder
_delay
;
/* # of added samples at start of mp3 */
int
encoder
_padding
;
/* # of added samples at end of mp3 */
int
crc
;
/* CRC of the first 190 bytes of this frame */
};
...
...
@@ -587,29 +586,29 @@ static int parse_lame(struct lame *lame, struct mad_bitptr *ptr, int *bitlen)
lame
->
peak
=
mad_f_todouble
(
mad_bit_read
(
ptr
,
32
)
<<
5
);
/* peak */
DEBUG
(
"LAME peak found: %f
\n
"
,
lame
->
peak
);
lame
->
track
G
ain
=
0
;
lame
->
track
_g
ain
=
0
;
name
=
mad_bit_read
(
ptr
,
3
);
/* gain name */
orig
=
mad_bit_read
(
ptr
,
3
);
/* gain originator */
sign
=
mad_bit_read
(
ptr
,
1
);
/* sign bit */
gain
=
mad_bit_read
(
ptr
,
9
);
/* gain*10 */
if
(
gain
&&
name
==
1
&&
orig
!=
0
)
{
lame
->
track
G
ain
=
((
sign
?
-
gain
:
gain
)
/
10
.
0
)
+
adj
;
DEBUG
(
"LAME track gain found: %f
\n
"
,
lame
->
track
G
ain
);
lame
->
track
_g
ain
=
((
sign
?
-
gain
:
gain
)
/
10
.
0
)
+
adj
;
DEBUG
(
"LAME track gain found: %f
\n
"
,
lame
->
track
_g
ain
);
}
/* tmz reports that this isn't currently written by any version of lame
* (as of 3.97). Since we have no way of testing it, don't use it.
* Wouldn't want to go blowing someone's ears just because we read it
* wrong. :P -- jat */
lame
->
album
G
ain
=
0
;
lame
->
album
_g
ain
=
0
;
#if 0
name = mad_bit_read(ptr, 3); /* gain name */
orig = mad_bit_read(ptr, 3); /* gain originator */
sign = mad_bit_read(ptr, 1); /* sign bit */
gain = mad_bit_read(ptr, 9); /* gain*10 */
if (gain && name == 2 && orig != 0) {
lame->album
G
ain = ((sign ? -gain : gain) / 10.0) + adj;
DEBUG("LAME album gain found: %f\n", lame->track
G
ain);
lame->album
_g
ain = ((sign ? -gain : gain) / 10.0) + adj;
DEBUG("LAME album gain found: %f\n", lame->track
_g
ain);
}
#else
mad_bit_read
(
ptr
,
16
);
...
...
@@ -617,11 +616,11 @@ static int parse_lame(struct lame *lame, struct mad_bitptr *ptr, int *bitlen)
mad_bit_read
(
ptr
,
16
);
lame
->
encoder
D
elay
=
mad_bit_read
(
ptr
,
12
);
lame
->
encoder
P
adding
=
mad_bit_read
(
ptr
,
12
);
lame
->
encoder
_d
elay
=
mad_bit_read
(
ptr
,
12
);
lame
->
encoder
_p
adding
=
mad_bit_read
(
ptr
,
12
);
DEBUG
(
"encoder delay is %i, encoder padding is %i
\n
"
,
lame
->
encoder
Delay
,
lame
->
encoderP
adding
);
lame
->
encoder
_delay
,
lame
->
encoder_p
adding
);
mad_bit_read
(
ptr
,
80
);
...
...
@@ -632,8 +631,9 @@ static int parse_lame(struct lame *lame, struct mad_bitptr *ptr, int *bitlen)
return
1
;
}
static
int
decodeFirstFrame
(
mp3DecodeData
*
data
,
struct
tag
**
tag
,
ReplayGainInfo
**
replayGainInfo
)
static
int
mp3_decode_first_frame
(
struct
mp3_data
*
data
,
struct
tag
**
tag
,
ReplayGainInfo
**
replay_gain_info_r
)
{
struct
decoder
*
decoder
=
data
->
decoder
;
struct
xing
xing
;
...
...
@@ -647,7 +647,7 @@ static int decodeFirstFrame(mp3DecodeData * data,
xing
.
flags
=
0
;
while
(
1
)
{
while
((
ret
=
decode
NextFrameHeader
(
data
,
tag
,
replayGainInfo
))
==
DECODE_CONT
&&
while
((
ret
=
decode
_next_frame_header
(
data
,
tag
,
replay_gain_info_r
))
==
DECODE_CONT
&&
(
!
decoder
||
decoder_get_command
(
decoder
)
==
DECODE_COMMAND_NONE
));
if
(
ret
==
DECODE_BREAK
||
(
decoder
&&
decoder_get_command
(
decoder
)
!=
DECODE_COMMAND_NONE
))
...
...
@@ -669,112 +669,111 @@ static int decodeFirstFrame(mp3DecodeData * data,
* Attempt to calulcate the length of the song from filesize
*/
{
off_t
offset
=
data
->
in
S
tream
->
offset
;
off_t
offset
=
data
->
in
put_s
tream
->
offset
;
mad_timer_t
duration
=
data
->
frame
.
header
.
duration
;
float
frameTime
=
((
float
)
mad_timer_count
(
duration
,
MAD_UNITS_MILLISECONDS
))
/
1000
;
float
frame_duration
=
((
float
)
mad_timer_count
(
duration
,
MAD_UNITS_MILLISECONDS
))
/
1000
;
if
(
data
->
stream
.
this_frame
!=
NULL
)
offset
-=
data
->
stream
.
bufend
-
data
->
stream
.
this_frame
;
else
offset
-=
data
->
stream
.
bufend
-
data
->
stream
.
buffer
;
if
(
data
->
in
S
tream
->
size
>=
offset
)
{
data
->
total
Time
=
((
data
->
inS
tream
->
size
-
offset
)
*
if
(
data
->
in
put_s
tream
->
size
>=
offset
)
{
data
->
total
_time
=
((
data
->
input_s
tream
->
size
-
offset
)
*
8
.
0
)
/
(
data
->
frame
).
header
.
bitrate
;
data
->
max
Frames
=
data
->
totalTime
/
frameTime
+
data
->
max
_frames
=
data
->
total_time
/
frame_duration
+
FRAMES_CUSHION
;
}
else
{
data
->
max
F
rames
=
FRAMES_CUSHION
;
data
->
total
T
ime
=
0
;
data
->
max
_f
rames
=
FRAMES_CUSHION
;
data
->
total
_t
ime
=
0
;
}
}
/*
* if an xing tag exists, use that!
*/
if
(
parse_xing
(
&
xing
,
&
ptr
,
&
bitlen
))
{
data
->
found
X
ing
=
1
;
data
->
mute
F
rame
=
MUTEFRAME_SKIP
;
data
->
found
_x
ing
=
1
;
data
->
mute
_f
rame
=
MUTEFRAME_SKIP
;
if
((
xing
.
flags
&
XING_FRAMES
)
&&
xing
.
frames
)
{
mad_timer_t
duration
=
data
->
frame
.
header
.
duration
;
mad_timer_multiply
(
&
duration
,
xing
.
frames
);
data
->
total
T
ime
=
((
float
)
mad_timer_count
(
duration
,
MAD_UNITS_MILLISECONDS
))
/
1000
;
data
->
max
F
rames
=
xing
.
frames
;
data
->
total
_t
ime
=
((
float
)
mad_timer_count
(
duration
,
MAD_UNITS_MILLISECONDS
))
/
1000
;
data
->
max
_f
rames
=
xing
.
frames
;
}
if
(
parse_lame
(
&
lame
,
&
ptr
,
&
bitlen
))
{
if
(
gapless
PlaybackEnabled
&&
data
->
in
S
tream
->
seekable
)
{
data
->
drop
SamplesAtStart
=
lame
.
encoderD
elay
+
if
(
gapless
_playback
&&
data
->
in
put_s
tream
->
seekable
)
{
data
->
drop
_start_samples
=
lame
.
encoder_d
elay
+
DECODERDELAY
;
data
->
drop
SamplesAtEnd
=
lame
.
encoderP
adding
;
data
->
drop
_end_samples
=
lame
.
encoder_p
adding
;
}
/* Album gain isn't currently used. See comment in
* parse_lame() for details. -- jat */
if
(
replay
GainInfo
&&
!*
replayGainInfo
&&
lame
.
track
G
ain
)
{
*
replay
GainInfo
=
newReplayGainInfo
();
(
*
replay
GainInfo
)
->
trackGain
=
lame
.
trackG
ain
;
(
*
replay
GainInfo
)
->
trackPeak
=
lame
.
peak
;
if
(
replay
_gain_info_r
&&
!*
replay_gain_info_r
&&
lame
.
track
_g
ain
)
{
*
replay
_gain_info_r
=
newReplayGainInfo
();
(
*
replay
_gain_info_r
)
->
trackGain
=
lame
.
track_g
ain
;
(
*
replay
_gain_info_r
)
->
trackPeak
=
lame
.
peak
;
}
}
}
if
(
!
data
->
max
F
rames
)
return
-
1
;
if
(
!
data
->
max
_f
rames
)
return
-
1
;
if
(
data
->
max
F
rames
>
8
*
1024
*
1024
)
{
if
(
data
->
max
_f
rames
>
8
*
1024
*
1024
)
{
ERROR
(
"mp3 file header indicates too many frames: %lu"
,
data
->
max
F
rames
);
data
->
max
_f
rames
);
return
-
1
;
}
data
->
frame
Offset
=
xmalloc
(
sizeof
(
long
)
*
data
->
maxF
rames
);
data
->
times
=
xmalloc
(
sizeof
(
mad_timer_t
)
*
data
->
max
F
rames
);
data
->
frame
_offsets
=
xmalloc
(
sizeof
(
long
)
*
data
->
max_f
rames
);
data
->
times
=
xmalloc
(
sizeof
(
mad_timer_t
)
*
data
->
max
_f
rames
);
return
0
;
}
static
void
mp3
DecodeDataFinalize
(
mp3DecodeData
*
data
)
static
void
mp3
_data_finish
(
struct
mp3_data
*
data
)
{
mad_synth_finish
(
&
data
->
synth
);
mad_frame_finish
(
&
data
->
frame
);
mad_stream_finish
(
&
data
->
stream
);
if
(
data
->
frame
Offset
)
free
(
data
->
frameOffset
);
if
(
data
->
frame
_offsets
)
free
(
data
->
frame_offsets
);
if
(
data
->
times
)
free
(
data
->
times
);
}
/* this is primarily used for getting total time for tags */
static
int
getMp3TotalT
ime
(
char
*
file
)
static
int
mp3_total_file_t
ime
(
char
*
file
)
{
struct
input_stream
in
S
tream
;
mp3DecodeD
ata
data
;
struct
input_stream
in
put_s
tream
;
struct
mp3_d
ata
data
;
int
ret
;
if
(
!
input_stream_open
(
&
in
S
tream
,
file
))
if
(
!
input_stream_open
(
&
in
put_s
tream
,
file
))
return
-
1
;
initMp3DecodeData
(
&
data
,
NULL
,
&
inS
tream
);
if
(
decodeFirstF
rame
(
&
data
,
NULL
,
NULL
)
<
0
)
mp3_data_init
(
&
data
,
NULL
,
&
input_s
tream
);
if
(
mp3_decode_first_f
rame
(
&
data
,
NULL
,
NULL
)
<
0
)
ret
=
-
1
;
else
ret
=
data
.
total
T
ime
+
0
.
5
;
mp3
DecodeDataFinalize
(
&
data
);
input_stream_close
(
&
in
S
tream
);
ret
=
data
.
total
_t
ime
+
0
.
5
;
mp3
_data_finish
(
&
data
);
input_stream_close
(
&
in
put_s
tream
);
return
ret
;
}
static
int
openMp3FromInputStream
(
struct
input_stream
*
inStream
,
mp3DecodeData
*
data
,
mp3_open
(
struct
input_stream
*
is
,
struct
mp3_data
*
data
,
struct
decoder
*
decoder
,
struct
tag
**
tag
,
ReplayGainInfo
**
replayGainInfo
)
ReplayGainInfo
**
replay_gain_info_r
)
{
initMp3DecodeData
(
data
,
decoder
,
inStream
);
mp3_data_init
(
data
,
decoder
,
is
);
*
tag
=
NULL
;
if
(
decodeFirstFrame
(
data
,
tag
,
replayGainInfo
)
<
0
)
{
mp3
DecodeDataFinalize
(
data
);
if
(
mp3_decode_first_frame
(
data
,
tag
,
replay_gain_info_r
)
<
0
)
{
mp3
_data_finish
(
data
);
if
(
tag
&&
*
tag
)
tag_free
(
*
tag
);
return
-
1
;
...
...
@@ -784,7 +783,7 @@ openMp3FromInputStream(struct input_stream *inStream, mp3DecodeData * data,
}
static
enum
mp3_action
mp3
Read
(
mp3DecodeData
*
data
,
ReplayGainInfo
**
replayGainInfo
)
mp3
_read
(
struct
mp3_data
*
data
,
ReplayGainInfo
**
replay_gain_info_r
)
{
struct
decoder
*
decoder
=
data
->
decoder
;
unsigned
int
pcm_length
,
max_samples
;
...
...
@@ -792,94 +791,94 @@ mp3Read(mp3DecodeData * data, ReplayGainInfo ** replayGainInfo)
int
ret
;
int
skip
;
if
(
data
->
current
Frame
>=
data
->
highestF
rame
)
{
if
(
data
->
current
_frame
>=
data
->
highest_f
rame
)
{
mad_timer_add
(
&
data
->
timer
,
(
data
->
frame
).
header
.
duration
);
data
->
bit
R
ate
=
(
data
->
frame
).
header
.
bitrate
;
if
(
data
->
current
Frame
>=
data
->
maxF
rames
)
{
data
->
current
Frame
=
data
->
maxF
rames
-
1
;
data
->
bit
_r
ate
=
(
data
->
frame
).
header
.
bitrate
;
if
(
data
->
current
_frame
>=
data
->
max_f
rames
)
{
data
->
current
_frame
=
data
->
max_f
rames
-
1
;
}
else
{
data
->
highest
F
rame
++
;
data
->
highest
_f
rame
++
;
}
data
->
frame
Offset
[
data
->
currentFrame
]
=
data
->
inS
tream
->
offset
;
data
->
frame
_offsets
[
data
->
current_frame
]
=
data
->
input_s
tream
->
offset
;
if
(
data
->
stream
.
this_frame
!=
NULL
)
{
data
->
frame
Offset
[
data
->
currentF
rame
]
-=
data
->
frame
_offsets
[
data
->
current_f
rame
]
-=
data
->
stream
.
bufend
-
data
->
stream
.
this_frame
;
}
else
{
data
->
frame
Offset
[
data
->
currentF
rame
]
-=
data
->
frame
_offsets
[
data
->
current_f
rame
]
-=
data
->
stream
.
bufend
-
data
->
stream
.
buffer
;
}
data
->
times
[
data
->
current
F
rame
]
=
data
->
timer
;
data
->
times
[
data
->
current
_f
rame
]
=
data
->
timer
;
}
else
{
data
->
timer
=
data
->
times
[
data
->
current
F
rame
];
data
->
timer
=
data
->
times
[
data
->
current
_f
rame
];
}
data
->
current
F
rame
++
;
data
->
elapsed
T
ime
=
data
->
current
_f
rame
++
;
data
->
elapsed
_t
ime
=
((
float
)
mad_timer_count
(
data
->
timer
,
MAD_UNITS_MILLISECONDS
))
/
1000
;
switch
(
data
->
mute
F
rame
)
{
switch
(
data
->
mute
_f
rame
)
{
case
MUTEFRAME_SKIP
:
data
->
mute
F
rame
=
MUTEFRAME_NONE
;
data
->
mute
_f
rame
=
MUTEFRAME_NONE
;
break
;
case
MUTEFRAME_SEEK
:
if
(
decoder_seek_where
(
decoder
)
<=
data
->
elapsed
T
ime
)
{
if
(
decoder_seek_where
(
decoder
)
<=
data
->
elapsed
_t
ime
)
{
decoder_clear
(
decoder
);
data
->
mute
F
rame
=
MUTEFRAME_NONE
;
data
->
mute
_f
rame
=
MUTEFRAME_NONE
;
decoder_command_finished
(
decoder
);
}
break
;
case
MUTEFRAME_NONE
:
mad_synth_frame
(
&
data
->
synth
,
&
data
->
frame
);
if
(
!
data
->
found
FirstF
rame
)
{
unsigned
int
samples
PerF
rame
=
(
data
->
synth
).
pcm
.
length
;
data
->
drop
FramesAtStart
=
data
->
dropSamplesAtStart
/
samplesPerF
rame
;
data
->
drop
FramesAtEnd
=
data
->
dropSamplesAtEnd
/
samplesPerF
rame
;
data
->
drop
SamplesAtStart
=
data
->
dropSamplesAtStart
%
samplesPerF
rame
;
data
->
drop
SamplesAtEnd
=
data
->
dropSamplesAtEnd
%
samplesPerF
rame
;
data
->
found
FirstF
rame
=
1
;
if
(
!
data
->
found
_first_f
rame
)
{
unsigned
int
samples
_per_f
rame
=
(
data
->
synth
).
pcm
.
length
;
data
->
drop
_start_frames
=
data
->
drop_start_samples
/
samples_per_f
rame
;
data
->
drop
_end_frames
=
data
->
drop_end_samples
/
samples_per_f
rame
;
data
->
drop
_start_samples
=
data
->
drop_start_samples
%
samples_per_f
rame
;
data
->
drop
_end_samples
=
data
->
drop_end_samples
%
samples_per_f
rame
;
data
->
found
_first_f
rame
=
1
;
}
if
(
data
->
drop
FramesAtStart
>
0
)
{
data
->
drop
FramesAtStart
--
;
if
(
data
->
drop
_start_frames
>
0
)
{
data
->
drop
_start_frames
--
;
break
;
}
else
if
((
data
->
drop
FramesAtEnd
>
0
)
&&
(
data
->
current
Frame
==
(
data
->
maxFrames
+
1
-
data
->
dropFramesAtEnd
)))
{
}
else
if
((
data
->
drop
_end_frames
>
0
)
&&
(
data
->
current
_frame
==
(
data
->
max_frames
+
1
-
data
->
drop_end_frames
)))
{
/* stop decoding, effectively dropping all remaining
* frames */
return
DECODE_BREAK
;
}
if
(
data
->
in
S
tream
->
meta_title
)
{
if
(
data
->
in
put_s
tream
->
meta_title
)
{
struct
tag
*
tag
=
tag_new
();
if
(
data
->
in
S
tream
->
meta_name
)
{
if
(
data
->
in
put_s
tream
->
meta_name
)
{
tag_add_item
(
tag
,
TAG_ITEM_NAME
,
data
->
in
S
tream
->
meta_name
);
data
->
in
put_s
tream
->
meta_name
);
}
tag_add_item
(
tag
,
TAG_ITEM_TITLE
,
data
->
in
S
tream
->
meta_title
);
free
(
data
->
in
S
tream
->
meta_title
);
data
->
in
S
tream
->
meta_title
=
NULL
;
data
->
in
put_s
tream
->
meta_title
);
free
(
data
->
in
put_s
tream
->
meta_title
);
data
->
in
put_s
tream
->
meta_title
=
NULL
;
tag_free
(
tag
);
}
if
(
!
data
->
decoded
FirstF
rame
)
{
i
=
data
->
drop
SamplesAtStart
;
data
->
decoded
FirstF
rame
=
1
;
if
(
!
data
->
decoded
_first_f
rame
)
{
i
=
data
->
drop
_start_samples
;
data
->
decoded
_first_f
rame
=
1
;
}
else
i
=
0
;
pcm_length
=
data
->
synth
.
pcm
.
length
;
if
(
data
->
drop
SamplesAtEnd
&&
(
data
->
current
Frame
==
data
->
maxFrames
-
data
->
dropFramesAtEnd
))
{
if
(
data
->
drop
SamplesAtEnd
>=
pcm_length
)
if
(
data
->
drop
_end_samples
&&
(
data
->
current
_frame
==
data
->
max_frames
-
data
->
drop_end_frames
))
{
if
(
data
->
drop
_end_samples
>=
pcm_length
)
pcm_length
=
0
;
else
pcm_length
-=
data
->
drop
SamplesAtEnd
;
pcm_length
-=
data
->
drop
_end_samples
;
}
max_samples
=
sizeof
(
data
->
output
B
uffer
)
/
sizeof
(
data
->
output
B
uffer
[
0
])
/
max_samples
=
sizeof
(
data
->
output
_b
uffer
)
/
sizeof
(
data
->
output
_b
uffer
[
0
])
/
MAD_NCHANNELS
(
&
(
data
->
frame
).
header
);
while
(
i
<
pcm_length
)
{
...
...
@@ -890,53 +889,52 @@ mp3Read(mp3DecodeData * data, ReplayGainInfo ** replayGainInfo)
i
+=
num_samples
;
mad_fixed_to_24_buffer
(
data
->
output
B
uffer
,
mad_fixed_to_24_buffer
(
data
->
output
_b
uffer
,
&
data
->
synth
,
i
-
num_samples
,
i
,
MAD_NCHANNELS
(
&
(
data
->
frame
).
header
));
num_samples
*=
MAD_NCHANNELS
(
&
(
data
->
frame
).
header
);
cmd
=
decoder_data
(
decoder
,
data
->
in
S
tream
,
data
->
in
S
tream
->
seekable
,
data
->
output
B
uffer
,
sizeof
(
data
->
output
B
uffer
[
0
])
*
num_samples
,
data
->
elapsed
T
ime
,
data
->
bit
R
ate
/
1000
,
(
replay
GainInfo
!=
NULL
)
?
*
replayGainInfo
:
NULL
);
cmd
=
decoder_data
(
decoder
,
data
->
in
put_s
tream
,
data
->
in
put_s
tream
->
seekable
,
data
->
output
_b
uffer
,
sizeof
(
data
->
output
_b
uffer
[
0
])
*
num_samples
,
data
->
elapsed
_t
ime
,
data
->
bit
_r
ate
/
1000
,
(
replay
_gain_info_r
!=
NULL
)
?
*
replay_gain_info_r
:
NULL
);
if
(
cmd
==
DECODE_COMMAND_STOP
)
return
DECODE_BREAK
;
}
if
(
data
->
drop
SamplesAtEnd
&&
(
data
->
current
Frame
==
data
->
maxFrames
-
data
->
dropFramesAtEnd
))
if
(
data
->
drop
_end_samples
&&
(
data
->
current
_frame
==
data
->
max_frames
-
data
->
drop_end_frames
))
/* stop decoding, effectively dropping
* all remaining samples */
return
DECODE_BREAK
;
if
(
decoder_get_command
(
decoder
)
==
DECODE_COMMAND_SEEK
&&
data
->
in
S
tream
->
seekable
)
{
data
->
in
put_s
tream
->
seekable
)
{
unsigned
long
j
=
0
;
data
->
mute
F
rame
=
MUTEFRAME_SEEK
;
while
(
j
<
data
->
highest
F
rame
&&
data
->
mute
_f
rame
=
MUTEFRAME_SEEK
;
while
(
j
<
data
->
highest
_f
rame
&&
decoder_seek_where
(
decoder
)
>
((
float
)
mad_timer_count
(
data
->
times
[
j
],
MAD_UNITS_MILLISECONDS
))
/
1000
)
{
j
++
;
}
if
(
j
<
data
->
highestFrame
)
{
if
(
seekMp3InputBuffer
(
data
,
data
->
frameOffset
[
j
])
==
0
)
{
if
(
j
<
data
->
highest_frame
)
{
if
(
mp3_seek
(
data
,
data
->
frame_offsets
[
j
])
==
0
)
{
decoder_clear
(
decoder
);
data
->
current
F
rame
=
j
;
data
->
current
_f
rame
=
j
;
decoder_command_finished
(
decoder
);
}
else
decoder_seek_error
(
decoder
);
data
->
mute
F
rame
=
MUTEFRAME_NONE
;
data
->
mute
_f
rame
=
MUTEFRAME_NONE
;
}
}
else
if
(
decoder_get_command
(
decoder
)
==
DECODE_COMMAND_SEEK
&&
!
data
->
in
S
tream
->
seekable
)
{
!
data
->
in
put_s
tream
->
seekable
)
{
decoder_seek_error
(
decoder
);
}
}
...
...
@@ -944,14 +942,14 @@ mp3Read(mp3DecodeData * data, ReplayGainInfo ** replayGainInfo)
while
(
1
)
{
skip
=
0
;
while
((
ret
=
decode
NextFrameH
eader
(
data
,
NULL
,
replayGainInfo
))
==
DECODE_CONT
decode
_next_frame_h
eader
(
data
,
NULL
,
replay_gain_info_r
))
==
DECODE_CONT
&&
decoder_get_command
(
decoder
)
==
DECODE_COMMAND_NONE
)
;
if
(
ret
==
DECODE_BREAK
||
decoder_get_command
(
decoder
)
!=
DECODE_COMMAND_NONE
)
break
;
else
if
(
ret
==
DECODE_SKIP
)
skip
=
1
;
if
(
data
->
mute
F
rame
==
MUTEFRAME_NONE
)
{
if
(
data
->
mute
_f
rame
==
MUTEFRAME_NONE
)
{
while
((
ret
=
decodeNextFrame
(
data
))
==
DECODE_CONT
&&
decoder_get_command
(
decoder
)
==
DECODE_COMMAND_NONE
)
;
if
(
ret
==
DECODE_BREAK
||
...
...
@@ -977,8 +975,7 @@ mp3Read(mp3DecodeData * data, ReplayGainInfo ** replayGainInfo)
return
ret
;
}
static
void
initAudioFormatFromMp3DecodeData
(
mp3DecodeData
*
data
,
struct
audio_format
*
af
)
static
void
mp3_audio_format
(
struct
mp3_data
*
data
,
struct
audio_format
*
af
)
{
af
->
bits
=
24
;
af
->
sample_rate
=
(
data
->
frame
).
header
.
samplerate
;
...
...
@@ -986,15 +983,15 @@ static void initAudioFormatFromMp3DecodeData(mp3DecodeData * data,
}
static
int
mp3_decode
(
struct
decoder
*
decoder
,
struct
input_stream
*
inS
tream
)
mp3_decode
(
struct
decoder
*
decoder
,
struct
input_stream
*
input_s
tream
)
{
mp3DecodeD
ata
data
;
struct
mp3_d
ata
data
;
struct
tag
*
tag
=
NULL
;
ReplayGainInfo
*
replay
GainI
nfo
=
NULL
;
ReplayGainInfo
*
replay
_gain_i
nfo
=
NULL
;
struct
audio_format
audio_format
;
if
(
openMp3FromInputStream
(
inS
tream
,
&
data
,
decoder
,
&
tag
,
&
replayGainI
nfo
)
<
0
)
{
if
(
mp3_open
(
input_s
tream
,
&
data
,
decoder
,
&
tag
,
&
replay_gain_i
nfo
)
<
0
)
{
if
(
decoder_get_command
(
decoder
)
==
DECODE_COMMAND_NONE
)
{
ERROR
(
"Input does not appear to be a mp3 bit stream.
\n
"
);
...
...
@@ -1003,67 +1000,69 @@ mp3_decode(struct decoder * decoder, struct input_stream *inStream)
return
0
;
}
initAudioFormatFromMp3DecodeData
(
&
data
,
&
audio_format
);
mp3_audio_format
(
&
data
,
&
audio_format
);
if
(
in
S
tream
->
meta_title
)
{
if
(
in
put_s
tream
->
meta_title
)
{
if
(
tag
)
tag_free
(
tag
);
tag
=
tag_new
();
tag_add_item
(
tag
,
TAG_ITEM_TITLE
,
inStream
->
meta_title
);
free
(
inStream
->
meta_title
);
inStream
->
meta_title
=
NULL
;
if
(
inStream
->
meta_name
)
{
tag_add_item
(
tag
,
TAG_ITEM_NAME
,
inStream
->
meta_name
);
tag_add_item
(
tag
,
TAG_ITEM_TITLE
,
input_stream
->
meta_title
);
free
(
input_stream
->
meta_title
);
input_stream
->
meta_title
=
NULL
;
if
(
input_stream
->
meta_name
)
{
tag_add_item
(
tag
,
TAG_ITEM_NAME
,
input_stream
->
meta_name
);
}
tag_free
(
tag
);
}
else
if
(
tag
)
{
if
(
in
S
tream
->
meta_name
)
{
if
(
in
put_s
tream
->
meta_name
)
{
tag_clear_items_by_type
(
tag
,
TAG_ITEM_NAME
);
tag_add_item
(
tag
,
TAG_ITEM_NAME
,
inStream
->
meta_name
);
tag_add_item
(
tag
,
TAG_ITEM_NAME
,
input_stream
->
meta_name
);
}
tag_free
(
tag
);
}
else
if
(
in
S
tream
->
meta_name
)
{
}
else
if
(
in
put_s
tream
->
meta_name
)
{
tag
=
tag_new
();
if
(
inStream
->
meta_name
)
{
tag_add_item
(
tag
,
TAG_ITEM_NAME
,
inStream
->
meta_name
);
if
(
input_stream
->
meta_name
)
{
tag_add_item
(
tag
,
TAG_ITEM_NAME
,
input_stream
->
meta_name
);
}
tag_free
(
tag
);
}
decoder_initialized
(
decoder
,
&
audio_format
,
data
.
total
T
ime
);
decoder_initialized
(
decoder
,
&
audio_format
,
data
.
total
_t
ime
);
while
(
mp3
Read
(
&
data
,
&
replayGainI
nfo
)
!=
DECODE_BREAK
)
;
while
(
mp3
_read
(
&
data
,
&
replay_gain_i
nfo
)
!=
DECODE_BREAK
)
;
if
(
replay
GainI
nfo
)
freeReplayGainInfo
(
replay
GainI
nfo
);
if
(
replay
_gain_i
nfo
)
freeReplayGainInfo
(
replay
_gain_i
nfo
);
if
(
decoder_get_command
(
decoder
)
==
DECODE_COMMAND_SEEK
&&
data
.
mute
F
rame
==
MUTEFRAME_SEEK
)
{
data
.
mute
_f
rame
==
MUTEFRAME_SEEK
)
{
decoder_clear
(
decoder
);
decoder_command_finished
(
decoder
);
}
decoder_flush
(
decoder
);
mp3
DecodeDataFinalize
(
&
data
);
mp3
_data_finish
(
&
data
);
return
0
;
}
static
struct
tag
*
mp3_tag
D
up
(
char
*
file
)
static
struct
tag
*
mp3_tag
_d
up
(
char
*
file
)
{
struct
tag
*
ret
=
NULL
;
int
total_time
;
ret
=
tag_id3_load
(
file
);
total_time
=
getMp3TotalTime
(
file
);
total_time
=
mp3_total_file_time
(
file
);
if
(
total_time
>=
0
)
{
if
(
!
ret
)
ret
=
tag_new
();
ret
->
time
=
total_time
;
}
else
{
DEBUG
(
"mp3_tag
D
up: Failed to get total song time from: %s
\n
"
,
DEBUG
(
"mp3_tag
_d
up: Failed to get total song time from: %s
\n
"
,
file
);
}
...
...
@@ -1071,14 +1070,14 @@ static struct tag *mp3_tagDup(char *file)
}
static
const
char
*
mp3_suffixes
[]
=
{
"mp3"
,
"mp2"
,
NULL
};
static
const
char
*
mp3_mime
T
ypes
[]
=
{
"audio/mpeg"
,
NULL
};
static
const
char
*
mp3_mime
_t
ypes
[]
=
{
"audio/mpeg"
,
NULL
};
struct
decoder_plugin
mp3Plugin
=
{
.
name
=
"mp3"
,
.
init
=
mp3_plugin_init
,
.
stream_decode
=
mp3_decode
,
.
tag_dup
=
mp3_tag
D
up
,
.
tag_dup
=
mp3_tag
_d
up
,
.
stream_types
=
INPUT_PLUGIN_STREAM_FILE
|
INPUT_PLUGIN_STREAM_URL
,
.
suffixes
=
mp3_suffixes
,
.
mime_types
=
mp3_mime
T
ypes
.
mime_types
=
mp3_mime
_t
ypes
};
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