Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2018-2021
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / audio resample filter
9 : *
10 : * GPAC is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU Lesser General Public License as published by
12 : * the Free Software Foundation; either version 2, or (at your option)
13 : * any later version.
14 : *
15 : * GPAC is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU Lesser General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU Lesser General Public
21 : * License along with this library; see the file COPYING. If not, write to
22 : * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 : *
24 : */
25 :
26 : #include <gpac/avparse.h>
27 : #include <gpac/constants.h>
28 : #include <gpac/filters.h>
29 : #include <gpac/internal/compositor_dev.h>
30 :
31 : #ifndef GPAC_DISABLE_PLAYER
32 :
33 : typedef struct
34 : {
35 : //opts
36 : u32 och, osr, ofmt;
37 :
38 : //internal
39 : GF_FilterPid *ipid, *opid;
40 : GF_AudioMixer *mixer;
41 : Bool cfg_forced;
42 : //output config
43 : u32 freq, nb_ch, afmt;
44 : u64 ch_cfg;
45 : u64 out_cts_plus_one;
46 : //source is planar
47 : Bool src_is_planar;
48 : GF_AudioInterface input_ai;
49 : Bool passthrough;
50 : u32 timescale;
51 : const char *data;
52 : u32 size, bytes_consumed;
53 : Fixed speed;
54 : GF_FilterPacket *in_pck;
55 : Bool cfg_changed;
56 : } GF_ResampleCtx;
57 :
58 :
59 2800 : static u8 *resample_fetch_frame(void *callback, u32 *size, u32 *planar_stride, u32 audio_delay_ms)
60 : {
61 : u32 sample_offset;
62 : GF_ResampleCtx *ctx = (GF_ResampleCtx *) callback;
63 2800 : if (!ctx->data) {
64 : //fetch data if none present (we may have drop the previous frame while mixing)
65 : assert(!ctx->in_pck);
66 77 : ctx->in_pck = gf_filter_pid_get_packet(ctx->ipid);
67 77 : if (!ctx->in_pck) {
68 45 : *size = 0;
69 45 : return NULL;
70 : }
71 32 : ctx->data = gf_filter_pck_get_data(ctx->in_pck, &ctx->size);
72 : //note we only update CTS when no packet is present at the start of process()
73 :
74 32 : if (!ctx->data) {
75 0 : *size = 0;
76 0 : return NULL;
77 : }
78 : }
79 :
80 : assert(ctx->data);
81 2755 : *size = ctx->size - ctx->bytes_consumed;
82 2755 : sample_offset = ctx->bytes_consumed;
83 : //planar mode, bytes consumed correspond to all channels, so move frame pointer
84 : //to first sample non consumed = bytes_consumed/nb_channels
85 2755 : if (ctx->src_is_planar) {
86 735 : *planar_stride = ctx->size / ctx->input_ai.chan;
87 735 : sample_offset /= ctx->input_ai.chan;
88 : }
89 2755 : return (char*)ctx->data + sample_offset;
90 : }
91 :
92 2755 : static void resample_release_frame(void *callback, u32 nb_bytes)
93 : {
94 : GF_ResampleCtx *ctx = (GF_ResampleCtx *) callback;
95 2755 : ctx->bytes_consumed += nb_bytes;
96 : assert(ctx->bytes_consumed<=ctx->size);
97 2755 : if (ctx->bytes_consumed==ctx->size) {
98 : //trash packet and get a new one
99 2753 : gf_filter_pid_drop_packet(ctx->ipid);
100 2753 : ctx->data = NULL;
101 2753 : ctx->in_pck = NULL;
102 2753 : ctx->size = ctx->bytes_consumed = 0;
103 : //do NOT fetch data until needed
104 : }
105 2755 : }
106 :
107 5318 : static Bool resample_get_config(struct _audiointerface *ai, Bool for_reconf)
108 : {
109 5318 : GF_ResampleCtx *ctx = (GF_ResampleCtx *) ai->callback;
110 5318 : if (ctx->cfg_changed) {
111 42 : ctx->cfg_changed = GF_FALSE;
112 42 : return GF_FALSE;
113 : }
114 : return GF_TRUE;
115 : }
116 7788 : static Bool resample_is_muted(void *callback)
117 : {
118 7788 : return GF_FALSE;
119 : }
120 5276 : static Fixed resample_get_speed(void *callback)
121 : {
122 : GF_ResampleCtx *ctx = (GF_ResampleCtx *) callback;
123 5276 : return ctx->speed;
124 : }
125 5268 : static Bool resample_get_channel_volume(void *callback, Fixed *vol)
126 : {
127 : u32 i;
128 5268 : for (i=0; i<GF_AUDIO_MIXER_MAX_CHANNELS; i++) vol[i] = FIX_ONE;
129 5268 : return GF_FALSE;
130 : }
131 :
132 43 : static GF_Err resample_initialize(GF_Filter *filter)
133 : {
134 43 : GF_ResampleCtx *ctx = gf_filter_get_udta(filter);
135 43 : ctx->mixer = gf_mixer_new(NULL);
136 43 : if (!ctx->mixer) return GF_OUT_OF_MEM;
137 :
138 43 : ctx->input_ai.callback = ctx;
139 43 : ctx->input_ai.FetchFrame = resample_fetch_frame;
140 43 : ctx->input_ai.ReleaseFrame = resample_release_frame;
141 43 : ctx->input_ai.GetConfig = resample_get_config;
142 43 : ctx->input_ai.IsMuted = resample_is_muted;
143 43 : ctx->input_ai.GetSpeed = resample_get_speed;
144 43 : ctx->input_ai.GetChannelVolume = resample_get_channel_volume;
145 43 : ctx->speed = FIX_ONE;
146 43 : return GF_OK;
147 : }
148 :
149 43 : static void resample_finalize(GF_Filter *filter)
150 : {
151 43 : GF_ResampleCtx *ctx = gf_filter_get_udta(filter);
152 43 : if (ctx->mixer) gf_mixer_del(ctx->mixer);
153 43 : if (ctx->in_pck && ctx->ipid) gf_filter_pid_drop_packet(ctx->ipid);
154 43 : }
155 :
156 :
157 46 : static GF_Err resample_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
158 : {
159 : const GF_PropertyValue *p;
160 : u32 sr, nb_ch, afmt;
161 : u64 ch_cfg;
162 46 : GF_ResampleCtx *ctx = gf_filter_get_udta(filter);
163 46 : if (is_remove) {
164 0 : if (ctx->opid) {
165 0 : gf_mixer_remove_input(ctx->mixer, &ctx->input_ai);
166 0 : gf_filter_pid_remove(ctx->opid);
167 0 : ctx->opid = NULL;
168 : }
169 0 : if (ctx->in_pck) gf_filter_pid_drop_packet(ctx->ipid);
170 0 : ctx->in_pck = NULL;
171 0 : return GF_OK;
172 : }
173 46 : if (! gf_filter_pid_check_caps(pid))
174 : return GF_NOT_SUPPORTED;
175 :
176 46 : if (!ctx->opid) {
177 43 : ctx->opid = gf_filter_pid_new(filter);
178 43 : gf_filter_pid_set_max_buffer(ctx->opid, gf_filter_pid_get_max_buffer(pid) );
179 : }
180 46 : if (!ctx->ipid) {
181 43 : ctx->ipid = pid;
182 43 : gf_mixer_add_input(ctx->mixer, &ctx->input_ai);
183 : }
184 :
185 46 : sr = ctx->freq;
186 46 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_SAMPLE_RATE);
187 46 : if (p) sr = p->value.uint;
188 46 : if (!sr) sr = 44100;
189 :
190 46 : nb_ch = ctx->nb_ch;
191 46 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_NUM_CHANNELS);
192 46 : if (p) nb_ch = p->value.uint;
193 46 : if (!nb_ch) nb_ch = 1;
194 :
195 46 : afmt = ctx->afmt;
196 46 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_AUDIO_FORMAT);
197 46 : if (p) afmt = p->value.uint;
198 :
199 46 : ch_cfg = ctx->ch_cfg;
200 46 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_CHANNEL_LAYOUT);
201 46 : if (p) ch_cfg = p->value.longuint;
202 46 : if (!ch_cfg) ch_cfg = (nb_ch==1) ? GF_AUDIO_CH_FRONT_CENTER : (GF_AUDIO_CH_FRONT_LEFT|GF_AUDIO_CH_FRONT_RIGHT);
203 :
204 46 : ctx->timescale = sr;
205 46 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_TIMESCALE);
206 46 : if (p) ctx->timescale = p->value.uint;
207 :
208 : //initial config
209 46 : if (!ctx->freq || !ctx->nb_ch || !ctx->afmt) {
210 : GF_Err e;
211 43 : ctx->afmt = ctx->ofmt ? ctx->ofmt : afmt;
212 43 : ctx->freq = ctx->osr ? ctx->osr : sr;
213 43 : ctx->nb_ch = ctx->och ? ctx->och : nb_ch;
214 43 : ctx->ch_cfg = ch_cfg;
215 :
216 43 : e = gf_mixer_set_config(ctx->mixer, ctx->freq, ctx->nb_ch, afmt, ctx->ch_cfg);
217 43 : if (e) return e;
218 : }
219 : //input reconfig
220 46 : if ((sr != ctx->input_ai.samplerate) || (nb_ch != ctx->input_ai.chan)
221 3 : || (afmt != ctx->input_ai.afmt) || (ch_cfg != ctx->input_ai.ch_layout)
222 2 : || (ctx->src_is_planar != gf_audio_fmt_is_planar(afmt))
223 : ) {
224 44 : ctx->input_ai.samplerate = sr;
225 44 : ctx->input_ai.afmt = afmt;
226 44 : ctx->input_ai.chan = nb_ch;
227 44 : ctx->input_ai.ch_layout = ch_cfg;
228 44 : ctx->src_is_planar = gf_audio_fmt_is_planar(afmt);
229 44 : ctx->cfg_changed = GF_TRUE;
230 : }
231 :
232 46 : ctx->passthrough = GF_FALSE;
233 46 : gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
234 :
235 46 : if ((ctx->input_ai.samplerate==ctx->freq) && (ctx->input_ai.chan==ctx->nb_ch) && (ctx->input_ai.afmt==ctx->afmt) && (ctx->speed==FIX_ONE))
236 44 : ctx->passthrough = GF_TRUE;
237 :
238 46 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAMPLE_RATE, &PROP_UINT(ctx->freq));
239 46 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_TIMESCALE, &PROP_UINT(ctx->freq));
240 46 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_AUDIO_FORMAT, &PROP_UINT(ctx->afmt));
241 46 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_NUM_CHANNELS, &PROP_UINT(ctx->nb_ch));
242 46 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CHANNEL_LAYOUT, &PROP_LONGUINT(ctx->ch_cfg));
243 46 : return GF_OK;
244 : }
245 :
246 :
247 2215 : static GF_Err resample_process(GF_Filter *filter)
248 : {
249 : u8 *output;
250 : u32 osize, written;
251 : GF_FilterPacket *dstpck;
252 2215 : GF_ResampleCtx *ctx = gf_filter_get_udta(filter);
253 : u32 bps, bytes_per_samp;
254 2215 : if (!ctx->ipid) return GF_OK;
255 :
256 2215 : bps = gf_audio_fmt_bit_depth(ctx->afmt);
257 2215 : bytes_per_samp = ctx->nb_ch * bps / 8;
258 :
259 : while (1) {
260 5273 : if (!ctx->in_pck) {
261 5229 : ctx->in_pck = gf_filter_pid_get_packet(ctx->ipid);
262 :
263 5229 : if (!ctx->in_pck) {
264 2256 : if (gf_filter_pid_is_eos(ctx->ipid)) {
265 82 : if (ctx->passthrough || ctx->input_ai.is_eos) {
266 41 : if (ctx->opid)
267 41 : gf_filter_pid_set_eos(ctx->opid);
268 : return GF_EOS;
269 : }
270 41 : ctx->input_ai.is_eos = 1;
271 : } else {
272 2174 : ctx->input_ai.is_eos = 0;
273 2174 : return GF_OK;
274 : }
275 : } else {
276 2973 : ctx->data = gf_filter_pck_get_data(ctx->in_pck, &ctx->size);
277 2973 : u64 cts = gf_filter_pck_get_cts(ctx->in_pck);
278 2973 : cts *= ctx->freq;
279 2973 : cts /= FIX2INT(ctx->speed * ctx->timescale);
280 2973 : if (!ctx->out_cts_plus_one) {
281 43 : ctx->out_cts_plus_one = cts + 1;
282 2930 : } else if (ctx->freq != ctx->input_ai.samplerate) {
283 : s64 diff = cts;
284 0 : diff -= ctx->out_cts_plus_one-1;
285 : //200ms max
286 0 : if (ABS(diff) * 1000 > ctx->freq * 200) {
287 0 : ctx->out_cts_plus_one = cts + 1;
288 : }
289 : }
290 : }
291 : }
292 :
293 3058 : if (ctx->passthrough) {
294 252 : gf_filter_pck_forward(ctx->in_pck, ctx->opid);
295 252 : gf_filter_pid_drop_packet(ctx->ipid);
296 252 : ctx->in_pck = NULL;
297 252 : continue;
298 : }
299 :
300 2806 : if (ctx->in_pck) {
301 2765 : osize = ctx->size * ctx->nb_ch * bps;
302 2765 : osize /= ctx->input_ai.chan * gf_audio_fmt_bit_depth(ctx->input_ai.afmt);
303 : //output in higher samplerate, need more space for same samples
304 2765 : if (ctx->freq > ctx->input_ai.samplerate) {
305 0 : osize *= ctx->freq;
306 0 : osize /= ctx->input_ai.samplerate;
307 0 : while (osize % bytes_per_samp)
308 0 : osize++;
309 : }
310 : } else {
311 : //flush remaining samples from mixer, use 20 sample buffer
312 41 : osize = 20*ctx->nb_ch * bps / 8;
313 : }
314 :
315 2806 : dstpck = gf_filter_pck_new_alloc(ctx->opid, osize, &output);
316 2806 : if (!dstpck) return GF_OUT_OF_MEM;
317 :
318 2806 : if (ctx->in_pck)
319 2765 : gf_filter_pck_merge_properties(ctx->in_pck, dstpck);
320 :
321 2806 : written = gf_mixer_get_output(ctx->mixer, output, osize, 0);
322 2806 : if (!written) {
323 83 : gf_filter_pck_discard(dstpck);
324 : } else {
325 2723 : if (written != osize) {
326 4 : gf_filter_pck_truncate(dstpck, written);
327 : }
328 2723 : gf_filter_pck_set_dts(dstpck, ctx->out_cts_plus_one - 1);
329 2723 : gf_filter_pck_set_cts(dstpck, ctx->out_cts_plus_one - 1);
330 2723 : gf_filter_pck_send(dstpck);
331 :
332 : //out_cts is in output time scale ( = freq), increase by the amount of bytes/bps
333 2723 : ctx->out_cts_plus_one += written / bytes_per_samp;
334 : }
335 :
336 : //still some bytes to use from packet, do not discard
337 2806 : if (ctx->bytes_consumed<ctx->size) {
338 44 : continue;
339 : }
340 : //done with this packet
341 2762 : if (ctx->in_pck) {
342 0 : ctx->in_pck = NULL;
343 0 : gf_filter_pid_drop_packet(ctx->ipid);
344 : }
345 : }
346 : return GF_OK;
347 : }
348 :
349 41 : static GF_Err resample_reconfigure_output(GF_Filter *filter, GF_FilterPid *pid)
350 : {
351 : u32 sr, nb_ch, afmt;
352 : u64 ch_cfg;
353 : GF_Err e;
354 : const GF_PropertyValue *p;
355 41 : GF_ResampleCtx *ctx = gf_filter_get_udta(filter);
356 41 : if (ctx->opid != pid) return GF_BAD_PARAM;
357 :
358 41 : sr = ctx->freq;
359 41 : p = gf_filter_pid_caps_query(pid, GF_PROP_PID_SAMPLE_RATE);
360 41 : if (p) sr = p->value.uint;
361 :
362 41 : nb_ch = ctx->nb_ch;
363 41 : p = gf_filter_pid_caps_query(pid, GF_PROP_PID_NUM_CHANNELS);
364 41 : if (p) nb_ch = p->value.uint;
365 :
366 41 : afmt = ctx->afmt;
367 41 : p = gf_filter_pid_caps_query(pid, GF_PROP_PID_AUDIO_FORMAT);
368 41 : if (p) afmt = p->value.uint;
369 :
370 41 : ch_cfg = ctx->ch_cfg;
371 41 : p = gf_filter_pid_caps_query(pid, GF_PROP_PID_CHANNEL_LAYOUT);
372 41 : if (p) ch_cfg = p->value.longuint;
373 :
374 41 : p = gf_filter_pid_caps_query(pid, GF_PROP_PID_AUDIO_SPEED);
375 41 : if (p) {
376 3 : ctx->speed = FLT2FIX((Float) p->value.number);
377 3 : if (ctx->speed<0) ctx->speed = -ctx->speed;
378 : } else {
379 38 : ctx->speed = FIX_ONE;
380 : }
381 :
382 41 : if ((sr==ctx->freq) && (nb_ch==ctx->nb_ch) && (afmt==ctx->afmt) && (ch_cfg==ctx->ch_cfg) && (ctx->speed == FIX_ONE) ) return GF_OK;
383 :
384 41 : ctx->afmt = afmt;
385 41 : ctx->freq = sr;
386 41 : ctx->nb_ch = nb_ch;
387 41 : ctx->ch_cfg = ch_cfg;
388 :
389 41 : e = gf_mixer_set_config(ctx->mixer, ctx->freq, ctx->nb_ch, ctx->afmt, ctx->ch_cfg);
390 41 : if (e) return e;
391 41 : ctx->passthrough = GF_FALSE;
392 :
393 41 : if ((ctx->input_ai.samplerate==ctx->freq) && (ctx->input_ai.chan==ctx->nb_ch) && (ctx->input_ai.afmt==afmt) && (ctx->speed == FIX_ONE))
394 0 : ctx->passthrough = GF_TRUE;
395 :
396 41 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAMPLE_RATE, &PROP_UINT(sr));
397 41 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_AUDIO_FORMAT, &PROP_UINT(afmt));
398 41 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_NUM_CHANNELS, &PROP_UINT(nb_ch));
399 41 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CHANNEL_LAYOUT, &PROP_LONGUINT(ch_cfg));
400 :
401 41 : if (ctx->speed > FIX_ONE) {
402 : GF_FilterEvent evt;
403 2 : GF_FEVT_INIT(evt, GF_FEVT_BUFFER_REQ, ctx->ipid);
404 2 : evt.buffer_req.max_buffer_us = FIX2INT( ctx->speed * 100000 );
405 2 : gf_filter_pid_send_event(ctx->ipid, &evt);
406 : }
407 :
408 : return GF_OK;
409 : }
410 :
411 324 : static Bool resample_process_event(GF_Filter *filter, const GF_FilterEvent *evt)
412 : {
413 324 : if (((evt->base.type==GF_FEVT_PLAY) || (evt->base.type==GF_FEVT_SET_SPEED) )
414 10 : && evt->play.speed
415 : ) {
416 10 : GF_ResampleCtx *ctx = gf_filter_get_udta(filter);
417 10 : ctx->speed = FLT2FIX(evt->play.speed);
418 10 : if (ctx->speed<0) ctx->speed = -ctx->speed;
419 :
420 10 : ctx->passthrough = GF_FALSE;
421 10 : if (ctx->speed > FIX_ONE) {
422 : GF_FilterEvent anevt;
423 0 : GF_FEVT_INIT(anevt, GF_FEVT_BUFFER_REQ, ctx->ipid);
424 0 : anevt.buffer_req.max_buffer_us = FIX2INT( ctx->speed * 100000 );
425 0 : gf_filter_pid_send_event(ctx->ipid, &anevt);
426 : }
427 : }
428 324 : return GF_FALSE;
429 : }
430 :
431 : static const GF_FilterCapability ResamplerCaps[] =
432 : {
433 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
434 : CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_CODECID, GF_CODECID_RAW),
435 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_AUDIO),
436 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_CODECID, GF_CODECID_RAW),
437 : };
438 :
439 : #define OFFS(_n) #_n, offsetof(GF_ResampleCtx, _n)
440 : static const GF_FilterArgs ResamplerArgs[] =
441 : {
442 : { OFFS(och), "desired number of output audio channels - 0 for auto", GF_PROP_UINT, "0", NULL, 0},
443 : { OFFS(osr), "desired sample rate of output audio - 0 for auto", GF_PROP_UINT, "0", NULL, 0},
444 : { OFFS(ofmt), "desired format of output audio - none for auto", GF_PROP_PCMFMT, "none", NULL, 0},
445 : {0}
446 : };
447 :
448 : GF_FilterRegister ResamplerRegister = {
449 : .name = "resample",
450 : GF_FS_SET_DESCRIPTION("Audio resampler")
451 : GF_FS_SET_HELP("This filter resamples raw audio to a target sample rate, number of channels or audio format.")
452 : .private_size = sizeof(GF_ResampleCtx),
453 : .initialize = resample_initialize,
454 : .finalize = resample_finalize,
455 : .args = ResamplerArgs,
456 : SETCAPS(ResamplerCaps),
457 : .configure_pid = resample_configure_pid,
458 : .process = resample_process,
459 : .reconfigure_output = resample_reconfigure_output,
460 : .process_event = resample_process_event,
461 : };
462 :
463 :
464 2877 : const GF_FilterRegister *resample_register(GF_FilterSession *session)
465 : {
466 2877 : return &ResamplerRegister;
467 : }
468 : #else
469 :
470 : const GF_FilterRegister *resample_register(GF_FilterSession *session)
471 : {
472 : return NULL;
473 : }
474 :
475 : #endif // GPAC_DISABLE_PLAYER
|