add MakerNote support for DJI
This commit is contained in:
102
TinyEXIF.cpp
102
TinyEXIF.cpp
@@ -145,6 +145,10 @@ public:
|
|||||||
length = parse32(buf + offs + 4, alignIntel);
|
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; }
|
uint16_t GetTag() const { return tag; }
|
||||||
uint32_t GetLength() const { return length; }
|
uint32_t GetLength() const { return length; }
|
||||||
uint32_t GetData() const { return parse32(buf + offs + 8, alignIntel); }
|
uint32_t GetData() const { return parse32(buf + offs + 8, alignIntel); }
|
||||||
@@ -153,11 +157,12 @@ public:
|
|||||||
bool IsShort() const { return format == 3; }
|
bool IsShort() const { return format == 3; }
|
||||||
bool IsLong() const { return format == 4; }
|
bool IsLong() const { return format == 4; }
|
||||||
bool IsRational() const { return format == 5 || format == 10; }
|
bool IsRational() const { return format == 5 || format == 10; }
|
||||||
|
bool IsFloat() const { return format == 11; }
|
||||||
|
|
||||||
bool Fetch(std::string& val) const {
|
bool Fetch(std::string& val) const {
|
||||||
if (format != 2 || length == 0)
|
if (format != 2 || length == 0)
|
||||||
return false;
|
return false;
|
||||||
val = parseEXIFString(buf, length, GetData(), tiff_header_start, len, alignIntel);
|
val = parseString(buf, length, GetData(), tiff_header_start, len, alignIntel);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool Fetch(uint8_t& val) const {
|
bool Fetch(uint8_t& val) const {
|
||||||
@@ -184,16 +189,30 @@ public:
|
|||||||
val = parse32(buf + offs + 8, alignIntel);
|
val = parse32(buf + offs + 8, alignIntel);
|
||||||
return true;
|
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 {
|
bool Fetch(double& val) const {
|
||||||
if (!IsRational() || length == 0)
|
if (!IsRational() || length == 0)
|
||||||
return false;
|
return false;
|
||||||
val = parseEXIFRational(buf + GetSubIFD(), alignIntel);
|
val = parseRational(buf + GetSubIFD(), alignIntel);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool Fetch(double& val, uint32_t idx) const {
|
bool Fetch(double& val, uint32_t idx) const {
|
||||||
if (!IsRational() || length <= idx)
|
if (!IsRational() || length <= idx)
|
||||||
return false;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,14 +236,22 @@ public:
|
|||||||
((uint32_t)buf[2]<<8) |
|
((uint32_t)buf[2]<<8) |
|
||||||
buf[3];
|
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);
|
const uint32_t denominator = parse32(buf+4, intel);
|
||||||
if (denominator == 0)
|
if (denominator == 0)
|
||||||
return 0.0;
|
return 0.0;
|
||||||
const uint32_t numerator = parse32(buf, intel);
|
const uint32_t numerator = parse32(buf, intel);
|
||||||
return (double)(int32_t)numerator/(double)(int32_t)denominator;
|
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 num_components,
|
||||||
unsigned data,
|
unsigned data,
|
||||||
unsigned base,
|
unsigned base,
|
||||||
@@ -448,6 +475,11 @@ void EXIFInfo::parseIFDExif(EntryParser& parser) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 0x927c:
|
||||||
|
// MakerNote
|
||||||
|
parseIFDMakerNote(parser);
|
||||||
|
break;
|
||||||
|
|
||||||
case 0x9291:
|
case 0x9291:
|
||||||
// Fractions of seconds for DateTimeOriginal
|
// Fractions of seconds for DateTimeOriginal
|
||||||
parser.Fetch(SubSecTimeOriginal);
|
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
|
// Parse tag as GPS IFD
|
||||||
void EXIFInfo::parseIFDGPS(EntryParser& parser) {
|
void EXIFInfo::parseIFDGPS(EntryParser& parser) {
|
||||||
switch (parser.GetTag()) {
|
switch (parser.GetTag()) {
|
||||||
@@ -985,6 +1071,9 @@ bool EXIFInfo::Geolocation_t::hasRelativeAltitude() const {
|
|||||||
bool EXIFInfo::Geolocation_t::hasOrientation() const {
|
bool EXIFInfo::Geolocation_t::hasOrientation() const {
|
||||||
return RollDegree != DBL_MAX && PitchDegree != DBL_MAX && YawDegree != DBL_MAX;
|
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() {
|
void EXIFInfo::clear() {
|
||||||
@@ -1055,6 +1144,9 @@ void EXIFInfo::clear() {
|
|||||||
GeoLocation.RollDegree = DBL_MAX;
|
GeoLocation.RollDegree = DBL_MAX;
|
||||||
GeoLocation.PitchDegree = DBL_MAX;
|
GeoLocation.PitchDegree = DBL_MAX;
|
||||||
GeoLocation.YawDegree = DBL_MAX;
|
GeoLocation.YawDegree = DBL_MAX;
|
||||||
|
GeoLocation.SpeedX = DBL_MAX;
|
||||||
|
GeoLocation.SpeedY = DBL_MAX;
|
||||||
|
GeoLocation.SpeedZ = DBL_MAX;
|
||||||
GeoLocation.GPSDOP = 0;
|
GeoLocation.GPSDOP = 0;
|
||||||
GeoLocation.GPSDifferential = 0;
|
GeoLocation.GPSDifferential = 0;
|
||||||
GeoLocation.GPSMapDatum = "";
|
GeoLocation.GPSMapDatum = "";
|
||||||
|
|||||||
@@ -133,6 +133,8 @@ private:
|
|||||||
void parseIFDExif(EntryParser&);
|
void parseIFDExif(EntryParser&);
|
||||||
// Parse tag as GPS IFD.
|
// Parse tag as GPS IFD.
|
||||||
void parseIFDGPS(EntryParser&);
|
void parseIFDGPS(EntryParser&);
|
||||||
|
// Parse tag as MakerNote IFD.
|
||||||
|
void parseIFDMakerNote(EntryParser&);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Data fields
|
// Data fields
|
||||||
@@ -270,6 +272,9 @@ public:
|
|||||||
double RollDegree; // Flight roll in degrees
|
double RollDegree; // Flight roll in degrees
|
||||||
double PitchDegree; // Flight pitch in degrees
|
double PitchDegree; // Flight pitch in degrees
|
||||||
double YawDegree; // Flight yaw 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)
|
double GPSDOP; // GPS DOP (data degree of precision)
|
||||||
uint16_t GPSDifferential; // Differential correction applied to the GPS receiver (may not exist)
|
uint16_t GPSDifferential; // Differential correction applied to the GPS receiver (may not exist)
|
||||||
// 0: measurement without differential correction
|
// 0: measurement without differential correction
|
||||||
@@ -288,6 +293,7 @@ public:
|
|||||||
bool hasAltitude() const; // Return true if (alt) is available
|
bool hasAltitude() const; // Return true if (alt) is available
|
||||||
bool hasRelativeAltitude()const;// Return true if (rel_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 hasOrientation() const; // Return true if (roll,yaw,pitch) is available
|
||||||
|
bool hasSpeed() const; // Return true if (speedX,speedY,speedZ) is available
|
||||||
} GeoLocation;
|
} GeoLocation;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
5
main.cpp
5
main.cpp
@@ -132,6 +132,11 @@ int main(int argc, const char** argv)
|
|||||||
std::cout << "GeoLocation.PitchDegree " << imageEXIF.GeoLocation.PitchDegree << "\n";
|
std::cout << "GeoLocation.PitchDegree " << imageEXIF.GeoLocation.PitchDegree << "\n";
|
||||||
std::cout << "GeoLocation.YawDegree " << imageEXIF.GeoLocation.YawDegree << "\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.GPSDOP " << imageEXIF.GeoLocation.GPSDOP << "\n";
|
||||||
std::cout << "GeoLocation.GPSDifferential " << imageEXIF.GeoLocation.GPSDifferential << "\n";
|
std::cout << "GeoLocation.GPSDifferential " << imageEXIF.GeoLocation.GPSDifferential << "\n";
|
||||||
if (!imageEXIF.GeoLocation.GPSMapDatum.empty())
|
if (!imageEXIF.GeoLocation.GPSMapDatum.empty())
|
||||||
|
|||||||
Reference in New Issue
Block a user