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
|
/*
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "audio_format.h"
#include "pcm_convert.h"
#include <string.h>
#include <glib.h>
#include <libavresample/avresample.h>
#include <libavutil/channel_layout.h>
#include <libavutil/frame.h>
#include <libavutil/opt.h>
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "pcm"
void pcm_convert_init(struct pcm_convert_state *state)
{
memset(state, 0, sizeof(*state));
}
void pcm_convert_deinit(struct pcm_convert_state *state)
{
avresample_free(&state->avr);
}
void
pcm_convert_reset(struct pcm_convert_state *state)
{
avresample_free(&state->avr);
}
AVFrame *pcm_convert(struct pcm_convert_state *state,
const struct audio_format *src_format,
const struct audio_format *dest_format,
const AVFrame *src)
{
AVFrame *dst;
int ret;
if (!state->avr) {
char in_layout[128], out_layout[128];
state->avr = avresample_alloc_context();
if (!state->avr)
return NULL;
state->dst_channel_layout = av_get_default_channel_layout(dest_format->channels);
state->dst_samplerate = dest_format->sample_rate;
state->dst_format = dest_format->format;
av_opt_set_int(state->avr, "in_channel_layout", src->channel_layout, 0);
av_opt_set_int(state->avr, "out_channel_layout", state->dst_channel_layout, 0);
av_opt_set_int(state->avr, "in_sample_rate", src->sample_rate, 0);
av_opt_set_int(state->avr, "out_sample_rate", state->dst_samplerate, 0);
av_opt_set_int(state->avr, "in_sample_fmt", src->format, 0);
av_opt_set_int(state->avr, "out_sample_fmt", state->dst_format, 0);
av_get_channel_layout_string(in_layout, sizeof(in_layout), -1, src->channel_layout);
av_get_channel_layout_string(out_layout, sizeof(out_layout), -1, state->dst_channel_layout);
g_debug("Opening resampling context %s:%d:%s -> %s:%d:%s\n",
av_get_sample_fmt_name(src->format), src->sample_rate, in_layout,
av_get_sample_fmt_name(state->dst_format), state->dst_samplerate, out_layout);
ret = avresample_open(state->avr);
if (ret < 0) {
g_warning("Error initializing format conversion.\n");
avresample_free(&state->avr);
return NULL;
}
}
dst = av_frame_alloc();
if (!dst)
return NULL;
dst->format = state->dst_format;
dst->channel_layout = state->dst_channel_layout;
dst->sample_rate = state->dst_samplerate;
dst->nb_samples = avresample_get_out_samples(state->avr, src->nb_samples);
ret = av_frame_get_buffer(dst, 32);
if (ret < 0) {
g_warning("Error allocating a buffer for format conversion.\n");
av_frame_free(&dst);
return NULL;
}
ret = avresample_convert(state->avr, dst->extended_data, dst->linesize[0],
dst->nb_samples, src->extended_data, src->linesize[0],
src->nb_samples);
if (ret < 0) {
g_warning("Error during format conversion.\n");
av_frame_free(&dst);
return NULL;
}
dst->nb_samples = ret;
return dst;
}
|