:: Dieses Skript stellt bei DJI Osmo 360 Videos das urspruengliche Aufnahmedatum wieder her, das beim Export der .OSV-Rohdatei in eine .mp4 verloren geht. Als Quelle dient wahlweise der Dateiname der .OSV (CAM_JJJJMMTTHHMMSS_...) oder deren Aenderungsdatum. Zu jeder .OSV wird automatisch die gleichnamige .mp4 im selben Ordner gesucht; existiert keine passende Datei, kann manuell ein anderer Dateiname angegeben werden.
:: Da die Osmo 360 kein GPS besitzt und daher keine Zeitzone in den Metadaten speichert, erfolgt eine Abfrage zur Angabe der Zeitzone, mit der Zeitzone dieses PCs als Standardwert. Wichtig: In der Kamera muss stets die lokale Uhrzeit des Aufnahmeortes eingestellt sein.
:: Optional koennen die Videos zusaetzlich per FFmpeg mit einem waehlbaren CRF-Wert komprimiert werden (H.265 oder AV1). Das korrekte Aufnahmedatum wird sowohl in die Originaldatei als auch in die komprimierte Ausgabedatei geschrieben.
::
:: Verwendung des Scripts:
::
:: Script als z. B. "osv-datefix.bat" anlegen.
:: "ffmpeg-release-essentials.zip" hier herunterladen, entpacken und aus dem Ordner "bin" die ffmpeg.exe in das Verzeichnis kopieren: https://www.gyan.dev/ffmpeg/builds/
:: "exiftool-XXX.zip" hier herunterladen, entpacken, in das Verzeichnis kopieren und die .exe-Datei umbenennen in "exiftool.exe": https://exiftool.org/
:: Version 1.0.0 - 29.08.2026 - @nurjns
@echo off
setlocal enabledelayedexpansion
cd /d "%~dp0"
title DJI Osmo 360 - Aufnahmedatum aus OSV wiederherstellen
echo ==========================================================
echo DJI Osmo 360 - Aufnahmedatum aus .OSV wiederherstellen
echo ==========================================================
echo.
:: ExifTool suchen: zuerst im Script-Ordner, danach im PATH
set "EXIFTOOL="
if exist "%~dp0exiftool.exe" set "EXIFTOOL=.\exiftool.exe"
if not defined EXIFTOOL (
where exiftool >nul 2>&1
if not errorlevel 1 set "EXIFTOOL=exiftool"
)
if not defined EXIFTOOL (
echo [FEHLER] ExifTool nicht gefunden^^! exiftool.exe ^(inkl. Ordner "exiftool_files"^) in diesen Ordner legen oder in den PATH aufnehmen.
pause & exit /b 1
)
"%EXIFTOOL%" -ver >nul 2>&1
if errorlevel 1 (
echo [FEHLER] ExifTool laesst sich nicht ausfuehren. Fehlt der Ordner "exiftool_files"?
pause & exit /b 1
)
:: PowerShell wird fuer Datums- und Offset-Berechnung benoetigt
where powershell >nul 2>&1
if errorlevel 1 (
echo [FEHLER] PowerShell nicht gefunden^^! Wird fuer die Zeitzonen-Berechnung benoetigt.
pause & exit /b 1
)
:: Pruefen ob ueberhaupt OSV-Dateien vorhanden sind
set "OSV_COUNT=0"
for %%F in (*.osv) do set /a OSV_COUNT+=1
if %OSV_COUNT%==0 (
echo [FEHLER] Keine .OSV-Dateien in diesem Ordner gefunden.
echo Das Script muss gemeinsam mit den OSV- und den exportierten MP4-Dateien im selben Ordner liegen.
echo Aktueller Ordner: %CD%
pause & exit /b 1
)
echo [INFO] %OSV_COUNT% OSV-Datei^(en^) gefunden.
echo.
:: Benutzerabfrage: Quelle fuer das Aufnahmedatum
echo Welche Quelle soll fuer das Aufnahmedatum verwendet werden?
echo 1 - Dateiname der OSV (Standard)
echo 2 - Aenderungsdatum der OSV
set /p DATESOURCE="Eingabe (1 oder 2): "
if not "%DATESOURCE%"=="1" if not "%DATESOURCE%"=="2" (
echo Ungueltige Eingabe. Standard: Dateiname wird verwendet.
set DATESOURCE=1
)
:: Benutzerabfrage: Zeitzone
:: Automatisch Sommer-/Winterzeit erkennen fuer Deutschland
for /f "usebackq delims=" %%i in (`powershell -NoProfile -Command "$tz = [System.TimeZoneInfo]::FindSystemTimeZoneById('W. Europe Standard Time'); $now = Get-Date; if($tz.IsDaylightSavingTime($now)) {'+02:00'} else {'+01:00'}"`) do set "SYSTEM_TZ=%%i"
:ASK_TZ
set "TIMEZONE="
echo.
set /p "TIMEZONE=Zeitzone fuer Metadaten (Format: +/-XX:00, leer fuer Standard: !SYSTEM_TZ!): "
if "!TIMEZONE!"=="" (
echo Leere Eingabe. Standard: !SYSTEM_TZ! wird verwendet
set "TIMEZONE=!SYSTEM_TZ!"
) else (
echo !TIMEZONE!| findstr /r "^[+-][0-9][0-9]:[0-9][0-9]$" >nul
if errorlevel 1 (
echo Ungueltige Eingabe bei Zeitzone^^! Beispiel: +02:00
goto ASK_TZ
)
)
:: Benutzerabfrage: Videos zusaetzlich komprimieren?
echo.
set "COMPRESS="
set /p "COMPRESS=Videos zusaetzlich mit ffmpeg komprimieren? (y/n): "
if /i "!COMPRESS!"=="y" (
set "COMPRESS=y"
call :SETUP_COMPRESS
) else (
set "COMPRESS=n"
)
echo.
echo ----------------------------------------------------------
echo.
set "CNT_OK=0"
set "CNT_SKIP=0"
set "CNT_ERR=0"
:: Schleife durch alle OSV-Dateien
for %%F in (*.osv) do (
call :PROCESS "%%F"
echo.
)
echo ----------------------------------------------------------
echo Fertig. Erfolgreich: %CNT_OK% Uebersprungen: %CNT_SKIP% Fehler: %CNT_ERR%
powershell -c [console]::beep(500,200)
pause
exit /b 0
:: ==========================================================
:: Verarbeitung einer einzelnen OSV-Datei
:: ==========================================================
:PROCESS
set "OSV=%~1"
set "BASE=%~n1"
set "TIMESTAMP="
set "MP4="
echo Bearbeite: !OSV!
:: --- Aufnahmedatum ermitteln ---
if "%DATESOURCE%"=="1" (
call :DATE_FROM_NAME
if not defined TIMESTAMP (
echo [WARNUNG] Dateiname entspricht nicht dem Muster CAM_JJJJMMTTHHMMSS_... - verwende Aenderungsdatum
call :DATE_FROM_MTIME
)
) else (
call :DATE_FROM_MTIME
)
if not defined TIMESTAMP (
echo [FEHLER] Kein gueltiges Datum ermittelbar fuer !OSV! - uebersprungen
set /a CNT_ERR+=1
goto :eof
)
echo [INFO] Aufnahmedatum: !TIMESTAMP!!TIMEZONE!
:: --- Passende MP4 suchen ---
if exist "!BASE!.mp4" (
set "MP4=!BASE!.mp4"
) else (
echo [WARNUNG] Keine passende Datei "!BASE!.mp4" gefunden.
set "CAND_COUNT=0"
for %%C in ("!BASE!*.mp4") do (
set /a CAND_COUNT+=1
echo Moeglicher Treffer: %%~nxC
)
if !CAND_COUNT! EQU 0 echo Keine MP4 mit passendem Namensanfang im Ordner.
goto :ASK_MP4
)
goto :MP4_OK
:ASK_MP4
set "MANUAL="
set /p "MANUAL=Anderen Dateinamen angeben (leer = ueberspringen): "
if "!MANUAL!"=="" (
echo [OK] Uebersprungen: !OSV! - keine MP4 zugeordnet
set /a CNT_SKIP+=1
goto :eof
)
:: Endung ergaenzen, falls vergessen
echo !MANUAL!| findstr /i /e ".mp4" >nul
if errorlevel 1 set "MANUAL=!MANUAL!.mp4"
if not exist "!MANUAL!" (
echo [FEHLER] Datei "!MANUAL!" existiert nicht.
goto :ASK_MP4
)
:: Sicherstellen, dass es kein Verzeichnis ist
if exist "!MANUAL!\" (
echo [FEHLER] "!MANUAL!" ist ein Verzeichnis.
goto :ASK_MP4
)
set "MP4=!MANUAL!"
:MP4_OK
:: --- Pruefen ob es wirklich eine lesbare MP4-Datei ist ---
set "FILETYPE="
for /f "usebackq delims=" %%T in (`%EXIFTOOL% -s3 -FileType "!MP4!" 2^>nul`) do set "FILETYPE=%%T"
if /i not "!FILETYPE!"=="MP4" (
echo [FEHLER] "!MP4!" ist keine gueltige oder lesbare MP4-Datei ^(erkannt: "!FILETYPE!"^) - uebersprungen
set /a CNT_ERR+=1
goto :eof
)
:: --- Datum in die Originaldatei schreiben ---
call :WRITE_DATE "!MP4!"
if "!WRITE_OK!"=="0" (
set /a CNT_ERR+=1
goto :eof
)
:: --- Optional: Video komprimieren und Datum auch dort setzen ---
if /i "%COMPRESS%"=="y" (
call :COMPRESS_FILE
) else (
set /a CNT_OK+=1
)
goto :eof
:: ==========================================================
:: Video mit ffmpeg komprimieren, danach Datum setzen
:: ==========================================================
:COMPRESS_FILE
for %%N in ("!MP4!") do set "OUTBASE=%%~nN"
:: Bereits komprimierte Dateien nicht erneut verarbeiten
echo !OUTBASE!| findstr /i "_crf" >nul
if not errorlevel 1 (
echo [OK] Kompression uebersprungen: !MP4! - bereits komprimiertes Video
set /a CNT_OK+=1
goto :eof
)
if "%CODECWAHL%"=="1" (
set "OUTFILE=!OUTBASE!_crf%CRF_WERT%.mp4"
) else (
set "OUTFILE=!OUTBASE!_AV1_crf%CRF_WERT%.mp4"
)
if exist "!OUTFILE!" (
echo [OK] Kompression uebersprungen: !OUTFILE! - bereits mit gleichen Einstellungen gerendert
set /a CNT_SKIP+=1
goto :eof
)
echo [INFO] Komprimiere nach: !OUTFILE!
if "%CODECWAHL%"=="1" (
:: H.265
ffmpeg -nostdin -y -i "!MP4!" -c:v libx265 -crf %CRF_WERT% -preset medium -pix_fmt yuv420p -tag:v hvc1 -movflags +faststart -c:a copy "!OUTFILE!"
) else (
:: AV1
if !CRF_WERT! LEQ 22 (
set "PRESET=2"
) else if !CRF_WERT! LEQ 28 (
set "PRESET=3"
) else if !CRF_WERT! LEQ 35 (
set "PRESET=6"
) else (
set "PRESET=10"
)
ffmpeg -nostdin -y -i "!MP4!" -c:v libsvtav1 -crf %CRF_WERT% -preset !PRESET! -pix_fmt yuv420p -movflags +faststart -c:a copy "!OUTFILE!"
)
if errorlevel 1 (
echo [FEHLER] ffmpeg konnte "!MP4!" nicht komprimieren
if exist "!OUTFILE!" del "!OUTFILE!"
set /a CNT_ERR+=1
goto :eof
)
call :WRITE_DATE "!OUTFILE!"
if "!WRITE_OK!"=="0" (
set /a CNT_ERR+=1
goto :eof
)
set /a CNT_OK+=1
goto :eof
:: ==========================================================
:: Datum per ExifTool in eine Datei schreiben und kontrollieren
:: ==========================================================
:WRITE_DATE
set "TARGET=%~1"
set "WRITE_OK=1"
:: --- Pruefen ob das Datum bereits korrekt gesetzt ist ---
set "CURRENT="
for /f "usebackq delims=" %%T in (`%EXIFTOOL% -s3 -QuickTime:CreateDate "!TARGET!" 2^>nul`) do set "CURRENT=%%T"
if "!CURRENT!"=="!TIMESTAMP!" (
echo [OK] Datum bereits korrekt: !TARGET!
goto :eof
)
"%EXIFTOOL%" -overwrite_original ^
"-DateTimeOriginal=!TIMESTAMP!!TIMEZONE!" ^
"-OffsetTimeOriginal=!TIMEZONE!" ^
"-QuickTime:CreateDate=!TIMESTAMP!" ^
"-QuickTime:ModifyDate=!TIMESTAMP!" ^
"-QuickTime:TrackCreateDate=!TIMESTAMP!" ^
"-QuickTime:TrackModifyDate=!TIMESTAMP!" ^
"-QuickTime:MediaCreateDate=!TIMESTAMP!" ^
"-QuickTime:MediaModifyDate=!TIMESTAMP!" ^
"-FileModifyDate=!TIMESTAMP!" ^
"!TARGET!"
if errorlevel 1 (
echo [FEHLER] ExifTool konnte "!TARGET!" nicht schreiben
set "WRITE_OK=0"
goto :eof
)
:: --- Kontrolle: geschriebenen Wert zurueckgelesen ---
set "VERIFY="
for /f "usebackq delims=" %%T in (`%EXIFTOOL% -s3 -QuickTime:CreateDate "!TARGET!" 2^>nul`) do set "VERIFY=%%T"
if not "!VERIFY!"=="!TIMESTAMP!" (
echo [FEHLER] Kontrolle fehlgeschlagen fuer "!TARGET!" - gelesen: !VERIFY!
set "WRITE_OK=0"
goto :eof
)
echo [OK] Verarbeitet: !TARGET!
goto :eof
:: ==========================================================
:: Einstellungen fuer die Kompression abfragen
:: ==========================================================
:SETUP_COMPRESS
:: ffprobe wird nicht benoetigt, da nicht geschnitten wird
where ffmpeg >nul 2>&1
if errorlevel 1 (
if exist "%~dp0ffmpeg.exe" (
set "PATH=%~dp0;%PATH%"
) else (
echo [FEHLER] ffmpeg nicht gefunden^^! ffmpeg.exe in diesen Ordner legen oder in den PATH aufnehmen.
echo [INFO] Kompression wird deaktiviert, Datum wird trotzdem gesetzt.
set "COMPRESS=n"
goto :eof
)
)
:: Benutzerabfrage: Codec-Auswahl
echo.
echo Waehle Codec:
echo 1 - H.265 - Gute Kompression, breite Unterstuetzung (Standard)
echo 2 - AV1 - Beste Kompression, Geschwindigkeit haengt von Qualitaetsstufe ab, fuer neuere Geraete
set /p CODECWAHL="Eingabe (1 oder 2): "
if not "!CODECWAHL!"=="1" if not "!CODECWAHL!"=="2" (
echo Ungueltige Eingabe. Standard: H.265 wird verwendet.
set CODECWAHL=1
)
:: Benutzerabfrage: CRF-Wert
:ASK_CRF
set CRF_WERT=
if "!CODECWAHL!"=="1" (
echo H.265 CRF-Wert ^(18=hoch, 24=normal, 30=niedrig, 35=sehr niedrig^)
) else (
echo AV1 CRF-Wert ^(18=sehr hoch, 22=hoch, 30=normal, 40=niedrig, 50=sehr niedrig^)
)
set /p CRF_WERT="Welcher CRF-Wert soll verwendet werden? "
echo !CRF_WERT!| findstr /r "^[0-9][0-9]*$" >nul
if errorlevel 1 goto :CRF_FEHLER
if !CRF_WERT! LSS 16 goto :CRF_FEHLER
if !CRF_WERT! GTR 50 goto :CRF_FEHLER
goto :CRF_OK
:CRF_FEHLER
echo Ungueltige Eingabe bei CRF-Wert^^!
goto ASK_CRF
:CRF_OK
goto :eof
:: ==========================================================
:: Datum aus dem OSV-Dateinamen (CAM_JJJJMMTTHHMMSS_...)
:: ==========================================================
:DATE_FROM_NAME
echo !BASE!| findstr /r /i "^CAM_[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]_" >nul
if errorlevel 1 goto :eof
for /f "tokens=2 delims=_" %%A in ("!BASE!") do set "DATETIME=%%A"
set "YYYY=!DATETIME:~0,4!"
set "MM=!DATETIME:~4,2!"
set "DD=!DATETIME:~6,2!"
set "hh=!DATETIME:~8,2!"
set "nn=!DATETIME:~10,2!"
set "ss=!DATETIME:~12,2!"
set "TIMESTAMP=!YYYY!:!MM!:!DD! !hh!:!nn!:!ss!"
goto :eof
:: ==========================================================
:: Datum aus dem Aenderungsdatum der OSV-Datei
:: ==========================================================
:DATE_FROM_MTIME
for /f "usebackq delims=" %%T in (`powershell -NoLogo -NoProfile -Command "(Get-Item -LiteralPath '!OSV!').LastWriteTime.ToString('yyyy:MM:dd HH:mm:ss')"`) do (
set "TIMESTAMP=%%T"
)
goto :eof
Comments