adf0d17497
publish / version_or_publish (push) Has been cancelled
storybook-build / changes (push) Has been cancelled
storybook-build / :storybook-build (push) Has been cancelled
Sync Gradio Skills to Hugging Face / sync-skills (push) Has been cancelled
functional / changes (push) Has been cancelled
functional / build-frontend (push) Has been cancelled
functional / functional-test-SSR=false (push) Has been cancelled
functional / functional-reload (push) Has been cancelled
js / changes (push) Has been cancelled
js / js-test (push) Has been cancelled
docs-build / changes (push) Has been cancelled
docs-build / docs-build (push) Has been cancelled
docs-build / website-build (push) Has been cancelled
functional / functional-test-SSR=true (push) Has been cancelled
hygiene / hygiene-test (push) Has been cancelled
python / changes (push) Has been cancelled
python / build (push) Has been cancelled
python / test-ubuntu-latest-flaky (push) Has been cancelled
python / test-ubuntu-latest-not-flaky (push) Has been cancelled
python / test-windows-latest-flaky (push) Has been cancelled
python / test-windows-latest-not-flaky (push) Has been cancelled
236 lines
8.7 KiB
Python
236 lines
8.7 KiB
Python
import os
|
|
import shutil
|
|
import tempfile
|
|
from copy import deepcopy
|
|
from pathlib import Path
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
import pytest
|
|
|
|
import gradio as gr
|
|
from gradio import processing_utils
|
|
from gradio.data_classes import FileData
|
|
|
|
|
|
class TestVideo:
|
|
@pytest.mark.asyncio
|
|
async def test_component_functions(self, media_data):
|
|
"""
|
|
Preprocess, serialize, deserialize, get_config
|
|
"""
|
|
x_video = FileData(path=deepcopy(media_data.BASE64_VIDEO)["path"])
|
|
video_input = gr.Video()
|
|
|
|
x_video = await processing_utils.async_move_files_to_cache(
|
|
[x_video], video_input
|
|
)
|
|
x_video = x_video[0]
|
|
|
|
output1 = video_input.preprocess(x_video)
|
|
assert isinstance(output1, str)
|
|
output2 = video_input.preprocess(x_video)
|
|
assert output1 == output2
|
|
|
|
video_input = gr.Video(include_audio=False)
|
|
output1 = video_input.preprocess(x_video)
|
|
output2 = video_input.preprocess(x_video)
|
|
assert output1 == output2
|
|
|
|
video_input = gr.Video(label="Upload Your Video")
|
|
assert video_input.get_config() == {
|
|
"autoplay": False,
|
|
"sources": ["upload", "webcam"],
|
|
"name": "video",
|
|
"buttons": ["download"],
|
|
"show_label": True,
|
|
"label": "Upload Your Video",
|
|
"container": True,
|
|
"min_width": 160,
|
|
"scale": None,
|
|
"height": None,
|
|
"width": None,
|
|
"elem_id": None,
|
|
"elem_classes": [],
|
|
"visible": True,
|
|
"playback_position": 0,
|
|
"value": None,
|
|
"interactive": None,
|
|
"proxy_url": None,
|
|
"webcam_options": {"constraints": None, "mirror": True},
|
|
"include_audio": True,
|
|
"format": None,
|
|
"_selectable": False,
|
|
"key": None,
|
|
"preserved_by_key": ["value"],
|
|
"loop": False,
|
|
"streaming": False,
|
|
"watermark": {"watermark": None, "position": "bottom-right"},
|
|
"subtitles": None,
|
|
}
|
|
assert video_input.preprocess(None) is None
|
|
video_input = gr.Video(format="avi")
|
|
output_video = video_input.preprocess(x_video)
|
|
assert output_video
|
|
assert output_video[-3:] == "avi"
|
|
assert "flip" not in output_video
|
|
|
|
# Output functionalities
|
|
y_vid_path = "test/test_files/video_sample.mp4"
|
|
video_output = gr.Video()
|
|
output1 = video_output.postprocess(y_vid_path)
|
|
assert output1
|
|
output1 = output1.model_dump()["path"]
|
|
assert output1.endswith("mp4")
|
|
output2 = video_output.postprocess(y_vid_path)
|
|
assert output2
|
|
output2 = output2.model_dump()["path"]
|
|
assert output1 == output2
|
|
output3 = video_output.postprocess(y_vid_path)
|
|
assert output3
|
|
assert output3.model_dump()["orig_name"] == "video_sample.mp4"
|
|
|
|
video = gr.Video(format="wav")
|
|
video_url_with_query_param = "https://github.com/gradio-app/gradio/raw/refs/heads/main/test/test_files/playable_but_bad_container.mp4?query=fake"
|
|
postprocessed_video_with_query_param = video.postprocess(
|
|
video_url_with_query_param
|
|
)
|
|
assert postprocessed_video_with_query_param
|
|
assert postprocessed_video_with_query_param.model_dump()["path"].endswith(
|
|
"playable_but_bad_container.wav"
|
|
)
|
|
|
|
p_video = gr.Video()
|
|
postprocessed_video = p_video.postprocess(Path(y_vid_path))
|
|
assert postprocessed_video
|
|
|
|
postprocessed_video = postprocessed_video.model_dump()
|
|
|
|
processed_video = {
|
|
"path": "video_sample.mp4",
|
|
"orig_name": "video_sample.mp4",
|
|
"mime_type": None,
|
|
"size": None,
|
|
"url": None,
|
|
"is_stream": False,
|
|
"meta": {"_type": "gradio.FileData"},
|
|
}
|
|
|
|
postprocessed_video["path"] = os.path.basename(postprocessed_video["path"])
|
|
assert processed_video == postprocessed_video
|
|
|
|
def test_in_interface(self, media_data):
|
|
"""
|
|
Interface, process
|
|
"""
|
|
x_video = media_data.BASE64_VIDEO["path"]
|
|
iface = gr.Interface(lambda x: x, "video", "playable_video")
|
|
assert iface(x_video).endswith(".mp4")
|
|
|
|
def test_video_postprocess_converts_to_playable_format(self):
|
|
test_file_dir = Path(__file__).parent.parent / "test_files"
|
|
# This file has a playable container but not playable codec
|
|
with tempfile.NamedTemporaryFile(
|
|
suffix="bad_video.mp4", delete=False
|
|
) as tmp_not_playable_vid:
|
|
bad_vid = str(test_file_dir / "bad_video_sample.mp4")
|
|
assert not processing_utils.video_is_playable(bad_vid)
|
|
shutil.copy(bad_vid, tmp_not_playable_vid.name)
|
|
output = gr.Video().postprocess(tmp_not_playable_vid.name)
|
|
assert output
|
|
output = output.model_dump()
|
|
assert processing_utils.video_is_playable(output["path"])
|
|
|
|
# This file has a playable codec but not a playable container
|
|
with tempfile.NamedTemporaryFile(
|
|
suffix="playable_but_bad_container.mkv", delete=False
|
|
) as tmp_not_playable_vid:
|
|
bad_vid = str(test_file_dir / "playable_but_bad_container.mkv")
|
|
assert not processing_utils.video_is_playable(bad_vid)
|
|
shutil.copy(bad_vid, tmp_not_playable_vid.name)
|
|
output = gr.Video().postprocess(tmp_not_playable_vid.name)
|
|
assert output
|
|
output = output.model_dump()
|
|
assert processing_utils.video_is_playable(output["path"])
|
|
|
|
@patch("pathlib.Path.exists", MagicMock(return_value=False))
|
|
@patch("gradio.components.video.FFmpeg")
|
|
def test_video_preprocessing_flips_video_for_webcam(self, mock_ffmpeg, media_data):
|
|
# Ensures that the cached temp video file is not used so that ffmpeg is called for each test
|
|
x_video = FileData(path=media_data.BASE64_VIDEO["path"])
|
|
video_input = gr.Video(sources=["webcam"])
|
|
_ = video_input.preprocess(x_video)
|
|
|
|
# Dict mapping filename to FFmpeg options
|
|
output_params = mock_ffmpeg.call_args_list[0][1]["outputs"]
|
|
assert "hflip" in list(output_params.values())[0]
|
|
assert "flip" in list(output_params.keys())[0]
|
|
|
|
mock_ffmpeg.reset_mock()
|
|
_ = gr.Video(
|
|
sources=["webcam"],
|
|
webcam_options=gr.WebcamOptions(mirror=False),
|
|
include_audio=True,
|
|
).preprocess(x_video)
|
|
mock_ffmpeg.assert_not_called()
|
|
|
|
mock_ffmpeg.reset_mock()
|
|
_ = gr.Video(sources=["upload"], format="mp4", include_audio=True).preprocess(
|
|
x_video
|
|
)
|
|
mock_ffmpeg.assert_not_called()
|
|
|
|
mock_ffmpeg.reset_mock()
|
|
output_file = gr.Video(
|
|
sources=["webcam"],
|
|
webcam_options=gr.WebcamOptions(mirror=True),
|
|
format="avi",
|
|
).preprocess(x_video)
|
|
assert output_file
|
|
output_params = mock_ffmpeg.call_args_list[0][1]["outputs"]
|
|
assert "hflip" in list(output_params.values())[0]
|
|
assert "flip" in list(output_params.keys())[0]
|
|
assert ".avi" in list(output_params.keys())[0]
|
|
assert ".avi" in output_file
|
|
|
|
mock_ffmpeg.reset_mock()
|
|
output_file = gr.Video(
|
|
sources=["webcam"],
|
|
webcam_options=gr.WebcamOptions(mirror=False),
|
|
format="avi",
|
|
include_audio=False,
|
|
).preprocess(x_video)
|
|
assert output_file
|
|
output_params = mock_ffmpeg.call_args_list[0][1]["outputs"]
|
|
assert list(output_params.values())[0] == ["-an"]
|
|
assert "flip" not in Path(list(output_params.keys())[0]).name
|
|
assert ".avi" in list(output_params.keys())[0]
|
|
assert ".avi" in output_file
|
|
|
|
|
|
def test_is_video_correct_length():
|
|
test_file_dir = Path(__file__).parent.parent / "test_files"
|
|
video_path = str(test_file_dir / "muted_video_sample.mp4")
|
|
assert (
|
|
gr.validators.is_video_correct_length(video_path, None, None)["is_valid"]
|
|
is True
|
|
)
|
|
assert (
|
|
gr.validators.is_video_correct_length(video_path, 1, None)["is_valid"] is True
|
|
)
|
|
assert (
|
|
gr.validators.is_video_correct_length(video_path, 1000, None)["is_valid"]
|
|
is False
|
|
)
|
|
assert (
|
|
gr.validators.is_video_correct_length(video_path, None, 1000)["is_valid"]
|
|
is True
|
|
)
|
|
assert (
|
|
gr.validators.is_video_correct_length(video_path, None, 1)["is_valid"] is False
|
|
)
|
|
assert (
|
|
gr.validators.is_video_correct_length(video_path, 1, 1000)["is_valid"] is True
|
|
)
|
|
assert gr.validators.is_video_correct_length(video_path, 1, 5)["is_valid"] is True
|
|
assert gr.validators.is_video_correct_length(video_path, 1, 2)["is_valid"] is False
|