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 "libavutil/common.h"
22cabdff1aSopenharmony_ci#include "libavutil/dict.h"
23cabdff1aSopenharmony_ci// #include "libavutil/error.h"
24cabdff1aSopenharmony_ci#include "libavutil/frame.h"
25cabdff1aSopenharmony_ci#include "libavutil/log.h"
26cabdff1aSopenharmony_ci#include "libavutil/mem.h"
27cabdff1aSopenharmony_ci#include "libavutil/opt.h"
28cabdff1aSopenharmony_ci
29cabdff1aSopenharmony_ci#include "avresample.h"
30cabdff1aSopenharmony_ci#include "internal.h"
31cabdff1aSopenharmony_ci#include "audio_data.h"
32cabdff1aSopenharmony_ci#include "audio_convert.h"
33cabdff1aSopenharmony_ci#include "audio_mix.h"
34cabdff1aSopenharmony_ci#include "resample.h"
35cabdff1aSopenharmony_ci
36cabdff1aSopenharmony_ciint avresample_open(AVAudioResampleContext *avr)
37cabdff1aSopenharmony_ci{
38cabdff1aSopenharmony_ci    int ret;
39cabdff1aSopenharmony_ci
40cabdff1aSopenharmony_ci    if (avresample_is_open(avr)) {
41cabdff1aSopenharmony_ci        av_log(avr, AV_LOG_ERROR, "The resampling context is already open.\n");
42cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
43cabdff1aSopenharmony_ci    }
44cabdff1aSopenharmony_ci
45cabdff1aSopenharmony_ci    /* set channel mixing parameters */
46cabdff1aSopenharmony_ci    avr->in_channels = av_get_channel_layout_nb_channels(avr->in_channel_layout);
47cabdff1aSopenharmony_ci    if (avr->in_channels <= 0 || avr->in_channels > AVRESAMPLE_MAX_CHANNELS) {
48cabdff1aSopenharmony_ci        av_log(avr, AV_LOG_ERROR, "Invalid input channel layout: %"PRIu64"\n",
49cabdff1aSopenharmony_ci               avr->in_channel_layout);
50cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
51cabdff1aSopenharmony_ci    }
52cabdff1aSopenharmony_ci    avr->out_channels = av_get_channel_layout_nb_channels(avr->out_channel_layout);
53cabdff1aSopenharmony_ci    if (avr->out_channels <= 0 || avr->out_channels > AVRESAMPLE_MAX_CHANNELS) {
54cabdff1aSopenharmony_ci        av_log(avr, AV_LOG_ERROR, "Invalid output channel layout: %"PRIu64"\n",
55cabdff1aSopenharmony_ci               avr->out_channel_layout);
56cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
57cabdff1aSopenharmony_ci    }
58cabdff1aSopenharmony_ci    avr->resample_channels = FFMIN(avr->in_channels, avr->out_channels);
59cabdff1aSopenharmony_ci    avr->downmix_needed    = avr->in_channels  > avr->out_channels;
60cabdff1aSopenharmony_ci    avr->upmix_needed      = avr->out_channels > avr->in_channels ||
61cabdff1aSopenharmony_ci                             (!avr->downmix_needed && (avr->mix_matrix ||
62cabdff1aSopenharmony_ci                              avr->in_channel_layout != avr->out_channel_layout));
63cabdff1aSopenharmony_ci    avr->mixing_needed     = avr->downmix_needed || avr->upmix_needed;
64cabdff1aSopenharmony_ci
65cabdff1aSopenharmony_ci    /* set resampling parameters */
66cabdff1aSopenharmony_ci    avr->resample_needed   = avr->in_sample_rate != avr->out_sample_rate ||
67cabdff1aSopenharmony_ci                             avr->force_resampling;
68cabdff1aSopenharmony_ci
69cabdff1aSopenharmony_ci    /* select internal sample format if not specified by the user */
70cabdff1aSopenharmony_ci    if (avr->internal_sample_fmt == AV_SAMPLE_FMT_NONE &&
71cabdff1aSopenharmony_ci        (avr->mixing_needed || avr->resample_needed)) {
72cabdff1aSopenharmony_ci        enum AVSampleFormat  in_fmt = av_get_planar_sample_fmt(avr->in_sample_fmt);
73cabdff1aSopenharmony_ci        enum AVSampleFormat out_fmt = av_get_planar_sample_fmt(avr->out_sample_fmt);
74cabdff1aSopenharmony_ci        int max_bps = FFMAX(av_get_bytes_per_sample(in_fmt),
75cabdff1aSopenharmony_ci                            av_get_bytes_per_sample(out_fmt));
76cabdff1aSopenharmony_ci        if (max_bps <= 2) {
77cabdff1aSopenharmony_ci            avr->internal_sample_fmt = AV_SAMPLE_FMT_S16P;
78cabdff1aSopenharmony_ci        } else if (avr->mixing_needed) {
79cabdff1aSopenharmony_ci            avr->internal_sample_fmt = AV_SAMPLE_FMT_FLTP;
80cabdff1aSopenharmony_ci        } else {
81cabdff1aSopenharmony_ci            if (max_bps <= 4) {
82cabdff1aSopenharmony_ci                if (in_fmt  == AV_SAMPLE_FMT_S32P ||
83cabdff1aSopenharmony_ci                    out_fmt == AV_SAMPLE_FMT_S32P) {
84cabdff1aSopenharmony_ci                    if (in_fmt  == AV_SAMPLE_FMT_FLTP ||
85cabdff1aSopenharmony_ci                        out_fmt == AV_SAMPLE_FMT_FLTP) {
86cabdff1aSopenharmony_ci                        /* if one is s32 and the other is flt, use dbl */
87cabdff1aSopenharmony_ci                        avr->internal_sample_fmt = AV_SAMPLE_FMT_DBLP;
88cabdff1aSopenharmony_ci                    } else {
89cabdff1aSopenharmony_ci                        /* if one is s32 and the other is s32, s16, or u8, use s32 */
90cabdff1aSopenharmony_ci                        avr->internal_sample_fmt = AV_SAMPLE_FMT_S32P;
91cabdff1aSopenharmony_ci                    }
92cabdff1aSopenharmony_ci                } else {
93cabdff1aSopenharmony_ci                    /* if one is flt and the other is flt, s16 or u8, use flt */
94cabdff1aSopenharmony_ci                    avr->internal_sample_fmt = AV_SAMPLE_FMT_FLTP;
95cabdff1aSopenharmony_ci                }
96cabdff1aSopenharmony_ci            } else {
97cabdff1aSopenharmony_ci                /* if either is dbl, use dbl */
98cabdff1aSopenharmony_ci                avr->internal_sample_fmt = AV_SAMPLE_FMT_DBLP;
99cabdff1aSopenharmony_ci            }
100cabdff1aSopenharmony_ci        }
101cabdff1aSopenharmony_ci        av_log(avr, AV_LOG_DEBUG, "Using %s as internal sample format\n",
102cabdff1aSopenharmony_ci               av_get_sample_fmt_name(avr->internal_sample_fmt));
103cabdff1aSopenharmony_ci    }
104cabdff1aSopenharmony_ci
105cabdff1aSopenharmony_ci    /* we may need to add an extra conversion in order to remap channels if
106cabdff1aSopenharmony_ci       the output format is not planar */
107cabdff1aSopenharmony_ci    if (avr->use_channel_map && !avr->mixing_needed && !avr->resample_needed &&
108cabdff1aSopenharmony_ci        !ff_sample_fmt_is_planar(avr->out_sample_fmt, avr->out_channels)) {
109cabdff1aSopenharmony_ci        avr->internal_sample_fmt = av_get_planar_sample_fmt(avr->out_sample_fmt);
110cabdff1aSopenharmony_ci    }
111cabdff1aSopenharmony_ci
112cabdff1aSopenharmony_ci    /* set sample format conversion parameters */
113cabdff1aSopenharmony_ci    if (avr->resample_needed || avr->mixing_needed)
114cabdff1aSopenharmony_ci        avr->in_convert_needed = avr->in_sample_fmt != avr->internal_sample_fmt;
115cabdff1aSopenharmony_ci    else
116cabdff1aSopenharmony_ci        avr->in_convert_needed = avr->use_channel_map &&
117cabdff1aSopenharmony_ci                                 !ff_sample_fmt_is_planar(avr->out_sample_fmt, avr->out_channels);
118cabdff1aSopenharmony_ci
119cabdff1aSopenharmony_ci    if (avr->resample_needed || avr->mixing_needed || avr->in_convert_needed)
120cabdff1aSopenharmony_ci        avr->out_convert_needed = avr->internal_sample_fmt != avr->out_sample_fmt;
121cabdff1aSopenharmony_ci    else
122cabdff1aSopenharmony_ci        avr->out_convert_needed = avr->in_sample_fmt != avr->out_sample_fmt;
123cabdff1aSopenharmony_ci
124cabdff1aSopenharmony_ci    avr->in_copy_needed = !avr->in_convert_needed && (avr->mixing_needed ||
125cabdff1aSopenharmony_ci                          (avr->use_channel_map && avr->resample_needed));
126cabdff1aSopenharmony_ci
127cabdff1aSopenharmony_ci    if (avr->use_channel_map) {
128cabdff1aSopenharmony_ci        if (avr->in_copy_needed) {
129cabdff1aSopenharmony_ci            avr->remap_point = REMAP_IN_COPY;
130cabdff1aSopenharmony_ci            av_log(avr, AV_LOG_TRACE, "remap channels during in_copy\n");
131cabdff1aSopenharmony_ci        } else if (avr->in_convert_needed) {
132cabdff1aSopenharmony_ci            avr->remap_point = REMAP_IN_CONVERT;
133cabdff1aSopenharmony_ci            av_log(avr, AV_LOG_TRACE, "remap channels during in_convert\n");
134cabdff1aSopenharmony_ci        } else if (avr->out_convert_needed) {
135cabdff1aSopenharmony_ci            avr->remap_point = REMAP_OUT_CONVERT;
136cabdff1aSopenharmony_ci            av_log(avr, AV_LOG_TRACE, "remap channels during out_convert\n");
137cabdff1aSopenharmony_ci        } else {
138cabdff1aSopenharmony_ci            avr->remap_point = REMAP_OUT_COPY;
139cabdff1aSopenharmony_ci            av_log(avr, AV_LOG_TRACE, "remap channels during out_copy\n");
140cabdff1aSopenharmony_ci        }
141cabdff1aSopenharmony_ci
142cabdff1aSopenharmony_ci#ifdef DEBUG
143cabdff1aSopenharmony_ci        {
144cabdff1aSopenharmony_ci            int ch;
145cabdff1aSopenharmony_ci            av_log(avr, AV_LOG_TRACE, "output map: ");
146cabdff1aSopenharmony_ci            if (avr->ch_map_info.do_remap)
147cabdff1aSopenharmony_ci                for (ch = 0; ch < avr->in_channels; ch++)
148cabdff1aSopenharmony_ci                    av_log(avr, AV_LOG_TRACE, " % 2d", avr->ch_map_info.channel_map[ch]);
149cabdff1aSopenharmony_ci            else
150cabdff1aSopenharmony_ci                av_log(avr, AV_LOG_TRACE, "n/a");
151cabdff1aSopenharmony_ci            av_log(avr, AV_LOG_TRACE, "\n");
152cabdff1aSopenharmony_ci            av_log(avr, AV_LOG_TRACE, "copy map:   ");
153cabdff1aSopenharmony_ci            if (avr->ch_map_info.do_copy)
154cabdff1aSopenharmony_ci                for (ch = 0; ch < avr->in_channels; ch++)
155cabdff1aSopenharmony_ci                    av_log(avr, AV_LOG_TRACE, " % 2d", avr->ch_map_info.channel_copy[ch]);
156cabdff1aSopenharmony_ci            else
157cabdff1aSopenharmony_ci                av_log(avr, AV_LOG_TRACE, "n/a");
158cabdff1aSopenharmony_ci            av_log(avr, AV_LOG_TRACE, "\n");
159cabdff1aSopenharmony_ci            av_log(avr, AV_LOG_TRACE, "zero map:   ");
160cabdff1aSopenharmony_ci            if (avr->ch_map_info.do_zero)
161cabdff1aSopenharmony_ci                for (ch = 0; ch < avr->in_channels; ch++)
162cabdff1aSopenharmony_ci                    av_log(avr, AV_LOG_TRACE, " % 2d", avr->ch_map_info.channel_zero[ch]);
163cabdff1aSopenharmony_ci            else
164cabdff1aSopenharmony_ci                av_log(avr, AV_LOG_TRACE, "n/a");
165cabdff1aSopenharmony_ci            av_log(avr, AV_LOG_TRACE, "\n");
166cabdff1aSopenharmony_ci            av_log(avr, AV_LOG_TRACE, "input map:  ");
167cabdff1aSopenharmony_ci            for (ch = 0; ch < avr->in_channels; ch++)
168cabdff1aSopenharmony_ci                av_log(avr, AV_LOG_TRACE, " % 2d", avr->ch_map_info.input_map[ch]);
169cabdff1aSopenharmony_ci            av_log(avr, AV_LOG_TRACE, "\n");
170cabdff1aSopenharmony_ci        }
171cabdff1aSopenharmony_ci#endif
172cabdff1aSopenharmony_ci    } else
173cabdff1aSopenharmony_ci        avr->remap_point = REMAP_NONE;
174cabdff1aSopenharmony_ci
175cabdff1aSopenharmony_ci    /* allocate buffers */
176cabdff1aSopenharmony_ci    if (avr->in_copy_needed || avr->in_convert_needed) {
177cabdff1aSopenharmony_ci        avr->in_buffer = ff_audio_data_alloc(FFMAX(avr->in_channels, avr->out_channels),
178cabdff1aSopenharmony_ci                                             0, avr->internal_sample_fmt,
179cabdff1aSopenharmony_ci                                             "in_buffer");
180cabdff1aSopenharmony_ci        if (!avr->in_buffer) {
181cabdff1aSopenharmony_ci            ret = AVERROR(EINVAL);
182cabdff1aSopenharmony_ci            goto error;
183cabdff1aSopenharmony_ci        }
184cabdff1aSopenharmony_ci    }
185cabdff1aSopenharmony_ci    if (avr->resample_needed) {
186cabdff1aSopenharmony_ci        avr->resample_out_buffer = ff_audio_data_alloc(avr->out_channels,
187cabdff1aSopenharmony_ci                                                       1024, avr->internal_sample_fmt,
188cabdff1aSopenharmony_ci                                                       "resample_out_buffer");
189cabdff1aSopenharmony_ci        if (!avr->resample_out_buffer) {
190cabdff1aSopenharmony_ci            ret = AVERROR(EINVAL);
191cabdff1aSopenharmony_ci            goto error;
192cabdff1aSopenharmony_ci        }
193cabdff1aSopenharmony_ci    }
194cabdff1aSopenharmony_ci    if (avr->out_convert_needed) {
195cabdff1aSopenharmony_ci        avr->out_buffer = ff_audio_data_alloc(avr->out_channels, 0,
196cabdff1aSopenharmony_ci                                              avr->out_sample_fmt, "out_buffer");
197cabdff1aSopenharmony_ci        if (!avr->out_buffer) {
198cabdff1aSopenharmony_ci            ret = AVERROR(EINVAL);
199cabdff1aSopenharmony_ci            goto error;
200cabdff1aSopenharmony_ci        }
201cabdff1aSopenharmony_ci    }
202cabdff1aSopenharmony_ci    avr->out_fifo = av_audio_fifo_alloc(avr->out_sample_fmt, avr->out_channels,
203cabdff1aSopenharmony_ci                                        1024);
204cabdff1aSopenharmony_ci    if (!avr->out_fifo) {
205cabdff1aSopenharmony_ci        ret = AVERROR(ENOMEM);
206cabdff1aSopenharmony_ci        goto error;
207cabdff1aSopenharmony_ci    }
208cabdff1aSopenharmony_ci
209cabdff1aSopenharmony_ci    /* setup contexts */
210cabdff1aSopenharmony_ci    if (avr->in_convert_needed) {
211cabdff1aSopenharmony_ci        avr->ac_in = ff_audio_convert_alloc(avr, avr->internal_sample_fmt,
212cabdff1aSopenharmony_ci                                            avr->in_sample_fmt, avr->in_channels,
213cabdff1aSopenharmony_ci                                            avr->in_sample_rate,
214cabdff1aSopenharmony_ci                                            avr->remap_point == REMAP_IN_CONVERT);
215cabdff1aSopenharmony_ci        if (!avr->ac_in) {
216cabdff1aSopenharmony_ci            ret = AVERROR(ENOMEM);
217cabdff1aSopenharmony_ci            goto error;
218cabdff1aSopenharmony_ci        }
219cabdff1aSopenharmony_ci    }
220cabdff1aSopenharmony_ci    if (avr->out_convert_needed) {
221cabdff1aSopenharmony_ci        enum AVSampleFormat src_fmt;
222cabdff1aSopenharmony_ci        if (avr->in_convert_needed)
223cabdff1aSopenharmony_ci            src_fmt = avr->internal_sample_fmt;
224cabdff1aSopenharmony_ci        else
225cabdff1aSopenharmony_ci            src_fmt = avr->in_sample_fmt;
226cabdff1aSopenharmony_ci        avr->ac_out = ff_audio_convert_alloc(avr, avr->out_sample_fmt, src_fmt,
227cabdff1aSopenharmony_ci                                             avr->out_channels,
228cabdff1aSopenharmony_ci                                             avr->out_sample_rate,
229cabdff1aSopenharmony_ci                                             avr->remap_point == REMAP_OUT_CONVERT);
230cabdff1aSopenharmony_ci        if (!avr->ac_out) {
231cabdff1aSopenharmony_ci            ret = AVERROR(ENOMEM);
232cabdff1aSopenharmony_ci            goto error;
233cabdff1aSopenharmony_ci        }
234cabdff1aSopenharmony_ci    }
235cabdff1aSopenharmony_ci    if (avr->resample_needed) {
236cabdff1aSopenharmony_ci        avr->resample = ff_audio_resample_init(avr);
237cabdff1aSopenharmony_ci        if (!avr->resample) {
238cabdff1aSopenharmony_ci            ret = AVERROR(ENOMEM);
239cabdff1aSopenharmony_ci            goto error;
240cabdff1aSopenharmony_ci        }
241cabdff1aSopenharmony_ci    }
242cabdff1aSopenharmony_ci    if (avr->mixing_needed) {
243cabdff1aSopenharmony_ci        avr->am = ff_audio_mix_alloc(avr);
244cabdff1aSopenharmony_ci        if (!avr->am) {
245cabdff1aSopenharmony_ci            ret = AVERROR(ENOMEM);
246cabdff1aSopenharmony_ci            goto error;
247cabdff1aSopenharmony_ci        }
248cabdff1aSopenharmony_ci    }
249cabdff1aSopenharmony_ci
250cabdff1aSopenharmony_ci    return 0;
251cabdff1aSopenharmony_ci
252cabdff1aSopenharmony_cierror:
253cabdff1aSopenharmony_ci    avresample_close(avr);
254cabdff1aSopenharmony_ci    return ret;
255cabdff1aSopenharmony_ci}
256cabdff1aSopenharmony_ci
257cabdff1aSopenharmony_ciint avresample_is_open(AVAudioResampleContext *avr)
258cabdff1aSopenharmony_ci{
259cabdff1aSopenharmony_ci    return !!avr->out_fifo;
260cabdff1aSopenharmony_ci}
261cabdff1aSopenharmony_ci
262cabdff1aSopenharmony_civoid avresample_close(AVAudioResampleContext *avr)
263cabdff1aSopenharmony_ci{
264cabdff1aSopenharmony_ci    ff_audio_data_free(&avr->in_buffer);
265cabdff1aSopenharmony_ci    ff_audio_data_free(&avr->resample_out_buffer);
266cabdff1aSopenharmony_ci    ff_audio_data_free(&avr->out_buffer);
267cabdff1aSopenharmony_ci    av_audio_fifo_free(avr->out_fifo);
268cabdff1aSopenharmony_ci    avr->out_fifo = NULL;
269cabdff1aSopenharmony_ci    ff_audio_convert_free(&avr->ac_in);
270cabdff1aSopenharmony_ci    ff_audio_convert_free(&avr->ac_out);
271cabdff1aSopenharmony_ci    ff_audio_resample_free(&avr->resample);
272cabdff1aSopenharmony_ci    ff_audio_mix_free(&avr->am);
273cabdff1aSopenharmony_ci    av_freep(&avr->mix_matrix);
274cabdff1aSopenharmony_ci
275cabdff1aSopenharmony_ci    avr->use_channel_map = 0;
276cabdff1aSopenharmony_ci}
277cabdff1aSopenharmony_ci
278cabdff1aSopenharmony_civoid avresample_free(AVAudioResampleContext **avr)
279cabdff1aSopenharmony_ci{
280cabdff1aSopenharmony_ci    if (!*avr)
281cabdff1aSopenharmony_ci        return;
282cabdff1aSopenharmony_ci    avresample_close(*avr);
283cabdff1aSopenharmony_ci    av_opt_free(*avr);
284cabdff1aSopenharmony_ci    av_freep(avr);
285cabdff1aSopenharmony_ci}
286cabdff1aSopenharmony_ci
287cabdff1aSopenharmony_cistatic int handle_buffered_output(AVAudioResampleContext *avr,
288cabdff1aSopenharmony_ci                                  AudioData *output, AudioData *converted)
289cabdff1aSopenharmony_ci{
290cabdff1aSopenharmony_ci    int ret;
291cabdff1aSopenharmony_ci
292cabdff1aSopenharmony_ci    if (!output || av_audio_fifo_size(avr->out_fifo) > 0 ||
293cabdff1aSopenharmony_ci        (converted && output->allocated_samples < converted->nb_samples)) {
294cabdff1aSopenharmony_ci        if (converted) {
295cabdff1aSopenharmony_ci            /* if there are any samples in the output FIFO or if the
296cabdff1aSopenharmony_ci               user-supplied output buffer is not large enough for all samples,
297cabdff1aSopenharmony_ci               we add to the output FIFO */
298cabdff1aSopenharmony_ci            av_log(avr, AV_LOG_TRACE, "[FIFO] add %s to out_fifo\n", converted->name);
299cabdff1aSopenharmony_ci            ret = ff_audio_data_add_to_fifo(avr->out_fifo, converted, 0,
300cabdff1aSopenharmony_ci                                            converted->nb_samples);
301cabdff1aSopenharmony_ci            if (ret < 0)
302cabdff1aSopenharmony_ci                return ret;
303cabdff1aSopenharmony_ci        }
304cabdff1aSopenharmony_ci
305cabdff1aSopenharmony_ci        /* if the user specified an output buffer, read samples from the output
306cabdff1aSopenharmony_ci           FIFO to the user output */
307cabdff1aSopenharmony_ci        if (output && output->allocated_samples > 0) {
308cabdff1aSopenharmony_ci            av_log(avr, AV_LOG_TRACE, "[FIFO] read from out_fifo to output\n");
309cabdff1aSopenharmony_ci            av_log(avr, AV_LOG_TRACE, "[end conversion]\n");
310cabdff1aSopenharmony_ci            return ff_audio_data_read_from_fifo(avr->out_fifo, output,
311cabdff1aSopenharmony_ci                                                output->allocated_samples);
312cabdff1aSopenharmony_ci        }
313cabdff1aSopenharmony_ci    } else if (converted) {
314cabdff1aSopenharmony_ci        /* copy directly to output if it is large enough or there is not any
315cabdff1aSopenharmony_ci           data in the output FIFO */
316cabdff1aSopenharmony_ci        av_log(avr, AV_LOG_TRACE, "[copy] %s to output\n", converted->name);
317cabdff1aSopenharmony_ci        output->nb_samples = 0;
318cabdff1aSopenharmony_ci        ret = ff_audio_data_copy(output, converted,
319cabdff1aSopenharmony_ci                                 avr->remap_point == REMAP_OUT_COPY ?
320cabdff1aSopenharmony_ci                                 &avr->ch_map_info : NULL);
321cabdff1aSopenharmony_ci        if (ret < 0)
322cabdff1aSopenharmony_ci            return ret;
323cabdff1aSopenharmony_ci        av_log(avr, AV_LOG_TRACE, "[end conversion]\n");
324cabdff1aSopenharmony_ci        return output->nb_samples;
325cabdff1aSopenharmony_ci    }
326cabdff1aSopenharmony_ci    av_log(avr, AV_LOG_TRACE, "[end conversion]\n");
327cabdff1aSopenharmony_ci    return 0;
328cabdff1aSopenharmony_ci}
329cabdff1aSopenharmony_ci
330cabdff1aSopenharmony_ciint attribute_align_arg avresample_convert(AVAudioResampleContext *avr,
331cabdff1aSopenharmony_ci                                           uint8_t **output, int out_plane_size,
332cabdff1aSopenharmony_ci                                           int out_samples,
333cabdff1aSopenharmony_ci                                           uint8_t * const *input,
334cabdff1aSopenharmony_ci                                           int in_plane_size, int in_samples)
335cabdff1aSopenharmony_ci{
336cabdff1aSopenharmony_ci    AudioData input_buffer;
337cabdff1aSopenharmony_ci    AudioData output_buffer;
338cabdff1aSopenharmony_ci    AudioData *current_buffer;
339cabdff1aSopenharmony_ci    int ret, direct_output;
340cabdff1aSopenharmony_ci
341cabdff1aSopenharmony_ci    /* reset internal buffers */
342cabdff1aSopenharmony_ci    if (avr->in_buffer) {
343cabdff1aSopenharmony_ci        avr->in_buffer->nb_samples = 0;
344cabdff1aSopenharmony_ci        ff_audio_data_set_channels(avr->in_buffer,
345cabdff1aSopenharmony_ci                                   avr->in_buffer->allocated_channels);
346cabdff1aSopenharmony_ci    }
347cabdff1aSopenharmony_ci    if (avr->resample_out_buffer) {
348cabdff1aSopenharmony_ci        avr->resample_out_buffer->nb_samples = 0;
349cabdff1aSopenharmony_ci        ff_audio_data_set_channels(avr->resample_out_buffer,
350cabdff1aSopenharmony_ci                                   avr->resample_out_buffer->allocated_channels);
351cabdff1aSopenharmony_ci    }
352cabdff1aSopenharmony_ci    if (avr->out_buffer) {
353cabdff1aSopenharmony_ci        avr->out_buffer->nb_samples = 0;
354cabdff1aSopenharmony_ci        ff_audio_data_set_channels(avr->out_buffer,
355cabdff1aSopenharmony_ci                                   avr->out_buffer->allocated_channels);
356cabdff1aSopenharmony_ci    }
357cabdff1aSopenharmony_ci
358cabdff1aSopenharmony_ci    av_log(avr, AV_LOG_TRACE, "[start conversion]\n");
359cabdff1aSopenharmony_ci
360cabdff1aSopenharmony_ci    /* initialize output_buffer with output data */
361cabdff1aSopenharmony_ci    direct_output = output && av_audio_fifo_size(avr->out_fifo) == 0;
362cabdff1aSopenharmony_ci    if (output) {
363cabdff1aSopenharmony_ci        ret = ff_audio_data_init(&output_buffer, output, out_plane_size,
364cabdff1aSopenharmony_ci                                 avr->out_channels, out_samples,
365cabdff1aSopenharmony_ci                                 avr->out_sample_fmt, 0, "output");
366cabdff1aSopenharmony_ci        if (ret < 0)
367cabdff1aSopenharmony_ci            return ret;
368cabdff1aSopenharmony_ci        output_buffer.nb_samples = 0;
369cabdff1aSopenharmony_ci    }
370cabdff1aSopenharmony_ci
371cabdff1aSopenharmony_ci    if (input) {
372cabdff1aSopenharmony_ci        /* initialize input_buffer with input data */
373cabdff1aSopenharmony_ci        ret = ff_audio_data_init(&input_buffer, input, in_plane_size,
374cabdff1aSopenharmony_ci                                 avr->in_channels, in_samples,
375cabdff1aSopenharmony_ci                                 avr->in_sample_fmt, 1, "input");
376cabdff1aSopenharmony_ci        if (ret < 0)
377cabdff1aSopenharmony_ci            return ret;
378cabdff1aSopenharmony_ci        current_buffer = &input_buffer;
379cabdff1aSopenharmony_ci
380cabdff1aSopenharmony_ci        if (avr->upmix_needed && !avr->in_convert_needed && !avr->resample_needed &&
381cabdff1aSopenharmony_ci            !avr->out_convert_needed && direct_output && out_samples >= in_samples) {
382cabdff1aSopenharmony_ci            /* in some rare cases we can copy input to output and upmix
383cabdff1aSopenharmony_ci               directly in the output buffer */
384cabdff1aSopenharmony_ci            av_log(avr, AV_LOG_TRACE, "[copy] %s to output\n", current_buffer->name);
385cabdff1aSopenharmony_ci            ret = ff_audio_data_copy(&output_buffer, current_buffer,
386cabdff1aSopenharmony_ci                                     avr->remap_point == REMAP_OUT_COPY ?
387cabdff1aSopenharmony_ci                                     &avr->ch_map_info : NULL);
388cabdff1aSopenharmony_ci            if (ret < 0)
389cabdff1aSopenharmony_ci                return ret;
390cabdff1aSopenharmony_ci            current_buffer = &output_buffer;
391cabdff1aSopenharmony_ci        } else if (avr->remap_point == REMAP_OUT_COPY &&
392cabdff1aSopenharmony_ci                   (!direct_output || out_samples < in_samples)) {
393cabdff1aSopenharmony_ci            /* if remapping channels during output copy, we may need to
394cabdff1aSopenharmony_ci             * use an intermediate buffer in order to remap before adding
395cabdff1aSopenharmony_ci             * samples to the output fifo */
396cabdff1aSopenharmony_ci            av_log(avr, AV_LOG_TRACE, "[copy] %s to out_buffer\n", current_buffer->name);
397cabdff1aSopenharmony_ci            ret = ff_audio_data_copy(avr->out_buffer, current_buffer,
398cabdff1aSopenharmony_ci                                     &avr->ch_map_info);
399cabdff1aSopenharmony_ci            if (ret < 0)
400cabdff1aSopenharmony_ci                return ret;
401cabdff1aSopenharmony_ci            current_buffer = avr->out_buffer;
402cabdff1aSopenharmony_ci        } else if (avr->in_copy_needed || avr->in_convert_needed) {
403cabdff1aSopenharmony_ci            /* if needed, copy or convert input to in_buffer, and downmix if
404cabdff1aSopenharmony_ci               applicable */
405cabdff1aSopenharmony_ci            if (avr->in_convert_needed) {
406cabdff1aSopenharmony_ci                ret = ff_audio_data_realloc(avr->in_buffer,
407cabdff1aSopenharmony_ci                                            current_buffer->nb_samples);
408cabdff1aSopenharmony_ci                if (ret < 0)
409cabdff1aSopenharmony_ci                    return ret;
410cabdff1aSopenharmony_ci                av_log(avr, AV_LOG_TRACE, "[convert] %s to in_buffer\n", current_buffer->name);
411cabdff1aSopenharmony_ci                ret = ff_audio_convert(avr->ac_in, avr->in_buffer,
412cabdff1aSopenharmony_ci                                       current_buffer);
413cabdff1aSopenharmony_ci                if (ret < 0)
414cabdff1aSopenharmony_ci                    return ret;
415cabdff1aSopenharmony_ci            } else {
416cabdff1aSopenharmony_ci                av_log(avr, AV_LOG_TRACE, "[copy] %s to in_buffer\n", current_buffer->name);
417cabdff1aSopenharmony_ci                ret = ff_audio_data_copy(avr->in_buffer, current_buffer,
418cabdff1aSopenharmony_ci                                         avr->remap_point == REMAP_IN_COPY ?
419cabdff1aSopenharmony_ci                                         &avr->ch_map_info : NULL);
420cabdff1aSopenharmony_ci                if (ret < 0)
421cabdff1aSopenharmony_ci                    return ret;
422cabdff1aSopenharmony_ci            }
423cabdff1aSopenharmony_ci            ff_audio_data_set_channels(avr->in_buffer, avr->in_channels);
424cabdff1aSopenharmony_ci            if (avr->downmix_needed) {
425cabdff1aSopenharmony_ci                av_log(avr, AV_LOG_TRACE, "[downmix] in_buffer\n");
426cabdff1aSopenharmony_ci                ret = ff_audio_mix(avr->am, avr->in_buffer);
427cabdff1aSopenharmony_ci                if (ret < 0)
428cabdff1aSopenharmony_ci                    return ret;
429cabdff1aSopenharmony_ci            }
430cabdff1aSopenharmony_ci            current_buffer = avr->in_buffer;
431cabdff1aSopenharmony_ci        }
432cabdff1aSopenharmony_ci    } else {
433cabdff1aSopenharmony_ci        /* flush resampling buffer and/or output FIFO if input is NULL */
434cabdff1aSopenharmony_ci        if (!avr->resample_needed)
435cabdff1aSopenharmony_ci            return handle_buffered_output(avr, output ? &output_buffer : NULL,
436cabdff1aSopenharmony_ci                                          NULL);
437cabdff1aSopenharmony_ci        current_buffer = NULL;
438cabdff1aSopenharmony_ci    }
439cabdff1aSopenharmony_ci
440cabdff1aSopenharmony_ci    if (avr->resample_needed) {
441cabdff1aSopenharmony_ci        AudioData *resample_out;
442cabdff1aSopenharmony_ci
443cabdff1aSopenharmony_ci        if (!avr->out_convert_needed && direct_output && out_samples > 0)
444cabdff1aSopenharmony_ci            resample_out = &output_buffer;
445cabdff1aSopenharmony_ci        else
446cabdff1aSopenharmony_ci            resample_out = avr->resample_out_buffer;
447cabdff1aSopenharmony_ci        av_log(avr, AV_LOG_TRACE, "[resample] %s to %s\n",
448cabdff1aSopenharmony_ci                current_buffer ? current_buffer->name : "null",
449cabdff1aSopenharmony_ci                resample_out->name);
450cabdff1aSopenharmony_ci        ret = ff_audio_resample(avr->resample, resample_out,
451cabdff1aSopenharmony_ci                                current_buffer);
452cabdff1aSopenharmony_ci        if (ret < 0)
453cabdff1aSopenharmony_ci            return ret;
454cabdff1aSopenharmony_ci
455cabdff1aSopenharmony_ci        /* if resampling did not produce any samples, just return 0 */
456cabdff1aSopenharmony_ci        if (resample_out->nb_samples == 0) {
457cabdff1aSopenharmony_ci            av_log(avr, AV_LOG_TRACE, "[end conversion]\n");
458cabdff1aSopenharmony_ci            return 0;
459cabdff1aSopenharmony_ci        }
460cabdff1aSopenharmony_ci
461cabdff1aSopenharmony_ci        current_buffer = resample_out;
462cabdff1aSopenharmony_ci    }
463cabdff1aSopenharmony_ci
464cabdff1aSopenharmony_ci    if (avr->upmix_needed) {
465cabdff1aSopenharmony_ci        av_log(avr, AV_LOG_TRACE, "[upmix] %s\n", current_buffer->name);
466cabdff1aSopenharmony_ci        ret = ff_audio_mix(avr->am, current_buffer);
467cabdff1aSopenharmony_ci        if (ret < 0)
468cabdff1aSopenharmony_ci            return ret;
469cabdff1aSopenharmony_ci    }
470cabdff1aSopenharmony_ci
471cabdff1aSopenharmony_ci    /* if we resampled or upmixed directly to output, return here */
472cabdff1aSopenharmony_ci    if (current_buffer == &output_buffer) {
473cabdff1aSopenharmony_ci        av_log(avr, AV_LOG_TRACE, "[end conversion]\n");
474cabdff1aSopenharmony_ci        return current_buffer->nb_samples;
475cabdff1aSopenharmony_ci    }
476cabdff1aSopenharmony_ci
477cabdff1aSopenharmony_ci    if (avr->out_convert_needed) {
478cabdff1aSopenharmony_ci        if (direct_output && out_samples >= current_buffer->nb_samples) {
479cabdff1aSopenharmony_ci            /* convert directly to output */
480cabdff1aSopenharmony_ci            av_log(avr, AV_LOG_TRACE, "[convert] %s to output\n", current_buffer->name);
481cabdff1aSopenharmony_ci            ret = ff_audio_convert(avr->ac_out, &output_buffer, current_buffer);
482cabdff1aSopenharmony_ci            if (ret < 0)
483cabdff1aSopenharmony_ci                return ret;
484cabdff1aSopenharmony_ci
485cabdff1aSopenharmony_ci            av_log(avr, AV_LOG_TRACE, "[end conversion]\n");
486cabdff1aSopenharmony_ci            return output_buffer.nb_samples;
487cabdff1aSopenharmony_ci        } else {
488cabdff1aSopenharmony_ci            ret = ff_audio_data_realloc(avr->out_buffer,
489cabdff1aSopenharmony_ci                                        current_buffer->nb_samples);
490cabdff1aSopenharmony_ci            if (ret < 0)
491cabdff1aSopenharmony_ci                return ret;
492cabdff1aSopenharmony_ci            av_log(avr, AV_LOG_TRACE, "[convert] %s to out_buffer\n", current_buffer->name);
493cabdff1aSopenharmony_ci            ret = ff_audio_convert(avr->ac_out, avr->out_buffer,
494cabdff1aSopenharmony_ci                                   current_buffer);
495cabdff1aSopenharmony_ci            if (ret < 0)
496cabdff1aSopenharmony_ci                return ret;
497cabdff1aSopenharmony_ci            current_buffer = avr->out_buffer;
498cabdff1aSopenharmony_ci        }
499cabdff1aSopenharmony_ci    }
500cabdff1aSopenharmony_ci
501cabdff1aSopenharmony_ci    return handle_buffered_output(avr, output ? &output_buffer : NULL,
502cabdff1aSopenharmony_ci                                  current_buffer);
503cabdff1aSopenharmony_ci}
504cabdff1aSopenharmony_ci
505cabdff1aSopenharmony_ciint avresample_config(AVAudioResampleContext *avr, AVFrame *out, AVFrame *in)
506cabdff1aSopenharmony_ci{
507cabdff1aSopenharmony_ci    if (avresample_is_open(avr)) {
508cabdff1aSopenharmony_ci        avresample_close(avr);
509cabdff1aSopenharmony_ci    }
510cabdff1aSopenharmony_ci
511cabdff1aSopenharmony_ci    if (in) {
512cabdff1aSopenharmony_ci        avr->in_channel_layout  = in->channel_layout;
513cabdff1aSopenharmony_ci        avr->in_sample_rate     = in->sample_rate;
514cabdff1aSopenharmony_ci        avr->in_sample_fmt      = in->format;
515cabdff1aSopenharmony_ci    }
516cabdff1aSopenharmony_ci
517cabdff1aSopenharmony_ci    if (out) {
518cabdff1aSopenharmony_ci        avr->out_channel_layout = out->channel_layout;
519cabdff1aSopenharmony_ci        avr->out_sample_rate    = out->sample_rate;
520cabdff1aSopenharmony_ci        avr->out_sample_fmt     = out->format;
521cabdff1aSopenharmony_ci    }
522cabdff1aSopenharmony_ci
523cabdff1aSopenharmony_ci    return 0;
524cabdff1aSopenharmony_ci}
525cabdff1aSopenharmony_ci
526cabdff1aSopenharmony_cistatic int config_changed(AVAudioResampleContext *avr,
527cabdff1aSopenharmony_ci                          AVFrame *out, AVFrame *in)
528cabdff1aSopenharmony_ci{
529cabdff1aSopenharmony_ci    int ret = 0;
530cabdff1aSopenharmony_ci
531cabdff1aSopenharmony_ci    if (in) {
532cabdff1aSopenharmony_ci        if (avr->in_channel_layout != in->channel_layout ||
533cabdff1aSopenharmony_ci            avr->in_sample_rate    != in->sample_rate ||
534cabdff1aSopenharmony_ci            avr->in_sample_fmt     != in->format) {
535cabdff1aSopenharmony_ci            ret |= AVERROR_INPUT_CHANGED;
536cabdff1aSopenharmony_ci        }
537cabdff1aSopenharmony_ci    }
538cabdff1aSopenharmony_ci
539cabdff1aSopenharmony_ci    if (out) {
540cabdff1aSopenharmony_ci        if (avr->out_channel_layout != out->channel_layout ||
541cabdff1aSopenharmony_ci            avr->out_sample_rate    != out->sample_rate ||
542cabdff1aSopenharmony_ci            avr->out_sample_fmt     != out->format) {
543cabdff1aSopenharmony_ci            ret |= AVERROR_OUTPUT_CHANGED;
544cabdff1aSopenharmony_ci        }
545cabdff1aSopenharmony_ci    }
546cabdff1aSopenharmony_ci
547cabdff1aSopenharmony_ci    return ret;
548cabdff1aSopenharmony_ci}
549cabdff1aSopenharmony_ci
550cabdff1aSopenharmony_cistatic inline int convert_frame(AVAudioResampleContext *avr,
551cabdff1aSopenharmony_ci                                AVFrame *out, AVFrame *in)
552cabdff1aSopenharmony_ci{
553cabdff1aSopenharmony_ci    int ret;
554cabdff1aSopenharmony_ci    uint8_t **out_data = NULL, **in_data = NULL;
555cabdff1aSopenharmony_ci    int out_linesize = 0, in_linesize = 0;
556cabdff1aSopenharmony_ci    int out_nb_samples = 0, in_nb_samples = 0;
557cabdff1aSopenharmony_ci
558cabdff1aSopenharmony_ci    if (out) {
559cabdff1aSopenharmony_ci        out_data       = out->extended_data;
560cabdff1aSopenharmony_ci        out_linesize   = out->linesize[0];
561cabdff1aSopenharmony_ci        out_nb_samples = out->nb_samples;
562cabdff1aSopenharmony_ci    }
563cabdff1aSopenharmony_ci
564cabdff1aSopenharmony_ci    if (in) {
565cabdff1aSopenharmony_ci        in_data       = in->extended_data;
566cabdff1aSopenharmony_ci        in_linesize   = in->linesize[0];
567cabdff1aSopenharmony_ci        in_nb_samples = in->nb_samples;
568cabdff1aSopenharmony_ci    }
569cabdff1aSopenharmony_ci
570cabdff1aSopenharmony_ci    ret = avresample_convert(avr, out_data, out_linesize,
571cabdff1aSopenharmony_ci                             out_nb_samples,
572cabdff1aSopenharmony_ci                             in_data, in_linesize,
573cabdff1aSopenharmony_ci                             in_nb_samples);
574cabdff1aSopenharmony_ci
575cabdff1aSopenharmony_ci    if (ret < 0) {
576cabdff1aSopenharmony_ci        if (out)
577cabdff1aSopenharmony_ci            out->nb_samples = 0;
578cabdff1aSopenharmony_ci        return ret;
579cabdff1aSopenharmony_ci    }
580cabdff1aSopenharmony_ci
581cabdff1aSopenharmony_ci    if (out)
582cabdff1aSopenharmony_ci        out->nb_samples = ret;
583cabdff1aSopenharmony_ci
584cabdff1aSopenharmony_ci    return 0;
585cabdff1aSopenharmony_ci}
586cabdff1aSopenharmony_ci
587cabdff1aSopenharmony_cistatic inline int available_samples(AVFrame *out)
588cabdff1aSopenharmony_ci{
589cabdff1aSopenharmony_ci    int samples;
590cabdff1aSopenharmony_ci    int bytes_per_sample = av_get_bytes_per_sample(out->format);
591cabdff1aSopenharmony_ci    if (!bytes_per_sample)
592cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
593cabdff1aSopenharmony_ci
594cabdff1aSopenharmony_ci    samples = out->linesize[0] / bytes_per_sample;
595cabdff1aSopenharmony_ci    if (av_sample_fmt_is_planar(out->format)) {
596cabdff1aSopenharmony_ci        return samples;
597cabdff1aSopenharmony_ci    } else {
598cabdff1aSopenharmony_ci        int channels = av_get_channel_layout_nb_channels(out->channel_layout);
599cabdff1aSopenharmony_ci        return samples / channels;
600cabdff1aSopenharmony_ci    }
601cabdff1aSopenharmony_ci}
602cabdff1aSopenharmony_ci
603cabdff1aSopenharmony_ciint avresample_convert_frame(AVAudioResampleContext *avr,
604cabdff1aSopenharmony_ci                             AVFrame *out, AVFrame *in)
605cabdff1aSopenharmony_ci{
606cabdff1aSopenharmony_ci    int ret, setup = 0;
607cabdff1aSopenharmony_ci
608cabdff1aSopenharmony_ci    if (!avresample_is_open(avr)) {
609cabdff1aSopenharmony_ci        if ((ret = avresample_config(avr, out, in)) < 0)
610cabdff1aSopenharmony_ci            return ret;
611cabdff1aSopenharmony_ci        if ((ret = avresample_open(avr)) < 0)
612cabdff1aSopenharmony_ci            return ret;
613cabdff1aSopenharmony_ci        setup = 1;
614cabdff1aSopenharmony_ci    } else {
615cabdff1aSopenharmony_ci        // return as is or reconfigure for input changes?
616cabdff1aSopenharmony_ci        if ((ret = config_changed(avr, out, in)))
617cabdff1aSopenharmony_ci            return ret;
618cabdff1aSopenharmony_ci    }
619cabdff1aSopenharmony_ci
620cabdff1aSopenharmony_ci    if (out) {
621cabdff1aSopenharmony_ci        if (!out->linesize[0]) {
622cabdff1aSopenharmony_ci            out->nb_samples = avresample_get_out_samples(avr, in->nb_samples);
623cabdff1aSopenharmony_ci            if ((ret = av_frame_get_buffer(out, 0)) < 0) {
624cabdff1aSopenharmony_ci                if (setup)
625cabdff1aSopenharmony_ci                    avresample_close(avr);
626cabdff1aSopenharmony_ci                return ret;
627cabdff1aSopenharmony_ci            }
628cabdff1aSopenharmony_ci        } else {
629cabdff1aSopenharmony_ci            if (!out->nb_samples)
630cabdff1aSopenharmony_ci                out->nb_samples = available_samples(out);
631cabdff1aSopenharmony_ci        }
632cabdff1aSopenharmony_ci    }
633cabdff1aSopenharmony_ci
634cabdff1aSopenharmony_ci    return convert_frame(avr, out, in);
635cabdff1aSopenharmony_ci}
636cabdff1aSopenharmony_ci
637cabdff1aSopenharmony_ciint avresample_get_matrix(AVAudioResampleContext *avr, double *matrix,
638cabdff1aSopenharmony_ci                          int stride)
639cabdff1aSopenharmony_ci{
640cabdff1aSopenharmony_ci    int in_channels, out_channels, i, o;
641cabdff1aSopenharmony_ci
642cabdff1aSopenharmony_ci    if (avr->am)
643cabdff1aSopenharmony_ci        return ff_audio_mix_get_matrix(avr->am, matrix, stride);
644cabdff1aSopenharmony_ci
645cabdff1aSopenharmony_ci    in_channels  = av_get_channel_layout_nb_channels(avr->in_channel_layout);
646cabdff1aSopenharmony_ci    out_channels = av_get_channel_layout_nb_channels(avr->out_channel_layout);
647cabdff1aSopenharmony_ci
648cabdff1aSopenharmony_ci    if ( in_channels <= 0 ||  in_channels > AVRESAMPLE_MAX_CHANNELS ||
649cabdff1aSopenharmony_ci        out_channels <= 0 || out_channels > AVRESAMPLE_MAX_CHANNELS) {
650cabdff1aSopenharmony_ci        av_log(avr, AV_LOG_ERROR, "Invalid channel layouts\n");
651cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
652cabdff1aSopenharmony_ci    }
653cabdff1aSopenharmony_ci
654cabdff1aSopenharmony_ci    if (!avr->mix_matrix) {
655cabdff1aSopenharmony_ci        av_log(avr, AV_LOG_ERROR, "matrix is not set\n");
656cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
657cabdff1aSopenharmony_ci    }
658cabdff1aSopenharmony_ci
659cabdff1aSopenharmony_ci    for (o = 0; o < out_channels; o++)
660cabdff1aSopenharmony_ci        for (i = 0; i < in_channels; i++)
661cabdff1aSopenharmony_ci            matrix[o * stride + i] = avr->mix_matrix[o * in_channels + i];
662cabdff1aSopenharmony_ci
663cabdff1aSopenharmony_ci    return 0;
664cabdff1aSopenharmony_ci}
665cabdff1aSopenharmony_ci
666cabdff1aSopenharmony_ciint avresample_set_matrix(AVAudioResampleContext *avr, const double *matrix,
667cabdff1aSopenharmony_ci                          int stride)
668cabdff1aSopenharmony_ci{
669cabdff1aSopenharmony_ci    int in_channels, out_channels, i, o;
670cabdff1aSopenharmony_ci
671cabdff1aSopenharmony_ci    if (avr->am)
672cabdff1aSopenharmony_ci        return ff_audio_mix_set_matrix(avr->am, matrix, stride);
673cabdff1aSopenharmony_ci
674cabdff1aSopenharmony_ci    in_channels  = av_get_channel_layout_nb_channels(avr->in_channel_layout);
675cabdff1aSopenharmony_ci    out_channels = av_get_channel_layout_nb_channels(avr->out_channel_layout);
676cabdff1aSopenharmony_ci
677cabdff1aSopenharmony_ci    if ( in_channels <= 0 ||  in_channels > AVRESAMPLE_MAX_CHANNELS ||
678cabdff1aSopenharmony_ci        out_channels <= 0 || out_channels > AVRESAMPLE_MAX_CHANNELS) {
679cabdff1aSopenharmony_ci        av_log(avr, AV_LOG_ERROR, "Invalid channel layouts\n");
680cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
681cabdff1aSopenharmony_ci    }
682cabdff1aSopenharmony_ci
683cabdff1aSopenharmony_ci    if (avr->mix_matrix)
684cabdff1aSopenharmony_ci        av_freep(&avr->mix_matrix);
685cabdff1aSopenharmony_ci    avr->mix_matrix = av_malloc(in_channels * out_channels *
686cabdff1aSopenharmony_ci                                sizeof(*avr->mix_matrix));
687cabdff1aSopenharmony_ci    if (!avr->mix_matrix)
688cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
689cabdff1aSopenharmony_ci
690cabdff1aSopenharmony_ci    for (o = 0; o < out_channels; o++)
691cabdff1aSopenharmony_ci        for (i = 0; i < in_channels; i++)
692cabdff1aSopenharmony_ci            avr->mix_matrix[o * in_channels + i] = matrix[o * stride + i];
693cabdff1aSopenharmony_ci
694cabdff1aSopenharmony_ci    return 0;
695cabdff1aSopenharmony_ci}
696cabdff1aSopenharmony_ci
697cabdff1aSopenharmony_ciint avresample_set_channel_mapping(AVAudioResampleContext *avr,
698cabdff1aSopenharmony_ci                                   const int *channel_map)
699cabdff1aSopenharmony_ci{
700cabdff1aSopenharmony_ci    ChannelMapInfo *info = &avr->ch_map_info;
701cabdff1aSopenharmony_ci    int in_channels, ch, i;
702cabdff1aSopenharmony_ci
703cabdff1aSopenharmony_ci    in_channels = av_get_channel_layout_nb_channels(avr->in_channel_layout);
704cabdff1aSopenharmony_ci    if (in_channels <= 0 ||  in_channels > AVRESAMPLE_MAX_CHANNELS) {
705cabdff1aSopenharmony_ci        av_log(avr, AV_LOG_ERROR, "Invalid input channel layout\n");
706cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
707cabdff1aSopenharmony_ci    }
708cabdff1aSopenharmony_ci
709cabdff1aSopenharmony_ci    memset(info, 0, sizeof(*info));
710cabdff1aSopenharmony_ci    memset(info->input_map, -1, sizeof(info->input_map));
711cabdff1aSopenharmony_ci
712cabdff1aSopenharmony_ci    for (ch = 0; ch < in_channels; ch++) {
713cabdff1aSopenharmony_ci        if (channel_map[ch] >= in_channels) {
714cabdff1aSopenharmony_ci            av_log(avr, AV_LOG_ERROR, "Invalid channel map\n");
715cabdff1aSopenharmony_ci            return AVERROR(EINVAL);
716cabdff1aSopenharmony_ci        }
717cabdff1aSopenharmony_ci        if (channel_map[ch] < 0) {
718cabdff1aSopenharmony_ci            info->channel_zero[ch] =  1;
719cabdff1aSopenharmony_ci            info->channel_map[ch]  = -1;
720cabdff1aSopenharmony_ci            info->do_zero          =  1;
721cabdff1aSopenharmony_ci        } else if (info->input_map[channel_map[ch]] >= 0) {
722cabdff1aSopenharmony_ci            info->channel_copy[ch] = info->input_map[channel_map[ch]];
723cabdff1aSopenharmony_ci            info->channel_map[ch]  = -1;
724cabdff1aSopenharmony_ci            info->do_copy          =  1;
725cabdff1aSopenharmony_ci        } else {
726cabdff1aSopenharmony_ci            info->channel_map[ch]            = channel_map[ch];
727cabdff1aSopenharmony_ci            info->input_map[channel_map[ch]] = ch;
728cabdff1aSopenharmony_ci            info->do_remap                   =  1;
729cabdff1aSopenharmony_ci        }
730cabdff1aSopenharmony_ci    }
731cabdff1aSopenharmony_ci    /* Fill-in unmapped input channels with unmapped output channels.
732cabdff1aSopenharmony_ci       This is used when remapping during conversion from interleaved to
733cabdff1aSopenharmony_ci       planar format. */
734cabdff1aSopenharmony_ci    for (ch = 0, i = 0; ch < in_channels && i < in_channels; ch++, i++) {
735cabdff1aSopenharmony_ci        while (ch < in_channels && info->input_map[ch] >= 0)
736cabdff1aSopenharmony_ci            ch++;
737cabdff1aSopenharmony_ci        while (i < in_channels && info->channel_map[i] >= 0)
738cabdff1aSopenharmony_ci            i++;
739cabdff1aSopenharmony_ci        if (ch >= in_channels || i >= in_channels)
740cabdff1aSopenharmony_ci            break;
741cabdff1aSopenharmony_ci        info->input_map[ch] = i;
742cabdff1aSopenharmony_ci    }
743cabdff1aSopenharmony_ci
744cabdff1aSopenharmony_ci    avr->use_channel_map = 1;
745cabdff1aSopenharmony_ci    return 0;
746cabdff1aSopenharmony_ci}
747cabdff1aSopenharmony_ci
748cabdff1aSopenharmony_ciint avresample_available(AVAudioResampleContext *avr)
749cabdff1aSopenharmony_ci{
750cabdff1aSopenharmony_ci    return av_audio_fifo_size(avr->out_fifo);
751cabdff1aSopenharmony_ci}
752cabdff1aSopenharmony_ci
753cabdff1aSopenharmony_ciint avresample_get_out_samples(AVAudioResampleContext *avr, int in_nb_samples)
754cabdff1aSopenharmony_ci{
755cabdff1aSopenharmony_ci    int64_t samples = avresample_get_delay(avr) + (int64_t)in_nb_samples;
756cabdff1aSopenharmony_ci
757cabdff1aSopenharmony_ci    if (avr->resample_needed) {
758cabdff1aSopenharmony_ci        samples = av_rescale_rnd(samples,
759cabdff1aSopenharmony_ci                                 avr->out_sample_rate,
760cabdff1aSopenharmony_ci                                 avr->in_sample_rate,
761cabdff1aSopenharmony_ci                                 AV_ROUND_UP);
762cabdff1aSopenharmony_ci    }
763cabdff1aSopenharmony_ci
764cabdff1aSopenharmony_ci    samples += avresample_available(avr);
765cabdff1aSopenharmony_ci
766cabdff1aSopenharmony_ci    if (samples > INT_MAX)
767cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
768cabdff1aSopenharmony_ci
769cabdff1aSopenharmony_ci    return samples;
770cabdff1aSopenharmony_ci}
771cabdff1aSopenharmony_ci
772cabdff1aSopenharmony_ciint avresample_read(AVAudioResampleContext *avr, uint8_t **output, int nb_samples)
773cabdff1aSopenharmony_ci{
774cabdff1aSopenharmony_ci    if (!output)
775cabdff1aSopenharmony_ci        return av_audio_fifo_drain(avr->out_fifo, nb_samples);
776cabdff1aSopenharmony_ci    return av_audio_fifo_read(avr->out_fifo, (void**)output, nb_samples);
777cabdff1aSopenharmony_ci}
778cabdff1aSopenharmony_ci
779cabdff1aSopenharmony_ciunsigned avresample_version(void)
780cabdff1aSopenharmony_ci{
781cabdff1aSopenharmony_ci    return LIBAVRESAMPLE_VERSION_INT;
782cabdff1aSopenharmony_ci}
783cabdff1aSopenharmony_ci
784cabdff1aSopenharmony_ciconst char *avresample_license(void)
785cabdff1aSopenharmony_ci{
786cabdff1aSopenharmony_ci#define LICENSE_PREFIX "libavresample license: "
787cabdff1aSopenharmony_ci    return LICENSE_PREFIX FFMPEG_LICENSE + sizeof(LICENSE_PREFIX) - 1;
788cabdff1aSopenharmony_ci}
789cabdff1aSopenharmony_ci
790cabdff1aSopenharmony_ciconst char *avresample_configuration(void)
791cabdff1aSopenharmony_ci{
792cabdff1aSopenharmony_ci    return FFMPEG_CONFIGURATION;
793cabdff1aSopenharmony_ci}
794