GPS Extraction Advice

The place for "I can't figure out how to..." questions.
Post Reply
diplonics2
User
Posts: 5
Joined: Wed May 10, 2017 3:14 pm
Are you a spambot?: no
Location: Maynooth, Ireland

GPS Extraction Advice

Post by diplonics2 » Wed May 10, 2017 3:27 pm

I have .MOV video with embedded GPS data and need to extract it.
getID3 has identified that there is a moov gps atom but I'm not sure if you could recommend the next steps to decode the data element.
In module.audio-video.quicktime.php I can trap the gps atom as a new switch case in the QuicktimeParseAtom() method.
While I've tried all manner of conversion options in the getid3_lib class to convert the gps atom data I still can't get human understandable results so am not sure if you can recommend an approach that might help here.
If it helps understand the gps data format then the python code below might assist as it can decode some of the GPS elements but I don't fully understand the struct unpack elements such that I can do an effective conversion to PHP.
Any advice/help would be much appreciated.
I can also provide the sample video if it helps.

Thanks in advance,

Paul

Code from: https://sergei.nz/files/nvtk_mp42gpx.py

Code: Select all

def get_gps_atom_info(eight_bytes):
    atom_pos,atom_size=struct.unpack('>II',eight_bytes)
    return int(atom_pos),int(atom_size)

def get_gps_atom(gps_atom_info,f):
    atom_pos,atom_size=gps_atom_info
    f.seek(atom_pos)
    data=f.read(atom_size)
    expected_type='free'
    expected_magic='GPS '
    atom_size1,atom_type,magic=struct.unpack_from('>I4s4s',data)
    atom_type=atom_type.decode()
    magic=magic.decode()
    #sanity:
    if atom_size != atom_size1 or atom_type != expected_type or magic != expected_magic:
        print("Error! skipping atom at %x (expected size:%d, actual size:%d, expected type:%s, actual type:%s, expected magic:%s, actual maigc:%s)!" % (int(atom_pos),atom_size,atom_size1,expected_type,atom_type,expected_magic,magic))
        return

    hour,mins,secs,activeReception,q,w,north,g,west,test1,test2,test3,test4= struct.unpack_from('<36xIIIcxxcdc7xdcxxxxfIII',data, 12)
    print(hour,mins,secs,activeReception,q,w,north,g,west,test1,test2,test3,test4)
    #active=active.decode()
    #latitude_b=latitude_b.decode()
    #longitude_b=longitude_b.decode()
    #print(latitude_b)
    #print(longitude_b)
    '''time=fix_time(hour,minute,second,year,month,day)
    latitude=fix_coordinates(latitude_b,latitude)
    longitude=fix_coordinates(longitude_b,longitude)
    speed=fix_speed(speed)

    print(latitude)
    #it seems that A indicate reception
    if active != 'A':
        print("Skipping: lost GPS satelite reception. Time: %s." % time)
        return

    return (latitude,longitude,time,speed)'''

def process_file(in_file):
    global gps_data
    print("Processing file '%s'..." % in_file)
    with open(in_file, "rb") as f:
        offset = 0
        while True:
            atom_pos = f.tell()
            atom_size, atom_type = get_atom_info(f.read(8))
            if atom_size == 0:
                break

            if atom_type == 'moov':
                print("Found moov atom...")
                sub_offset = offset+8

                while sub_offset < (offset + atom_size):
                    sub_atom_pos = f.tell()
                    sub_atom_size, sub_atom_type = get_atom_info(f.read(8))

                    print(sub_atom_type)
                    if str(sub_atom_type) == 'gps ':
                        print("Found gps chunk descriptor atom...")
                        gps_offset = 16 + sub_offset # +16 = skip headers
                        f.seek(gps_offset,0)
                        count = 0
                        while gps_offset < ( sub_offset + sub_atom_size):
                            print("Count is now  " + str(count))
                            count+=1
                            gps_data.append(get_gps_atom(get_gps_atom_info(f.read(8)),f))
                            gps_offset += 8
                            f.seek(gps_offset,0)

                    sub_offset += sub_atom_size
                    f.seek(sub_offset,0)

            offset += atom_size
            f.seek(offset,0)

