1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
3cabdff1aSopenharmony_ci *
4cabdff1aSopenharmony_ci * This file is part of FFmpeg.
5cabdff1aSopenharmony_ci *
6cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
7cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
8cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
9cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
10cabdff1aSopenharmony_ci *
11cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
12cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
13cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14cabdff1aSopenharmony_ci * Lesser General Public License for more details.
15cabdff1aSopenharmony_ci *
16cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
17cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
18cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19cabdff1aSopenharmony_ci */
20cabdff1aSopenharmony_ci
21cabdff1aSopenharmony_ci#include <stdint.h>
22cabdff1aSopenharmony_ci#include <string.h>
23cabdff1aSopenharmony_ci
24cabdff1aSopenharmony_ci#include "libavutil/mem.h"
25cabdff1aSopenharmony_ci#include "audio_data.h"
26cabdff1aSopenharmony_ci
27cabdff1aSopenharmony_cistatic const AVClass audio_data_class = {
28cabdff1aSopenharmony_ci    .class_name = "AudioData",
29cabdff1aSopenharmony_ci    .item_name  = av_default_item_name,
30cabdff1aSopenharmony_ci    .version    = LIBAVUTIL_VERSION_INT,
31cabdff1aSopenharmony_ci};
32cabdff1aSopenharmony_ci
33cabdff1aSopenharmony_ci/*
34cabdff1aSopenharmony_ci * Calculate alignment for data pointers.
35cabdff1aSopenharmony_ci */
36cabdff1aSopenharmony_cistatic void calc_ptr_alignment(AudioData *a)
37cabdff1aSopenharmony_ci{
38cabdff1aSopenharmony_ci    int p;
39cabdff1aSopenharmony_ci    int min_align = 128;
40cabdff1aSopenharmony_ci
41cabdff1aSopenharmony_ci    for (p = 0; p < a->planes; p++) {
42cabdff1aSopenharmony_ci        int cur_align = 128;
43cabdff1aSopenharmony_ci        while ((intptr_t)a->data[p] % cur_align)
44cabdff1aSopenharmony_ci            cur_align >>= 1;
45cabdff1aSopenharmony_ci        if (cur_align < min_align)
46cabdff1aSopenharmony_ci            min_align = cur_align;
47cabdff1aSopenharmony_ci    }
48cabdff1aSopenharmony_ci    a->ptr_align = min_align;
49cabdff1aSopenharmony_ci}
50cabdff1aSopenharmony_ci
51cabdff1aSopenharmony_ciint ff_sample_fmt_is_planar(enum AVSampleFormat sample_fmt, int channels)
52cabdff1aSopenharmony_ci{
53cabdff1aSopenharmony_ci    if (channels == 1)
54cabdff1aSopenharmony_ci        return 1;
55cabdff1aSopenharmony_ci    else
56cabdff1aSopenharmony_ci        return av_sample_fmt_is_planar(sample_fmt);
57cabdff1aSopenharmony_ci}
58cabdff1aSopenharmony_ci
59cabdff1aSopenharmony_ciint ff_audio_data_set_channels(AudioData *a, int channels)
60cabdff1aSopenharmony_ci{
61cabdff1aSopenharmony_ci    if (channels < 1 || channels > AVRESAMPLE_MAX_CHANNELS ||
62cabdff1aSopenharmony_ci        channels > a->allocated_channels)
63cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
64cabdff1aSopenharmony_ci
65cabdff1aSopenharmony_ci    a->channels  = channels;
66cabdff1aSopenharmony_ci    a->planes    = a->is_planar ? channels : 1;
67cabdff1aSopenharmony_ci
68cabdff1aSopenharmony_ci    calc_ptr_alignment(a);
69cabdff1aSopenharmony_ci
70cabdff1aSopenharmony_ci    return 0;
71cabdff1aSopenharmony_ci}
72cabdff1aSopenharmony_ci
73cabdff1aSopenharmony_ciint ff_audio_data_init(AudioData *a, uint8_t * const *src, int plane_size,
74cabdff1aSopenharmony_ci                       int channels, int nb_samples,
75cabdff1aSopenharmony_ci                       enum AVSampleFormat sample_fmt, int read_only,
76cabdff1aSopenharmony_ci                       const char *name)
77cabdff1aSopenharmony_ci{
78cabdff1aSopenharmony_ci    int p;
79cabdff1aSopenharmony_ci
80cabdff1aSopenharmony_ci    memset(a, 0, sizeof(*a));
81cabdff1aSopenharmony_ci    a->class = &audio_data_class;
82cabdff1aSopenharmony_ci
83cabdff1aSopenharmony_ci    if (channels < 1 || channels > AVRESAMPLE_MAX_CHANNELS) {
84cabdff1aSopenharmony_ci        av_log(a, AV_LOG_ERROR, "invalid channel count: %d\n", channels);
85cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
86cabdff1aSopenharmony_ci    }
87cabdff1aSopenharmony_ci
88cabdff1aSopenharmony_ci    a->sample_size = av_get_bytes_per_sample(sample_fmt);
89cabdff1aSopenharmony_ci    if (!a->sample_size) {
90cabdff1aSopenharmony_ci        av_log(a, AV_LOG_ERROR, "invalid sample format\n");
91cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
92cabdff1aSopenharmony_ci    }
93cabdff1aSopenharmony_ci    a->is_planar = ff_sample_fmt_is_planar(sample_fmt, channels);
94cabdff1aSopenharmony_ci    a->planes    = a->is_planar ? channels : 1;
95cabdff1aSopenharmony_ci    a->stride    = a->sample_size * (a->is_planar ? 1 : channels);
96cabdff1aSopenharmony_ci
97cabdff1aSopenharmony_ci    for (p = 0; p < (a->is_planar ? channels : 1); p++) {
98cabdff1aSopenharmony_ci        if (!src[p]) {
99cabdff1aSopenharmony_ci            av_log(a, AV_LOG_ERROR, "invalid NULL pointer for src[%d]\n", p);
100cabdff1aSopenharmony_ci            return AVERROR(EINVAL);
101cabdff1aSopenharmony_ci        }
102cabdff1aSopenharmony_ci        a->data[p] = src[p];
103cabdff1aSopenharmony_ci    }
104cabdff1aSopenharmony_ci    a->allocated_samples  = nb_samples * !read_only;
105cabdff1aSopenharmony_ci    a->nb_samples         = nb_samples;
106cabdff1aSopenharmony_ci    a->sample_fmt         = sample_fmt;
107cabdff1aSopenharmony_ci    a->channels           = channels;
108cabdff1aSopenharmony_ci    a->allocated_channels = channels;
109cabdff1aSopenharmony_ci    a->read_only          = read_only;
110cabdff1aSopenharmony_ci    a->allow_realloc      = 0;
111cabdff1aSopenharmony_ci    a->name               = name ? name : "{no name}";
112cabdff1aSopenharmony_ci
113cabdff1aSopenharmony_ci    calc_ptr_alignment(a);
114cabdff1aSopenharmony_ci    a->samples_align = plane_size / a->stride;
115cabdff1aSopenharmony_ci
116cabdff1aSopenharmony_ci    return 0;
117cabdff1aSopenharmony_ci}
118cabdff1aSopenharmony_ci
119cabdff1aSopenharmony_ciAudioData *ff_audio_data_alloc(int channels, int nb_samples,
120cabdff1aSopenharmony_ci                               enum AVSampleFormat sample_fmt, const char *name)
121cabdff1aSopenharmony_ci{
122cabdff1aSopenharmony_ci    AudioData *a;
123cabdff1aSopenharmony_ci    int ret;
124cabdff1aSopenharmony_ci
125cabdff1aSopenharmony_ci    if (channels < 1 || channels > AVRESAMPLE_MAX_CHANNELS)
126cabdff1aSopenharmony_ci        return NULL;
127cabdff1aSopenharmony_ci
128cabdff1aSopenharmony_ci    a = av_mallocz(sizeof(*a));
129cabdff1aSopenharmony_ci    if (!a)
130cabdff1aSopenharmony_ci        return NULL;
131cabdff1aSopenharmony_ci
132cabdff1aSopenharmony_ci    a->sample_size = av_get_bytes_per_sample(sample_fmt);
133cabdff1aSopenharmony_ci    if (!a->sample_size) {
134cabdff1aSopenharmony_ci        av_free(a);
135cabdff1aSopenharmony_ci        return NULL;
136cabdff1aSopenharmony_ci    }
137cabdff1aSopenharmony_ci    a->is_planar = ff_sample_fmt_is_planar(sample_fmt, channels);
138cabdff1aSopenharmony_ci    a->planes    = a->is_planar ? channels : 1;
139cabdff1aSopenharmony_ci    a->stride    = a->sample_size * (a->is_planar ? 1 : channels);
140cabdff1aSopenharmony_ci
141cabdff1aSopenharmony_ci    a->class              = &audio_data_class;
142cabdff1aSopenharmony_ci    a->sample_fmt         = sample_fmt;
143cabdff1aSopenharmony_ci    a->channels           = channels;
144cabdff1aSopenharmony_ci    a->allocated_channels = channels;
145cabdff1aSopenharmony_ci    a->read_only          = 0;
146cabdff1aSopenharmony_ci    a->allow_realloc      = 1;
147cabdff1aSopenharmony_ci    a->name               = name ? name : "{no name}";
148cabdff1aSopenharmony_ci
149cabdff1aSopenharmony_ci    if (nb_samples > 0) {
150cabdff1aSopenharmony_ci        ret = ff_audio_data_realloc(a, nb_samples);
151cabdff1aSopenharmony_ci        if (ret < 0) {
152cabdff1aSopenharmony_ci            av_free(a);
153cabdff1aSopenharmony_ci            return NULL;
154cabdff1aSopenharmony_ci        }
155cabdff1aSopenharmony_ci        return a;
156cabdff1aSopenharmony_ci    } else {
157cabdff1aSopenharmony_ci        calc_ptr_alignment(a);
158cabdff1aSopenharmony_ci        return a;
159cabdff1aSopenharmony_ci    }
160cabdff1aSopenharmony_ci}
161cabdff1aSopenharmony_ci
162cabdff1aSopenharmony_ciint ff_audio_data_realloc(AudioData *a, int nb_samples)
163cabdff1aSopenharmony_ci{
164cabdff1aSopenharmony_ci    int ret, new_buf_size, plane_size, p;
165cabdff1aSopenharmony_ci
166cabdff1aSopenharmony_ci    /* check if buffer is already large enough */
167cabdff1aSopenharmony_ci    if (a->allocated_samples >= nb_samples)
168cabdff1aSopenharmony_ci        return 0;
169cabdff1aSopenharmony_ci
170cabdff1aSopenharmony_ci    /* validate that the output is not read-only and realloc is allowed */
171cabdff1aSopenharmony_ci    if (a->read_only || !a->allow_realloc)
172cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
173cabdff1aSopenharmony_ci
174cabdff1aSopenharmony_ci    new_buf_size = av_samples_get_buffer_size(&plane_size,
175cabdff1aSopenharmony_ci                                              a->allocated_channels, nb_samples,
176cabdff1aSopenharmony_ci                                              a->sample_fmt, 0);
177cabdff1aSopenharmony_ci    if (new_buf_size < 0)
178cabdff1aSopenharmony_ci        return new_buf_size;
179cabdff1aSopenharmony_ci
180cabdff1aSopenharmony_ci    /* if there is already data in the buffer and the sample format is planar,
181cabdff1aSopenharmony_ci       allocate a new buffer and copy the data, otherwise just realloc the
182cabdff1aSopenharmony_ci       internal buffer and set new data pointers */
183cabdff1aSopenharmony_ci    if (a->nb_samples > 0 && a->is_planar) {
184cabdff1aSopenharmony_ci        uint8_t *new_data[AVRESAMPLE_MAX_CHANNELS] = { NULL };
185cabdff1aSopenharmony_ci
186cabdff1aSopenharmony_ci        ret = av_samples_alloc(new_data, &plane_size, a->allocated_channels,
187cabdff1aSopenharmony_ci                               nb_samples, a->sample_fmt, 0);
188cabdff1aSopenharmony_ci        if (ret < 0)
189cabdff1aSopenharmony_ci            return ret;
190cabdff1aSopenharmony_ci
191cabdff1aSopenharmony_ci        for (p = 0; p < a->planes; p++)
192cabdff1aSopenharmony_ci            memcpy(new_data[p], a->data[p], a->nb_samples * a->stride);
193cabdff1aSopenharmony_ci
194cabdff1aSopenharmony_ci        av_freep(&a->buffer);
195cabdff1aSopenharmony_ci        memcpy(a->data, new_data, sizeof(new_data));
196cabdff1aSopenharmony_ci        a->buffer = a->data[0];
197cabdff1aSopenharmony_ci    } else {
198cabdff1aSopenharmony_ci        av_freep(&a->buffer);
199cabdff1aSopenharmony_ci        a->buffer = av_malloc(new_buf_size);
200cabdff1aSopenharmony_ci        if (!a->buffer)
201cabdff1aSopenharmony_ci            return AVERROR(ENOMEM);
202cabdff1aSopenharmony_ci        ret = av_samples_fill_arrays(a->data, &plane_size, a->buffer,
203cabdff1aSopenharmony_ci                                     a->allocated_channels, nb_samples,
204cabdff1aSopenharmony_ci                                     a->sample_fmt, 0);
205cabdff1aSopenharmony_ci        if (ret < 0)
206cabdff1aSopenharmony_ci            return ret;
207cabdff1aSopenharmony_ci    }
208cabdff1aSopenharmony_ci    a->buffer_size       = new_buf_size;
209cabdff1aSopenharmony_ci    a->allocated_samples = nb_samples;
210cabdff1aSopenharmony_ci
211cabdff1aSopenharmony_ci    calc_ptr_alignment(a);
212cabdff1aSopenharmony_ci    a->samples_align = plane_size / a->stride;
213cabdff1aSopenharmony_ci
214cabdff1aSopenharmony_ci    return 0;
215cabdff1aSopenharmony_ci}
216cabdff1aSopenharmony_ci
217cabdff1aSopenharmony_civoid ff_audio_data_free(AudioData **a)
218cabdff1aSopenharmony_ci{
219cabdff1aSopenharmony_ci    if (!*a)
220cabdff1aSopenharmony_ci        return;
221cabdff1aSopenharmony_ci    av_free((*a)->buffer);
222cabdff1aSopenharmony_ci    av_freep(a);
223cabdff1aSopenharmony_ci}
224cabdff1aSopenharmony_ci
225cabdff1aSopenharmony_ciint ff_audio_data_copy(AudioData *dst, AudioData *src, ChannelMapInfo *map)
226cabdff1aSopenharmony_ci{
227cabdff1aSopenharmony_ci    int ret, p;
228cabdff1aSopenharmony_ci
229cabdff1aSopenharmony_ci    /* validate input/output compatibility */
230cabdff1aSopenharmony_ci    if (dst->sample_fmt != src->sample_fmt || dst->channels < src->channels)
231cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
232cabdff1aSopenharmony_ci
233cabdff1aSopenharmony_ci    if (map && !src->is_planar) {
234cabdff1aSopenharmony_ci        av_log(src, AV_LOG_ERROR, "cannot remap packed format during copy\n");
235cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
236cabdff1aSopenharmony_ci    }
237cabdff1aSopenharmony_ci
238cabdff1aSopenharmony_ci    /* if the input is empty, just empty the output */
239cabdff1aSopenharmony_ci    if (!src->nb_samples) {
240cabdff1aSopenharmony_ci        dst->nb_samples = 0;
241cabdff1aSopenharmony_ci        return 0;
242cabdff1aSopenharmony_ci    }
243cabdff1aSopenharmony_ci
244cabdff1aSopenharmony_ci    /* reallocate output if necessary */
245cabdff1aSopenharmony_ci    ret = ff_audio_data_realloc(dst, src->nb_samples);
246cabdff1aSopenharmony_ci    if (ret < 0)
247cabdff1aSopenharmony_ci        return ret;
248cabdff1aSopenharmony_ci
249cabdff1aSopenharmony_ci    /* copy data */
250cabdff1aSopenharmony_ci    if (map) {
251cabdff1aSopenharmony_ci        if (map->do_remap) {
252cabdff1aSopenharmony_ci            for (p = 0; p < src->planes; p++) {
253cabdff1aSopenharmony_ci                if (map->channel_map[p] >= 0)
254cabdff1aSopenharmony_ci                    memcpy(dst->data[p], src->data[map->channel_map[p]],
255cabdff1aSopenharmony_ci                           src->nb_samples * src->stride);
256cabdff1aSopenharmony_ci            }
257cabdff1aSopenharmony_ci        }
258cabdff1aSopenharmony_ci        if (map->do_copy || map->do_zero) {
259cabdff1aSopenharmony_ci            for (p = 0; p < src->planes; p++) {
260cabdff1aSopenharmony_ci                if (map->channel_copy[p])
261cabdff1aSopenharmony_ci                    memcpy(dst->data[p], dst->data[map->channel_copy[p]],
262cabdff1aSopenharmony_ci                           src->nb_samples * src->stride);
263cabdff1aSopenharmony_ci                else if (map->channel_zero[p])
264cabdff1aSopenharmony_ci                    av_samples_set_silence(&dst->data[p], 0, src->nb_samples,
265cabdff1aSopenharmony_ci                                           1, dst->sample_fmt);
266cabdff1aSopenharmony_ci            }
267cabdff1aSopenharmony_ci        }
268cabdff1aSopenharmony_ci    } else {
269cabdff1aSopenharmony_ci        for (p = 0; p < src->planes; p++)
270cabdff1aSopenharmony_ci            memcpy(dst->data[p], src->data[p], src->nb_samples * src->stride);
271cabdff1aSopenharmony_ci    }
272cabdff1aSopenharmony_ci
273cabdff1aSopenharmony_ci    dst->nb_samples = src->nb_samples;
274cabdff1aSopenharmony_ci
275cabdff1aSopenharmony_ci    return 0;
276cabdff1aSopenharmony_ci}
277cabdff1aSopenharmony_ci
278cabdff1aSopenharmony_ciint ff_audio_data_combine(AudioData *dst, int dst_offset, AudioData *src,
279cabdff1aSopenharmony_ci                          int src_offset, int nb_samples)
280cabdff1aSopenharmony_ci{
281cabdff1aSopenharmony_ci    int ret, p, dst_offset2, dst_move_size;
282cabdff1aSopenharmony_ci
283cabdff1aSopenharmony_ci    /* validate input/output compatibility */
284cabdff1aSopenharmony_ci    if (dst->sample_fmt != src->sample_fmt || dst->channels != src->channels) {
285cabdff1aSopenharmony_ci        av_log(src, AV_LOG_ERROR, "sample format mismatch\n");
286cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
287cabdff1aSopenharmony_ci    }
288cabdff1aSopenharmony_ci
289cabdff1aSopenharmony_ci    /* validate offsets are within the buffer bounds */
290cabdff1aSopenharmony_ci    if (dst_offset < 0 || dst_offset > dst->nb_samples ||
291cabdff1aSopenharmony_ci        src_offset < 0 || src_offset > src->nb_samples) {
292cabdff1aSopenharmony_ci        av_log(src, AV_LOG_ERROR, "offset out-of-bounds: src=%d dst=%d\n",
293cabdff1aSopenharmony_ci               src_offset, dst_offset);
294cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
295cabdff1aSopenharmony_ci    }
296cabdff1aSopenharmony_ci
297cabdff1aSopenharmony_ci    /* check offsets and sizes to see if we can just do nothing and return */
298cabdff1aSopenharmony_ci    if (nb_samples > src->nb_samples - src_offset)
299cabdff1aSopenharmony_ci        nb_samples = src->nb_samples - src_offset;
300cabdff1aSopenharmony_ci    if (nb_samples <= 0)
301cabdff1aSopenharmony_ci        return 0;
302cabdff1aSopenharmony_ci
303cabdff1aSopenharmony_ci    /* validate that the output is not read-only */
304cabdff1aSopenharmony_ci    if (dst->read_only) {
305cabdff1aSopenharmony_ci        av_log(dst, AV_LOG_ERROR, "dst is read-only\n");
306cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
307cabdff1aSopenharmony_ci    }
308cabdff1aSopenharmony_ci
309cabdff1aSopenharmony_ci    /* reallocate output if necessary */
310cabdff1aSopenharmony_ci    ret = ff_audio_data_realloc(dst, dst->nb_samples + nb_samples);
311cabdff1aSopenharmony_ci    if (ret < 0) {
312cabdff1aSopenharmony_ci        av_log(dst, AV_LOG_ERROR, "error reallocating dst\n");
313cabdff1aSopenharmony_ci        return ret;
314cabdff1aSopenharmony_ci    }
315cabdff1aSopenharmony_ci
316cabdff1aSopenharmony_ci    dst_offset2   = dst_offset + nb_samples;
317cabdff1aSopenharmony_ci    dst_move_size = dst->nb_samples - dst_offset;
318cabdff1aSopenharmony_ci
319cabdff1aSopenharmony_ci    for (p = 0; p < src->planes; p++) {
320cabdff1aSopenharmony_ci        if (dst_move_size > 0) {
321cabdff1aSopenharmony_ci            memmove(dst->data[p] + dst_offset2 * dst->stride,
322cabdff1aSopenharmony_ci                    dst->data[p] + dst_offset  * dst->stride,
323cabdff1aSopenharmony_ci                    dst_move_size * dst->stride);
324cabdff1aSopenharmony_ci        }
325cabdff1aSopenharmony_ci        memcpy(dst->data[p] + dst_offset * dst->stride,
326cabdff1aSopenharmony_ci               src->data[p] + src_offset * src->stride,
327cabdff1aSopenharmony_ci               nb_samples * src->stride);
328cabdff1aSopenharmony_ci    }
329cabdff1aSopenharmony_ci    dst->nb_samples += nb_samples;
330cabdff1aSopenharmony_ci
331cabdff1aSopenharmony_ci    return 0;
332cabdff1aSopenharmony_ci}
333cabdff1aSopenharmony_ci
334cabdff1aSopenharmony_civoid ff_audio_data_drain(AudioData *a, int nb_samples)
335cabdff1aSopenharmony_ci{
336cabdff1aSopenharmony_ci    if (a->nb_samples <= nb_samples) {
337cabdff1aSopenharmony_ci        /* drain the whole buffer */
338cabdff1aSopenharmony_ci        a->nb_samples = 0;
339cabdff1aSopenharmony_ci    } else {
340cabdff1aSopenharmony_ci        int p;
341cabdff1aSopenharmony_ci        int move_offset = a->stride * nb_samples;
342cabdff1aSopenharmony_ci        int move_size   = a->stride * (a->nb_samples - nb_samples);
343cabdff1aSopenharmony_ci
344cabdff1aSopenharmony_ci        for (p = 0; p < a->planes; p++)
345cabdff1aSopenharmony_ci            memmove(a->data[p], a->data[p] + move_offset, move_size);
346cabdff1aSopenharmony_ci
347cabdff1aSopenharmony_ci        a->nb_samples -= nb_samples;
348cabdff1aSopenharmony_ci    }
349cabdff1aSopenharmony_ci}
350cabdff1aSopenharmony_ci
351cabdff1aSopenharmony_ciint ff_audio_data_add_to_fifo(AVAudioFifo *af, AudioData *a, int offset,
352cabdff1aSopenharmony_ci                              int nb_samples)
353cabdff1aSopenharmony_ci{
354cabdff1aSopenharmony_ci    uint8_t *offset_data[AVRESAMPLE_MAX_CHANNELS];
355cabdff1aSopenharmony_ci    int offset_size, p;
356cabdff1aSopenharmony_ci
357cabdff1aSopenharmony_ci    if (offset >= a->nb_samples)
358cabdff1aSopenharmony_ci        return 0;
359cabdff1aSopenharmony_ci    offset_size = offset * a->stride;
360cabdff1aSopenharmony_ci    for (p = 0; p < a->planes; p++)
361cabdff1aSopenharmony_ci        offset_data[p] = a->data[p] + offset_size;
362cabdff1aSopenharmony_ci
363cabdff1aSopenharmony_ci    return av_audio_fifo_write(af, (void **)offset_data, nb_samples);
364cabdff1aSopenharmony_ci}
365cabdff1aSopenharmony_ci
366cabdff1aSopenharmony_ciint ff_audio_data_read_from_fifo(AVAudioFifo *af, AudioData *a, int nb_samples)
367cabdff1aSopenharmony_ci{
368cabdff1aSopenharmony_ci    int ret;
369cabdff1aSopenharmony_ci
370cabdff1aSopenharmony_ci    if (a->read_only)
371cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
372cabdff1aSopenharmony_ci
373cabdff1aSopenharmony_ci    ret = ff_audio_data_realloc(a, nb_samples);
374cabdff1aSopenharmony_ci    if (ret < 0)
375cabdff1aSopenharmony_ci        return ret;
376cabdff1aSopenharmony_ci
377cabdff1aSopenharmony_ci    ret = av_audio_fifo_read(af, (void **)a->data, nb_samples);
378cabdff1aSopenharmony_ci    if (ret >= 0)
379cabdff1aSopenharmony_ci        a->nb_samples = ret;
380cabdff1aSopenharmony_ci    return ret;
381cabdff1aSopenharmony_ci}
382