Professional video processing pipeline with AI analysis, 360° processing, and adaptive streaming capabilities. ✨ Core Features: • AI-powered content analysis with scene detection and quality assessment • Next-generation codec support (AV1, HEVC, HDR10) • Adaptive streaming (HLS/DASH) with smart bitrate ladders • Complete 360° video processing with multiple projection support • Spatial audio processing (Ambisonic, binaural, object-based) • Viewport-adaptive streaming with up to 75% bandwidth savings • Professional testing framework with video-themed HTML dashboards 🏗️ Architecture: • Modern Python 3.11+ with full type hints • Pydantic-based configuration with validation • Async processing with Procrastinate task queue • Comprehensive test coverage with 11 detailed examples • Professional documentation structure 🚀 Production Ready: • MIT License for open source use • PyPI-ready package metadata • Docker support for scalable deployment • Quality assurance with ruff, mypy, and pytest • Comprehensive example library From simple encoding to immersive experiences - complete multimedia processing platform for modern applications.
178 lines
6.7 KiB
Python
178 lines
6.7 KiB
Python
"""Tests for 360° video functionality."""
|
|
|
|
import pytest
|
|
|
|
from video_processor import HAS_360_SUPPORT, ProcessorConfig
|
|
from video_processor.utils.video_360 import Video360Detection, Video360Utils
|
|
|
|
|
|
class TestVideo360Detection:
|
|
"""Tests for 360° video detection."""
|
|
|
|
def test_aspect_ratio_detection(self):
|
|
"""Test 360° detection based on aspect ratio."""
|
|
# Mock metadata for 2:1 aspect ratio (typical 360° video)
|
|
metadata = {
|
|
"video": {
|
|
"width": 3840,
|
|
"height": 1920,
|
|
},
|
|
"filename": "test_video.mp4",
|
|
}
|
|
|
|
result = Video360Detection.detect_360_video(metadata)
|
|
|
|
assert result["is_360_video"] is True
|
|
assert "aspect_ratio" in result["detection_methods"]
|
|
assert result["confidence"] >= 0.8
|
|
|
|
def test_filename_pattern_detection(self):
|
|
"""Test 360° detection based on filename patterns."""
|
|
metadata = {
|
|
"video": {"width": 1920, "height": 1080},
|
|
"filename": "my_360_video.mp4",
|
|
}
|
|
|
|
result = Video360Detection.detect_360_video(metadata)
|
|
|
|
assert result["is_360_video"] is True
|
|
assert "filename" in result["detection_methods"]
|
|
assert result["projection_type"] == "equirectangular"
|
|
|
|
def test_spherical_metadata_detection(self):
|
|
"""Test 360° detection based on spherical metadata."""
|
|
metadata = {
|
|
"video": {"width": 1920, "height": 1080},
|
|
"filename": "test.mp4",
|
|
"format": {"tags": {"Spherical": "1", "ProjectionType": "equirectangular"}},
|
|
}
|
|
|
|
result = Video360Detection.detect_360_video(metadata)
|
|
|
|
assert result["is_360_video"] is True
|
|
assert "spherical_metadata" in result["detection_methods"]
|
|
assert result["confidence"] == 1.0
|
|
assert result["projection_type"] == "equirectangular"
|
|
|
|
def test_no_360_detection(self):
|
|
"""Test that regular videos are not detected as 360°."""
|
|
metadata = {
|
|
"video": {"width": 1920, "height": 1080},
|
|
"filename": "regular_video.mp4",
|
|
}
|
|
|
|
result = Video360Detection.detect_360_video(metadata)
|
|
|
|
assert result["is_360_video"] is False
|
|
assert result["confidence"] == 0.0
|
|
assert len(result["detection_methods"]) == 0
|
|
|
|
|
|
class TestVideo360Utils:
|
|
"""Tests for 360° video utilities."""
|
|
|
|
def test_bitrate_multipliers(self):
|
|
"""Test bitrate multipliers for different projection types."""
|
|
assert (
|
|
Video360Utils.get_recommended_bitrate_multiplier("equirectangular") == 2.5
|
|
)
|
|
assert Video360Utils.get_recommended_bitrate_multiplier("cubemap") == 2.0
|
|
assert Video360Utils.get_recommended_bitrate_multiplier("unknown") == 2.0
|
|
|
|
def test_optimal_resolutions(self):
|
|
"""Test optimal resolution recommendations."""
|
|
equirect_resolutions = Video360Utils.get_optimal_resolutions("equirectangular")
|
|
assert (3840, 1920) in equirect_resolutions # 4K 360°
|
|
assert (1920, 960) in equirect_resolutions # 2K 360°
|
|
|
|
def test_missing_dependencies(self):
|
|
"""Test missing dependency detection."""
|
|
missing = Video360Utils.get_missing_dependencies()
|
|
assert isinstance(missing, list)
|
|
|
|
# Without optional dependencies, these should be missing
|
|
if not HAS_360_SUPPORT:
|
|
assert "opencv-python" in missing
|
|
assert "py360convert" in missing
|
|
|
|
|
|
class TestProcessorConfig360:
|
|
"""Tests for 360° configuration."""
|
|
|
|
def test_default_360_settings(self):
|
|
"""Test default 360° configuration values."""
|
|
config = ProcessorConfig()
|
|
|
|
assert config.enable_360_processing == HAS_360_SUPPORT
|
|
assert config.auto_detect_360 is True
|
|
assert config.force_360_projection is None
|
|
assert config.video_360_bitrate_multiplier == 2.5
|
|
assert config.generate_360_thumbnails is True
|
|
assert "front" in config.thumbnail_360_projections
|
|
assert "stereographic" in config.thumbnail_360_projections
|
|
|
|
def test_360_validation_without_dependencies(self):
|
|
"""Test that 360° processing can't be enabled without dependencies."""
|
|
if not HAS_360_SUPPORT:
|
|
with pytest.raises(
|
|
ValueError, match="360° processing requires optional dependencies"
|
|
):
|
|
ProcessorConfig(enable_360_processing=True)
|
|
|
|
@pytest.mark.skipif(not HAS_360_SUPPORT, reason="360° dependencies not available")
|
|
def test_360_validation_with_dependencies(self):
|
|
"""Test that 360° processing can be enabled with dependencies."""
|
|
config = ProcessorConfig(enable_360_processing=True)
|
|
assert config.enable_360_processing is True
|
|
|
|
def test_bitrate_multiplier_validation(self):
|
|
"""Test bitrate multiplier validation."""
|
|
# Valid range
|
|
config = ProcessorConfig(video_360_bitrate_multiplier=3.0)
|
|
assert config.video_360_bitrate_multiplier == 3.0
|
|
|
|
# Invalid range should raise validation error
|
|
with pytest.raises(ValueError):
|
|
ProcessorConfig(video_360_bitrate_multiplier=0.5) # Below minimum
|
|
|
|
with pytest.raises(ValueError):
|
|
ProcessorConfig(video_360_bitrate_multiplier=6.0) # Above maximum
|
|
|
|
def test_custom_360_settings(self):
|
|
"""Test custom 360° configuration."""
|
|
config = ProcessorConfig(
|
|
auto_detect_360=False,
|
|
video_360_bitrate_multiplier=2.0,
|
|
generate_360_thumbnails=False,
|
|
thumbnail_360_projections=["front", "back"],
|
|
)
|
|
|
|
assert config.auto_detect_360 is False
|
|
assert config.video_360_bitrate_multiplier == 2.0
|
|
assert config.generate_360_thumbnails is False
|
|
assert config.thumbnail_360_projections == ["front", "back"]
|
|
|
|
|
|
# Integration test for basic video processor
|
|
class TestVideoProcessor360Integration:
|
|
"""Integration tests for 360° video processing."""
|
|
|
|
def test_processor_creation_without_360_support(self):
|
|
"""Test that video processor works without 360° support."""
|
|
from video_processor import VideoProcessor
|
|
|
|
config = ProcessorConfig() # 360° disabled by default when deps missing
|
|
processor = VideoProcessor(config)
|
|
|
|
assert processor.thumbnail_360_generator is None
|
|
|
|
@pytest.mark.skipif(not HAS_360_SUPPORT, reason="360° dependencies not available")
|
|
def test_processor_creation_with_360_support(self):
|
|
"""Test that video processor works with 360° support."""
|
|
from video_processor import VideoProcessor
|
|
|
|
config = ProcessorConfig(enable_360_processing=True)
|
|
processor = VideoProcessor(config)
|
|
|
|
assert processor.thumbnail_360_generator is not None
|