Convert hex to latitude longitude from dashcam .MOV file

Viewed 1244

I have an OEM dashcam that saves videos in .MOV format. I want to extract the embedded gps data from the video files programmatically. Upon opening the .mov file in a hex editor I found data packets with freeGPS headers and I can confirm that for my 7 seconds sample video there are 7 packets so I know this where the gps data comes from.

I already found the date and time but I got stuck with converting the hex values to latitude longitude. Below are the hex values and their equivalent coordinates when extracted using 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

The bolded bytes directly translates to @N and @E so I think they are not part of the conversion. I already tried the below answers but I did not succeed in getting the correct coordinates.

How to convert GPS Longitude and latitude from hex

How to convert my binary (hex) data to latitude and longitude?

I already sent an email to the dashcam provider asking for their protocol documentation but it does not look like they have one since they sent Registrator Viewer when I asked for their own video player.

I will also include the first freeGPS packet in case I am looking at the wrong place.

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

Data in bold extracted in order : freeGPS, time, latitude@N?, longitude@E?, date

I can confirm that time and date are correct. The speed is supposed to be 1km/h but I can't also find that.

Thanks in advance for those who can help.

EDIT: Here is the link for the test video. Test Video

2 Answers

Found this explanation of GPS data format, worked for me.

        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);
    }
Related