从行车记录仪 .MOV 文件将十六进制转换为纬度经度
Convert hex to latitude longitude from dashcam .MOV file
我有一个以 .MOV 格式保存视频的 OEM 行车记录仪。我想以编程方式从视频文件中提取嵌入式 gps 数据。在十六进制编辑器中打开 .mov 文件后,我发现带有 freeGPS
headers 的数据包,我可以确认我的 7 秒示例视频有 7 个数据包,所以我知道 gps 数据的来源.
我已经找到了日期和时间,但我无法将十六进制值转换为纬度经度。以下是使用 Registrator Viewer 提取时的十六进制值及其等效坐标。
273108AC1C7996404E,0D022B873EA3C74045 - 14.637967,121.041475
516B9A771C7996404E,0D022B873EA3C74045 - 14.637963,121.041475
B9FC87F41B7996404E,52499D803EA3C74045 - 14.637955,121.041472
B9FC87F41B7996404E,52499D803EA3C74045 - 14.637955,121.041472
B459F5B91A7996404E,C442AD693EA3C74045 - 14.637935,121.041460
1DEBE2361A7996404E,ACADD85F3EA3C74045 - 14.637927,121.041455
08CE19511A7996404E,4FD1915C3EA3C74045 - 14.637928,121.041453
粗体字节直接转换为@N 和@E,所以我认为它们不是转换的一部分。我已经尝试了以下答案,但我没有成功获得正确的坐标。
How to convert GPS Longitude and latitude from hex
How to convert my binary (hex) data to latitude and longitude?
我已经向行车记录仪提供商发送了一封电子邮件,要求他们提供协议文档,但看起来他们没有,因为当我要求他们提供自己的视频播放器时,他们发送了 Registrator Viewer。
我还会包含第一个 freeGPS
数据包,以防我看错地方。
00 00 80 00 66 72 65 65 47 50 53 20 98 00 00 00 78 2E 78 78 00 00 00 00 00 00 00 00 00 00 00 00 30 30 30 30 30 00 00 00 00 00 00 00 00 00 00 00 03 00 00 00 03 00 00 00 27 00 00 00 41 00 00 00 27 31 08 AC 1C 79 96 40 4E 00 00 00 00 00 00 00 0D 02 2B 87 3E A3 C7 40 45 00 00 00 00 00 00 00 8F C2 F5 28 5C 8F E2 3F 48 E1 7A 14 AE 07 68 40 11 00 00 00 06 00 00 00 14 00 00 00 76 00 00 00 88 00 00 00 DE 00 00 00 4D 00 00 00 49 00 00 00 4F 00 00 00 2D 00 00 00 2B 00 00 00 00 00 00 00
按顺序提取的粗体数据:freeGPS、时间、latitude@N?、longitude@E?、date
我可以确认时间和日期是正确的。速度应该是1km/h,但我也找不到。
在此先感谢那些可以提供帮助的人。
编辑:
这是测试视频的 link。 Test Video
不确定这有多大帮助,但如果您将十六进制字符串(包括末尾的 0x40)转换为小端 IEEE-754 双精度实数,那么您将获得大约 100 倍的 lat/lon。
在 C 中,我做了类似的事情
printf( "%f\n", *(double*)"\x27\x31\x08\xAC\x1C\x79\x96\x40" );
printf( "%f\n", *(double*)"\x0D\x02\x2B\x87\x3E\xA3\xC7\x40" );
出来了
1438.278000
12102.488500
更新感谢@TDG
如果 1438.278
被解释为 14 度 38.278 分钟,那么您将得到一个小数值 14.6379666666666667
。如果 12102.4885
被解释为 121 度和 2.4885 分钟,则十进制等效值是 121.041475
.
执行此操作的一些示例 C 代码
#include<stdio.h>
double convert( double input ) {
int i = input/100;
return ( input - i*100 ) / 60 + i;
}
int main(){
printf( "%f\n", convert( *(double*)"\x27\x31\x08\xAC\x1C\x79\x96\x40" ) );
printf( "%f\n", convert( *(double*)"\x0D\x02\x2B\x87\x3E\xA3\xC7\x40" ) );
}
找到 this GPS 数据格式的解释,对我有用。
public static ViofoGpsPoint Parse(uint offset, uint size, byte[] file)
{
byte[] data = new byte[size];
Array.Copy(file, offset, data, 0, size);
uint pos = 0;
uint size1 = Box.ReadUintBE(data, pos); pos += 4;
string type = Encoding.ASCII.GetString(data, (int)pos, 4); pos += 4;
string magic = Encoding.ASCII.GetString(data, (int)pos, 4); pos += 4;
if (size != size1 || type != "free" || magic != "GPS ")
return null;
ViofoGpsPoint gps = new ViofoGpsPoint();
//# checking for weird Azdome 0xAA XOR "encrypted" GPS data.
//This portion is a quick fix.
uint payload_size = 254;
if (data[pos] == 0x05)
{
if (size < 254)
payload_size = size;
byte[] payload = new byte[payload_size];
pos += 6; //???
for (int i = 0; i < payload_size; i++)
{
payload[i] = (byte)(file[pos + i] ^ 0xAA);
}
}
else if ((char)data[pos] == 'L')
{
const uint OFFSET_V2 = 48, OFFSET_V1 = 16;
pos = OFFSET_V2;
//# Datetime data
int hour = (int)Box.ReadUintLE(data, pos); pos += 4;
int minute = (int)Box.ReadUintLE(data, pos); pos += 4;
int second = (int)Box.ReadUintLE(data, pos); pos += 4;
int year = (int)Box.ReadUintLE(data, pos); pos += 4;
int month = (int)Box.ReadUintLE(data, pos); pos += 4;
int day = (int)Box.ReadUintLE(data, pos); pos += 4;
try { gps.Date = new DateTime(2000 + year, month, day, hour, minute, second); }
catch (Exception err) { Debug.WriteLine(err.ToString()); return null; }
//# Coordinate data
char active = (char)data[pos]; pos++;
gps.IsActive = (active == 'A');
gps.Latitude_hemisphere = (char)data[pos]; pos++;
gps.Longtitude_hemisphere = (char)data[pos]; pos++;
gps.Unknown = data[pos]; pos++;
float lat = Box.ReadFloatLE(data, pos); pos += 4;
gps.Latitude = FixCoordinate(lat, gps.Latitude_hemisphere);
float lon = Box.ReadFloatLE(data, pos); pos += 4;
gps.Longtitude = FixCoordinate(lon, gps.Longtitude_hemisphere);
gps.Speed = Box.ReadFloatLE(data, pos); pos += 4;
gps.Bearing = Box.ReadFloatLE(data, pos); pos += 4;
return gps;
}
return null;
}
/// <summary>
/// # Novatek stores coordinates in odd DDDmm.mmmm format
/// </summary>
/// <param name="coord"></param>
/// <param name="hemisphere"></param>
/// <returns></returns>
private static double FixCoordinate(double coord, char hemisphere)
{
double minutes = coord % 100.0;
double degrees = coord - minutes;
double coordinate = degrees / 100.0 + (minutes / 60.0);
if (hemisphere == 'S' || hemisphere == 'W')
return -1 * (coordinate);
else
return (coordinate);
}
我有一个以 .MOV 格式保存视频的 OEM 行车记录仪。我想以编程方式从视频文件中提取嵌入式 gps 数据。在十六进制编辑器中打开 .mov 文件后,我发现带有 freeGPS
headers 的数据包,我可以确认我的 7 秒示例视频有 7 个数据包,所以我知道 gps 数据的来源.
我已经找到了日期和时间,但我无法将十六进制值转换为纬度经度。以下是使用 Registrator Viewer 提取时的十六进制值及其等效坐标。
273108AC1C7996404E,0D022B873EA3C74045 - 14.637967,121.041475 516B9A771C7996404E,0D022B873EA3C74045 - 14.637963,121.041475 B9FC87F41B7996404E,52499D803EA3C74045 - 14.637955,121.041472 B9FC87F41B7996404E,52499D803EA3C74045 - 14.637955,121.041472 B459F5B91A7996404E,C442AD693EA3C74045 - 14.637935,121.041460 1DEBE2361A7996404E,ACADD85F3EA3C74045 - 14.637927,121.041455 08CE19511A7996404E,4FD1915C3EA3C74045 - 14.637928,121.041453
粗体字节直接转换为@N 和@E,所以我认为它们不是转换的一部分。我已经尝试了以下答案,但我没有成功获得正确的坐标。
How to convert GPS Longitude and latitude from hex
How to convert my binary (hex) data to latitude and longitude?
我已经向行车记录仪提供商发送了一封电子邮件,要求他们提供协议文档,但看起来他们没有,因为当我要求他们提供自己的视频播放器时,他们发送了 Registrator Viewer。
我还会包含第一个 freeGPS
数据包,以防我看错地方。
00 00 80 00 66 72 65 65 47 50 53 20 98 00 00 00 78 2E 78 78 00 00 00 00 00 00 00 00 00 00 00 00 30 30 30 30 30 00 00 00 00 00 00 00 00 00 00 00 03 00 00 00 03 00 00 00 27 00 00 00 41 00 00 00 27 31 08 AC 1C 79 96 40 4E 00 00 00 00 00 00 00 0D 02 2B 87 3E A3 C7 40 45 00 00 00 00 00 00 00 8F C2 F5 28 5C 8F E2 3F 48 E1 7A 14 AE 07 68 40 11 00 00 00 06 00 00 00 14 00 00 00 76 00 00 00 88 00 00 00 DE 00 00 00 4D 00 00 00 49 00 00 00 4F 00 00 00 2D 00 00 00 2B 00 00 00 00 00 00 00
按顺序提取的粗体数据:freeGPS、时间、latitude@N?、longitude@E?、date
我可以确认时间和日期是正确的。速度应该是1km/h,但我也找不到。
在此先感谢那些可以提供帮助的人。
编辑: 这是测试视频的 link。 Test Video
不确定这有多大帮助,但如果您将十六进制字符串(包括末尾的 0x40)转换为小端 IEEE-754 双精度实数,那么您将获得大约 100 倍的 lat/lon。
在 C 中,我做了类似的事情
printf( "%f\n", *(double*)"\x27\x31\x08\xAC\x1C\x79\x96\x40" );
printf( "%f\n", *(double*)"\x0D\x02\x2B\x87\x3E\xA3\xC7\x40" );
出来了
1438.278000
12102.488500
更新感谢@TDG
如果 1438.278
被解释为 14 度 38.278 分钟,那么您将得到一个小数值 14.6379666666666667
。如果 12102.4885
被解释为 121 度和 2.4885 分钟,则十进制等效值是 121.041475
.
执行此操作的一些示例 C 代码
#include<stdio.h>
double convert( double input ) {
int i = input/100;
return ( input - i*100 ) / 60 + i;
}
int main(){
printf( "%f\n", convert( *(double*)"\x27\x31\x08\xAC\x1C\x79\x96\x40" ) );
printf( "%f\n", convert( *(double*)"\x0D\x02\x2B\x87\x3E\xA3\xC7\x40" ) );
}
找到 this GPS 数据格式的解释,对我有用。
public static ViofoGpsPoint Parse(uint offset, uint size, byte[] file)
{
byte[] data = new byte[size];
Array.Copy(file, offset, data, 0, size);
uint pos = 0;
uint size1 = Box.ReadUintBE(data, pos); pos += 4;
string type = Encoding.ASCII.GetString(data, (int)pos, 4); pos += 4;
string magic = Encoding.ASCII.GetString(data, (int)pos, 4); pos += 4;
if (size != size1 || type != "free" || magic != "GPS ")
return null;
ViofoGpsPoint gps = new ViofoGpsPoint();
//# checking for weird Azdome 0xAA XOR "encrypted" GPS data.
//This portion is a quick fix.
uint payload_size = 254;
if (data[pos] == 0x05)
{
if (size < 254)
payload_size = size;
byte[] payload = new byte[payload_size];
pos += 6; //???
for (int i = 0; i < payload_size; i++)
{
payload[i] = (byte)(file[pos + i] ^ 0xAA);
}
}
else if ((char)data[pos] == 'L')
{
const uint OFFSET_V2 = 48, OFFSET_V1 = 16;
pos = OFFSET_V2;
//# Datetime data
int hour = (int)Box.ReadUintLE(data, pos); pos += 4;
int minute = (int)Box.ReadUintLE(data, pos); pos += 4;
int second = (int)Box.ReadUintLE(data, pos); pos += 4;
int year = (int)Box.ReadUintLE(data, pos); pos += 4;
int month = (int)Box.ReadUintLE(data, pos); pos += 4;
int day = (int)Box.ReadUintLE(data, pos); pos += 4;
try { gps.Date = new DateTime(2000 + year, month, day, hour, minute, second); }
catch (Exception err) { Debug.WriteLine(err.ToString()); return null; }
//# Coordinate data
char active = (char)data[pos]; pos++;
gps.IsActive = (active == 'A');
gps.Latitude_hemisphere = (char)data[pos]; pos++;
gps.Longtitude_hemisphere = (char)data[pos]; pos++;
gps.Unknown = data[pos]; pos++;
float lat = Box.ReadFloatLE(data, pos); pos += 4;
gps.Latitude = FixCoordinate(lat, gps.Latitude_hemisphere);
float lon = Box.ReadFloatLE(data, pos); pos += 4;
gps.Longtitude = FixCoordinate(lon, gps.Longtitude_hemisphere);
gps.Speed = Box.ReadFloatLE(data, pos); pos += 4;
gps.Bearing = Box.ReadFloatLE(data, pos); pos += 4;
return gps;
}
return null;
}
/// <summary>
/// # Novatek stores coordinates in odd DDDmm.mmmm format
/// </summary>
/// <param name="coord"></param>
/// <param name="hemisphere"></param>
/// <returns></returns>
private static double FixCoordinate(double coord, char hemisphere)
{
double minutes = coord % 100.0;
double degrees = coord - minutes;
double coordinate = degrees / 100.0 + (minutes / 60.0);
if (hemisphere == 'S' || hemisphere == 'W')
return -1 * (coordinate);
else
return (coordinate);
}