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
b2ec5d0f
Commit
b2ec5d0f
authored
Feb 12, 2018
by
Max Kellermann
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
decoder/HybridDSD: new decoder plugin for Hybrid DSD
parent
0c300bd4
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
283 additions
and
0 deletions
+283
-0
Makefile.am
Makefile.am
+2
-0
NEWS
NEWS
+1
-0
user.xml
doc/user.xml
+13
-0
DecoderList.cxx
src/decoder/DecoderList.cxx
+2
-0
HybridDsdDecoderPlugin.cxx
src/decoder/plugins/HybridDsdDecoderPlugin.cxx
+240
-0
HybridDsdDecoderPlugin.hxx
src/decoder/plugins/HybridDsdDecoderPlugin.hxx
+25
-0
No files found.
Makefile.am
View file @
b2ec5d0f
...
...
@@ -1074,6 +1074,8 @@ DECODER_LIBS = \
if
ENABLE_DSD
libdecoder_a_SOURCES
+=
\
src/decoder/plugins/HybridDsdDecoderPlugin.cxx
\
src/decoder/plugins/HybridDsdDecoderPlugin.hxx
\
src/decoder/plugins/DsdiffDecoderPlugin.cxx
\
src/decoder/plugins/DsdiffDecoderPlugin.hxx
\
src/decoder/plugins/DsfDecoderPlugin.cxx
\
...
...
NEWS
View file @
b2ec5d0f
...
...
@@ -12,6 +12,7 @@ ver 0.21 (not yet released)
- new tags "OriginalDate", "MUSICBRAINZ_WORKID"
* decoder
- gme: try loading m3u sidecar files
- hybrid_dsd: new decoder plugin
- pcm: support audio/L24 (RFC 3190)
* resampler
- soxr: flush resampler at end of song
...
...
doc/user.xml
View file @
b2ec5d0f
...
...
@@ -2762,6 +2762,19 @@ run</programlisting>
</informaltable>
</section>
<section
id=
"hybrid_dsd_decoder"
>
<title><varname>
hybrid_dsd
</varname></title>
<para>
Hybrid-DSD is a MP4 container file
(
<filename>
*.m4a
</filename>
) which contains both ALAC and
DSD data. It is disabled by default, and works only if you
explicitly enable it. Without this plugin, the ALAC parts
gets handled by the
<link
linkend=
"ffmpeg_decoder"
>
FFmpeg
decoder plugin
</link>
.
</para>
</section>
<section
id=
"mad_decoder"
>
<title><varname>
mad
</varname></title>
...
...
src/decoder/DecoderList.cxx
View file @
b2ec5d0f
...
...
@@ -26,6 +26,7 @@
#include "plugins/PcmDecoderPlugin.hxx"
#include "plugins/DsdiffDecoderPlugin.hxx"
#include "plugins/DsfDecoderPlugin.hxx"
#include "plugins/HybridDsdDecoderPlugin.hxx"
#include "plugins/FlacDecoderPlugin.h"
#include "plugins/OpusDecoderPlugin.h"
#include "plugins/VorbisDecoderPlugin.h"
...
...
@@ -73,6 +74,7 @@ const struct DecoderPlugin *const decoder_plugins[] = {
#ifdef ENABLE_DSD
&
dsdiff_decoder_plugin
,
&
dsf_decoder_plugin
,
&
hybrid_dsd_decoder_plugin
,
#endif
#ifdef ENABLE_FAAD
&
faad_decoder_plugin
,
...
...
src/decoder/plugins/HybridDsdDecoderPlugin.cxx
0 → 100644
View file @
b2ec5d0f
/*
* Copyright 2003-2017 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 "HybridDsdDecoderPlugin.hxx"
#include "../DecoderAPI.hxx"
#include "input/InputStream.hxx"
#include "system/ByteOrder.hxx"
#include "util/Domain.hxx"
#include "util/WritableBuffer.hxx"
#include "util/StaticFifoBuffer.hxx"
#include "Log.hxx"
#include <string.h>
static
constexpr
Domain
hybrid_dsd_domain
(
"hybrid_dsd"
);
namespace
{
static
bool
InitHybridDsdDecoder
(
const
ConfigBlock
&
block
)
{
if
(
block
.
GetBlockParam
(
"enabled"
)
==
nullptr
)
{
LogInfo
(
hybrid_dsd_domain
,
"The Hybrid DSD decoder is disabled because it was not explicitly enabled"
);
return
false
;
}
return
true
;
}
struct
UnsupportedFile
{};
struct
Mp4ChunkHeader
{
uint32_t
size
;
char
type
[
4
];
};
void
ReadFull
(
DecoderClient
&
client
,
InputStream
&
input
,
WritableBuffer
<
uint8_t
>
dest
)
{
while
(
!
dest
.
empty
())
{
size_t
nbytes
=
client
.
Read
(
input
,
dest
.
data
,
dest
.
size
);
if
(
nbytes
==
0
)
throw
UnsupportedFile
();
dest
.
skip_front
(
nbytes
);
}
}
void
ReadFull
(
DecoderClient
&
client
,
InputStream
&
input
,
WritableBuffer
<
void
>
dest
)
{
ReadFull
(
client
,
input
,
WritableBuffer
<
uint8_t
>::
FromVoid
(
dest
));
}
template
<
typename
T
>
T
ReadFullT
(
DecoderClient
&
client
,
InputStream
&
input
)
{
T
dest
;
ReadFull
(
client
,
input
,
WritableBuffer
<
void
>
(
&
dest
,
sizeof
(
dest
)));
return
dest
;
}
Mp4ChunkHeader
ReadHeader
(
DecoderClient
&
client
,
InputStream
&
input
)
{
return
ReadFullT
<
Mp4ChunkHeader
>
(
client
,
input
);
}
uint32_t
ReadBE32
(
DecoderClient
&
client
,
InputStream
&
input
)
{
return
FromBE32
(
ReadFullT
<
uint32_t
>
(
client
,
input
));
}
}
/* anonymous namespace */
static
std
::
pair
<
AudioFormat
,
offset_type
>
FindHybridDsdData
(
DecoderClient
&
client
,
InputStream
&
input
)
{
auto
audio_format
=
AudioFormat
::
Undefined
();
while
(
true
)
{
auto
header
=
ReadHeader
(
client
,
input
);
const
size_t
header_size
=
FromBE32
(
header
.
size
);
if
(
header_size
<
sizeof
(
header
))
throw
UnsupportedFile
();
size_t
remaining
=
header_size
-
sizeof
(
header
);
if
(
memcmp
(
header
.
type
,
"bphv"
,
4
)
==
0
)
{
/* ? */
if
(
remaining
!=
4
||
ReadBE32
(
client
,
input
)
!=
1
)
throw
UnsupportedFile
();
remaining
-=
4
;
audio_format
.
format
=
SampleFormat
::
DSD
;
}
else
if
(
memcmp
(
header
.
type
,
"bphc"
,
4
)
==
0
)
{
/* channel count */
if
(
remaining
!=
4
)
throw
UnsupportedFile
();
auto
channels
=
ReadBE32
(
client
,
input
);
remaining
-=
4
;
if
(
!
audio_valid_channel_count
(
channels
))
throw
UnsupportedFile
();
audio_format
.
channels
=
channels
;
}
else
if
(
memcmp
(
header
.
type
,
"bphr"
,
4
)
==
0
)
{
/* (bit) sample rate */
if
(
remaining
!=
4
)
throw
UnsupportedFile
();
auto
sample_rate
=
ReadBE32
(
client
,
input
)
/
8
;
remaining
-=
4
;
if
(
!
audio_valid_sample_rate
(
sample_rate
))
throw
UnsupportedFile
();
audio_format
.
sample_rate
=
sample_rate
;
}
else
if
(
memcmp
(
header
.
type
,
"bphf"
,
4
)
==
0
)
{
/* ? */
if
(
remaining
!=
4
||
ReadBE32
(
client
,
input
)
!=
0
)
throw
UnsupportedFile
();
remaining
-=
4
;
}
else
if
(
memcmp
(
header
.
type
,
"bphd"
,
4
)
==
0
)
{
/* the actual DSD data */
if
(
!
audio_format
.
IsValid
())
throw
UnsupportedFile
();
return
std
::
make_pair
(
audio_format
,
remaining
);
}
input
.
LockSkip
(
remaining
);
}
}
static
void
HybridDsdDecode
(
DecoderClient
&
client
,
InputStream
&
input
)
{
if
(
!
input
.
CheapSeeking
())
/* probe only if seeking is cheap, i.e. not for HTTP
streams */
return
;
offset_type
remaining_bytes
;
size_t
frame_size
;
try
{
auto
result
=
FindHybridDsdData
(
client
,
input
);
auto
duration
=
SignedSongTime
::
FromS
(
result
.
second
/
result
.
first
.
GetTimeToSize
());
client
.
Ready
(
result
.
first
,
/* TODO: implement seeking */
false
,
duration
);
frame_size
=
result
.
first
.
GetFrameSize
();
remaining_bytes
=
result
.
second
;
}
catch
(
UnsupportedFile
)
{
return
;
}
StaticFifoBuffer
<
uint8_t
,
16384
>
buffer
;
auto
cmd
=
client
.
GetCommand
();
while
(
remaining_bytes
>
0
)
{
switch
(
cmd
)
{
case
DecoderCommand
:
:
NONE
:
case
DecoderCommand
:
:
START
:
break
;
case
DecoderCommand
:
:
STOP
:
return
;
case
DecoderCommand
:
:
SEEK
:
// TODO: implement seeking
break
;
}
auto
w
=
buffer
.
Write
();
if
(
!
w
.
empty
())
{
if
(
remaining_bytes
<
(
1
<<
30ull
)
&&
w
.
size
>
size_t
(
remaining_bytes
))
w
.
size
=
remaining_bytes
;
const
size_t
nbytes
=
client
.
Read
(
input
,
w
.
data
,
w
.
size
);
if
(
nbytes
==
0
)
return
;
remaining_bytes
-=
nbytes
;
buffer
.
Append
(
nbytes
);
}
auto
r
=
buffer
.
Read
();
auto
n_frames
=
r
.
size
/
frame_size
;
if
(
n_frames
>
0
)
{
cmd
=
client
.
SubmitData
(
input
,
r
.
data
,
n_frames
*
frame_size
,
0
);
buffer
.
Consume
(
n_frames
*
frame_size
);
}
}
}
static
const
char
*
const
hybrid_dsd_suffixes
[]
=
{
"m4a"
,
nullptr
};
const
struct
DecoderPlugin
hybrid_dsd_decoder_plugin
=
{
"hybrid_dsd"
,
InitHybridDsdDecoder
,
nullptr
,
HybridDsdDecode
,
nullptr
,
nullptr
,
nullptr
,
nullptr
,
hybrid_dsd_suffixes
,
nullptr
,
};
src/decoder/plugins/HybridDsdDecoderPlugin.hxx
0 → 100644
View file @
b2ec5d0f
/*
* Copyright 2003-2018 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPD_DECODER_HYBRID_DSD_HXX
#define MPD_DECODER_HYBRID_DSD_HXX
extern
const
struct
DecoderPlugin
hybrid_dsd_decoder_plugin
;
#endif
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment