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