Skip to content

Commit 331614b

Browse files
committed
af_scaletempo2: fix audio-video de-sync caused by speed changes
Fixes mpv-player#12028, audio-video desynchronization caused by changing speed. There was an additional issue that audio was always delayed by half the configured search-interval. Include `ola_hop_size` in the delay to compensate for that. Notes: - Every WSOLA iteration advances the input buffer by _some amount_, and produces data in the output buffer always of size `ola_hop_size`. - `mp_scaletempo2_fill_buffer` is always called with `ola_hop_size` - Thus, the rendered frames are always cleared immediately after processing, and `num_complete_frames` is 0 in the delay calculation. - The factors contributing to delay are: - the pending samples in the input buffer according to the search block position, - the pending rendered samples in the output buffer, and - an amount of `ola_hop_size` on the output side - Because the optimal block can be anywhere in the search block, calculate the delay according to the average position, or start of the center window. The frame_delay code looked like that of the rubberband filter, which might not work for scaletempo2. Sometimes a different amount of input audio was consumed by scaletempo2 than expected. It may have been caused by speed changes being a more dynamic process in scaletempo2. This can be seen by where `playback_rate` is used in `run_one_wsola_iteration`: `playback_rate` is only referenced after the iteration, when updating the time and removing old data from buffers. In scaletempo2, the playback speed is applied by changing the amount the search block is moved. That apparently averages out correctly at constant playback speed, but when the speed changes, the error in this assumption probably spikes. This error accumulated across all speed changes because of the persistent `frame_delay` value. With the removal of the persistent `frame_delay`, there should be no way for the audio to drift off. By deriving the delay from filter buffer positions, and the buffers are filled only as much as needed, the delay always stays within buffer bounds.
1 parent 3bdf702 commit 331614b

File tree

1 file changed

+6
-8
lines changed

1 file changed

+6
-8
lines changed

audio/filter/af_scaletempo2.c

+6-8
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ struct priv {
1515
bool sent_final;
1616
struct mp_aframe *pending;
1717
bool initialized;
18-
double frame_delay;
1918
float speed;
2019
};
2120

@@ -67,7 +66,6 @@ static void process(struct mp_filter *f)
6766
uint8_t **planes = mp_aframe_get_data_ro(p->pending);
6867
int read = mp_scaletempo2_fill_input_buffer(&p->data,
6968
planes, frame_size, final);
70-
p->frame_delay += read;
7169
mp_aframe_skip_samples(p->pending, read);
7270
}
7371
p->sent_final |= final;
@@ -109,11 +107,13 @@ static void process(struct mp_filter *f)
109107
(float**)planes, out_samples, p->speed);
110108

111109
double pts = mp_aframe_get_pts(p->pending);
112-
p->frame_delay -= out_samples * p->speed;
113-
114110
if (pts != MP_NOPTS_VALUE) {
115-
double delay = p->frame_delay / mp_aframe_get_effective_rate(out);
116-
mp_aframe_set_pts(out, pts - delay);
111+
double center_candidate = p->data.search_block_index + p->data.search_block_center_offset
112+
- p->data.ola_hop_size;
113+
double frame_delay = p->data.input_buffer_frames - center_candidate
114+
+ p->data.num_complete_frames * p->speed
115+
+ p->data.ola_hop_size * p->speed;
116+
mp_aframe_set_pts(out, pts - frame_delay / mp_aframe_get_effective_rate(out));
117117
}
118118

119119
mp_aframe_set_size(out, out_samples);
@@ -137,7 +137,6 @@ static bool init_scaletempo2(struct mp_filter *f)
137137
mp_aframe_reset(p->cur_format);
138138
p->initialized = true;
139139
p->sent_final = false;
140-
p->frame_delay = 0;
141140
mp_aframe_config_copy(p->cur_format, p->pending);
142141

143142
mp_scaletempo2_init(&p->data, mp_aframe_get_channels(p->pending),
@@ -163,7 +162,6 @@ static void reset(struct mp_filter *f)
163162
{
164163
struct priv *p = f->priv;
165164
mp_scaletempo2_reset(&p->data);
166-
p->frame_delay = 0;
167165
p->initialized = false;
168166
TA_FREEP(&p->pending);
169167
}

0 commit comments

Comments
 (0)