Commit | Line | Data |
---|---|---|
2ba45a60 DM |
1 | /* |
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 | |
6 | * | |
7 | * This file is part of FFmpeg. | |
8 | * | |
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. | |
13 | * | |
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. | |
18 | * | |
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 | |
22 | */ | |
23 | ||
24 | /** | |
25 | * @file | |
26 | * Direct Stream Digital (DSD) decoder | |
27 | */ | |
28 | ||
29 | #include "libavcodec/internal.h" | |
30 | #include "libavcodec/mathops.h" | |
31 | #include "avcodec.h" | |
32 | #include "dsd_tablegen.h" | |
33 | ||
34 | #define FIFOSIZE 16 /** must be a power of two */ | |
35 | #define FIFOMASK (FIFOSIZE - 1) /** bit mask for FIFO offsets */ | |
36 | ||
37 | #if FIFOSIZE * 8 < HTAPS * 2 | |
38 | #error "FIFOSIZE too small" | |
39 | #endif | |
40 | ||
41 | /** | |
42 | * Per-channel buffer | |
43 | */ | |
44 | typedef struct { | |
45 | unsigned char buf[FIFOSIZE]; | |
46 | unsigned pos; | |
47 | } DSDContext; | |
48 | ||
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) | |
52 | { | |
53 | unsigned pos, i; | |
54 | unsigned char* p; | |
55 | double sum; | |
56 | ||
57 | pos = s->pos; | |
58 | ||
59 | while (samples-- > 0) { | |
60 | s->buf[pos] = lsbf ? ff_reverse[*src] : *src; | |
61 | src += src_stride; | |
62 | ||
63 | p = s->buf + ((pos - CTABLES) & FIFOMASK); | |
64 | *p = ff_reverse[*p]; | |
65 | ||
66 | sum = 0.0; | |
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]; | |
71 | } | |
72 | ||
73 | *dst = (float)sum; | |
74 | dst += dst_stride; | |
75 | ||
76 | pos = (pos + 1) & FIFOMASK; | |
77 | } | |
78 | ||
79 | s->pos = pos; | |
80 | } | |
81 | ||
82 | static av_cold void init_static_data(void) | |
83 | { | |
84 | static int done = 0; | |
85 | if (done) | |
86 | return; | |
87 | dsd_ctables_tableinit(); | |
88 | done = 1; | |
89 | } | |
90 | ||
91 | static av_cold int decode_init(AVCodecContext *avctx) | |
92 | { | |
93 | DSDContext * s; | |
94 | int i; | |
95 | ||
96 | init_static_data(); | |
97 | ||
98 | s = av_malloc_array(sizeof(DSDContext), avctx->channels); | |
99 | if (!s) | |
100 | return AVERROR(ENOMEM); | |
101 | ||
102 | for (i = 0; i < avctx->channels; i++) { | |
103 | s[i].pos = 0; | |
104 | memset(s[i].buf, 0x69, sizeof(s[i].buf)); | |
105 | ||
106 | /* 0x69 = 01101001 | |
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 | |
110 | */ | |
111 | } | |
112 | ||
113 | avctx->sample_fmt = AV_SAMPLE_FMT_FLTP; | |
114 | avctx->priv_data = s; | |
115 | return 0; | |
116 | } | |
117 | ||
118 | static int decode_frame(AVCodecContext *avctx, void *data, | |
119 | int *got_frame_ptr, AVPacket *avpkt) | |
120 | { | |
121 | DSDContext * s = avctx->priv_data; | |
122 | AVFrame *frame = data; | |
123 | int ret, i; | |
124 | int lsbf = avctx->codec_id == AV_CODEC_ID_DSD_LSBF || avctx->codec_id == AV_CODEC_ID_DSD_LSBF_PLANAR; | |
125 | int src_next; | |
126 | int src_stride; | |
127 | ||
128 | frame->nb_samples = avpkt->size / avctx->channels; | |
129 | ||
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; | |
132 | src_stride = 1; | |
133 | } else { | |
134 | src_next = 1; | |
135 | src_stride = avctx->channels; | |
136 | } | |
137 | ||
138 | if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) | |
139 | return ret; | |
140 | ||
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, | |
145 | dst, 1); | |
146 | } | |
147 | ||
148 | *got_frame_ptr = 1; | |
149 | return frame->nb_samples * avctx->channels; | |
150 | } | |
151 | ||
152 | #define DSD_DECODER(id_, name_, long_name_) \ | |
153 | AVCodec ff_##name_##_decoder = { \ | |
154 | .name = #name_, \ | |
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 }, \ | |
162 | }; | |
163 | ||
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") |