feat(app): add full motion comparison app with audio support and pose similarity analysis
This commit is contained in:
105
audio_player.py
Normal file
105
audio_player.py
Normal file
@@ -0,0 +1,105 @@
|
||||
import os
|
||||
import time
|
||||
import tempfile
|
||||
import streamlit as st
|
||||
from config import PYGAME_AVAILABLE, MOVIEPY_AVAILABLE
|
||||
|
||||
if PYGAME_AVAILABLE:
|
||||
import pygame
|
||||
|
||||
if MOVIEPY_AVAILABLE:
|
||||
from moviepy.editor import VideoFileClip
|
||||
|
||||
class AudioPlayer:
|
||||
"""A class to handle audio extraction and playback for the video."""
|
||||
|
||||
def __init__(self):
|
||||
self.is_playing = False
|
||||
self.audio_file = None
|
||||
self.start_time = None
|
||||
self.pygame_initialized = False
|
||||
|
||||
if PYGAME_AVAILABLE:
|
||||
try:
|
||||
# Initialize pygame mixer with a specific frequency to avoid common issues
|
||||
pygame.mixer.pre_init(frequency=44100, size=-16, channels=2, buffer=512)
|
||||
pygame.mixer.init()
|
||||
self.pygame_initialized = True
|
||||
except Exception as e:
|
||||
st.warning(f"Audio mixer initialization failed: {e}")
|
||||
|
||||
def extract_audio_from_video(self, video_path):
|
||||
"""Extracts audio from a video file using MoviePy."""
|
||||
if not MOVIEPY_AVAILABLE or not self.pygame_initialized:
|
||||
return None
|
||||
|
||||
try:
|
||||
temp_audio = tempfile.mktemp(suffix='.wav')
|
||||
video_clip = VideoFileClip(video_path)
|
||||
if video_clip.audio is not None:
|
||||
video_clip.audio.write_audiofile(temp_audio, verbose=False, logger=None)
|
||||
video_clip.close()
|
||||
return temp_audio
|
||||
else:
|
||||
video_clip.close()
|
||||
return None
|
||||
except Exception as e:
|
||||
st.warning(f"Could not extract audio: {e}")
|
||||
return None
|
||||
|
||||
def load_audio(self, video_path):
|
||||
"""Loads an audio file for playback."""
|
||||
if not self.pygame_initialized:
|
||||
return False
|
||||
|
||||
try:
|
||||
audio_file = self.extract_audio_from_video(video_path)
|
||||
if audio_file and os.path.exists(audio_file):
|
||||
self.audio_file = audio_file
|
||||
return True
|
||||
return False
|
||||
except Exception as e:
|
||||
st.error(f"Failed to load audio: {e}")
|
||||
return False
|
||||
|
||||
def play(self):
|
||||
"""Plays the loaded audio file."""
|
||||
if not self.pygame_initialized or not self.audio_file or self.is_playing:
|
||||
return False
|
||||
try:
|
||||
pygame.mixer.music.load(self.audio_file)
|
||||
pygame.mixer.music.play()
|
||||
self.is_playing = True
|
||||
self.start_time = time.time()
|
||||
return True
|
||||
except Exception as e:
|
||||
st.warning(f"Audio playback failed: {e}")
|
||||
return False
|
||||
|
||||
def stop(self):
|
||||
"""Stops the audio playback."""
|
||||
if self.pygame_initialized and self.is_playing:
|
||||
try:
|
||||
pygame.mixer.music.stop()
|
||||
self.is_playing = False
|
||||
return True
|
||||
except Exception as e:
|
||||
return False
|
||||
return False
|
||||
|
||||
def restart(self):
|
||||
"""Restarts the audio from the beginning."""
|
||||
if self.pygame_initialized and self.audio_file:
|
||||
self.stop()
|
||||
return self.play()
|
||||
return False
|
||||
|
||||
def cleanup(self):
|
||||
"""Cleans up audio resources."""
|
||||
self.stop()
|
||||
if self.audio_file and os.path.exists(self.audio_file):
|
||||
try:
|
||||
os.unlink(self.audio_file)
|
||||
self.audio_file = None
|
||||
except Exception:
|
||||
pass
|
||||
Reference in New Issue
Block a user