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