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 11package Image::ExifTool::Parrot; 12 13use strict; 14use vars qw($VERSION); 15 16$VERSION = '1.01'; 17 18sub 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 664Image::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) 672sub 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 7151; # end 716 717__END__ 718 719=head1 NAME 720 721Image::ExifTool::Parrot - Read timed metadata from Parrot drone videos 722 723=head1 SYNOPSIS 724 725This module is loaded automatically by Image::ExifTool when required. 726 727=head1 DESCRIPTION 728 729This module contains definitions required by Image::ExifTool to interpret 730timed metadata from the 'mett' frame found in Parrot drone MP4 videos. 731 732=head1 AUTHOR 733 734Copyright 2003-2021, Phil Harvey (philharvey66 at gmail.com) 735 736This library is free software; you can redistribute it and/or modify it 737under 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 749L<Image::ExifTool::TagNames/Parrot Tags>, 750L<Image::ExifTool(3pm)|Image::ExifTool> 751 752=cut 753