Video Converter - Software Requirements Specification (SRS)¶
Document Version: 1.0.2 Date: 2025-12-24 Status: Active Reference Document: PRD v1.1.0
Document Information¶
Traceability Information¶
| Item | Reference |
|---|---|
| Parent Document | PRD.md v1.1.0 |
| Related Documents | SDS.md, development-plan.md, architecture/*.md |
| Requirements ID Scheme | SRS-xxx (this document), FR-xxx/NFR-xxx (PRD) |
Change History¶
| Version | Date | Author | Changes |
|---|---|---|---|
| 1.0.0 | 2025-12-21 | - | Initial creation |
| 1.0.1 | 2025-12-23 | - | Updated document status and references to align with PRD v1.1.0 |
| 1.0.2 | 2025-12-24 | - | Updated class names and method signatures to match implementation (MetadataProcessor, VideoValidator, CompressionValidator, ServiceManager, LaunchdPlistGenerator, PhotosVideoFilter) |
Table of Contents¶
- Overview
- System Overview
- Functional Requirements Details
- Non-Functional Requirements Details
- External Interface Requirements
- Data Requirements
- System Constraints
- Requirements Traceability Matrix
- Verification and Validation
- Appendix
1. Overview¶
1.1 Purpose¶
This document specifies the software requirements for the Video Converter system in detail. It provides technical specifications derived from the PRD (Product Requirements Document) at a level sufficient for the development team to implement.
1.2 Scope¶
| Item | Content |
|---|---|
| System Name | Video Converter |
| Version | 0.2.0.0+ |
| Target Platform | macOS 12.0+ (Apple Silicon) |
| Development Language | Python 3.10+ |
Note: This project uses 0.x.x.x versioning to indicate active development status.
1.3 Definitions and Abbreviations¶
| Abbreviation | Definition |
|---|---|
| SRS | Software Requirements Specification |
| PRD | Product Requirements Document |
| FR | Functional Requirement |
| NFR | Non-Functional Requirement |
| US | User Story |
| RTM | Requirements Traceability Matrix |
| HEVC | High Efficiency Video Coding (H.265) |
| AVC | Advanced Video Coding (H.264) |
1.4 Reference Documents¶
- PRD.md - Product Requirements Document
- SDS.md - Software Design Specification (Design implementation of this document)
- development-plan.md - Development Plan
- 01-system-architecture.md - System Architecture
- 02-sequence-diagrams.md - Sequence Diagrams
- 03-data-flow-and-states.md - Data Flow and States
- 04-processing-procedures.md - Processing Procedures
2. System Overview¶
2.1 System Context¶
┌─────────────────────────────────────────────────────────────────────────┐
│ System Context │
└─────────────────────────────────────────────────────────────────────────┘
┌─────────────┐
│ User │
│ (macOS) │
└──────┬──────┘
│ CLI / Notifications
▼
┌──────────────┐ ┌─────────────────┐ ┌──────────────┐
│ Photos │───read────▶│ Video Converter │───write───▶│ File System │
│ Library │ │ System │ │ (Output) │
└──────────────┘ └────────┬────────┘ └──────────────┘
│
┌────────────────┼────────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ FFmpeg │ │ ExifTool │ │ launchd │
│ (Convert)│ │ (Meta) │ │ (Auto) │
└──────────┘ └──────────┘ └──────────┘
2.2 System Functions Overview¶
| Function Area | Description | PRD Reference |
|---|---|---|
| Codec Detection | Auto-detect H.264/H.265 codec | FR-001 |
| Video Conversion | H.264 → H.265 encoding | FR-002, FR-003 |
| Photos Integration | Scan and extract from Photos library | FR-101 ~ FR-105 |
| Metadata Processing | Preserve GPS, dates, etc. | FR-201 ~ FR-204 |
| Quality Management | Verify conversion results | FR-301 ~ FR-304 |
| Automation | Schedule and folder watch execution | FR-401 ~ FR-404 |
| CLI | Command-line interface | FR-501 ~ FR-505 |
| Safety Management | Original preservation and error recovery | FR-601 ~ FR-604 |
2.3 User Classification¶
| User Type | Description | PRD Reference |
|---|---|---|
| General User | Basic CLI functions, relies on automation | Persona: Minsu |
| Advanced User | Detailed CLI options, quality customization | Persona: Jiyeon |
| Developer/Admin | Script integration, log analysis, service management | Persona: Sungho |
3. Functional Requirements Details¶
3.1 Codec Detection Module (SRS-100)¶
SRS-101: Video Codec Detection¶
| Item | Content |
|---|---|
| ID | SRS-101 |
| Name | Video Codec Detection |
| PRD Trace | FR-001, US-201 |
| Priority | P0 (Required) |
Description: The system shall detect the video stream codec of input video files.
Preconditions: - Valid video file path provided - FFprobe installed on system
Input:
Input: video_path: Path
- Absolute path to video file
- Supported extensions: .mp4, .mov, .m4v, .MP4, .MOV, .M4V
Processing Logic:
def detect_codec(video_path: Path) -> CodecInfo:
"""
Extract video codec info using FFprobe
Algorithm:
1. Construct FFprobe command
- Select video stream only (-select_streams v:0)
- Extract codec name (-show_entries stream=codec_name)
2. Execute FFprobe as subprocess
3. Parse and normalize output (lowercase)
4. Return CodecInfo object
"""
FFprobe Command:
ffprobe -v error \
-select_streams v:0 \
-show_entries stream=codec_name \
-of default=noprint_wrappers=1:nokey=1 \
"<video_path>"
Output:
Output: CodecInfo
- codec_name: str # "h264", "hevc", "av1", etc.
- is_h264: bool # Is H.264
- is_hevc: bool # Is H.265/HEVC
Codec Mapping Table: | FFprobe Output | Normalized Value | is_h264 | is_hevc | |----------------|------------------|---------|---------| | h264 | h264 | True | False | | avc | h264 | True | False | | avc1 | h264 | True | False | | hevc | hevc | False | True | | h265 | hevc | False | True | | hvc1 | hevc | False | True | | hev1 | hevc | False | True |
Exception Handling: | Exception | Handling | Error Code | |-----------|----------|------------| | File not found | Raise FileNotFoundError | E-101 | | FFprobe execution failed | Raise FFprobeError | E-102 | | No video stream | Raise NoVideoStreamError | E-103 | | Unknown codec | Raise UnknownCodecError | E-104 |
Performance Requirements: - Single file detection time: ≤500ms - Memory usage: ≤10MB
3.2 Video Conversion Module (SRS-200)¶
SRS-201: Hardware Accelerated Conversion (VideoToolbox)¶
| Item | Content |
|---|---|
| ID | SRS-201 |
| Name | Hardware Accelerated H.265 Conversion |
| PRD Trace | FR-002, US-203, US-204 |
| Priority | P0 (Required) |
Description: Convert H.264 video to H.265 using Apple Silicon's VideoToolbox for hardware acceleration.
Preconditions: - Input file is H.264 codec (verified by SRS-101) - Apple Silicon Mac (M1/M2/M3/M4) - FFmpeg 5.0+ (hevc_videotoolbox support)
Input:
Input: ConversionRequest
- input_path: Path # Input video path
- output_path: Path # Output video path
- quality: int # Quality setting (1-100, default 45)
- audio_mode: str # "copy" | "transcode" (default "copy")
Quality Setting Mapping: | Preset | quality Value | Expected Compression | Use Case | |--------|---------------|---------------------|----------| | High Quality | 30-40 | 35-45% | Archiving | | Balanced (default) | 45-55 | 45-55% | General use | | Fast | 60-70 | 55-65% | Bulk conversion |
FFmpeg Command Generation:
def build_hardware_command(request: ConversionRequest) -> List[str]:
"""
Generate FFmpeg command for hardware encoding
"""
return [
"ffmpeg",
"-y", # Allow overwrite
"-i", str(request.input_path), # Input file
"-c:v", "hevc_videotoolbox", # VideoToolbox encoder
"-q:v", str(request.quality), # Quality setting
"-tag:v", "hvc1", # QuickTime compatible tag
"-c:a", request.audio_mode, # Audio handling
"-map_metadata", "0", # Metadata copy
"-movflags", "use_metadata_tags",
"-progress", "pipe:1", # Progress output
str(request.output_path)
]
Progress Monitoring:
class ProgressMonitor:
"""
FFmpeg progress parsing and callback handling
FFmpeg progress output format:
- out_time_ms=12500000
- frame=375
- fps=45.2
- speed=3.5x
"""
def parse_progress(self, line: str) -> Optional[ProgressInfo]:
"""
Parse progress line
Returns:
ProgressInfo: Progress information
- current_time_ms: int # Current processed time (ms)
- frame: int # Processed frame count
- fps: float # Current processing speed
- speed: float # Speed relative to realtime
"""
Output:
Output: ConversionResult
- success: bool # Success flag
- input_path: Path # Input path
- output_path: Path # Output path
- original_size: int # Original size (bytes)
- converted_size: int # Converted size (bytes)
- compression_ratio: float # Compression ratio (0.0-1.0)
- duration_seconds: float # Conversion duration
- speed_ratio: float # Speed relative to realtime
- error_message: str # Error message if failed
Exception Handling: | Exception | Retry | Handling | Error Code | |-----------|-------|----------|------------| | FFmpeg execution failed | 3x | Exponential backoff retry | E-201 | | Disk space insufficient | 0x | Fail immediately, notify user | E-202 | | Input file corrupted | 0x | Move to failed folder | E-203 | | Output file creation failed | 1x | Retry with temp directory | E-204 | | Encoder initialization failed | 1x | Fallback to software encoder | E-205 |
Retry Logic:
async def convert_with_retry(
request: ConversionRequest,
max_retries: int = 3
) -> ConversionResult:
"""
Retry logic with exponential backoff
Retry delays: 5s, 10s, 20s
"""
for attempt in range(max_retries):
try:
result = await self._convert(request)
if result.success:
return result
except RetryableError as e:
if attempt < max_retries - 1:
delay = 5 * (2 ** attempt) # 5, 10, 20 seconds
await asyncio.sleep(delay)
else:
raise MaxRetriesExceededError(e)
SRS-202: Software Conversion (libx265)¶
| Item | Content |
|---|---|
| ID | SRS-202 |
| Name | Software H.265 Conversion |
| PRD Trace | FR-003, US-203 |
| Priority | P1 (Important) |
Description: High-quality software encoding using libx265. Slower than hardware encoding but provides smaller file sizes and higher quality.
FFmpeg Command Generation:
def build_software_command(request: ConversionRequest) -> List[str]:
"""
Generate FFmpeg command for software encoding
"""
return [
"ffmpeg",
"-y",
"-i", str(request.input_path),
"-c:v", "libx265", # Software encoder
"-crf", str(request.crf), # CRF quality setting
"-preset", request.preset, # Encoding preset
"-c:a", request.audio_mode,
"-map_metadata", "0",
"-progress", "pipe:1",
str(request.output_path)
]
CRF Setting Guide: | Use Case | CRF Value | Preset | Expected Compression | Expected VMAF | |----------|-----------|--------|---------------------|---------------| | Archiving | 18-20 | slow | 30-40% | 97+ | | High Quality | 20-22 | slow | 40-50% | 95+ | | Balanced | 22-24 | medium | 45-55% | 93+ | | Size Priority | 24-28 | fast | 55-65% | 90+ |
3.3 Photos Integration Module (SRS-300)¶
SRS-301: Photos Library Scan¶
| Item | Content |
|---|---|
| ID | SRS-301 |
| Name | Photos Library Scan |
| PRD Trace | FR-101, FR-102, US-201, US-205 |
| Priority | P0 (Required) |
Description: Query the macOS Photos library video list using osxphotos and filter only H.264 codec videos.
Preconditions: - osxphotos 0.70+ installed - Photos library access permission (Full Disk Access)
Interface:
class PhotosLibrary:
"""Low-level Photos library access via osxphotos"""
def __init__(self, library_path: Optional[Path] = None):
"""
Parameters:
library_path: Photos library path
None uses default path
Default: ~/Pictures/Photos Library.photoslibrary
"""
def get_all_videos(self) -> List[PhotosVideoInfo]:
"""Get all videos from Photos library"""
class PhotosVideoFilter:
"""Filter Photos library videos for conversion candidates"""
def __init__(
self,
library: PhotosLibrary,
include_albums: Optional[List[str]] = None,
exclude_albums: Optional[List[str]] = None
):
"""
Parameters:
library: PhotosLibrary instance
include_albums: Specific albums to include (None for all)
exclude_albums: Albums to exclude (default: Screenshots, Bursts, Slo-mo)
"""
def get_conversion_candidates(
self,
from_date: Optional[datetime] = None,
to_date: Optional[datetime] = None,
limit: Optional[int] = None
) -> List[PhotosVideoInfo]:
"""
Get H.264 videos that need conversion
Parameters:
from_date: Only videos created after this date
to_date: Only videos created before this date
limit: Maximum number of videos to return
Returns:
List of PhotosVideoInfo objects (H.264 codec only)
"""
def get_stats(self) -> LibraryStats:
"""Get library statistics with codec distribution"""
class VideoExporter:
"""Export videos from Photos library to temporary directory"""
def export(
self,
video: PhotosVideoInfo,
on_progress: Optional[Callable[[float], None]] = None
) -> Path:
"""
Export video file with progress tracking
Parameters:
video: Video info to export
on_progress: Progress callback (0.0-1.0)
Returns:
Exported file path in temp directory
"""
Note: The Photos integration is split into three specialized classes: -
PhotosLibrary: Low-level library access and video enumeration -PhotosVideoFilter: H.264 video filtering with album and date constraints -VideoExporter: Temporary file export with progress tracking
VideoInfo Data Structure:
@dataclass
class VideoInfo:
"""Video information data class"""
uuid: str # Photos internal UUID
original_filename: str # Original filename
path: Optional[Path] # Local file path (None if iCloud)
codec: str # Video codec
duration: float # Duration (seconds)
size: int # File size (bytes)
width: int # Horizontal resolution
height: int # Vertical resolution
fps: float # Frame rate
creation_date: datetime # Capture date
location: Optional[Tuple[float, float]] # (latitude, longitude)
albums: List[str] # Album membership
is_in_icloud: bool # iCloud only flag
is_favorite: bool # Favorite flag
3.4 Metadata Processing Module (SRS-400)¶
SRS-401: Metadata Extraction¶
| Item | Content |
|---|---|
| ID | SRS-401 |
| Name | Metadata Extraction |
| PRD Trace | FR-201, US-301, US-302 |
| Priority | P0 (Required) |
Description: Extract all metadata from the original video using ExifTool.
Interface:
class MetadataProcessor:
"""Metadata extraction and restoration management"""
def extract(self, video_path: Path) -> Metadata:
"""
Extract metadata from video
ExifTool command: exiftool -json <path>
Returns:
Metadata object
"""
def apply(
self,
source_path: Path,
target_path: Path,
tags: Optional[List[str]] = None
) -> None:
"""
Copy metadata from source to target
ExifTool command:
exiftool -overwrite_original -tagsFromFile <source> -all:all <target>
Parameters:
source_path: Original video path
target_path: Target video path
tags: Specific tags only (None for all)
"""
def apply_gps(
self,
source_path: Path,
target_path: Path
) -> None:
"""
Explicit GPS coordinate copy
ExifTool command:
exiftool -overwrite_original -tagsFromFile <source> "-GPS*" <target>
"""
def sync_timestamps(
self,
source_path: Path,
target_path: Path
) -> None:
"""
Synchronize file system timestamps
Uses os.utime()
"""
GPS Tag Mapping: | ExifTool Tag | Description | Priority | |--------------|-------------|----------| | QuickTime:GPSCoordinates | QuickTime container GPS | 1 | | Keys:GPSCoordinates | Apple Keys GPS | 2 | | XMP:GPSLatitude | XMP GPS latitude | 3 | | XMP:GPSLongitude | XMP GPS longitude | 3 | | Composite:GPSLatitude | Calculated GPS latitude | 4 | | Composite:GPSLongitude | Calculated GPS longitude | 4 |
3.5 Quality Management Module (SRS-500)¶
SRS-501: Conversion Result Verification¶
| Item | Content |
|---|---|
| ID | SRS-501 |
| Name | Conversion Result Verification |
| PRD Trace | FR-301, FR-302, FR-303, US-503 |
| Priority | P0 (Required) |
Description: Verify the integrity and quality of converted video files.
Interface:
class VideoValidator:
"""Video file integrity and property validation"""
def validate(
self,
video_path: Path,
strictness: ValidationStrictness = ValidationStrictness.STANDARD
) -> ValidationResult:
"""
Validate video file integrity and properties
Validation steps:
1. File integrity check (FFprobe)
2. Video stream presence verification
3. Codec and container format detection
4. Duration and bitrate validation
"""
class CompressionValidator:
"""Conversion compression ratio validation"""
def validate(
self,
original_size: int,
converted_size: int,
content_type: ContentType = ContentType.UNKNOWN
) -> CompressionValidationResult:
"""
Validate compression ratio is within expected range
Validation steps:
1. Calculate compression ratio
2. Determine expected range based on content type
3. Check if ratio is within normal, warning, or error range
4. Generate appropriate severity and recommendations
"""
Note: The validation functionality is split into two specialized classes: -
VideoValidator: Handles file integrity and video property validation -CompressionValidator: Handles compression ratio analysis and content-aware validation
Validation Steps Detail:
Step 1: File Integrity Check
def check_integrity(self, path: Path) -> IntegrityResult:
"""
File integrity check with FFprobe
Command: ffprobe -v error -show_format -show_streams <path>
Checks:
- File exists and size > 0
- Video stream exists
- Codec info extractable
- Duration > 0
"""
Step 2: Property Comparison
def compare_properties(
self,
original: VideoProperties,
converted: VideoProperties
) -> PropertyComparisonResult:
"""
Video property comparison
Comparison items and tolerances:
- Resolution: Exact match
- Frame rate: ±0.1 fps
- Duration: ±1.0 second
- Audio channels: Exact match
"""
Step 3: Compression Ratio Check
def check_compression_ratio(
self,
original_size: int,
converted_size: int
) -> CompressionResult:
"""
Compression ratio normal range verification
Normal range: 20% ~ 80%
Warning range: 15-20% or 80-90%
Error range: <15% or >90%
Abnormal case analysis:
- Too small: Possible quality loss
- Too large: Conversion failure or inefficient encoding
"""
3.6 Automation Module (SRS-600)¶
SRS-601: Schedule-Based Execution¶
| Item | Content |
|---|---|
| ID | SRS-601 |
| Name | Schedule-Based Auto Execution |
| PRD Trace | FR-401, US-401 |
| Priority | P0 (Required) |
Description: Use launchd's StartCalendarInterval to automatically run conversion at specified times.
plist Template:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.user.videoconverter</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/python3</string>
<string>${INSTALL_DIR}/main.py</string>
<string>run</string>
<string>--mode</string>
<string>photos</string>
</array>
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>${SCHEDULE_HOUR}</integer>
<key>Minute</key>
<integer>${SCHEDULE_MINUTE}</integer>
</dict>
<key>StandardOutPath</key>
<string>${LOG_DIR}/stdout.log</string>
<key>StandardErrorPath</key>
<string>${LOG_DIR}/stderr.log</string>
<key>ThrottleInterval</key>
<integer>30</integer>
</dict>
</plist>
Service Management Interface:
class ServiceManager:
"""launchd service lifecycle management"""
PLIST_DIR = Path.home() / "Library/LaunchAgents"
LABEL = "com.user.videoconverter"
def install(self, config: AutomationConfig) -> ServiceResult:
"""
Install service
1. Generate plist file using LaunchdPlistGenerator
2. Copy to LaunchAgents directory
3. Execute launchctl load
"""
def uninstall(self) -> ServiceResult:
"""
Remove service
1. Execute launchctl unload
2. Delete plist file
"""
def start(self) -> ServiceResult:
"""Manual service start: launchctl start <label>"""
def stop(self) -> ServiceResult:
"""Stop service: launchctl stop <label>"""
def status(self) -> DetailedServiceStatus:
"""Query service status: launchctl list | grep <label>"""
class LaunchdPlistGenerator:
"""launchd plist file generation"""
def generate(self, config: LaunchdConfig) -> str:
"""
Generate plist XML content
Creates properly formatted launchd plist with:
- Label and program arguments
- Schedule configuration (StartCalendarInterval)
- Standard output/error paths
- ThrottleInterval and other settings
"""
Note: The automation functionality is split into two specialized classes: -
ServiceManager: Handles service lifecycle (install, uninstall, start, stop, status) -LaunchdPlistGenerator: Handles plist file generation from configuration
3.7 CLI Module (SRS-700)¶
SRS-701: CLI Command Structure¶
| Item | Content |
|---|---|
| ID | SRS-701 |
| Name | CLI Command Structure |
| PRD Trace | FR-501 ~ FR-505 |
| Priority | P0 (Required) |
Description: Access all system functions through command-line interface.
Command Structure:
video-converter <command> [options] [arguments]
Commands:
convert Single file conversion
run Batch conversion execution
scan Scan conversion targets (without converting)
status Service status check
stats Conversion statistics query
config Configuration management
install Service installation
uninstall Service removal
version Version information
Global Options:
-c, --config PATH Config file path
-v, --verbose Detailed log output
-q, --quiet Minimal output mode
--log-file PATH Log file path
-h, --help Show help
Command Details:
convert command:
video-converter convert <input> <output> [options]
Arguments:
input Input video file path
output Output video file path
Options:
-m, --mode MODE Encoding mode (hardware|software) [default: hardware]
-q, --quality INT Quality setting (hardware: 1-100, software: CRF 0-51)
--preset PRESET Encoding preset (fast|medium|slow)
--no-metadata Don't copy metadata
--validate Validate quality after conversion
Examples:
video-converter convert input.mp4 output.mp4
video-converter convert input.mp4 output.mp4 -m hardware -q 45
video-converter convert input.mp4 output.mp4 -m software --preset slow
run command:
video-converter run [options]
Options:
--mode MODE Source mode (photos|folder) [default: photos]
--folder PATH Target folder for folder mode
--since DATE Only videos after this date (YYYY-MM-DD)
--album ALBUM Specific albums only (can be specified multiple times)
--dry-run Simulate without actual conversion
--limit N Process maximum N items
Examples:
video-converter run
video-converter run --mode photos --since 2024-01-01
video-converter run --mode folder --folder ~/Videos/ToConvert
video-converter run --dry-run --limit 5
3.8 Safety Management Module (SRS-800)¶
SRS-801: Original Preservation¶
| Item | Content |
|---|---|
| ID | SRS-801 |
| Name | Original File Preservation |
| PRD Trace | FR-601, US-501, US-502 |
| Priority | P0 (Required) |
Description: On successful conversion, preserve original files by moving to a separate folder instead of deleting.
Directory Structure:
~/Videos/VideoConverter/
├── input/ # Conversion queue (folder mode)
├── output/ # Conversion results
├── processed/ # Successful originals (organized by date)
│ ├── 2024-12/
│ └── 2025-01/
├── failed/ # Failed originals
└── logs/ # Log files
4. Non-Functional Requirements Details¶
4.1 Performance Requirements (SRS-NFR-100)¶
| ID | Requirement | Target | Measurement | PRD Trace |
|---|---|---|---|---|
| SRS-NFR-101 | 4K 30min video HW conversion | ≤5min | Benchmark | NFR-P01 |
| SRS-NFR-102 | 1080p 10min video HW conversion | ≤30sec | Benchmark | NFR-P02 |
| SRS-NFR-103 | CPU usage (HW mode) | ≤30% | Activity Monitor | NFR-P03 |
| SRS-NFR-104 | Memory usage | ≤1GB | Activity Monitor | NFR-P04 |
| SRS-NFR-105 | Codec detection time | ≤500ms | Unit test | - |
| SRS-NFR-106 | Photos scan (1000 items) | ≤30sec | Benchmark | - |
4.2 Reliability Requirements (SRS-NFR-200)¶
| ID | Requirement | Target | Measurement | PRD Trace |
|---|---|---|---|---|
| SRS-NFR-201 | Conversion success rate | ≥99% | Batch test | NFR-R01 |
| SRS-NFR-202 | Metadata preservation rate | 100% | Auto verify | NFR-R02 |
| SRS-NFR-203 | Service uptime | ≥99.9% | Log analysis | NFR-R03 |
| SRS-NFR-204 | Error recovery success rate | ≥95% | Retry logs | NFR-R04 |
4.3 Compatibility Requirements (SRS-NFR-400)¶
| ID | Requirement | Target | Notes | PRD Trace |
|---|---|---|---|---|
| SRS-NFR-401 | macOS version | 12.0+ | Monterey or later | NFR-C01 |
| SRS-NFR-402 | Python version | 3.10+ | osxphotos requirement | NFR-C02 |
| SRS-NFR-403 | FFmpeg version | 5.0+ | hevc_videotoolbox | NFR-C03 |
| SRS-NFR-404 | ExifTool version | 12.0+ | GPS tag support | - |
| SRS-NFR-405 | osxphotos version | 0.70+ | Photos 16 support | - |
| SRS-NFR-406 | Video formats | .mp4/.mov/.m4v | H.264 codec | NFR-C04 |
4.4 Security Requirements (SRS-NFR-500)¶
| ID | Requirement | Implementation | PRD Trace |
|---|---|---|---|
| SRS-NFR-501 | Photos minimum privilege | Read-only access | NFR-S01 |
| SRS-NFR-502 | Temp file security | Delete immediately after use | NFR-S02 |
| SRS-NFR-503 | Config file security | 0600 permission | NFR-S03 |
| SRS-NFR-504 | Log privacy | Filename only, path hashed | - |
| SRS-NFR-505 | No external communication | Local processing only | - |
5. External Interface Requirements¶
5.1 User Interface¶
SRS-UI-001: CLI Interface¶
Output Format:
Progress Display:
Result Summary:
╭─────────────────────────────────────────────╮
│ Conversion Report │
├─────────────────────────────────────────────┤
│ Videos processed: 15 │
│ Success: 14 │
│ Failed: 1 │
│ Skipped: 3 (already HEVC) │
├─────────────────────────────────────────────┤
│ Original size: 35.2 GB │
│ Converted size: 15.8 GB │
│ Space saved: 19.4 GB (55%) │
╰─────────────────────────────────────────────╯
6. Data Requirements¶
6.1 Data Model¶
6.1.1 Configuration Data¶
config.json Schema (abbreviated):
{
"version": "0.1.0.0",
"encoding": {
"mode": "hardware",
"quality": 45,
"crf": 22,
"preset": "slow"
},
"paths": {
"output": "~/Videos/Converted",
"processed": "~/Videos/Processed",
"failed": "~/Videos/Failed"
},
"automation": {
"enabled": true,
"schedule_hour": 3,
"schedule_minute": 0
}
}
6.1.2 Conversion History Data¶
SQLite Schema:
CREATE TABLE conversion_history (
id INTEGER PRIMARY KEY AUTOINCREMENT,
video_uuid TEXT NOT NULL,
original_filename TEXT NOT NULL,
original_path TEXT NOT NULL,
output_path TEXT NOT NULL,
original_size INTEGER NOT NULL,
converted_size INTEGER NOT NULL,
compression_ratio REAL NOT NULL,
conversion_mode TEXT NOT NULL,
quality_setting INTEGER,
vmaf_score REAL,
started_at TIMESTAMP NOT NULL,
completed_at TIMESTAMP NOT NULL,
duration_seconds REAL NOT NULL,
status TEXT NOT NULL,
error_message TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_video_uuid ON conversion_history(video_uuid);
CREATE INDEX idx_status ON conversion_history(status);
6.2 Data Storage¶
| Data Type | Location | Format |
|---|---|---|
| User config | ~/.config/video_converter/config.json | JSON |
| Conversion history | ~/.config/video_converter/history.db | SQLite |
| Execution logs | ~/Library/Logs/video_converter/ | Text |
| Temp files | /tmp/video_converter/ | Binary |
7. System Constraints¶
7.1 Technical Constraints¶
| Constraint | Impact | Mitigation |
|---|---|---|
| Cannot directly modify Photos library | Converted files stored separately | Clearly guide output folder |
| VideoToolbox quality limits | Slightly larger files than SW | Provide quality presets |
| iCloud sync delays | Some videos not processable | Retry logic, wait option |
| launchd ThrottleInterval | Minimum 30 second interval | Batch processing for efficiency |
7.2 Operational Constraints¶
| Constraint | Impact | Mitigation |
|---|---|---|
| Power required (laptop) | Battery drain | Check power state |
| 2x storage needed | Space shortage during conversion | Pre-check space |
| Mac must be powered on | Schedule may be missed | Process on next run |
8. Requirements Traceability Matrix (RTM)¶
8.1 PRD → SRS Tracing¶
| PRD ID | PRD Name | SRS ID | SRS Name | Status |
|---|---|---|---|---|
| US-201 | Auto-find H.264 | SRS-101, SRS-301 | Codec detection, Photos scan | Mapped |
| US-203 | Progress check | SRS-201 | Progress monitoring | Mapped |
| US-301 | Date preservation | SRS-401, SRS-402 | Metadata processing | Mapped |
| US-302 | GPS preservation | SRS-401 | GPS special handling | Mapped |
| US-401 | Schedule execution | SRS-601 | launchd schedule | Mapped |
| FR-001 | H.264 detection | SRS-101 | Codec detection | Mapped |
| FR-002 | H.265 HW conversion | SRS-201 | Hardware conversion | Mapped |
| FR-003 | H.265 SW conversion | SRS-202 | Software conversion | Mapped |
| FR-101 | Photos scan | SRS-301 | Photos scan | Mapped |
| FR-201 | Metadata extraction | SRS-401 | Metadata extraction | Mapped |
| NFR-P01 | 4K conversion time | SRS-NFR-101 | ≤5min | Mapped |
| NFR-R01 | Conversion success rate | SRS-NFR-201 | ≥99% | Mapped |
9. Verification and Validation¶
9.1 Verification Methods¶
| Requirement Type | Verification Method | Tool |
|---|---|---|
| Functional requirements | Unit/Integration tests | pytest |
| Performance requirements | Benchmark tests | custom scripts |
| Reliability requirements | Long-run tests | CI/CD |
| Usability requirements | User testing | Survey/observation |
9.2 Acceptance Criteria¶
| ID | Criterion | Verification |
|---|---|---|
| AC-001 | H.264 codec correctly detected | 10 samples 100% accurate |
| AC-002 | Converted file is HEVC codec | FFprobe verification |
| AC-003 | GPS coordinates match to 6 decimal places | ExifTool comparison |
| AC-004 | Date matches within 1 second | ExifTool comparison |
| AC-005 | Duration difference within 1 second | FFprobe comparison |
10. Appendix¶
10.1 Glossary¶
| Term | Definition |
|---|---|
| H.264/AVC | Advanced Video Coding, video codec standardized in 2003 |
| H.265/HEVC | High Efficiency Video Coding, 50% improvement over H.264 |
| VideoToolbox | Apple hardware video encoding/decoding framework |
| CRF | Constant Rate Factor, quality-based encoding setting |
| VMAF | Video Multimethod Assessment Fusion, quality metric |
| launchd | macOS service management framework |
| osxphotos | Python Photos library access tool |
| ExifTool | Metadata read/write tool |
| FFmpeg | Multimedia processing framework |
| FFprobe | FFmpeg media analysis tool |
10.2 Error Code Definitions¶
| Code | Description | Retry | User Message |
|---|---|---|---|
| E-101 | File not found | No | File not found |
| E-102 | FFprobe execution failed | Yes | Media analysis failed |
| E-103 | No video stream | No | File has no video |
| E-201 | FFmpeg execution failed | Yes | Conversion error |
| E-202 | Disk space insufficient | No | Not enough storage |
| E-203 | Input file corrupted | No | File is corrupted |
| E-301 | Photos access denied | No | Photos permission required |
| E-401 | Metadata extraction failed | Yes | Metadata read failed |
10.3 Reference Documents¶
- PRD.md - Product Requirements Document
- development-plan.md - Development Plan
- 01-system-architecture.md - System Architecture
- 02-sequence-diagrams.md - Sequence Diagrams
- 03-data-flow-and-states.md - Data Flow and States
- 04-processing-procedures.md - Processing Procedures
Approval¶
| Role | Name | Signature | Date |
|---|---|---|---|
| Tech Lead | |||
| Architect | |||
| QA Lead |
This document is updated as development progresses.