2 * Direct Stream Digital (DSD) decoder
3 * based on BSD licensed dsd2pcm by Sebastian Gesemann
4 * Copyright (c) 2009, 2011 Sebastian Gesemann. All rights reserved.
5 * Copyright (c) 2014 Peter Ross
7 * This file is part of FFmpeg.
9 * FFmpeg is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * FFmpeg is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with FFmpeg; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26 * Direct Stream Digital (DSD) decoder
29 #include "libavcodec/internal.h"
30 #include "libavcodec/mathops.h"
32 #include "dsd_tablegen.h"
34 #define FIFOSIZE 16 /** must be a power of two */
35 #define FIFOMASK (FIFOSIZE - 1) /** bit mask for FIFO offsets */
37 #if FIFOSIZE * 8 < HTAPS * 2
38 #error "FIFOSIZE too small"
45 unsigned char buf
[FIFOSIZE
];
49 static void dsd2pcm_translate(DSDContext
* s
, size_t samples
, int lsbf
,
50 const unsigned char *src
, ptrdiff_t src_stride
,
51 float *dst
, ptrdiff_t dst_stride
)
59 while (samples
-- > 0) {
60 s
->buf
[pos
] = lsbf
? ff_reverse
[*src
] : *src
;
63 p
= s
->buf
+ ((pos
- CTABLES
) & FIFOMASK
);
67 for (i
= 0; i
< CTABLES
; i
++) {
68 unsigned char a
= s
->buf
[(pos
- i
) & FIFOMASK
];
69 unsigned char b
= s
->buf
[(pos
- (CTABLES
*2 - 1) + i
) & FIFOMASK
];
70 sum
+= ctables
[i
][a
] + ctables
[i
][b
];
76 pos
= (pos
+ 1) & FIFOMASK
;
82 static av_cold
void init_static_data(void)
87 dsd_ctables_tableinit();
91 static av_cold
int decode_init(AVCodecContext
*avctx
)
98 s
= av_malloc_array(sizeof(DSDContext
), avctx
->channels
);
100 return AVERROR(ENOMEM
);
102 for (i
= 0; i
< avctx
->channels
; i
++) {
104 memset(s
[i
].buf
, 0x69, sizeof(s
[i
].buf
));
107 * This pattern "on repeat" makes a low energy 352.8 kHz tone
108 * and a high energy 1.0584 MHz tone which should be filtered
109 * out completely by any playback system --> silence
113 avctx
->sample_fmt
= AV_SAMPLE_FMT_FLTP
;
114 avctx
->priv_data
= s
;
118 static int decode_frame(AVCodecContext
*avctx
, void *data
,
119 int *got_frame_ptr
, AVPacket
*avpkt
)
121 DSDContext
* s
= avctx
->priv_data
;
122 AVFrame
*frame
= data
;
124 int lsbf
= avctx
->codec_id
== AV_CODEC_ID_DSD_LSBF
|| avctx
->codec_id
== AV_CODEC_ID_DSD_LSBF_PLANAR
;
128 frame
->nb_samples
= avpkt
->size
/ avctx
->channels
;
130 if (avctx
->codec_id
== AV_CODEC_ID_DSD_LSBF_PLANAR
|| avctx
->codec_id
== AV_CODEC_ID_DSD_MSBF_PLANAR
) {
131 src_next
= frame
->nb_samples
;
135 src_stride
= avctx
->channels
;
138 if ((ret
= ff_get_buffer(avctx
, frame
, 0)) < 0)
141 for (i
= 0; i
< avctx
->channels
; i
++) {
142 float * dst
= ((float **)frame
->extended_data
)[i
];
143 dsd2pcm_translate(&s
[i
], frame
->nb_samples
, lsbf
,
144 avpkt
->data
+ i
* src_next
, src_stride
,
149 return frame
->nb_samples
* avctx
->channels
;
152 #define DSD_DECODER(id_, name_, long_name_) \
153 AVCodec ff_##name_##_decoder = { \
155 .long_name = NULL_IF_CONFIG_SMALL(long_name_), \
156 .type = AVMEDIA_TYPE_AUDIO, \
157 .id = AV_CODEC_ID_##id_, \
158 .init = decode_init, \
159 .decode = decode_frame, \
160 .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLTP, \
161 AV_SAMPLE_FMT_NONE }, \
164 DSD_DECODER(DSD_LSBF
, dsd_lsbf
, "DSD (Direct Stream Digital), least significant bit first")
165 DSD_DECODER(DSD_MSBF
, dsd_msbf
, "DSD (Direct Stream Digital), most significant bit first")
166 DSD_DECODER(DSD_MSBF_PLANAR
, dsd_msbf_planar
, "DSD (Direct Stream Digital), most significant bit first, planar")
167 DSD_DECODER(DSD_LSBF_PLANAR
, dsd_lsbf_planar
, "DSD (Direct Stream Digital), least significant bit first, planar")