5

I just got a Garmin Dash Cam 20 and recorded some videos with it, and also confirmed that Garmin's own player can show the GPS information on a map.

I can't seem to find any technical information on where the GPS information is stored (assuming within the AVI file at this point) in contrast to some other Garmin action cam I have that stores the GPS separately in a GPX file. I need to integrate with a system, so manually using Garmin's player to extract it is not an option.

Does anyone have some pointers on where the GPS information might be stored?

There is also audio on the video, so it do not look like its encoded in the audio stream.

  • There is an GPX export function in the software. www8.garmin.com/support/download_details.jsp?id=6681 – Mapperz Aug 5 '15 at 14:25
  • its not an option for us, we need to do this from code, so I am looking for examples or information on how this data is embedded into the AVI file so we can extract it with code ourself. I cant find anything on google – Poul K. Sørensen Aug 5 '15 at 16:19
3

The video files recorded with garmin dash cam 20 are RIFF AVI files . There is a GR20 chunk in the file which contains sequence of 36 byte length binary data. Each 36 byte is about a frame, in this order:

bytes |type    |description
------+--------+----------------------------
0-4   |int32   |Frame number
6-8   |int16   |Speed in Km/h
8-12  |int32   |Longitude (in custom format, see comments)
12-16 |int32   |Latitude (in custom format, see comments)
16-20 |int32   |Time (in unix time format)
20-24 |int32   |traveling direction (0-359)
24-28 |single  |G sensor axis 1
28-32 |single  |G sensor axis 2
32-36 |single  |G sensor axis 3
------+--------+----------------------------

Longitude and latitude in file are in int32 type and they are not real latitude and longitude, you should divide them with 11930464.3017314 floating number to get real lat/long in degrees. for example if you get in value of '612222120' from bytes 8-12, then you should numberically divide it by 11930464.3017314 which result is:

612222120/11930464.3017314 = 51.31586705

Which is longitude in degrees.

After first 36 bytes you should start again for second one and so on untill chunk ends. Chunk length is multiply of 36. I've got the same problem but thanks to jagabo I've got my answer in here (which lead me to here):

Example of parser for finding chunks (including GR02) in RIFF file pragmatically with C# is here

  • Thanks. I managed to get some of this done myself and based on some translated japaneese, i came to the conclusion that the lat/lng was stored such value/11930464 would give the lat/lng, so now i need to figure out what is correct, 11930464 or 11930464.3017314 – Poul K. Sørensen Aug 31 '15 at 8:55
  • i dont know which one is correct, but i think the difference is negligible as it is about 2.529e-8. based on my calculations if one is wrong and other is rights, then using wrong one get at most around 70cm error in locating position on the everywhere on the earth and the accuracy of gps itself is much cheaper than 0.7 m (i think its precision is less than 3m) – epsi1on Sep 2 '15 at 8:26
  • You are right. Just did the same calculations and conclussions – Poul K. Sørensen Sep 2 '15 at 15:07
2

I've recently bought Garmin Dash Cam 35, hoping that format will be similar. Well, it isn't.

First of all: files are MP4, not AVI. GPS data seems to be stored in 22 bytes of SEI message. I was able to extract it using mp4parser in scala:

import com.coremedia.iso.IsoFile
import com.googlecode.mp4parser.authoring.samples.DefaultMp4SampleList

/**
  * Created by matemaciek on 01/09/2016.
  */
def decode(track: String) {
  val GPS_TRACK_IDX = 3
  val iso = new IsoFile(track)
  val samples: DefaultMp4SampleList = new DefaultMp4SampleList(GPS_TRACK_IDX, iso)
  val csv = (0 until samples.size).map(samples.get).map(
    sample => (
      (0 until sample.getSize.toInt).map("%02X" format sample.asByteBuffer.get(_)).mkString,
      sample.asByteBuffer.getShort(10),
      sample.asByteBuffer.getInt(14),
      sample.asByteBuffer.getInt(18),
      sample.asByteBuffer.getInt(14) / 11930464.711111112,
      sample.asByteBuffer.getInt(18) / 11930464.711111112)
  ).map(_.productIterator.mkString(",")).mkString("\n")
  println(csv)
}

decode("E:\\DCIM\\103UNSVD\\GRMN0845.MP4")

I'm trying to reverse engineer what is where - Results so far:

bytes |type    |description
------+--------+----------------------------
0-9   |Unknown |Unknown (always 00 14 50 4E 44 4D 00 00 00 00)
10-11 |int16   |Speed in Km/h
12-13 |Unknown |Unknow (usually 01 00, in case of event 01 01 - some kind of flags?)
14-17 |int32   |Longitude
18-21 |int32   |Latitude
------+--------+----------------------------

Coordinates are in same format as in Dash Cam 20, I've adjusted dividing factor so when GPS signal is lost it returns exactly -180 (as Garmin's software do).

  • Thanks for sharing. nice to know, keep updating if you find new information. – Poul K. Sørensen Sep 1 '16 at 8:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.