video-processor/tests/test_video_360.py
Ryan Malloy bcd37ba55f Implement comprehensive 360° video processing system (Phase 4)
This milestone completes the video processor with full 360° video support:

## New Features
- Complete 360° video analysis and processing pipeline
- Multi-projection support (equirectangular, cubemap, EAC, stereographic, fisheye)
- Viewport extraction and animated viewport tracking
- Spatial audio processing (ambisonic, binaural, object-based)
- 360° adaptive streaming with tiled encoding
- AI-enhanced 360° content analysis integration
- Comprehensive test infrastructure with synthetic video generation

## Core Components
- Video360Processor: Complete 360° analysis and processing
- ProjectionConverter: Batch conversion between projections
- SpatialAudioProcessor: Advanced spatial audio handling
- Video360StreamProcessor: Viewport-adaptive streaming
- Comprehensive data models and validation

## Test Infrastructure
- 360° video downloader with curated test sources
- Synthetic 360° video generator for CI/CD
- Integration tests covering full processing pipeline
- Performance benchmarks for parallel processing

## Documentation & Examples
- Complete 360° processing examples and workflows
- Comprehensive development summary documentation
- Integration guides for all four processing phases

This completes the roadmap: AI analysis, advanced codecs, streaming, and 360° video processing.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-06 08:42:44 -06:00

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