/src/ffmpeg/libavutil/samplefmt.c
Line | Count | Source |
1 | | /* |
2 | | * This file is part of FFmpeg. |
3 | | * |
4 | | * FFmpeg is free software; you can redistribute it and/or |
5 | | * modify it under the terms of the GNU Lesser General Public |
6 | | * License as published by the Free Software Foundation; either |
7 | | * version 2.1 of the License, or (at your option) any later version. |
8 | | * |
9 | | * FFmpeg is distributed in the hope that it will be useful, |
10 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | | * Lesser General Public License for more details. |
13 | | * |
14 | | * You should have received a copy of the GNU Lesser General Public |
15 | | * License along with FFmpeg; if not, write to the Free Software |
16 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
17 | | */ |
18 | | |
19 | | #include "error.h" |
20 | | #include "macros.h" |
21 | | #include "mem.h" |
22 | | #include "samplefmt.h" |
23 | | |
24 | | #include <limits.h> |
25 | | #include <stdio.h> |
26 | | #include <string.h> |
27 | | |
28 | | typedef struct SampleFmtInfo { |
29 | | char name[8]; |
30 | | int bits; |
31 | | int planar; |
32 | | enum AVSampleFormat altform; ///< planar<->packed alternative form |
33 | | } SampleFmtInfo; |
34 | | |
35 | | /** this table gives more information about formats */ |
36 | | static const SampleFmtInfo sample_fmt_info[AV_SAMPLE_FMT_NB] = { |
37 | | [AV_SAMPLE_FMT_U8] = { .name = "u8", .bits = 8, .planar = 0, .altform = AV_SAMPLE_FMT_U8P }, |
38 | | [AV_SAMPLE_FMT_S16] = { .name = "s16", .bits = 16, .planar = 0, .altform = AV_SAMPLE_FMT_S16P }, |
39 | | [AV_SAMPLE_FMT_S32] = { .name = "s32", .bits = 32, .planar = 0, .altform = AV_SAMPLE_FMT_S32P }, |
40 | | [AV_SAMPLE_FMT_S64] = { .name = "s64", .bits = 64, .planar = 0, .altform = AV_SAMPLE_FMT_S64P }, |
41 | | [AV_SAMPLE_FMT_FLT] = { .name = "flt", .bits = 32, .planar = 0, .altform = AV_SAMPLE_FMT_FLTP }, |
42 | | [AV_SAMPLE_FMT_DBL] = { .name = "dbl", .bits = 64, .planar = 0, .altform = AV_SAMPLE_FMT_DBLP }, |
43 | | [AV_SAMPLE_FMT_U8P] = { .name = "u8p", .bits = 8, .planar = 1, .altform = AV_SAMPLE_FMT_U8 }, |
44 | | [AV_SAMPLE_FMT_S16P] = { .name = "s16p", .bits = 16, .planar = 1, .altform = AV_SAMPLE_FMT_S16 }, |
45 | | [AV_SAMPLE_FMT_S32P] = { .name = "s32p", .bits = 32, .planar = 1, .altform = AV_SAMPLE_FMT_S32 }, |
46 | | [AV_SAMPLE_FMT_S64P] = { .name = "s64p", .bits = 64, .planar = 1, .altform = AV_SAMPLE_FMT_S64 }, |
47 | | [AV_SAMPLE_FMT_FLTP] = { .name = "fltp", .bits = 32, .planar = 1, .altform = AV_SAMPLE_FMT_FLT }, |
48 | | [AV_SAMPLE_FMT_DBLP] = { .name = "dblp", .bits = 64, .planar = 1, .altform = AV_SAMPLE_FMT_DBL }, |
49 | | [AV_SAMPLE_FMT_DSD] = { .name = "dsd", .bits = 8, .planar = 0, .altform = AV_SAMPLE_FMT_DSD }, |
50 | | }; |
51 | | |
52 | | const char *av_get_sample_fmt_name(enum AVSampleFormat sample_fmt) |
53 | 0 | { |
54 | 0 | if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB) |
55 | 0 | return NULL; |
56 | 0 | return sample_fmt_info[sample_fmt].name; |
57 | 0 | } |
58 | | |
59 | | enum AVSampleFormat av_get_sample_fmt(const char *name) |
60 | 0 | { |
61 | 0 | int i; |
62 | |
|
63 | 0 | for (i = 0; i < AV_SAMPLE_FMT_NB; i++) |
64 | 0 | if (!strcmp(sample_fmt_info[i].name, name)) |
65 | 0 | return i; |
66 | 0 | return AV_SAMPLE_FMT_NONE; |
67 | 0 | } |
68 | | |
69 | | enum AVSampleFormat av_get_alt_sample_fmt(enum AVSampleFormat sample_fmt, int planar) |
70 | 0 | { |
71 | 0 | if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB) |
72 | 0 | return AV_SAMPLE_FMT_NONE; |
73 | 0 | if (sample_fmt_info[sample_fmt].planar == planar) |
74 | 0 | return sample_fmt; |
75 | 0 | return sample_fmt_info[sample_fmt].altform; |
76 | 0 | } |
77 | | |
78 | | enum AVSampleFormat av_get_packed_sample_fmt(enum AVSampleFormat sample_fmt) |
79 | 0 | { |
80 | 0 | if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB) |
81 | 0 | return AV_SAMPLE_FMT_NONE; |
82 | 0 | if (sample_fmt_info[sample_fmt].planar) |
83 | 0 | return sample_fmt_info[sample_fmt].altform; |
84 | 0 | return sample_fmt; |
85 | 0 | } |
86 | | |
87 | | enum AVSampleFormat av_get_planar_sample_fmt(enum AVSampleFormat sample_fmt) |
88 | 0 | { |
89 | 0 | if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB) |
90 | 0 | return AV_SAMPLE_FMT_NONE; |
91 | 0 | if (sample_fmt_info[sample_fmt].planar) |
92 | 0 | return sample_fmt; |
93 | 0 | return sample_fmt_info[sample_fmt].altform; |
94 | 0 | } |
95 | | |
96 | | char *av_get_sample_fmt_string (char *buf, int buf_size, enum AVSampleFormat sample_fmt) |
97 | 0 | { |
98 | | /* print header */ |
99 | 0 | if (sample_fmt < 0) |
100 | 0 | snprintf(buf, buf_size, "name " " depth"); |
101 | 0 | else if (sample_fmt < AV_SAMPLE_FMT_NB) { |
102 | 0 | SampleFmtInfo info = sample_fmt_info[sample_fmt]; |
103 | 0 | snprintf (buf, buf_size, "%-6s" " %2d ", info.name, info.bits); |
104 | 0 | } |
105 | |
|
106 | 0 | return buf; |
107 | 0 | } |
108 | | |
109 | | int av_get_bytes_per_sample(enum AVSampleFormat sample_fmt) |
110 | 0 | { |
111 | 0 | return sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB ? |
112 | 0 | 0 : sample_fmt_info[sample_fmt].bits >> 3; |
113 | 0 | } |
114 | | |
115 | | int av_sample_fmt_is_planar(enum AVSampleFormat sample_fmt) |
116 | 0 | { |
117 | 0 | if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB) |
118 | 0 | return 0; |
119 | 0 | return sample_fmt_info[sample_fmt].planar; |
120 | 0 | } |
121 | | |
122 | | int av_samples_get_buffer_size(int *linesize, int nb_channels, int nb_samples, |
123 | | enum AVSampleFormat sample_fmt, int align) |
124 | 0 | { |
125 | 0 | int line_size; |
126 | 0 | int sample_size = av_get_bytes_per_sample(sample_fmt); |
127 | 0 | int planar = av_sample_fmt_is_planar(sample_fmt); |
128 | | |
129 | | /* validate parameter ranges */ |
130 | 0 | if (!sample_size || nb_samples <= 0 || nb_channels <= 0) |
131 | 0 | return AVERROR(EINVAL); |
132 | | |
133 | | /* auto-select alignment if not specified */ |
134 | 0 | if (!align) { |
135 | 0 | if (nb_samples > INT_MAX - 31) |
136 | 0 | return AVERROR(EINVAL); |
137 | 0 | align = 1; |
138 | 0 | nb_samples = FFALIGN(nb_samples, 32); |
139 | 0 | } |
140 | | |
141 | | /* check for integer overflow */ |
142 | 0 | if (nb_channels > INT_MAX / align || |
143 | 0 | (int64_t)nb_channels * nb_samples > (INT_MAX - (align * nb_channels)) / sample_size) |
144 | 0 | return AVERROR(EINVAL); |
145 | | |
146 | 0 | line_size = planar ? FFALIGN(nb_samples * sample_size, align) : |
147 | 0 | FFALIGN(nb_samples * sample_size * nb_channels, align); |
148 | 0 | if (linesize) |
149 | 0 | *linesize = line_size; |
150 | |
|
151 | 0 | return planar ? line_size * nb_channels : line_size; |
152 | 0 | } |
153 | | |
154 | | int av_samples_fill_arrays(uint8_t **audio_data, int *linesize, |
155 | | const uint8_t *buf, int nb_channels, int nb_samples, |
156 | | enum AVSampleFormat sample_fmt, int align) |
157 | 0 | { |
158 | 0 | int ch, planar, buf_size, line_size; |
159 | |
|
160 | 0 | planar = av_sample_fmt_is_planar(sample_fmt); |
161 | 0 | buf_size = av_samples_get_buffer_size(&line_size, nb_channels, nb_samples, |
162 | 0 | sample_fmt, align); |
163 | 0 | if (buf_size < 0) |
164 | 0 | return buf_size; |
165 | | |
166 | 0 | if (linesize) |
167 | 0 | *linesize = line_size; |
168 | |
|
169 | 0 | memset(audio_data, 0, planar |
170 | 0 | ? sizeof(*audio_data) * nb_channels |
171 | 0 | : sizeof(*audio_data)); |
172 | |
|
173 | 0 | if (!buf) |
174 | 0 | return buf_size; |
175 | | |
176 | 0 | audio_data[0] = (uint8_t *)buf; |
177 | 0 | for (ch = 1; planar && ch < nb_channels; ch++) |
178 | 0 | audio_data[ch] = audio_data[ch-1] + line_size; |
179 | |
|
180 | 0 | return buf_size; |
181 | 0 | } |
182 | | |
183 | | int av_samples_alloc(uint8_t **audio_data, int *linesize, int nb_channels, |
184 | | int nb_samples, enum AVSampleFormat sample_fmt, int align) |
185 | 0 | { |
186 | 0 | uint8_t *buf; |
187 | 0 | int size = av_samples_get_buffer_size(NULL, nb_channels, nb_samples, |
188 | 0 | sample_fmt, align); |
189 | 0 | if (size < 0) |
190 | 0 | return size; |
191 | | |
192 | 0 | buf = av_malloc(size); |
193 | 0 | if (!buf) |
194 | 0 | return AVERROR(ENOMEM); |
195 | | |
196 | 0 | size = av_samples_fill_arrays(audio_data, linesize, buf, nb_channels, |
197 | 0 | nb_samples, sample_fmt, align); |
198 | 0 | if (size < 0) { |
199 | 0 | av_free(buf); |
200 | 0 | return size; |
201 | 0 | } |
202 | | |
203 | 0 | av_samples_set_silence(audio_data, 0, nb_samples, nb_channels, sample_fmt); |
204 | |
|
205 | 0 | return size; |
206 | 0 | } |
207 | | |
208 | | int av_samples_alloc_array_and_samples(uint8_t ***audio_data, int *linesize, int nb_channels, |
209 | | int nb_samples, enum AVSampleFormat sample_fmt, int align) |
210 | 0 | { |
211 | 0 | int ret, nb_planes = av_sample_fmt_is_planar(sample_fmt) ? nb_channels : 1; |
212 | |
|
213 | 0 | *audio_data = av_calloc(nb_planes, sizeof(**audio_data)); |
214 | 0 | if (!*audio_data) |
215 | 0 | return AVERROR(ENOMEM); |
216 | 0 | ret = av_samples_alloc(*audio_data, linesize, nb_channels, |
217 | 0 | nb_samples, sample_fmt, align); |
218 | 0 | if (ret < 0) |
219 | 0 | av_freep(audio_data); |
220 | 0 | return ret; |
221 | 0 | } |
222 | | |
223 | | int av_samples_copy(uint8_t * const *dst, uint8_t * const *src, int dst_offset, |
224 | | int src_offset, int nb_samples, int nb_channels, |
225 | | enum AVSampleFormat sample_fmt) |
226 | 0 | { |
227 | 0 | int planar = av_sample_fmt_is_planar(sample_fmt); |
228 | 0 | int planes = planar ? nb_channels : 1; |
229 | 0 | int block_align = av_get_bytes_per_sample(sample_fmt) * (planar ? 1 : nb_channels); |
230 | 0 | int data_size = nb_samples * block_align; |
231 | 0 | int i; |
232 | |
|
233 | 0 | dst_offset *= block_align; |
234 | 0 | src_offset *= block_align; |
235 | |
|
236 | 0 | if((dst[0] < src[0] ? src[0] - dst[0] : dst[0] - src[0]) >= data_size) { |
237 | 0 | for (i = 0; i < planes; i++) |
238 | 0 | memcpy(dst[i] + dst_offset, src[i] + src_offset, data_size); |
239 | 0 | } else { |
240 | 0 | for (i = 0; i < planes; i++) |
241 | 0 | memmove(dst[i] + dst_offset, src[i] + src_offset, data_size); |
242 | 0 | } |
243 | |
|
244 | 0 | return 0; |
245 | 0 | } |
246 | | |
247 | | int av_samples_set_silence(uint8_t * const *audio_data, int offset, int nb_samples, |
248 | | int nb_channels, enum AVSampleFormat sample_fmt) |
249 | 0 | { |
250 | 0 | int planar = av_sample_fmt_is_planar(sample_fmt); |
251 | 0 | int planes = planar ? nb_channels : 1; |
252 | 0 | int block_align = av_get_bytes_per_sample(sample_fmt) * (planar ? 1 : nb_channels); |
253 | 0 | int data_size = nb_samples * block_align; |
254 | 0 | int fill_char, i; |
255 | |
|
256 | 0 | if (sample_fmt == AV_SAMPLE_FMT_U8 || sample_fmt == AV_SAMPLE_FMT_U8P) |
257 | 0 | fill_char = 0x80; |
258 | 0 | else if (sample_fmt == AV_SAMPLE_FMT_DSD) |
259 | 0 | fill_char = 0x69; // only ultrasonic tones, filtered out on playback |
260 | 0 | else |
261 | 0 | fill_char = 0x00; |
262 | |
|
263 | 0 | offset *= block_align; |
264 | |
|
265 | 0 | for (i = 0; i < planes; i++) |
266 | 0 | memset(audio_data[i] + offset, fill_char, data_size); |
267 | |
|
268 | 0 | return 0; |
269 | 0 | } |