Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

command to extract specific GPMF values to an ndjson file #34

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions bin/gopro-data-extract.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import argparse
import json

from gopro_overlay.ffmpeg import load_gpmd_from
from gopro_overlay.gpmd import GoproMeta, interpret_item


class DataDumpVisitor:
def __init__(self, fourcc, converter):
self._fourcc = fourcc
self._converter = converter
self._counter = 0

def vic_DEVC(self, item, contents):
return self

def vic_STRM(self, item, contents):
return DataDumpStreamVisitor(
fourcc = self._fourcc,
visit=lambda fourcc, c: self._converter(self._counter, fourcc, c)
)

def v_end(self):
self._counter += 1
pass


class DataDumpStreamVisitor:
def __init__(self, fourcc, visit):
self._fourcc = fourcc
self._visit = visit
self._scale = None

def vi_SCAL(self, item):
self._scale = interpret_item(item)

def __getattr__(self, attr):
if attr in ['vi_' + self._fourcc, 'vi_GPSU']:
def vi(item):
data = interpret_item(item, self._scale)
self._visit(item.fourcc, data)
return data
return vi
else:
raise AttributeError(attr)

def v_end(self):
pass


class DumpAggregateConverter:
def __init__(self, file):
self.time = None
self.file = file
self.queue = []

def output(self, start, end, queue):
if not queue:
return

# assume uniform distribution of values between two timestamps
delta = (end - start) / len(queue)
for i, item in enumerate(queue):
t = start + delta*i
d = {'timestamp': t.isoformat()}

if hasattr(item, '_asdict'):
d |= item._asdict()
else:
d['value'] = item

json.dump(d, self.file)
self.file.write('\n')

def convert(self, counter, fourcc, data):
# Find values we are interested in, bracketed between GPSU time stamps.
if fourcc == 'GPSU':
if self.time:
start = self.time
end = data
self.output(start, end, self.queue)
self.time = data
self.queue = []
else:
if isinstance(data, list):
self.queue.extend(data)
else:
self.queue.append(data)


def dump(input_file, fourcc, output_file):
gpmd_from = load_gpmd_from(input_file)
meta = GoproMeta.parse(gpmd_from)

with open(output_file, 'wt', encoding='utf-8') as file:
converter = DumpAggregateConverter(file)
meta.accept(DataDumpVisitor(fourcc=fourcc, converter=converter.convert))


if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Extract GoPro metadata")
parser.add_argument("input", help="Input file")
parser.add_argument("output", help="Output NDJSON file")
parser.add_argument("--fourcc", "-f", action="store", default='ACCL', help='GPMD fourcc field to extract')

args = parser.parse_args()
dump(args.input, args.fourcc, args.output)