DJI Osmo 360 OSV Datefix Script
  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: www.gyan.dev/ffmpeg/builds/
  9. :: "exiftool-XXX.zip" hier herunterladen, entpacken, in das Verzeichnis kopieren und die .exe-Datei umbenennen in "exiftool.exe": exiftool.org
  10. :: Version 1.0 - 26.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. ffmpeg -nostdin -y -i "!MP4!" -c:v libx265 -crf %CRF_WERT% -preset slow -pix_fmt yuv420p -tag:v hvc1 -movflags +faststart -c:a copy "!OUTFILE!"
  244. ) else (
  245. ffmpeg -nostdin -y -i "!MP4!" -c:v libaom-av1 -crf %CRF_WERT% -cpu-used %CPU_USED% -pix_fmt yuv420p -movflags +faststart -c:a copy "!OUTFILE!"
  246. )
  247.  
  248. if errorlevel 1 (
  249. echo [FEHLER] ffmpeg konnte "!MP4!" nicht komprimieren
  250. if exist "!OUTFILE!" del "!OUTFILE!"
  251. set /a CNT_ERR+=1
  252. goto :eof
  253. )
  254.  
  255. call :WRITE_DATE "!OUTFILE!"
  256. if "!WRITE_OK!"=="0" (
  257. set /a CNT_ERR+=1
  258. goto :eof
  259. )
  260.  
  261. set /a CNT_OK+=1
  262. goto :eof
  263.  
  264.  
  265. :: ==========================================================
  266. :: Datum per ExifTool in eine Datei schreiben und kontrollieren
  267. :: ==========================================================
  268. :WRITE_DATE
  269. set "TARGET=%~1"
  270. set "WRITE_OK=1"
  271.  
  272. :: --- Pruefen ob das Datum bereits korrekt gesetzt ist ---
  273. set "CURRENT="
  274. for /f "usebackq delims=" %%T in (`%EXIFTOOL% -s3 -QuickTime:CreateDate "!TARGET!" 2^>nul`) do set "CURRENT=%%T"
  275. if "!CURRENT!"=="!TIMESTAMP!" (
  276. echo [OK] Datum bereits korrekt: !TARGET!
  277. goto :eof
  278. )
  279.  
  280. "%EXIFTOOL%" -overwrite_original ^
  281. "-DateTimeOriginal=!TIMESTAMP!!TIMEZONE!" ^
  282. "-OffsetTimeOriginal=!TIMEZONE!" ^
  283. "-QuickTime:CreateDate=!TIMESTAMP!" ^
  284. "-QuickTime:ModifyDate=!TIMESTAMP!" ^
  285. "-QuickTime:TrackCreateDate=!TIMESTAMP!" ^
  286. "-QuickTime:TrackModifyDate=!TIMESTAMP!" ^
  287. "-QuickTime:MediaCreateDate=!TIMESTAMP!" ^
  288. "-QuickTime:MediaModifyDate=!TIMESTAMP!" ^
  289. "-FileModifyDate=!TIMESTAMP!" ^
  290. "!TARGET!"
  291.  
  292. if errorlevel 1 (
  293. echo [FEHLER] ExifTool konnte "!TARGET!" nicht schreiben
  294. set "WRITE_OK=0"
  295. goto :eof
  296. )
  297.  
  298. :: --- Kontrolle: geschriebenen Wert zurueckgelesen ---
  299. set "VERIFY="
  300. for /f "usebackq delims=" %%T in (`%EXIFTOOL% -s3 -QuickTime:CreateDate "!TARGET!" 2^>nul`) do set "VERIFY=%%T"
  301. if not "!VERIFY!"=="!TIMESTAMP!" (
  302. echo [FEHLER] Kontrolle fehlgeschlagen fuer "!TARGET!" - gelesen: !VERIFY!
  303. set "WRITE_OK=0"
  304. goto :eof
  305. )
  306.  
  307. echo [OK] Verarbeitet: !TARGET!
  308. goto :eof
  309.  
  310.  
  311. :: ==========================================================
  312. :: Einstellungen fuer die Kompression abfragen
  313. :: ==========================================================
  314. :SETUP_COMPRESS
  315. :: ffprobe wird nicht benoetigt, da nicht geschnitten wird
  316. where ffmpeg >nul 2>&1
  317. if errorlevel 1 (
  318. if exist "%~dp0ffmpeg.exe" (
  319. set "PATH=%~dp0;%PATH%"
  320. ) else (
  321. echo [FEHLER] ffmpeg nicht gefunden^^! ffmpeg.exe in diesen Ordner legen oder in den PATH aufnehmen.
  322. echo [INFO] Kompression wird deaktiviert, Datum wird trotzdem gesetzt.
  323. set "COMPRESS=n"
  324. goto :eof
  325. )
  326. )
  327.  
  328. :: Benutzerabfrage: Codec-Auswahl
  329. echo.
  330. echo Waehle Codec:
  331. echo 1 - H.265 - Gute Kompression, schnellere Kodierung, breite Unterstuetzung (Standard)
  332. echo 2 - AV1 - Beste Kompression, aber sehr langsam, fuer neuere Geraete
  333. set /p CODECWAHL="Eingabe (1 oder 2): "
  334.  
  335. if not "!CODECWAHL!"=="1" if not "!CODECWAHL!"=="2" (
  336. echo Ungueltige Eingabe. Standard: H.265 wird verwendet.
  337. set CODECWAHL=1
  338. )
  339.  
  340. :: Benutzerabfrage: CRF-Wert
  341. :ASK_CRF
  342. set CRF_WERT=
  343. if "!CODECWAHL!"=="1" (
  344. echo H.265 CRF-Wert ^(18=hoch, 24=normal, 30=niedrig, 35=sehr niedrig^)
  345. ) else (
  346. echo AV1 CRF-Wert ^(20=hoch, 30=normal, 38=niedrig, 45=sehr niedrig^)
  347. )
  348. set /p CRF_WERT="Welcher CRF-Wert soll verwendet werden? "
  349.  
  350. echo !CRF_WERT!| findstr /r "^[0-9][0-9]*$" >nul
  351. if errorlevel 1 goto :CRF_FEHLER
  352. if !CRF_WERT! LSS 16 goto :CRF_FEHLER
  353. if !CRF_WERT! GTR 50 goto :CRF_FEHLER
  354. goto :CRF_OK
  355. :CRF_FEHLER
  356. echo Ungueltige Eingabe bei CRF-Wert^^!
  357. goto ASK_CRF
  358. :CRF_OK
  359.  
  360. :: AV1 - CPU-Used dynamisch bestimmen
  361. if !CRF_WERT! LEQ 20 (
  362. set "CPU_USED=2"
  363. ) else if !CRF_WERT! LEQ 28 (
  364. set "CPU_USED=4"
  365. ) else if !CRF_WERT! LEQ 35 (
  366. set "CPU_USED=6"
  367. ) else (
  368. set "CPU_USED=8"
  369. )
  370. goto :eof
  371.  
  372.  
  373. :: ==========================================================
  374. :: Datum aus dem OSV-Dateinamen (CAM_JJJJMMTTHHMMSS_...)
  375. :: ==========================================================
  376. :DATE_FROM_NAME
  377. 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
  378. if errorlevel 1 goto :eof
  379.  
  380. for /f "tokens=2 delims=_" %%A in ("!BASE!") do set "DATETIME=%%A"
  381. set "YYYY=!DATETIME:~0,4!"
  382. set "MM=!DATETIME:~4,2!"
  383. set "DD=!DATETIME:~6,2!"
  384. set "hh=!DATETIME:~8,2!"
  385. set "nn=!DATETIME:~10,2!"
  386. set "ss=!DATETIME:~12,2!"
  387.  
  388. set "TIMESTAMP=!YYYY!:!MM!:!DD! !hh!:!nn!:!ss!"
  389. goto :eof
  390.  
  391.  
  392. :: ==========================================================
  393. :: Datum aus dem Aenderungsdatum der OSV-Datei
  394. :: ==========================================================
  395. :DATE_FROM_MTIME
  396. for /f "usebackq delims=" %%T in (`powershell -NoLogo -NoProfile -Command "(Get-Item -LiteralPath '!OSV!').LastWriteTime.ToString('yyyy:MM:dd HH:mm:ss')"`) do (
  397. set "TIMESTAMP=%%T"
  398. )
  399. goto :eof
Pasted 2026-08-25 17:44:29

Short link: