Plugins: - misc_fixes v2.8: Pre-processing, container remux, stream conforming - stream_organizer v4.8: English priority, subtitle extraction, SRT conversion - combined_audio_standardizer v1.13: AAC/Opus encoding, downmix creation - av1_svt_converter v2.22: AV1 video encoding via SVT-AV1 Structure: - Local/ - Plugin .js files (mount in Tdarr) - agent_notes/ - Development documentation - Latest-Reports/ - Error logs for analysis
140 lines
4.7 KiB
Markdown
140 lines
4.7 KiB
Markdown
# SVT-AV1 Plugin Bitrate Feature Analysis
|
|
|
|
## Current State
|
|
|
|
### Existing Bitrate Control
|
|
|
|
The plugin currently implements bitrate control via the `maxrate_cap` dropdown input:
|
|
|
|
- **Type**: Dropdown with 11 preset values
|
|
- **Options**: `0` (unlimited), `2000`, `3000`, `4000`, `5000`, `6000`, `8000`, `10000`, `12000`, `15000`, `20000` kbps
|
|
- **Default**: `0*` (unlimited)
|
|
- **Implementation**: Lines 531-540 in the plugin
|
|
- **Behavior**: When set to non-zero, applies `-maxrate` and `-bufsize` (2x maxrate) to FFmpeg command
|
|
|
|
### Current Logic Flow
|
|
|
|
```mermaid
|
|
graph TD
|
|
A[Start] --> B{maxrate_cap != 0?}
|
|
B -->|Yes| C[Apply maxrate + bufsize<br/>Buffer = 2.0x maxrate]
|
|
B -->|No| D[Uncapped CRF<br/>No bitrate limit]
|
|
C --> E[Build FFmpeg Command]
|
|
D --> E
|
|
```
|
|
|
|
## Requirements from Agent Notes
|
|
|
|
From [implementation_plan.md](file:///home/user/Public/Projects/tdarr_plugs/Local/agent_notes/implementation_plan.md):
|
|
|
|
1. **Custom Maxrate**: Allow users to manually type a specific kbps value (not limited to dropdown presets)
|
|
2. **Source-Relative Bitrate**: Allow setting bitrate cap relative to source file bitrate
|
|
- Options: `match_source`, `75%_source`, `50%_source`, `33%_source`, `25%_source`
|
|
3. **Logic Precedence**:
|
|
- If strategy ≠ static → Calculate from source
|
|
- Else if custom_maxrate > 0 → Use custom value
|
|
- Else → Use maxrate_cap dropdown
|
|
|
|
## Design Decisions
|
|
|
|
### Input Design
|
|
|
|
**1. Custom Maxrate Input**
|
|
- **Type**: Text input (string)
|
|
- **Default**: Empty string `''`
|
|
- **Validation**: Parse as integer, check > 0, handle NaN gracefully
|
|
- **Position**: After `maxrate_cap` dropdown
|
|
|
|
**2. Target Bitrate Strategy Dropdown**
|
|
- **Type**: Dropdown
|
|
- **Options**: 6 choices
|
|
- `static*` - Use custom_maxrate or maxrate_cap (default)
|
|
- `match_source` - Match source bitrate (100%)
|
|
- `75%_source` - 75% of source
|
|
- `50%_source` - 50% of source
|
|
- `33%_source` - 33% of source
|
|
- `25%_source` - 25% of source
|
|
- **Position**: After `custom_maxrate` input
|
|
|
|
### Bitrate Detection Strategy
|
|
|
|
```mermaid
|
|
graph TD
|
|
A[Start] --> B[Check videoStream.bit_rate]
|
|
B -->|Available| C[Use video stream bitrate]
|
|
B -->|Missing| D[Check format.bit_rate]
|
|
D -->|Available| E[Use overall file bitrate]
|
|
D -->|Missing| F[sourceBitrateKbps = null<br/>Log warning]
|
|
C --> G[Convert bps to kbps]
|
|
E --> G
|
|
G --> H[sourceBitrateKbps ready]
|
|
F --> I[Fall back to static mode]
|
|
```
|
|
|
|
**Key Details**:
|
|
- Primary source: `file.ffProbeData.streams[videoStreamIndex].bit_rate` (bps)
|
|
- Fallback: `file.ffProbeData.format.bit_rate` (bps)
|
|
- Conversion: Divide by 1000 to get kbps
|
|
- Graceful failure: If neither available, log warning and use static mode
|
|
|
|
### Logic Precedence Implementation
|
|
|
|
```javascript
|
|
// Priority 1: target_bitrate_strategy (highest)
|
|
if (strategy !== 'static' && sourceBitrateKbps) {
|
|
calculatedMaxrate = Math.round(sourceBitrateKbps * multiplier);
|
|
}
|
|
|
|
// Priority 2: custom_maxrate (middle)
|
|
if (!calculatedMaxrate && custom_maxrate !== '' && parseInt(custom_maxrate) > 0) {
|
|
calculatedMaxrate = parseInt(custom_maxrate);
|
|
}
|
|
|
|
// Priority 3: maxrate_cap dropdown (lowest, existing)
|
|
if (!calculatedMaxrate && maxrate_cap !== '0') {
|
|
calculatedMaxrate = parseInt(maxrate_cap);
|
|
}
|
|
|
|
// Priority 4: No limit (default)
|
|
if (!calculatedMaxrate) {
|
|
// Uncapped CRF mode (existing behavior)
|
|
}
|
|
```
|
|
|
|
### Info Logging Strategy
|
|
|
|
Add clear logs to help users understand which bitrate method was used:
|
|
|
|
- **Strategy mode**: `"Using target bitrate strategy '50%_source': Source bitrate 10000k → Maxrate 5000k"`
|
|
- **Custom mode**: `"Using custom maxrate: 7500k"`
|
|
- **Dropdown mode**: `"Using maxrate cap from dropdown: 5000k"`
|
|
- **Fallback warning**: `"Warning: target_bitrate_strategy selected but source bitrate unavailable. Falling back to static mode."`
|
|
|
|
## Edge Cases to Handle
|
|
|
|
1. **Invalid custom_maxrate input**
|
|
- Non-numeric strings → Ignore, fall through to dropdown
|
|
- Negative numbers → Ignore, fall through to dropdown
|
|
- Zero → Treat as empty, fall through to dropdown
|
|
|
|
2. **Missing source bitrate with strategy selected**
|
|
- Log warning message
|
|
- Fall back to custom_maxrate or maxrate_cap
|
|
- Don't error/crash the plugin
|
|
|
|
3. **All inputs empty/zero**
|
|
- Default to uncapped CRF mode (existing behavior)
|
|
- No maxrate applied
|
|
|
|
4. **Conflicting inputs**
|
|
- User sets both strategy and custom_maxrate
|
|
- Strategy takes precedence (as designed)
|
|
- Log which one was used
|
|
|
|
## Compatibility Considerations
|
|
|
|
- **Backward compatible**: Existing configurations continue to work
|
|
- **Default behavior**: `target_bitrate_strategy = 'static'` and `custom_maxrate = ''` → Original behavior
|
|
- **No breaking changes**: All new inputs have safe defaults
|
|
- **FFmpeg compatibility**: Uses existing `-maxrate` and `-bufsize` flags (no new FFmpeg requirements)
|