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
dc32d1f3
Commit
dc32d1f3
authored
Oct 27, 2012
by
Jurgen Kramer
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add tag support for DSD (DSDIFF & DSF) decoders
parent
cbdaa136
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
235 additions
and
3 deletions
+235
-3
dsdiff_decoder_plugin.c
src/decoder/dsdiff_decoder_plugin.c
+138
-0
dsdlib.c
src/decoder/dsdlib.c
+56
-0
dsdlib.h
src/decoder/dsdlib.h
+5
-0
dsf_decoder_plugin.c
src/decoder/dsf_decoder_plugin.c
+27
-2
tag_id3.c
src/tag_id3.c
+1
-1
tag_id3.h
src/tag_id3.h
+8
-0
No files found.
src/decoder/dsdiff_decoder_plugin.c
View file @
dc32d1f3
...
@@ -52,10 +52,23 @@ struct dsdiff_chunk_header {
...
@@ -52,10 +52,23 @@ struct dsdiff_chunk_header {
uint32_t
size_high
,
size_low
;
uint32_t
size_high
,
size_low
;
};
};
/** struct for DSDIFF native Artist and Title tags */
struct
dsdiff_native_tag
{
uint32_t
size
;
};
struct
dsdiff_metadata
{
struct
dsdiff_metadata
{
unsigned
sample_rate
,
channels
;
unsigned
sample_rate
,
channels
;
bool
bitreverse
;
bool
bitreverse
;
uint64_t
chunk_size
;
uint64_t
chunk_size
;
#ifdef HAVE_ID3TAG
goffset
id3_offset
;
uint64_t
id3_size
;
#endif
/** offset for artist tag */
goffset
diar_offset
;
/** offset for title tag */
goffset
diti_offset
;
};
};
static
bool
lsbitfirst
;
static
bool
lsbitfirst
;
...
@@ -187,6 +200,127 @@ dsdiff_read_prop(struct decoder *decoder, struct input_stream *is,
...
@@ -187,6 +200,127 @@ dsdiff_read_prop(struct decoder *decoder, struct input_stream *is,
return
dsdlib_skip_to
(
decoder
,
is
,
end_offset
);
return
dsdlib_skip_to
(
decoder
,
is
,
end_offset
);
}
}
static
void
dsdiff_handle_native_tag
(
struct
input_stream
*
is
,
const
struct
tag_handler
*
handler
,
void
*
handler_ctx
,
goffset
tagoffset
,
enum
tag_type
type
)
{
if
(
!
dsdlib_skip_to
(
NULL
,
is
,
tagoffset
))
return
;
struct
dsdiff_native_tag
metatag
;
if
(
!
dsdlib_read
(
NULL
,
is
,
&
metatag
,
sizeof
(
metatag
)))
return
;
uint32_t
length
=
GUINT32_FROM_BE
(
metatag
.
size
);
/* Check and limit size of the tag to prevent a stack overflow */
if
(
length
==
0
||
length
>
60
)
return
;
char
string
[
length
];
char
*
label
;
label
=
string
;
if
(
!
dsdlib_read
(
NULL
,
is
,
label
,
(
size_t
)
length
))
return
;
string
[
length
]
=
'\0'
;
tag_handler_invoke_tag
(
handler
,
handler_ctx
,
type
,
label
);
return
;
}
/**
* Read and parse additional metadata chunks for tagging purposes. By default
* dsdiff files only support equivalents for artist and title but some of the
* extract tools add an id3 tag to provide more tags. If such id3 is found
* this will be used for tagging otherwise the native tags (if any) will be
* used
*/
static
bool
dsdiff_read_metadata_extra
(
struct
decoder
*
decoder
,
struct
input_stream
*
is
,
struct
dsdiff_metadata
*
metadata
,
struct
dsdiff_chunk_header
*
chunk_header
,
const
struct
tag_handler
*
handler
,
void
*
handler_ctx
)
{
/* skip from DSD data to next chunk header */
if
(
!
dsdlib_skip
(
decoder
,
is
,
metadata
->
chunk_size
))
return
false
;
if
(
!
dsdiff_read_chunk_header
(
decoder
,
is
,
chunk_header
))
return
false
;
#ifdef HAVE_ID3TAG
metadata
->
id3_size
=
0
;
#endif
/* Now process all the remaining chunk headers in the stream
and record their position and size */
while
(
is
->
offset
<
is
->
size
)
{
uint64_t
chunk_size
=
dsdiff_chunk_size
(
chunk_header
);
/* DIIN chunk, is directly followed by other chunks */
if
(
dsdlib_id_equals
(
&
chunk_header
->
id
,
"DIIN"
))
chunk_size
=
0
;
/* DIAR chunk - DSDIFF native tag for Artist */
if
(
dsdlib_id_equals
(
&
chunk_header
->
id
,
"DIAR"
))
{
chunk_size
=
dsdiff_chunk_size
(
chunk_header
);
metadata
->
diar_offset
=
is
->
offset
;
}
/* DITI chunk - DSDIFF native tag for Title */
if
(
dsdlib_id_equals
(
&
chunk_header
->
id
,
"DITI"
))
{
chunk_size
=
dsdiff_chunk_size
(
chunk_header
);
metadata
->
diti_offset
=
is
->
offset
;
}
#ifdef HAVE_ID3TAG
/* 'ID3 ' chunk, offspec. Used by sacdextract */
if
(
dsdlib_id_equals
(
&
chunk_header
->
id
,
"ID3 "
))
{
chunk_size
=
dsdiff_chunk_size
(
chunk_header
);
metadata
->
id3_offset
=
is
->
offset
;
metadata
->
id3_size
=
chunk_size
;
}
#endif
if
(
chunk_size
!=
0
)
{
if
(
!
dsdlib_skip
(
decoder
,
is
,
chunk_size
))
break
;
}
if
(
is
->
offset
<
is
->
size
)
{
if
(
!
dsdiff_read_chunk_header
(
decoder
,
is
,
chunk_header
))
return
false
;
}
chunk_size
=
0
;
}
/* done processing chunk headers, process tags if any */
#ifdef HAVE_ID3TAG
if
(
metadata
->
id3_offset
!=
0
)
{
/* a ID3 tag has preference over the other tags, do not process
other tags if we have one */
dsdlib_tag_id3
(
is
,
handler
,
handler_ctx
,
metadata
->
id3_offset
);
return
true
;
}
#endif
if
(
metadata
->
diar_offset
!=
0
)
dsdiff_handle_native_tag
(
is
,
handler
,
handler_ctx
,
metadata
->
diar_offset
,
TAG_ARTIST
);
if
(
metadata
->
diti_offset
!=
0
)
dsdiff_handle_native_tag
(
is
,
handler
,
handler_ctx
,
metadata
->
diti_offset
,
TAG_TITLE
);
return
true
;
}
/**
/**
* Read and parse all metadata chunks at the beginning. Stop when the
* Read and parse all metadata chunks at the beginning. Stop when the
* first "DSD" chunk is seen, and return its header in the
* first "DSD" chunk is seen, and return its header in the
...
@@ -374,6 +508,10 @@ dsdiff_scan_stream(struct input_stream *is,
...
@@ -374,6 +508,10 @@ dsdiff_scan_stream(struct input_stream *is,
metadata
.
sample_rate
;
metadata
.
sample_rate
;
tag_handler_invoke_duration
(
handler
,
handler_ctx
,
songtime
);
tag_handler_invoke_duration
(
handler
,
handler_ctx
,
songtime
);
/* Read additional metadata and created tags if available */
dsdiff_read_metadata_extra
(
NULL
,
is
,
&
metadata
,
&
chunk_header
,
handler
,
handler_ctx
);
return
true
;
return
true
;
}
}
...
...
src/decoder/dsdlib.c
View file @
dc32d1f3
...
@@ -27,12 +27,18 @@
...
@@ -27,12 +27,18 @@
#include "dsf_decoder_plugin.h"
#include "dsf_decoder_plugin.h"
#include "decoder_api.h"
#include "decoder_api.h"
#include "util/bit_reverse.h"
#include "util/bit_reverse.h"
#include "tag_handler.h"
#include "tag_id3.h"
#include "dsdlib.h"
#include "dsdlib.h"
#include "dsdiff_decoder_plugin.h"
#include "dsdiff_decoder_plugin.h"
#include <unistd.h>
#include <unistd.h>
#include <stdio.h>
/* for SEEK_SET, SEEK_CUR */
#include <stdio.h>
/* for SEEK_SET, SEEK_CUR */
#ifdef HAVE_ID3TAG
#include <id3tag.h>
#endif
bool
bool
dsdlib_id_equals
(
const
struct
dsdlib_id
*
id
,
const
char
*
s
)
dsdlib_id_equals
(
const
struct
dsdlib_id
*
id
,
const
char
*
s
)
{
{
...
@@ -110,3 +116,53 @@ dsdlib_skip(struct decoder *decoder, struct input_stream *is,
...
@@ -110,3 +116,53 @@ dsdlib_skip(struct decoder *decoder, struct input_stream *is,
return
true
;
return
true
;
}
}
/**
* Add tags from ID3 tag. All tags commonly found in the ID3 tags of
* DSF and DSDIFF files are imported
*/
#ifdef HAVE_ID3TAG
void
dsdlib_tag_id3
(
struct
input_stream
*
is
,
const
struct
tag_handler
*
handler
,
void
*
handler_ctx
,
goffset
tagoffset
)
{
assert
(
tagoffset
>=
0
);
if
(
tagoffset
==
0
)
return
;
if
(
!
dsdlib_skip_to
(
NULL
,
is
,
tagoffset
))
return
;
struct
id3_tag
*
id3_tag
=
NULL
;
id3_length_t
count
;
/* Prevent broken files causing problems */
if
(
is
->
offset
>=
is
->
size
)
return
;
count
=
is
->
size
-
is
->
offset
;
/* Check and limit id3 tag size to prevent a stack overflow */
if
(
count
==
0
||
count
>
4096
)
return
;
id3_byte_t
dsdid3
[
count
];
id3_byte_t
*
dsdid3data
;
dsdid3data
=
dsdid3
;
if
(
!
dsdlib_read
(
NULL
,
is
,
dsdid3data
,
count
))
return
;
id3_tag
=
id3_tag_parse
(
dsdid3data
,
count
);
if
(
id3_tag
==
NULL
)
return
;
scan_id3_tag
(
id3_tag
,
handler
,
handler_ctx
);
id3_tag_delete
(
id3_tag
);
return
;
}
#endif
src/decoder/dsdlib.h
View file @
dc32d1f3
...
@@ -39,4 +39,9 @@ bool
...
@@ -39,4 +39,9 @@ bool
dsdlib_skip
(
struct
decoder
*
decoder
,
struct
input_stream
*
is
,
dsdlib_skip
(
struct
decoder
*
decoder
,
struct
input_stream
*
is
,
goffset
delta
);
goffset
delta
);
void
dsdlib_tag_id3
(
struct
input_stream
*
is
,
const
struct
tag_handler
*
handler
,
void
*
handler_ctx
,
goffset
tagoffset
);
#endif
#endif
src/decoder/dsf_decoder_plugin.c
View file @
dc32d1f3
...
@@ -45,6 +45,10 @@ struct dsf_metadata {
...
@@ -45,6 +45,10 @@ struct dsf_metadata {
unsigned
sample_rate
,
channels
;
unsigned
sample_rate
,
channels
;
bool
bitreverse
;
bool
bitreverse
;
uint64_t
chunk_size
;
uint64_t
chunk_size
;
#ifdef HAVE_ID3TAG
goffset
id3_offset
;
uint64_t
id3_size
;
#endif
};
};
struct
dsf_header
{
struct
dsf_header
{
...
@@ -57,6 +61,7 @@ struct dsf_header {
...
@@ -57,6 +61,7 @@ struct dsf_header {
/** pointer to id3v2 metadata, should be at the end of the file */
/** pointer to id3v2 metadata, should be at the end of the file */
uint32_t
pmeta_low
,
pmeta_high
;
uint32_t
pmeta_low
,
pmeta_high
;
};
};
/** DSF file fmt chunk */
/** DSF file fmt chunk */
struct
dsf_fmt_chunk
{
struct
dsf_fmt_chunk
{
...
@@ -109,6 +114,12 @@ dsf_read_metadata(struct decoder *decoder, struct input_stream *is,
...
@@ -109,6 +114,12 @@ dsf_read_metadata(struct decoder *decoder, struct input_stream *is,
if
(
sizeof
(
dsf_header
)
!=
chunk_size
)
if
(
sizeof
(
dsf_header
)
!=
chunk_size
)
return
false
;
return
false
;
#ifdef HAVE_ID3TAG
uint64_t
metadata_offset
;
metadata_offset
=
(((
uint64_t
)
GUINT32_FROM_LE
(
dsf_header
.
pmeta_high
))
<<
32
)
|
((
uint64_t
)
GUINT32_FROM_LE
(
dsf_header
.
pmeta_low
));
#endif
/* read the 'fmt ' chunk of the DSF file */
/* read the 'fmt ' chunk of the DSF file */
struct
dsf_fmt_chunk
dsf_fmt_chunk
;
struct
dsf_fmt_chunk
dsf_fmt_chunk
;
if
(
!
dsdlib_read
(
decoder
,
is
,
&
dsf_fmt_chunk
,
sizeof
(
dsf_fmt_chunk
))
||
if
(
!
dsdlib_read
(
decoder
,
is
,
&
dsf_fmt_chunk
,
sizeof
(
dsf_fmt_chunk
))
||
...
@@ -153,9 +164,19 @@ dsf_read_metadata(struct decoder *decoder, struct input_stream *is,
...
@@ -153,9 +164,19 @@ dsf_read_metadata(struct decoder *decoder, struct input_stream *is,
data_size
-=
sizeof
(
data_chunk
);
data_size
-=
sizeof
(
data_chunk
);
metadata
->
chunk_size
=
data_size
;
metadata
->
chunk_size
=
data_size
;
/* data_size cannot be bigger or equal to total file size */
if
(
data_size
>=
(
unsigned
)
is
->
size
)
return
false
;
metadata
->
channels
=
(
unsigned
)
dsf_fmt_chunk
.
channelnum
;
metadata
->
channels
=
(
unsigned
)
dsf_fmt_chunk
.
channelnum
;
metadata
->
sample_rate
=
samplefreq
;
metadata
->
sample_rate
=
samplefreq
;
#ifdef HAVE_ID3TAG
/* metada_offset cannot be bigger then or equal to total file size */
if
(
metadata_offset
>=
(
unsigned
)
is
->
size
)
metadata
->
id3_offset
=
0
;
else
metadata
->
id3_offset
=
(
goffset
)
metadata_offset
;
#endif
/* check bits per sample format, determine if bitreverse is needed */
/* check bits per sample format, determine if bitreverse is needed */
metadata
->
bitreverse
=
dsf_fmt_chunk
.
bitssample
==
1
;
metadata
->
bitreverse
=
dsf_fmt_chunk
.
bitssample
==
1
;
return
true
;
return
true
;
...
@@ -285,7 +306,7 @@ dsf_stream_decode(struct decoder *decoder, struct input_stream *is)
...
@@ -285,7 +306,7 @@ dsf_stream_decode(struct decoder *decoder, struct input_stream *is)
decoder_initialized
(
decoder
,
&
audio_format
,
false
,
songtime
);
decoder_initialized
(
decoder
,
&
audio_format
,
false
,
songtime
);
if
(
!
dsf_decode_chunk
(
decoder
,
is
,
metadata
.
channels
,
if
(
!
dsf_decode_chunk
(
decoder
,
is
,
metadata
.
channels
,
metadata
.
chunk_size
,
chunk_size
,
metadata
.
bitreverse
))
metadata
.
bitreverse
))
return
;
return
;
}
}
...
@@ -316,6 +337,10 @@ dsf_scan_stream(struct input_stream *is,
...
@@ -316,6 +337,10 @@ dsf_scan_stream(struct input_stream *is,
metadata
.
sample_rate
;
metadata
.
sample_rate
;
tag_handler_invoke_duration
(
handler
,
handler_ctx
,
songtime
);
tag_handler_invoke_duration
(
handler
,
handler_ctx
,
songtime
);
#ifdef HAVE_ID3TAG
/* Add available tags from the ID3 tag */
dsdlib_tag_id3
(
is
,
handler
,
handler_ctx
,
metadata
.
id3_offset
);
#endif
return
true
;
return
true
;
}
}
...
...
src/tag_id3.c
View file @
dc32d1f3
...
@@ -344,7 +344,7 @@ tag_id3_import_ufid(struct id3_tag *id3_tag,
...
@@ -344,7 +344,7 @@ tag_id3_import_ufid(struct id3_tag *id3_tag,
}
}
}
}
static
void
void
scan_id3_tag
(
struct
id3_tag
*
tag
,
scan_id3_tag
(
struct
id3_tag
*
tag
,
const
struct
tag_handler
*
handler
,
void
*
handler_ctx
)
const
struct
tag_handler
*
handler
,
void
*
handler_ctx
)
{
{
...
...
src/tag_id3.h
View file @
dc32d1f3
...
@@ -48,6 +48,14 @@ struct tag *tag_id3_import(struct id3_tag *);
...
@@ -48,6 +48,14 @@ struct tag *tag_id3_import(struct id3_tag *);
struct
id3_tag
*
struct
id3_tag
*
tag_id3_load
(
const
char
*
path_fs
,
GError
**
error_r
);
tag_id3_load
(
const
char
*
path_fs
,
GError
**
error_r
);
/**
* Import all tags from the provided id3_tag *tag
*
*/
void
scan_id3_tag
(
struct
id3_tag
*
tag
,
const
struct
tag_handler
*
handler
,
void
*
handler_ctx
);
#else
#else
static
inline
bool
static
inline
bool
...
...
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