exiftool-vendored.exe 13.0.0 → 13.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (208) hide show
  1. package/bin/exiftool.exe +0 -0
  2. package/bin/exiftool_files/exiftool.pl +169 -65
  3. package/bin/exiftool_files/lib/File/RandomAccess.pm +1 -1
  4. package/bin/exiftool_files/lib/File/RandomAccess.pod +2 -2
  5. package/bin/exiftool_files/lib/Image/ExifTool/AAC.pm +1 -1
  6. package/bin/exiftool_files/lib/Image/ExifTool/AES.pm +1 -1
  7. package/bin/exiftool_files/lib/Image/ExifTool/AFCP.pm +6 -6
  8. package/bin/exiftool_files/lib/Image/ExifTool/AIFF.pm +2 -2
  9. package/bin/exiftool_files/lib/Image/ExifTool/APE.pm +2 -2
  10. package/bin/exiftool_files/lib/Image/ExifTool/APP12.pm +1 -1
  11. package/bin/exiftool_files/lib/Image/ExifTool/ASF.pm +2 -2
  12. package/bin/exiftool_files/lib/Image/ExifTool/Apple.pm +11 -9
  13. package/bin/exiftool_files/lib/Image/ExifTool/Audible.pm +1 -1
  14. package/bin/exiftool_files/lib/Image/ExifTool/BMP.pm +1 -1
  15. package/bin/exiftool_files/lib/Image/ExifTool/BPG.pm +1 -1
  16. package/bin/exiftool_files/lib/Image/ExifTool/BZZ.pm +1 -1
  17. package/bin/exiftool_files/lib/Image/ExifTool/BigTIFF.pm +1 -1
  18. package/bin/exiftool_files/lib/Image/ExifTool/BuildTagLookup.pm +46 -26
  19. package/bin/exiftool_files/lib/Image/ExifTool/CBOR.pm +5 -2
  20. package/bin/exiftool_files/lib/Image/ExifTool/Canon.pm +68 -28
  21. package/bin/exiftool_files/lib/Image/ExifTool/CanonCustom.pm +1 -1
  22. package/bin/exiftool_files/lib/Image/ExifTool/CanonRaw.pm +1 -1
  23. package/bin/exiftool_files/lib/Image/ExifTool/CanonVRD.pm +1 -1
  24. package/bin/exiftool_files/lib/Image/ExifTool/CaptureOne.pm +1 -1
  25. package/bin/exiftool_files/lib/Image/ExifTool/Casio.pm +1 -1
  26. package/bin/exiftool_files/lib/Image/ExifTool/Charset.pm +1 -1
  27. package/bin/exiftool_files/lib/Image/ExifTool/DICOM.pm +1 -1
  28. package/bin/exiftool_files/lib/Image/ExifTool/DJI.pm +196 -30
  29. package/bin/exiftool_files/lib/Image/ExifTool/DNG.pm +1 -1
  30. package/bin/exiftool_files/lib/Image/ExifTool/DPX.pm +1 -1
  31. package/bin/exiftool_files/lib/Image/ExifTool/DV.pm +1 -1
  32. package/bin/exiftool_files/lib/Image/ExifTool/DarwinCore.pm +1 -1
  33. package/bin/exiftool_files/lib/Image/ExifTool/DjVu.pm +1 -1
  34. package/bin/exiftool_files/lib/Image/ExifTool/EXE.pm +138 -33
  35. package/bin/exiftool_files/lib/Image/ExifTool/Exif.pm +29 -16
  36. package/bin/exiftool_files/lib/Image/ExifTool/FITS.pm +3 -3
  37. package/bin/exiftool_files/lib/Image/ExifTool/FLAC.pm +1 -1
  38. package/bin/exiftool_files/lib/Image/ExifTool/FLIF.pm +3 -3
  39. package/bin/exiftool_files/lib/Image/ExifTool/FLIR.pm +1 -1
  40. package/bin/exiftool_files/lib/Image/ExifTool/Fixup.pm +1 -1
  41. package/bin/exiftool_files/lib/Image/ExifTool/Flash.pm +1 -1
  42. package/bin/exiftool_files/lib/Image/ExifTool/FlashPix.pm +17 -21
  43. package/bin/exiftool_files/lib/Image/ExifTool/Font.pm +2 -2
  44. package/bin/exiftool_files/lib/Image/ExifTool/FotoStation.pm +1 -1
  45. package/bin/exiftool_files/lib/Image/ExifTool/FujiFilm.pm +1 -1
  46. package/bin/exiftool_files/lib/Image/ExifTool/GE.pm +1 -1
  47. package/bin/exiftool_files/lib/Image/ExifTool/GIF.pm +144 -93
  48. package/bin/exiftool_files/lib/Image/ExifTool/GIMP.pm +1 -1
  49. package/bin/exiftool_files/lib/Image/ExifTool/GM.pm +1 -1
  50. package/bin/exiftool_files/lib/Image/ExifTool/GPS.pm +34 -30
  51. package/bin/exiftool_files/lib/Image/ExifTool/GeoTiff.pm +1 -1
  52. package/bin/exiftool_files/lib/Image/ExifTool/Geolocation.dat +0 -0
  53. package/bin/exiftool_files/lib/Image/ExifTool/Geolocation.pm +19 -9
  54. package/bin/exiftool_files/lib/Image/ExifTool/Geotag.pm +46 -12
  55. package/bin/exiftool_files/lib/Image/ExifTool/GoPro.pm +120 -8
  56. package/bin/exiftool_files/lib/Image/ExifTool/H264.pm +1 -1
  57. package/bin/exiftool_files/lib/Image/ExifTool/HP.pm +2 -2
  58. package/bin/exiftool_files/lib/Image/ExifTool/HTML.pm +1 -1
  59. package/bin/exiftool_files/lib/Image/ExifTool/HtmlDump.pm +1 -1
  60. package/bin/exiftool_files/lib/Image/ExifTool/ICC_Profile.pm +81 -2
  61. package/bin/exiftool_files/lib/Image/ExifTool/ICO.pm +1 -1
  62. package/bin/exiftool_files/lib/Image/ExifTool/ID3.pm +8 -8
  63. package/bin/exiftool_files/lib/Image/ExifTool/IPTC.pm +10 -7
  64. package/bin/exiftool_files/lib/Image/ExifTool/ISO.pm +1 -1
  65. package/bin/exiftool_files/lib/Image/ExifTool/ITC.pm +1 -1
  66. package/bin/exiftool_files/lib/Image/ExifTool/Import.pm +5 -4
  67. package/bin/exiftool_files/lib/Image/ExifTool/InDesign.pm +2 -2
  68. package/bin/exiftool_files/lib/Image/ExifTool/InfiRay.pm +1 -1
  69. package/bin/exiftool_files/lib/Image/ExifTool/JPEG.pm +38 -5
  70. package/bin/exiftool_files/lib/Image/ExifTool/JPEGDigest.pm +1 -1
  71. package/bin/exiftool_files/lib/Image/ExifTool/JSON.pm +1 -1
  72. package/bin/exiftool_files/lib/Image/ExifTool/JVC.pm +1 -1
  73. package/bin/exiftool_files/lib/Image/ExifTool/Jpeg2000.pm +10 -9
  74. package/bin/exiftool_files/lib/Image/ExifTool/Kodak.pm +1 -1
  75. package/bin/exiftool_files/lib/Image/ExifTool/KyoceraRaw.pm +1 -1
  76. package/bin/exiftool_files/lib/Image/ExifTool/LIF.pm +1 -1
  77. package/bin/exiftool_files/lib/Image/ExifTool/LNK.pm +2 -2
  78. package/bin/exiftool_files/lib/Image/ExifTool/Lang/cs.pm +1 -1
  79. package/bin/exiftool_files/lib/Image/ExifTool/Lang/de.pm +1 -1
  80. package/bin/exiftool_files/lib/Image/ExifTool/Lang/en_ca.pm +1 -1
  81. package/bin/exiftool_files/lib/Image/ExifTool/Lang/en_gb.pm +1 -1
  82. package/bin/exiftool_files/lib/Image/ExifTool/Lang/es.pm +1 -1
  83. package/bin/exiftool_files/lib/Image/ExifTool/Lang/fi.pm +1 -1
  84. package/bin/exiftool_files/lib/Image/ExifTool/Lang/fr.pm +1 -1
  85. package/bin/exiftool_files/lib/Image/ExifTool/Lang/it.pm +1 -1
  86. package/bin/exiftool_files/lib/Image/ExifTool/Lang/ja.pm +1 -1
  87. package/bin/exiftool_files/lib/Image/ExifTool/Lang/ko.pm +1 -1
  88. package/bin/exiftool_files/lib/Image/ExifTool/Lang/nl.pm +1 -1
  89. package/bin/exiftool_files/lib/Image/ExifTool/Lang/pl.pm +1 -1
  90. package/bin/exiftool_files/lib/Image/ExifTool/Lang/ru.pm +1 -1
  91. package/bin/exiftool_files/lib/Image/ExifTool/Lang/sk.pm +1 -1
  92. package/bin/exiftool_files/lib/Image/ExifTool/Lang/sv.pm +1 -1
  93. package/bin/exiftool_files/lib/Image/ExifTool/Lang/tr.pm +1 -1
  94. package/bin/exiftool_files/lib/Image/ExifTool/Lang/zh_cn.pm +1 -1
  95. package/bin/exiftool_files/lib/Image/ExifTool/Lang/zh_tw.pm +1 -1
  96. package/bin/exiftool_files/lib/Image/ExifTool/Leaf.pm +1 -1
  97. package/bin/exiftool_files/lib/Image/ExifTool/LigoGPS.pm +409 -0
  98. package/bin/exiftool_files/lib/Image/ExifTool/Lytro.pm +1 -1
  99. package/bin/exiftool_files/lib/Image/ExifTool/M2TS.pm +57 -18
  100. package/bin/exiftool_files/lib/Image/ExifTool/MIE.pm +15 -6
  101. package/bin/exiftool_files/lib/Image/ExifTool/MIEUnits.pod +1 -1
  102. package/bin/exiftool_files/lib/Image/ExifTool/MIFF.pm +1 -1
  103. package/bin/exiftool_files/lib/Image/ExifTool/MISB.pm +1 -1
  104. package/bin/exiftool_files/lib/Image/ExifTool/MNG.pm +1 -1
  105. package/bin/exiftool_files/lib/Image/ExifTool/MOI.pm +1 -1
  106. package/bin/exiftool_files/lib/Image/ExifTool/MPC.pm +1 -1
  107. package/bin/exiftool_files/lib/Image/ExifTool/MPEG.pm +1 -1
  108. package/bin/exiftool_files/lib/Image/ExifTool/MPF.pm +1 -1
  109. package/bin/exiftool_files/lib/Image/ExifTool/MRC.pm +1 -1
  110. package/bin/exiftool_files/lib/Image/ExifTool/MWG.pm +1 -1
  111. package/bin/exiftool_files/lib/Image/ExifTool/MXF.pm +3 -3
  112. package/bin/exiftool_files/lib/Image/ExifTool/MacOS.pm +3 -2
  113. package/bin/exiftool_files/lib/Image/ExifTool/MakerNotes.pm +1 -1
  114. package/bin/exiftool_files/lib/Image/ExifTool/Matroska.pm +22 -6
  115. package/bin/exiftool_files/lib/Image/ExifTool/Microsoft.pm +2 -2
  116. package/bin/exiftool_files/lib/Image/ExifTool/Minolta.pm +1 -1
  117. package/bin/exiftool_files/lib/Image/ExifTool/MinoltaRaw.pm +1 -1
  118. package/bin/exiftool_files/lib/Image/ExifTool/Motorola.pm +1 -1
  119. package/bin/exiftool_files/lib/Image/ExifTool/Nikon.pm +457 -103
  120. package/bin/exiftool_files/lib/Image/ExifTool/NikonCapture.pm +1 -1
  121. package/bin/exiftool_files/lib/Image/ExifTool/NikonCustom.pm +6 -6
  122. package/bin/exiftool_files/lib/Image/ExifTool/NikonSettings.pm +1 -1
  123. package/bin/exiftool_files/lib/Image/ExifTool/Nintendo.pm +1 -1
  124. package/bin/exiftool_files/lib/Image/ExifTool/OOXML.pm +8 -8
  125. package/bin/exiftool_files/lib/Image/ExifTool/Ogg.pm +1 -1
  126. package/bin/exiftool_files/lib/Image/ExifTool/Olympus.pm +1 -1
  127. package/bin/exiftool_files/lib/Image/ExifTool/OpenEXR.pm +1 -1
  128. package/bin/exiftool_files/lib/Image/ExifTool/Opus.pm +1 -1
  129. package/bin/exiftool_files/lib/Image/ExifTool/Other.pm +1 -1
  130. package/bin/exiftool_files/lib/Image/ExifTool/PCX.pm +1 -1
  131. package/bin/exiftool_files/lib/Image/ExifTool/PDF.pm +49 -18
  132. package/bin/exiftool_files/lib/Image/ExifTool/PGF.pm +1 -1
  133. package/bin/exiftool_files/lib/Image/ExifTool/PICT.pm +1 -1
  134. package/bin/exiftool_files/lib/Image/ExifTool/PLIST.pm +4 -4
  135. package/bin/exiftool_files/lib/Image/ExifTool/PLUS.pm +1 -1
  136. package/bin/exiftool_files/lib/Image/ExifTool/PNG.pm +20 -8
  137. package/bin/exiftool_files/lib/Image/ExifTool/PPM.pm +12 -3
  138. package/bin/exiftool_files/lib/Image/ExifTool/PSP.pm +1 -1
  139. package/bin/exiftool_files/lib/Image/ExifTool/Palm.pm +1 -1
  140. package/bin/exiftool_files/lib/Image/ExifTool/Panasonic.pm +27 -3
  141. package/bin/exiftool_files/lib/Image/ExifTool/PanasonicRaw.pm +1 -1
  142. package/bin/exiftool_files/lib/Image/ExifTool/Parrot.pm +1 -1
  143. package/bin/exiftool_files/lib/Image/ExifTool/Pentax.pm +1 -1
  144. package/bin/exiftool_files/lib/Image/ExifTool/PhaseOne.pm +4 -4
  145. package/bin/exiftool_files/lib/Image/ExifTool/PhotoCD.pm +1 -1
  146. package/bin/exiftool_files/lib/Image/ExifTool/PhotoMechanic.pm +1 -1
  147. package/bin/exiftool_files/lib/Image/ExifTool/Photoshop.pm +65 -4
  148. package/bin/exiftool_files/lib/Image/ExifTool/PostScript.pm +1 -1
  149. package/bin/exiftool_files/lib/Image/ExifTool/PrintIM.pm +1 -1
  150. package/bin/exiftool_files/lib/Image/ExifTool/Protobuf.pm +270 -0
  151. package/bin/exiftool_files/lib/Image/ExifTool/Qualcomm.pm +1 -1
  152. package/bin/exiftool_files/lib/Image/ExifTool/QuickTime.pm +327 -88
  153. package/bin/exiftool_files/lib/Image/ExifTool/QuickTimeStream.pl +199 -195
  154. package/bin/exiftool_files/lib/Image/ExifTool/README +12 -2
  155. package/bin/exiftool_files/lib/Image/ExifTool/RIFF.pm +21 -6
  156. package/bin/exiftool_files/lib/Image/ExifTool/RSRC.pm +1 -1
  157. package/bin/exiftool_files/lib/Image/ExifTool/RTF.pm +2 -2
  158. package/bin/exiftool_files/lib/Image/ExifTool/Radiance.pm +1 -1
  159. package/bin/exiftool_files/lib/Image/ExifTool/Rawzor.pm +1 -1
  160. package/bin/exiftool_files/lib/Image/ExifTool/Real.pm +1 -1
  161. package/bin/exiftool_files/lib/Image/ExifTool/Reconyx.pm +1 -1
  162. package/bin/exiftool_files/lib/Image/ExifTool/Red.pm +1 -1
  163. package/bin/exiftool_files/lib/Image/ExifTool/Ricoh.pm +4 -4
  164. package/bin/exiftool_files/lib/Image/ExifTool/Samsung.pm +6 -2
  165. package/bin/exiftool_files/lib/Image/ExifTool/Sanyo.pm +1 -1
  166. package/bin/exiftool_files/lib/Image/ExifTool/Scalado.pm +1 -1
  167. package/bin/exiftool_files/lib/Image/ExifTool/Shift.pl +1 -1
  168. package/bin/exiftool_files/lib/Image/ExifTool/Shortcuts.pm +1 -1
  169. package/bin/exiftool_files/lib/Image/ExifTool/Sigma.pm +1 -1
  170. package/bin/exiftool_files/lib/Image/ExifTool/SigmaRaw.pm +1 -1
  171. package/bin/exiftool_files/lib/Image/ExifTool/Sony.pm +6 -5
  172. package/bin/exiftool_files/lib/Image/ExifTool/SonyIDC.pm +1 -1
  173. package/bin/exiftool_files/lib/Image/ExifTool/Stim.pm +1 -1
  174. package/bin/exiftool_files/lib/Image/ExifTool/TagInfoXML.pm +6 -5
  175. package/bin/exiftool_files/lib/Image/ExifTool/TagLookup.pm +7028 -6968
  176. package/bin/exiftool_files/lib/Image/ExifTool/TagNames.pod +12079 -11630
  177. package/bin/exiftool_files/lib/Image/ExifTool/Text.pm +4 -3
  178. package/bin/exiftool_files/lib/Image/ExifTool/Theora.pm +1 -1
  179. package/bin/exiftool_files/lib/Image/ExifTool/Torrent.pm +3 -3
  180. package/bin/exiftool_files/lib/Image/ExifTool/Trailer.pm +318 -0
  181. package/bin/exiftool_files/lib/Image/ExifTool/Unknown.pm +1 -1
  182. package/bin/exiftool_files/lib/Image/ExifTool/VCard.pm +3 -3
  183. package/bin/exiftool_files/lib/Image/ExifTool/Validate.pm +6 -6
  184. package/bin/exiftool_files/lib/Image/ExifTool/Vorbis.pm +1 -1
  185. package/bin/exiftool_files/lib/Image/ExifTool/WPG.pm +1 -1
  186. package/bin/exiftool_files/lib/Image/ExifTool/WTV.pm +1 -1
  187. package/bin/exiftool_files/lib/Image/ExifTool/WriteCanonRaw.pl +1 -1
  188. package/bin/exiftool_files/lib/Image/ExifTool/WriteExif.pl +3 -3
  189. package/bin/exiftool_files/lib/Image/ExifTool/WriteIPTC.pl +1 -1
  190. package/bin/exiftool_files/lib/Image/ExifTool/WritePDF.pl +1 -1
  191. package/bin/exiftool_files/lib/Image/ExifTool/WritePNG.pl +1 -1
  192. package/bin/exiftool_files/lib/Image/ExifTool/WritePhotoshop.pl +1 -1
  193. package/bin/exiftool_files/lib/Image/ExifTool/WritePostScript.pl +1 -1
  194. package/bin/exiftool_files/lib/Image/ExifTool/WriteQuickTime.pl +170 -79
  195. package/bin/exiftool_files/lib/Image/ExifTool/WriteRIFF.pl +17 -6
  196. package/bin/exiftool_files/lib/Image/ExifTool/WriteXMP.pl +3 -3
  197. package/bin/exiftool_files/lib/Image/ExifTool/Writer.pl +89 -96
  198. package/bin/exiftool_files/lib/Image/ExifTool/XISF.pm +1 -1
  199. package/bin/exiftool_files/lib/Image/ExifTool/XMP.pm +28 -13
  200. package/bin/exiftool_files/lib/Image/ExifTool/XMP2.pl +106 -3
  201. package/bin/exiftool_files/lib/Image/ExifTool/XMPStruct.pl +2 -3
  202. package/bin/exiftool_files/lib/Image/ExifTool/ZIP.pm +2 -2
  203. package/bin/exiftool_files/lib/Image/ExifTool/ZISRAW.pm +1 -1
  204. package/bin/exiftool_files/lib/Image/ExifTool/iWork.pm +1 -1
  205. package/bin/exiftool_files/lib/Image/ExifTool.pm +467 -228
  206. package/bin/exiftool_files/lib/Image/ExifTool.pod +118 -72
  207. package/bin/exiftool_files/windows_exiftool.txt +96 -51
  208. package/package.json +8 -8
