1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * This file is part of FFmpeg.
3cabdff1aSopenharmony_ci *
4cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
5cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
6cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
7cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
8cabdff1aSopenharmony_ci *
9cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
10cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
11cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12cabdff1aSopenharmony_ci * Lesser General Public License for more details.
13cabdff1aSopenharmony_ci *
14cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
15cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
16cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17cabdff1aSopenharmony_ci */
18cabdff1aSopenharmony_ci
19cabdff1aSopenharmony_ci#include "error.h"
20cabdff1aSopenharmony_ci#include "macros.h"
21cabdff1aSopenharmony_ci#include "mem.h"
22cabdff1aSopenharmony_ci#include "samplefmt.h"
23cabdff1aSopenharmony_ci
24cabdff1aSopenharmony_ci#include <limits.h>
25cabdff1aSopenharmony_ci#include <stdio.h>
26cabdff1aSopenharmony_ci#include <string.h>
27cabdff1aSopenharmony_ci
28cabdff1aSopenharmony_citypedef struct SampleFmtInfo {
29cabdff1aSopenharmony_ci    char name[8];
30cabdff1aSopenharmony_ci    int bits;
31cabdff1aSopenharmony_ci    int planar;
32cabdff1aSopenharmony_ci    enum AVSampleFormat altform; ///< planar<->packed alternative form
33cabdff1aSopenharmony_ci} SampleFmtInfo;
34cabdff1aSopenharmony_ci
35cabdff1aSopenharmony_ci/** this table gives more information about formats */
36cabdff1aSopenharmony_cistatic const SampleFmtInfo sample_fmt_info[AV_SAMPLE_FMT_NB] = {
37cabdff1aSopenharmony_ci    [AV_SAMPLE_FMT_U8]   = { .name =   "u8", .bits =  8, .planar = 0, .altform = AV_SAMPLE_FMT_U8P  },
38cabdff1aSopenharmony_ci    [AV_SAMPLE_FMT_S16]  = { .name =  "s16", .bits = 16, .planar = 0, .altform = AV_SAMPLE_FMT_S16P },
39cabdff1aSopenharmony_ci    [AV_SAMPLE_FMT_S32]  = { .name =  "s32", .bits = 32, .planar = 0, .altform = AV_SAMPLE_FMT_S32P },
40cabdff1aSopenharmony_ci    [AV_SAMPLE_FMT_S64]  = { .name =  "s64", .bits = 64, .planar = 0, .altform = AV_SAMPLE_FMT_S64P },
41cabdff1aSopenharmony_ci    [AV_SAMPLE_FMT_FLT]  = { .name =  "flt", .bits = 32, .planar = 0, .altform = AV_SAMPLE_FMT_FLTP },
42cabdff1aSopenharmony_ci    [AV_SAMPLE_FMT_DBL]  = { .name =  "dbl", .bits = 64, .planar = 0, .altform = AV_SAMPLE_FMT_DBLP },
43cabdff1aSopenharmony_ci    [AV_SAMPLE_FMT_U8P]  = { .name =  "u8p", .bits =  8, .planar = 1, .altform = AV_SAMPLE_FMT_U8   },
44cabdff1aSopenharmony_ci    [AV_SAMPLE_FMT_S16P] = { .name = "s16p", .bits = 16, .planar = 1, .altform = AV_SAMPLE_FMT_S16  },
45cabdff1aSopenharmony_ci    [AV_SAMPLE_FMT_S32P] = { .name = "s32p", .bits = 32, .planar = 1, .altform = AV_SAMPLE_FMT_S32  },
46cabdff1aSopenharmony_ci    [AV_SAMPLE_FMT_S64P] = { .name = "s64p", .bits = 64, .planar = 1, .altform = AV_SAMPLE_FMT_S64  },
47cabdff1aSopenharmony_ci    [AV_SAMPLE_FMT_FLTP] = { .name = "fltp", .bits = 32, .planar = 1, .altform = AV_SAMPLE_FMT_FLT  },
48cabdff1aSopenharmony_ci    [AV_SAMPLE_FMT_DBLP] = { .name = "dblp", .bits = 64, .planar = 1, .altform = AV_SAMPLE_FMT_DBL  },
49cabdff1aSopenharmony_ci};
50cabdff1aSopenharmony_ci
51cabdff1aSopenharmony_ciconst char *av_get_sample_fmt_name(enum AVSampleFormat sample_fmt)
52cabdff1aSopenharmony_ci{
53cabdff1aSopenharmony_ci    if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB)
54cabdff1aSopenharmony_ci        return NULL;
55cabdff1aSopenharmony_ci    return sample_fmt_info[sample_fmt].name;
56cabdff1aSopenharmony_ci}
57cabdff1aSopenharmony_ci
58cabdff1aSopenharmony_cienum AVSampleFormat av_get_sample_fmt(const char *name)
59cabdff1aSopenharmony_ci{
60cabdff1aSopenharmony_ci    int i;
61cabdff1aSopenharmony_ci
62cabdff1aSopenharmony_ci    for (i = 0; i < AV_SAMPLE_FMT_NB; i++)
63cabdff1aSopenharmony_ci        if (!strcmp(sample_fmt_info[i].name, name))
64cabdff1aSopenharmony_ci            return i;
65cabdff1aSopenharmony_ci    return AV_SAMPLE_FMT_NONE;
66cabdff1aSopenharmony_ci}
67cabdff1aSopenharmony_ci
68cabdff1aSopenharmony_cienum AVSampleFormat av_get_alt_sample_fmt(enum AVSampleFormat sample_fmt, int planar)
69cabdff1aSopenharmony_ci{
70cabdff1aSopenharmony_ci    if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB)
71cabdff1aSopenharmony_ci        return AV_SAMPLE_FMT_NONE;
72cabdff1aSopenharmony_ci    if (sample_fmt_info[sample_fmt].planar == planar)
73cabdff1aSopenharmony_ci        return sample_fmt;
74cabdff1aSopenharmony_ci    return sample_fmt_info[sample_fmt].altform;
75cabdff1aSopenharmony_ci}
76cabdff1aSopenharmony_ci
77cabdff1aSopenharmony_cienum AVSampleFormat av_get_packed_sample_fmt(enum AVSampleFormat sample_fmt)
78cabdff1aSopenharmony_ci{
79cabdff1aSopenharmony_ci    if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB)
80cabdff1aSopenharmony_ci        return AV_SAMPLE_FMT_NONE;
81cabdff1aSopenharmony_ci    if (sample_fmt_info[sample_fmt].planar)
82cabdff1aSopenharmony_ci        return sample_fmt_info[sample_fmt].altform;
83cabdff1aSopenharmony_ci    return sample_fmt;
84cabdff1aSopenharmony_ci}
85cabdff1aSopenharmony_ci
86cabdff1aSopenharmony_cienum AVSampleFormat av_get_planar_sample_fmt(enum AVSampleFormat sample_fmt)
87cabdff1aSopenharmony_ci{
88cabdff1aSopenharmony_ci    if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB)
89cabdff1aSopenharmony_ci        return AV_SAMPLE_FMT_NONE;
90cabdff1aSopenharmony_ci    if (sample_fmt_info[sample_fmt].planar)
91cabdff1aSopenharmony_ci        return sample_fmt;
92cabdff1aSopenharmony_ci    return sample_fmt_info[sample_fmt].altform;
93cabdff1aSopenharmony_ci}
94cabdff1aSopenharmony_ci
95cabdff1aSopenharmony_cichar *av_get_sample_fmt_string (char *buf, int buf_size, enum AVSampleFormat sample_fmt)
96cabdff1aSopenharmony_ci{
97cabdff1aSopenharmony_ci    /* print header */
98cabdff1aSopenharmony_ci    if (sample_fmt < 0)
99cabdff1aSopenharmony_ci        snprintf(buf, buf_size, "name  " " depth");
100cabdff1aSopenharmony_ci    else if (sample_fmt < AV_SAMPLE_FMT_NB) {
101cabdff1aSopenharmony_ci        SampleFmtInfo info = sample_fmt_info[sample_fmt];
102cabdff1aSopenharmony_ci        snprintf (buf, buf_size, "%-6s" "   %2d ", info.name, info.bits);
103cabdff1aSopenharmony_ci    }
104cabdff1aSopenharmony_ci
105cabdff1aSopenharmony_ci    return buf;
106cabdff1aSopenharmony_ci}
107cabdff1aSopenharmony_ci
108cabdff1aSopenharmony_ciint av_get_bytes_per_sample(enum AVSampleFormat sample_fmt)
109cabdff1aSopenharmony_ci{
110cabdff1aSopenharmony_ci     return sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB ?
111cabdff1aSopenharmony_ci        0 : sample_fmt_info[sample_fmt].bits >> 3;
112cabdff1aSopenharmony_ci}
113cabdff1aSopenharmony_ci
114cabdff1aSopenharmony_ciint av_sample_fmt_is_planar(enum AVSampleFormat sample_fmt)
115cabdff1aSopenharmony_ci{
116cabdff1aSopenharmony_ci     if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB)
117cabdff1aSopenharmony_ci         return 0;
118cabdff1aSopenharmony_ci     return sample_fmt_info[sample_fmt].planar;
119cabdff1aSopenharmony_ci}
120cabdff1aSopenharmony_ci
121cabdff1aSopenharmony_ciint av_samples_get_buffer_size(int *linesize, int nb_channels, int nb_samples,
122cabdff1aSopenharmony_ci                               enum AVSampleFormat sample_fmt, int align)
123cabdff1aSopenharmony_ci{
124cabdff1aSopenharmony_ci    int line_size;
125cabdff1aSopenharmony_ci    int sample_size = av_get_bytes_per_sample(sample_fmt);
126cabdff1aSopenharmony_ci    int planar      = av_sample_fmt_is_planar(sample_fmt);
127cabdff1aSopenharmony_ci
128cabdff1aSopenharmony_ci    /* validate parameter ranges */
129cabdff1aSopenharmony_ci    if (!sample_size || nb_samples <= 0 || nb_channels <= 0)
130cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
131cabdff1aSopenharmony_ci
132cabdff1aSopenharmony_ci    /* auto-select alignment if not specified */
133cabdff1aSopenharmony_ci    if (!align) {
134cabdff1aSopenharmony_ci        if (nb_samples > INT_MAX - 31)
135cabdff1aSopenharmony_ci            return AVERROR(EINVAL);
136cabdff1aSopenharmony_ci        align = 1;
137cabdff1aSopenharmony_ci        nb_samples = FFALIGN(nb_samples, 32);
138cabdff1aSopenharmony_ci    }
139cabdff1aSopenharmony_ci
140cabdff1aSopenharmony_ci    /* check for integer overflow */
141cabdff1aSopenharmony_ci    if (nb_channels > INT_MAX / align ||
142cabdff1aSopenharmony_ci        (int64_t)nb_channels * nb_samples > (INT_MAX - (align * nb_channels)) / sample_size)
143cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
144cabdff1aSopenharmony_ci
145cabdff1aSopenharmony_ci    line_size = planar ? FFALIGN(nb_samples * sample_size,               align) :
146cabdff1aSopenharmony_ci                         FFALIGN(nb_samples * sample_size * nb_channels, align);
147cabdff1aSopenharmony_ci    if (linesize)
148cabdff1aSopenharmony_ci        *linesize = line_size;
149cabdff1aSopenharmony_ci
150cabdff1aSopenharmony_ci    return planar ? line_size * nb_channels : line_size;
151cabdff1aSopenharmony_ci}
152cabdff1aSopenharmony_ci
153cabdff1aSopenharmony_ciint av_samples_fill_arrays(uint8_t **audio_data, int *linesize,
154cabdff1aSopenharmony_ci                           const uint8_t *buf, int nb_channels, int nb_samples,
155cabdff1aSopenharmony_ci                           enum AVSampleFormat sample_fmt, int align)
156cabdff1aSopenharmony_ci{
157cabdff1aSopenharmony_ci    int ch, planar, buf_size, line_size;
158cabdff1aSopenharmony_ci
159cabdff1aSopenharmony_ci    planar   = av_sample_fmt_is_planar(sample_fmt);
160cabdff1aSopenharmony_ci    buf_size = av_samples_get_buffer_size(&line_size, nb_channels, nb_samples,
161cabdff1aSopenharmony_ci                                          sample_fmt, align);
162cabdff1aSopenharmony_ci    if (buf_size < 0)
163cabdff1aSopenharmony_ci        return buf_size;
164cabdff1aSopenharmony_ci
165cabdff1aSopenharmony_ci    if (linesize)
166cabdff1aSopenharmony_ci        *linesize = line_size;
167cabdff1aSopenharmony_ci
168cabdff1aSopenharmony_ci    memset(audio_data, 0, planar
169cabdff1aSopenharmony_ci                          ? sizeof(*audio_data) * nb_channels
170cabdff1aSopenharmony_ci                          : sizeof(*audio_data));
171cabdff1aSopenharmony_ci
172cabdff1aSopenharmony_ci    if (!buf)
173cabdff1aSopenharmony_ci        return buf_size;
174cabdff1aSopenharmony_ci
175cabdff1aSopenharmony_ci    audio_data[0] = (uint8_t *)buf;
176cabdff1aSopenharmony_ci    for (ch = 1; planar && ch < nb_channels; ch++)
177cabdff1aSopenharmony_ci        audio_data[ch] = audio_data[ch-1] + line_size;
178cabdff1aSopenharmony_ci
179cabdff1aSopenharmony_ci    return buf_size;
180cabdff1aSopenharmony_ci}
181cabdff1aSopenharmony_ci
182cabdff1aSopenharmony_ciint av_samples_alloc(uint8_t **audio_data, int *linesize, int nb_channels,
183cabdff1aSopenharmony_ci                     int nb_samples, enum AVSampleFormat sample_fmt, int align)
184cabdff1aSopenharmony_ci{
185cabdff1aSopenharmony_ci    uint8_t *buf;
186cabdff1aSopenharmony_ci    int size = av_samples_get_buffer_size(NULL, nb_channels, nb_samples,
187cabdff1aSopenharmony_ci                                          sample_fmt, align);
188cabdff1aSopenharmony_ci    if (size < 0)
189cabdff1aSopenharmony_ci        return size;
190cabdff1aSopenharmony_ci
191cabdff1aSopenharmony_ci    buf = av_malloc(size);
192cabdff1aSopenharmony_ci    if (!buf)
193cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
194cabdff1aSopenharmony_ci
195cabdff1aSopenharmony_ci    size = av_samples_fill_arrays(audio_data, linesize, buf, nb_channels,
196cabdff1aSopenharmony_ci                                  nb_samples, sample_fmt, align);
197cabdff1aSopenharmony_ci    if (size < 0) {
198cabdff1aSopenharmony_ci        av_free(buf);
199cabdff1aSopenharmony_ci        return size;
200cabdff1aSopenharmony_ci    }
201cabdff1aSopenharmony_ci
202cabdff1aSopenharmony_ci    av_samples_set_silence(audio_data, 0, nb_samples, nb_channels, sample_fmt);
203cabdff1aSopenharmony_ci
204cabdff1aSopenharmony_ci    return size;
205cabdff1aSopenharmony_ci}
206cabdff1aSopenharmony_ci
207cabdff1aSopenharmony_ciint av_samples_alloc_array_and_samples(uint8_t ***audio_data, int *linesize, int nb_channels,
208cabdff1aSopenharmony_ci                                       int nb_samples, enum AVSampleFormat sample_fmt, int align)
209cabdff1aSopenharmony_ci{
210cabdff1aSopenharmony_ci    int ret, nb_planes = av_sample_fmt_is_planar(sample_fmt) ? nb_channels : 1;
211cabdff1aSopenharmony_ci
212cabdff1aSopenharmony_ci    *audio_data = av_calloc(nb_planes, sizeof(**audio_data));
213cabdff1aSopenharmony_ci    if (!*audio_data)
214cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
215cabdff1aSopenharmony_ci    ret = av_samples_alloc(*audio_data, linesize, nb_channels,
216cabdff1aSopenharmony_ci                           nb_samples, sample_fmt, align);
217cabdff1aSopenharmony_ci    if (ret < 0)
218cabdff1aSopenharmony_ci        av_freep(audio_data);
219cabdff1aSopenharmony_ci    return ret;
220cabdff1aSopenharmony_ci}
221cabdff1aSopenharmony_ci
222cabdff1aSopenharmony_ciint av_samples_copy(uint8_t **dst, uint8_t * const *src, int dst_offset,
223cabdff1aSopenharmony_ci                    int src_offset, int nb_samples, int nb_channels,
224cabdff1aSopenharmony_ci                    enum AVSampleFormat sample_fmt)
225cabdff1aSopenharmony_ci{
226cabdff1aSopenharmony_ci    int planar      = av_sample_fmt_is_planar(sample_fmt);
227cabdff1aSopenharmony_ci    int planes      = planar ? nb_channels : 1;
228cabdff1aSopenharmony_ci    int block_align = av_get_bytes_per_sample(sample_fmt) * (planar ? 1 : nb_channels);
229cabdff1aSopenharmony_ci    int data_size   = nb_samples * block_align;
230cabdff1aSopenharmony_ci    int i;
231cabdff1aSopenharmony_ci
232cabdff1aSopenharmony_ci    dst_offset *= block_align;
233cabdff1aSopenharmony_ci    src_offset *= block_align;
234cabdff1aSopenharmony_ci
235cabdff1aSopenharmony_ci    if((dst[0] < src[0] ? src[0] - dst[0] : dst[0] - src[0]) >= data_size) {
236cabdff1aSopenharmony_ci        for (i = 0; i < planes; i++)
237cabdff1aSopenharmony_ci            memcpy(dst[i] + dst_offset, src[i] + src_offset, data_size);
238cabdff1aSopenharmony_ci    } else {
239cabdff1aSopenharmony_ci        for (i = 0; i < planes; i++)
240cabdff1aSopenharmony_ci            memmove(dst[i] + dst_offset, src[i] + src_offset, data_size);
241cabdff1aSopenharmony_ci    }
242cabdff1aSopenharmony_ci
243cabdff1aSopenharmony_ci    return 0;
244cabdff1aSopenharmony_ci}
245cabdff1aSopenharmony_ci
246cabdff1aSopenharmony_ciint av_samples_set_silence(uint8_t **audio_data, int offset, int nb_samples,
247cabdff1aSopenharmony_ci                           int nb_channels, enum AVSampleFormat sample_fmt)
248cabdff1aSopenharmony_ci{
249cabdff1aSopenharmony_ci    int planar      = av_sample_fmt_is_planar(sample_fmt);
250cabdff1aSopenharmony_ci    int planes      = planar ? nb_channels : 1;
251cabdff1aSopenharmony_ci    int block_align = av_get_bytes_per_sample(sample_fmt) * (planar ? 1 : nb_channels);
252cabdff1aSopenharmony_ci    int data_size   = nb_samples * block_align;
253cabdff1aSopenharmony_ci    int fill_char   = (sample_fmt == AV_SAMPLE_FMT_U8 ||
254cabdff1aSopenharmony_ci                     sample_fmt == AV_SAMPLE_FMT_U8P) ? 0x80 : 0x00;
255cabdff1aSopenharmony_ci    int i;
256cabdff1aSopenharmony_ci
257cabdff1aSopenharmony_ci    offset *= block_align;
258cabdff1aSopenharmony_ci
259cabdff1aSopenharmony_ci    for (i = 0; i < planes; i++)
260cabdff1aSopenharmony_ci        memset(audio_data[i] + offset, fill_char, data_size);
261cabdff1aSopenharmony_ci
262cabdff1aSopenharmony_ci    return 0;
263cabdff1aSopenharmony_ci}
264