add MakerNote support for DJI

This commit is contained in:
cDc
2018-07-10 10:00:24 +03:00
parent 8e3316cb41
commit 04969097a4
3 changed files with 108 additions and 5 deletions

View File

@@ -145,6 +145,10 @@ public:
length = parse32(buf + offs + 4, alignIntel);
}
const uint8_t* GetBuffer() const { return buf; }
unsigned GetOffset() const { return offs; }
bool IsIntelAligned() const { return alignIntel; }
uint16_t GetTag() const { return tag; }
uint32_t GetLength() const { return length; }
uint32_t GetData() const { return parse32(buf + offs + 8, alignIntel); }
@@ -153,11 +157,12 @@ public:
bool IsShort() const { return format == 3; }
bool IsLong() const { return format == 4; }
bool IsRational() const { return format == 5 || format == 10; }
bool IsFloat() const { return format == 11; }
bool Fetch(std::string& val) const {
if (format != 2 || length == 0)
return false;
val = parseEXIFString(buf, length, GetData(), tiff_header_start, len, alignIntel);
val = parseString(buf, length, GetData(), tiff_header_start, len, alignIntel);
return true;
}
bool Fetch(uint8_t& val) const {
@@ -184,16 +189,30 @@ public:
val = parse32(buf + offs + 8, alignIntel);
return true;
}
bool Fetch(float& val) const {
if (!IsFloat() || length == 0)
return false;
val = parseFloat(buf + offs + 8, alignIntel);
return true;
}
bool Fetch(double& val) const {
if (!IsRational() || length == 0)
return false;
val = parseEXIFRational(buf + GetSubIFD(), alignIntel);
val = parseRational(buf + GetSubIFD(), alignIntel);
return true;
}
bool Fetch(double& val, uint32_t idx) const {
if (!IsRational() || length <= idx)
return false;
val = parseEXIFRational(buf + GetSubIFD() + idx*8, alignIntel);
val = parseRational(buf + GetSubIFD() + idx*8, alignIntel);
return true;
}
bool FetchFloat(double& val) const {
float _val;
if (!Fetch(_val))
return false;
val = _val;
return true;
}
@@ -217,14 +236,22 @@ public:
((uint32_t)buf[2]<<8) |
buf[3];
}
static double parseEXIFRational(const uint8_t* buf, bool intel) {
static float parseFloat(const uint8_t* buf, bool intel) {
union {
uint32_t i;
float f;
} i2f;
i2f.i = parse32(buf, intel);
return i2f.f;
}
static double parseRational(const uint8_t* buf, bool intel) {
const uint32_t denominator = parse32(buf+4, intel);
if (denominator == 0)
return 0.0;
const uint32_t numerator = parse32(buf, intel);
return (double)(int32_t)numerator/(double)(int32_t)denominator;
}
static std::string parseEXIFString(const uint8_t* buf,
static std::string parseString(const uint8_t* buf,
unsigned num_components,
unsigned data,
unsigned base,
@@ -448,6 +475,11 @@ void EXIFInfo::parseIFDExif(EntryParser& parser) {
}
break;
case 0x927c:
// MakerNote
parseIFDMakerNote(parser);
break;
case 0x9291:
// Fractions of seconds for DateTimeOriginal
parser.Fetch(SubSecTimeOriginal);
@@ -534,6 +566,60 @@ void EXIFInfo::parseIFDExif(EntryParser& parser) {
}
}
// Parse tag as MakerNote IFD
void EXIFInfo::parseIFDMakerNote(EntryParser& parser) {
const unsigned startOff = parser.GetOffset();
const uint32_t off = parser.GetSubIFD();
if (0 != _tcsicmp(Make.c_str(), "DJI"))
return;
int num_entries = EntryParser::parse16(parser.GetBuffer()+off, parser.IsIntelAligned());
if (uint32_t(2 + 12 * num_entries) > parser.GetLength())
return;
parser.Init(off+2);
parser.ParseTag();
--num_entries;
std::string maker;
if (parser.GetTag() == 1 && parser.Fetch(maker)) {
if (0 == _tcsicmp(maker.c_str(), "DJI")) {
while (--num_entries >= 0) {
parser.ParseTag();
switch (parser.GetTag()) {
case 3:
// SpeedX
parser.FetchFloat(GeoLocation.SpeedX);
break;
case 4:
// SpeedY
parser.FetchFloat(GeoLocation.SpeedY);
break;
case 5:
// SpeedZ
parser.FetchFloat(GeoLocation.SpeedZ);
break;
case 9:
// Camera Pitch
parser.FetchFloat(GeoLocation.PitchDegree);
break;
case 10:
// Camera Yaw
parser.FetchFloat(GeoLocation.YawDegree);
break;
case 11:
// Camera Roll
parser.FetchFloat(GeoLocation.RollDegree);
break;
}
}
}
}
parser.Init(startOff+12);
}
// Parse tag as GPS IFD
void EXIFInfo::parseIFDGPS(EntryParser& parser) {
switch (parser.GetTag()) {
@@ -985,6 +1071,9 @@ bool EXIFInfo::Geolocation_t::hasRelativeAltitude() const {
bool EXIFInfo::Geolocation_t::hasOrientation() const {
return RollDegree != DBL_MAX && PitchDegree != DBL_MAX && YawDegree != DBL_MAX;
}
bool EXIFInfo::Geolocation_t::hasSpeed() const {
return SpeedX != DBL_MAX && SpeedY != DBL_MAX && SpeedZ != DBL_MAX;
}
void EXIFInfo::clear() {
@@ -1055,6 +1144,9 @@ void EXIFInfo::clear() {
GeoLocation.RollDegree = DBL_MAX;
GeoLocation.PitchDegree = DBL_MAX;
GeoLocation.YawDegree = DBL_MAX;
GeoLocation.SpeedX = DBL_MAX;
GeoLocation.SpeedY = DBL_MAX;
GeoLocation.SpeedZ = DBL_MAX;
GeoLocation.GPSDOP = 0;
GeoLocation.GPSDifferential = 0;
GeoLocation.GPSMapDatum = "";

View File

@@ -133,6 +133,8 @@ private:
void parseIFDExif(EntryParser&);
// Parse tag as GPS IFD.
void parseIFDGPS(EntryParser&);
// Parse tag as MakerNote IFD.
void parseIFDMakerNote(EntryParser&);
public:
// Data fields
@@ -270,6 +272,9 @@ public:
double RollDegree; // Flight roll in degrees
double PitchDegree; // Flight pitch in degrees
double YawDegree; // Flight yaw in degrees
double SpeedX; // Flight speed on X in meters/second
double SpeedY; // Flight speed on Y in meters/second
double SpeedZ; // Flight speed on Z in meters/second
double GPSDOP; // GPS DOP (data degree of precision)
uint16_t GPSDifferential; // Differential correction applied to the GPS receiver (may not exist)
// 0: measurement without differential correction
@@ -288,6 +293,7 @@ public:
bool hasAltitude() const; // Return true if (alt) is available
bool hasRelativeAltitude()const;// Return true if (rel_alt) is available
bool hasOrientation() const; // Return true if (roll,yaw,pitch) is available
bool hasSpeed() const; // Return true if (speedX,speedY,speedZ) is available
} GeoLocation;
};

View File

@@ -132,6 +132,11 @@ int main(int argc, const char** argv)
std::cout << "GeoLocation.PitchDegree " << imageEXIF.GeoLocation.PitchDegree << "\n";
std::cout << "GeoLocation.YawDegree " << imageEXIF.GeoLocation.YawDegree << "\n";
}
if (imageEXIF.GeoLocation.hasSpeed()) {
std::cout << "GeoLocation.SpeedX " << imageEXIF.GeoLocation.SpeedX << "\n";
std::cout << "GeoLocation.SpeedY " << imageEXIF.GeoLocation.SpeedY << "\n";
std::cout << "GeoLocation.SpeedZ " << imageEXIF.GeoLocation.SpeedZ << "\n";
}
std::cout << "GeoLocation.GPSDOP " << imageEXIF.GeoLocation.GPSDOP << "\n";
std::cout << "GeoLocation.GPSDifferential " << imageEXIF.GeoLocation.GPSDifferential << "\n";
if (!imageEXIF.GeoLocation.GPSMapDatum.empty())