Add cross-platform videoinfo command with verbose option
This commit is contained in:
parent
a353b86677
commit
b8c07a4247
79
Makefile
79
Makefile
|
|
@ -1,37 +1,76 @@
|
||||||
# VideoTools Makefile
|
# root/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
|
PREFIX ?= /usr/local
|
||||||
INSTALL_DIR = $(PREFIX)/bin
|
INSTALL_DIR = $(PREFIX)/bin
|
||||||
DOC_DIR = $(PREFIX)/share/doc/videotools
|
DOC_DIR = $(PREFIX)/share/doc/videotools
|
||||||
|
|
||||||
SCRIPT = video-tools.sh
|
SCRIPT = video-tools.sh
|
||||||
DOCS = docs
|
DOCS = docs
|
||||||
|
VERSION_FILE = VERSION
|
||||||
|
|
||||||
install:
|
# ------------------------
|
||||||
|
# Installation
|
||||||
|
# ------------------------
|
||||||
|
|
||||||
|
install: verify
|
||||||
@echo "Installing VideoTools..."
|
@echo "Installing VideoTools..."
|
||||||
mkdir -p "$(INSTALL_DIR)"
|
@mkdir -p "$(INSTALL_DIR)"
|
||||||
cp "$(SCRIPT)" "$(INSTALL_DIR)/video-tools"
|
@install -m 755 "$(SCRIPT)" "$(INSTALL_DIR)/video-tools"
|
||||||
chmod +x "$(INSTALL_DIR)/video-tools"
|
@echo "✔ Installed script to $(INSTALL_DIR)/video-tools"
|
||||||
@echo "Copied script to $(INSTALL_DIR)/video-tools"
|
|
||||||
|
|
||||||
mkdir -p "$(DOC_DIR)"
|
@mkdir -p "$(DOC_DIR)"
|
||||||
cp -r "$(DOCS)"/* "$(DOC_DIR)/"
|
@cp -r "$(DOCS)"/* "$(DOC_DIR)/"
|
||||||
@echo "Documentation installed to $(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:
|
uninstall:
|
||||||
@echo "Removing VideoTools..."
|
@echo "Removing VideoTools..."
|
||||||
rm -f "$(INSTALL_DIR)/video-tools"
|
@rm -f "$(INSTALL_DIR)/video-tools"
|
||||||
rm -rf "$(DOC_DIR)"
|
@rm -rf "$(DOC_DIR)"
|
||||||
@echo "VideoTools uninstalled."
|
@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
|
||||||
|
@echo "✔ Environment OK."
|
||||||
|
@echo ""
|
||||||
|
|
||||||
|
# ------------------------
|
||||||
|
# Documentation
|
||||||
|
# ------------------------
|
||||||
|
|
||||||
docs:
|
docs:
|
||||||
@echo "Opening documentation..."
|
@echo "Available documentation files:"
|
||||||
@ls -1 $(DOCS)
|
@ls -1 "$(DOCS)"
|
||||||
|
|
||||||
|
# ------------------------
|
||||||
|
# Help
|
||||||
|
# ------------------------
|
||||||
|
|
||||||
help:
|
help:
|
||||||
@echo "Available targets:"
|
@echo "Available targets:"
|
||||||
@echo " make install Install the toolkit system-wide"
|
@echo " make install Install the toolkit system-wide"
|
||||||
@echo " make uninstall Remove the toolkit"
|
@echo " make uninstall Remove the toolkit"
|
||||||
@echo " make docs List documentation files"
|
@echo " make verify Check if FFmpeg and environment are ready"
|
||||||
@echo " make help Show this message"
|
@echo " make docs List documentation files"
|
||||||
|
@echo " make help Show this message"
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
# CLI Function Reference
|
# docs/CLI_Functions.md
|
||||||
|
# CLI Function Reference (v0.1.0)
|
||||||
|
|
||||||
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.
|
Each command can be run from any terminal once the tool is installed.
|
||||||
|
|
@ -12,7 +13,7 @@ Each command can be run from any terminal once the tool is installed.
|
||||||
| `convert-single` | `video-tools convert-single <input> <output.mp4>` | Converts a single video to MP4. |
|
| `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. |
|
| `convert-multiple` | `video-tools convert-multiple <input1> <input2> ... <output.mp4>` | Combines multiple video files into one MP4. |
|
||||||
|
|
||||||
All outputs are saved in your default `~/Videos` folder.
|
All outputs are saved in your default `~/Videos` folder, unless overridden in `config/config.json`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -21,7 +22,7 @@ All outputs are saved in your default `~/Videos` folder.
|
||||||
### 1. convert-single
|
### 1. convert-single
|
||||||
|
|
||||||
**Purpose**
|
**Purpose**
|
||||||
Convert a single input video file into an MP4 with modern compression and audio standards.
|
Convert a single input video file into an MP4 using modern compression and audio standards.
|
||||||
|
|
||||||
**Usage**
|
**Usage**
|
||||||
```bash
|
```bash
|
||||||
|
|
@ -42,14 +43,15 @@ video-tools convert-single \
|
||||||
|
|
||||||
**Behavior**
|
**Behavior**
|
||||||
- Converts older formats (AVI, MPG, MOV, MKV, etc.) into MP4.
|
- Converts older formats (AVI, MPG, MOV, MKV, etc.) into MP4.
|
||||||
- Ensures output uses the H.264 codec (libx264) and AAC audio.
|
- Uses H.264 (`libx264`) for video and AAC for audio.
|
||||||
- Rebuilds timestamps to avoid sync issues.
|
- Rebuilds timestamps with `-fflags +genpts` to prevent sync issues.
|
||||||
- Adds `+faststart` flag for quicker playback when streamed or loaded in players.
|
- Adds `-movflags +faststart` to improve playback and streaming performance.
|
||||||
|
- Displays detailed FFmpeg progress and conversion status.
|
||||||
|
|
||||||
**When to use**
|
**When to Use**
|
||||||
- When you want to upgrade old videos to a more efficient format.
|
- To modernize older video files.
|
||||||
- When a single video won’t play on mobile or modern devices.
|
- When a video fails to play properly on mobile or modern devices.
|
||||||
- To reduce file size without losing visible quality.
|
- To reduce file size while retaining visual quality.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -78,14 +80,15 @@ video-tools convert-multiple \
|
||||||
```
|
```
|
||||||
|
|
||||||
**Behavior**
|
**Behavior**
|
||||||
- Reads all listed files in order and merges them seamlessly.
|
- Merges all listed videos sequentially.
|
||||||
- Each input is re-encoded using the same H.264/AAC settings.
|
- Re-encodes each input using the same H.264/AAC settings.
|
||||||
- Temporary file list is automatically created and deleted.
|
- Creates and deletes a temporary file list automatically.
|
||||||
- Logs detailed FFmpeg progress to the terminal.
|
- Displays each added file and overall progress in the terminal.
|
||||||
|
- Ensures the output file is playable immediately after completion.
|
||||||
|
|
||||||
**When to use**
|
**When to Use**
|
||||||
- When combining multi-part video discs, episodes, or scene splits.
|
- To combine multi-part video discs, episodes, or segmented clips.
|
||||||
- When creating a single playable MP4 from segmented source material.
|
- When creating a single playback file from multiple source files.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
# Conversion Settings
|
# docs/Conversion_Settings.md
|
||||||
|
# Conversion Settings (v0.1.0)
|
||||||
|
|
||||||
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:
|
All conversions produce:
|
||||||
```
|
```
|
||||||
Format: MP4
|
Format: MP4
|
||||||
|
|
@ -13,10 +15,10 @@ Video Codec: H.264 (libx264)
|
||||||
Audio Codec: AAC
|
Audio Codec: AAC
|
||||||
```
|
```
|
||||||
|
|
||||||
MP4 was chosen because:
|
**Why MP4?**
|
||||||
- It’s universally supported across modern devices.
|
- Universally supported across modern devices.
|
||||||
- It balances size and compatibility well.
|
- Balances quality, compression, and compatibility.
|
||||||
- H.264 encoding provides excellent quality at smaller bitrates.
|
- H.264 encoding provides excellent visual quality at modest bitrates.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -25,8 +27,8 @@ MP4 was chosen because:
|
||||||
| Parameter | Value | Purpose |
|
| Parameter | Value | Purpose |
|
||||||
|------------|--------|----------|
|
|------------|--------|----------|
|
||||||
| `-c:v libx264` | H.264 video encoding | Modern, efficient codec with wide hardware support |
|
| `-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 |
|
| `-crf 18` | Constant Rate Factor | Maintains near-lossless visual quality (lower = better) |
|
||||||
| `-preset slow` | Encoding preset | Improves compression efficiency; trades some speed |
|
| `-preset slow` | Encoding preset | Improves compression efficiency at moderate CPU cost |
|
||||||
| `-c:a aac` | Audio codec | Standard high-quality stereo audio |
|
| `-c:a aac` | Audio codec | Standard high-quality stereo audio |
|
||||||
| `-b:a 192k` | Audio bitrate | Balances fidelity and file size |
|
| `-b:a 192k` | Audio bitrate | Balances fidelity and file size |
|
||||||
| `-movflags +faststart` | MP4 optimization | Enables faster playback start in players or web streams |
|
| `-movflags +faststart` | MP4 optimization | Enables faster playback start in players or web streams |
|
||||||
|
|
@ -36,38 +38,39 @@ MP4 was chosen because:
|
||||||
|
|
||||||
## Quality vs. File Size
|
## Quality vs. File Size
|
||||||
|
|
||||||
The CRF scale (used by FFmpeg) defines quality and compression balance:
|
The **CRF scale** (used by FFmpeg) defines the balance between quality and compression:
|
||||||
|
|
||||||
| CRF | Description | Typical Use |
|
| CRF | Description | Typical Use |
|
||||||
|------|-------------|--------------|
|
|------|-------------|--------------|
|
||||||
| 14–16 | Near lossless | Archival or professional mastering |
|
| 14–16 | Near lossless | Archival or professional mastering |
|
||||||
| 18–20 | High quality | Everyday use, visually lossless |
|
| 18–20 | High quality | Everyday use, visually lossless |
|
||||||
| 21–24 | Medium quality | Small file sizes, light compression |
|
| 21–24 | Medium quality | Smaller file sizes with light compression |
|
||||||
| 25+ | Low quality | Fast compression, heavy size reduction |
|
| 25+ | Low quality | Fast compression, noticeable loss |
|
||||||
|
|
||||||
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.
|
**Default CRF: 18**
|
||||||
|
Provides visually lossless results while reducing most AVI/MPG files to **40–60% smaller sizes**.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Why Preset "slow"
|
## Why Use Preset “slow”
|
||||||
|
|
||||||
The preset defines encoding effort vs. compression efficiency.
|
The preset defines the trade-off between encoding speed and compression efficiency.
|
||||||
Options range from `ultrafast` → `veryslow`.
|
Range: `ultrafast` → `veryslow`.
|
||||||
|
|
||||||
- **slow** provides strong compression without extreme CPU time.
|
- `slow` offers excellent compression without excessive CPU time.
|
||||||
- Encoding speed is roughly 2–3× real-time on a midrange CPU.
|
- Typical speed: ~2–3× real-time on a midrange CPU.
|
||||||
- File sizes are typically 10–20% smaller than `medium` preset at the same quality.
|
- Output files are usually **10–20% smaller** than with `medium` preset at the same quality.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Audio Strategy
|
## Audio Strategy
|
||||||
|
|
||||||
AAC at 192k is chosen for:
|
**AAC at 192k** is chosen for:
|
||||||
- Wide playback compatibility (phones, TVs, players).
|
- Broad device compatibility (phones, TVs, web players).
|
||||||
- Transparent stereo sound for most sources.
|
- Transparent stereo sound for most content.
|
||||||
- Reasonable storage size (~2MB/minute of stereo audio).
|
- Efficient storage (~2 MB/min of stereo audio).
|
||||||
|
|
||||||
If future needs arise, the tool can later support:
|
Future options may include:
|
||||||
- `-c:a copy` for untouched audio streams.
|
- `-c:a copy` for untouched audio streams.
|
||||||
- `-b:a 320k` for high-fidelity preservation.
|
- `-b:a 320k` for high-fidelity preservation.
|
||||||
|
|
||||||
|
|
@ -75,13 +78,12 @@ If future needs arise, the tool can later support:
|
||||||
|
|
||||||
## Color Space & Scaling
|
## Color Space & Scaling
|
||||||
|
|
||||||
No scaling is applied by default.
|
No scaling is applied by default — the video retains its original resolution and color profile.
|
||||||
The video retains original resolution and color profile.
|
|
||||||
|
|
||||||
Upscaling and filtering will be handled in a separate command (`upscale-video`) in future versions, with support for:
|
Planned future command: `upscale-video`, supporting:
|
||||||
- FFmpeg’s `scale` and `zscale` filters.
|
- FFmpeg’s `scale` and `zscale` filters.
|
||||||
- `lanczos` resampling (for sharp, clean upscale).
|
- `lanczos` resampling for sharp, clean upscales.
|
||||||
- Optional integration with ML-based models (Real-ESRGAN, waifu2x).
|
- Optional ML upscaling (Real-ESRGAN, waifu2x).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
# Video Tools CLI
|
# docs/README.md
|
||||||
|
# Video Tools CLI (v0.1.0)
|
||||||
|
|
||||||
A simple command-line utility for video conversion and merging using FFmpeg.
|
A simple command-line utility for video conversion and merging using FFmpeg.
|
||||||
Designed for personal use and sharing with friends.
|
Designed for personal use and sharing with friends.
|
||||||
|
|
@ -38,7 +39,7 @@ sudo apt install ffmpeg # For Debian or Ubuntu
|
||||||
|
|
||||||
1. Clone or copy the repository:
|
1. Clone or copy the repository:
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/YourName/VideoTools.git
|
git clone https://git.leaktechnologies.dev/Leak_Technologies/VideoTools.git
|
||||||
cd VideoTools
|
cd VideoTools
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -67,10 +68,11 @@ video-tools convert-single "input.avi" "output.mp4"
|
||||||
| Video codec | `libx264` | High-quality H.264 encoding |
|
| Video codec | `libx264` | High-quality H.264 encoding |
|
||||||
| Audio codec | `aac` | High-quality AAC stereo audio |
|
| Audio codec | `aac` | High-quality AAC stereo audio |
|
||||||
| Quality (CRF) | 18 | Visually lossless quality |
|
| Quality (CRF) | 18 | Visually lossless quality |
|
||||||
| Preset | slow | Balances speed and compression |
|
| Preset | `slow` | Balances speed and compression |
|
||||||
| Audio bitrate | 192k | High-quality stereo output |
|
| Audio bitrate | 192k | High-quality stereo output |
|
||||||
|
|
||||||
These defaults prioritize quality while still reducing file sizes compared to older formats such as AVI or MPG.
|
These defaults prioritize quality while still reducing file sizes compared to older formats such as AVI or MPG.
|
||||||
|
For more details, see [`docs/Conversion_Settings.md`](./Conversion_Settings.md).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -84,7 +86,7 @@ video-tools convert-single \
|
||||||
"Example Movie.mp4"
|
"Example Movie.mp4"
|
||||||
```
|
```
|
||||||
|
|
||||||
Output:
|
**Output**
|
||||||
```
|
```
|
||||||
/home/stu/Videos/Example Movie.mp4
|
/home/stu/Videos/Example Movie.mp4
|
||||||
```
|
```
|
||||||
|
|
@ -101,7 +103,7 @@ video-tools convert-multiple \
|
||||||
"Example Movie Combined.mp4"
|
"Example Movie Combined.mp4"
|
||||||
```
|
```
|
||||||
|
|
||||||
Output:
|
**Output**
|
||||||
```
|
```
|
||||||
/home/stu/Videos/Example Movie Combined.mp4
|
/home/stu/Videos/Example Movie Combined.mp4
|
||||||
```
|
```
|
||||||
|
|
@ -123,15 +125,29 @@ Output:
|
||||||
|
|
||||||
| Feature | Status |
|
| Feature | Status |
|
||||||
|----------|--------|
|
|----------|--------|
|
||||||
| convert-single | ✅ Done |
|
| `convert-single` | ✅ Done |
|
||||||
| convert-multiple | ✅ Done |
|
| `convert-multiple` | ✅ Done |
|
||||||
| upscale-video | 🔜 Planned |
|
| `upscale-video` | 🔜 Planned |
|
||||||
| batch conversion | 🔜 Planned |
|
| `batch conversion` | 🔜 Planned |
|
||||||
| automatic format detection | 🔜 Planned |
|
| `automatic format detection` | 🔜 Planned |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Documentation Index
|
||||||
|
|
||||||
|
| File | Description |
|
||||||
|
|------|--------------|
|
||||||
|
| [`docs/CLI_Functions.md`](./CLI_Functions.md) | Command usage reference |
|
||||||
|
| [`docs/Conversion_Settings.md`](./Conversion_Settings.md) | Technical breakdown of FFmpeg defaults |
|
||||||
|
| [`docs/Upscale.md`](./Upscale.md) | Planned module for loss-minimized video upscaling |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Free for personal use.
|
Free for personal use.
|
||||||
You can modify or share this tool with anyone.
|
You may modify or share this tool with anyone.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
End of File
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
# Upscale Module (Planned)
|
# docs/Upscale.md
|
||||||
|
# Upscale Module (Planned) — v0.1.0
|
||||||
|
|
||||||
The `upscale-video` command will provide loss-minimized video upscaling.
|
The `upscale-video` command will provide loss-minimized video upscaling.
|
||||||
|
|
||||||
|
|
@ -11,7 +12,7 @@ This module will allow upscaling of existing videos to higher resolutions such a
|
||||||
- 1080p (Full HD)
|
- 1080p (Full HD)
|
||||||
- 2160p (4K)
|
- 2160p (4K)
|
||||||
|
|
||||||
It will use FFmpeg’s native scaling filters first and optionally integrate machine learning tools later.
|
It will begin with FFmpeg’s native scaling filters and may later support machine learning-based methods.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -33,9 +34,9 @@ Optional parameters:
|
||||||
|
|
||||||
## Default Behavior
|
## Default Behavior
|
||||||
|
|
||||||
If no resolution is provided, the tool will upscale intelligently to the nearest standard resolution above the input video.
|
If no explicit resolution is provided, the tool will upscale intelligently to the nearest standard resolution above the source.
|
||||||
|
|
||||||
Example:
|
**Examples:**
|
||||||
- Input: 960×540 → Output: 1280×720
|
- Input: 960×540 → Output: 1280×720
|
||||||
- Input: 1280×720 → Output: 1920×1080
|
- Input: 1280×720 → Output: 1920×1080
|
||||||
|
|
||||||
|
|
@ -50,9 +51,10 @@ 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
|
-c:v libx264 -crf 18 -preset slow -c:a aac -b:a 192k output_1080p.mp4
|
||||||
```
|
```
|
||||||
|
|
||||||
- `scale=1920:1080:flags=lanczos` → high-quality resampling
|
**Explanation:**
|
||||||
- `lanczos` offers sharp, low-artifact upscale
|
- `scale=1920:1080:flags=lanczos` → performs high-quality resampling.
|
||||||
- Later versions may support `zscale` or ML-based filters
|
- `lanczos` produces sharp, low-artifact results.
|
||||||
|
- Future versions may introduce `zscale` or machine-learning upscalers.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -60,9 +62,9 @@ ffmpeg -i input.mp4 -vf scale=1920:1080:flags=lanczos \
|
||||||
|
|
||||||
| Feature | Status |
|
| Feature | Status |
|
||||||
|----------|--------|
|
|----------|--------|
|
||||||
| FFmpeg scaler (lanczos) | 🔜 Planned |
|
| FFmpeg scaler (`lanczos`) | 🔜 Planned |
|
||||||
| ML-based upscaling (Real-ESRGAN / waifu2x) | 🚧 Research |
|
| ML-based upscaling (Real-ESRGAN / waifu2x) | 🚧 Research |
|
||||||
| Auto resolution detection | 🔜 Planned |
|
| Auto-resolution detection | 🔜 Planned |
|
||||||
| GPU acceleration support | 🔜 Planned |
|
| GPU acceleration support | 🔜 Planned |
|
||||||
| Configurable presets | 🔜 Planned |
|
| Configurable presets | 🔜 Planned |
|
||||||
|
|
||||||
|
|
|
||||||
296
video-tools.sh
296
video-tools.sh
|
|
@ -1,17 +1,19 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
#
|
# video-tools.sh
|
||||||
|
# ----------------------------------------------------------
|
||||||
# Simple FFmpeg CLI Toolset
|
# Simple FFmpeg CLI Toolset
|
||||||
# -------------------------
|
|
||||||
# Provides easy commands for single or multi-file video conversion.
|
# Provides easy commands for single or multi-file video conversion.
|
||||||
# Works on Linux and Windows (Git Bash / WSL) as long as ffmpeg is installed.
|
# Works on Linux and Windows (Git Bash / WSL) as long as ffmpeg is installed.
|
||||||
#
|
# ----------------------------------------------------------
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
# ==========================================================
|
# ==========================================================
|
||||||
# Configuration system
|
# 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
|
# Default configuration
|
||||||
|
|
@ -22,7 +24,7 @@ AUDIO_CODEC="aac"
|
||||||
CRF="18" # lower = higher quality
|
CRF="18" # lower = higher quality
|
||||||
PRESET="slow" # slower = better compression
|
PRESET="slow" # slower = better compression
|
||||||
AUDIO_BITRATE="192k"
|
AUDIO_BITRATE="192k"
|
||||||
VERSION="0.1.0"
|
VERSION="0.1.1"
|
||||||
|
|
||||||
# ==========================================================
|
# ==========================================================
|
||||||
# Utility: Colour logging
|
# Utility: Colour logging
|
||||||
|
|
@ -39,7 +41,7 @@ warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
||||||
error() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
|
error() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
|
||||||
|
|
||||||
# ==========================================================
|
# ==========================================================
|
||||||
# Check dependencies early
|
# Dependency check
|
||||||
# ==========================================================
|
# ==========================================================
|
||||||
if ! command -v ffmpeg >/dev/null 2>&1; then
|
if ! command -v ffmpeg >/dev/null 2>&1; then
|
||||||
error "ffmpeg is not installed or not in PATH."
|
error "ffmpeg is not installed or not in PATH."
|
||||||
|
|
@ -62,6 +64,33 @@ else
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mkdir -p "$OUTPUT_DIR" || { error "Failed to create output directory $OUTPUT_DIR"; exit 1; }
|
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
|
# Header output
|
||||||
|
|
@ -78,6 +107,81 @@ print_header() {
|
||||||
echo "----------------------------------------------"
|
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
|
# Convert one file
|
||||||
# ==========================================================
|
# ==========================================================
|
||||||
|
|
@ -85,85 +189,243 @@ convert_single() {
|
||||||
local input="$1"
|
local input="$1"
|
||||||
local output_name="$2"
|
local output_name="$2"
|
||||||
local output_path="$OUTPUT_DIR/$output_name"
|
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
|
print_header
|
||||||
info "Converting single video..."
|
info "Converting single video..."
|
||||||
info "Input : $input"
|
info "Input : $input"
|
||||||
info "Output: $output_path"
|
info "Output: $output_path"
|
||||||
|
info "Log : $log_file"
|
||||||
|
|
||||||
if [[ ! -f "$input" ]]; then
|
if [[ ! -f "$input" ]]; then
|
||||||
error "Input file not found: $input"
|
error "Input file not found: $input"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
start_time=$(date +%s)
|
||||||
ffmpeg -hide_banner -loglevel info -fflags +genpts \
|
ffmpeg -hide_banner -loglevel info -fflags +genpts \
|
||||||
-i "$input" \
|
-i "$input" \
|
||||||
-c:v "$VIDEO_CODEC" -crf "$CRF" -preset "$PRESET" \
|
-c:v "$VIDEO_CODEC" -crf "$CRF" -preset "$PRESET" \
|
||||||
-c:a "$AUDIO_CODEC" -b:a "$AUDIO_BITRATE" -movflags +faststart \
|
-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"
|
success "Conversion complete: $output_path"
|
||||||
|
print_summary "$log_file" "$safe_input" "$output_path" "$start_time" "$end_time"
|
||||||
}
|
}
|
||||||
|
|
||||||
# ==========================================================
|
# ==========================================================
|
||||||
# Combine multiple files
|
# Combine multiple files
|
||||||
# ==========================================================
|
# ==========================================================
|
||||||
convert_multiple() {
|
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]}"
|
local output_name="${args[-1]}"
|
||||||
unset '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
|
local list_file
|
||||||
list_file=$(mktemp)
|
list_file=$(mktemp)
|
||||||
local output_path="$OUTPUT_DIR/$output_name"
|
local output_path="$OUTPUT_DIR/$output_name"
|
||||||
|
local log_file
|
||||||
|
log_file=$(generate_logfile "$output_name")
|
||||||
|
local start_time end_time
|
||||||
|
|
||||||
print_header
|
print_header
|
||||||
info "Combining multiple videos..."
|
info "Combining multiple videos..."
|
||||||
|
info "Output: $output_path"
|
||||||
|
info "Log : $log_file"
|
||||||
|
|
||||||
|
# Verify each input and build concat list
|
||||||
for input in "${args[@]}"; do
|
for input in "${args[@]}"; do
|
||||||
if [[ ! -f "$input" ]]; then
|
if [[ ! -f "$input" ]]; then
|
||||||
error "Missing input file: $input"
|
error "Missing input file: '$input'"
|
||||||
rm -f "$list_file"
|
rm -f "$list_file"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
echo "file '$input'" >> "$list_file"
|
printf "file '%s'\n" "$(safe_path "$input")" >> "$list_file"
|
||||||
info " + Added: $input"
|
info " + Added: $input"
|
||||||
done
|
done
|
||||||
echo "----------------------------------------------"
|
echo "----------------------------------------------"
|
||||||
|
|
||||||
|
# Run FFmpeg and record timing
|
||||||
|
start_time=$(date +%s)
|
||||||
ffmpeg -hide_banner -loglevel info -f concat -safe 0 -i "$list_file" \
|
ffmpeg -hide_banner -loglevel info -f concat -safe 0 -i "$list_file" \
|
||||||
-c:v "$VIDEO_CODEC" -crf "$CRF" -preset "$PRESET" \
|
-c:v "$VIDEO_CODEC" -crf "$CRF" -preset "$PRESET" \
|
||||||
-c:a "$AUDIO_CODEC" -b:a "$AUDIO_BITRATE" -movflags +faststart \
|
-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"
|
rm -f "$list_file"
|
||||||
success "Combined video created: $output_path"
|
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
|
# Dispatcher
|
||||||
# ==========================================================
|
# ==========================================================
|
||||||
case "${1:-}" in
|
case "${1:-}" in
|
||||||
convert-single)
|
convert-single)
|
||||||
shift
|
shift
|
||||||
if [[ $# -ne 2 ]]; then
|
if [[ $# -lt 2 ]]; then
|
||||||
error "Usage: $0 convert-single <input> <output.mp4>"
|
error "Usage: $0 convert-single <input> <output.mp4> [--hi-rate|--portable]"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
convert_single "$@"
|
# Optional profile flag
|
||||||
|
if [[ $# -eq 3 ]]; then
|
||||||
|
apply_profile "${3:-}"
|
||||||
|
fi
|
||||||
|
convert_single "$1" "$2"
|
||||||
;;
|
;;
|
||||||
convert-multiple)
|
convert-multiple)
|
||||||
shift
|
shift
|
||||||
if [[ $# -lt 3 ]]; then
|
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
|
exit 1
|
||||||
fi
|
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 "$@"
|
convert_multiple "$@"
|
||||||
;;
|
;;
|
||||||
|
videoinfo|--videoinfo|--fileinfo)
|
||||||
|
shift
|
||||||
|
show_videoinfo "$@"
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
echo "Video Tools v$VERSION"
|
echo "Video Tools v$VERSION"
|
||||||
echo "Usage:"
|
echo "Usage:"
|
||||||
echo " $0 convert-single <input> <output.mp4>"
|
echo " $0 convert-single <input> <output.mp4> [--hi-rate|--portable]"
|
||||||
echo " $0 convert-multiple <input1> <input2> ... <output.mp4>"
|
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 ""
|
||||||
echo "All outputs will be saved in: $OUTPUT_DIR"
|
echo "All outputs will be saved in: $OUTPUT_DIR"
|
||||||
|
echo "Logs stored in: $LOG_DIR"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user