James Heinrich
getID3() v1 developer
Posts: 1432
Joined: Fri May 04, 2001 4:00 pm
Are you a spambot?: no
Location: Northern Ontario, Canada
Contact:

Re: GPS Extraction Advice

Post by James Heinrich » Wed May 10, 2017 3:32 pm

Are you able to provide a small sample file so I can see what you're seeing?

diplonics2
User
Posts: 5
Joined: Wed May 10, 2017 3:14 pm
Are you a spambot?: no
Location: Maynooth, Ireland

Re: GPS Extraction Advice

Post by diplonics2 » Wed May 10, 2017 3:37 pm

Yep, approx 150MB in size.
Generating download link now and shall send on in a moment.

Thanks,

Paul

diplonics2
User
Posts: 5
Joined: Wed May 10, 2017 3:14 pm
Are you a spambot?: no
Location: Maynooth, Ireland

Re: GPS Extraction Advice

Post by diplonics2 » Wed May 10, 2017 3:51 pm

https://filesender.heanet.ie/1.7/?vid=5 ... 006e0df8d7

Just to note this is coming from my University email which I tried to register my first account with but never got the activation email for, (probably caught in spam!!)
Also attached is a txt file with the JSON output from the python code of the GPS that is in this file.

Paul
Attachments
GPS Data.txt
(34.06 KiB) Downloaded 63 times

James Heinrich
getID3() v1 developer
Posts: 1432
Joined: Fri May 04, 2001 4:00 pm
Are you a spambot?: no
Location: Northern Ontario, Canada
Contact:

Re: GPS Extraction Advice

Post by James Heinrich » Wed May 10, 2017 3:59 pm

I have grabbed your sample file, thanks. I'll take a look and get back to you.

diplonics2
User
Posts: 5
Joined: Wed May 10, 2017 3:14 pm
Are you a spambot?: no
Location: Maynooth, Ireland

Re: GPS Extraction Advice

Post by diplonics2 » Wed May 10, 2017 4:16 pm

Appreciate this, I'll delete the download URL now.
Heading for train now so going offline till tomorrow.

James Heinrich
getID3() v1 developer
Posts: 1432
Joined: Fri May 04, 2001 4:00 pm
Are you a spambot?: no
Location: Northern Ontario, Canada
Contact:

Re: GPS Extraction Advice

Post by James Heinrich » Wed May 10, 2017 6:28 pm

In my research I also came across the sample code you provided, which seems to have been written by Sergei Franco and is available at https://sergei.nz/files/nvtk_mp42gpx.py
Just giving credit where due

James Heinrich
getID3() v1 developer
Posts: 1432
Joined: Fri May 04, 2001 4:00 pm
Are you a spambot?: no
Location: Northern Ontario, Canada
Contact:

Re: GPS Extraction Advice

Post by James Heinrich » Wed May 10, 2017 9:08 pm

I have looked at your file, and made some additions to getID3 at:
https://github.com/JamesHeinrich/getID3 ... e9f4bdd3be

You can now look at the track list in [quicktime][gps_track] which should contain the most interesting bits.

diplonics2
User
Posts: 5
Joined: Wed May 10, 2017 3:14 pm
Are you a spambot?: no
Location: Maynooth, Ireland

Re: GPS Extraction Advice

Post by diplonics2 » Thu May 11, 2017 9:18 am

Okay, that looks brilliant so thanks a lot.
Will pull the code and try it now.
Also, didn't mean for you to do all the work as trying to work through and understand how GPS can be encoded/decoded in Video streams.
This gives me a significant head-start though so will read through your code thoroughly.

Also, as you point out, credit due to Sergei Franco for the original python.
Just for clarity the source for the Python I provided was from another developer who'd changed it to slightly to handle the sample video discussed here.
At the line "hour,mins,secs,activeReception,......." the byte unpack sequence and the byte chunks have been changed but I only discovered the original connection myself yesterday and should have provided crediting as noted.

Thanks again.

Post Reply