finished aux.Command, working volume detection pre-pass
This commit is contained in:
parent
5c3df8f2fc
commit
b165bb628d
2 changed files with 82 additions and 56 deletions
94
aux.py
94
aux.py
|
@ -5,28 +5,46 @@ import queue
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
import time
|
|
||||||
|
|
||||||
import over # FIXME
|
|
||||||
|
|
||||||
# --------------------------------------------------
|
# --------------------------------------------------
|
||||||
|
|
||||||
def capture_output(stream, fifo):
|
def capture_output(stream, fifo):
|
||||||
while True:
|
while True:
|
||||||
chunk = stream.read1(100)
|
chunk = stream.read1(128)
|
||||||
|
|
||||||
if chunk:
|
if chunk:
|
||||||
fifo.put(chunk)
|
fifo.put(chunk)
|
||||||
else:
|
else:
|
||||||
|
fifo.put(None) # indicates a process has terminated
|
||||||
break
|
break
|
||||||
|
|
||||||
stream.close()
|
stream.close()
|
||||||
|
|
||||||
class Command:
|
class Command:
|
||||||
|
"""
|
||||||
|
A shell command with argument substitution and output capture.
|
||||||
|
|
||||||
|
>>> c = Command(["process.sh", "-x", "ARGUMENT"])
|
||||||
|
>>> c.ARGUMENT = "file.txt"
|
||||||
|
>>> c.dump()
|
||||||
|
['process.sh', '-x', 'file.txt']
|
||||||
|
>>> c.run(stderr=False) # capture stdout
|
||||||
|
>>> c.get_output()
|
||||||
|
b'some output'
|
||||||
|
>>> c.get_output()
|
||||||
|
b'' # there was no output since the last call
|
||||||
|
>>> c.get_output()
|
||||||
|
b'more of it\nand some more'
|
||||||
|
>>> c.get_output()
|
||||||
|
None # indicates the process ended and there is no more output
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, sequence):
|
def __init__(self, sequence):
|
||||||
self.__dict__["sequence"] = list(sequence)
|
self.__dict__["sequence"] = list(sequence)
|
||||||
self.__dict__["thread"] = None
|
self.__dict__["thread"] = None
|
||||||
self.__dict__["fifo"] = None
|
self.__dict__["fifo"] = None
|
||||||
|
self.__dict__["terminated"] = False
|
||||||
|
|
||||||
def __setattr__(self, name, value):
|
def __setattr__(self, name, value):
|
||||||
found = False
|
found = False
|
||||||
|
@ -53,11 +71,10 @@ class Command:
|
||||||
|
|
||||||
return out
|
return out
|
||||||
|
|
||||||
def run(self, async=False, stderr=False):
|
def run(self, stderr=False):
|
||||||
"""
|
"""
|
||||||
Executes the command in the current environment.
|
Executes the command in the current environment.
|
||||||
|
|
||||||
async return immediatelly, use poll_output to get output
|
|
||||||
stderr capture stderr instead of stdout
|
stderr capture stderr instead of stdout
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -67,54 +84,53 @@ class Command:
|
||||||
target=capture_output,
|
target=capture_output,
|
||||||
args=(self.process.stderr if stderr else self.process.stdout, self.fifo)
|
args=(self.process.stderr if stderr else self.process.stdout, self.fifo)
|
||||||
)
|
)
|
||||||
|
self.__dict__["terminated"] = False
|
||||||
self.thread.daemon = True # thread dies with the program
|
self.thread.daemon = True # thread dies with the program
|
||||||
self.thread.start()
|
self.thread.start()
|
||||||
|
|
||||||
if not async:
|
def get_output(self, blocking=False):
|
||||||
buffer = []
|
|
||||||
probably_dead = False
|
|
||||||
|
|
||||||
while True:
|
|
||||||
probably_dead = self.process.poll() is not None
|
|
||||||
|
|
||||||
chunk = self.poll_output()
|
|
||||||
|
|
||||||
if chunk:
|
|
||||||
buffer.append(chunk)
|
|
||||||
else:
|
|
||||||
time.sleep(0.01)
|
|
||||||
|
|
||||||
if not chunk and self.process.poll() is not None and probably_dead:
|
|
||||||
break
|
|
||||||
|
|
||||||
return b"".join(buffer)
|
|
||||||
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def poll_output(self):
|
|
||||||
"""
|
"""
|
||||||
Returns the output of a currently running process and clears the buffer.
|
Returns the output of a currently running process and clears the buffer.
|
||||||
|
|
||||||
Returns None if no process is running.
|
Returns None if no process is running and no more output is available.
|
||||||
|
|
||||||
Blocking - always returns at least one char.
|
blocking block until some output is available or the process terminates
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if self.fifo.empty():
|
|
||||||
return None
|
|
||||||
|
|
||||||
else:
|
|
||||||
buffer = []
|
buffer = []
|
||||||
|
|
||||||
|
if self.terminated:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if blocking:
|
||||||
|
buffer.append(self.fifo.get())
|
||||||
|
|
||||||
while not self.fifo.empty():
|
while not self.fifo.empty():
|
||||||
buffer.append(self.fifo.get_nowait())
|
buffer.append(self.fifo.get_nowait()) # FIXME nowait needed?
|
||||||
|
|
||||||
|
if None in buffer:
|
||||||
|
self.__dict__["terminated"] = True
|
||||||
|
|
||||||
|
if len(buffer) == 1:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
assert(buffer[-1] is None)
|
||||||
|
del buffer[-1]
|
||||||
|
|
||||||
return b"".join(buffer)
|
return b"".join(buffer)
|
||||||
|
|
||||||
@property
|
def get_all_output(self):
|
||||||
def running(self):
|
buffer = []
|
||||||
return self.process.poll() is None
|
|
||||||
|
while True:
|
||||||
|
chunk = self.get_output(blocking=True)
|
||||||
|
|
||||||
|
if chunk is None:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
buffer.append(chunk)
|
||||||
|
|
||||||
|
return b''.join(buffer) if buffer else None
|
||||||
|
|
||||||
# --------------------------------------------------
|
# --------------------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,8 @@ if __name__ == "__main__":
|
||||||
|
|
||||||
identify_cmd = Command(command.identify)
|
identify_cmd = Command(command.identify)
|
||||||
identify_cmd.INFILE = tgt
|
identify_cmd.INFILE = tgt
|
||||||
identify_raw = identify_cmd.run()
|
identify_cmd.run()
|
||||||
|
identify_raw = identify_cmd.get_all_output()
|
||||||
identify_dict = json.loads(identify_raw.decode("utf-8"))
|
identify_dict = json.loads(identify_raw.decode("utf-8"))
|
||||||
|
|
||||||
info = over.core.types.ndict()
|
info = over.core.types.ndict()
|
||||||
|
@ -95,29 +96,38 @@ if __name__ == "__main__":
|
||||||
|
|
||||||
norm_pre_cmd = Command(command.normalize_prepass)
|
norm_pre_cmd = Command(command.normalize_prepass)
|
||||||
norm_pre_cmd.INFILE = tgt
|
norm_pre_cmd.INFILE = tgt
|
||||||
norm_pre_cmd.run(async=True, stderr=True)
|
norm_pre_cmd.run(stderr=True)
|
||||||
|
|
||||||
pb = over.core.textui.ProgressBar(50, int(info.video_fps.value * info.duration), "frames")
|
pb = over.core.textui.ProgressBar(50, int(info.video_fps.value * info.duration), "frames")
|
||||||
|
|
||||||
while True:
|
output_buffer = []
|
||||||
probably_dead = not norm_pre_cmd.running
|
|
||||||
|
|
||||||
|
while True:
|
||||||
time.sleep(.25)
|
time.sleep(.25)
|
||||||
|
|
||||||
o = norm_pre_cmd.poll_output()
|
out = norm_pre_cmd.get_output()
|
||||||
|
|
||||||
if o:
|
if out:
|
||||||
if b"frame=" in o:
|
output_buffer.append(out)
|
||||||
frame_id = re.findall(b"frame= *(\d+) ", o)[0]
|
|
||||||
|
if b"frame=" in out:
|
||||||
|
frame_id = re.findall(b"frame= *(\d+) ", out)[0]
|
||||||
pb.update(int(frame_id))
|
pb.update(int(frame_id))
|
||||||
|
|
||||||
elif b"mean_volume: " in o:
|
elif out is None:
|
||||||
info.mean_volume = float(re.findall(b"mean_volume: (-\d+\.\d+) dB", o)[0])
|
|
||||||
info.volume_correction = info.mean_volume - main.cfg.normalize_mean
|
|
||||||
else:
|
|
||||||
print(o)
|
|
||||||
|
|
||||||
elif not norm_pre_cmd.running and probably_dead:
|
|
||||||
break
|
break
|
||||||
|
|
||||||
|
output = b''.join(output_buffer)
|
||||||
|
|
||||||
|
if b"mean_volume: " in output:
|
||||||
|
info.mean_volume = float(re.findall(b"mean_volume: (-\d+\.\d+) dB", output)[0])
|
||||||
|
info.volume_correction = info.mean_volume - main.cfg.normalize_mean
|
||||||
|
else:
|
||||||
|
_print("§runexpected ffmpeg output§/, dump follows", prefix.fail, suffix=":\n")
|
||||||
|
print(output)
|
||||||
|
raise RuntimeError
|
||||||
|
|
||||||
|
pb.blank()
|
||||||
_print("detected volume %.2f dB, correction %.2f dB" %(info.mean_volume, info.volume_correction))
|
_print("detected volume %.2f dB, correction %.2f dB" %(info.mean_volume, info.volume_correction))
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue