1 /*
2 * Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
3 *
4 * This file is part of MPlayer.
5 *
6 * MPlayer is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * MPlayer is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <inttypes.h>
25
26 #include "config.h"
27 #include "af.h"
28 #include "libavutil/rational.h"
29 #include "libswresample/swresample.h"
30 #include "libavutil/channel_layout.h"
31 #include "libavutil/opt.h"
32 #include "libavutil/mem.h"
33 #include "libavutil/common.h"
34
35 // Data for specific instances of this filter
36 typedef struct af_resample_s{
37 struct SwrContext *swrctx;
38 uint8_t *in[1];
39 uint8_t *tmp[1];
40 int in_alloc;
41 int tmp_alloc;
42
43 int filter_length;
44 int linear;
45 int phase_shift;
46 double cutoff;
47
48 int ctx_out_rate;
49 int ctx_in_rate;
50 int ctx_filter_size;
51 int ctx_phase_shift;
52 int ctx_linear;
53 double ctx_cutoff;
54 }af_resample_t;
55
56
57 // Initialization and runtime control
control(struct af_instance_s * af,int cmd,void * arg)58 static int control(struct af_instance_s* af, int cmd, void* arg)
59 {
60 af_resample_t* s = (af_resample_t*)af->setup;
61 af_data_t *data= (af_data_t*)arg;
62 int out_rate, test_output_res; // helpers for checking input format
63
64 switch(cmd){
65 case AF_CONTROL_REINIT:
66 if((af->data->rate == data->rate) || (af->data->rate == 0))
67 return AF_DETACH;
68
69 af->data->nch = data->nch;
70 if (af->data->nch > AF_NCH) af->data->nch = AF_NCH;
71 af->data->format = AF_FORMAT_S16_NE;
72 af->data->bps = 2;
73 af->mul = (double)af->data->rate / data->rate;
74 af->delay = af->data->nch * s->filter_length / FFMIN(af->mul, 1); // *bps*.5
75
76 if (s->ctx_out_rate != af->data->rate || s->ctx_in_rate != data->rate || s->ctx_filter_size != s->filter_length ||
77 s->ctx_phase_shift != s->phase_shift || s->ctx_linear != s->linear || s->ctx_cutoff != s->cutoff) {
78 swr_free(&s->swrctx);
79 if((s->swrctx=swr_alloc()) == NULL) return AF_ERROR;
80 av_opt_set_int(s->swrctx, "out_sample_rate", af->data->rate, 0);
81 av_opt_set_int(s->swrctx, "in_sample_rate", data->rate, 0);
82 av_opt_set_int(s->swrctx, "filter_size", s->filter_length, 0);
83 av_opt_set_int(s->swrctx, "phase_shift", s->phase_shift, 0);
84 av_opt_set_int(s->swrctx, "linear_interp", s->linear, 0);
85 av_opt_set_double(s->swrctx, "cutoff", s->cutoff, 0);
86 av_opt_set_sample_fmt(s->swrctx, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0);
87 av_opt_set_sample_fmt(s->swrctx, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);
88 av_opt_set_int(s->swrctx, "in_channel_count", af->data->nch, 0);
89 av_opt_set_int(s->swrctx, "out_channel_count", af->data->nch, 0);
90 if(swr_init(s->swrctx) < 0) return AF_ERROR;
91 s->ctx_out_rate = af->data->rate;
92 s->ctx_in_rate = data->rate;
93 s->ctx_filter_size = s->filter_length;
94 s->ctx_phase_shift = s->phase_shift;
95 s->ctx_linear = s->linear;
96 s->ctx_cutoff = s->cutoff;
97 }
98
99 // hack to make af_test_output ignore the samplerate change
100 out_rate = af->data->rate;
101 af->data->rate = data->rate;
102 test_output_res = af_test_output(af, (af_data_t*)arg);
103 af->data->rate = out_rate;
104 return test_output_res;
105 case AF_CONTROL_COMMAND_LINE:{
106 s->cutoff= 0.0;
107 sscanf((char*)arg,"%d:%d:%d:%d:%lf", &af->data->rate, &s->filter_length, &s->linear, &s->phase_shift, &s->cutoff);
108 if(s->cutoff <= 0.0) s->cutoff= FFMAX(1.0 - 6.5/(s->filter_length+8), 0.80);
109 return AF_OK;
110 }
111 case AF_CONTROL_RESAMPLE_RATE | AF_CONTROL_SET:
112 af->data->rate = *(int*)arg;
113 return AF_OK;
114 }
115 return AF_UNKNOWN;
116 }
117
118 // Deallocate memory
uninit(struct af_instance_s * af)119 static void uninit(struct af_instance_s* af)
120 {
121 if(af->data)
122 free(af->data->audio);
123 free(af->data);
124 if(af->setup){
125 af_resample_t *s = af->setup;
126 swr_free(&s->swrctx);
127 av_free(s->in[0]);
128 av_free(s->tmp[0]);
129 free(s);
130 }
131 }
132
133 // Filter data through filter
play(struct af_instance_s * af,af_data_t * data)134 static af_data_t* play(struct af_instance_s* af, af_data_t* data)
135 {
136 af_resample_t *s = af->setup;
137 int ret;
138 int8_t *in = (int8_t*)data->audio;
139 int8_t *out;
140 int chans = data->nch;
141 int in_len = data->len;
142 int out_len = in_len * af->mul + 10;
143
144 if(AF_OK != RESIZE_LOCAL_BUFFER(af,data))
145 return NULL;
146
147 av_fast_malloc(&s->tmp[0], &s->tmp_alloc, FFALIGN(out_len,32));
148 if(s->tmp[0] == NULL) return NULL;
149
150 out= (int8_t*)af->data->audio;
151
152 out_len= FFMIN(out_len, af->data->len);
153
154 av_fast_malloc(&s->in[0], &s->in_alloc, FFALIGN(in_len,32));
155 if(s->in[0] == NULL) return NULL;
156
157 memcpy(s->in[0], in, in_len);
158
159 ret = swr_convert(s->swrctx, &s->tmp[0], out_len/chans/2, &s->in[0], in_len/chans/2);
160 if (ret < 0) return NULL;
161 out_len= ret*chans*2;
162
163 memcpy(out, s->tmp[0], out_len);
164
165 data->audio = af->data->audio;
166 data->len = out_len;
167 data->rate = af->data->rate;
168 return data;
169 }
170
af_open(af_instance_t * af)171 static int af_open(af_instance_t* af){
172 af_resample_t *s = calloc(1,sizeof(af_resample_t));
173 af->control=control;
174 af->uninit=uninit;
175 af->play=play;
176 af->mul=1;
177 af->data=calloc(1,sizeof(af_data_t));
178 s->filter_length= 16;
179 s->cutoff= FFMAX(1.0 - 6.5/(s->filter_length+8), 0.80);
180 s->phase_shift= 10;
181 // s->setup = RSMP_INT | FREQ_SLOPPY;
182 af->setup=s;
183 return AF_OK;
184 }
185
186 const af_info_t af_info_lavcresample = {
187 "Sample frequency conversion using libavcodec",
188 "lavcresample",
189 "Michael Niedermayer",
190 "",
191 AF_FLAGS_REENTRANT,
192 af_open
193 };
194