@@ -29,6 +29,7 @@ sub Process360Fly($$$);
29
29
  sub ProcessFMAS($$$);
30
30
  sub ProcessWolfbox($$$);
31
31
  sub ProcessCAMM($$$);
32
+ sub OrderCipherDigits($$$;$);
32
33
 
33
34
  # QuickTime data types that have ExifTool equivalents
34
35
  # (ref https://developer.apple.com/library/content/documentation/QuickTime/QTFF/Metadata/Metadata.html#//apple_ref/doc/uid/TP40000939-CH1-SW35)
@@ -94,6 +95,7 @@ my %insvDataLen = (
94
95
  # 0xb00 => 10, # ? (Insta360 X3)
95
96
  # 0xd00 => 10, # ? (Insta360 Ace Pro)
96
97
  # 0x1200 ? # ? (Insta360 Ace Pro)
98
+ # 0x1600 ? # ? (?)
97
99
  );
98
100
 
99
101
  # limit the default amount of data we read for some record types
@@ -109,7 +111,7 @@ my %insvLimit = (
109
111
  The tags below are extracted from timed metadata in QuickTime and other
110
112
  formats of video files when the ExtractEmbedded option is used. Although
111
113
  most of these tags are combined into the single table below, ExifTool
112
- currently reads 78 different formats of timed GPS metadata from video files.
114
+ currently reads 100 different types of timed GPS metadata from video files.
113
115
  },
