1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
#define AL_LOG_SECTION "ff_resampler"
#include <al/log.h>
#include <al/lib.h>
#include <libavutil/opt.h>
#include "resampler.h"
static bool ff_resampler_init(struct camu_resampler *resamp, struct camu_resampler_format *fmt)
{
struct camu_ff_resampler *av = (struct camu_ff_resampler *)resamp;
av->resample_context = NULL;
al_assert(fmt->resampler_needed);
camu_audio_format_copy(&av->fmt, &fmt->req);
SwrContext *swr = swr_alloc();
#ifndef CAMU_OLD_FFMPEG
av_opt_set_chlayout(swr, "in_chlayout", &fmt->in.channel_layout, 0);
av_opt_set_chlayout(swr, "out_chlayout", &fmt->req.channel_layout, 0);
#else
av_opt_set_channel_layout(swr, "in_channel_layout", fmt->in.channel_layout, 0);
av_opt_set_channel_layout(swr, "out_channel_layout", fmt->req.channel_layout, 0);
#endif
av_opt_set_int(swr, "in_sample_rate", fmt->in.sample_rate, 0);
av_opt_set_int(swr, "out_sample_rate", fmt->req.sample_rate, 0);
av_opt_set_sample_fmt(swr, "in_sample_fmt", (enum AVSampleFormat)fmt->in.format, 0);
av_opt_set_sample_fmt(swr, "out_sample_fmt", (enum AVSampleFormat)fmt->req.format, 0);
#ifdef CAMU_HAVE_SOXR
// Slower but more accurate resampler.
av_opt_set_int(swr, "resampler", SWR_ENGINE_SOXR, 0);
log_info("Using SoX resampler.");
#endif
s32 ret = swr_init(swr);
if (ret != 0) {
swr_free(&swr);
log_error("Failed to init resampler context (%s).", av_err2str(ret));
return false;
}
av->resample_context = swr;
return true;
}
static inline void free_sample_data(struct camu_ff_resampler *av)
{
if (av->data[0]) av_freep(&av->data[0]);
}
static inline void alloc_sample_data(struct camu_ff_resampler *av, s32 sample_count)
{
if (av->sample_count >= sample_count) return;
free_sample_data(av);
s32 nb_channels = av->fmt.channel_count;
av_samples_alloc(av->data, NULL, nb_channels, sample_count, (enum AVSampleFormat)av->fmt.format, 32);
av->sample_count = sample_count;
}
static s32 ff_resampler_convert(struct camu_resampler *resamp, const u8 **in_data, s32 in_samples)
{
struct camu_ff_resampler *av = (struct camu_ff_resampler *)resamp;
al_assert(in_samples > 0);
s32 out_resample_count = swr_get_out_samples(av->resample_context, in_samples);
alloc_sample_data(av, out_resample_count);
s32 resample_count = swr_convert(av->resample_context, av->data,
out_resample_count, in_data, in_samples);
if (resample_count < 0) {
log_error("Failed to convert samples (%d).", resample_count);
}
return resample_count;
}
static s32 ff_resampler_flush(struct camu_resampler *resamp)
{
struct camu_ff_resampler *av = (struct camu_ff_resampler *)resamp;
s32 resample_count = swr_convert(av->resample_context, av->data,
av->sample_count, NULL, 0);
if (swr_init(av->resample_context) != 0) {
swr_free(&av->resample_context);
log_error("Failed to re-init resampler context after flush.");
return -1;
}
return resample_count;
}
static u8 **ff_resampler_get_data(struct camu_resampler *resamp)
{
struct camu_ff_resampler *av = (struct camu_ff_resampler *)resamp;
return (u8 **)av->data;
}
static void ff_resampler_free(struct camu_resampler **resamp)
{
struct camu_ff_resampler *av = (struct camu_ff_resampler *)*resamp;
if (av->resample_context) {
swr_close(av->resample_context);
swr_free(&av->resample_context);
}
free_sample_data(av);
al_free(av);
*resamp = NULL;
}
struct camu_resampler *camu_ff_resampler_create(void)
{
struct camu_ff_resampler *av = al_alloc_object(struct camu_ff_resampler);
av->resamp.init = ff_resampler_init;
av->resamp.convert = ff_resampler_convert;
av->resamp.flush = ff_resampler_flush;
av->resamp.get_data = ff_resampler_get_data;
av->resamp.free = ff_resampler_free;
return (struct camu_resampler *)av;
}
|