Skip to content

Commit

Permalink
1.5.4 rewrites internal command calling to be less bad
Browse files Browse the repository at this point in the history
  • Loading branch information
natis1 committed Aug 4, 2020
1 parent 7e94884 commit e618789
Show file tree
Hide file tree
Showing 8 changed files with 151 additions and 120 deletions.
25 changes: 15 additions & 10 deletions qencoder/aomkf.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ def find_aom_keyframes(stat_file, key_freq_min):

return keyframes_list

def aom_keyframes(video_path, video_path_str, stat_file, stat_file_str, min_scene_len, ffmpeg_pipe, encoder, netThreads, video_params, qinterface):
def aom_keyframes(video_path: Path, stat_file: Path, min_scene_len, ffmpeg_pipe, encoder, netThreads, video_params, rtenc, qinterface):
"""[Get frame numbers for splits from aomenc 1 pass stat file]
"""
qinterface.q.put([0, "Analysis", 0])
Expand All @@ -147,21 +147,26 @@ def aom_keyframes(video_path, video_path_str, stat_file, stat_file_str, min_scen
video.release()

if total < 1:
total = frame_probe(video_path_str)
total = frame_probe(video_path)

ffmpeg_pipe = ffmpeg_pipe[:-2] # remove the ' |' at the end

f = f'ffmpeg -y -hide_banner -loglevel error -i \'{video_path_str}\' {ffmpeg_pipe}'
f1 = ["ffmpeg", "-y", "-hide_banner", "-loglevel", "error", "-i", video_path.as_posix()]
f = f1 + ffmpeg_pipe.split()
# removed -w -h from aomenc since ffmpeg filters can change it and it can be added into video_params
# TODO(n9Mtq4): if an encoder other than aom is being used, video_params becomes the default so -w -h may be needed again
e = ""
if (encoder == "aom"):
e = f'aomenc --passes=2 --pass=1 {video_params} --fpf=\'{stat_file_str}\' -o {os.devnull} -'
e = []
if (encoder == "aom" and not rtenc):
e621 = ["aomenc", "--passes=2", "--pass=1"]
e2 = ["--fpf=" + stat_file.as_posix(), "-o", os.devnull, "-"]
e = e621 + video_params.split() + e2
else:
e = f'aomenc --passes=2 --pass=1 --threads={str(netThreads)} --cpu-used=5 --end-usage=q --cq-level=40 --fpf=\'{stat_file_str}\' -o {os.devnull} -'

ffmpeg_pipe = subprocess.Popen(f, shell=True, stdout=PIPE, stderr=STDOUT)
pipe = subprocess.Popen(e, shell=True, stdin=ffmpeg_pipe.stdout, stdout=PIPE,
e = ["aomenc", "--passes=2", "--pass=1", "--threads=" + str(netThreads),
"--cpu-used=5", "--end-usage=q", "--cq-level=40", "--fpf=" + stat_file.as_posix(),
"-o", os.devnull, "-"]
print(e)
ffmpeg_pipe = subprocess.Popen(f, stdout=PIPE, stderr=STDOUT)
pipe = subprocess.Popen(e, stdin=ffmpeg_pipe.stdout, stdout=PIPE,
stderr=STDOUT, universal_newlines=True)

encoder_history = deque(maxlen=20)
Expand Down
49 changes: 25 additions & 24 deletions qencoder/ffmpeg.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
import sys


def frame_probe(source):
def frame_probe(source: Path):
"""Get frame count."""
cmd = "ffmpeg -hide_banner -i '" + str(source) + "' -map 0:v:0 -f null -"
r = subprocess.run(cmd, shell = True, stdout=PIPE, stderr=PIPE)
cmd = ["ffmpeg", "-hide_banner", "-i", source.as_posix(), "-map", "0:v:0", "-f", "null", "-"]
r = subprocess.run(cmd, stdout=PIPE, stderr=PIPE)
matches = re.findall(r"frame=\s*([0-9]+)\s", r.stderr.decode("utf-8") + r.stdout.decode("utf-8"))
return int(matches[-1])

Expand Down Expand Up @@ -56,16 +56,16 @@ def write_progress_file(file, chunk, frames):
json.dump(d, f)


def frame_check(source: Path, source_str, encoded: Path, encoded_str, temp: Path, nocheck):
def frame_check(source: Path, encoded: Path, temp: Path, nocheck):
"""Checking if source and encoded video frame count match."""
try:
status_file = Path(temp / 'done.json')

if nocheck:
s1 = frame_probe(source_str)
s1 = frame_probe(source)
write_progress_file(status_file, source, s1)
else:
s1, s2 = [frame_probe(i) for i in (source_str, encoded_str)]
s1, s2 = [frame_probe(i) for i in (source, encoded)]
if s1 == s2:
write_progress_file(status_file, source, s1)
else:
Expand All @@ -82,43 +82,44 @@ def frame_check(source: Path, source_str, encoded: Path, encoded_str, temp: Path
doneFileLock.release()


def concatenate_video(temp, temp_folder, output):
def concatenate_video(temp: Path, output: Path):
"""With FFMPEG concatenate encoded segments into final file."""

with open(f'{temp_folder / "concat" }', 'w') as f:
with open(f'{temp / "concat" }', 'w') as f:

encode_files = sorted((temp_folder / 'encode').iterdir())
encode_files = sorted((temp / 'encode').iterdir())
# Replace all the ' with '/'' so ffmpeg can read the path correctly
f.writelines("file '" + str(file.absolute()).replace('\'','\'\\\'\'') + "'\n" for file in encode_files)

# Add the audio file if one was extracted from the input
audio_file = temp + "/audio.mkv"
audio_actualfile = temp_folder / "audio.mkv"
if audio_actualfile.exists():
audio = f'-i \'{audio_file}\' -c:a copy -map 1'
audio_file = temp / "audio.mkv"
if audio_file.exists():
audio = ["-i", audio_file.as_posix(), "-c:a", "copy", "-map", "1"]
else:
audio = ''
audio = []

cmd = f' ffmpeg -y -hide_banner -loglevel error -f concat -safe 0 -i \'{temp + "/concat"}\' ' \
f'{audio} -c copy -map 0 -y \'{output}\''
concat = subprocess.run(cmd, shell=True, stdout=PIPE, stderr=STDOUT).stdout
cmd1 = ["ffmpeg", "-y", "-hide_banner", "-loglevel", "error", "-f", "concat", "-safe", "0", "-i", temp / "concat"]
cmd2 = ["-c", "copy", "-map", "0", "-y", output.as_posix()]
cmd = cmd1 + audio + cmd2
concat = subprocess.run(cmd, stdout=PIPE, stderr=STDOUT).stdout


if len(concat) > 0:
print(concat.decode())
raise Exception


def extract_audio(input_vid, temp, audio_params):
def extract_audio(input_vid: Path, temp: Path, audio_params):
"""Extracting audio from source, transcoding if needed."""
audio_file = temp + "/audio.mkv"
audio_file = temp / "audio.mkv"

# Checking is source have audio track
check = fr' ffmpeg -y -hide_banner -loglevel error -ss 0 -i \'{input_vid}\' -t 0 -vn -c:a copy -f null -'
is_audio_here = len(subprocess.run(check, shell=True, stdout=PIPE, stderr=STDOUT).stdout) == 0
check = ["ffmpeg", "-y", "-hide_banner", "-loglevel", "error",
"-ss", "0", "-i", input_vid.as_posix(), "-t", "0", "-vn", "-c:a", "copy", "-f", "null", "-"]
is_audio_here = len(subprocess.run(check, stdout=PIPE, stderr=STDOUT).stdout) == 0

# If source have audio track - process it
if is_audio_here:
cmd = f'ffmpeg -y -hide_banner -loglevel error -i \'{input_vid}\' -vn ' \
f'{audio_params} {audio_file}'
subprocess.run(cmd, shell=True)
cmd1 = ["ffmpeg", "-y", "-hide_banner", "-loglevel", "error", "-i", input_vid.as_posix(), "-vn"]
cmd = cmd1 + audio_params.split() + [audio_file.as_posix()]
subprocess.run(cmd)
2 changes: 1 addition & 1 deletion qencoder/mainwindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -737,7 +737,7 @@ def retranslateUi(self, qencoder):
self.pushButton_vmafmodel.setText(_translate("qencoder", "Choose Model"))
self.checkBox_shutdown.setStatusTip(_translate("qencoder", "May not work depending on OS/config, please test first with a short queue/video."))
self.checkBox_shutdown.setText(_translate("qencoder", "Shutdown after completion"))
self.checkBox_lessshitsplit.setStatusTip(_translate("qencoder", "Do not use pyscenedetect at all. Still in testing but if you can test it, check this. It\'s totally worth it."))
self.checkBox_lessshitsplit.setStatusTip(_translate("qencoder", "Do not use pyscenedetect. Far slower, but less fail prone and better. Recommended for most encodes!"))
self.checkBox_lessshitsplit.setText(_translate("qencoder", "Use First Pass For Splitting"))
self.checkBox_unsafeSplit.setStatusTip(_translate("qencoder", "Allow splitting on frames that weren\'t keyframes in the original. might cause chunking errors."))
self.checkBox_unsafeSplit.setText(_translate("qencoder", "Unsafe Splitting"))
Expand Down
2 changes: 1 addition & 1 deletion qencoder/mainwindow.ui
Original file line number Diff line number Diff line change
Expand Up @@ -1401,7 +1401,7 @@
<item row="2" column="8" colspan="3">
<widget class="QCheckBox" name="checkBox_lessshitsplit">
<property name="statusTip">
<string>Do not use pyscenedetect at all. Still in testing but if you can test it, check this. It's totally worth it.</string>
<string>Do not use pyscenedetect. Far slower, but less fail prone and better. Recommended for most encodes!</string>
</property>
<property name="text">
<string>Use First Pass For Splitting</string>
Expand Down
Loading

0 comments on commit e618789

Please sign in to comment.