Skip to content

Instantly share code, notes, and snippets.

@mittinatten
Last active October 17, 2019 12:20
Show Gist options
  • Save mittinatten/846f33d91ef4830dece6a79ad6f06fe6 to your computer and use it in GitHub Desktop.
Save mittinatten/846f33d91ef4830dece6a79ad6f06fe6 to your computer and use it in GitHub Desktop.
Node-script to extract GPS coordinates from QuickTime video
// Quite crude, but worked for the one example file I had
// QuickTime docs https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/QTFFPreface/qtffPreface.html
const fs = require('fs');
if (!process.argv[2]) {
console.error('Please specify a file name');
process.exit(1);
}
const fileName = process.argv[2];
if (!fileName.match(/\.mov$/i)) {
console.error('Only works with .mov files');
process.exit(1);
}
const file = fs.readFileSync(fileName);
function getAtom(file, start) {
if (start + 8 >= file.length || start < 0) {
return null;
}
const size = file.readInt32BE(start);
return {
size,
type: file.toString('ascii', start + 4, start + 8),
start,
};
}
function readKeys(file, atom) {
const keys = [];
let offset = atom.start + 8 + 4; // skip version and flags
const count = file.readInt32BE(offset);
offset += 4;
for (let i = 0; i < count; ++i) {
const keySize = file.readInt32BE(offset);
const namespace = file.toString('ascii', offset + 4, offset + 8);
const value = file.toString('ascii', offset + 8, offset + keySize);
offset += keySize;
keys.push(value);
}
return keys;
}
function parseCoords(file, atom) {
if (atom) {
const value = file
.toString('ascii', atom.start + 8, atom.start + atom.size)
.replace(/\/$/, '');
const coord = value.split('+').slice(1);
return { lat: coord[0], long: coord[1], alt: coord[2] };
}
return null;
}
function getCoordsFromILST(file, atom, index) {
let offset = atom.start + 8 + 4;
const count = file.readInt32BE(offset);
const items = getAtoms(file, offset + 4);
return parseCoords(file, items[index]);
}
const coord = [];
function getAtoms(file, start) {
let atom;
let offset = start;
const atoms = [];
let keys;
do {
atom = getAtom(file, offset);
if (atom) {
if (atom.type.match(/(moov|meta|trak)/)) {
atom.children = getAtoms(file, offset + 8);
}
if (atom.type === 'keys') {
keys = readKeys(file, atom);
}
if (atom.type === 'ilst' && keys) {
coord.push(
getCoordsFromILST(
file,
atom,
keys.indexOf('com.apple.quicktime.location.ISO6709')
)
);
}
offset = offset + atom.size;
atoms.push(atom);
}
} while (atom && atom.size);
return atoms;
}
getAtoms(file, 0);
console.log(coord);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment