blob: fc077f644443634628fc6c461d844a21c9e72d1c
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 "common.h" |
20 | #include "samplefmt.h" |
21 | |
22 | #include <stdio.h> |
23 | #include <stdlib.h> |
24 | #include <string.h> |
25 | |
26 | typedef struct SampleFmtInfo { |
27 | char name[8]; |
28 | int bits; |
29 | int planar; |
30 | enum AVSampleFormat altform; ///< planar<->packed alternative form |
31 | } SampleFmtInfo; |
32 | |
33 | /** this table gives more information about formats */ |
34 | static const SampleFmtInfo sample_fmt_info[AV_SAMPLE_FMT_NB] = { |
35 | [AV_SAMPLE_FMT_U8] = { .name = "u8", .bits = 8, .planar = 0, .altform = AV_SAMPLE_FMT_U8P }, |
36 | [AV_SAMPLE_FMT_S16] = { .name = "s16", .bits = 16, .planar = 0, .altform = AV_SAMPLE_FMT_S16P }, |
37 | [AV_SAMPLE_FMT_S32] = { .name = "s32", .bits = 32, .planar = 0, .altform = AV_SAMPLE_FMT_S32P }, |
38 | [AV_SAMPLE_FMT_S64] = { .name = "s64", .bits = 64, .planar = 0, .altform = AV_SAMPLE_FMT_S64P }, |
39 | [AV_SAMPLE_FMT_FLT] = { .name = "flt", .bits = 32, .planar = 0, .altform = AV_SAMPLE_FMT_FLTP }, |
40 | [AV_SAMPLE_FMT_DBL] = { .name = "dbl", .bits = 64, .planar = 0, .altform = AV_SAMPLE_FMT_DBLP }, |
41 | [AV_SAMPLE_FMT_U8P] = { .name = "u8p", .bits = 8, .planar = 1, .altform = AV_SAMPLE_FMT_U8 }, |
42 | [AV_SAMPLE_FMT_S16P] = { .name = "s16p", .bits = 16, .planar = 1, .altform = AV_SAMPLE_FMT_S16 }, |
43 | [AV_SAMPLE_FMT_S32P] = { .name = "s32p", .bits = 32, .planar = 1, .altform = AV_SAMPLE_FMT_S32 }, |
44 | [AV_SAMPLE_FMT_S64P] = { .name = "s64p", .bits = 64, .planar = 1, .altform = AV_SAMPLE_FMT_S64 }, |
45 | [AV_SAMPLE_FMT_FLTP] = { .name = "fltp", .bits = 32, .planar = 1, .altform = AV_SAMPLE_FMT_FLT }, |
46 | [AV_SAMPLE_FMT_DBLP] = { .name = "dblp", .bits = 64, .planar = 1, .altform = AV_SAMPLE_FMT_DBL }, |
47 | }; |
48 | |
49 | const char *av_get_sample_fmt_name(enum AVSampleFormat sample_fmt) |
50 | { |
51 | if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB) |
52 | return NULL; |
53 | return sample_fmt_info[sample_fmt].name; |
54 | } |
55 | |
56 | enum AVSampleFormat av_get_sample_fmt(const char *name) |
57 | { |
58 | int i; |
59 | |
60 | for (i = 0; i < AV_SAMPLE_FMT_NB; i++) |
61 | if (!strcmp(sample_fmt_info[i].name, name)) |
62 | return i; |
63 | return AV_SAMPLE_FMT_NONE; |
64 | } |
65 | |
66 | enum AVSampleFormat av_get_alt_sample_fmt(enum AVSampleFormat sample_fmt, int planar) |
67 | { |
68 | if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB) |
69 | return AV_SAMPLE_FMT_NONE; |
70 | if (sample_fmt_info[sample_fmt].planar == planar) |
71 | return sample_fmt; |
72 | return sample_fmt_info[sample_fmt].altform; |
73 | } |
74 | |
75 | enum AVSampleFormat av_get_packed_sample_fmt(enum AVSampleFormat sample_fmt) |
76 | { |
77 | if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB) |
78 | return AV_SAMPLE_FMT_NONE; |
79 | if (sample_fmt_info[sample_fmt].planar) |
80 | return sample_fmt_info[sample_fmt].altform; |
81 | return sample_fmt; |
82 | } |
83 | |
84 | enum AVSampleFormat av_get_planar_sample_fmt(enum AVSampleFormat sample_fmt) |
85 | { |
86 | if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB) |
87 | return AV_SAMPLE_FMT_NONE; |
88 | if (sample_fmt_info[sample_fmt].planar) |
89 | return sample_fmt; |
90 | return sample_fmt_info[sample_fmt].altform; |
91 | } |
92 | |
93 | char *av_get_sample_fmt_string (char *buf, int buf_size, enum AVSampleFormat sample_fmt) |
94 | { |
95 | /* print header */ |
96 | if (sample_fmt < 0) |
97 | snprintf(buf, buf_size, "name " " depth"); |
98 | else if (sample_fmt < AV_SAMPLE_FMT_NB) { |
99 | SampleFmtInfo info = sample_fmt_info[sample_fmt]; |
100 | snprintf (buf, buf_size, "%-6s" " %2d ", info.name, info.bits); |
101 | } |
102 | |
103 | return buf; |
104 | } |
105 | |
106 | int av_get_bytes_per_sample(enum AVSampleFormat sample_fmt) |
107 | { |
108 | return sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB ? |
109 | 0 : sample_fmt_info[sample_fmt].bits >> 3; |
110 | } |
111 | |
112 | int av_sample_fmt_is_planar(enum AVSampleFormat sample_fmt) |
113 | { |
114 | if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB) |
115 | return 0; |
116 | return sample_fmt_info[sample_fmt].planar; |
117 | } |
118 | |
119 | int av_samples_get_buffer_size(int *linesize, int nb_channels, int nb_samples, |
120 | enum AVSampleFormat sample_fmt, int align) |
121 | { |
122 | int line_size; |
123 | int sample_size = av_get_bytes_per_sample(sample_fmt); |
124 | int planar = av_sample_fmt_is_planar(sample_fmt); |
125 | |
126 | /* validate parameter ranges */ |
127 | if (!sample_size || nb_samples <= 0 || nb_channels <= 0) |
128 | return AVERROR(EINVAL); |
129 | |
130 | /* auto-select alignment if not specified */ |
131 | if (!align) { |
132 | if (nb_samples > INT_MAX - 31) |
133 | return AVERROR(EINVAL); |
134 | align = 1; |
135 | nb_samples = FFALIGN(nb_samples, 32); |
136 | } |
137 | |
138 | /* check for integer overflow */ |
139 | if (nb_channels > INT_MAX / align || |
140 | (int64_t)nb_channels * nb_samples > (INT_MAX - (align * nb_channels)) / sample_size) |
141 | return AVERROR(EINVAL); |
142 | |
143 | line_size = planar ? FFALIGN(nb_samples * sample_size, align) : |
144 | FFALIGN(nb_samples * sample_size * nb_channels, align); |
145 | if (linesize) |
146 | *linesize = line_size; |
147 | |
148 | return planar ? line_size * nb_channels : line_size; |
149 | } |
150 | |
151 | int av_samples_fill_arrays(uint8_t **audio_data, int *linesize, |
152 | const uint8_t *buf, int nb_channels, int nb_samples, |
153 | enum AVSampleFormat sample_fmt, int align) |
154 | { |
155 | int ch, planar, buf_size, line_size; |
156 | |
157 | planar = av_sample_fmt_is_planar(sample_fmt); |
158 | buf_size = av_samples_get_buffer_size(&line_size, nb_channels, nb_samples, |
159 | sample_fmt, align); |
160 | if (buf_size < 0) |
161 | return buf_size; |
162 | |
163 | audio_data[0] = (uint8_t *)buf; |
164 | for (ch = 1; planar && ch < nb_channels; ch++) |
165 | audio_data[ch] = audio_data[ch-1] + line_size; |
166 | |
167 | if (linesize) |
168 | *linesize = line_size; |
169 | |
170 | return buf_size; |
171 | } |
172 | |
173 | int av_samples_alloc(uint8_t **audio_data, int *linesize, int nb_channels, |
174 | int nb_samples, enum AVSampleFormat sample_fmt, int align) |
175 | { |
176 | uint8_t *buf; |
177 | int size = av_samples_get_buffer_size(NULL, nb_channels, nb_samples, |
178 | sample_fmt, align); |
179 | if (size < 0) |
180 | return size; |
181 | |
182 | buf = av_malloc(size); |
183 | if (!buf) |
184 | return AVERROR(ENOMEM); |
185 | |
186 | size = av_samples_fill_arrays(audio_data, linesize, buf, nb_channels, |
187 | nb_samples, sample_fmt, align); |
188 | if (size < 0) { |
189 | av_free(buf); |
190 | return size; |
191 | } |
192 | |
193 | av_samples_set_silence(audio_data, 0, nb_samples, nb_channels, sample_fmt); |
194 | |
195 | return size; |
196 | } |
197 | |
198 | int av_samples_alloc_array_and_samples(uint8_t ***audio_data, int *linesize, int nb_channels, |
199 | int nb_samples, enum AVSampleFormat sample_fmt, int align) |
200 | { |
201 | int ret, nb_planes = av_sample_fmt_is_planar(sample_fmt) ? nb_channels : 1; |
202 | |
203 | *audio_data = av_calloc(nb_planes, sizeof(**audio_data)); |
204 | if (!*audio_data) |
205 | return AVERROR(ENOMEM); |
206 | ret = av_samples_alloc(*audio_data, linesize, nb_channels, |
207 | nb_samples, sample_fmt, align); |
208 | if (ret < 0) |
209 | av_freep(audio_data); |
210 | return ret; |
211 | } |
212 | |
213 | int av_samples_copy(uint8_t **dst, uint8_t * const *src, int dst_offset, |
214 | int src_offset, int nb_samples, int nb_channels, |
215 | enum AVSampleFormat sample_fmt) |
216 | { |
217 | int planar = av_sample_fmt_is_planar(sample_fmt); |
218 | int planes = planar ? nb_channels : 1; |
219 | int block_align = av_get_bytes_per_sample(sample_fmt) * (planar ? 1 : nb_channels); |
220 | int data_size = nb_samples * block_align; |
221 | int i; |
222 | |
223 | dst_offset *= block_align; |
224 | src_offset *= block_align; |
225 | |
226 | if((dst[0] < src[0] ? src[0] - dst[0] : dst[0] - src[0]) >= data_size) { |
227 | for (i = 0; i < planes; i++) |
228 | memcpy(dst[i] + dst_offset, src[i] + src_offset, data_size); |
229 | } else { |
230 | for (i = 0; i < planes; i++) |
231 | memmove(dst[i] + dst_offset, src[i] + src_offset, data_size); |
232 | } |
233 | |
234 | return 0; |
235 | } |
236 | |
237 | int av_samples_set_silence(uint8_t **audio_data, int offset, int nb_samples, |
238 | int nb_channels, enum AVSampleFormat sample_fmt) |
239 | { |
240 | int planar = av_sample_fmt_is_planar(sample_fmt); |
241 | int planes = planar ? nb_channels : 1; |
242 | int block_align = av_get_bytes_per_sample(sample_fmt) * (planar ? 1 : nb_channels); |
243 | int data_size = nb_samples * block_align; |
244 | int fill_char = (sample_fmt == AV_SAMPLE_FMT_U8 || |
245 | sample_fmt == AV_SAMPLE_FMT_U8P) ? 0x80 : 0x00; |
246 | int i; |
247 | |
248 | offset *= block_align; |
249 | |
250 | for (i = 0; i < planes; i++) |
251 | memset(audio_data[i] + offset, fill_char, data_size); |
252 | |
253 | return 0; |
254 | } |
255 |