Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 58 additions & 2 deletions app/processors/video_processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import os
import gc
from functools import partial
import psutil

import cv2
import numpy
Expand Down Expand Up @@ -49,6 +50,8 @@ def __init__(self, main_window: 'MainWindow', num_threads=2):

self.virtcam: pyvirtualcam.Camera|None = None

self.ffplay_sound_sp = None

self.recording_sp: subprocess.Popen|None = None
self.temp_file = ''
#Used to calculate the total processing time
Expand Down Expand Up @@ -120,7 +123,10 @@ def display_next_frame(self):
if not self.recording:
video_control_actions.update_widget_values_from_markers(self.main_window, self.next_frame_to_display)
graphics_view_actions.update_graphics_view(self.main_window, pixmap, self.next_frame_to_display)
self.threads.pop(self.next_frame_to_display)
try:
self.threads.pop(self.next_frame_to_display)
except:
print("Thread not found in dict!")
self.next_frame_to_display += 1

def display_next_webcam_frame(self):
Expand Down Expand Up @@ -190,15 +196,20 @@ def process_video(self):
else:
fps = self.media_capture.get(cv2.CAP_PROP_FPS)

if self.main_window.liveSoundButton.isChecked():
self.start_live_sound()

interval = 1000 / fps if fps > 0 else 30
interval = int(interval * 0.8) #Process 20% faster to offset the frame loading & processing time so the video will be played close to the original fps

print(f"Starting frame_read_timer with an interval of {interval} ms.")
if self.recording:
self.frame_read_timer.start()
self.frame_display_timer.start()
else:
self.frame_read_timer.start(interval)
self.frame_display_timer.start()

self.gpu_memory_update_timer.start(5000) #Update GPU memory progressbar every 5 Seconds

else:
Expand Down Expand Up @@ -333,6 +344,7 @@ def stop_processing(self):
self.frame_display_timer.stop()
self.gpu_memory_update_timer.stop()
self.join_and_clear_threads()
self.stop_live_sound()


# print("Clearing Threads and Queues")
Expand Down Expand Up @@ -441,4 +453,48 @@ def enable_virtualcam(self, backend=False):
def disable_virtualcam(self):
if self.virtcam:
self.virtcam.close()
self.virtcam = None
self.virtcam = None

def start_live_sound(self):
# Start up audio if requested
seek_time = (self.next_frame_to_display)/self.fps
args = ["ffplay",
'-vn',
'-ss', str(seek_time),
'-nodisp',
'-stats',
'-loglevel', 'quiet',
'-sync', 'audio',
'-af', f'atempo={self.main_window.control["LiveSoundSpeedDecimalSlider"]}',
self.media_path]

self.ffplay_sound_sp = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

def stop_live_sound(self):
if self.ffplay_sound_sp:
parent_pid = self.ffplay_sound_sp.pid

try:
# Terminate any child processes spawned by ffplay
try:
parent_proc = psutil.Process(parent_pid)
children = parent_proc.children(recursive=True)
for child in children:
try:
child.kill()
except psutil.NoSuchProcess:
pass # The child process has already terminated
except psutil.NoSuchProcess:
pass # The parent process has already terminated

# Terminate the parent process
self.ffplay_sound_sp.terminate()
try:
self.ffplay_sound_sp.wait(timeout=2)
except subprocess.TimeoutExpired:
self.ffplay_sound_sp.kill()

except psutil.NoSuchProcess:
pass # The process no longer exists

self.ffplay_sound_sp = None
82 changes: 65 additions & 17 deletions app/ui/core/MainWindow.ui
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,54 @@
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayoutMediaButtons">
<item>
<spacer name="horizontalSpacer_7">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::MinimumExpanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="liveSoundButton">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>[Experimental] Toggle Live Sound while the video is playing</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="media.qrc">
<normaloff>:/media/media/audio_off.png</normaloff>:/media/media/audio_off.png</iconset>
</property>
<property name="iconSize">
<size>
<width>16</width>
<height>20</height>
</size>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
Expand Down Expand Up @@ -559,35 +607,35 @@
<height>120</height>
</size>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAsNeeded</enum>
</property>
<property name="toolTip">
<string>Save Embedding</string>
</property>
<property name="uniformItemSizes">
<bool>true</bool>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarPolicy::ScrollBarAlwaysOff</enum>
</property>
<property name="viewMode">
<enum>QListView::IconMode</enum>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarPolicy::ScrollBarAsNeeded</enum>
</property>
<property name="movement">
<enum>QListView::Static</enum>
<property name="autoScroll">
<bool>false</bool>
</property>
<property name="wrapping">
<bool>true</bool>
<property name="movement">
<enum>QListView::Movement::Static</enum>
</property>
<property name="layoutMode">
<enum>QListView::Batched</enum>
<enum>QListView::LayoutMode::Batched</enum>
</property>
<property name="spacing">
<number>4</number>
</property>
<property name="autoScroll">
<bool>false</bool>
<property name="viewMode">
<enum>QListView::ViewMode::IconMode</enum>
</property>
<property name="uniformItemSizes">
<bool>true</bool>
</property>
<property name="wrapping" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
Expand Down
Loading