/src/ffmpeg/libavutil/samplefmt.c
Line | Count | Source (jump to first uncovered line) |
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 | | }; |
50 | | |
51 | | const char *av_get_sample_fmt_name(enum AVSampleFormat sample_fmt) |
52 | 1.29k | { |
53 | 1.29k | if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB) |
54 | 5 | return NULL; |
55 | 1.29k | return sample_fmt_info[sample_fmt].name; |
56 | 1.29k | } |
57 | | |
58 | | enum AVSampleFormat av_get_sample_fmt(const char *name) |
59 | 0 | { |
60 | 0 | int i; |
61 | |
|
62 | 0 | for (i = 0; i < AV_SAMPLE_FMT_NB; i++) |
63 | 0 | if (!strcmp(sample_fmt_info[i].name, name)) |
64 | 0 | return i; |
65 | 0 | return AV_SAMPLE_FMT_NONE; |
66 | 0 | } |
67 | | |
68 | | enum AVSampleFormat av_get_alt_sample_fmt(enum AVSampleFormat sample_fmt, int planar) |
69 | 0 | { |
70 | 0 | if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB) |
71 | 0 | return AV_SAMPLE_FMT_NONE; |
72 | 0 | if (sample_fmt_info[sample_fmt].planar == planar) |
73 | 0 | return sample_fmt; |
74 | 0 | return sample_fmt_info[sample_fmt].altform; |
75 | 0 | } |
76 | | |
77 | | enum AVSampleFormat av_get_packed_sample_fmt(enum AVSampleFormat sample_fmt) |
78 | 390 | { |
79 | 390 | if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB) |
80 | 0 | return AV_SAMPLE_FMT_NONE; |
81 | 390 | if (sample_fmt_info[sample_fmt].planar) |
82 | 248 | return sample_fmt_info[sample_fmt].altform; |
83 | 142 | return sample_fmt; |
84 | 390 | } |
85 | | |
86 | | enum AVSampleFormat av_get_planar_sample_fmt(enum AVSampleFormat sample_fmt) |
87 | 142 | { |
88 | 142 | if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB) |
89 | 0 | return AV_SAMPLE_FMT_NONE; |
90 | 142 | if (sample_fmt_info[sample_fmt].planar) |
91 | 68 | return sample_fmt; |
92 | 74 | return sample_fmt_info[sample_fmt].altform; |
93 | 142 | } |
94 | | |
95 | | char *av_get_sample_fmt_string (char *buf, int buf_size, enum AVSampleFormat sample_fmt) |
96 | 0 | { |
97 | | /* print header */ |
98 | 0 | if (sample_fmt < 0) |
99 | 0 | snprintf(buf, buf_size, "name " " depth"); |
100 | 0 | else if (sample_fmt < AV_SAMPLE_FMT_NB) { |
101 | 0 | SampleFmtInfo info = sample_fmt_info[sample_fmt]; |
102 | 0 | snprintf (buf, buf_size, "%-6s" " %2d ", info.name, info.bits); |
103 | 0 | } |
104 | |
|
105 | 0 | return buf; |
106 | 0 | } |
107 | | |
108 | | int av_get_bytes_per_sample(enum AVSampleFormat sample_fmt) |
109 | 11.8M | { |
110 | 11.8M | return sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB ? |
111 | 11.8M | 0 : sample_fmt_info[sample_fmt].bits >> 3; |
112 | 11.8M | } |
113 | | |
114 | | int av_sample_fmt_is_planar(enum AVSampleFormat sample_fmt) |
115 | 14.5M | { |
116 | 14.5M | if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB) |
117 | 331 | return 0; |
118 | 14.5M | return sample_fmt_info[sample_fmt].planar; |
119 | 14.5M | } |
120 | | |
121 | | int av_samples_get_buffer_size(int *linesize, int nb_channels, int nb_samples, |
122 | | enum AVSampleFormat sample_fmt, int align) |
123 | 5.22M | { |
124 | 5.22M | int line_size; |
125 | 5.22M | int sample_size = av_get_bytes_per_sample(sample_fmt); |
126 | 5.22M | int planar = av_sample_fmt_is_planar(sample_fmt); |
127 | | |
128 | | /* validate parameter ranges */ |
129 | 5.22M | if (!sample_size || nb_samples <= 0 || nb_channels <= 0) |
130 | 2.11M | return AVERROR(EINVAL); |
131 | | |
132 | | /* auto-select alignment if not specified */ |
133 | 3.10M | if (!align) { |
134 | 3.05M | if (nb_samples > INT_MAX - 31) |
135 | 0 | return AVERROR(EINVAL); |
136 | 3.05M | align = 1; |
137 | 3.05M | nb_samples = FFALIGN(nb_samples, 32); |
138 | 3.05M | } |
139 | | |
140 | | /* check for integer overflow */ |
141 | 3.10M | if (nb_channels > INT_MAX / align || |
142 | 3.10M | (int64_t)nb_channels * nb_samples > (INT_MAX - (align * nb_channels)) / sample_size) |
143 | 0 | return AVERROR(EINVAL); |
144 | | |
145 | 3.10M | line_size = planar ? FFALIGN(nb_samples * sample_size, align) : |
146 | 3.10M | FFALIGN(nb_samples * sample_size * nb_channels, align); |
147 | 3.10M | if (linesize) |
148 | 3.06M | *linesize = line_size; |
149 | | |
150 | 3.10M | return planar ? line_size * nb_channels : line_size; |
151 | 3.10M | } |
152 | | |
153 | | int av_samples_fill_arrays(uint8_t **audio_data, int *linesize, |
154 | | const uint8_t *buf, int nb_channels, int nb_samples, |
155 | | enum AVSampleFormat sample_fmt, int align) |
156 | 41.3k | { |
157 | 41.3k | int ch, planar, buf_size, line_size; |
158 | | |
159 | 41.3k | planar = av_sample_fmt_is_planar(sample_fmt); |
160 | 41.3k | buf_size = av_samples_get_buffer_size(&line_size, nb_channels, nb_samples, |
161 | 41.3k | sample_fmt, align); |
162 | 41.3k | if (buf_size < 0) |
163 | 6 | return buf_size; |
164 | | |
165 | 41.3k | if (linesize) |
166 | 0 | *linesize = line_size; |
167 | | |
168 | 41.3k | memset(audio_data, 0, planar |
169 | 41.3k | ? sizeof(*audio_data) * nb_channels |
170 | 41.3k | : sizeof(*audio_data)); |
171 | | |
172 | 41.3k | if (!buf) |
173 | 0 | return buf_size; |
174 | | |
175 | 41.3k | audio_data[0] = (uint8_t *)buf; |
176 | 122k | for (ch = 1; planar && ch < nb_channels; ch++) |
177 | 81.3k | audio_data[ch] = audio_data[ch-1] + line_size; |
178 | | |
179 | 41.3k | return buf_size; |
180 | 41.3k | } |
181 | | |
182 | | int av_samples_alloc(uint8_t **audio_data, int *linesize, int nb_channels, |
183 | | int nb_samples, enum AVSampleFormat sample_fmt, int align) |
184 | 0 | { |
185 | 0 | uint8_t *buf; |
186 | 0 | int size = av_samples_get_buffer_size(NULL, nb_channels, nb_samples, |
187 | 0 | sample_fmt, align); |
188 | 0 | if (size < 0) |
189 | 0 | return size; |
190 | | |
191 | 0 | buf = av_malloc(size); |
192 | 0 | if (!buf) |
193 | 0 | return AVERROR(ENOMEM); |
194 | | |
195 | 0 | size = av_samples_fill_arrays(audio_data, linesize, buf, nb_channels, |
196 | 0 | nb_samples, sample_fmt, align); |
197 | 0 | if (size < 0) { |
198 | 0 | av_free(buf); |
199 | 0 | return size; |
200 | 0 | } |
201 | | |
202 | 0 | av_samples_set_silence(audio_data, 0, nb_samples, nb_channels, sample_fmt); |
203 | |
|
204 | 0 | return size; |
205 | 0 | } |
206 | | |
207 | | int av_samples_alloc_array_and_samples(uint8_t ***audio_data, int *linesize, int nb_channels, |
208 | | int nb_samples, enum AVSampleFormat sample_fmt, int align) |
209 | 0 | { |
210 | 0 | int ret, nb_planes = av_sample_fmt_is_planar(sample_fmt) ? nb_channels : 1; |
211 | |
|
212 | 0 | *audio_data = av_calloc(nb_planes, sizeof(**audio_data)); |
213 | 0 | if (!*audio_data) |
214 | 0 | return AVERROR(ENOMEM); |
215 | 0 | ret = av_samples_alloc(*audio_data, linesize, nb_channels, |
216 | 0 | nb_samples, sample_fmt, align); |
217 | 0 | if (ret < 0) |
218 | 0 | av_freep(audio_data); |
219 | 0 | return ret; |
220 | 0 | } |
221 | | |
222 | | int av_samples_copy(uint8_t * const *dst, uint8_t * const *src, int dst_offset, |
223 | | int src_offset, int nb_samples, int nb_channels, |
224 | | enum AVSampleFormat sample_fmt) |
225 | 2.06k | { |
226 | 2.06k | int planar = av_sample_fmt_is_planar(sample_fmt); |
227 | 2.06k | int planes = planar ? nb_channels : 1; |
228 | 2.06k | int block_align = av_get_bytes_per_sample(sample_fmt) * (planar ? 1 : nb_channels); |
229 | 2.06k | int data_size = nb_samples * block_align; |
230 | 2.06k | int i; |
231 | | |
232 | 2.06k | dst_offset *= block_align; |
233 | 2.06k | src_offset *= block_align; |
234 | | |
235 | 2.06k | if((dst[0] < src[0] ? src[0] - dst[0] : dst[0] - src[0]) >= data_size) { |
236 | 0 | for (i = 0; i < planes; i++) |
237 | 0 | memcpy(dst[i] + dst_offset, src[i] + src_offset, data_size); |
238 | 2.06k | } else { |
239 | 7.17k | for (i = 0; i < planes; i++) |
240 | 5.11k | memmove(dst[i] + dst_offset, src[i] + src_offset, data_size); |
241 | 2.06k | } |
242 | | |
243 | 2.06k | return 0; |
244 | 2.06k | } |
245 | | |
246 | | int av_samples_set_silence(uint8_t * const *audio_data, int offset, int nb_samples, |
247 | | int nb_channels, enum AVSampleFormat sample_fmt) |
248 | 6.30M | { |
249 | 6.30M | int planar = av_sample_fmt_is_planar(sample_fmt); |
250 | 6.30M | int planes = planar ? nb_channels : 1; |
251 | 6.30M | int block_align = av_get_bytes_per_sample(sample_fmt) * (planar ? 1 : nb_channels); |
252 | 6.30M | int data_size = nb_samples * block_align; |
253 | 6.30M | int fill_char = (sample_fmt == AV_SAMPLE_FMT_U8 || |
254 | 6.30M | sample_fmt == AV_SAMPLE_FMT_U8P) ? 0x80 : 0x00; |
255 | 6.30M | int i; |
256 | | |
257 | 6.30M | offset *= block_align; |
258 | | |
259 | 12.6M | for (i = 0; i < planes; i++) |
260 | 6.30M | memset(audio_data[i] + offset, fill_char, data_size); |
261 | | |
262 | 6.30M | return 0; |
263 | 6.30M | } |