Root cause of the reported 'timestamps off by different amounts, sometimes early, sometimes late' bug: _extract_audio_wav() never passed an explicit -map to ffmpeg, so on multi-audio-track files it relied on ffmpeg's own default-stream heuristic -- which has no knowledge of, and isn't guaranteed to agree with, whichever audio track mpv is actually configured to play. A wrong-track clap is essentially unrelated to the true one (not a small timestamp-math error), which explains the inconsistent, file-dependent symptom -- and our single-audio-track synthetic fixtures never exercised this path at all, since they only ever had one track to pick. Fixed by threading an explicit ffmpeg stream index through detect_claps() -> _extract_audio_wav(), sourced in main.py from mpv's own track-list (the ff-index of whichever audio track has selected=True). Detection now always analyzes the exact track the user is listening to, on both 'Detect All' and 'Detect Next'. Also: _probe_audio_start_time() used to silently fall back to 0.0 if ffprobe couldn't parse start_time as a plain float (e.g. N/A) -- same failure class (silently wrong instead of loud). Now emits a Python warning instead, so a genuinely unparseable/unusual container is at least visible rather than silently mis-corrected. Verified two ways: (1) ruled out an initial alternate hypothesis (video stream's own start_time mattering) empirically against the existing single-track fixtures before ruling it out. (2) Built a new two-audio-track fixture (sync_test_MULTITRACK.mp4: track 1 has a beep at 3s, track 2 at 7s) and confirmed end-to-end through the real app -- switching mpv's active track from aid=1 to aid=2 correctly flips which clap gets detected, which is exactly the mechanism this bug required.
89 lines
3.5 KiB
Python
89 lines
3.5 KiB
Python
"""Verifies clap detection analyzes whichever audio track mpv is actually
|
|
playing, not whichever one ffmpeg's own default-stream heuristic would
|
|
pick. Uses a synthetic fixture with two audio tracks with claps at very
|
|
different times (3s vs 7s) -- if detection ignored mpv's active track
|
|
selection, switching mpv to the second track would still incorrectly
|
|
report the first track's 3s clap instead of the second track's 7s one.
|
|
|
|
This directly tests the bug hypothesis from user report: 'sometimes too
|
|
early, sometimes too late, by different amounts' -- exactly what you'd
|
|
see if detection sometimes analyzed the wrong audio track on
|
|
multi-audio-track files, since a wrong-track clap position is essentially
|
|
unrelated to the true one (not a small timestamp-math error).
|
|
"""
|
|
import sys
|
|
import time
|
|
from pathlib import Path
|
|
|
|
from PyQt6.QtWidgets import QApplication
|
|
|
|
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
|
import main as app_main
|
|
|
|
ROOT = Path(__file__).resolve().parent.parent
|
|
CLIP = str(ROOT / "test_media" / "sync_test_MULTITRACK.mp4")
|
|
|
|
|
|
def wait_for(predicate, qapp, timeout=20):
|
|
deadline = time.time() + timeout
|
|
while not predicate() and time.time() < deadline:
|
|
qapp.processEvents()
|
|
time.sleep(0.05)
|
|
return predicate()
|
|
|
|
|
|
def main():
|
|
qapp = QApplication(sys.argv)
|
|
win = app_main.MainWindow()
|
|
win.show()
|
|
qapp.processEvents()
|
|
|
|
win._load(CLIP)
|
|
qapp.processEvents()
|
|
time.sleep(0.3)
|
|
qapp.processEvents()
|
|
|
|
mpv = win.source_panel.player.mpv
|
|
print(f"default aid: {mpv.aid}")
|
|
default_index = win._current_audio_stream_index()
|
|
print(f"resolved ff-index for default track: {default_index}")
|
|
assert default_index == 1, f"expected default track's ff-index to be 1, got {default_index}"
|
|
|
|
win.detect_all_button.click()
|
|
qapp.processEvents()
|
|
ok = wait_for(lambda: win.detect_all_button.isEnabled(), qapp)
|
|
assert ok, "detection did not finish in time"
|
|
markers = win.source_panel.marker_strip.markers()
|
|
print(f"markers with default track selected: {markers}")
|
|
assert any(abs(m - 3.0) < 0.5 for m in markers), f"expected a marker near 3.0s (default track's clap): {markers}"
|
|
assert not any(abs(m - 7.0) < 0.5 for m in markers), f"should not see the OTHER track's 7.0s clap yet: {markers}"
|
|
|
|
# Now switch mpv to the second audio track (aid=2), simulating a file
|
|
# where the user is listening to a non-default track, and rerun
|
|
# detection -- it must follow the switch, not keep reporting the first
|
|
# track's clap.
|
|
mpv.aid = 2
|
|
qapp.processEvents()
|
|
time.sleep(0.2)
|
|
switched_index = win._current_audio_stream_index()
|
|
print(f"resolved ff-index after switching to aid=2: {switched_index}")
|
|
assert switched_index == 2, f"expected ff-index 2 after switching tracks, got {switched_index}"
|
|
|
|
win.source_panel.marker_strip.clear()
|
|
win.detect_all_button.click()
|
|
qapp.processEvents()
|
|
ok = wait_for(lambda: win.detect_all_button.isEnabled(), qapp)
|
|
assert ok, "detection did not finish in time"
|
|
markers = win.source_panel.marker_strip.markers()
|
|
print(f"markers with second track selected: {markers}")
|
|
assert any(abs(m - 7.0) < 0.5 for m in markers), f"expected a marker near 7.0s (second track's clap) after switching: {markers}"
|
|
assert not any(abs(m - 3.0) < 0.5 for m in markers), f"should not see the FIRST track's 3.0s clap after switching: {markers}"
|
|
|
|
win.close()
|
|
qapp.processEvents()
|
|
print("\nPASS: clap detection follows mpv's actual selected audio track, not ffmpeg's default")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|