Multimedia: Alle Medien-Dateien umcodieren (inkl. webm und .webp)

edit | delete

Autor: Ralf v.d.Mark

eingetragen: Dienstag, 23. Dezember 2025 um 15:49 Uhr (52/2025 Kalenderwoche)

geändert: Mittwoch, 24. Dezember 2025 um 13:50 Uhr (52/2025 Kalenderwoche)

Keywords: Multimedia Medien Dateien umcodieren videos bilder

Kategorien: Windows,

Text:

Umcodieren aller Video- und Bildformate außer MP4!
(".flv",".mov",".mpg",".mpeg",".avi",".wmv",".mkv",".mts",".m2ts",".3gp",".vob",".ts",".webm",".webp")

Siehe weitere Umcodier-Scripte

Das PowerShell-Script "convert-allMediainkl-Unterordner2MP4uJPG.ps1" (Multithreading-fähig, JSON-loggend, deutsch, ASCII-sicher) macht Folgendes::
✔ alle Nicht-MP4-Videos verarbeitet
✔ zusätzlich WEBM --> MP4 und WEBP --> JPG umwandelt
✔ Multithreading nutzt (PowerShell-Jobs --> parallel, CPU-optimiert)
✔ Die Metadaten der Quelle werden in die neue Mediendatei übernommen
✔ eine Text-Logdatei mit Zeitstempel erzeugt
✔ Originaldateien in _Backup-Filme verschiebt
✔ MP4/JPG im Originalordner erzeugt
✔ farbige Konsolenausgabe hat
✔ ASCII-sicher ist (keine Umlaute, keine Unicode-Symbole)
✔ Backup-Ordner: _____Backup-Filme --> wird korrekt ignoriert
✔ Logdateien: Zeitstempel im Namen --> keine Überschreibung
✔ JSON-Log: wird fortgeschrieben --> perfekt für spätere Auswertung
✔ Dateisystem- und Video-Metadaten landen im Text-Log (Erstellungs-, Änderungs- und Zugriffsdatum sowie Dauer, Bitrate und Auflösung).
✔ WEBP/WEBM: Sonderbehandlung eingebaut --> läuft
✔ Remux/Reencode: Codec-Check mit ffprobe --> korrekt
✔ Job-Handling: Warteschleife + Cleanup --> stabil
✔ Multithreading: $MaxJobs = 8 --> sauber konfigurierbar
Wichtige Hinweise zum Multithreading:
- Ein Ryzen 9 kann 12–16 parallele Jobs locker stemmen
- Ein Ryzen 7 eher 6–8 Jobs
- Standardmäßig sind 8 Threads, aber anpassbar unter:
- --> $MaxJobs = 8


Kleine Anleitung, um das jeweilige Script zu starten:

1) FFmpeg muss installiert sein
(- ffmpeg\bin kopieren nach z. B. "C:\Programme\ffmpeg\bin"
- Windows-Suche --> „Umgebungsvariablen“
- „PATH“ bearbeiten --> neuen Eintrag hinzufügen:
- C:\Programme\ffmpeg\bin
- OK --> fertig.).

2a) Skript "convert-....ps1" in den Ordner mit den Mediendateien legen
2b) EMPFOHLEN: Skript "convert-allMedia
inkl-Unterordner2MP4uJPG.ps1" in den obersten Ordner mit den Mediendateien legen.

3) PowerShell öffnen

4) In den (obersten) Ordner wechseln, wo das Script liegt: "e:" und "cd ..."

5) Script ausführen: "./convert-allMediainkl-Unterordner2_MP4uJPG.ps1"

Falls PowerShell meckert wegen der Ausführungsrichtlinie:
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass

6a) Fertig — alle MP4s liegen daneben.
6b) Fertig - alle MP4s liegen im Originalordner und die veraltete Mediendatei im Backup-Ordner

Quellcode:  

