Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e340e56dc8 | |||
| b8c07a4247 | |||
| a353b86677 |
93
Makefile
93
Makefile
|
|
@ -1,37 +1,92 @@
|
|||
# VideoTools Makefile
|
||||
# Cross-platform installer for Linux and Windows (Git Bash/WSL)
|
||||
# Cross-platform installer for VideoTools (Linux / Windows via Git Bash or WSL)
|
||||
|
||||
PREFIX ?= /usr/local
|
||||
INSTALL_DIR = $(PREFIX)/bin
|
||||
DOC_DIR = $(PREFIX)/share/doc/videotools
|
||||
|
||||
SCRIPT = video-tools.sh
|
||||
DOCS = docs
|
||||
VERSION_FILE = VERSION
|
||||
|
||||
install:
|
||||
# ------------------------
|
||||
# Installation
|
||||
# ------------------------
|
||||
|
||||
install: verify
|
||||
@echo "Installing VideoTools..."
|
||||
mkdir -p "$(INSTALL_DIR)"
|
||||
cp "$(SCRIPT)" "$(INSTALL_DIR)/video-tools"
|
||||
chmod +x "$(INSTALL_DIR)/video-tools"
|
||||
@echo "Copied script to $(INSTALL_DIR)/video-tools"
|
||||
@mkdir -p "$(INSTALL_DIR)"
|
||||
@install -m 755 "$(SCRIPT)" "$(INSTALL_DIR)/video-tools"
|
||||
@echo "✔ Installed script to $(INSTALL_DIR)/video-tools"
|
||||
|
||||
mkdir -p "$(DOC_DIR)"
|
||||
cp -r "$(DOCS)"/* "$(DOC_DIR)/"
|
||||
@echo "Documentation installed to $(DOC_DIR)"
|
||||
@mkdir -p "$(DOC_DIR)"
|
||||
@cp -r "$(DOCS)"/* "$(DOC_DIR)/"
|
||||
@echo "✔ Installed documentation to $(DOC_DIR)"
|
||||
|
||||
@if [ -f "$(VERSION_FILE)" ]; then \
|
||||
VERSION=$$(cat $(VERSION_FILE)); \
|
||||
echo "✔ VideoTools v$$VERSION installed successfully."; \
|
||||
else \
|
||||
echo "⚠ Version file not found. Install completed without version info."; \
|
||||
fi
|
||||
@echo ""
|
||||
|
||||
# ------------------------
|
||||
# Uninstall
|
||||
# ------------------------
|
||||
|
||||
uninstall:
|
||||
@echo "Removing VideoTools..."
|
||||
rm -f "$(INSTALL_DIR)/video-tools"
|
||||
rm -rf "$(DOC_DIR)"
|
||||
@echo "VideoTools uninstalled."
|
||||
@rm -f "$(INSTALL_DIR)/video-tools"
|
||||
@rm -rf "$(DOC_DIR)"
|
||||
@echo "✔ VideoTools uninstalled."
|
||||
|
||||
# ------------------------
|
||||
# Verification
|
||||
# ------------------------
|
||||
|
||||
verify:
|
||||
@echo "Checking environment..."
|
||||
@if ! command -v ffmpeg >/dev/null 2>&1; then \
|
||||
echo "✖ FFmpeg not found. Please install FFmpeg before continuing."; \
|
||||
exit 1; \
|
||||
else \
|
||||
echo "✔ FFmpeg found."; \
|
||||
fi
|
||||
@if ! command -v ffprobe >/dev/null 2>&1; then \
|
||||
echo "✖ FFprobe not found. Please install FFprobe before continuing."; \
|
||||
exit 1; \
|
||||
else \
|
||||
echo "✔ FFprobe found."; \
|
||||
fi
|
||||
@echo "✔ Environment OK."
|
||||
@echo ""
|
||||
|
||||
# ------------------------
|
||||
# Documentation
|
||||
# ------------------------
|
||||
|
||||
docs:
|
||||
@echo "Opening documentation..."
|
||||
@ls -1 $(DOCS)
|
||||
@echo "Available documentation files:"
|
||||
@ls -1 "$(DOCS)" | sed 's/^/ - /'
|
||||
|
||||
# ------------------------
|
||||
# Help
|
||||
# ------------------------
|
||||
|
||||
help:
|
||||
@echo "Available targets:"
|
||||
@echo "VideoTools Makefile — available targets:"
|
||||
@echo ""
|
||||
@echo " make install Install the toolkit system-wide"
|
||||
@echo " make uninstall Remove the toolkit"
|
||||
@echo " make docs List documentation files"
|
||||
@echo " make uninstall Remove all installed files"
|
||||
@echo " make verify Check FFmpeg, FFprobe, and environment"
|
||||
@echo " make docs List available documentation"
|
||||
@echo " make help Show this message"
|
||||
@echo ""
|
||||
@echo "Installation directories:"
|
||||
@echo " Script: $(INSTALL_DIR)"
|
||||
@echo " Docs : $(DOC_DIR)"
|
||||
@echo ""
|
||||
@echo "Note: Windows users can run 'make' via Git Bash or WSL."
|
||||
|
||||
# ------------------------
|
||||
# End of File
|
||||
# ------------------------
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"version": "0.1.0",
|
||||
"version": "0.1.1",
|
||||
"output_dir": "~/Videos",
|
||||
"video_codec": "libx264",
|
||||
"audio_codec": "aac",
|
||||
|
|
@ -9,5 +9,22 @@
|
|||
"default_filter": "lanczos",
|
||||
"enable_faststart": true,
|
||||
"auto_timestamp_fix": true,
|
||||
"allow_overwrite": false
|
||||
"allow_overwrite": false,
|
||||
"logging": {
|
||||
"enabled": true,
|
||||
"directory": "~/.local/share/video-tools/logs",
|
||||
"timestamp_format": "%Y-%m-%d_%H-%M-%S"
|
||||
},
|
||||
"profiles": {
|
||||
"hi-rate": {
|
||||
"crf": 14,
|
||||
"preset": "veryslow",
|
||||
"audio_bitrate": "320k"
|
||||
},
|
||||
"portable": {
|
||||
"crf": 24,
|
||||
"preset": "faster",
|
||||
"audio_bitrate": "128k"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
113
docs/CHANGELOG.md
Normal file
113
docs/CHANGELOG.md
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
# docs/CHANGELOG.md
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
||||
This project adheres to [Semantic Versioning](https://semver.org/).
|
||||
|
||||
---
|
||||
|
||||
## [0.1.2] - 2025-11-06
|
||||
### Added
|
||||
- Relative path headers (`# docs/...`) restored to the top of all documentation files for readability and navigation.
|
||||
- Updated documentation to reflect:
|
||||
- `videoinfo` and `--verbose` functionality.
|
||||
- Logging directory structure with ISO timestamps and `latest.log` symlink.
|
||||
- Cross-platform (Linux/Windows) compatibility details.
|
||||
- Added clarification on the `--hi-rate` and `--portable` profiles in `docs/CLI_Functions.md`.
|
||||
- Added reference to computed bitrate fallback in the upcoming version roadmap.
|
||||
|
||||
### Changed
|
||||
- Documentation standardized for plain-text (Gitea-safe) format.
|
||||
- Minor corrections to examples and paths in `README.md` and `CLI_Functions.md`.
|
||||
- Clarified usage of `convert-multiple` and quoting rules for paths with spaces.
|
||||
- Improved layout consistency across all docs for version parity.
|
||||
|
||||
### Planned for 0.1.3
|
||||
- Computed fallback bitrate in `videoinfo` for older containers (AVI, WMV, MPG).
|
||||
- Colorized technical output for clarity.
|
||||
- Header profile label display (Default / High Rate / Portable).
|
||||
- Automatic configuration detection improvements.
|
||||
|
||||
---
|
||||
|
||||
## [0.1.1] - 2025-11-05
|
||||
### Added
|
||||
- `--hi-rate` and `--portable` profile options:
|
||||
- High-rate: CRF 14, preset `veryslow`, 320 kbps audio
|
||||
- Portable: CRF 24, preset `faster`, 128 kbps audio
|
||||
- `videoinfo` command:
|
||||
- Displays concise technical details (duration, codecs, resolution, FPS, bitrate, etc.)
|
||||
- `--verbose` flag outputs full `ffprobe` metadata for debugging
|
||||
- Automatic log directory:
|
||||
- `~/.local/share/video-tools/logs/` with ISO-timestamped filenames
|
||||
- Symlink `latest.log` points to the newest log
|
||||
- Conversion summary now includes bitrate, FPS, elapsed time, and mux overhead
|
||||
- Cross-platform compatibility confirmed for Linux and Windows (Git Bash / WSL)
|
||||
|
||||
### Changed
|
||||
- Improved `convert-multiple` handling of spaced file paths
|
||||
- Cleaner and color-coded CLI output
|
||||
- Updated internal default values for logging and error messages
|
||||
- Improved argument parsing for optional profile flags
|
||||
|
||||
### Fixed
|
||||
- Resolved “unbound variable output_name” in `convert_multiple`
|
||||
- Fixed missing log directory permissions
|
||||
- Corrected path handling issues on Windows systems
|
||||
- Ensured temporary concat lists are removed after conversion
|
||||
|
||||
---
|
||||
|
||||
## [0.1.0] - 2025-11-04
|
||||
### Added
|
||||
- Initial release of **Video Tools CLI**
|
||||
- `convert-single` command:
|
||||
- Converts a single input file (AVI, MPG, MKV, MOV, etc.) into MP4
|
||||
- Uses FFmpeg with modern compression (`libx264`, `AAC`, CRF 18)
|
||||
- Automatically corrects timestamps (`-fflags +genpts`)
|
||||
- Outputs to `~/Videos`
|
||||
- `convert-multiple` command:
|
||||
- Merges multiple video inputs into one MP4
|
||||
- Re-encodes using same compression settings
|
||||
- Creates and cleans temporary file lists automatically
|
||||
- Config system (`config/config.json`) with optional `jq` parsing
|
||||
- Version tracking via `VERSION` file
|
||||
- Color-coded CLI feedback for INFO, WARN, ERROR, OK
|
||||
- Graceful error handling with safe exits and cleanup
|
||||
- Compatible with:
|
||||
- Linux (bash / zsh / fish shells)
|
||||
- Windows (via Git Bash or WSL)
|
||||
|
||||
### Documentation
|
||||
- `docs/README.md` — general usage and installation guide
|
||||
- `docs/CLI_Functions.md` — detailed command reference
|
||||
- `docs/Conversion_Settings.md` — technical breakdown of FFmpeg defaults
|
||||
- `docs/Upscale.md` — planned module outline for future upscaling support
|
||||
|
||||
### Build System
|
||||
- `Makefile` with:
|
||||
- `install` / `uninstall` / `verify` / `docs` / `help` targets
|
||||
- Version-aware output and FFmpeg dependency check
|
||||
- Installs both binary and documentation to system paths
|
||||
|
||||
---
|
||||
|
||||
## Planned for [0.2.0]
|
||||
### Added
|
||||
- `upscale-video` command:
|
||||
- FFmpeg `lanczos` scaling for 720p / 1080p / 4K
|
||||
- Optional H.265 (HEVC) encoding for smaller files
|
||||
- `convert-batch` for folder-wide conversions
|
||||
- JSON-driven override for per-run configuration (custom CRF, bitrate, etc.)
|
||||
- Optional parallel encoding support
|
||||
- Automatic codec detection before re-encoding
|
||||
|
||||
### Improvements
|
||||
- More detailed progress bar during FFmpeg execution
|
||||
- Unified cross-platform installer for Windows (PowerShell script)
|
||||
- Expanded error handling and logging to `logs/` directory
|
||||
|
||||
---
|
||||
|
||||
End of File
|
||||
|
|
@ -1,140 +1,165 @@
|
|||
# CLI Function Reference
|
||||
# docs/CLI_Functions.md
|
||||
CLI Function Reference (v0.1.2)
|
||||
|
||||
This document describes the available commands in `video-tools.sh`.
|
||||
This document describes the available commands in video-tools.sh.
|
||||
Each command can be run from any terminal once the tool is installed.
|
||||
|
||||
---
|
||||
------------------------------------------------------------
|
||||
Quick Reference
|
||||
------------------------------------------------------------
|
||||
|
||||
## Quick Reference
|
||||
Command: convert-single
|
||||
Syntax: video-tools convert-single <input> <output.mp4>
|
||||
Description: Converts a single video to MP4.
|
||||
|
||||
| Command | Syntax | Description |
|
||||
|----------|---------|-------------|
|
||||
| `convert-single` | `video-tools convert-single <input> <output.mp4>` | Converts a single video to MP4. |
|
||||
| `convert-multiple` | `video-tools convert-multiple <input1> <input2> ... <output.mp4>` | Combines multiple video files into one MP4. |
|
||||
Command: convert-multiple
|
||||
Syntax: video-tools convert-multiple <input1> <input2> ... <output.mp4>
|
||||
Description: Combines multiple video files into one MP4.
|
||||
|
||||
All outputs are saved in your default `~/Videos` folder.
|
||||
Command: videoinfo
|
||||
Syntax: video-tools videoinfo <file>
|
||||
Description: Displays concise technical details for a video.
|
||||
|
||||
---
|
||||
Command: videoinfo --verbose
|
||||
Syntax: video-tools videoinfo <file> --verbose
|
||||
Description: Displays full raw ffprobe metadata for advanced debugging.
|
||||
|
||||
## Command Details
|
||||
All outputs are saved in your default ~/Videos folder, unless overridden in config/config.json.
|
||||
|
||||
### 1. convert-single
|
||||
------------------------------------------------------------
|
||||
1. convert-single
|
||||
------------------------------------------------------------
|
||||
|
||||
**Purpose**
|
||||
Convert a single input video file into an MP4 with modern compression and audio standards.
|
||||
Purpose:
|
||||
Convert a single input video file into an MP4 using modern compression and audio standards.
|
||||
|
||||
**Usage**
|
||||
```bash
|
||||
video-tools convert-single <input> <output.mp4>
|
||||
```
|
||||
Usage:
|
||||
video-tools convert-single <input> <output.mp4> [--hi-rate | --portable]
|
||||
|
||||
**Example**
|
||||
```bash
|
||||
video-tools convert-single \
|
||||
"/run/media/user/Linux/MyData/Videos/Example Collection/Example Movie Part1.avi" \
|
||||
"Example Movie.mp4"
|
||||
```
|
||||
Examples:
|
||||
video-tools convert-single "example.avi" "example.mp4"
|
||||
video-tools convert-single "movie.avi" "movie_high.mp4" --hi-rate
|
||||
video-tools convert-single "clip.avi" "clip_mobile.mp4" --portable
|
||||
|
||||
**Output**
|
||||
```
|
||||
/home/user/Videos/Example Movie.mp4
|
||||
```
|
||||
Profiles:
|
||||
Default - CRF 18, preset slow, audio 192k (balanced quality/speed)
|
||||
--hi-rate - CRF 14, preset veryslow, audio 320k (maximum quality)
|
||||
--portable - CRF 24, preset faster, audio 128k (mobile optimized)
|
||||
|
||||
**Behavior**
|
||||
Behavior:
|
||||
- Converts older formats (AVI, MPG, MOV, MKV, etc.) into MP4.
|
||||
- Ensures output uses the H.264 codec (libx264) and AAC audio.
|
||||
- Rebuilds timestamps to avoid sync issues.
|
||||
- Adds `+faststart` flag for quicker playback when streamed or loaded in players.
|
||||
- Uses H.264 (libx264) for video and AAC for audio.
|
||||
- Rebuilds timestamps with -fflags +genpts to prevent sync issues.
|
||||
- Adds -movflags +faststart to improve playback and streaming.
|
||||
- Displays detailed FFmpeg progress and conversion summary.
|
||||
- Creates timestamped logs in ~/.local/share/video-tools/logs/.
|
||||
|
||||
**When to use**
|
||||
- When you want to upgrade old videos to a more efficient format.
|
||||
- When a single video won’t play on mobile or modern devices.
|
||||
- To reduce file size without losing visible quality.
|
||||
When to Use:
|
||||
- To modernize legacy or incompatible video files.
|
||||
- When playback fails on mobile or modern systems.
|
||||
- To reduce file size while preserving visible quality.
|
||||
|
||||
---
|
||||
------------------------------------------------------------
|
||||
2. convert-multiple
|
||||
------------------------------------------------------------
|
||||
|
||||
### 2. convert-multiple
|
||||
|
||||
**Purpose**
|
||||
Purpose:
|
||||
Combine several clips or discs into one MP4 output file.
|
||||
|
||||
**Usage**
|
||||
```bash
|
||||
video-tools convert-multiple <input1> <input2> ... <output.mp4>
|
||||
```
|
||||
Usage:
|
||||
video-tools convert-multiple <input1> <input2> ... <output.mp4> [--hi-rate | --portable]
|
||||
|
||||
**Example**
|
||||
```bash
|
||||
Example:
|
||||
video-tools convert-multiple \
|
||||
"/run/media/user/Linux/MyData/Videos/Example Collection/Example Movie Part1.avi" \
|
||||
"/run/media/user/Linux/MyData/Videos/Example Collection/Example Movie Part2.avi" \
|
||||
"/run/media/user/Linux/MyData/Videos/Example Collection/Example Movie Part3.avi" \
|
||||
"Example Movie Combined.mp4"
|
||||
```
|
||||
|
||||
**Output**
|
||||
```
|
||||
/home/user/Videos/Example Movie Combined.mp4
|
||||
```
|
||||
Behavior:
|
||||
- Merges all listed videos sequentially into a single MP4.
|
||||
- Re-encodes each input using the same profile (default, hi-rate, or portable).
|
||||
- Creates and deletes a temporary concat list automatically.
|
||||
- Displays each added file and progress in the terminal.
|
||||
- Ensures the output is playable immediately after completion.
|
||||
- Logs conversion details in ~/.local/share/video-tools/logs/.
|
||||
|
||||
**Behavior**
|
||||
- Reads all listed files in order and merges them seamlessly.
|
||||
- Each input is re-encoded using the same H.264/AAC settings.
|
||||
- Temporary file list is automatically created and deleted.
|
||||
- Logs detailed FFmpeg progress to the terminal.
|
||||
When to Use:
|
||||
- To combine multi-part discs, episodes, or clips.
|
||||
- When producing a single continuous playback file.
|
||||
|
||||
**When to use**
|
||||
- When combining multi-part video discs, episodes, or scene splits.
|
||||
- When creating a single playable MP4 from segmented source material.
|
||||
------------------------------------------------------------
|
||||
3. videoinfo
|
||||
------------------------------------------------------------
|
||||
|
||||
---
|
||||
Purpose:
|
||||
Display detailed technical information about a video file.
|
||||
|
||||
## Return Codes
|
||||
Usage:
|
||||
video-tools videoinfo <file> [--verbose]
|
||||
|
||||
| Code | Meaning |
|
||||
|------|----------|
|
||||
| 0 | Success |
|
||||
| 1 | Invalid syntax or missing arguments |
|
||||
| 2 | FFmpeg execution error |
|
||||
Examples:
|
||||
video-tools videoinfo "movie.mp4"
|
||||
video-tools videoinfo "movie.mp4" --verbose
|
||||
|
||||
---
|
||||
Behavior:
|
||||
- Without flags: Displays key metadata (duration, codecs, resolution, FPS, bitrate).
|
||||
- With --verbose: Prints full raw ffprobe data for technical inspection.
|
||||
- Outputs consistent formatting across platforms (no bc dependency).
|
||||
- Provides fallback for older files missing embedded bitrate metadata.
|
||||
- Useful for comparing encoding quality or diagnosing container issues.
|
||||
|
||||
## Common Issues
|
||||
------------------------------------------------------------
|
||||
Return Codes
|
||||
------------------------------------------------------------
|
||||
|
||||
| Symptom | Cause | Fix |
|
||||
|----------|--------|----|
|
||||
| Conversion fails immediately | Input path invalid | Ensure file path is correct and quoted |
|
||||
| Merge creates sync issues | Source files differ in resolution or frame rate | Convert each to MP4 first, then merge |
|
||||
| Output not found | FFmpeg failed silently | Check terminal logs for permission or codec errors |
|
||||
0 - Success
|
||||
1 - Invalid syntax or missing arguments
|
||||
2 - FFmpeg or ffprobe execution error
|
||||
|
||||
---
|
||||
------------------------------------------------------------
|
||||
Common Issues
|
||||
------------------------------------------------------------
|
||||
|
||||
## Planned Additions
|
||||
Symptom: Conversion fails immediately
|
||||
Cause: Input path invalid
|
||||
Fix: Ensure full path is correct and quoted properly.
|
||||
|
||||
| Command | Description |
|
||||
|----------|-------------|
|
||||
| `convert-batch` | Convert every video in a folder automatically |
|
||||
| `upscale-video` | Upscale videos to 1080p or 4K using `lanczos` or ML filters |
|
||||
| `compress-video` | Recompress MP4s using HEVC or AV1 for smaller storage |
|
||||
| `video-info` | Quick summary of resolution, codec, and bitrate |
|
||||
Symptom: Merge causes sync or timing drift
|
||||
Cause: Source files differ in resolution or frame rate
|
||||
Fix: Convert each to MP4 first, then merge.
|
||||
|
||||
---
|
||||
Symptom: Output not found
|
||||
Cause: FFmpeg encountered an error
|
||||
Fix: Review the relevant log in ~/.local/share/video-tools/logs/.
|
||||
|
||||
## Technical Summary
|
||||
------------------------------------------------------------
|
||||
Planned Additions
|
||||
------------------------------------------------------------
|
||||
|
||||
### Conversion Logic
|
||||
- Uses FFmpeg with explicit input and output flags:
|
||||
```
|
||||
ffmpeg -fflags +genpts -i "input" -c:v libx264 -crf 18 -preset slow -c:a aac -b:a 192k -movflags +faststart "output"
|
||||
```
|
||||
- `-fflags +genpts` regenerates presentation timestamps (avoids "Non-monotonic DTS" errors).
|
||||
- Re-encoding ensures compatibility and stable playback.
|
||||
convert-batch - Convert every video in a folder automatically.
|
||||
upscale-video - Upscale videos to 720p, 1080p, or 4K using lanczos or ML-based filters.
|
||||
compress-video - Recompress MP4s with HEVC (H.265) or AV1 for reduced size.
|
||||
video-compare - Compare bitrate, resolution, and encoding stats between two files.
|
||||
auto-fix - Automatically repair timestamps or rotation metadata before encoding.
|
||||
|
||||
### File Safety
|
||||
- Original files are untouched.
|
||||
- All intermediate list files are removed automatically.
|
||||
- FFmpeg handles SIGINT (Ctrl+C) gracefully—partially written files are still playable.
|
||||
------------------------------------------------------------
|
||||
Technical Summary
|
||||
------------------------------------------------------------
|
||||
|
||||
---
|
||||
Conversion Logic:
|
||||
ffmpeg -fflags +genpts -i "input" \
|
||||
-c:v libx264 -crf 18 -preset slow \
|
||||
-c:a aac -b:a 192k -movflags +faststart "output"
|
||||
|
||||
Notes:
|
||||
- -fflags +genpts regenerates presentation timestamps (avoids "Non-monotonic DTS" errors).
|
||||
- Modern codecs ensure full compatibility and efficient compression.
|
||||
- Re-encoding avoids playback issues caused by legacy container formats.
|
||||
|
||||
File Safety:
|
||||
- Original files remain untouched.
|
||||
- All intermediate concat lists are deleted automatically.
|
||||
- FFmpeg handles SIGINT (Ctrl+C) safely — partial outputs remain playable.
|
||||
|
||||
------------------------------------------------------------
|
||||
End of File
|
||||
|
|
|
|||
|
|
@ -1,99 +1,134 @@
|
|||
# Conversion Settings
|
||||
# docs/Conversion_Settings.md
|
||||
Conversion Settings (v0.1.2)
|
||||
|
||||
This file documents the default FFmpeg parameters used in `video-tools.sh` and explains why they are chosen.
|
||||
This file documents the default FFmpeg parameters used in video-tools.sh and explains why they are chosen.
|
||||
|
||||
---
|
||||
------------------------------------------------------------
|
||||
Output Format
|
||||
------------------------------------------------------------
|
||||
|
||||
## Output Format
|
||||
All conversions produce:
|
||||
```
|
||||
Format: MP4
|
||||
Container: MPEG-4 Part 14
|
||||
Video Codec: H.264 (libx264)
|
||||
Audio Codec: AAC
|
||||
```
|
||||
|
||||
MP4 was chosen because:
|
||||
- It’s universally supported across modern devices.
|
||||
- It balances size and compatibility well.
|
||||
- H.264 encoding provides excellent quality at smaller bitrates.
|
||||
Why MP4:
|
||||
- Universally supported across modern devices.
|
||||
- Balances quality, compression, and compatibility.
|
||||
- H.264 encoding provides excellent visual quality at modest bitrates.
|
||||
- AAC audio ensures consistent playback on all major systems including Windows, macOS, Android, and iOS.
|
||||
|
||||
---
|
||||
------------------------------------------------------------
|
||||
Default Parameters
|
||||
------------------------------------------------------------
|
||||
|
||||
## Default Parameters
|
||||
Parameter: -c:v libx264
|
||||
Purpose: H.264 video encoding (modern, efficient, hardware-accelerated)
|
||||
|
||||
| Parameter | Value | Purpose |
|
||||
|------------|--------|----------|
|
||||
| `-c:v libx264` | H.264 video encoding | Modern, efficient codec with wide hardware support |
|
||||
| `-crf 18` | Constant Rate Factor | Maintains near-lossless visual quality; lower = better |
|
||||
| `-preset slow` | Encoding preset | Improves compression efficiency; trades some speed |
|
||||
| `-c:a aac` | Audio codec | Standard high-quality stereo audio |
|
||||
| `-b:a 192k` | Audio bitrate | Balances fidelity and file size |
|
||||
| `-movflags +faststart` | MP4 optimization | Enables faster playback start in players or web streams |
|
||||
| `-fflags +genpts` | Timestamp repair | Regenerates timestamps on older AVI/MPEG inputs |
|
||||
Parameter: -crf 18
|
||||
Purpose: Constant Rate Factor for near-lossless quality (lower = higher quality)
|
||||
|
||||
---
|
||||
Parameter: -preset slow
|
||||
Purpose: Improves compression efficiency at moderate CPU cost
|
||||
|
||||
## Quality vs. File Size
|
||||
Parameter: -c:a aac
|
||||
Purpose: High-quality audio encoding compatible with most players
|
||||
|
||||
The CRF scale (used by FFmpeg) defines quality and compression balance:
|
||||
Parameter: -b:a 192k
|
||||
Purpose: Balances clarity and file size
|
||||
|
||||
| CRF | Description | Typical Use |
|
||||
|------|-------------|--------------|
|
||||
| 14–16 | Near lossless | Archival or professional mastering |
|
||||
| 18–20 | High quality | Everyday use, visually lossless |
|
||||
| 21–24 | Medium quality | Small file sizes, light compression |
|
||||
| 25+ | Low quality | Fast compression, heavy size reduction |
|
||||
Parameter: -movflags +faststart
|
||||
Purpose: Optimizes MP4 for streaming and faster playback start
|
||||
|
||||
The default of **CRF 18** keeps visual clarity virtually identical to the original while cutting most AVI or MPG files to **40–60% smaller** sizes.
|
||||
Parameter: -fflags +genpts
|
||||
Purpose: Rebuilds timestamps to prevent sync issues with older containers
|
||||
|
||||
---
|
||||
------------------------------------------------------------
|
||||
Profile Presets
|
||||
------------------------------------------------------------
|
||||
|
||||
## Why Preset "slow"
|
||||
Default Profile:
|
||||
CRF 18
|
||||
Preset slow
|
||||
Audio 192k
|
||||
Balanced for visual clarity and efficient storage.
|
||||
|
||||
The preset defines encoding effort vs. compression efficiency.
|
||||
Options range from `ultrafast` → `veryslow`.
|
||||
Hi-Rate Profile (--hi-rate):
|
||||
CRF 14
|
||||
Preset veryslow
|
||||
Audio 320k
|
||||
Maximum quality, slower encoding, ideal for archiving or high-bitrate content.
|
||||
|
||||
- **slow** provides strong compression without extreme CPU time.
|
||||
- Encoding speed is roughly 2–3× real-time on a midrange CPU.
|
||||
- File sizes are typically 10–20% smaller than `medium` preset at the same quality.
|
||||
Portable Profile (--portable):
|
||||
CRF 24
|
||||
Preset faster
|
||||
Audio 128k
|
||||
Optimized for mobile devices and reduced file sizes.
|
||||
|
||||
---
|
||||
Each profile automatically adjusts encoding parameters to ensure consistent results without user intervention.
|
||||
|
||||
## Audio Strategy
|
||||
------------------------------------------------------------
|
||||
Quality vs. File Size
|
||||
------------------------------------------------------------
|
||||
|
||||
AAC at 192k is chosen for:
|
||||
- Wide playback compatibility (phones, TVs, players).
|
||||
- Transparent stereo sound for most sources.
|
||||
- Reasonable storage size (~2MB/minute of stereo audio).
|
||||
The CRF (Constant Rate Factor) scale controls perceived quality versus compression level.
|
||||
|
||||
If future needs arise, the tool can later support:
|
||||
- `-c:a copy` for untouched audio streams.
|
||||
- `-b:a 320k` for high-fidelity preservation.
|
||||
CRF 14–16: Near-lossless (archival or studio preservation)
|
||||
CRF 18–20: High quality (default visual transparency)
|
||||
CRF 21–24: Medium (smaller file size, minimal loss)
|
||||
CRF 25+: Low quality (fast encoding, visible artifacts)
|
||||
|
||||
---
|
||||
Default CRF: 18
|
||||
Produces files roughly 40–60 percent smaller than original sources with minimal visible loss.
|
||||
|
||||
## Color Space & Scaling
|
||||
------------------------------------------------------------
|
||||
Preset Choice
|
||||
------------------------------------------------------------
|
||||
|
||||
No scaling is applied by default.
|
||||
The video retains original resolution and color profile.
|
||||
Presets define encoding speed versus compression efficiency.
|
||||
Range: ultrafast → veryslow
|
||||
|
||||
Upscaling and filtering will be handled in a separate command (`upscale-video`) in future versions, with support for:
|
||||
- FFmpeg’s `scale` and `zscale` filters.
|
||||
- `lanczos` resampling (for sharp, clean upscale).
|
||||
- Optional integration with ML-based models (Real-ESRGAN, waifu2x).
|
||||
The preset "slow" was chosen because:
|
||||
- Offers a strong balance between speed and compression.
|
||||
- Output files are typically 10–20 percent smaller than those encoded at "medium".
|
||||
- Encoding speed is roughly two to three times real-time on a midrange CPU.
|
||||
|
||||
---
|
||||
------------------------------------------------------------
|
||||
Audio Strategy
|
||||
------------------------------------------------------------
|
||||
|
||||
## Future Additions
|
||||
AAC at 192k is used for:
|
||||
- Transparent stereo audio for most content.
|
||||
- Low CPU usage during encoding.
|
||||
- Roughly two megabytes per minute of stereo content.
|
||||
|
||||
| Planned Setting | Description |
|
||||
|------------------|-------------|
|
||||
| `upscale-mode` | Default scaling filter for upscaling tasks |
|
||||
| `hevc-mode` | Switch to H.265 (libx265) for smaller files |
|
||||
| `audio-pass` | Option to skip audio re-encoding |
|
||||
| `config.json` | User-editable file to override default values |
|
||||
Future audio options include:
|
||||
- -c:a copy to preserve original streams when re-encoding is unnecessary.
|
||||
- -b:a 320k for studio-grade sound reproduction.
|
||||
- FLAC or PCM support for lossless audio workflows.
|
||||
|
||||
---
|
||||
------------------------------------------------------------
|
||||
Color and Resolution
|
||||
------------------------------------------------------------
|
||||
|
||||
No scaling or color adjustments occur unless explicitly requested.
|
||||
Source resolution, frame rate, and color space (usually bt709) are preserved.
|
||||
|
||||
Future command "upscale-video" will support:
|
||||
- FFmpeg scale and zscale filters.
|
||||
- Lanczos resampling for high-quality upscales.
|
||||
- Optional machine-learning upscalers such as Real-ESRGAN or waifu2x.
|
||||
|
||||
------------------------------------------------------------
|
||||
Future Additions
|
||||
------------------------------------------------------------
|
||||
|
||||
upscale-mode Choose default scaling filter for upscaling tasks
|
||||
hevc-mode Switch to H.265 (libx265) for smaller, more efficient files
|
||||
audio-pass Skip audio re-encoding when not needed
|
||||
config.json User-editable configuration to override all defaults
|
||||
auto-bitrate Compute estimated average bitrate for legacy containers
|
||||
|
||||
------------------------------------------------------------
|
||||
End of File
|
||||
|
|
|
|||
208
docs/README.md
208
docs/README.md
|
|
@ -1,137 +1,153 @@
|
|||
# Video Tools CLI
|
||||
# docs/README.md
|
||||
Video Tools CLI (v0.1.2)
|
||||
|
||||
A simple command-line utility for video conversion and merging using FFmpeg.
|
||||
Designed for personal use and sharing with friends.
|
||||
Works on both Linux and Windows (via Git Bash or WSL).
|
||||
A lightweight command-line utility for video conversion, merging, and media inspection using FFmpeg.
|
||||
Developed by Leak Technologies for efficient local video processing.
|
||||
Fully compatible with Linux and Windows (via Git Bash or WSL).
|
||||
|
||||
---
|
||||
------------------------------------------------------------
|
||||
Overview
|
||||
------------------------------------------------------------
|
||||
|
||||
## Overview
|
||||
The tool provides several core commands:
|
||||
|
||||
This tool provides two main commands:
|
||||
convert-single Converts a single video to MP4 using high-quality compression.
|
||||
convert-multiple Combines multiple video clips or discs into one MP4 file.
|
||||
videoinfo Displays technical details such as bitrate, resolution, codecs, and duration.
|
||||
videoinfo --verbose Shows full ffprobe metadata for advanced analysis.
|
||||
|
||||
| Command | Description |
|
||||
|----------|-------------|
|
||||
| `convert-single` | Converts a single video file to MP4 using modern compression. |
|
||||
| `convert-multiple` | Combines multiple video files into one high-quality MP4. |
|
||||
All converted videos are saved to ~/Videos by default.
|
||||
Logs are stored in ~/.local/share/video-tools/logs with ISO timestamps.
|
||||
|
||||
All output files are saved in your `~/Videos` directory by default.
|
||||
------------------------------------------------------------
|
||||
Requirements
|
||||
------------------------------------------------------------
|
||||
|
||||
---
|
||||
Linux:
|
||||
Install FFmpeg using your package manager:
|
||||
sudo pacman -S ffmpeg (Arch, Garuda, EndeavourOS)
|
||||
sudo apt install ffmpeg (Debian, Ubuntu, Mint)
|
||||
|
||||
## Requirements
|
||||
Windows:
|
||||
1. Download FFmpeg from https://ffmpeg.org/download.html
|
||||
2. Add FFmpeg to your PATH environment variable.
|
||||
3. Use Git Bash or WSL to execute video-tools.sh.
|
||||
|
||||
### Linux
|
||||
Install FFmpeg with your package manager:
|
||||
```bash
|
||||
sudo pacman -S ffmpeg # For Arch or Garuda
|
||||
sudo apt install ffmpeg # For Debian or Ubuntu
|
||||
```
|
||||
|
||||
### Windows
|
||||
1. Install FFmpeg from https://ffmpeg.org/download.html
|
||||
2. Use **Git Bash** or **WSL** to run the script.
|
||||
|
||||
---
|
||||
|
||||
## Installation
|
||||
------------------------------------------------------------
|
||||
Installation
|
||||
------------------------------------------------------------
|
||||
|
||||
1. Clone or copy the repository:
|
||||
```bash
|
||||
git clone https://github.com/YourName/VideoTools.git
|
||||
git clone https://git.leaktechnologies.dev/Leak_Technologies/VideoTools.git
|
||||
cd VideoTools
|
||||
```
|
||||
|
||||
2. Make the script executable:
|
||||
```bash
|
||||
chmod +x video-tools.sh
|
||||
```
|
||||
|
||||
3. (Optional) Add it to PATH:
|
||||
```bash
|
||||
3. (Optional) Add it to your system PATH:
|
||||
sudo ln -s ~/VideoTools/video-tools.sh /usr/local/bin/video-tools
|
||||
```
|
||||
|
||||
You can now run it globally:
|
||||
```bash
|
||||
You can now use it globally:
|
||||
video-tools convert-single "input.avi" "output.mp4"
|
||||
```
|
||||
|
||||
---
|
||||
------------------------------------------------------------
|
||||
Default Settings
|
||||
------------------------------------------------------------
|
||||
|
||||
## Default Settings
|
||||
Output directory: ~/Videos
|
||||
Video codec: libx264
|
||||
Audio codec: aac
|
||||
Quality (CRF): 18
|
||||
Preset: slow
|
||||
Audio bitrate: 192k
|
||||
|
||||
| Setting | Value | Description |
|
||||
|----------|--------|-------------|
|
||||
| Output directory | `~/Videos` | All results are stored here |
|
||||
| Video codec | `libx264` | High-quality H.264 encoding |
|
||||
| Audio codec | `aac` | High-quality AAC stereo audio |
|
||||
| Quality (CRF) | 18 | Visually lossless quality |
|
||||
| Preset | slow | Balances speed and compression |
|
||||
| Audio bitrate | 192k | High-quality stereo output |
|
||||
These defaults balance visual quality and compression efficiency.
|
||||
They are ideal for general use, personal archiving, and local playback.
|
||||
|
||||
These defaults prioritize quality while still reducing file sizes compared to older formats such as AVI or MPG.
|
||||
For full parameter details, see docs/Conversion_Settings.md.
|
||||
|
||||
---
|
||||
------------------------------------------------------------
|
||||
Example Usage
|
||||
------------------------------------------------------------
|
||||
|
||||
## Example Conversions
|
||||
Convert a single file:
|
||||
video-tools convert-single "/path/to/input.avi" "output.mp4"
|
||||
|
||||
### Convert a single AVI file
|
||||
Merge multiple videos:
|
||||
video-tools convert-multiple "/path/to/part1.avi" "/path/to/part2.avi" "combined.mp4"
|
||||
|
||||
```bash
|
||||
video-tools convert-single \
|
||||
"/run/media/stu/Linux/MyData/Videos/Example Collection/Example Movie Part1.avi" \
|
||||
"Example Movie.mp4"
|
||||
```
|
||||
Check video info:
|
||||
video-tools videoinfo "combined.mp4"
|
||||
|
||||
Output:
|
||||
```
|
||||
/home/stu/Videos/Example Movie.mp4
|
||||
```
|
||||
Verbose mode:
|
||||
video-tools videoinfo "combined.mp4" --verbose
|
||||
|
||||
---
|
||||
------------------------------------------------------------
|
||||
Conversion Profiles
|
||||
------------------------------------------------------------
|
||||
|
||||
### Combine multiple AVI parts into one MP4
|
||||
Default:
|
||||
CRF 18, preset slow, 192k audio (balanced quality and speed)
|
||||
|
||||
```bash
|
||||
video-tools convert-multiple \
|
||||
"/run/media/stu/Linux/MyData/Videos/Example Collection/Example Movie Part1.avi" \
|
||||
"/run/media/stu/Linux/MyData/Videos/Example Collection/Example Movie Part2.avi" \
|
||||
"/run/media/stu/Linux/MyData/Videos/Example Collection/Example Movie Part3.avi" \
|
||||
"Example Movie Combined.mp4"
|
||||
```
|
||||
--hi-rate:
|
||||
CRF 14, preset veryslow, 320k audio (maximum quality)
|
||||
|
||||
Output:
|
||||
```
|
||||
/home/stu/Videos/Example Movie Combined.mp4
|
||||
```
|
||||
--portable:
|
||||
CRF 24, preset faster, 128k audio (mobile optimized)
|
||||
|
||||
---
|
||||
Profiles can be added after any convert command.
|
||||
|
||||
## Troubleshooting
|
||||
Example:
|
||||
video-tools convert-single "movie.avi" "movie_high.mp4" --hi-rate
|
||||
|
||||
| Issue | Cause | Solution |
|
||||
|--------|--------|----------|
|
||||
| `command not found` | Script not in PATH | Use full path or add symlink to `/usr/local/bin` |
|
||||
| `ffmpeg not found` | FFmpeg not installed | Install FFmpeg using your package manager |
|
||||
| `Permission denied` | Script not executable | Run `chmod +x video-tools.sh` |
|
||||
| Merge fails | Input files have mismatched codecs | Convert each input to MP4 first, then merge |
|
||||
------------------------------------------------------------
|
||||
Troubleshooting
|
||||
------------------------------------------------------------
|
||||
|
||||
---
|
||||
Problem: command not found
|
||||
Cause: Script not linked globally
|
||||
Fix: Run ./video-tools.sh or create a symlink in /usr/local/bin
|
||||
|
||||
## Roadmap
|
||||
Problem: ffmpeg not found
|
||||
Cause: FFmpeg not installed
|
||||
Fix: Install it using your system package manager
|
||||
|
||||
| Feature | Status |
|
||||
|----------|--------|
|
||||
| convert-single | ✅ Done |
|
||||
| convert-multiple | ✅ Done |
|
||||
| upscale-video | 🔜 Planned |
|
||||
| batch conversion | 🔜 Planned |
|
||||
| automatic format detection | 🔜 Planned |
|
||||
Problem: permission denied
|
||||
Cause: Missing executable permission
|
||||
Fix: chmod +x video-tools.sh
|
||||
|
||||
---
|
||||
Problem: merge fails
|
||||
Cause: Inputs use different codecs or frame rates
|
||||
Fix: Convert each input to MP4 first, then merge
|
||||
|
||||
## License
|
||||
------------------------------------------------------------
|
||||
Roadmap
|
||||
------------------------------------------------------------
|
||||
|
||||
Free for personal use.
|
||||
You can modify or share this tool with anyone.
|
||||
convert-single Complete
|
||||
convert-multiple Complete
|
||||
videoinfo Complete
|
||||
upscale-video Planned
|
||||
batch conversion Planned
|
||||
auto format detect Planned
|
||||
video-compare Planned
|
||||
config overrides Planned
|
||||
|
||||
------------------------------------------------------------
|
||||
Documentation Index
|
||||
------------------------------------------------------------
|
||||
|
||||
docs/CLI_Functions.md Command reference and usage examples
|
||||
docs/Conversion_Settings.md Technical breakdown of encoding defaults
|
||||
docs/CHANGELOG.md Version history and planned updates
|
||||
docs/Upscale.md Future plans for scaling and ML-based enhancement
|
||||
|
||||
------------------------------------------------------------
|
||||
License
|
||||
------------------------------------------------------------
|
||||
|
||||
Free for personal and educational use.
|
||||
Redistribution permitted with attribution to Leak Technologies.
|
||||
|
||||
------------------------------------------------------------
|
||||
End of File
|
||||
|
|
|
|||
102
docs/Upscale.md
102
docs/Upscale.md
|
|
@ -1,71 +1,83 @@
|
|||
# Upscale Module (Planned)
|
||||
# docs/Upscale.md
|
||||
Upscale Module (Planned) - v0.1.2
|
||||
|
||||
The `upscale-video` command will provide loss-minimized video upscaling.
|
||||
The upscale-video command will provide high-quality resolution upscaling with minimal visual loss.
|
||||
It will begin with traditional FFmpeg filters and later introduce machine learning based upscalers.
|
||||
|
||||
---
|
||||
------------------------------------------------------------
|
||||
Overview
|
||||
------------------------------------------------------------
|
||||
|
||||
## Overview
|
||||
|
||||
This module will allow upscaling of existing videos to higher resolutions such as:
|
||||
The goal of this module is to let users upscale existing videos to standardized modern resolutions such as:
|
||||
- 720p (HD)
|
||||
- 1080p (Full HD)
|
||||
- 2160p (4K)
|
||||
- 2160p (4K UHD)
|
||||
|
||||
It will use FFmpeg’s native scaling filters first and optionally integrate machine learning tools later.
|
||||
The first release will use FFmpeg’s built-in scaling filters including lanczos, bicubic, and spline36.
|
||||
Future updates will explore GPU and ML-based upscaling options such as Real-ESRGAN and waifu2x.
|
||||
|
||||
---
|
||||
------------------------------------------------------------
|
||||
Planned Syntax
|
||||
------------------------------------------------------------
|
||||
|
||||
## Planned Syntax
|
||||
|
||||
```bash
|
||||
video-tools upscale-video <input> <output.mp4> --scale 1920x1080
|
||||
```
|
||||
|
||||
Optional parameters:
|
||||
```
|
||||
--scale <WxH> Set explicit resolution
|
||||
--filter <name> Choose scaling filter (lanczos, bicubic, spline36)
|
||||
--hevc Encode using H.265 for smaller output
|
||||
--keep-audio Copy original audio stream without re-encoding
|
||||
```
|
||||
--scale <WxH> Specify custom resolution
|
||||
--filter <name> Choose scaling filter (lanczos, bicubic, spline36, bilinear)
|
||||
--hevc Encode output with H.265 for reduced file size
|
||||
--keep-audio Copy the original audio stream without re-encoding
|
||||
|
||||
---
|
||||
------------------------------------------------------------
|
||||
Default Behavior
|
||||
------------------------------------------------------------
|
||||
|
||||
## Default Behavior
|
||||
When no scale or filter is provided, the tool will automatically upscale to the next common resolution above the source.
|
||||
|
||||
If no resolution is provided, the tool will upscale intelligently to the nearest standard resolution above the input video.
|
||||
Examples:
|
||||
Input: 960x540 → Output: 1280x720
|
||||
Input: 1280x720 → Output: 1920x1080
|
||||
Input: 1440x1080 → Output: 1920x1080
|
||||
|
||||
Example:
|
||||
- Input: 960×540 → Output: 1280×720
|
||||
- Input: 1280×720 → Output: 1920×1080
|
||||
The tool will retain the same aspect ratio and avoid unnecessary stretching or cropping.
|
||||
|
||||
---
|
||||
------------------------------------------------------------
|
||||
Technical Notes
|
||||
------------------------------------------------------------
|
||||
|
||||
## Technical Notes
|
||||
Example FFmpeg usage:
|
||||
ffmpeg -i input.mp4 -vf scale=1920:1080:flags=lanczos -c:v libx264 -crf 18 -preset slow -c:a aac -b:a 192k output_1080p.mp4
|
||||
|
||||
### FFmpeg Filter Example
|
||||
Explanation:
|
||||
scale=1920:1080:flags=lanczos performs resampling using the Lanczos algorithm for sharp, high-quality results.
|
||||
Lanczos minimizes aliasing and ringing while retaining edge detail.
|
||||
Future implementations may use zscale for improved color management or GPU-accelerated scaling with CUDA or Vulkan.
|
||||
|
||||
```bash
|
||||
ffmpeg -i input.mp4 -vf scale=1920:1080:flags=lanczos \
|
||||
-c:v libx264 -crf 18 -preset slow -c:a aac -b:a 192k output_1080p.mp4
|
||||
```
|
||||
------------------------------------------------------------
|
||||
Planned Features
|
||||
------------------------------------------------------------
|
||||
|
||||
- `scale=1920:1080:flags=lanczos` → high-quality resampling
|
||||
- `lanczos` offers sharp, low-artifact upscale
|
||||
- Later versions may support `zscale` or ML-based filters
|
||||
FFmpeg scaler (lanczos) Planned
|
||||
zscale and bicubic scaling Planned
|
||||
ML-based upscaling (Real-ESRGAN) Research stage
|
||||
Auto-resolution detection Planned
|
||||
GPU acceleration support Planned
|
||||
Configurable quality presets Planned
|
||||
HEVC and AV1 encoder options Planned
|
||||
Batch folder upscaling mode Planned
|
||||
|
||||
---
|
||||
------------------------------------------------------------
|
||||
Example Future Commands
|
||||
------------------------------------------------------------
|
||||
|
||||
## Planned Features
|
||||
Upscale to 1080p using default settings:
|
||||
video-tools upscale-video "movie.mp4" "movie_1080p.mp4"
|
||||
|
||||
| Feature | Status |
|
||||
|----------|--------|
|
||||
| FFmpeg scaler (lanczos) | 🔜 Planned |
|
||||
| ML-based upscaling (Real-ESRGAN / waifu2x) | 🚧 Research |
|
||||
| Auto resolution detection | 🔜 Planned |
|
||||
| GPU acceleration support | 🔜 Planned |
|
||||
| Configurable presets | 🔜 Planned |
|
||||
Upscale to 4K using HEVC and Lanczos filter:
|
||||
video-tools upscale-video "movie.mp4" "movie_4k.mp4" --scale 3840x2160 --hevc --filter lanczos
|
||||
|
||||
---
|
||||
Copy original audio without re-encoding:
|
||||
video-tools upscale-video "documentary.mp4" "documentary_upscaled.mp4" --keep-audio
|
||||
|
||||
------------------------------------------------------------
|
||||
End of File
|
||||
|
|
|
|||
296
video-tools.sh
296
video-tools.sh
|
|
@ -1,17 +1,19 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# video-tools.sh
|
||||
# ----------------------------------------------------------
|
||||
# Simple FFmpeg CLI Toolset
|
||||
# -------------------------
|
||||
# Provides easy commands for single or multi-file video conversion.
|
||||
# Works on Linux and Windows (Git Bash / WSL) as long as ffmpeg is installed.
|
||||
#
|
||||
# ----------------------------------------------------------
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# ==========================================================
|
||||
# Configuration system
|
||||
# ==========================================================
|
||||
CONFIG_FILE="$(dirname "$0")/config/config.json"
|
||||
SCRIPT_DIR="$(dirname "$0")"
|
||||
CONFIG_FILE="$SCRIPT_DIR/config/config.json"
|
||||
LOG_DIR="$HOME/.local/share/video-tools/logs"
|
||||
|
||||
# -------------------------
|
||||
# Default configuration
|
||||
|
|
@ -22,7 +24,7 @@ AUDIO_CODEC="aac"
|
|||
CRF="18" # lower = higher quality
|
||||
PRESET="slow" # slower = better compression
|
||||
AUDIO_BITRATE="192k"
|
||||
VERSION="0.1.0"
|
||||
VERSION="0.1.1"
|
||||
|
||||
# ==========================================================
|
||||
# Utility: Colour logging
|
||||
|
|
@ -39,7 +41,7 @@ warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
|||
error() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
|
||||
|
||||
# ==========================================================
|
||||
# Check dependencies early
|
||||
# Dependency check
|
||||
# ==========================================================
|
||||
if ! command -v ffmpeg >/dev/null 2>&1; then
|
||||
error "ffmpeg is not installed or not in PATH."
|
||||
|
|
@ -62,6 +64,33 @@ else
|
|||
fi
|
||||
|
||||
mkdir -p "$OUTPUT_DIR" || { error "Failed to create output directory $OUTPUT_DIR"; exit 1; }
|
||||
mkdir -p "$LOG_DIR" || { error "Failed to create log directory $LOG_DIR"; exit 1; }
|
||||
|
||||
# ==========================================================
|
||||
# Conversion Profiles
|
||||
# ==========================================================
|
||||
apply_profile() {
|
||||
local profile="$1"
|
||||
case "$profile" in
|
||||
hi-rate|--hi-rate)
|
||||
info "Applying high bitrate profile..."
|
||||
CRF="14"
|
||||
PRESET="veryslow"
|
||||
AUDIO_BITRATE="320k"
|
||||
;;
|
||||
portable|--portable)
|
||||
info "Applying portable/mobile profile..."
|
||||
CRF="24"
|
||||
PRESET="faster"
|
||||
AUDIO_BITRATE="128k"
|
||||
;;
|
||||
default|--default|"")
|
||||
;;
|
||||
*)
|
||||
warn "Unknown profile: $profile — ignoring."
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# ==========================================================
|
||||
# Header output
|
||||
|
|
@ -78,6 +107,81 @@ print_header() {
|
|||
echo "----------------------------------------------"
|
||||
}
|
||||
|
||||
# ==========================================================
|
||||
# Path sanitization (handles spaces, quotes, etc.)
|
||||
# ==========================================================
|
||||
safe_path() {
|
||||
local p="$1"
|
||||
printf "%s" "$p" | sed "s/'/'\\\\''/g"
|
||||
}
|
||||
|
||||
sanitize_name() {
|
||||
local name="$1"
|
||||
echo "$name" | sed 's/[^A-Za-z0-9._-]/_/g'
|
||||
}
|
||||
|
||||
# ==========================================================
|
||||
# Summary report parser
|
||||
# ==========================================================
|
||||
print_summary() {
|
||||
local log_file="$1"
|
||||
local input="$2"
|
||||
local output="$3"
|
||||
local start_time="$4"
|
||||
local end_time="$5"
|
||||
|
||||
local elapsed=$((end_time - start_time))
|
||||
local elapsed_min=$((elapsed / 60))
|
||||
local elapsed_sec=$((elapsed % 60))
|
||||
|
||||
local duration bitrate speed fps frames mux_overhead vbitrate abitrate
|
||||
duration=$(grep -Eo "time=[0-9:.]+" "$log_file" | tail -1 | cut -d= -f2)
|
||||
bitrate=$(grep -Eo "bitrate=[0-9.]+kbits/s" "$log_file" | tail -1 | awk -F= '{print $2}')
|
||||
speed=$(grep -Eo "speed=[0-9.]+x" "$log_file" | tail -1 | cut -d= -f2)
|
||||
fps=$(grep -Eo "fps=[0-9.]+" "$log_file" | tail -1 | cut -d= -f2)
|
||||
frames=$(grep -Eo "frame=[0-9]+" "$log_file" | tail -1 | awk -F= '{print $2}')
|
||||
mux_overhead=$(grep -Eo "muxing overhead: [0-9.]+%" "$log_file" | tail -1 | awk '{print $3}')
|
||||
vbitrate=$(grep -Eo "kb/s:[0-9.]+" "$log_file" | tail -1 | cut -d: -f2)
|
||||
abitrate=$(echo "$AUDIO_BITRATE" | sed 's/k//')
|
||||
|
||||
echo ""
|
||||
echo "----------------------------------------------"
|
||||
echo "Conversion Summary"
|
||||
echo "----------------------------------------------"
|
||||
echo "Input File : $input"
|
||||
echo "Output File : $output"
|
||||
echo "Log File : $log_file"
|
||||
echo "Duration : ${duration:-unknown}"
|
||||
echo "Encoding Speed : ${speed:-unknown}"
|
||||
echo "Elapsed Time : ${elapsed_min}m ${elapsed_sec}s"
|
||||
echo "Status : ✅ Successful"
|
||||
echo "----------------------------------------------"
|
||||
echo "[Technical Stats]"
|
||||
echo "Average Bitrate : ${bitrate:-N/A}"
|
||||
echo "Video Bitrate : ${vbitrate:-N/A} kb/s"
|
||||
echo "Audio Bitrate : ${abitrate:-N/A} kb/s"
|
||||
echo "Frames Encoded : ${frames:-N/A}"
|
||||
echo "FPS Achieved : ${fps:-N/A}"
|
||||
echo "Mux Overhead : ${mux_overhead:-N/A}"
|
||||
echo "CRF Setting : $CRF"
|
||||
echo "----------------------------------------------"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# ==========================================================
|
||||
# Generate timestamped log file
|
||||
# ==========================================================
|
||||
generate_logfile() {
|
||||
local output_name="$1"
|
||||
local timestamp
|
||||
timestamp=$(date +"%Y-%m-%d_%H-%M-%S")
|
||||
local base
|
||||
base=$(basename "$output_name" .mp4)
|
||||
local safe_base
|
||||
safe_base=$(sanitize_name "$base")
|
||||
echo "$LOG_DIR/${timestamp}_${safe_base}.log"
|
||||
}
|
||||
|
||||
# ==========================================================
|
||||
# Convert one file
|
||||
# ==========================================================
|
||||
|
|
@ -85,85 +189,243 @@ convert_single() {
|
|||
local input="$1"
|
||||
local output_name="$2"
|
||||
local output_path="$OUTPUT_DIR/$output_name"
|
||||
local safe_input
|
||||
safe_input="$(safe_path "$input")"
|
||||
local log_file
|
||||
log_file=$(generate_logfile "$output_name")
|
||||
local start_time end_time
|
||||
|
||||
print_header
|
||||
info "Converting single video..."
|
||||
info "Input : $input"
|
||||
info "Output: $output_path"
|
||||
info "Log : $log_file"
|
||||
|
||||
if [[ ! -f "$input" ]]; then
|
||||
error "Input file not found: $input"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
start_time=$(date +%s)
|
||||
ffmpeg -hide_banner -loglevel info -fflags +genpts \
|
||||
-i "$input" \
|
||||
-c:v "$VIDEO_CODEC" -crf "$CRF" -preset "$PRESET" \
|
||||
-c:a "$AUDIO_CODEC" -b:a "$AUDIO_BITRATE" -movflags +faststart \
|
||||
"$output_path" || { error "Conversion failed."; exit 1; }
|
||||
"$output_path" 2>&1 | tee "$log_file"
|
||||
end_time=$(date +%s)
|
||||
|
||||
ln -sf "$log_file" "$LOG_DIR/latest.log" 2>/dev/null || true
|
||||
success "Conversion complete: $output_path"
|
||||
print_summary "$log_file" "$safe_input" "$output_path" "$start_time" "$end_time"
|
||||
}
|
||||
|
||||
# ==========================================================
|
||||
# Combine multiple files
|
||||
# ==========================================================
|
||||
convert_multiple() {
|
||||
local args=("$@")
|
||||
# Rebuild args array safely to preserve quoted file paths
|
||||
local args=()
|
||||
while [[ $# -gt 0 ]]; do
|
||||
args+=("$1")
|
||||
shift
|
||||
done
|
||||
|
||||
# Ensure at least two inputs + one output
|
||||
if [[ ${#args[@]} -lt 3 ]]; then
|
||||
error "Usage: $0 convert-multiple <input1> <input2> ... <output.mp4> [--hi-rate|--portable]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Extract and verify output filename
|
||||
local output_name="${args[-1]}"
|
||||
unset 'args[-1]'
|
||||
if [[ -z "${output_name:-}" ]]; then
|
||||
warn "Output name missing — defaulting to combined_output.mp4"
|
||||
output_name="combined_output.mp4"
|
||||
fi
|
||||
|
||||
# Setup working paths
|
||||
local list_file
|
||||
list_file=$(mktemp)
|
||||
local output_path="$OUTPUT_DIR/$output_name"
|
||||
local log_file
|
||||
log_file=$(generate_logfile "$output_name")
|
||||
local start_time end_time
|
||||
|
||||
print_header
|
||||
info "Combining multiple videos..."
|
||||
info "Output: $output_path"
|
||||
info "Log : $log_file"
|
||||
|
||||
# Verify each input and build concat list
|
||||
for input in "${args[@]}"; do
|
||||
if [[ ! -f "$input" ]]; then
|
||||
error "Missing input file: $input"
|
||||
error "Missing input file: '$input'"
|
||||
rm -f "$list_file"
|
||||
exit 1
|
||||
fi
|
||||
echo "file '$input'" >> "$list_file"
|
||||
printf "file '%s'\n" "$(safe_path "$input")" >> "$list_file"
|
||||
info " + Added: $input"
|
||||
done
|
||||
echo "----------------------------------------------"
|
||||
|
||||
# Run FFmpeg and record timing
|
||||
start_time=$(date +%s)
|
||||
ffmpeg -hide_banner -loglevel info -f concat -safe 0 -i "$list_file" \
|
||||
-c:v "$VIDEO_CODEC" -crf "$CRF" -preset "$PRESET" \
|
||||
-c:a "$AUDIO_CODEC" -b:a "$AUDIO_BITRATE" -movflags +faststart \
|
||||
"$output_path" || { error "Merge failed."; rm -f "$list_file"; exit 1; }
|
||||
"$output_path" 2>&1 | tee "$log_file"
|
||||
end_time=$(date +%s)
|
||||
|
||||
# Cleanup and summary
|
||||
ln -sf "$log_file" "$LOG_DIR/latest.log" 2>/dev/null || true
|
||||
rm -f "$list_file"
|
||||
success "Combined video created: $output_path"
|
||||
print_summary "$log_file" "Multiple inputs" "$output_path" "$start_time" "$end_time"
|
||||
}
|
||||
|
||||
|
||||
# ==========================================================
|
||||
# Show concise or verbose video information (cross-platform)
|
||||
# ==========================================================
|
||||
show_videoinfo() {
|
||||
if ! command -v ffprobe >/dev/null 2>&1; then
|
||||
error "ffprobe is not installed or not in PATH."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ $# -lt 1 ]]; then
|
||||
error "Usage: $0 videoinfo <file1> [file2 ...] [--verbose]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Detect verbose flag
|
||||
local verbose=false
|
||||
for arg in "$@"; do
|
||||
[[ "$arg" == "--verbose" ]] && verbose=true
|
||||
done
|
||||
|
||||
for input in "$@"; do
|
||||
[[ "$input" == "--verbose" ]] && continue
|
||||
if [[ ! -f "$input" ]]; then
|
||||
error "File not found: $input"
|
||||
continue
|
||||
fi
|
||||
|
||||
echo "----------------------------------------------"
|
||||
echo "File: $input"
|
||||
echo "----------------------------------------------"
|
||||
|
||||
if $verbose; then
|
||||
ffprobe -v error \
|
||||
-show_entries format=filename,format_name,duration,size,bit_rate \
|
||||
-show_streams \
|
||||
-of default=noprint_wrappers=1:nokey=0 \
|
||||
"$input" | sed 's/^/ /'
|
||||
else
|
||||
# Collect metadata safely
|
||||
local duration size format vcodec acodec width height fps profile pix_fmt dar sar vbitrate abitrate channels arate bitrate
|
||||
|
||||
duration=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$input")
|
||||
size=$(ffprobe -v error -show_entries format=size -of default=noprint_wrappers=1:nokey=1 "$input")
|
||||
format=$(ffprobe -v error -show_entries format=format_name -of default=noprint_wrappers=1:nokey=1 "$input")
|
||||
bitrate=$(ffprobe -v error -show_entries format=bit_rate -of default=noprint_wrappers=1:nokey=1 "$input")
|
||||
|
||||
vcodec=$(ffprobe -v error -select_streams v:0 -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 "$input")
|
||||
profile=$(ffprobe -v error -select_streams v:0 -show_entries stream=profile -of default=noprint_wrappers=1:nokey=1 "$input")
|
||||
width=$(ffprobe -v error -select_streams v:0 -show_entries stream=width -of default=noprint_wrappers=1:nokey=1 "$input")
|
||||
height=$(ffprobe -v error -select_streams v:0 -show_entries stream=height -of default=noprint_wrappers=1:nokey=1 "$input")
|
||||
fps=$(ffprobe -v error -select_streams v:0 -show_entries stream=r_frame_rate -of default=noprint_wrappers=1:nokey=1 "$input" | awk -F'/' '{if ($2>0) printf "%.2f", $1/$2; else print $1}')
|
||||
pix_fmt=$(ffprobe -v error -select_streams v:0 -show_entries stream=pix_fmt -of default=noprint_wrappers=1:nokey=1 "$input")
|
||||
dar=$(ffprobe -v error -select_streams v:0 -show_entries stream=display_aspect_ratio -of default=noprint_wrappers=1:nokey=1 "$input")
|
||||
sar=$(ffprobe -v error -select_streams v:0 -show_entries stream=sample_aspect_ratio -of default=noprint_wrappers=1:nokey=1 "$input")
|
||||
vbitrate=$(ffprobe -v error -select_streams v:0 -show_entries stream=bit_rate -of default=noprint_wrappers=1:nokey=1 "$input")
|
||||
|
||||
acodec=$(ffprobe -v error -select_streams a:0 -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 "$input")
|
||||
abitrate=$(ffprobe -v error -select_streams a:0 -show_entries stream=bit_rate -of default=noprint_wrappers=1:nokey=1 "$input")
|
||||
channels=$(ffprobe -v error -select_streams a:0 -show_entries stream=channels -of default=noprint_wrappers=1:nokey=1 "$input")
|
||||
arate=$(ffprobe -v error -select_streams a:0 -show_entries stream=sample_rate -of default=noprint_wrappers=1:nokey=1 "$input")
|
||||
|
||||
# Compute duration minutes without bc
|
||||
local mins secs
|
||||
mins=$(( ${duration%.*} / 60 ))
|
||||
secs=$(( ${duration%.*} % 60 ))
|
||||
|
||||
# Simple size + bitrate formatting (cross-platform safe)
|
||||
local size_mb=$(( size / 1048576 ))
|
||||
local bitrate_mbps=$(( bitrate / 1000000 ))
|
||||
local vbitrate_mbps=$(( vbitrate / 1000000 ))
|
||||
local abitrate_kbps=$(( abitrate / 1000 ))
|
||||
|
||||
echo " Duration: ${duration:-N/A} sec (${mins}m ${secs}s)"
|
||||
echo " Size: ${size_mb} MB"
|
||||
echo " Container: ${format:-N/A}"
|
||||
echo " Video Codec: ${vcodec:-N/A} (${profile:-N/A})"
|
||||
echo " Resolution: ${width:-N/A}x${height:-N/A} @ ${fps:-N/A} fps"
|
||||
echo " Aspect Ratio: ${dar:-N/A} (SAR ${sar:-N/A})"
|
||||
echo " Pixel Format: ${pix_fmt:-N/A}"
|
||||
echo " Video Bitrate: ${vbitrate_mbps} Mbps"
|
||||
echo " Audio Codec: ${acodec:-N/A}"
|
||||
echo " Audio: ${channels:-N/A} ch @ ${arate:-N/A} Hz"
|
||||
echo " Audio Bitrate: ${abitrate_kbps} kbps"
|
||||
echo " Overall Rate: ${bitrate_mbps} Mbps"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
# ==========================================================
|
||||
# Dispatcher
|
||||
# ==========================================================
|
||||
case "${1:-}" in
|
||||
convert-single)
|
||||
shift
|
||||
if [[ $# -ne 2 ]]; then
|
||||
error "Usage: $0 convert-single <input> <output.mp4>"
|
||||
if [[ $# -lt 2 ]]; then
|
||||
error "Usage: $0 convert-single <input> <output.mp4> [--hi-rate|--portable]"
|
||||
exit 1
|
||||
fi
|
||||
convert_single "$@"
|
||||
# Optional profile flag
|
||||
if [[ $# -eq 3 ]]; then
|
||||
apply_profile "${3:-}"
|
||||
fi
|
||||
convert_single "$1" "$2"
|
||||
;;
|
||||
convert-multiple)
|
||||
shift
|
||||
if [[ $# -lt 3 ]]; then
|
||||
error "Usage: $0 convert-multiple <input1> <input2> ... <output.mp4>"
|
||||
error "Usage: $0 convert-multiple <input1> <input2> ... <output.mp4> [--hi-rate|--portable]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Handle optional profile flag
|
||||
last_arg="${@: -1}"
|
||||
case "$last_arg" in
|
||||
--hi-rate|--portable)
|
||||
apply_profile "$last_arg"
|
||||
set -- "${@:1:$(($#-1))}"
|
||||
;;
|
||||
esac
|
||||
|
||||
convert_multiple "$@"
|
||||
;;
|
||||
videoinfo|--videoinfo|--fileinfo)
|
||||
shift
|
||||
show_videoinfo "$@"
|
||||
;;
|
||||
*)
|
||||
echo "Video Tools v$VERSION"
|
||||
echo "Usage:"
|
||||
echo " $0 convert-single <input> <output.mp4>"
|
||||
echo " $0 convert-multiple <input1> <input2> ... <output.mp4>"
|
||||
echo " $0 convert-single <input> <output.mp4> [--hi-rate|--portable]"
|
||||
echo " $0 convert-multiple <input1> <input2> ... <output.mp4> [--hi-rate|--portable]"
|
||||
echo " $0 videoinfo <file1> [file2 ...]"
|
||||
echo ""
|
||||
echo "Profiles:"
|
||||
echo " --hi-rate Highest bitrate and quality (CRF 14, 320k audio)"
|
||||
echo " --portable Smaller file size for mobile (CRF 24, 128k audio)"
|
||||
echo ""
|
||||
echo "All outputs will be saved in: $OUTPUT_DIR"
|
||||
echo "Logs stored in: $LOG_DIR"
|
||||
;;
|
||||
esac
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user