Fast_deploy / ComfyUI-MiniMaxH3-Context-Loop /tests /_ffmpeg_concat_path_unit_test.py
dzmdd's picture
Upload folder using huggingface_hub (part 2)
bc50ea0 verified
Raw History Blame Contribute Delete
5.72 kB
#!/usr/bin/env python3
"""Issue #45: preserve filenames in Assemble's quoted FFmpeg concat list."""
import ast
import ctypes
import ctypes.util
import io
import json
import os
import pathlib
import shlex
import shutil
import subprocess
import tempfile
from unittest.mock import patch
ROOT = pathlib.Path(__file__).resolve().parents[1]
def production_writer():
# Run the actual list-writing block, without importing ComfyUI or a model.
tree = ast.parse((ROOT / "chain_nodes.py").read_text(encoding="utf-8"))
assemble = next(node for node in tree.body
if isinstance(node, ast.ClassDef)
and node.name == "MiniMaxH3ChainAssemble")
blocks = [node for node in ast.walk(assemble)
if isinstance(node, ast.With)
and any(isinstance(item.context_expr, ast.Call)
and isinstance(item.context_expr.func, ast.Name)
and item.context_expr.func.id == "open"
and item.context_expr.args
and isinstance(item.context_expr.args[0], ast.Name)
and item.context_expr.args[0].id == "concat_path"
for item in node.items)]
assert len(blocks) == 1, "Expected exactly one assembly concat-list writer"
code = compile(ast.Module(body=blocks, type_ignores=[]),
str(ROOT / "chain_nodes.py"), "exec")
def write(paths, concat_path):
exec(code, {"segment_paths": paths, "concat_path": str(concat_path)})
return write
def path_checks(write):
paths = [
r"\\mightyjobs\Resources\comfyui_output\h3_chains\demo\segments\clip_0001.mp4",
r"R:\comfyui_output\h3_chains\demo\segments\clip_0001.mp4",
r"C:\ComfyUI output\scene one's clip.mp4",
r"\\mightyjobs\Shared media\café\scene one's clip.mp4",
r"\\?\UNC\mightyjobs\Resources\comfyui_output\clip_0001.mp4",
"/tmp/render output/café/scene one's clip.mp4",
r"/tmp/render output/a\literal\backslash.mp4",
r"/tmp/render output/a\'quoted' clip.mp4",
"/tmp/render output/ #clip [one]; &two.mp4 ",
]
# The mock keeps the stream open after the production with-block exits.
stream = io.StringIO()
with patch("builtins.open") as opened:
opened.return_value.__enter__.return_value = stream
write(paths, "unused.concat.txt")
lines = stream.getvalue().splitlines()
assert len(lines) == len(paths)
for path, line in zip(paths, lines):
assert shlex.split(line) == ["file", path], (path, line)
if "'" not in path:
assert line == "file '%s'" % path
print("H3 concat paths: UNC, mapped drives, extended UNC, POSIX, spaces, "
"Unicode and apostrophes preserved")
# Cross-check with FFmpeg's own tokenizer when its shared library exists.
library = ctypes.util.find_library("avutil")
if not library:
print("SKIP native FFmpeg tokenizer: shared libavutil unavailable")
return
lib = ctypes.CDLL(library)
lib.av_get_token.argtypes = [ctypes.POINTER(ctypes.c_char_p), ctypes.c_char_p]
lib.av_get_token.restype = ctypes.c_void_p
lib.av_free.argtypes = [ctypes.c_void_p]
lib.av_free.restype = None
for path, line in zip(paths, lines):
cursor = ctypes.c_char_p(line.removeprefix("file ").encode("utf-8"))
token = lib.av_get_token(ctypes.byref(cursor), b" \t\r\n")
assert token, "FFmpeg could not allocate a parsed token"
try:
assert ctypes.string_at(token).decode("utf-8") == path
finally:
lib.av_free(token)
print("H3 concat paths: FFmpeg's native av_get_token preserves all 9 paths")
def media_checks(write):
ffmpeg, ffprobe = shutil.which("ffmpeg"), shutil.which("ffprobe")
if not ffmpeg or not ffprobe:
print("SKIP media concat: ffmpeg/ffprobe unavailable")
return
def run(command):
result = subprocess.run(command, capture_output=True, text=True,
encoding="utf-8", errors="replace", timeout=30)
assert result.returncode == 0, result.stderr
return result.stdout
# Only these throwaway CPU-generated clips are touched, never project data.
with tempfile.TemporaryDirectory(prefix="h3-concat-paths-") as temporary:
root = pathlib.Path(temporary)
first = root / "scene one's café.mp4"
second = root / (r"scene\two's clip.mp4" if os.name != "nt"
else "scene two's clip.mp4")
run([ffmpeg, "-v", "error", "-nostdin", "-f", "lavfi", "-i",
"color=c=red:s=16x16:r=24", "-frames:v", "3", "-c:v", "libx264",
"-pix_fmt", "yuv420p", str(first)])
shutil.copyfile(first, second)
final_dir = root / "final output"
final_dir.mkdir()
concat = final_dir / ".concat.txt"
output = final_dir / "joined.mp4"
write([str(first), str(second)], concat)
run([ffmpeg, "-v", "error", "-nostdin", "-f", "concat", "-safe", "0",
"-i", str(concat), "-map", "0:v:0", "-c", "copy", str(output)])
info = json.loads(run([ffprobe, "-v", "error", "-select_streams", "v:0",
"-count_frames", "-show_entries",
"stream=nb_read_frames", "-of", "json", str(output)]))
assert int(info["streams"][0]["nb_read_frames"]) == 6
assert first.is_file() and second.is_file()
print("H3 concat media: real H.264 stream-copy assembles all 6 frames "
"with special-character filenames")
if __name__ == "__main__":
writer = production_writer()
path_checks(writer)
media_checks(writer)