1 | #------------------------------------------------------------------------------
|
---|
2 | # File: Parrot.pm
|
---|
3 | #
|
---|
4 | # Description: Read timed metadata from Parrot drone videos
|
---|
5 | #
|
---|
6 | # Revisions: 2019-10-23 - P. Harvey Created
|
---|
7 | #
|
---|
8 | # References: 1) https://developer.parrot.com/docs/pdraw/metadata.html
|
---|
9 | #------------------------------------------------------------------------------
|
---|
10 |
|
---|
11 | package Image::ExifTool::Parrot;
|
---|
12 |
|
---|
13 | use strict;
|
---|
14 | use vars qw($VERSION);
|
---|
15 |
|
---|
16 | $VERSION = '1.01';
|
---|
17 |
|
---|
18 | sub Process_mett($$$);
|
---|
19 |
|
---|
20 | # tags found in Parrot 'mett' timed metadata (ref 1)
|
---|
21 | %Image::ExifTool::Parrot::mett = (
|
---|
22 | PROCESS_PROC => \&Process_mett,
|
---|
23 | # put the 'P' records first in the documentation
|
---|
24 | VARS => { SORT_PROC => sub { my ($a,$b)=@_; $a=~s/P/A/; $b=~s/P/A/; $a cmp $b } },
|
---|
25 | NOTES => q{
|
---|
26 | Streaming metadata found in Parrot drone videos. See
|
---|
27 | L<https://developer.parrot.com/docs/pdraw/metadata.html> for the
|
---|
28 | specification.
|
---|
29 | },
|
---|
30 | P1 => {
|
---|
31 | Name => 'ParrotV1',
|
---|
32 | SubDirectory => { TagTable => 'Image::ExifTool::Parrot::V1' },
|
---|
33 | },
|
---|
34 | P2 => {
|
---|
35 | Name => 'ParrotV2',
|
---|
36 | SubDirectory => { TagTable => 'Image::ExifTool::Parrot::V2' },
|
---|
37 | },
|
---|
38 | P3 => {
|
---|
39 | Name => 'ParrotV3',
|
---|
40 | SubDirectory => { TagTable => 'Image::ExifTool::Parrot::V3' },
|
---|
41 | },
|
---|
42 | E1 => {
|
---|
43 | Name => 'ParrotTimeStamp',
|
---|
44 | SubDirectory => { TagTable => 'Image::ExifTool::Parrot::TimeStamp' },
|
---|
45 | },
|
---|
46 | E2 => {
|
---|
47 | Name => 'ParrotFollowMe',
|
---|
48 | SubDirectory => { TagTable => 'Image::ExifTool::Parrot::FollowMe' },
|
---|
49 | },
|
---|
50 | E3 => {
|
---|
51 | Name => 'ParrotAutomation',
|
---|
52 | SubDirectory => { TagTable => 'Image::ExifTool::Parrot::Automation' },
|
---|
53 | },
|
---|
54 | );
|
---|
55 |
|
---|
56 | # tags found in the Parrot 'mett' V1 timed metadata (ref 1) [untested]
|
---|
57 | %Image::ExifTool::Parrot::V1 = (
|
---|
58 | PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
---|
59 | NOTES => 'Parrot version 1 streaming metadata.',
|
---|
60 | GROUPS => { 2 => 'Location' },
|
---|
61 | 4 => {
|
---|
62 | Name => 'DroneYaw',
|
---|
63 | Format => 'int16s',
|
---|
64 | ValueConv => '$val / 0x1000 * 180 / 3.14159', # convert from rad to deg
|
---|
65 | },
|
---|
66 | 6 => {
|
---|
67 | Name => 'DronePitch',
|
---|
68 | Format => 'int16s',
|
---|
69 | ValueConv => '$val / 0x1000 * 180 / 3.14159',
|
---|
70 | },
|
---|
71 | 8 => {
|
---|
72 | Name => 'DroneRoll',
|
---|
73 | Format => 'int16s',
|
---|
74 | ValueConv => '$val / 0x1000 * 180 / 3.14159',
|
---|
75 | },
|
---|
76 | 10 => {
|
---|
77 | Name => 'CameraPan',
|
---|
78 | Format => 'int16s',
|
---|
79 | ValueConv => '$val / 0x1000 * 180 / 3.14159',
|
---|
80 | },
|
---|
81 | 12 => {
|
---|
82 | Name => 'CameraTilt',
|
---|
83 | Format => 'int16s',
|
---|
84 | ValueConv => '$val / 0x1000 * 180 / 3.14159',
|
---|
85 | },
|
---|
86 | 14 => {
|
---|
87 | Name => 'FrameView', # (W,X,Y,Z)
|
---|
88 | Format => 'int16s[4]',
|
---|
89 | ValueConv => 'my @a = split " ",$val; $_ /= 0x1000 foreach @a; "@a"',
|
---|
90 | },
|
---|
91 | 22 => {
|
---|
92 | Name => 'ExposureTime',
|
---|
93 | Groups => { 2 => 'Camera' },
|
---|
94 | Format => 'int16s',
|
---|
95 | ValueConv => '$val / 0x100 / 1000',
|
---|
96 | PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)',
|
---|
97 | },
|
---|
98 | 24 => {
|
---|
99 | Name => 'ISO',
|
---|
100 | Groups => { 2 => 'Camera' },
|
---|
101 | Format => 'int16s',
|
---|
102 | },
|
---|
103 | 26 => {
|
---|
104 | Name => 'WifiRSSI',
|
---|
105 | Groups => { 2 => 'Device' },
|
---|
106 | Format => 'int8s',
|
---|
107 | PrintConv => '"$val dBm"',
|
---|
108 | },
|
---|
109 | 27 => {
|
---|
110 | Name => 'Battery',
|
---|
111 | Groups => { 2 => 'Device' },
|
---|
112 | PrintConv => '"$val %"',
|
---|
113 | },
|
---|
114 | 28 => {
|
---|
115 | Name => 'GPSLatitude',
|
---|
116 | Format => 'int32s',
|
---|
117 | ValueConv => '$val / 0x100000',
|
---|
118 | PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")',
|
---|
119 | },
|
---|
120 | 32 => {
|
---|
121 | Name => 'GPSLongitude',
|
---|
122 | Format => 'int32s',
|
---|
123 | ValueConv => '$val / 0x100000',
|
---|
124 | PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")',
|
---|
125 | },
|
---|
126 | 36 => {
|
---|
127 | Name => 'GPSAltitude',
|
---|
128 | Format => 'int32s',
|
---|
129 | Mask => 0xffffff00,
|
---|
130 | ValueConv => '$val / 0x100',
|
---|
131 | PrintConv => 'sprintf("%.3f m", $val)',
|
---|
132 | },
|
---|
133 | 36.1 => {
|
---|
134 | Name => 'GPSSatellites', # (SV count)
|
---|
135 | Format => 'int32s',
|
---|
136 | Mask => 0xff,
|
---|
137 | },
|
---|
138 | 40 => {
|
---|
139 | Name => 'AltitudeFromTakeOff',
|
---|
140 | Format => 'int32s',
|
---|
141 | ValueConv => '$val / 0x10000',
|
---|
142 | PrintConv => 'sprintf("%.3f m", $val)',
|
---|
143 | },
|
---|
144 | 44 => {
|
---|
145 | Name => 'DistanceFromHome',
|
---|
146 | Format => 'int32u',
|
---|
147 | ValueConv => '$val / 0x10000',
|
---|
148 | },
|
---|
149 | 48 => {
|
---|
150 | Name => 'SpeedX',
|
---|
151 | Format => 'int16s',
|
---|
152 | ValueConv => '$val / 0x100',
|
---|
153 | },
|
---|
154 | 50 => {
|
---|
155 | Name => 'SpeedY',
|
---|
156 | Format => 'int16s',
|
---|
157 | ValueConv => '$val / 0x100',
|
---|
158 | },
|
---|
159 | 52 => {
|
---|
160 | Name => 'SpeedZ',
|
---|
161 | Format => 'int16s',
|
---|
162 | ValueConv => '$val / 0x100',
|
---|
163 | },
|
---|
164 | 54 => {
|
---|
165 | Name => 'Binning',
|
---|
166 | Groups => { 2 => 'Device' },
|
---|
167 | Mask => 0x80,
|
---|
168 | },
|
---|
169 | 54.1 => {
|
---|
170 | Name => 'FlyingState',
|
---|
171 | Groups => { 2 => 'Device' },
|
---|
172 | Mask => 0x7f,
|
---|
173 | PrintConv => {
|
---|
174 | 0 => 'Landed',
|
---|
175 | 1 => 'Taking Off',
|
---|
176 | 2 => 'Hovering',
|
---|
177 | 3 => 'Flying',
|
---|
178 | 4 => 'Landing',
|
---|
179 | 5 => 'Emergency',
|
---|
180 | },
|
---|
181 | },
|
---|
182 | 55 => {
|
---|
183 | Name => 'Animation',
|
---|
184 | Groups => { 2 => 'Device' },
|
---|
185 | Mask => 0x80,
|
---|
186 | },
|
---|
187 | 55.1 => {
|
---|
188 | Name => 'PilotingMode',
|
---|
189 | Groups => { 2 => 'Device' },
|
---|
190 | Mask => 0x7f,
|
---|
191 | PrintConv => {
|
---|
192 | 0 => 'Manual',
|
---|
193 | 1 => 'Return Home',
|
---|
194 | 2 => 'Flight Plan',
|
---|
195 | 3 => 'Follow Me',
|
---|
196 | },
|
---|
197 | },
|
---|
198 | );
|
---|
199 |
|
---|
200 | # tags found in the Parrot 'mett' V2 timed metadata (ref 1) [untested]
|
---|
201 | %Image::ExifTool::Parrot::V2 = (
|
---|
202 | PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
---|
203 | Groups => { 2 => 'Location' },
|
---|
204 | NOTES => 'Parrot version 2 basic streaming metadata.',
|
---|
205 | 4 => {
|
---|
206 | Name => 'Elevation',
|
---|
207 | Notes => 'estimated distance from ground',
|
---|
208 | Format => 'int32s',
|
---|
209 | ValueConv => '$val / 0x10000',
|
---|
210 | PrintConv => 'sprintf("%.3f m", $val)',
|
---|
211 | },
|
---|
212 | 8 => {
|
---|
213 | Name => 'GPSLatitude',
|
---|
214 | Format => 'int32s',
|
---|
215 | ValueConv => '$val / 0x400000',
|
---|
216 | PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")',
|
---|
217 | },
|
---|
218 | 12 => {
|
---|
219 | Name => 'GPSLongitude',
|
---|
220 | Format => 'int32s',
|
---|
221 | ValueConv => '$val / 0x400000',
|
---|
222 | PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")',
|
---|
223 | },
|
---|
224 | 16 => {
|
---|
225 | Name => 'GPSAltitude',
|
---|
226 | Format => 'int32s',
|
---|
227 | Mask => 0xffffff00,
|
---|
228 | ValueConv => '$val / 0x100',
|
---|
229 | PrintConv => 'sprintf("%.3f m", $val)',
|
---|
230 | },
|
---|
231 | 16.1 => {
|
---|
232 | Name => 'GPSSatellites', # (SV count)
|
---|
233 | Format => 'int32s',
|
---|
234 | Mask => 0xff,
|
---|
235 | },
|
---|
236 | 20 => {
|
---|
237 | Name => 'GPSVelocityNorth', # (m/s)
|
---|
238 | Format => 'int16s',
|
---|
239 | ValueConv => '$val / 0x100',
|
---|
240 | },
|
---|
241 | 22 => {
|
---|
242 | Name => 'GPSVelocityEast', # (m/s)
|
---|
243 | Format => 'int16s',
|
---|
244 | ValueConv => '$val / 0x100',
|
---|
245 | },
|
---|
246 | 24 => {
|
---|
247 | Name => 'GPSVelocityDown', # (m/s)
|
---|
248 | Format => 'int16s',
|
---|
249 | ValueConv => '$val / 0x100',
|
---|
250 | },
|
---|
251 | 26 => {
|
---|
252 | Name => 'AirSpeed', # (m/s)
|
---|
253 | Format => 'int16s',
|
---|
254 | RawConv => '$val < 0 ? undef : $val',
|
---|
255 | ValueConv => '$val / 0x100',
|
---|
256 | },
|
---|
257 | 28 => {
|
---|
258 | Name => 'DroneQuaternion', # (W,X,Y,Z)
|
---|
259 | Format => 'int16s[4]',
|
---|
260 | ValueConv => 'my @a = split " ",$val; $_ /= 0x4000 foreach @a; "@a"',
|
---|
261 | },
|
---|
262 | 36 => {
|
---|
263 | Name => 'FrameView', # (W,X,Y,Z)
|
---|
264 | Format => 'int16s[4]',
|
---|
265 | ValueConv => 'my @a = split " ",$val; $_ /= 0x4000 foreach @a; "@a"',
|
---|
266 | },
|
---|
267 | 44 => {
|
---|
268 | Name => 'CameraPan',
|
---|
269 | Format => 'int16s',
|
---|
270 | ValueConv => '$val / 0x1000 * 180 / 3.14159', # convert from rad to deg
|
---|
271 | },
|
---|
272 | 46 => {
|
---|
273 | Name => 'CameraTilt',
|
---|
274 | Format => 'int16s',
|
---|
275 | ValueConv => '$val / 0x1000 * 180 / 3.14159',
|
---|
276 | },
|
---|
277 | 48 => {
|
---|
278 | Name => 'ExposureTime',
|
---|
279 | Groups => { 2 => 'Camera' },
|
---|
280 | Format => 'int16u',
|
---|
281 | ValueConv => '$val / 0x100 / 1000',
|
---|
282 | PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)',
|
---|
283 | },
|
---|
284 | 50 => {
|
---|
285 | Name => 'ISO',
|
---|
286 | Groups => { 2 => 'Camera' },
|
---|
287 | Format => 'int16u',
|
---|
288 | },
|
---|
289 | 52 => {
|
---|
290 | Name => 'Binning',
|
---|
291 | Groups => { 2 => 'Device' },
|
---|
292 | Mask => 0x80,
|
---|
293 | },
|
---|
294 | 52.1 => {
|
---|
295 | Name => 'FlyingState',
|
---|
296 | Groups => { 2 => 'Device' },
|
---|
297 | Mask => 0x7f,
|
---|
298 | PrintConv => {
|
---|
299 | 0 => 'Landed',
|
---|
300 | 1 => 'Taking Off',
|
---|
301 | 2 => 'Hovering',
|
---|
302 | 3 => 'Flying',
|
---|
303 | 4 => 'Landing',
|
---|
304 | 5 => 'Emergency',
|
---|
305 | 6 => 'User Takeoff',
|
---|
306 | 7 => 'Motor Ramping',
|
---|
307 | 8 => 'Emergency Landing',
|
---|
308 | },
|
---|
309 | },
|
---|
310 | 53 => {
|
---|
311 | Name => 'Animation',
|
---|
312 | Groups => { 2 => 'Device' },
|
---|
313 | Mask => 0x80,
|
---|
314 | },
|
---|
315 | 53.1 => {
|
---|
316 | Name => 'PilotingMode',
|
---|
317 | Groups => { 2 => 'Device' },
|
---|
318 | Mask => 0x7f,
|
---|
319 | PrintConv => {
|
---|
320 | 0 => 'Manual',
|
---|
321 | 1 => 'Return Home',
|
---|
322 | 2 => 'Flight Plan',
|
---|
323 | 3 => 'Follow Me / Tracking', # (same as 'Tracking')
|
---|
324 | 4 => 'Magic Carpet',
|
---|
325 | 5 => 'Move To',
|
---|
326 | },
|
---|
327 | },
|
---|
328 | 54 => {
|
---|
329 | Name => 'WifiRSSI',
|
---|
330 | Groups => { 2 => 'Device' },
|
---|
331 | Format => 'int8s',
|
---|
332 | PrintConv => '"$val dBm"',
|
---|
333 | },
|
---|
334 | 55 => {
|
---|
335 | Name => 'Battery',
|
---|
336 | Groups => { 2 => 'Device' },
|
---|
337 | PrintConv => '"$val %"',
|
---|
338 | },
|
---|
339 | );
|
---|
340 |
|
---|
341 | # tags found in the Parrot 'mett' V3 timed metadata (ref 1)
|
---|
342 | %Image::ExifTool::Parrot::V3 = (
|
---|
343 | PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
---|
344 | GROUPS => { 2 => 'Location' },
|
---|
345 | NOTES => 'Parrot version 3 basic streaming metadata.',
|
---|
346 | 4 => {
|
---|
347 | Name => 'Elevation',
|
---|
348 | Notes => 'estimated distance from ground',
|
---|
349 | Format => 'int32s',
|
---|
350 | ValueConv => '$val / 0x10000',
|
---|
351 | PrintConv => 'sprintf("%.3f m", $val)',
|
---|
352 | },
|
---|
353 | 8 => {
|
---|
354 | Name => 'GPSLatitude',
|
---|
355 | Format => 'int32s',
|
---|
356 | ValueConv => '$val / 0x400000',
|
---|
357 | PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")',
|
---|
358 | },
|
---|
359 | 12 => {
|
---|
360 | Name => 'GPSLongitude',
|
---|
361 | Format => 'int32s',
|
---|
362 | ValueConv => '$val / 0x400000',
|
---|
363 | PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")',
|
---|
364 | },
|
---|
365 | 16 => {
|
---|
366 | Name => 'GPSAltitude',
|
---|
367 | Format => 'int32s',
|
---|
368 | Mask => 0xffffff00,
|
---|
369 | ValueConv => '$val / 0x100',
|
---|
370 | PrintConv => 'sprintf("%.3f m", $val)',
|
---|
371 | },
|
---|
372 | 16.1 => {
|
---|
373 | Name => 'GPSSatellites', # (SV count)
|
---|
374 | Format => 'int32s',
|
---|
375 | Mask => 0xff,
|
---|
376 | },
|
---|
377 | 20 => {
|
---|
378 | Name => 'GPSVelocityNorth', # (m/s)
|
---|
379 | Format => 'int16s',
|
---|
380 | ValueConv => '$val / 0x100',
|
---|
381 | },
|
---|
382 | 22 => {
|
---|
383 | Name => 'GPSVelocityEast', # (m/s)
|
---|
384 | Format => 'int16s',
|
---|
385 | ValueConv => '$val / 0x100',
|
---|
386 | },
|
---|
387 | 24 => {
|
---|
388 | Name => 'GPSVelocityDown', # (m/s)
|
---|
389 | Format => 'int16s',
|
---|
390 | ValueConv => '$val / 0x100',
|
---|
391 | },
|
---|
392 | 26 => {
|
---|
393 | Name => 'AirSpeed', # (m/s)
|
---|
394 | Format => 'int16s',
|
---|
395 | RawConv => '$val < 0 ? undef : $val',
|
---|
396 | ValueConv => '$val / 0x100',
|
---|
397 | },
|
---|
398 | 28 => {
|
---|
399 | Name => 'DroneQuaternion', # (W,X,Y,Z)
|
---|
400 | Format => 'int16s[4]',
|
---|
401 | ValueConv => 'my @a = split " ",$val; $_ /= 0x4000 foreach @a; "@a"',
|
---|
402 | },
|
---|
403 | 36 => {
|
---|
404 | Name => 'FrameBaseView', # (W,X,Y,Z without pan/tilt)
|
---|
405 | Format => 'int16s[4]',
|
---|
406 | ValueConv => 'my @a = split " ",$val; $_ /= 0x4000 foreach @a; "@a"',
|
---|
407 | },
|
---|
408 | 44 => {
|
---|
409 | Name => 'FrameView', # (W,X,Y,Z)
|
---|
410 | Format => 'int16s[4]',
|
---|
411 | ValueConv => 'my @a = split " ",$val; $_ /= 0x4000 foreach @a; "@a"',
|
---|
412 | },
|
---|
413 | 52 => {
|
---|
414 | Name => 'ExposureTime',
|
---|
415 | Groups => { 2 => 'Camera' },
|
---|
416 | Format => 'int16u',
|
---|
417 | ValueConv => '$val / 0x100 / 1000',
|
---|
418 | PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)',
|
---|
419 | },
|
---|
420 | 54 => {
|
---|
421 | Name => 'ISO',
|
---|
422 | Groups => { 2 => 'Camera' },
|
---|
423 | Format => 'int16u',
|
---|
424 | },
|
---|
425 | 56 => {
|
---|
426 | Name => 'RedBalance',
|
---|
427 | Groups => { 2 => 'Camera' },
|
---|
428 | Format => 'int16u',
|
---|
429 | ValueConv => '$val / 0x4000',
|
---|
430 | },
|
---|
431 | 58 => {
|
---|
432 | Name => 'BlueBalance',
|
---|
433 | Groups => { 2 => 'Camera' },
|
---|
434 | Format => 'int16u',
|
---|
435 | ValueConv => '$val / 0x4000',
|
---|
436 | },
|
---|
437 | 60 => {
|
---|
438 | Name => 'FOV', # (degrees)
|
---|
439 | Description => 'Field Of View',
|
---|
440 | Notes => 'horizontal and vertical field of view in degrees',
|
---|
441 | Groups => { 2 => 'Image' },
|
---|
442 | Format => 'int16u[2]',
|
---|
443 | ValueConv => 'my @a = split " ",$val; $_ /= 0x100 foreach @a; "@a"',
|
---|
444 | },
|
---|
445 | 64 => {
|
---|
446 | Name => 'LinkGoodput',
|
---|
447 | Groups => { 2 => 'Device' },
|
---|
448 | Format => 'int32u',
|
---|
449 | Mask => 0xffffff00,
|
---|
450 | PrintConv => '"$val kbit/s"',
|
---|
451 | },
|
---|
452 | 64.1 => {
|
---|
453 | Name => 'LinkQuality',
|
---|
454 | Groups => { 2 => 'Device' },
|
---|
455 | Format => 'int32u',
|
---|
456 | Notes => '0-5',
|
---|
457 | Mask => 0xff,
|
---|
458 | },
|
---|
459 | 68 => {
|
---|
460 | Name => 'WifiRSSI',
|
---|
461 | Groups => { 2 => 'Device' },
|
---|
462 | Format => 'int8s',
|
---|
463 | PrintConv => '"$val dBm"',
|
---|
464 | },
|
---|
465 | 69 => {
|
---|
466 | Name => 'Battery',
|
---|
467 | Groups => { 2 => 'Device' },
|
---|
468 | PrintConv => '"$val %"',
|
---|
469 | },
|
---|
470 | 70 => {
|
---|
471 | Name => 'Binning',
|
---|
472 | Groups => { 2 => 'Device' },
|
---|
473 | Mask => 0x80,
|
---|
474 | },
|
---|
475 | 70.1 => {
|
---|
476 | Name => 'FlyingState',
|
---|
477 | Groups => { 2 => 'Device' },
|
---|
478 | Mask => 0x7f,
|
---|
479 | PrintConv => {
|
---|
480 | 0 => 'Landed',
|
---|
481 | 1 => 'Taking Off',
|
---|
482 | 2 => 'Hovering',
|
---|
483 | 3 => 'Flying',
|
---|
484 | 4 => 'Landing',
|
---|
485 | 5 => 'Emergency',
|
---|
486 | 6 => 'User Takeoff',
|
---|
487 | 7 => 'Motor Ramping',
|
---|
488 | 8 => 'Emergency Landing',
|
---|
489 | },
|
---|
490 | },
|
---|
491 | 71 => {
|
---|
492 | Name => 'Animation',
|
---|
493 | Groups => { 2 => 'Device' },
|
---|
494 | Mask => 0x80,
|
---|
495 | },
|
---|
496 | 71.1 => {
|
---|
497 | Name => 'PilotingMode',
|
---|
498 | Groups => { 2 => 'Device' },
|
---|
499 | Mask => 0x7f,
|
---|
500 | PrintConv => {
|
---|
501 | 0 => 'Manual',
|
---|
502 | 1 => 'Return Home',
|
---|
503 | 2 => 'Flight Plan',
|
---|
504 | 3 => 'Follow Me / Tracking', # (same as 'Tracking')
|
---|
505 | 4 => 'Magic Carpet',
|
---|
506 | 5 => 'Move To',
|
---|
507 | },
|
---|
508 | },
|
---|
509 | );
|
---|
510 |
|
---|
511 | # tags found in the Parrot 'mett' E1 timestamp timed metadata (ref 1)
|
---|
512 | %Image::ExifTool::Parrot::TimeStamp = (
|
---|
513 | PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
---|
514 | NOTES => 'Parrot streaming metadata timestamp extension.',
|
---|
515 | GROUPS => { 2 => 'Time' },
|
---|
516 | 4 => {
|
---|
517 | Name => 'TimeStamp',
|
---|
518 | Format => 'int64u',
|
---|
519 | ValueConv => '$val / 1e6',
|
---|
520 | },
|
---|
521 | );
|
---|
522 |
|
---|
523 | # tags found in the Parrot 'mett' E2 follow-me timed metadata (ref 1) [untested]
|
---|
524 | %Image::ExifTool::Parrot::FollowMe = (
|
---|
525 | PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
---|
526 | GROUPS => { 2 => 'Location' },
|
---|
527 | NOTES => 'Parrot streaming metadata follow-me extension.',
|
---|
528 | 4 => {
|
---|
529 | Name => 'GPSTargetLatitude',
|
---|
530 | Format => 'int32s',
|
---|
531 | ValueConv => '$val / 0x400000',
|
---|
532 | },
|
---|
533 | 8 => {
|
---|
534 | Name => 'GPSTargetLongitude',
|
---|
535 | Format => 'int32s',
|
---|
536 | ValueConv => '$val / 0x400000',
|
---|
537 | },
|
---|
538 | 12 => {
|
---|
539 | Name => 'GPSTargetAltitude',
|
---|
540 | Format => 'int32s',
|
---|
541 | ValueConv => '$val / 0x10000',
|
---|
542 | },
|
---|
543 | 16 => {
|
---|
544 | Name => 'Follow-meMode',
|
---|
545 | Groups => { 2 => 'Device' },
|
---|
546 | PrintConv => { BITMASK => {
|
---|
547 | 0 => 'Follow-me enabled',
|
---|
548 | 1 => 'Follow-me', # (0=Look-at-me! auggh. see AutomationFlags below)
|
---|
549 | 2 => 'Angle locked',
|
---|
550 | }},
|
---|
551 | },
|
---|
552 | 17 => {
|
---|
553 | Name => 'Follow-meAnimation',
|
---|
554 | Groups => { 2 => 'Device' },
|
---|
555 | PrintConv => {
|
---|
556 | 0 => 'None',
|
---|
557 | 1 => 'Orbit',
|
---|
558 | 2 => 'Boomerang',
|
---|
559 | 3 => 'Parabola',
|
---|
560 | 4 => 'Zenith',
|
---|
561 | },
|
---|
562 | },
|
---|
563 | );
|
---|
564 |
|
---|
565 | # tags found in the Parrot 'mett' E3 automation timed metadata (ref 1)
|
---|
566 | %Image::ExifTool::Parrot::Automation = (
|
---|
567 | PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
---|
568 | GROUPS => { 2 => 'Location' },
|
---|
569 | NOTES => 'Parrot streaming metadata automation extension.',
|
---|
570 | 4 => {
|
---|
571 | Name => 'GPSFramingLatitude',
|
---|
572 | Format => 'int32s',
|
---|
573 | ValueConv => '$val / 0x400000',
|
---|
574 | },
|
---|
575 | 8 => {
|
---|
576 | Name => 'GPSFramingLongitude',
|
---|
577 | Format => 'int32s',
|
---|
578 | ValueConv => '$val / 0x400000',
|
---|
579 | },
|
---|
580 | 12 => {
|
---|
581 | Name => 'GPSFramingAltitude',
|
---|
582 | Format => 'int32s',
|
---|
583 | ValueConv => '$val / 0x10000',
|
---|
584 | },
|
---|
585 | 16 => {
|
---|
586 | Name => 'GPSDestLatitude',
|
---|
587 | Format => 'int32s',
|
---|
588 | ValueConv => '$val / 0x400000',
|
---|
589 | },
|
---|
590 | 20 => {
|
---|
591 | Name => 'GPSDestLongitude',
|
---|
592 | Format => 'int32s',
|
---|
593 | ValueConv => '$val / 0x400000',
|
---|
594 | },
|
---|
595 | 24 => {
|
---|
596 | Name => 'GPSDestAltitude',
|
---|
597 | Format => 'int32s',
|
---|
598 | ValueConv => '$val / 0x10000',
|
---|
599 | },
|
---|
600 | 28 => {
|
---|
601 | Name => 'AutomationAnimation',
|
---|
602 | Groups => { 2 => 'Device' },
|
---|
603 | PrintConv => {
|
---|
604 | 0 => 'None',
|
---|
605 | 1 => 'Orbit',
|
---|
606 | 2 => 'Boomerang',
|
---|
607 | 3 => 'Parabola',
|
---|
608 | 4 => 'Dolly Slide',
|
---|
609 | 5 => 'Dolly Zoom',
|
---|
610 | 6 => 'Reveal Vertical',
|
---|
611 | 7 => 'Reveal Horizontal',
|
---|
612 | 8 => 'Candle',
|
---|
613 | 9 => 'Flip Front',
|
---|
614 | 10 => 'Flip Back',
|
---|
615 | 11 => 'Flip Left',
|
---|
616 | 12 => 'Flip Right',
|
---|
617 | 13 => 'Twist Up',
|
---|
618 | 14 => 'Position Twist Up',
|
---|
619 | },
|
---|
620 | },
|
---|
621 | 29 => {
|
---|
622 | Name => 'AutomationFlags',
|
---|
623 | Groups => { 2 => 'Device' },
|
---|
624 | PrintConv => { BITMASK => {
|
---|
625 | 0 => 'Follow-me enabled',
|
---|
626 | 1 => 'Look-at-me enabled', # (really? opposite sense to Follow-meMode above!)
|
---|
627 | 2 => 'Angle locked',
|
---|
628 | }},
|
---|
629 | },
|
---|
630 | );
|
---|
631 |
|
---|
632 | %Image::ExifTool::Parrot::Composite = (
|
---|
633 | GPSDateTime => {
|
---|
634 | Description => 'GPS Date/Time',
|
---|
635 | Groups => { 2 => 'Time' },
|
---|
636 | SubDoc => 1,
|
---|
637 | Require => {
|
---|
638 | 0 => 'Parrot:GPSLatitude', # (avoids creating this tag for other videos)
|
---|
639 | 1 => 'Main:CreateDate',
|
---|
640 | 2 => 'SampleTime',
|
---|
641 | },
|
---|
642 | ValueConv => q{
|
---|
643 | my $time = $val[1];
|
---|
644 | my $diff = $val[2];
|
---|
645 | # handle time zone and shift to UTC
|
---|
646 | if ($time =~ s/([-+])(\d{1,2}):?(\d{2})$//) {
|
---|
647 | my $secs = (($2 * 60) + $3) * 60;
|
---|
648 | $secs *= -1 if $1 eq '+';
|
---|
649 | $diff += $secs;
|
---|
650 | } elsif ($time !~ s/Z$//) {
|
---|
651 | # shift from local time
|
---|
652 | $diff += GetUnixTime($time, 1) - GetUnixTime($time);
|
---|
653 | }
|
---|
654 | my $sign = ($diff =~ s/^-// ? '-' : '');
|
---|
655 | $time .= '.000'; # add decimal seconds
|
---|
656 | ShiftTime($time, "${sign}0:0:$diff");
|
---|
657 | return $time . 'Z';
|
---|
658 | },
|
---|
659 | PrintConv => '$self->ConvertDateTime($val)',
|
---|
660 | },
|
---|
661 | );
|
---|
662 |
|
---|
663 | # add our composite tags
|
---|
664 | Image::ExifTool::AddCompositeTags('Image::ExifTool::Parrot');
|
---|
665 |
|
---|
666 |
|
---|
667 | #------------------------------------------------------------------------------
|
---|
668 | # Parse Parrot 'mett' timed metadata
|
---|
669 | # Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref
|
---|
670 | # Returns: 1 on success
|
---|
671 | # (this metadata design is really stupid -- you need to know the size of the base structures)
|
---|
672 | sub Process_mett($$$)
|
---|
673 | {
|
---|
674 | my ($et, $dirInfo, $tagTbl) = @_;
|
---|
675 | my $dataPt = $$dirInfo{DataPt};
|
---|
676 | my $dataPos = $$dirInfo{DataPos};
|
---|
677 | my $dirEnd = length $$dataPt;
|
---|
678 | my $pos = $$dirInfo{DirStart} || 0;
|
---|
679 |
|
---|
680 | $et->VerboseDir('Parrot mett', undef, $dirEnd);
|
---|
681 |
|
---|
682 | while ($pos + 4 < $dirEnd) {
|
---|
683 | my ($id, $nwords) = unpack("x${pos}a2n", $$dataPt);
|
---|
684 | my $size;
|
---|
685 | if ($id !~ /^[EP]\d/) {
|
---|
686 | # no ID so this should be a 60-byte V1 recording record, otherwise give up
|
---|
687 | last unless $dirEnd == 60;
|
---|
688 | $id = 'P1'; # generate a fake ID
|
---|
689 | # ignore the first 4 of the record so the fields will align with
|
---|
690 | # the other V1 records (unfortunately, this means that we won't
|
---|
691 | # decode the V1 recording frame timestamp, but oh well)
|
---|
692 | $pos += 4;
|
---|
693 | $size = $dirEnd - $pos;
|
---|
694 | # must override size for P3 and P3 records since it includes the extensions (augh!)
|
---|
695 | } elsif ($id eq 'P2') {
|
---|
696 | $size = 56;
|
---|
697 | } elsif ($id eq 'P3') {
|
---|
698 | $size = 72;
|
---|
699 | } else {
|
---|
700 | $size = $nwords * 4 + 4;
|
---|
701 | }
|
---|
702 | last if $pos + $size > $dirEnd;
|
---|
703 | $et->HandleTag($tagTbl, $id, undef,
|
---|
704 | DataPt => $dataPt,
|
---|
705 | DataPos => $dataPos,
|
---|
706 | Base => $$dirInfo{Base},
|
---|
707 | Start => $pos,
|
---|
708 | Size => $size,
|
---|
709 | );
|
---|
710 | $pos += $size;
|
---|
711 | }
|
---|
712 | return 1;
|
---|
713 | }
|
---|
714 |
|
---|
715 | 1; # end
|
---|
716 |
|
---|
717 | __END__
|
---|
718 |
|
---|
719 | =head1 NAME
|
---|
720 |
|
---|
721 | Image::ExifTool::Parrot - Read timed metadata from Parrot drone videos
|
---|
722 |
|
---|
723 | =head1 SYNOPSIS
|
---|
724 |
|
---|
725 | This module is loaded automatically by Image::ExifTool when required.
|
---|
726 |
|
---|
727 | =head1 DESCRIPTION
|
---|
728 |
|
---|
729 | This module contains definitions required by Image::ExifTool to interpret
|
---|
730 | timed metadata from the 'mett' frame found in Parrot drone MP4 videos.
|
---|
731 |
|
---|
732 | =head1 AUTHOR
|
---|
733 |
|
---|
734 | Copyright 2003-2021, Phil Harvey (philharvey66 at gmail.com)
|
---|
735 |
|
---|
736 | This library is free software; you can redistribute it and/or modify it
|
---|
737 | under the same terms as Perl itself.
|
---|
738 |
|
---|
739 | =head1 REFERENCES
|
---|
740 |
|
---|
741 | =over 4
|
---|
742 |
|
---|
743 | =item L<https://developer.parrot.com/docs/pdraw/metadata.html>
|
---|
744 |
|
---|
745 | =back
|
---|
746 |
|
---|
747 | =head1 SEE ALSO
|
---|
748 |
|
---|
749 | L<Image::ExifTool::TagNames/Parrot Tags>,
|
---|
750 | L<Image::ExifTool(3pm)|Image::ExifTool>
|
---|
751 |
|
---|
752 | =cut
|
---|