83 lines
3.3 KiB
Python
83 lines
3.3 KiB
Python
import shutil
|
|
import subprocess
|
|
|
|
import pytest
|
|
from PIL import Image
|
|
|
|
from app.media.converter import analyze, converted_frames
|
|
|
|
|
|
VIDEO_CASES = [
|
|
("mp4", "mpeg4"),
|
|
("mov", "mpeg4"),
|
|
("mkv", "ffv1"),
|
|
("avi", "mpeg4"),
|
|
("webm", "libvpx-vp9"),
|
|
]
|
|
|
|
|
|
@pytest.mark.skipif(not shutil.which("ffmpeg"), reason="FFmpeg is not installed")
|
|
@pytest.mark.parametrize(("extension", "codec"), VIDEO_CASES)
|
|
def test_common_video_containers_probe_sample_and_merge_identical_frames(tmp_path, extension, codec):
|
|
source = tmp_path / ("constant." + extension)
|
|
result = subprocess.run([
|
|
"ffmpeg", "-nostdin", "-v", "error", "-f", "lavfi",
|
|
"-i", "color=c=red:s=96x54:r=30:d=0.3",
|
|
"-an", "-c:v", codec, "-y", str(source),
|
|
], stdout=subprocess.DEVNULL, stderr=subprocess.PIPE, check=False, timeout=30)
|
|
if result.returncode:
|
|
pytest.skip(codec + " encoder unavailable")
|
|
metadata = analyze(source, tmp_path / ("previews-" + extension))
|
|
frames = list(converted_frames(source, metadata, {
|
|
"fit_mode": "contain", "center_x": 0.5, "center_y": 0.5, "zoom": 1,
|
|
"transparency_color": "#000000", "padding_color": "#010203",
|
|
}))
|
|
assert metadata["decoder"] == "ffmpeg"
|
|
assert metadata["dynamic"] is True
|
|
assert 250 <= metadata["duration_ms"] <= 350
|
|
assert len(frames) == 1
|
|
assert frames[0][1] >= 250
|
|
assert len(frames[0][0]) == 64 * 64 * 3
|
|
|
|
|
|
@pytest.mark.skipif(not shutil.which("ffmpeg"), reason="FFmpeg is not installed")
|
|
def test_ffmpeg_free_crop_keeps_the_complete_wide_frame_and_void_padding(tmp_path):
|
|
source = tmp_path / "wide.mkv"
|
|
result = subprocess.run([
|
|
"ffmpeg", "-nostdin", "-v", "error", "-f", "lavfi",
|
|
"-i", "color=c=red:s=96x48:r=20:d=0.1",
|
|
"-an", "-c:v", "ffv1", "-y", str(source),
|
|
], stdout=subprocess.DEVNULL, stderr=subprocess.PIPE, check=False, timeout=30)
|
|
if result.returncode:
|
|
pytest.skip("ffv1 encoder unavailable")
|
|
metadata = analyze(source, tmp_path / "wide-previews")
|
|
frames = list(converted_frames(source, metadata, {
|
|
"fit_mode": "crop", "center_x": 0.5, "center_y": 0.5, "zoom": 1,
|
|
"transparency_color": "#00FF00", "padding_color": "#0000FF",
|
|
}))
|
|
output = Image.frombytes("RGB", (64, 64), frames[0][0])
|
|
assert output.getpixel((32, 0)) == (0, 0, 255)
|
|
assert output.getpixel((32, 32))[0] > 240
|
|
assert output.getpixel((32, 63)) == (0, 0, 255)
|
|
|
|
|
|
@pytest.mark.skipif(not shutil.which("heif-enc"), reason="libheif examples are not installed")
|
|
def test_heic_uses_local_libheif_decoder(tmp_path):
|
|
png = tmp_path / "source.png"
|
|
source = tmp_path / "source.heic"
|
|
Image.new("RGB", (32, 20), (4, 5, 6)).save(png)
|
|
result = subprocess.run(
|
|
["heif-enc", "-q", "100", str(png), "-o", str(source)],
|
|
stdout=subprocess.DEVNULL, stderr=subprocess.PIPE, check=False, timeout=30,
|
|
)
|
|
if result.returncode:
|
|
pytest.skip("HEIC encoder unavailable")
|
|
metadata = analyze(source, tmp_path / "heic-previews")
|
|
frames = list(converted_frames(source, metadata, {
|
|
"fit_mode": "stretch", "center_x": 0.5, "center_y": 0.5, "zoom": 1,
|
|
"transparency_color": "#000000", "padding_color": "#000000",
|
|
}))
|
|
assert metadata["decoder"] in {"pillow", "heif"}
|
|
assert metadata["dynamic"] is False
|
|
assert len(frames) == 1
|