# ============================================
# Multithreaded Video Converter (ASCII-safe)
# ============================================

# Anzahl paralleler Jobs
$MaxJobs    = 8
$CrfValue   = 18
$Preset     = "slow"
$BackupName = "_____Backup-Filme"

# Basisordner & Backup
$BaseDir   = Split-Path -Parent $MyInvocation.MyCommand.Path
$BackupDir = Join-Path $BaseDir $BackupName
New-Item -ItemType Directory -Force -Path $BackupDir | Out-Null

# Logdatei
$timestamp = Get-Date -Format "yyyy-MM-dd_HH-mm-ss"
$LogFile   = Join-Path $BackupDir "conversion_log_$timestamp.txt"
"=== Videokonvertierung gestartet: $(Get-Date) ===" | Out-File -FilePath $LogFile -Encoding ASCII

# Dateiformate
$extensions = "*.flv","*.mov","*.mpg","*.mpeg","*.avi","*.wmv","*.mkv","*.mts","*.m2ts","*.3gp","*.vob","*.ts","*.webm","*.webp","*.FLV","*.MOV","*.MPG","*.MPEG","*.AVI","*.WMV","*.MKV","*.MTS","*.M2TS","*.3GP","*.VOB","*.TS","*.WEBM","*.WEBP"

# Dateien sammeln (Backup ausschliessen)
$files = foreach ($ext in $extensions) {
    Get-ChildItem -Path $BaseDir -Filter $ext -Recurse -File -ErrorAction SilentlyContinue |
    Where-Object { $_.FullName -notlike "$BackupDir*" }
}

