nurjns

DJI 360 Video Metadata Fixer

Aug 26th, 2026 (edited)
30,514
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Batch 12.54 KB | None | 0 0
  1. :: 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.
  2. :: 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.
  3. :: 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.
  4. ::
  5. :: Verwendung des Scripts:
  6. ::
  7. :: Script als z. B. "osv-datefix.bat" anlegen.
  8. :: "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/
  9. :: "exiftool-XXX.zip" hier herunterladen, entpacken, in das Verzeichnis kopieren und die .exe-Datei umbenennen in "exiftool.exe": https://exiftool.org/
  10. :: Version 1.0.0 - 29.08.2026 - @nurjns
  11.  
  12. @echo off
  13. setlocal enabledelayedexpansion
  14. cd /d "%~dp0"
  15. title DJI Osmo 360 - Aufnahmedatum aus OSV wiederherstellen
  16.  
  17. echo ==========================================================
  18. echo  DJI Osmo 360 - Aufnahmedatum aus .OSV wiederherstellen
  19. echo ==========================================================
  20. echo.
  21.  
  22. :: ExifTool suchen: zuerst im Script-Ordner, danach im PATH
  23. set "EXIFTOOL="
  24. if exist "%~dp0exiftool.exe" set "EXIFTOOL=.\exiftool.exe"
  25. if not defined EXIFTOOL (
  26.     where exiftool >nul 2>&1
  27.     if not errorlevel 1 set "EXIFTOOL=exiftool"
  28. )
  29. if not defined EXIFTOOL (
  30.     echo [FEHLER] ExifTool nicht gefunden^^! exiftool.exe ^(inkl. Ordner "exiftool_files"^) in diesen Ordner legen oder in den PATH aufnehmen.
  31.     pause & exit /b 1
  32. )
  33.  
  34. "%EXIFTOOL%" -ver >nul 2>&1
  35. if errorlevel 1 (
  36.     echo [FEHLER] ExifTool laesst sich nicht ausfuehren. Fehlt der Ordner "exiftool_files"?
  37.     pause & exit /b 1
  38. )
  39.  
  40. :: PowerShell wird fuer Datums- und Offset-Berechnung benoetigt
  41. where powershell >nul 2>&1
  42. if errorlevel 1 (
  43.     echo [FEHLER] PowerShell nicht gefunden^^! Wird fuer die Zeitzonen-Berechnung benoetigt.
  44.     pause & exit /b 1
  45. )
  46.  
  47. :: Pruefen ob ueberhaupt OSV-Dateien vorhanden sind
  48. set "OSV_COUNT=0"
  49. for %%F in (*.osv) do set /a OSV_COUNT+=1
  50. if %OSV_COUNT%==0 (
  51.     echo [FEHLER] Keine .OSV-Dateien in diesem Ordner gefunden.
  52.     echo Das Script muss gemeinsam mit den OSV- und den exportierten MP4-Dateien im selben Ordner liegen.
  53.     echo Aktueller Ordner: %CD%
  54.     pause & exit /b 1
  55. )
  56.  
  57. echo [INFO] %OSV_COUNT% OSV-Datei^(en^) gefunden.
  58. echo.
  59.  
  60. :: Benutzerabfrage: Quelle fuer das Aufnahmedatum
  61. echo Welche Quelle soll fuer das Aufnahmedatum verwendet werden?
  62. echo 1 - Dateiname der OSV (Standard)
  63. echo 2 - Aenderungsdatum der OSV
  64. set /p DATESOURCE="Eingabe (1 oder 2): "
  65.  
  66. if not "%DATESOURCE%"=="1" if not "%DATESOURCE%"=="2" (
  67.     echo Ungueltige Eingabe. Standard: Dateiname wird verwendet.
  68.     set DATESOURCE=1
  69. )
  70.  
  71. :: Benutzerabfrage: Zeitzone
  72. :: Automatisch Sommer-/Winterzeit erkennen fuer Deutschland
  73. 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"
  74.  
  75. :ASK_TZ
  76. set "TIMEZONE="
  77. echo.
  78. set /p "TIMEZONE=Zeitzone fuer Metadaten (Format: +/-XX:00, leer fuer Standard: !SYSTEM_TZ!): "
  79. if "!TIMEZONE!"=="" (
  80.     echo Leere Eingabe. Standard: !SYSTEM_TZ! wird verwendet
  81.     set "TIMEZONE=!SYSTEM_TZ!"
  82. ) else (
  83.     echo !TIMEZONE!| findstr /r "^[+-][0-9][0-9]:[0-9][0-9]$" >nul
  84.     if errorlevel 1 (
  85.         echo Ungueltige Eingabe bei Zeitzone^^! Beispiel: +02:00
  86.         goto ASK_TZ
  87.     )
  88. )
  89.  
  90. :: Benutzerabfrage: Videos zusaetzlich komprimieren?
  91. echo.
  92. set "COMPRESS="
  93. set /p "COMPRESS=Videos zusaetzlich mit ffmpeg komprimieren? (y/n): "
  94. if /i "!COMPRESS!"=="y" (
  95.     set "COMPRESS=y"
  96.     call :SETUP_COMPRESS
  97. ) else (
  98.     set "COMPRESS=n"
  99. )
  100.  
  101. echo.
  102. echo ----------------------------------------------------------
  103. echo.
  104.  
  105. set "CNT_OK=0"
  106. set "CNT_SKIP=0"
  107. set "CNT_ERR=0"
  108.  
  109. :: Schleife durch alle OSV-Dateien
  110. for %%F in (*.osv) do (
  111.     call :PROCESS "%%F"
  112.     echo.
  113. )
  114.  
  115. echo ----------------------------------------------------------
  116. echo Fertig. Erfolgreich: %CNT_OK%  Uebersprungen: %CNT_SKIP%  Fehler: %CNT_ERR%
  117. powershell -c [console]::beep(500,200)
  118. pause
  119. exit /b 0
  120.  
  121.  
  122. :: ==========================================================
  123. :: Verarbeitung einer einzelnen OSV-Datei
  124. :: ==========================================================
  125. :PROCESS
  126. set "OSV=%~1"
  127. set "BASE=%~n1"
  128. set "TIMESTAMP="
  129. set "MP4="
  130.  
  131. echo Bearbeite: !OSV!
  132.  
  133. :: --- Aufnahmedatum ermitteln ---
  134. if "%DATESOURCE%"=="1" (
  135.     call :DATE_FROM_NAME
  136.     if not defined TIMESTAMP (
  137.         echo [WARNUNG] Dateiname entspricht nicht dem Muster CAM_JJJJMMTTHHMMSS_... - verwende Aenderungsdatum
  138.         call :DATE_FROM_MTIME
  139.     )
  140. ) else (
  141.     call :DATE_FROM_MTIME
  142. )
  143.  
  144. if not defined TIMESTAMP (
  145.     echo [FEHLER] Kein gueltiges Datum ermittelbar fuer !OSV! - uebersprungen
  146.     set /a CNT_ERR+=1
  147.     goto :eof
  148. )
  149.  
  150. echo [INFO] Aufnahmedatum: !TIMESTAMP!!TIMEZONE!
  151.  
  152. :: --- Passende MP4 suchen ---
  153. if exist "!BASE!.mp4" (
  154.     set "MP4=!BASE!.mp4"
  155. ) else (
  156.     echo [WARNUNG] Keine passende Datei "!BASE!.mp4" gefunden.
  157.     set "CAND_COUNT=0"
  158.     for %%C in ("!BASE!*.mp4") do (
  159.         set /a CAND_COUNT+=1
  160.         echo         Moeglicher Treffer: %%~nxC
  161.     )
  162.     if !CAND_COUNT! EQU 0 echo         Keine MP4 mit passendem Namensanfang im Ordner.
  163.     goto :ASK_MP4
  164. )
  165. goto :MP4_OK
  166.  
  167. :ASK_MP4
  168. set "MANUAL="
  169. set /p "MANUAL=Anderen Dateinamen angeben (leer = ueberspringen): "
  170. if "!MANUAL!"=="" (
  171.     echo [OK] Uebersprungen: !OSV! - keine MP4 zugeordnet
  172.     set /a CNT_SKIP+=1
  173.     goto :eof
  174. )
  175. :: Endung ergaenzen, falls vergessen
  176. echo !MANUAL!| findstr /i /e ".mp4" >nul
  177. if errorlevel 1 set "MANUAL=!MANUAL!.mp4"
  178. if not exist "!MANUAL!" (
  179.     echo [FEHLER] Datei "!MANUAL!" existiert nicht.
  180.     goto :ASK_MP4
  181. )
  182. :: Sicherstellen, dass es kein Verzeichnis ist
  183. if exist "!MANUAL!\" (
  184.     echo [FEHLER] "!MANUAL!" ist ein Verzeichnis.
  185.     goto :ASK_MP4
  186. )
  187. set "MP4=!MANUAL!"
  188.  
  189. :MP4_OK
  190. :: --- Pruefen ob es wirklich eine lesbare MP4-Datei ist ---
  191. set "FILETYPE="
  192. for /f "usebackq delims=" %%T in (`%EXIFTOOL% -s3 -FileType "!MP4!" 2^>nul`) do set "FILETYPE=%%T"
  193. if /i not "!FILETYPE!"=="MP4" (
  194.     echo [FEHLER] "!MP4!" ist keine gueltige oder lesbare MP4-Datei ^(erkannt: "!FILETYPE!"^) - uebersprungen
  195.     set /a CNT_ERR+=1
  196.     goto :eof
  197. )
  198.  
  199. :: --- Datum in die Originaldatei schreiben ---
  200. call :WRITE_DATE "!MP4!"
  201. if "!WRITE_OK!"=="0" (
  202.     set /a CNT_ERR+=1
  203.     goto :eof
  204. )
  205.  
  206. :: --- Optional: Video komprimieren und Datum auch dort setzen ---
  207. if /i "%COMPRESS%"=="y" (
  208.     call :COMPRESS_FILE
  209. ) else (
  210.     set /a CNT_OK+=1
  211. )
  212. goto :eof
  213.  
  214.  
  215. :: ==========================================================
  216. :: Video mit ffmpeg komprimieren, danach Datum setzen
  217. :: ==========================================================
  218. :COMPRESS_FILE
  219. for %%N in ("!MP4!") do set "OUTBASE=%%~nN"
  220.  
  221. :: Bereits komprimierte Dateien nicht erneut verarbeiten
  222. echo !OUTBASE!| findstr /i "_crf" >nul
  223. if not errorlevel 1 (
  224.     echo [OK] Kompression uebersprungen: !MP4! - bereits komprimiertes Video
  225.     set /a CNT_OK+=1
  226.     goto :eof
  227. )
  228.  
  229. if "%CODECWAHL%"=="1" (
  230.     set "OUTFILE=!OUTBASE!_crf%CRF_WERT%.mp4"
  231. ) else (
  232.     set "OUTFILE=!OUTBASE!_AV1_crf%CRF_WERT%.mp4"
  233. )
  234.  
  235. if exist "!OUTFILE!" (
  236.     echo [OK] Kompression uebersprungen: !OUTFILE! - bereits mit gleichen Einstellungen gerendert
  237.     set /a CNT_SKIP+=1
  238.     goto :eof
  239. )
  240.  
  241. echo [INFO] Komprimiere nach: !OUTFILE!
  242. if "%CODECWAHL%"=="1" (
  243.     :: H.265
  244.     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!"
  245. ) else (
  246.     :: AV1
  247.     if !CRF_WERT! LEQ 22 (
  248.         set "PRESET=2"
  249.     ) else if !CRF_WERT! LEQ 28 (
  250.         set "PRESET=3"
  251.     ) else if !CRF_WERT! LEQ 35 (
  252.         set "PRESET=6"
  253.     ) else (
  254.         set "PRESET=10"
  255.     )
  256.     ffmpeg -nostdin -y -i "!MP4!" -c:v libsvtav1 -crf %CRF_WERT% -preset !PRESET! -pix_fmt yuv420p -movflags +faststart -c:a copy "!OUTFILE!"
  257. )
  258.  
  259. if errorlevel 1 (
  260.     echo [FEHLER] ffmpeg konnte "!MP4!" nicht komprimieren
  261.     if exist "!OUTFILE!" del "!OUTFILE!"
  262.     set /a CNT_ERR+=1
  263.     goto :eof
  264. )
  265.  
  266. call :WRITE_DATE "!OUTFILE!"
  267. if "!WRITE_OK!"=="0" (
  268.     set /a CNT_ERR+=1
  269.     goto :eof
  270. )
  271.  
  272. set /a CNT_OK+=1
  273. goto :eof
  274.  
  275. :: ==========================================================
  276. :: Datum per ExifTool in eine Datei schreiben und kontrollieren
  277. :: ==========================================================
  278. :WRITE_DATE
  279. set "TARGET=%~1"
  280. set "WRITE_OK=1"
  281.  
  282. :: --- Pruefen ob das Datum bereits korrekt gesetzt ist ---
  283. set "CURRENT="
  284. for /f "usebackq delims=" %%T in (`%EXIFTOOL% -s3 -QuickTime:CreateDate "!TARGET!" 2^>nul`) do set "CURRENT=%%T"
  285. if "!CURRENT!"=="!TIMESTAMP!" (
  286.     echo [OK] Datum bereits korrekt: !TARGET!
  287.     goto :eof
  288. )
  289.  
  290. "%EXIFTOOL%" -overwrite_original ^
  291.     "-DateTimeOriginal=!TIMESTAMP!!TIMEZONE!" ^
  292.     "-OffsetTimeOriginal=!TIMEZONE!" ^
  293.     "-QuickTime:CreateDate=!TIMESTAMP!" ^
  294.     "-QuickTime:ModifyDate=!TIMESTAMP!" ^
  295.     "-QuickTime:TrackCreateDate=!TIMESTAMP!" ^
  296.     "-QuickTime:TrackModifyDate=!TIMESTAMP!" ^
  297.     "-QuickTime:MediaCreateDate=!TIMESTAMP!" ^
  298.     "-QuickTime:MediaModifyDate=!TIMESTAMP!" ^
  299.     "-FileModifyDate=!TIMESTAMP!" ^
  300.     "!TARGET!"
  301.  
  302. if errorlevel 1 (
  303.     echo [FEHLER] ExifTool konnte "!TARGET!" nicht schreiben
  304.     set "WRITE_OK=0"
  305.     goto :eof
  306. )
  307.  
  308. :: --- Kontrolle: geschriebenen Wert zurueckgelesen ---
  309. set "VERIFY="
  310. for /f "usebackq delims=" %%T in (`%EXIFTOOL% -s3 -QuickTime:CreateDate "!TARGET!" 2^>nul`) do set "VERIFY=%%T"
  311. if not "!VERIFY!"=="!TIMESTAMP!" (
  312.     echo [FEHLER] Kontrolle fehlgeschlagen fuer "!TARGET!" - gelesen: !VERIFY!
  313.     set "WRITE_OK=0"
  314.     goto :eof
  315. )
  316.  
  317. echo [OK] Verarbeitet: !TARGET!
  318. goto :eof
  319.  
  320. :: ==========================================================
  321. :: Einstellungen fuer die Kompression abfragen
  322. :: ==========================================================
  323. :SETUP_COMPRESS
  324. :: ffprobe wird nicht benoetigt, da nicht geschnitten wird
  325. where ffmpeg >nul 2>&1
  326. if errorlevel 1 (
  327.     if exist "%~dp0ffmpeg.exe" (
  328.         set "PATH=%~dp0;%PATH%"
  329.     ) else (
  330.         echo [FEHLER] ffmpeg nicht gefunden^^! ffmpeg.exe in diesen Ordner legen oder in den PATH aufnehmen.
  331.         echo [INFO] Kompression wird deaktiviert, Datum wird trotzdem gesetzt.
  332.         set "COMPRESS=n"
  333.         goto :eof
  334.     )
  335. )
  336.  
  337. :: Benutzerabfrage: Codec-Auswahl
  338. echo.
  339. echo Waehle Codec:
  340. echo 1 - H.265 - Gute Kompression, breite Unterstuetzung (Standard)
  341. echo 2 - AV1 - Beste Kompression, Geschwindigkeit haengt von Qualitaetsstufe ab, fuer neuere Geraete
  342. set /p CODECWAHL="Eingabe (1 oder 2): "
  343.  
  344. if not "!CODECWAHL!"=="1" if not "!CODECWAHL!"=="2" (
  345.     echo Ungueltige Eingabe. Standard: H.265 wird verwendet.
  346.     set CODECWAHL=1
  347. )
  348.  
  349. :: Benutzerabfrage: CRF-Wert
  350. :ASK_CRF
  351. set CRF_WERT=
  352. if "!CODECWAHL!"=="1" (
  353.     echo H.265 CRF-Wert ^(18=hoch, 24=normal, 30=niedrig, 35=sehr niedrig^)
  354. ) else (
  355.     echo AV1 CRF-Wert ^(18=sehr hoch, 22=hoch, 30=normal, 40=niedrig, 50=sehr niedrig^)
  356. )
  357. set /p CRF_WERT="Welcher CRF-Wert soll verwendet werden? "
  358.  
  359. echo !CRF_WERT!| findstr /r "^[0-9][0-9]*$" >nul
  360. if errorlevel 1 goto :CRF_FEHLER
  361. if !CRF_WERT! LSS 16 goto :CRF_FEHLER
  362. if !CRF_WERT! GTR 50 goto :CRF_FEHLER
  363. goto :CRF_OK
  364. :CRF_FEHLER
  365. echo Ungueltige Eingabe bei CRF-Wert^^!
  366. goto ASK_CRF
  367. :CRF_OK
  368.  
  369. goto :eof
  370.  
  371. :: ==========================================================
  372. :: Datum aus dem OSV-Dateinamen (CAM_JJJJMMTTHHMMSS_...)
  373. :: ==========================================================
  374. :DATE_FROM_NAME
  375. 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
  376. if errorlevel 1 goto :eof
  377.  
  378. for /f "tokens=2 delims=_" %%A in ("!BASE!") do set "DATETIME=%%A"
  379. set "YYYY=!DATETIME:~0,4!"
  380. set "MM=!DATETIME:~4,2!"
  381. set "DD=!DATETIME:~6,2!"
  382. set "hh=!DATETIME:~8,2!"
  383. set "nn=!DATETIME:~10,2!"
  384. set "ss=!DATETIME:~12,2!"
  385.  
  386. set "TIMESTAMP=!YYYY!:!MM!:!DD! !hh!:!nn!:!ss!"
  387. goto :eof
  388.  
  389. :: ==========================================================
  390. :: Datum aus dem Aenderungsdatum der OSV-Datei
  391. :: ==========================================================
  392. :DATE_FROM_MTIME
  393. for /f "usebackq delims=" %%T in (`powershell -NoLogo -NoProfile -Command "(Get-Item -LiteralPath '!OSV!').LastWriteTime.ToString('yyyy:MM:dd HH:mm:ss')"`) do (
  394.     set "TIMESTAMP=%%T"
  395. )
  396. goto :eof
Advertisement