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
117
118
119
120
121
|
#include <asm-generic/errno-base.h>
#include <assert.h>
#include <libavcodec/avcodec.h>
#include <libavutil/error.h>
#include <libavutil/opt.h>
#include <libswresample/swresample.h>
#include "resampler.h"
#define MICROSECOND 1000000
static inline uint64_t div_uint64_ceil(uint64_t num, uint64_t den)
{
return (num / den) + (num % den != 0);
}
static int resampler_init (struct Resampler *resampler, const AVChannelLayout *out_chlayout, enum AVSampleFormat out_sample_fmt, int64_t out_sample_rate, uint64_t out_frame_size)
{
/* Let me tell you something; you --don't want-- CAN'T configure a
* SwrContext manually, GOOD ****ING LUCK DOING THAT. The documentation is
* so bad on that matter, it only referes to "tHe PaRaMeTeRs" or show off a
* list of deprecated attribute which looks nothing like what's actually
* used in their API. I tried to copy what's being done in their a API but
* whatever I do would either not work or be liable to change since it's not
* documented for shit (even the documented stuff doesn't appears stable, so
* wtf am I saying anyway). A ****ing joke, I tell you that.
*
* Pardon my french.
*
* Anywho, instead of configuring the input parameter directly, we shove
* them in resampler so we can recall them before calling ffmpeg's SWR
* allocator.
*/
resampler->out_chlayout = out_chlayout;
resampler->out_sample_fmt = out_sample_fmt;
resampler->out_sample_rate = out_sample_rate;
resampler->out_frame_size = out_frame_size;
resampler->swr = NULL;
return 0;
}
static int resampler_conf (struct Resampler *resampler, const AVChannelLayout *in_chlayout, enum AVSampleFormat in_sample_fmt, int64_t in_sample_rate)
{
int err;
err = swr_alloc_set_opts2(
&resampler->swr,
resampler->out_chlayout,
resampler->out_sample_fmt,
resampler->out_sample_rate,
in_chlayout,
in_sample_fmt,
in_sample_rate,
0, 0);
if (err) return err;
if (!swr_is_initialized(resampler->swr))
if ((err = swr_init(resampler->swr)))
return err;
resampler->in_sample_rate = in_sample_rate;
resampler->needed = div_uint64_ceil(resampler->out_frame_size * in_sample_rate, resampler->out_sample_rate);
return 0;
}
int resampler_send_frame (struct Resampler *resampler, AVFrame *in)
{
int err;
if ((err = swr_convert(resampler->swr, NULL, 0, (const uint8_t **)in->extended_data, in->nb_samples)) < 0)
return err;
resampler->stored += in->nb_samples;
return 0;
}
int resampler_send_empty (struct Resampler *resampler, unsigned int microsecond)
{
// TODO: Check for downcasting
int nb_samples;
nb_samples = div_uint64_ceil(microsecond * resampler->in_sample_rate, 1000);
return swr_inject_silence(resampler->swr, nb_samples);
}
int resampler_convert (struct Resampler *resampler, AVFrame *out)
{
int err;
assert(out != NULL);
assert(resampler->swr != NULL);
if (resampler->stored < resampler->needed) {
return AVERROR(EAGAIN);
/*
err = swr_inject_silence(resampler->swr, resampler->needed - resampler->stored);
if (err < 0) return err;
*/
}
err = swr_convert(resampler->swr, out->extended_data, out->nb_samples, NULL, 0);
if (err < 0) return err;
resampler->stored = 0;
return 0;
}
void resampler_free (struct Resampler *resampler)
{
if (resampler == NULL) return;
swr_free(&resampler->swr);
}
int resampler_init_for_encoder (struct Resampler *resampler, const struct Encoder *encoder)
{
AVCodecContext *avctx = encoder->avctx;
return resampler_init(resampler, &avctx->ch_layout, avctx->sample_fmt, avctx->sample_rate, avctx->frame_size);
}
int resampler_conf_for_decoder (struct Resampler *resampler, const struct Decoder *decoder)
{
AVCodecContext *avctx = decoder->avctx;
return resampler_conf(resampler, &avctx->ch_layout, avctx->sample_fmt, avctx->sample_rate);
}
|