# ============================================
# Job-Funktion
# ============================================
$ScriptBlock = {
    param($file, $relativePath, $BackupDir, $LogFile, $CrfValue, $Preset)

    $mp4Path = [System.IO.Path]::ChangeExtension($file, ".mp4")
    $jpgPath = [System.IO.Path]::ChangeExtension($file, ".jpg")

    # Falls MP4 schon existiert -> neuen Namen mit (doppelt)
    if (Test-Path $mp4Path) {
        $folder = Split-Path $mp4Path -Parent
        $name   = [System.IO.Path]::GetFileNameWithoutExtension($mp4Path)
        $mp4Path = Join-Path $folder ($name + " (doppelt).mp4")
    }

    # Backup-Zielpfad
    $backupTarget = Join-Path $BackupDir $relativePath
    $backupFolder = Split-Path $backupTarget -Parent
    New-Item -ItemType Directory -Force -Path $backupFolder | Out-Null

    # Dateisystem-Metadaten
    $fileInfo      = Get-Item $file
    $creationTime  = $fileInfo.CreationTime
    $lastWriteTime = $fileInfo.LastWriteTime
    $lastAccessTime= $fileInfo.LastAccessTime

    # WEBP -> JPG
    if ($file.ToLower().EndsWith(".webp")) {
        ffmpeg -y -i "$file" "$jpgPath"

        Add-Content -Encoding ASCII $LogFile "Neue JPG-Datei erzeugt: $jpgPath"
        Add-Content -Encoding ASCII $LogFile "Datum erstellt: $creationTime"
        Add-Content -Encoding ASCII $LogFile "Datum geaendert: $lastWriteTime"
        Add-Content -Encoding ASCII $LogFile "Datum letzter Zugriff: $lastAccessTime"

        # Zeitstempel uebernehmen
        Set-ItemProperty -Path $jpgPath -Name CreationTime -Value $creationTime
        Set-ItemProperty -Path $jpgPath -Name LastWriteTime -Value $lastWriteTime

        # relativen Pfad sauber berechnen
		$relativePath = $file.Substring($using:BaseDir.Length).TrimStart('\','/')
		$backupTarget = Join-Path $using:BackupDir $relativePath

		# Datei im Backup mit gleichem Namen liegt -> löschen (falls vorhanden) 
		if (Test-Path -Path $backupTarget -PathType Leaf) {
			Remove-Item -Path $backupTarget -Force -ErrorAction SilentlyContinue
		}

		# Originaldatei ins Backup verschieben
		Move-Item -Force "$file" "$backupTarget"

        return
    }

    # WEBM -> MP4
    if ($file.ToLower().EndsWith(".webm")) {
        ffmpeg -y -i "$file" -c:v libx264 -preset $Preset -crf $CrfValue -c:a aac "$mp4Path"

        Add-Content -Encoding ASCII $LogFile "Neue MP4-Datei erzeugt: $mp4Path"
        Add-Content -Encoding ASCII $LogFile "Datum erstellt: $creationTime"
        Add-Content -Encoding ASCII $LogFile "Datum geaendert: $lastWriteTime"
        Add-Content -Encoding ASCII $LogFile "Datum letzter Zugriff: $lastAccessTime"

        # Zeitstempel uebernehmen
        Set-ItemProperty -Path $mp4Path -Name CreationTime -Value $creationTime
        Set-ItemProperty -Path $mp4Path -Name LastWriteTime -Value $lastWriteTime

        # relativen Pfad sauber berechnen
		$relativePath = $file.Substring($using:BaseDir.Length).TrimStart('\','/')
		$backupTarget = Join-Path $using:BackupDir $relativePath

		# Datei im Backup mit gleichem Namen liegt -> löschen (falls vorhanden) 
		if (Test-Path -Path $backupTarget -PathType Leaf) {
			Remove-Item -Path $backupTarget -Force -ErrorAction SilentlyContinue
		}

		# Originaldatei ins Backup verschieben
		Move-Item -Force "$file" "$backupTarget"
		
        return
    }

    # Standardfall: andere Videoformate
    ffmpeg -y -i "$file" -c:v libx264 -preset $Preset -crf $CrfValue -c:a aac "$mp4Path"

    Add-Content -Encoding ASCII $LogFile "Neue MP4-Datei erzeugt: $mp4Path"
    Add-Content -Encoding ASCII $LogFile "Datum erstellt: $creationTime"
    Add-Content -Encoding ASCII $LogFile "Datum geaendert: $lastWriteTime"
    Add-Content -Encoding ASCII $LogFile "Datum letzter Zugriff: $lastAccessTime"

    # Zeitstempel uebernehmen
    Set-ItemProperty -Path $mp4Path -Name CreationTime -Value $creationTime
    Set-ItemProperty -Path $mp4Path -Name LastWriteTime -Value $lastWriteTime

    # relativen Pfad sauber berechnen
	$relativePath = $file.Substring($using:BaseDir.Length).TrimStart('\','/')
	$backupTarget = Join-Path $using:BackupDir $relativePath

	# Datei im Backup mit gleichem Namen liegt -> löschen (falls vorhanden) 
	if (Test-Path -Path $backupTarget -PathType Leaf) {
		Remove-Item -Path $backupTarget -Force -ErrorAction SilentlyContinue
	}

	# Originaldatei ins Backup verschieben
	Move-Item -Force "$file" "$backupTarget"
}

# ============================================
# Jobs starten
# ============================================
foreach ($fileObj in $files) {
    while ((Get-Job -State Running).Count -ge $MaxJobs) {
        Start-Sleep -Milliseconds 200
    }
    $file = $fileObj.FullName
    $relativePath = Resolve-Path $file -Relative
	
	Write-Host "Starte Job fuer: $file" -ForegroundColor Cyan
	
    Start-Job -ScriptBlock $ScriptBlock -ArgumentList $file, $relativePath, $BackupDir, $LogFile, $CrfValue, $Preset | Out-Null
}

Get-Job | Wait-Job | Out-Null
Get-Job | Remove-Job | Out-Null

Add-Content -Encoding ASCII $LogFile "`n=== Videokonvertierung abgeschlossen: $(Get-Date) ==="