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