audio-video
SKILL.md
Audio & Video Processing Skill
Complete guide for audio and video processing.
Quick Reference
FFmpeg Commands
| Task | Command |
|---|---|
| Convert | ffmpeg -i input.mp4 output.webm |
| Extract Audio | ffmpeg -i video.mp4 -vn audio.mp3 |
| Thumbnail | ffmpeg -i video.mp4 -ss 5 -frames:v 1 thumb.jpg |
| Resize | ffmpeg -i input.mp4 -vf scale=1280:720 output.mp4 |
| Compress | ffmpeg -i input.mp4 -crf 28 output.mp4 |
Common Formats
Video: MP4, WebM, MKV, AVI, MOV
Audio: MP3, AAC, WAV, FLAC, OGG
Codecs: H.264, H.265/HEVC, VP9, AV1
1. FFmpeg Basics
Installation
# Ubuntu/Debian
sudo apt install ffmpeg
# macOS
brew install ffmpeg
# Windows (Chocolatey)
choco install ffmpeg
Basic Conversion
# Video format conversion
ffmpeg -i input.avi output.mp4
# Audio format conversion
ffmpeg -i input.wav output.mp3
# With codec specification
ffmpeg -i input.mp4 -c:v libx264 -c:a aac output.mp4
Video Quality Control
# CRF (Constant Rate Factor) - 0-51, lower = better quality
ffmpeg -i input.mp4 -c:v libx264 -crf 23 output.mp4
# Bitrate control
ffmpeg -i input.mp4 -c:v libx264 -b:v 2M output.mp4
# Two-pass encoding for better quality
ffmpeg -i input.mp4 -c:v libx264 -b:v 2M -pass 1 -f null /dev/null
ffmpeg -i input.mp4 -c:v libx264 -b:v 2M -pass 2 output.mp4
2. Video Processing
Resize and Scale
# Scale to specific resolution
ffmpeg -i input.mp4 -vf "scale=1920:1080" output.mp4
# Scale maintaining aspect ratio
ffmpeg -i input.mp4 -vf "scale=1280:-1" output.mp4 # Auto height
ffmpeg -i input.mp4 -vf "scale=-1:720" output.mp4 # Auto width
# Scale with padding (letterbox)
ffmpeg -i input.mp4 -vf "scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2" output.mp4
Trim and Cut
# Cut from timestamp to timestamp
ffmpeg -i input.mp4 -ss 00:01:00 -to 00:02:00 -c copy output.mp4
# Cut with duration
ffmpeg -i input.mp4 -ss 00:01:00 -t 30 -c copy output.mp4
# Fast seek (put -ss before input)
ffmpeg -ss 00:01:00 -i input.mp4 -t 30 -c copy output.mp4
Concatenate Videos
# Create file list
echo "file 'video1.mp4'" > list.txt
echo "file 'video2.mp4'" >> list.txt
echo "file 'video3.mp4'" >> list.txt
# Concatenate
ffmpeg -f concat -safe 0 -i list.txt -c copy output.mp4
Add Watermark
# Image watermark
ffmpeg -i input.mp4 -i logo.png -filter_complex "overlay=10:10" output.mp4
# Bottom right corner
ffmpeg -i input.mp4 -i logo.png -filter_complex "overlay=W-w-10:H-h-10" output.mp4
# Text watermark
ffmpeg -i input.mp4 -vf "drawtext=text='Copyright':fontsize=24:fontcolor=white:x=10:y=10" output.mp4
Speed Adjustment
# Speed up 2x
ffmpeg -i input.mp4 -filter:v "setpts=0.5*PTS" -filter:a "atempo=2.0" output.mp4
# Slow down 0.5x
ffmpeg -i input.mp4 -filter:v "setpts=2*PTS" -filter:a "atempo=0.5" output.mp4
3. Audio Processing
Extract Audio
# Extract audio track
ffmpeg -i video.mp4 -vn -c:a copy audio.aac
# Convert to MP3
ffmpeg -i video.mp4 -vn -c:a libmp3lame -q:a 2 audio.mp3
# Extract specific audio stream
ffmpeg -i video.mp4 -map 0:a:0 -c copy audio.m4a
Audio Conversion
# WAV to MP3
ffmpeg -i input.wav -c:a libmp3lame -b:a 320k output.mp3
# FLAC to MP3
ffmpeg -i input.flac -c:a libmp3lame -q:a 0 output.mp3
# MP3 to AAC
ffmpeg -i input.mp3 -c:a aac -b:a 256k output.m4a
Audio Normalization
# Loudnorm filter (EBU R128)
ffmpeg -i input.mp3 -af loudnorm=I=-16:LRA=11:TP=-1.5 output.mp3
# Volume adjustment
ffmpeg -i input.mp3 -af "volume=2.0" output.mp3 # 2x louder
ffmpeg -i input.mp3 -af "volume=0.5" output.mp3 # Half volume
# Peak normalization
ffmpeg -i input.mp3 -af "acompressor" output.mp3
Merge Audio/Video
# Replace audio track
ffmpeg -i video.mp4 -i audio.mp3 -c:v copy -c:a aac -map 0:v -map 1:a output.mp4
# Add audio to video (mix)
ffmpeg -i video.mp4 -i audio.mp3 -c:v copy -filter_complex "[0:a][1:a]amix=inputs=2:duration=first" output.mp4
4. Thumbnails and Screenshots
Single Thumbnail
# At specific time
ffmpeg -i video.mp4 -ss 00:00:05 -frames:v 1 thumbnail.jpg
# Best quality
ffmpeg -i video.mp4 -ss 00:00:05 -frames:v 1 -q:v 2 thumbnail.jpg
# Specific size
ffmpeg -i video.mp4 -ss 00:00:05 -frames:v 1 -vf "scale=320:180" thumbnail.jpg
Multiple Thumbnails
# Every N seconds
ffmpeg -i video.mp4 -vf "fps=1/10" thumbnails_%03d.jpg # Every 10 seconds
# Specific number of thumbnails
ffmpeg -i video.mp4 -vf "select='not(mod(n,300))'" -vsync vfr thumb_%03d.jpg
# Thumbnail sprite/grid
ffmpeg -i video.mp4 -vf "fps=1/10,scale=160:90,tile=10x10" sprite.jpg
GIF Creation
# Simple GIF
ffmpeg -i video.mp4 -ss 0 -t 5 -vf "fps=10,scale=320:-1" output.gif
# High quality GIF with palette
ffmpeg -i video.mp4 -ss 0 -t 5 -vf "fps=10,scale=320:-1:flags=lanczos,palettegen" palette.png
ffmpeg -i video.mp4 -i palette.png -ss 0 -t 5 -filter_complex "[0:v]fps=10,scale=320:-1:flags=lanczos[x];[x][1:v]paletteuse" output.gif
5. Streaming Formats
HLS (HTTP Live Streaming)
# Generate HLS
ffmpeg -i input.mp4 \
-c:v libx264 -c:a aac \
-hls_time 10 \
-hls_list_size 0 \
-hls_segment_filename "segment_%03d.ts" \
output.m3u8
# Adaptive bitrate HLS
ffmpeg -i input.mp4 \
-filter_complex "[0:v]split=3[v1][v2][v3];[v1]scale=1920:1080[v1out];[v2]scale=1280:720[v2out];[v3]scale=854:480[v3out]" \
-map "[v1out]" -c:v:0 libx264 -b:v:0 5M \
-map "[v2out]" -c:v:1 libx264 -b:v:1 2M \
-map "[v3out]" -c:v:2 libx264 -b:v:2 1M \
-map 0:a -c:a aac -b:a 128k \
-var_stream_map "v:0,a:0 v:1,a:0 v:2,a:0" \
-master_pl_name master.m3u8 \
-hls_time 6 \
-hls_segment_filename "v%v/segment_%03d.ts" \
v%v/index.m3u8
DASH (Dynamic Adaptive Streaming)
ffmpeg -i input.mp4 \
-c:v libx264 -c:a aac \
-f dash \
-init_seg_name "init-\$RepresentationID\$.m4s" \
-media_seg_name "chunk-\$RepresentationID\$-\$Number%05d\$.m4s" \
output.mpd
6. Python Integration
PyAV (FFmpeg bindings)
import av
def transcode_video(input_path, output_path, target_codec='libx264'):
input_container = av.open(input_path)
output_container = av.open(output_path, 'w')
# Get input streams
video_stream = input_container.streams.video[0]
audio_stream = input_container.streams.audio[0] if input_container.streams.audio else None
# Create output streams
output_video = output_container.add_stream(target_codec, rate=video_stream.average_rate)
output_video.width = video_stream.width
output_video.height = video_stream.height
output_video.pix_fmt = 'yuv420p'
if audio_stream:
output_audio = output_container.add_stream('aac', rate=audio_stream.rate)
for packet in input_container.demux():
if packet.stream.type == 'video':
for frame in packet.decode():
for out_packet in output_video.encode(frame):
output_container.mux(out_packet)
elif packet.stream.type == 'audio' and audio_stream:
for frame in packet.decode():
for out_packet in output_audio.encode(frame):
output_container.mux(out_packet)
# Flush encoders
for packet in output_video.encode():
output_container.mux(packet)
output_container.close()
input_container.close()
MoviePy
from moviepy.editor import VideoFileClip, concatenate_videoclips, TextClip, CompositeVideoClip
def process_video(input_path, output_path):
# Load video
clip = VideoFileClip(input_path)
# Trim
trimmed = clip.subclip(10, 60) # 10s to 60s
# Resize
resized = trimmed.resize(height=720)
# Add text overlay
txt_clip = TextClip("Hello World", fontsize=50, color='white')
txt_clip = txt_clip.set_position('center').set_duration(5)
# Composite
final = CompositeVideoClip([resized, txt_clip])
# Export
final.write_videofile(
output_path,
codec='libx264',
audio_codec='aac'
)
clip.close()
def create_thumbnail(video_path, output_path, time=5):
clip = VideoFileClip(video_path)
frame = clip.get_frame(time)
clip.save_frame(output_path, t=time)
clip.close()
def concatenate_videos(video_paths, output_path):
clips = [VideoFileClip(path) for path in video_paths]
final = concatenate_videoclips(clips)
final.write_videofile(output_path)
for clip in clips:
clip.close()
FFmpeg Subprocess
import subprocess
import json
def get_video_info(video_path):
"""Get video metadata using ffprobe"""
cmd = [
'ffprobe',
'-v', 'quiet',
'-print_format', 'json',
'-show_format',
'-show_streams',
video_path
]
result = subprocess.run(cmd, capture_output=True, text=True)
return json.loads(result.stdout)
def transcode_video(input_path, output_path, options=None):
"""Transcode video with FFmpeg"""
cmd = ['ffmpeg', '-i', input_path]
if options:
if 'video_codec' in options:
cmd.extend(['-c:v', options['video_codec']])
if 'audio_codec' in options:
cmd.extend(['-c:a', options['audio_codec']])
if 'crf' in options:
cmd.extend(['-crf', str(options['crf'])])
if 'resolution' in options:
cmd.extend(['-vf', f"scale={options['resolution']}"])
cmd.extend(['-y', output_path])
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
raise Exception(f"FFmpeg error: {result.stderr}")
return True
def generate_hls(input_path, output_dir):
"""Generate HLS stream"""
import os
os.makedirs(output_dir, exist_ok=True)
cmd = [
'ffmpeg', '-i', input_path,
'-c:v', 'libx264',
'-c:a', 'aac',
'-hls_time', '10',
'-hls_list_size', '0',
'-hls_segment_filename', f'{output_dir}/segment_%03d.ts',
f'{output_dir}/index.m3u8'
]
subprocess.run(cmd, check=True)
7. Live Streaming
RTMP Server (nginx-rtmp)
# nginx.conf
rtmp {
server {
listen 1935;
application live {
live on;
record off;
# HLS output
hls on;
hls_path /var/www/hls;
hls_fragment 3;
hls_playlist_length 60;
}
}
}
Stream to RTMP
# Stream file to RTMP
ffmpeg -re -i input.mp4 -c copy -f flv rtmp://server/live/stream
# Stream webcam
ffmpeg -f v4l2 -i /dev/video0 -f alsa -i hw:0 \
-c:v libx264 -preset veryfast -b:v 2M \
-c:a aac -b:a 128k \
-f flv rtmp://server/live/stream
# Stream to YouTube
ffmpeg -i input.mp4 \
-c:v libx264 -preset medium -b:v 4M \
-c:a aac -b:a 128k \
-f flv rtmp://a.rtmp.youtube.com/live2/YOUR_STREAM_KEY
8. Video Processing Pipeline
Async Processing with Celery
from celery import Celery
import os
celery = Celery('video_tasks')
@celery.task
def process_upload(video_id, input_path):
"""Complete video processing pipeline"""
output_dir = f'/videos/{video_id}'
os.makedirs(output_dir, exist_ok=True)
# Generate thumbnail
generate_thumbnail.delay(video_id, input_path, f'{output_dir}/thumb.jpg')
# Transcode to multiple resolutions
resolutions = [
('1080p', '1920:1080', '5M'),
('720p', '1280:720', '2.5M'),
('480p', '854:480', '1M'),
]
for name, scale, bitrate in resolutions:
transcode_resolution.delay(
video_id, input_path,
f'{output_dir}/{name}.mp4',
scale, bitrate
)
# Generate HLS
generate_hls.delay(video_id, input_path, f'{output_dir}/hls')
@celery.task
def generate_thumbnail(video_id, input_path, output_path):
cmd = [
'ffmpeg', '-i', input_path,
'-ss', '5', '-frames:v', '1',
'-vf', 'scale=320:-1',
output_path
]
subprocess.run(cmd, check=True)
@celery.task
def transcode_resolution(video_id, input_path, output_path, scale, bitrate):
cmd = [
'ffmpeg', '-i', input_path,
'-c:v', 'libx264', '-b:v', bitrate,
'-vf', f'scale={scale}',
'-c:a', 'aac', '-b:a', '128k',
output_path
]
subprocess.run(cmd, check=True)
9. Audio Analysis
Waveform Generation
import librosa
import librosa.display
import matplotlib.pyplot as plt
import numpy as np
def generate_waveform(audio_path, output_path):
"""Generate waveform image"""
y, sr = librosa.load(audio_path)
plt.figure(figsize=(14, 5))
librosa.display.waveshow(y, sr=sr)
plt.title('Waveform')
plt.savefig(output_path, dpi=150, bbox_inches='tight')
plt.close()
def generate_spectrogram(audio_path, output_path):
"""Generate spectrogram image"""
y, sr = librosa.load(audio_path)
D = librosa.stft(y)
S_db = librosa.amplitude_to_db(np.abs(D), ref=np.max)
plt.figure(figsize=(14, 5))
librosa.display.specshow(S_db, sr=sr, x_axis='time', y_axis='hz')
plt.colorbar(format='%+2.0f dB')
plt.title('Spectrogram')
plt.savefig(output_path, dpi=150, bbox_inches='tight')
plt.close()
10. Best Practices
Encoding Presets
# Web-optimized MP4
ffmpeg -i input.mp4 \
-c:v libx264 -preset slow -crf 22 \
-c:a aac -b:a 128k \
-movflags +faststart \
output.mp4
# Archive quality
ffmpeg -i input.mp4 \
-c:v libx264 -preset veryslow -crf 18 \
-c:a flac \
archive.mkv
# Mobile-optimized
ffmpeg -i input.mp4 \
-c:v libx264 -preset fast -crf 28 \
-vf "scale='min(720,iw)':-2" \
-c:a aac -b:a 96k \
mobile.mp4
Best Practices
- Use hardware acceleration - NVENC, VAAPI, VideoToolbox
- Optimize for web - faststart flag for streaming
- Choose right codec - H.264 for compatibility, VP9/AV1 for quality
- Appropriate CRF - 18-23 for quality, 28+ for size
- Two-pass for size - When file size matters
- Process async - Queue long operations
- Generate previews - Thumbnails and sprites
- Validate input - Check format before processing
- Clean temp files - Remove intermediate files
- Monitor resources - CPU/memory limits
Weekly Installs
4
Repository
fgarofalo56/sup…t_fabricFirst Seen
Mar 3, 2026
Security Audits
Installed on
openclaw4
gemini-cli4
claude-code4
github-copilot4
codex4
kimi-cli4