114
116
  VARS => { NO_ID => 1 },
115
117
  GPSLatitude => { PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")', RawConv => '$$self{FoundGPSLatitude} = 1; $val' },
@@ -145,7 +147,7 @@ my %insvLimit = (
145
147
  CameraDateTime=>{ PrintConv => '$self->ConvertDateTime($val)', Groups => { 2 => 'Time' } },
146
148
  DateTimeStamp =>{ PrintConv => '$self->ConvertDateTime($val)', Groups => { 2 => 'Time' } },
147
149
  VideoTimeStamp => { Groups => { 2 => 'Video' } },
148
- Accelerometer=> { Notes => '3-axis acceleration in units of g' },
150
+ Accelerometer=> { Notes => '3-axis acceleration, usually in units of g' },
149
151
  AccelerometerData => { },
150
152
  AngularVelocity => { },
151
153
  GSensor => { },
@@ -339,14 +341,21 @@ my %insvLimit = (
339
341
  Groups => { 2 => 'Preview' },
340
342
  RawConv => '$self->ValidateImage(\$val,$tag)',
341
343
  },
342
- # djmd - DJI AC003 Osmo Action 4 cam
343
- #TODO djmd => { SubDirectory => { TagTable => 'Image::ExifTool::DJI::djmd', ByteOrder => 'Little-Endian' } },
344
- # (also DJI_20240615181302_0006_D.LRF)
345
- # dbgi - DJI AC003 Osmo Action 4 cam -- lots more unknown stuff
344
+ djmd => { # (DJI AC003 Osmo Action 4 cam)
345
+ Name => 'DJIMetadata',
346
+ SubDirectory => { TagTable => 'Image::ExifTool::DJI::Protobuf' },
347
+ },
348
+ dbgi => { # (DJI AC003 Osmo Action 4 cam)
349
+ Name => 'DJIDebug',
350
+ Unknown => 2,
351
+ Notes => 'extracted only if Unknown option is 2 or greater',
352
+ SubDirectory => { TagTable => 'Image::ExifTool::DJI::Protobuf' },
353
+ },
346
354
  Unknown00 => { Unknown => 1 },
347
355
  Unknown01 => { Unknown => 1 },
348
356
  Unknown02 => { Unknown => 1 },
349
357
  Unknown03 => { Unknown => 1 },
358
+ MagneticVariation => { }, # (from LIGOGPSINFO)
350
359
  );
351
360
 
352
361
  # tags found in 'camm' type 0 timed metadata (ref 4)
@@ -894,7 +903,7 @@ sub FoundSomething($$;$$)
894
903
  #------------------------------------------------------------------------------
895
904
  # Approximate GPSDateTime value from sample time and CreateDate
896
905
  # Inputs: 0) ExifTool ref, 1) tag table ptr, 2) sample time (s)
897
- # 3) true if CreateDate is at end of video, 4) flag if CreateDate is UTC
906
+ # 3) true if CreateDate is UTC
898
907
  # Notes: Uses ExifTool CreateDateAtEnd as flag to subtract video duration
899
908
  sub SetGPSDateTime($$$;$)
900
909
  {
@@ -905,9 +914,9 @@ sub SetGPSDateTime($$$;$)
905
914
  if ($$et{CreateDateAtEnd}) { # adjust if CreateDate is at end of video
906
915
  return unless $$value{TimeScale} and $$value{Duration};
907
916
  $sampleTime -= $$value{Duration} / $$value{TimeScale};
908
- $et->WarnOnce('Approximating GPSDateTime as CreateDate - Duration + SampleTime', 1);
917
+ $et->Warn('Approximating GPSDateTime as CreateDate - Duration + SampleTime', 1);
909
918
  } else {
910
- $et->WarnOnce('Approximating GPSDateTime as CreateDate + SampleTime', 1);
919
+ $et->Warn('Approximating GPSDateTime as CreateDate + SampleTime', 1);
911
920
  }
912
921
  my $utc = $et->Options('QuickTimeUTC');
913
922
  $utc = $isUTC unless defined $utc; # (allow QuickTimeUTC=0 to override $isUTC default)
@@ -1268,7 +1277,7 @@ sub ProcessSamples($)
1268
1277
  ($startChunk, $samplesPerChunk, $descIdx) = @{shift @$stsc};
1269
1278
  $nextChunk = $$stsc[0][0] if @$stsc;
1270
1279
  }
1271
- @$size < @$start + $samplesPerChunk and $et->WarnOnce('Sample size error'), last;
1280
+ @$size < @$start + $samplesPerChunk and $et->Warn('Sample size error'), last;
1272
1281
  last unless defined $chunkStart and length $chunkStart;
1273
1282
  my $sampleStart = $chunkStart;
1274
1283
  my $chunkSize = 0;
@@ -1296,7 +1305,7 @@ Sample: for ($i=0; ; ) {
1296
1305
  push @chunkSize, $chunkSize;
1297
1306
  ++$iChunk;
1298
1307
  }
1299
- @$start == @$size or $et->WarnOnce('Incorrect sample start/size count'), return;
1308
+ @$start == @$size or $et->Warn('Incorrect sample start/size count'), return;
1300
1309
  # process as chunks if we are only interested in calculating hash
1301
1310
  if ($type eq 'soun' or $type eq 'vide') {
1302
1311
  $start = $stco;
@@ -1326,7 +1335,7 @@ Sample: for ($i=0; ; ) {
1326
1335
  $hdrFmt = ($hdrLen == 4 ? 'N' : $hdrLen == 2 ? 'n' : 'C');
1327
1336
  require Image::ExifTool::H264;
1328
1337
  }
1329
-
1338
+
1330
1339
  # loop through all samples
1331
1340
  for ($i=0; $i<@$start and $i<@$size; ++$i) {
1332
1341
 
@@ -1346,11 +1355,11 @@ Sample: for ($i=0; ; ) {
1346
1355
  }
1347
1356
  }
1348
1357
  # read the sample data
1349
- $raf->Seek($$start[$i], 0) or $et->WarnOnce("Seek error in $type data"), next;
1358
+ $raf->Seek($$start[$i], 0) or $et->Warn("Seek error in $type data"), next;
1350
1359
  my $buff;
1351
1360
  my $n = $raf->Read($buff, $size);
1352
1361
  unless ($n == $size) {
1353
- $et->WarnOnce("Error reading $type data");
1362
+ $et->Warn("Error reading $type data");
1354
1363
  next unless $n;
1355
1364
  $size = $n;
1356
1365
  }
@@ -1432,7 +1441,7 @@ Sample: for ($i=0; ; ) {
1432
1441
 
1433
1442
  if ($$tagTbl{$metaFormat}) {
1434
1443
  my $tagInfo = $et->GetTagInfo($tagTbl, $metaFormat, \$buff);
1435
- if ($tagInfo) {
1444
+ if ($tagInfo and (not $$tagInfo{Unknown} or $$et{OPTIONS}{Unknown} >= $$tagInfo{Unknown})) {
1436
1445
  FoundSomething($et, $tagTbl, $time[$i], $dur[$i]);
1437
1446
  $$et{ee} = $ee; # need ee information for 'keys'
1438
1447
  $et->HandleTag($tagTbl, $metaFormat, undef,
@@ -1442,6 +1451,15 @@ Sample: for ($i=0; ; ) {
1442
1451
  TagInfo => $tagInfo,
1443
1452
  );
1444
1453
  delete $$et{ee};
1454
+ # synthesize GPSDateTime if necessary for djmd metadata
1455
+ if ($metaFormat eq 'djmd') {
1456
+ if (defined $$et{GPSLatitude} and defined $$et{GPSLongitude} and not $$et{GPSDateTime}) {
1457
+ SetGPSDateTime($et, $tagTbl, $time[$i], 1); # (NC)
1458
+ }
1459
+ delete $$et{GPSLatitude};
1460
+ delete $$et{GPSLongitude};
1461
+ delete $$et{GPSDateTime};
1462
+ }
1445
1463
  } elsif ($metaFormat eq 'camm' and $buff =~ /^X/) {
1446
1464
  # seen 'camm' metadata in this format (X/Y/Z acceleration and G force? + GPRMC + ?)
1447
1465
  # "X0000.0000Y0000.0000Z0000.0000G0000.0000$GPRMC,000125,V,,,,,000.0,,280908,002.1,N*71~, 794021 \x0a"
@@ -1494,7 +1512,7 @@ Sample: for ($i=0; ; ) {
1494
1512
  # clean up
1495
1513
  $raf->Seek($tell, 0); # restore original file position
1496
1514
  delete $$et{DOC_NUM};
1497
- $$et{HandlerType} = $$et{HanderDesc} = '';
1515
+ $$et{HandlerType} = '';
1498
1516
  }
1499
1517
 
1500
1518
  #------------------------------------------------------------------------------
@@ -1545,7 +1563,7 @@ sub ProcessFreeGPS($$$)
1545
1563
  my ($et, $dirInfo, $tagTbl) = @_;
1546
1564
  my $dataPt = $$dirInfo{DataPt};
1547
1565
  my $dirLen = length $$dataPt;
1548
- my ($yr, $mon, $day, $hr, $min, $sec, $stat, $lbl, $ddd);
1566
+ my ($yr, $mon, $day, $hr, $min, $sec, $ss, $stat, $lbl, $ddd, $done);
1549
1567
  my ($lat, $latRef, $lon, $lonRef, $spd, $trk, $alt, @acc, @xtra);
1550
1568
 
1551
1569
  return 0 if $dirLen < 82;
@@ -1670,7 +1688,7 @@ sub ProcessFreeGPS($$$)
1670
1688
  }
1671
1689
  if ($notEnc and $notStr) {
1672
1690
 
1673
- $debug and $et->FoundTag(GPSType => '3a');
1691
+ $debug and $et->FoundTag(GPSType => 3);
1674
1692
  # decode freeGPS from ViofoA119v3 dashcam (similar to Novatek GPS format)
1675
1693
  # 0000: 00 00 40 00 66 72 65 65 47 50 53 20 f0 03 00 00 [..@.freeGPS ....]
1676
1694
  # 0010: 05 00 00 00 2f 00 00 00 03 00 00 00 13 00 00 00 [..../...........]
@@ -1684,7 +1702,7 @@ sub ProcessFreeGPS($$$)
1684
1702
  ($sec,$min,$hr,$day,$mon,$yr) = gmtime($time);
1685
1703
  $yr += 1900;
1686
1704
  ++$mon;
1687
- $et->WarnOnce('Converting GPSDateTime to UTC based on local time zone',1);
1705
+ $et->Warn('Converting GPSDateTime to UTC based on local time zone',1);
1688
1706
  }
1689
1707
  $lat = GetFloat($dataPt, 0x2c);
1690
1708
  $lon = GetFloat($dataPt, 0x30);
@@ -1698,7 +1716,7 @@ sub ProcessFreeGPS($$$)
1698
1716
 
1699
1717
  } else {
1700
1718
 
1701
- $debug and $et->FoundTag(GPSType => '3b');
1719
+ $debug and $et->FoundTag(GPSType => 4);
1702
1720
  # decode freeGPS from E-ACE B44 dashcam
1703
1721
  # 0000: 00 00 40 00 66 72 65 65 47 50 53 20 f0 03 00 00 [..@.freeGPS ....]
1704
1722
  # 0010: 08 00 00 00 22 00 00 00 01 00 00 00 18 00 00 00 [...."...........]
@@ -1729,40 +1747,76 @@ sub ProcessFreeGPS($$$)
1729
1747
  ($lon = DecryptLucky($ln, $key)) =~ /^\d{1,5}\.\d+$/ or undef($lon), next;
1730
1748
  last;
1731
1749
  }
1732
- $lon or $et->WarnOnce('Unknown encryption for latitude/longitude');
1750
+ $lon or $et->Warn('Unknown encryption for latitude/longitude');
1733
1751
  }
1734
1752
  }
1735
1753
 
1736
- } elsif ($$dataPt =~ /^.{21}\0\0\0A([NS])([EW])/s) {
1754
+ } elsif ($$dataPt =~ /^(.{16}|.{48}|.{80})LIGOGPSINFO\0/s and length($$dataPt) >= length($1) + 0x84) {
1737
1755
 
1738
- $debug and $et->FoundTag(GPSType => 4);
1739
- # also decode 'gpmd' chunk from Kingslim D4 dashcam videos
1740
- # 0000: 0a 00 00 00 0b 00 00 00 07 00 00 00 e5 07 00 00 [................]
1741
- # 0010: 06 00 00 00 03 00 00 00 41 4e 57 31 91 52 83 45 [........ANW1.R.E]
1742
- # 0020: 15 70 fe c5 29 5c c3 41 ae c7 af 42 00 00 d1 be [.p..)\.A...B....]
1743
- # 0030: 00 00 80 3b 00 00 2c 3e 00 00 00 00 00 00 00 00 [...;..,>........]
1744
- # 0040: 00 00 00 00 00 00 00 00 00 00 00 00 26 26 26 26 [............&&&&]
1745
- # 0050: 4c 49 47 4f 47 50 53 49 4e 46 4f 00 00 00 00 05 [LIGOGPSINFO.....]
1746
- # 0060: 01 00 00 00 23 23 23 23 75 00 00 00 c0 22 20 20 [....####u...." ]
1747
- # 0070: 20 f0 12 10 12 21 e5 0e 10 12 2f 90 10 13 01 f2 [ ....!..../.....]
1748
- ($latRef, $lonRef) = ($1, $2);
1749
- ($hr,$min,$sec,$yr,$mon,$day) = unpack("V6", $$dataPt);
1750
- # lat/lon aren't decoded properly, but spd,trk,acc are
1751
- $lat = GetFloat($dataPt, 0x1c);
1752
- $lon = GetFloat($dataPt, 0x20);
1753
- $et->VPrint(0, sprintf("Raw lat/lon = %.9f %.9f\n", $lat, $lon));
1754
- $et->WarnOnce('GPSLatitude/Longitude encryption is not yet known, so these will be wrong');
1755
- $lat = abs $lat;
1756
- $lon = abs $lon;
1757
- $spd = GetFloat($dataPt, 0x24) * $knotsToKph; # (convert knots to km/h)
1758
- $trk = GetFloat($dataPt, 0x28);
1759
- $acc[0] = GetFloat($dataPt, 0x2c);
1760
- $acc[1] = GetFloat($dataPt, 0x30);
1761
- $acc[2] = GetFloat($dataPt, 0x34);
1756
+ $debug and $et->FoundTag(GPSType => 5);
1757
+ my $pos = length $1;
1758
+ # iiway s1 dual dash cam - offset 16, encrypted and fuzzed with scale 1
1759
+ # 0000: 00 00 40 00 66 72 65 65 47 50 53 20 f0 03 00 00 [..@.freeGPS ....]
1760
+ # 0010: 4c 49 47 4f 47 50 53 49 4e 46 4f 00 00 00 00 05 [LIGOGPSINFO.....]
1761
+ # 0020: 0a 00 00 00 23 23 23 23 6a 00 00 00 c0 20 20 20 [....####j.... ]
1762
+ # 0030: 20 f0 12 10 12 22 e1 0e 10 12 2f 90 10 13 02 f2 [ ...."..../.....]
1763
+ # XGODY 12" 4K Dashcam - offset 16, encrypted and fuzzed with scale 1
1764
+ # 0000: 00 00 00 a8 66 72 65 65 47 50 53 20 98 00 00 00 [....freeGPS ....]
1765
+ # 0010: 4c 49 47 4f 47 50 53 49 4e 46 4f 00 00 00 00 05 [LIGOGPSINFO.....]
1766
+ # 0020: cd 61 00 00 23 23 23 23 6d 00 00 00 c1 ec 41 20 [.a..####m.....A ]
1767
+ # 0030: 20 f0 12 10 12 24 e5 0e 10 11 2f 92 10 12 00 f6 [ ....$..../.....]
1768
+ # ABASK A8 4K Dashcam - offset 16, encrypted and fuzzed with scale 3
1769
+ # 0000: 00 00 40 00 66 72 65 65 47 50 53 20 f0 03 00 00 [..@.freeGPS ....]
1770
+ # 0010: 4c 49 47 4f 47 50 53 49 4e 46 4f 00 00 00 00 05 [LIGOGPSINFO.....]
1771
+ # 0020: 00 00 00 00 23 23 23 23 69 00 00 00 c0 20 20 20 [....####i.... ]
1772
+ # 0030: 20 f0 12 10 12 23 e5 0e 10 12 2f 99 10 11 02 f2 [ ....#..../.....]
1773
+ # Unknown dashcam (forum16060) - offset 16, enciphered and fuzzed with scale 1
1774
+ # 0000: 00 00 40 00 66 72 65 65 47 50 53 20 98 00 00 00 [..@.freeGPS ....]
1775
+ # 0010: 4c 49 47 4f 47 50 53 49 4e 46 4f 00 00 00 00 0d [LIGOGPSINFO.....]
1776
+ # 0020: 0a 00 00 00 23 23 23 23 3b 00 a0 34 46 44 46 31 [....####;..4FDF1]
1777
+ # 0030: 2f 44 39 2f 45 38 20 44 3d 4c 47 4a 4c 39 38 20 [/D9/E8 D=LGJL98 ]
1778
+ # Rexing dashcam V1GW-4K - offset 48, encrypted and fuzzed with scale 1
1779
+ # 0000: 00 00 40 00 66 72 65 65 47 50 53 20 f0 03 00 00 [..@.freeGPS ....]
1780
+ # 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................]
1781
+ # 0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................]
1782
+ # 0030: 4c 49 47 4f 47 50 53 49 4e 46 4f 00 00 00 00 05 [LIGOGPSINFO.....]
1783
+ # 0040: 01 00 00 00 23 23 23 23 73 00 00 00 c0 20 20 20 [....####s.... ]
1784
+ # 0050: 20 f0 12 10 12 23 e5 0e 10 12 2f 95 10 12 01 f3 [ ....#..../.....]
1785
+ # Kingslim D4 dashcam - offset 80, encrypted and fuzzed with scale 1
1786
+ # 0000: 0a 00 00 00 0b 00 00 00 07 00 00 00 e5 07 00 00 [................]
1787
+ # 0010: 06 00 00 00 03 00 00 00 41 4e 57 31 91 52 83 45 [........ANW1.R.E]
1788
+ # 0020: 15 70 fe c5 29 5c c3 41 ae c7 af 42 00 00 d1 be [.p..)\.A...B....]
1789
+ # 0030: 00 00 80 3b 00 00 2c 3e 00 00 00 00 00 00 00 00 [...;..,>........]
1790
+ # 0040: 00 00 00 00 00 00 00 00 00 00 00 00 26 26 26 26 [............&&&&]
1791
+ # 0050: 4c 49 47 4f 47 50 53 49 4e 46 4f 00 00 00 00 05 [LIGOGPSINFO.....]
1792
+ # 0060: 01 00 00 00 23 23 23 23 75 00 00 00 c0 22 20 20 [....####u...." ]
1793
+ # 0070: 20 f0 12 10 12 21 e5 0e 10 12 2f 90 10 13 01 f2 [ ....!..../.....]
1794
+ my %dirInfo = ( DataPt => $dataPt, DirStart => $pos, DirName => "LigoGPS_$pos" );
1795
+ # (this is weak, but the only difference I could find between these 2 headers)
1796
+ # (NOTE: ../testpics/gps_video/forum16229.mp4 uses this word for a counter!)
1797
+ $$et{LigoGPSScale} = 3 if $pos == 16 and $$dataPt =~ /^.{12}\xf0\x03\0\0.{16}\0{4}/s;
1798
+ Image::ExifTool::LigoGPS::ProcessLigoGPS($et, \%dirInfo, $tagTbl);
1799
+ $done = 1;
1800
+
1801
+ # also... when offset is 0x50 (Kingslim), the GPS also exists in this format:
1802
+ # ($latRef, $lonRef) = ($1, $2);
1803
+ # ($hr,$min,$sec,$yr,$mon,$day) = unpack("V6", $$dataPt);
1804
+ # # lat/lon aren't decoded properly, but spd,trk,acc are
1805
+ # $lat = GetFloat($dataPt, 0x1c);
1806
+ # $lon = GetFloat($dataPt, 0x20);
1807
+ # $et->VPrint(0, sprintf("Raw lat/lon = %.9f %.9f\n", $lat, $lon));
1808
+ # $et->Warn('GPSLatitude/Longitude encryption is not yet known, so these will be wrong');
1809
+ # $lat = abs $lat;
1810
+ # $lon = abs $lon;
1811
+ # $spd = GetFloat($dataPt, 0x24) * $knotsToKph; # (convert knots to km/h)
1812
+ # $trk = GetFloat($dataPt, 0x28);
1813
+ # $acc[0] = GetFloat($dataPt, 0x2c);
1814
+ # $acc[1] = GetFloat($dataPt, 0x30);
1815
+ # $acc[2] = GetFloat($dataPt, 0x34);
1762
1816
 
1763
1817
  } elsif ($$dataPt =~ /^.{60}A\0{3}.{4}([NS])\0{3}.{4}([EW])\0{3}/s) {
1764
1818
 
1765
- $debug and $et->FoundTag(GPSType => 5);
1819
+ $debug and $et->FoundTag(GPSType => 6);
1766
1820
  # decode freeGPS from Akaso dashcam
1767
1821
  # 0000: 00 00 80 00 66 72 65 65 47 50 53 20 60 00 00 00 [....freeGPS `...]
1768
1822
  # 0010: 78 2e 78 78 00 00 00 00 00 00 00 00 00 00 00 00 [x.xx............]
@@ -1796,7 +1850,7 @@ sub ProcessFreeGPS($$$)
1796
1850
 
1797
1851
  } elsif ($$dataPt =~ /^.{60}4W`b]S</s and length($$dataPt) >= 140) {
1798
1852
 
1799
- $debug and $et->FoundTag(GPSType => 6);
1853
+ $debug and $et->FoundTag(GPSType => 7);
1800
1854
  # 0000: 00 00 40 00 66 72 65 65 47 50 53 20 f0 01 00 00 [..@.freeGPS ....]
1801
1855
  # 0010: 5a 58 53 42 4e 58 59 53 00 00 00 00 00 00 00 00 [ZXSBNXYS........]
1802
1856
  # 0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................]
@@ -1806,18 +1860,18 @@ sub ProcessFreeGPS($$$)
1806
1860
  # 0060: 42 3e 49 49 40 42 45 3c 55 3c 45 47 3e 45 43 41 [B>II@BE<U<EG>ECA]
1807
1861
  # decipher $GPRMC by subtracting 16 from each character value
1808
1862
  $_ = pack 'C*', map { $_>=16 and $_-=16 } unpack('x60C80', $$dataPt);
1809
- unless (/[A-Z]{2}RMC,(\d{2})(\d{2})(\d+(\.\d*)?),A?,(\d*?\d{1,2}\.\d+),([NS]),(\d*?\d{1,2}\.\d+),([EW]),(\d*\.?\d*),(\d*\.?\d*),(\d{2})(\d{2})(\d+)/) {
1810
- SetByteOrder($oldOrder);
1811
- return 0;
1863
+ if (/[A-Z]{2}RMC,(\d{2})(\d{2})(\d+(\.\d*)?),A?,(\d*?\d{1,2}\.\d+),([NS]),(\d*?\d{1,2}\.\d+),([EW]),(\d*\.?\d*),(\d*\.?\d*),(\d{2})(\d{2})(\d+)/) {
1864
+ ($yr,$mon,$day,$hr,$min,$sec,$lat,$latRef,$lon,$lonRef) = ($13,$12,$11,$1,$2,$3,$5,$6,$7,$8);
1865
+ $yr += ($yr >= 70 ? 1900 : 2000);
1866
+ $spd = $9 * $knotsToKph if length $9;
1867
+ $trk = $10 if length $10;
1868
+ } else {
1869
+ $done = 1;
1812
1870
  }
1813
- ($yr,$mon,$day,$hr,$min,$sec,$lat,$latRef,$lon,$lonRef) = ($13,$12,$11,$1,$2,$3,$5,$6,$7,$8);
1814
- $yr += ($yr >= 70 ? 1900 : 2000);
1815
- $spd = $9 * $knotsToKph if length $9;
1816
- $trk = $10 if length $10;
1817
1871
 
1818
1872
  } elsif ($$dataPt =~ /^.{64}[\x01-\x0c]\0{3}[\x01-\x1f]\0{3}A[NS][EW]\0{5}/s) {
1819
1873
 
1820
- $debug and $et->FoundTag(GPSType => 7);
1874
+ $debug and $et->FoundTag(GPSType => 8);
1821
1875
  # Akaso V1 dascham
1822
1876
  # 0000: 00 00 80 00 66 72 65 65 47 50 53 20 78 00 00 00 [....freeGPS x...]
1823
1877
  # 0010: 59 6e 64 41 6b 61 73 6f 43 61 72 00 00 00 00 00 [YndAkasoCar.....]
@@ -1842,7 +1896,7 @@ sub ProcessFreeGPS($$$)
1842
1896
  ($hr,$min,$sec,$yr,$mon,$day,$stat,$latRef,$lonRef) =
1843
1897
  unpack('x48V6a1a1a1x1', $$dataPt);
1844
1898
 
1845
- $et->WarnOnce('GPSLatitude/Longitude encryption is not yet known, so these will be wrong');
1899
+ $et->Warn('GPSLatitude/Longitude encryption is not yet known, so these will be wrong');
1846
1900
  # (see https://exiftool.org/forum/index.php?topic=11320.0)
1847
1901
 
1848
1902
  $spd = GetFloat($dataPt, 0x60);
@@ -1850,11 +1904,11 @@ sub ProcessFreeGPS($$$)
1850
1904
  $lat = GetDouble($dataPt, 0x50); # latitude is here, but encrypted somehow
1851
1905
  $lon = GetDouble($dataPt, 0x58); # longitude is here, but encrypted somehow
1852
1906
  $ddd = 1; # don't convert until we know what the format is
1853
- #my $serialNum = substr($$dataPt, 0x68, 20);
1907
+ #my $serialNum = substr($$dataPt, 0x68, 20); # (confirmed)
1854
1908
 
1855
1909
  } elsif ($$dataPt =~ /^.{12}\xac\0\0\0.{44}(.{72})/s) {
1856
1910
 
1857
- $debug and $et->FoundTag(GPSType => 8);
1911
+ $debug and $et->FoundTag(GPSType => 9);
1858
1912
  # EACHPAI dash cam
1859
1913
  # 0000: 00 00 80 00 66 72 65 65 47 50 53 20 ac 00 00 00 [....freeGPS ....]
1860
1914
  # 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................]
@@ -1866,19 +1920,18 @@ sub ProcessFreeGPS($$$)
1866
1920
  # 0070: 43 41 3c 40 42 40 46 42 40 3c 3c 3c 51 3a 47 46 [CA<@B@FB@<<<Q:GF]
1867
1921
  # 0080: 00 2a 36 35 00 00 00 00 00 00 00 00 00 00 00 00 [.*65............]
1868
1922
 
1869
- $et->WarnOnce("Can't yet decrypt EACHPAI timed GPS", 1);
1923
+ $et->Warn("Can't yet decrypt EACHPAI timed GPS", 1);
1870
1924
  # (see https://exiftool.org/forum/index.php?topic=5095.msg61266#msg61266)
1871
- SetByteOrder($oldOrder);
1872
- return 1;
1925
+ $done = 1;
1873
1926
 
1874
- my $time = pack 'C*', map { $_ ^= 0 } unpack 'C*', $1;
1875
- # bytes 7-12 are the timestamp in ASCII HHMMSS after xor-ing with 0x70
1876
- substr($time,7,6) = pack 'C*', map { $_ ^= 0x70 } unpack 'C*', substr($time,7,6);
1877
- # (other values are currently unknown)
1927
+ # my $time = pack 'C*', map { $_ ^= 0 } unpack 'C*', $1;
1928
+ # # bytes 7-12 are the timestamp in ASCII HHMMSS after xor-ing with 0x70
1929
+ # substr($time,7,6) = pack 'C*', map { $_ ^= 0x70 } unpack 'C*', substr($time,7,6);
1930
+ # # (other values are currently unknown)
1878
1931
 
1879
1932
  } elsif ($$dataPt =~ /^.{64}A([NS])([EW])\0/s) {
1880
1933
 
1881
- $debug and $et->FoundTag(GPSType => 9);
1934
+ $debug and $et->FoundTag(GPSType => 10);
1882
1935
  # Vantrue S1 dashcam
1883
1936
  # 0000: 00 00 80 00 66 72 65 65 47 50 53 20 78 00 00 00 [....freeGPS x...]
1884
1937
  # 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................]
@@ -1890,21 +1943,21 @@ sub ProcessFreeGPS($$$)
1890
1943
  # 0070: 05 00 00 00 7f 00 00 00 07 01 00 00 00 00 00 00 [................]
1891
1944
  ($latRef, $lonRef) = ($1, $2);
1892
1945
  ($yr,$mon,$day,$hr,$min,$sec,@acc) = unpack('x68V6x20V3', $$dataPt);
1893
- unless ($mon>=1 and $mon<=12 and $day>=1 and $day<=31) {
1894
- SetByteOrder($oldOrder);
1895
- return 0;
1946
+ if ($mon>=1 and $mon<=12 and $day>=1 and $day<=31) {
1947
+ # (not sure about acc scaling)
1948
+ @acc = map { SignedInt32 / 1000 } @acc;
1949
+ $lon = GetFloat($dataPt, 0x5c);
1950
+ $lat = GetFloat($dataPt, 0x60);
1951
+ $spd = GetFloat($dataPt, 0x64) * $knotsToKph;
1952
+ $trk = GetFloat($dataPt, 0x68);
1953
+ $alt = GetFloat($dataPt, 0x6c);
1954
+ } else {
1955
+ $done = 1;
1896
1956
  }
1897
- # (not sure about acc scaling)
1898
- @acc = map { SignedInt32 / 1000 } @acc;
1899
- $lon = GetFloat($dataPt, 0x5c);
1900
- $lat = GetFloat($dataPt, 0x60);
1901
- $spd = GetFloat($dataPt, 0x64) * $knotsToKph;
1902
- $trk = GetFloat($dataPt, 0x68);
1903
- $alt = GetFloat($dataPt, 0x6c);
1904
1957
 
1905
1958
  } elsif (substr($$dataPt,0x45,3) eq 'ATC') {
1906
1959
 
1907
- $debug and $et->FoundTag(GPSType => 10);
1960
+ $debug and $et->FoundTag(GPSType => 11);
1908
1961
  # header looks like this: (sample 1)
1909
1962
  # 0000: 00 00 80 00 66 72 65 65 47 50 53 20 38 06 00 00 [....freeGPS 8...]
1910
1963
  # 0010: 49 51 53 32 30 31 33 30 33 30 36 42 00 00 00 00 [IQS20130306B....]
@@ -1945,7 +1998,7 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
1945
1998
  my $i;
1946
1999
  for ($i=0; $i<@dateMax; ++$i) {
1947
2000
  next if $now[$i] <= $dateMax[$i];
1948
- $et->WarnOnce('Invalid GPS date/time');
2001
+ $et->Warn('Invalid GPS date/time');
1949
2002
  next ATCRec; # ignore this record
1950
2003
  }
1951
2004
  # look for next ATC record in temporal sequence
@@ -2012,12 +2065,11 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
2012
2065
  }
2013
2066
  # save position of most recent record (needed when parsing the next freeGPS block)
2014
2067
  $$et{FreeGPS2}{RecentRecPos} = $lastRecPos;
2015
- SetByteOrder($oldOrder);
2016
- return 1;
2068
+ $done = 1;
2017
2069
 
2018
2070
  } elsif ($$dataPt =~ /^.{60}A\0.{10}([NS])\0.{14}([EW])\0/s and $dirLen >= 0x88) {
2019
2071
 
2020
- $debug and $et->FoundTag(GPSType => 11);
2072
+ $debug and $et->FoundTag(GPSType => 12);
2021
2073
  # header looks like this in my sample:
2022
2074
  # 0000: 00 00 80 00 66 72 65 65 47 50 53 20 08 01 00 00 [....freeGPS ....]
2023
2075
  # 0010: 32 30 31 33 30 38 31 35 2e 30 31 00 00 00 00 00 [20130815.01.....]
@@ -2048,9 +2100,14 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
2048
2100
 
2049
2101
  } elsif ($$dataPt =~ /^.{16}A([NS])([EW])\0/s) {
2050
2102
 
2051
- $debug and $et->FoundTag(GPSType => 12);
2103
+ $debug and $et->FoundTag(GPSType => 13);
2052
2104
  # INNOVV MP4 video (same format as INNOVV TS)
2053
- while ($$dataPt =~ /(A[NS][EW]\0.{28})/g) {
2105
+ # 0000: 00 00 40 00 66 72 65 65 47 50 53 20 f0 03 00 00 [..@.freeGPS ....]
2106
+ # 0010: 41 4e 45 00 e4 56 96 45 86 b1 ca 44 5c 8f e2 40 [ANE..V.E...D\..@]
2107
+ # 0020: 33 33 58 43 c3 00 00 00 30 00 00 00 a0 fe ff ff [33XC....0.......]
2108
+ # 0030: 41 4e 45 00 e3 56 96 45 82 b1 ca 44 5c 8f fa 40 [ANE..V.E...D\..@]
2109
+ # 0040: c3 75 56 43 8c ff ff ff 8c 00 00 00 c3 fd ff ff [.uVC............]
2110
+ while ($$dataPt =~ /(A[NS][EW]\0.{28})/sg) {
2054
2111
  my $dat = $1;
2055
2112
  $lat = abs(GetFloat(\$dat, 4)); # (abs just to be safe)
2056
2113
  $lon = abs(GetFloat(\$dat, 8)); # (abs just to be safe)
@@ -2065,12 +2122,35 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
2065
2122
  $et->HandleTag($tagTbl, GPSTrack => $trk);
2066
2123
  $et->HandleTag($tagTbl, Accelerometer => "@acc");
2067
2124
  }
2068
- SetByteOrder($oldOrder);
2069
- return 1;
2125
+ $done = 1;
2126
+
2127
+ } elsif ($$dataPt =~ /^.{20}[\0-\x18][\0-\x3b]{2}[\0-\x09]A([NS])([EW])/s) {
2128
+
2129
+ $debug and $et->FoundTag(GPSType => 14);
2130
+ # XBHT motorcycle dashcam Model XB702
2131
+ # 0000: 00 00 40 00 66 72 65 65 47 50 53 20 f0 03 00 00 [..@.freeGPS ....]
2132
+ # 0010: 00 17 05 11 0d 25 18 00 41 4e 45 64 83 3f 00 00 [.....%..ANEd.?..]
2133
+ # 0020: 44 3d c5 02 48 6d ff 07 df 03 00 00 6b 00 00 00 [D=..Hm......k...]
2134
+ # 0030: 00 00 00 00 00 17 05 11 0d 25 18 01 41 4e 45 64 [.........%..ANEd]
2135
+ # 0040: 8b 3f 00 00 30 3d c5 02 50 6d ff 07 df 03 00 00 [.?..0=..Pm......]
2136
+ while ($$dataPt =~ /(.{7}[\0-\x09]A[NS][EW].{25})/sg) {
2137
+ my $dat = $1;
2138
+ ($yr,$mon,$day,$hr,$min,$sec,$ss,$latRef,$lonRef,$lat,$lon,$spd) =
2139
+ unpack('xC7xCCx5VVx4v', $dat);
2140
+ $yr += 2000; $lat /= 1e4; $lon /= 1e4;
2141
+ ConvertLatLon($lat, $lon);
2142
+ $$et{DOC_NUM} = ++$$et{DOC_COUNT};
2143
+ my $time = sprintf('%.4d:%.2d:%.2d %.2d:%.2d:%.2d.%d',$yr,$mon,$day,$hr,$min,$sec,$ss);
2144
+ $et->HandleTag($tagTbl, GPSDateTime => $time);
2145
+ $et->HandleTag($tagTbl, GPSLatitude => $lat * ($latRef eq 'S' ? -1 : 1));
2146
+ $et->HandleTag($tagTbl, GPSLongitude => $lon * ($lonRef eq 'W' ? -1 : 1));
2147
+ $et->HandleTag($tagTbl, GPSSpeed => $spd);
2148
+ }
2149
+ $done = 1;
2070
2150
 
2071
2151
  } elsif ($$dataPt =~ /^.{28}A.{11}([NS]).{15}([EW])/s) {
2072
2152
 
2073
- $debug and $et->FoundTag(GPSType => 13);
2153
+ $debug and $et->FoundTag(GPSType => 15);
2074
2154
  # Vantrue N4 dashcam
2075
2155
  # 0000: 00 00 40 00 66 72 65 65 47 50 53 20 f0 03 00 00 [..@.freeGPS ....]
2076
2156
  # 0010: 0d 00 00 00 16 00 00 00 1e 00 00 00 41 00 00 00 [............A...]
@@ -2127,7 +2207,7 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
2127
2207
  ($hr,$min,$sec,$yr,$mon,$day,$stat,$latRef,$lonRef) =
2128
2208
  unpack('x48V6a1a1a1x1V4', $$dataPt);
2129
2209
  if (substr($$dataPt, 16, 3) eq 'IQS') {
2130
- $debug and $et->FoundTag(GPSType => 14);
2210
+ $debug and $et->FoundTag(GPSType => 16);
2131
2211
  # Type 3b (ref PH)
2132
2212
  # header looks like this in my sample:
2133
2213
  # 0000: 00 00 80 00 66 72 65 65 47 50 53 20 4c 00 00 00 [....freeGPS L...]
@@ -2139,7 +2219,7 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
2139
2219
  $spd = Get32s($dataPt, 0x54) / 100 * $mpsToKph;
2140
2220
  $alt = GetFloat($dataPt, 0x58) / 1000; # (NC)
2141
2221
  } else {
2142
- $debug and $et->FoundTag(GPSType => 15);
2222
+ $debug and $et->FoundTag(GPSType => 17);
2143
2223
  $lat = GetFloat($dataPt, 0x4c);
2144
2224
  $lon = GetFloat($dataPt, 0x50);
2145
2225
  $spd = GetFloat($dataPt, 0x54) * $knotsToKph;
@@ -2159,7 +2239,7 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
2159
2239
 
2160
2240
  } elsif ($$dataPt =~ m<^.{23}(\d{4})/(\d{2})/(\d{2}) (\d{2}):(\d{2}):(\d{2}) [N|S]>s) {
2161
2241
 
2162
- $debug and $et->FoundTag(GPSType => 16);
2242
+ $debug and $et->FoundTag(GPSType => 18);
2163
2243
  # XGODY 12" 4K Dashcam
2164
2244
  # 0000: 00 00 00 a8 66 72 65 65 47 50 53 20 98 00 00 00 [....freeGPS ....]
2165
2245
  # 0010: 6e 6f 72 6d 61 6c 3a 32 30 32 34 2f 30 35 2f 32 [normal:2024/05/2]
@@ -2190,8 +2270,8 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
2190
2270
  }
2191
2271
 
2192
2272
  } elsif ($$dataPt =~ m/^.{30}A.{20}VV/) {
2193
-
2194
- $debug and $et->FoundTag(GPSType => 17);
2273
+
2274
+ $debug and $et->FoundTag(GPSType => 19);
2195
2275
  # 70mai A810 dashcam (note: no timestamps in the samples I have)
2196
2276
  # 0000: 00 00 40 00 66 72 65 65 47 50 53 20 ed 01 00 00 [..@.freeGPS ....]
2197
2277
  # 0010: 03 00 ed 01 00 00 00 0f 00 00 70 08 00 00 41 66 [..........p...Af]
@@ -2208,7 +2288,7 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
2208
2288
 
2209
2289
  } else {
2210
2290
 
2211
- $debug and $et->FoundTag(GPSType => 18);
2291
+ $debug and $et->FoundTag(GPSType => 20);
2212
2292
  # (look for binary GPS as stored by Nextbase 512G, ref PH)
2213
2293
  # 0000: 00 00 80 00 66 72 65 65 47 50 53 20 78 01 00 00 [....freeGPS x...]
2214
2294
  # 0010: 78 2e 78 78 00 00 00 00 00 00 00 00 00 00 00 00 [x.xx............]
@@ -2254,14 +2334,14 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
2254
2334
  $et->HandleTag($tagTbl, GPSTrack => $trk);
2255
2335
  last if $pos += 0x20 > length($$dataPt) - 0x1e;
2256
2336
  }
2257
- SetByteOrder($oldOrder);
2258
- return $$et{DOC_NUM} ? 1 : 0; # return 0 if nothing extracted
2337
+ $done = 1;
2259
2338
  }
2339
+ SetByteOrder($oldOrder);
2340
+ return $$et{DOC_NUM} ? 1 : 0 if $done;
2341
+ return 0 if defined $yr and $mon < 1 or $mon > 12; # quick sanity check
2260
2342
  #
2261
2343
  # save tag values extracted by above code
2262
2344
  #
2263
- SetByteOrder($oldOrder);
2264
- return 0 if defined $yr and $mon < 1 or $mon > 12; # quick sanity check
2265
2345
  FoundSomething($et, $tagTbl, $$dirInfo{SampleTime}, $$dirInfo{SampleDuration});
2266
2346
  $sec = '0' . $sec unless $sec =~ /^\d{2}/; # pad integer part of seconds to 2 digits
2267
2347
  if (defined $yr) {
@@ -2401,8 +2481,8 @@ sub Process_tx3g($$$)
2401
2481
  if ($text =~ /^HOME\(/) {
2402
2482
  # --- sample text from Autel Evo II drone ---
2403
2483
  # HOME(W: 109.318642, N: 40.769371) 2023-09-12 10:28:07
2404
- # GPS(W: 109.339287, N: 40.768574, 2371.76m)
2405
- # HDR ISO:100 SHUTTER:1000 EV:-0.7 F-NUM:1.8
2484
+ # GPS(W: 109.339287, N: 40.768574, 2371.76m)
2485
+ # HDR ISO:100 SHUTTER:1000 EV:-0.7 F-NUM:1.8
2406
2486
  # F.PRY (1.0\xc2\xb0, -3.7\xc2\xb0, -59.0\xc2\xb0), G.PRY (-51.1\xc2\xb0, 0.0\xc2\xb0, -58.9\xc2\xb0)
2407
2487
  my $line;
2408
2488
  foreach $line (split /\x0a/, $text) {
@@ -2479,7 +2559,7 @@ sub Process_mebx($$$)
2479
2559
  Size => $len - 8,
2480
2560
  );
2481
2561
  } else {
2482
- $et->WarnOnce('No key information for mebx ID ' . PrintableTagID($id,1));
2562
+ $et->Warn('No key information for mebx ID ' . PrintableTagID($id,1));
2483
2563
  }
2484
2564
  }
2485
2565
  return 1;
@@ -2602,7 +2682,7 @@ sub Process_gdat($$$)
2602
2682
  {
2603
2683
  my ($et, $dirInfo, $tagTbl) = @_;
2604
2684
  unless ($$et{OPTIONS}{ExtractEmbedded}) {
2605
- $et->WarnOnce('Use the ExtractEmbedded option to extract timed GPSData',3);
2685
+ $et->Warn('Use the ExtractEmbedded option to extract timed GPSData',3);
2606
2686
  return 0;
2607
2687
  }
2608
2688
  my $dataPt = $$dirInfo{DataPt};
@@ -2653,84 +2733,8 @@ sub Process_nbmt($$$)
2653
2733
  delete $$et{NoMoreTextDecoding};
2654
2734
  delete $$et{DOC_NUM};
2655
2735
  } else {
2656
- $et->WarnOnce('Use the ExtractEmbedded option to extract timed GPSData',3);
2657
- }
2658
- return 1;
2659
- }
2660
-
2661
- #------------------------------------------------------------------------------
2662
- # Process LIGOGPS JSON-format GPS from Yada RoadCam Pro 4K BT58189
2663
- # Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref
2664
- # Returns: 1 on success
2665
- # Sample data (chained 512-byte records starting like this):
2666
- # 0000: 4c 49 47 4f 47 50 53 49 4e 46 4f 20 7b 22 48 6f [LIGOGPSINFO {"Ho]
2667
- # 0010: 75 72 22 3a 20 22 32 33 22 2c 20 22 4d 69 6e 75 [ur": "23", "Minu]
2668
- # 0020: 74 65 22 3a 20 22 31 30 22 2c 20 22 53 65 63 6f [te": "10", "Seco]
2669
- # 0030: 6e 64 22 3a 20 22 32 32 22 2c 20 22 59 65 61 72 [nd": "22", "Year]
2670
- # 0040: 22 3a 20 22 32 30 32 33 22 2c 20 22 4d 6f 6e 74 [": "2023", "Mont]
2671
- # 0050: 68 22 3a 20 22 31 32 22 2c 20 22 44 61 79 22 3a [h": "12", "Day":]
2672
- # 0060: 20 22 32 38 22 2c 20 22 73 74 61 74 75 73 22 3a [ "28", "status":]
2673
- sub ProcessLIGO_JSON($$$)
2674
- {
2675
- my ($et, $dirInfo, $tagTbl) = @_;
2676
- my $dataPt = $$dirInfo{DataPt};
2677
- my $dirLen = $$dirInfo{DirLen};
2678
- require Image::ExifTool::Import;
2679
- $et->VerboseDir('LIGO_JSON', undef, length($$dataPt));
2680
- while ($$dataPt =~ /LIGOGPSINFO (\{.*?\})/g) {
2681
- my $json = $1;
2682
- my %dbase;
2683
- Image::ExifTool::Import::ReadJSON(\$json, \%dbase);
2684
- my $info = $dbase{'*'} or next;
2685
- # my sample contains the following JSON fields (in this order):
2686
- # Hour Minute Second Year Month Day (GPS UTC time)
2687
- # status NS EW Latitude Longitude Speed (speed in knots)
2688
- # GsensorX GsensorY GsensorZ (units? - only seen "000" for all)
2689
- # MHour MMinute MSecond MYear MMonth MDay (local dashcam clock time)
2690
- # OLatitude OLongitude (? same values as Latitude/Longitude)
2691
- next unless defined $$info{status} and $$info{status} eq 'A'; # only read if GPS is active
2692
- $$et{DOC_NUM} = ++$$et{DOC_COUNT};
2693
- my $num = 0;
2694
- defined $$info{$_} and ++$num foreach qw(Year Month Day Hour Minute Second);
2695
- if ($num == 6) {
2696
- # this is the GPS time in UTC
2697
- my $time = sprintf('%.4d:%.2d:%.2d %.2d:%.2d:%.2dZ',@$info{qw{Year Month Day Hour Minute Second}});
2698
- $et->HandleTag($tagTbl, GPSDateTime => $time);
2699
- }
2700
- if ($$info{Latitude} and $$info{Longitude}) {
2701
- my $lat = $$info{Latitude};
2702
- $lat = -$lat if $$info{NS} and $$info{NS} eq 'S';
2703
- my $lon = $$info{Longitude};
2704
- $lon = -$lon if $$info{EW} and $$info{EW} eq 'W';
2705
- $et->HandleTag($tagTbl, GPSLatitude => $lat);
2706
- $et->HandleTag($tagTbl, GPSLongitude => $lon);
2707
- }
2708
- $et->HandleTag($tagTbl, GPSSpeed => $$info{Speed} * $knotsToKph) if defined $$info{Speed};
2709
- if (defined $$info{GsensorX} and defined $$info{GsensorY} and defined $$info{GsensorZ}) {
2710
- # (don't know conversion factor for accel data, so leave it raw for now)
2711
- $et->HandleTag($tagTbl, Accelerometer => "$$info{GsensorX} $$info{GsensorY} $$info{GsensorZ}");
2712
- }
2713
- $num = 0;
2714
- defined $$info{$_} and ++$num foreach qw(MYear MMonth MDay MHour MMinute MSecond);
2715
- if ($num == 6) {
2716
- # this is the dashcam clock time (local time zone)
2717
- my $time = sprintf('%.4d:%.2d:%.2d %.2d:%.2d:%.2d',@$info{qw{MYear MMonth MDay MHour MMinute MSecond}});
2718
- $et->HandleTag($tagTbl, DateTimeOriginal => $time);
2719
- }
2720
- if (defined $$info{OLatitude} and defined $$info{OLongitude}) {
2721
- my $lat = $$info{OLatitude};
2722
- $lat = -$lat if $$info{NS} and $$info{NS} eq 'S';
2723
- my $lon = $$info{OLongitude};
2724
- $lon = -$lon if $$info{EW} and $$info{EW} eq 'W';
2725
- $et->HandleTag($tagTbl, GPSLatitude2 => $lat);
2726
- $et->HandleTag($tagTbl, GPSLongitude2 => $lon);
2727
- }
2728
- unless ($et->Options('ExtractEmbedded')) {
2729
- $et->WarnOnce('Use the ExtractEmbedded option to extract all timed GPS',3);
2730
- last;
2731
- }
2736
+ $et->Warn('Use the ExtractEmbedded option to extract timed GPSData',3);
2732
2737
  }
2733
- delete $$et{DOC_NUM};
2734
2738
  return 1;
2735
2739
  }
2736
2740
 
@@ -2773,7 +2777,7 @@ sub ProcessKenwood($$$)
2773
2777
  }
2774
2778
  $et->HandleTag($tagTbl, Accelerometer => "@acc") if @acc;
2775
2779
  unless ($et->Options('ExtractEmbedded')) {
2776
- $et->WarnOnce('Use the ExtractEmbedded option to extract all timed GPS',3);
2780
+ $et->Warn('Use the ExtractEmbedded option to extract all timed GPS',3);
2777
2781
  last;
2778
2782
  }
2779
2783
  }
@@ -2896,7 +2900,7 @@ sub ProcessKenwoodTrailer($$$)
2896
2900
  $raf->Read($buff, 14) and $buff eq 'CCCCCCCCCCCCCC' or return 0;
2897
2901
  $et->VerboseDir('Kenwood trailer', undef, undef);
2898
2902
  unless ($$et{OPTIONS}{ExtractEmbedded}) {
2899
- $et->WarnOnce('Use the ExtractEmbedded option to extract timed GPSData from Kenwood trailer',3);
2903
+ $et->Warn('Use the ExtractEmbedded option to extract timed GPSData from Kenwood trailer',3);
2900
2904
  return 1;
2901
2905
  }
2902
2906
  while ($raf->Read($buff, 121) and $buff =~ /^GPSDATA--(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/) {
@@ -3119,7 +3123,7 @@ sub ProcessTTAD($$$)
3119
3123
  $et->HandleTag($tagTbl, "Unknown0$type" => "@a");
3120
3124
  }
3121
3125
  } else {
3122
- $et->WarnOnce("Unknown TTAD record type $type",1);
3126
+ $et->Warn("Unknown TTAD record type $type",1);
3123
3127
  }
3124
3128
  # without -ee, stop after we find types 0,3,5 (ie. bitmask 0x29)
3125
3129
  $eeOpt or ($found & 0x29) != 0x29 or EEWarn($et), last;
@@ -3150,16 +3154,18 @@ sub ProcessInsta360($;$)
3150
3154
  my $verbose = $et->Options('Verbose');
3151
3155
  my $tagTbl = GetTagTable('Image::ExifTool::QuickTime::Stream');
3152
3156
  my $fileEnd = $raf->Tell();
3157
+ my $trailEnd = $fileEnd - $offset;
3153
3158
  my $trailerLen = unpack('x38V', $buff);
3154
- $trailerLen > $fileEnd and $et->Warn('Bad Insta360 trailer size'), return 0;
3159
+ $trailerLen > $trailEnd and $et->Warn('Bad Insta360 trailer size'), return 0;
3155
3160
  if ($dirInfo) {
3156
3161
  $$dirInfo{DirLen} = $trailerLen;
3157
- $$dirInfo{DataPos} = $fileEnd - $trailerLen;
3162
+ $$dirInfo{DataPos} = $trailEnd - $trailerLen;
3158
3163
  if ($$dirInfo{OutFile}) {
3159
3164
  if ($$et{DEL_GROUP}{Insta360}) {
3160
3165
  ++$$et{CHANGED};
3166
+ return 1;
3161
3167
  # just copy the trailer when writing
3162
- } elsif ($trailerLen > $fileEnd or not $raf->Seek($$dirInfo{DataPos}, 0) or
3168
+ } elsif ($trailerLen > $trailEnd or not $raf->Seek($$dirInfo{DataPos}, 0) or
3163
3169
  $raf->Read(${$$dirInfo{OutFile}}, $trailerLen) != $trailerLen)
3164
3170
  {
3165
3171
  return 0;
@@ -3171,13 +3177,13 @@ sub ProcessInsta360($;$)
3171
3177
  }
3172
3178
  unless ($et->Options('ExtractEmbedded')) {
3173
3179
  # can arrive here when reading Insta360 trailer on JPEG image (INSP file)
3174
- $et->WarnOnce('Use ExtractEmbedded option to extract timed metadata from Insta360 trailer',3);
3180
+ $et->Warn('Use ExtractEmbedded option to extract timed metadata from Insta360 trailer',3);
3175
3181
  return 1;
3176
3182
  }
3177
3183
 
3178
3184
  my $unknown = $et->Options('Unknown');
3179
3185
  # position relative to end of trailer (avoids using large offsets for files > 2 GB)
3180
- my $epos = -78-$offset;
3186
+ my $epos = -78;
3181
3187
  my ($i, $p);
3182
3188
  $$et{SET_GROUP0} = 'Trailer';
3183
3189
  $$et{SET_GROUP1} = 'Insta360';
@@ -3186,7 +3192,7 @@ sub ProcessInsta360($;$)
3186
3192
  for (;;) {
3187
3193
  my ($id, $len) = unpack('vV', $buff);
3188
3194
  ($epos -= $len) + $trailerLen < 0 and last;
3189
- $raf->Seek($epos, 2) or last;
3195
+ $raf->Seek($epos-$offset, 2) or last;
3190
3196
  if ($verbose) {
3191
3197
  $et->VPrint(0, sprintf("Insta360 Record 0x%x (offset 0x%x, %d bytes):\n", $id, $fileEnd + $epos, $len));
3192
3198
  }
@@ -3214,7 +3220,7 @@ sub ProcessInsta360($;$)
3214
3220
  $dlen = 20;
3215
3221
  }
3216
3222
  }
3217
- $raf->Seek($epos, 2) or last;
3223
+ $raf->Seek($epos-$offset, 2) or last;
3218
3224
  }
3219
3225
  } elsif ($id == 0x200) {
3220
3226
  $dlen = $len;
@@ -3343,8 +3349,8 @@ sub ProcessInsta360($;$)
3343
3349
  } else {
3344
3350
  ($epos -= 6) + $trailerLen < 0 and last; # step back to previous record
3345
3351
  }
3346
- $raf->Seek($epos, 2) or last; # seek to start of next footer
3347
- $raf->Read($buff, 6) == 6 or last; # read footer
3352
+ $raf->Seek($epos-$offset, 2) or last; # seek to start of next footer
3353
+ $raf->Read($buff, 6) == 6 or last; # read footer
3348
3354
  }
3349
3355
  delete $$et{DOC_NUM};
3350
3356
  SetByteOrder('MM');
@@ -3368,8 +3374,8 @@ sub ProcessCAMM($$$)
3368
3374
  my $rtnVal = 0;
3369
3375
  while ($pos + 4 < $end) {
3370
3376
  my $type = Get16u($dataPt, $pos + 2);
3371
- my $size = $size{$type} or $et->WarnOnce("Unknown camm record type $type"), last;
3372
- $pos + $size > $end and $et->WarnOnce("Truncated camm record $type"), last;
3377
+ my $size = $size{$type} or $et->Warn("Unknown camm record type $type"), last;
3378
+ $pos + $size > $end and $et->Warn("Truncated camm record $type"), last;
3373
3379
  my $tagTbl = GetTagTable("Image::ExifTool::QuickTime::camm$type");
3374
3380
  $$dirInfo{DirStart} = $pos;
3375
3381
  $$dirInfo{DirLen} = $size;
@@ -3603,8 +3609,6 @@ sub ScanMediaData($)
3603
3609
  $et->VPrint(0, "--------------------------\n");
3604
3610
  $$et{INDENT} = substr $$et{INDENT}, 0, -2;
3605
3611
  }
3606
- # process Insta360 trailer if it exists
3607
- ProcessInsta360($et);
3608
3612
  }
3609
3613
 
3610
3614
  1; # end
@@ -3626,7 +3630,7 @@ information like GPS tracks from MOV, MP4 and INSV media data.
3626
3630
 
3627
3631
  =head1 AUTHOR
3628
3632
 
3629
- Copyright 2003-2024, Phil Harvey (philharvey66 at gmail.com)
3633
+ Copyright 2003-2025, Phil Harvey (philharvey66 at gmail.com)
3630
3634
 
3631
3635
  This library is free software; you can redistribute it and/or modify it
3632
3636
  under the same terms as Perl itself.