def get_video_start_time_blackvue(video_file): fd = open(video_file, 'rb') fd.seek(0, io.SEEK_END) eof = fd.tell() fd.seek(0) while fd.tell() < eof: box = Box.parse_stream(fd) if box.type.decode('utf-8') == "moov": fd.seek(box.offset + 8, 0) size = struct.unpack('>I', fd.read(4))[0] typ = fd.read(4) fd.seek(4, os.SEEK_CUR) creation_time = struct.unpack('>I', fd.read(4))[0] modification_time = struct.unpack('>I', fd.read(4))[0] time_scale = struct.unpack('>I', fd.read(4))[0] duration = struct.unpack('>I', fd.read(4))[0] # from documentation # in seconds since midnight, January 1, 1904 video_start_time_epoch = creation_time * 1000 - duration epoch_start = datetime.datetime(year=1904, month=1, day=1) video_start_time = epoch_start + \ datetime.timedelta(milliseconds=video_start_time_epoch) return video_start_time
def ismt_to_ttml(ismt_data): fd = io.BytesIO(ismt_data) while True: x = Box.parse_stream(fd) if x.type == b'mdat': return x.data
def get_video_start_time_blackvue(video_file): with open(video_file, 'rb') as fd: fd.seek(0, io.SEEK_END) eof = fd.tell() fd.seek(0) while fd.tell() < eof: box = Box.parse_stream(fd) if box.type.decode('utf-8') == "moov": fd.seek(box.offset + 8, 0) size = struct.unpack('>I', fd.read(4))[0] typ = fd.read(4) fd.seek(4, os.SEEK_CUR) creation_time = struct.unpack('>I', fd.read(4))[0] modification_time = struct.unpack('>I', fd.read(4))[0] time_scale = struct.unpack('>I', fd.read(4))[0] duration = struct.unpack('>I', fd.read(4))[0] # from documentation # in seconds since midnight, January 1, 1904 video_start_time_epoch = creation_time * 1000 - duration epoch_start = datetime.datetime(year=1904, month=1, day=1) video_start_time = epoch_start + \ datetime.timedelta(milliseconds=video_start_time_epoch) return video_start_time
def decrypt(key, inp, out): """ decrypt() @param key: AES-128 CENC key in bytes @param inp: Open input file @param out: Open output file """ with BufferedReader(inp) as reader: senc_boxes = deque() trun_boxes = deque() while reader.peek(1): box = Box.parse_stream(reader) fix_headers(box) for stsd_box in BoxUtil.find(box, b'stsz'): sample_size = stsd_box.sample_size if box.type == b'moof': senc_boxes.extend(BoxUtil.find(box, b'senc')) trun_boxes.extend(BoxUtil.find(box, b'trun')) elif box.type == b'mdat': senc_box = senc_boxes.popleft() trun_box = trun_boxes.popleft() clear_box = b'' with BytesIO(box.data) as box_bytes: for sample, sample_info in zip( senc_box.sample_encryption_info, trun_box.sample_info): counter = Counter.new(64, prefix=sample.iv, initial_value=0) cipher = AES.new(key, AES.MODE_CTR, counter=counter) if sample_size: cipher_bytes = box_bytes.read(sample_size) clear_box += cipher.decrypt(cipher_bytes) elif not sample.subsample_encryption_info: cipher_bytes = box_bytes.read( sample_info.sample_size) clear_box += cipher.decrypt(cipher_bytes) else: for subsample in sample.subsample_encryption_info: clear_box += box_bytes.read( subsample.clear_bytes) cipher_bytes = box_bytes.read( subsample.cipher_bytes) clear_box += cipher.decrypt(cipher_bytes) box.data = clear_box out.write(Box.build(box)) return
def dump(): parser = argparse.ArgumentParser(description='Dump all the boxes from an MP4 file') parser.add_argument("input_file", type=argparse.FileType("rb"), metavar="FILE", help="Path to the MP4 file to open") args = parser.parse_args() fd = args.input_file fd.seek(0, io.SEEK_END) eof = fd.tell() fd.seek(0) while fd.tell() < eof: box = Box.parse_stream(fd) print(box)
def find_camera_model(videos_folder): from mapillary_tools.uploader import get_video_file_list file_list = get_video_file_list(videos_folder) fd = open(file_list[0], "rb") fd.seek(0, io.SEEK_END) eof = fd.tell() fd.seek(0) while fd.tell() < eof: box = Box.parse_stream(fd) if box.type.decode("utf-8") == "free": # or 'ftyp': return box.data[29:39]
def find_camera_model(videos_folder) -> bytes: from mapillary_tools.uploader import get_video_file_list file_list = get_video_file_list(videos_folder) if not file_list: raise RuntimeError(f"No video found in {videos_folder}") fd = open(file_list[0], "rb") fd.seek(0, io.SEEK_END) eof = fd.tell() fd.seek(0) while fd.tell() < eof: box = Box.parse_stream(fd) if box.type.decode("utf-8") == "free": # or 'ftyp': return box.data[29:39] raise RuntimeError(f"camera model not found in {file_list[0]}")
def test_parse_video_samples(self): infile = open('3.cmfv', 'rb') moov_box = [] moof_box = [] for i in range(5): t = Box.parse_stream(infile) if (t["type"] == b"moov"): moov_box = t if (t["type"] == b"moof"): moof_box = t res = BoxUtil.find_samples_fragmented(moov_box, moof_box, 1) self.assertEqual(res[0]["decode_time"], 12288) self.assertEqual(res[1]["decode_time"], 12800) self.assertEqual(res[2]["decode_time"], 13312) self.assertEqual(res[0]["offset_mdat"], 8) self.assertEqual(res[1]["offset_mdat"], 2223) self.assertEqual(res[2]["offset_mdat"], 2400)
def find_camera_model(videos_folder): from mapillary_tools.uploader import get_video_file_list file_list = get_video_file_list(videos_folder) fd = open(file_list[0], 'rb') fd.seek(0, io.SEEK_END) eof = fd.tell() fd.seek(0) while fd.tell() < eof: try: box = Box.parse_stream(fd) except RangeError: print('error parsing blackvue GPS information, exiting') sys.exit(1) except ConstError: print('error parsing blackvue GPS information, exiting') sys.exit(1) if box.type.decode('utf-8') == 'free':# or 'ftyp': return box.data[29:39]
def find_camera_model(videos_folder): from mapillary_tools.uploader import get_video_file_list file_list = get_video_file_list(videos_folder) fd = open(file_list[0], 'rb') fd.seek(0, io.SEEK_END) eof = fd.tell() fd.seek(0) while fd.tell() < eof: try: box = Box.parse_stream(fd) except RangeError: print('error parsing blackvue GPS information, exiting') sys.exit(1) except ConstError: print('error parsing blackvue GPS information, exiting') sys.exit(1) if box.type.decode('utf-8') == 'free': # or 'ftyp': return box.data[29:39]
def get_points_from_bv(path, use_nmea_stream_timestamp=False): points = [] fd = open(path, 'rb') fd.seek(0, io.SEEK_END) eof = fd.tell() fd.seek(0) date = None first_gps_date = None first_gps_time = None found_first_gps_date = False found_first_gps_time = False while fd.tell() < eof: try: box = Box.parse_stream(fd) except RangeError: print('error parsing blackvue GPS information, exiting') sys.exit(1) except ConstError: print('error parsing blackvue GPS information, exiting') sys.exit(1) if box.type.decode('utf-8') == 'free': length = len(box.data) offset = 0 while offset < length: newb = Box.parse(box.data[offset:]) if newb.type.decode('utf-8') == 'gps': lines = newb.data # Parse GPS trace for l in lines.splitlines(): m = l.lstrip('[]0123456789') # this utc millisecond timestamp seems to be the camera's # todo: unused? # match = re.search('\[([0-9]+)\]', l) # if match: # utcdate = match.group(1) #By default, use camera timestamp. Only use GPS Timestamp if camera was not set up correctly and date/time is wrong if use_nmea_stream_timestamp == False: if "$GPGGA" in m: match = re.search('\[([0-9]+)\]', l) if match: epoch_in_local_time = match.group(1) camera_date = datetime.datetime.utcfromtimestamp( int(epoch_in_local_time) / 1000.0) data = pynmea2.parse(m) if (data.is_valid): if found_first_gps_time == False: first_gps_time = data.timestamp found_first_gps_time = True lat, lon, alt = data.latitude, data.longitude, data.altitude points.append((camera_date, lat, lon, alt)) if use_nmea_stream_timestamp == True or found_first_gps_date == False: if "GPRMC" in m: try: data = pynmea2.parse(m) if data.is_valid: date = data.datetime.date() if found_first_gps_date == False: first_gps_date = date except pynmea2.ChecksumError as e: # There are often Checksum errors in the GPS stream, better not to show errors to user pass except Exception as e: print( "Warning: Error in parsing gps trace to extract date information, nmea parsing failed" ) if use_nmea_stream_timestamp == True: if "$GPGGA" in m: try: data = pynmea2.parse(m) if (data.is_valid): lat, lon, alt = data.latitude, data.longitude, data.altitude if not date: timestamp = data.timestamp else: timestamp = datetime.datetime.combine( date, data.timestamp) points.append( (timestamp, lat, lon, alt)) except Exception as e: print( "Error in parsing gps trace to extract time and gps information, nmea parsing failed due to {}" .format(e)) #If there are no points after parsing just return empty vector if points == []: return [] #After parsing all points, fix timedate issues if use_nmea_stream_timestamp == False: # If we use the camera timestamp, we need to get the timezone offset, since Mapillary backend expects UTC timestamps first_gps_timestamp = datetime.datetime.combine( first_gps_date, first_gps_time) delta_t = points[0][0] - first_gps_timestamp if delta_t.days > 0: hours_diff_to_utc = round(delta_t.total_seconds() / 3600) else: hours_diff_to_utc = round( delta_t.total_seconds() / 3600) * -1 utc_points = [] for idx, point in enumerate(points): delay_compensation = datetime.timedelta( seconds=-1.8 ) #Compensate for solution age when location gets timestamped by camera clock. Value is empirical from various cameras/recordings new_timestamp = points[idx][0] + datetime.timedelta( hours=hours_diff_to_utc) + delay_compensation lat = points[idx][1] lon = points[idx][2] alt = points[idx][3] utc_points.append((new_timestamp, lat, lon, alt)) points = utc_points points.sort() else: #add date to points that don't have it yet, because GPRMC message came later utc_points = [] for idx, point in enumerate(points): if type(points[idx][0]) != type( datetime.datetime.today()): timestamp = datetime.datetime.combine( first_gps_date, points[idx][0]) else: timestamp = points[idx][0] lat = points[idx][1] lon = points[idx][2] alt = points[idx][3] utc_points.append((timestamp, lat, lon, alt)) points = utc_points points.sort() offset += newb.end break return points
def get_points_from_bv(path,use_nmea_stream_timestamp=False): points = [] with open(path, 'rb') as fd: fd.seek(0, io.SEEK_END) eof = fd.tell() fd.seek(0) date = None first_gps_date = None first_gps_time = None found_first_gps_date = False found_first_gps_time = False while fd.tell() < eof: try: box = Box.parse_stream(fd) except RangeError: print('error parsing blackvue GPS information, exiting') sys.exit(1) except ConstError: print('error parsing blackvue GPS information, exiting') sys.exit(1) if box.type.decode('utf-8') == 'free': length = len(box.data) offset = 0 while offset < length: newb = Box.parse(box.data[offset:]) if newb.type.decode('utf-8') == 'gps': lines = newb.data # Parse GPS trace for l in lines.splitlines(): m = l.lstrip('[]0123456789') # this utc millisecond timestamp seems to be the camera's # todo: unused? # match = re.search('\[([0-9]+)\]', l) # if match: # utcdate = match.group(1) #By default, use camera timestamp. Only use GPS Timestamp if camera was not set up correctly and date/time is wrong if use_nmea_stream_timestamp==False: if "$GPGGA" in m: match = re.search('\[([0-9]+)\]', l) if match: epoch_in_local_time = match.group(1) camera_date=datetime.datetime.utcfromtimestamp(int(epoch_in_local_time)/1000.0) data = pynmea2.parse(m) if(data.is_valid): if found_first_gps_time == False: first_gps_time = data.timestamp found_first_gps_time = True lat, lon, alt = data.latitude, data.longitude, data.altitude points.append((camera_date, lat, lon, alt)) if use_nmea_stream_timestamp==True or found_first_gps_date==False: if "GPRMC" in m: try: data = pynmea2.parse(m) if data.is_valid: date = data.datetime.date() if found_first_gps_date == False: first_gps_date=date except pynmea2.ChecksumError as e: # There are often Checksum errors in the GPS stream, better not to show errors to user pass except Exception as e: print( "Warning: Error in parsing gps trace to extract date information, nmea parsing failed") if use_nmea_stream_timestamp==True: if "$GPGGA" in m: try: data = pynmea2.parse(m) if(data.is_valid): lat, lon, alt = data.latitude, data.longitude, data.altitude if not date: timestamp = data.timestamp else: timestamp = datetime.datetime.combine( date, data.timestamp) points.append((timestamp, lat, lon, alt)) except Exception as e: print( "Error in parsing gps trace to extract time and gps information, nmea parsing failed due to {}".format(e)) #If there are no points after parsing just return empty vector if points == []: return [] #After parsing all points, fix timedate issues if use_nmea_stream_timestamp==False: # If we use the camera timestamp, we need to get the timezone offset, since Mapillary backend expects UTC timestamps first_gps_timestamp = datetime.datetime.combine(first_gps_date, first_gps_time) delta_t = points[0][0]-first_gps_timestamp if delta_t.days>0: hours_diff_to_utc = round(delta_t.total_seconds()/3600) else: hours_diff_to_utc = round(delta_t.total_seconds()/3600) * -1 utc_points=[] for idx, point in enumerate(points): delay_compensation = datetime.timedelta(seconds=-1.8) #Compensate for solution age when location gets timestamped by camera clock. Value is empirical from various cameras/recordings new_timestamp = points[idx][0]+datetime.timedelta(hours=hours_diff_to_utc)+delay_compensation lat = points[idx][1] lon = points[idx][2] alt = points[idx][3] utc_points.append((new_timestamp, lat, lon, alt)) points = utc_points points.sort() else: #add date to points that don't have it yet, because GPRMC message came later utc_points=[] for idx, point in enumerate(points): if type(points[idx][0]) != type(datetime.datetime.today()): timestamp = datetime.datetime.combine( first_gps_date, points[idx][0]) else: timestamp = points[idx][0] lat = points[idx][1] lon = points[idx][2] alt = points[idx][3] utc_points.append((timestamp, lat, lon, alt)) points = utc_points points.sort() offset += newb.end break return points
def get_points_from_bv(path): points = [] fd = open(path, 'rb') fd.seek(0, io.SEEK_END) eof = fd.tell() fd.seek(0) date = None while fd.tell() < eof: try: box = Box.parse_stream(fd) except RangeError: print('error parsing blackvue GPS information, exiting') sys.exit(1) except ConstError: print('error parsing blackvue GPS information, exiting') sys.exit(1) if box.type.decode('utf-8') == 'free': length = len(box.data) offset = 0 while offset < length: newb = Box.parse(box.data[offset:]) if newb.type.decode('utf-8') == 'gps': lines = newb.data for l in lines: if "GPRMC" in l: m = l.lstrip('[]0123456789') try: data = pynmea2.parse(m) date = data.datetime.date() except Exception as e: print( "Error in extracting the gps trace, nmea parsing failed due to {}" .format(e)) break # Parse GPS trace for l in lines.splitlines(): # this utc millisecond timestamp seems to be the camera's # todo: unused? # match = re.search('\[([0-9]+)\]', l) # if match: # utcdate = match.group(1) m = l.lstrip('[]0123456789') if "GPRMC" in m: try: data = pynmea2.parse(m) date = data.datetime.date() except Exception as e: print( "Error in parsing gps trace to extract date information, nmea parsing failed due to {}" .format(e)) if "$GPGGA" in m: try: if not date: print( "Error, could not extract date from the video gps trace, exiting..." ) sys.exit(1) data = pynmea2.parse(m) timestamp = datetime.datetime.combine( date, data.timestamp) lat, lon, alt = data.latitude, data.longitude, data.altitude points.append((timestamp, lat, lon, alt)) except Exception as e: print( "Error in parsing gps trace to extract time and gps information, nmea parsing failed due to {}" .format(e)) points.sort() offset += newb.end break return points
def dump(file, dump_embedded, dump_raw_blocks, extended_scan, verbose): """ Extract GPS and Acceleration data from BlackVue MP4 recordings. BlackVue extracts data embedded in the MP4 recordings of a BlackVue Dashcam. """ for filename in file: filebase = os.path.splitext(filename)[0] with open(filename, 'rb') as fd: fd.seek(0, io.SEEK_END) eof = fd.tell() fd.seek(0) while fd.tell() < eof: try: box = Box.parse_stream(fd) # print(box) content = dict(box.__getstate__()) ctype = content['type'].decode('utf8') if 'data' in content and ctype == 'free': offset = content['offset'] end = content['end'] data = content['data'] if verbose: print( "Found container of type '{}', data has length {}." .format(ctype, len(data))) if dump_embedded: with open( filename + "-{:012d}-{}.bin".format(offset, ctype), "wb") as ofd: ofd.write(data) idx = 0 while idx < len(data): block_len = int.from_bytes(data[idx:idx + 4], 'big') block_data = data[idx + 4:idx + block_len] if verbose: print("Found block with len {}".format( block_len)) if block_len == 0: break if dump_raw_blocks: with open( filebase + "-{:012d}-{}-{:08d}.bin".format( offset, ctype, idx), "wb") as ofd: ofd.write(block_data) if block_data[0:4] in emb_file_def: first, has_length, termination, ext = emb_file_def[ block_data[0:4]] # some data like thmb indicates the length: last = first + int.from_bytes( block_data[4:8], 'big') if has_length else block_len # other data like gps is zero terminated: last = block_data.find( termination ) if termination is not None else last if ext is not None: with open(filebase + ext, "wb") as ofd: ofd.write(block_data[first:last]) if ext == '.3gf': with open(filebase + ext + ".txt", "wt") as ofd: n = 0 while first < last: chunk = block_data[first:first + 10] time_ms = int.from_bytes( chunk[0:4], 'big') if time_ms == 0xffffffff: break acc_1u = int.from_bytes( chunk[4:6], 'big') acc_2u = int.from_bytes( chunk[6:8], 'big') acc_3u = int.from_bytes( chunk[8:10], 'big') acc_1s = int.from_bytes( chunk[4:6], 'big', signed=True) acc_2s = int.from_bytes( chunk[6:8], 'big', signed=True) acc_3s = int.from_bytes( chunk[8:10], 'big', signed=True) ofd.write( ("{:8d} " + "{:08x} {:04x} {:04x} {:04x} " + "{:6d} {:6d} {:6d} {:6d}\n" ).format( n, time_ms, acc_1u, acc_2u, acc_3u, time_ms, acc_1s, acc_2s, acc_3s)) first += 10 n += 1 idx += block_len if verbose: ("Got to idx {}.".format(idx)) if not extended_scan: break except construct.core.ConstError: break except Exception as e: print(e) raise
def detect_file_type(input_file): device = "X" make = "unknown" model = "unknown" if input_file.lower().endswith(".ts"): with open(input_file, "rb") as f: device = "A" input_packet = f.read(188) #First packet, try to autodetect if bytes("\xB0\x0D\x30\x34\xC3", encoding="raw_unicode_escape" ) in input_packet[4:20] or args.device_override == "V": device = "V" make = "Viofo" model = "A119 V3" if bytes("\x40\x1F\x4E\x54\x39", encoding="raw_unicode_escape" ) in input_packet[4:20] or args.device_override == "B": device = "B" make = "Blueskysea" model = "B4K" while device == "A": currentdata = {} input_packet = f.read(188) if not input_packet: break #Autodetect camera type if device == 'A' and input_packet.startswith( bytes("\x47\x03\x00", encoding="raw_unicode_escape")): bs = list(input_packet) active = chr(bs[156]) lathem = chr(bs[157]) lonhem = chr(bs[158]) if lathem in "NS" and lonhem in "EW": device = "B" make = "Blueskysea" model = "B4K" print("Autodetected as Blueskysea B4K") break if device == 'A' and input_packet.startswith( bytes("\x47\x43\x00", encoding="raw_unicode_escape")): bs = list(input_packet) active = chr(bs[34]) lathem = chr(bs[35]) lonhem = chr(bs[36]) if lathem in "NS" and lonhem in "EW": device = "V" print("Autodetected as Viofo A119 V3") make = "Viofo" model = "A119 V3" break if input_file.lower().endswith( ".mp4"): #Guess which MP4 method is used: Novatek, Subtitle, NMEA with open(input_file, "rb") as fx: if True: fx.seek(0, io.SEEK_END) eof = fx.tell() fx.seek(0) lines = [] while fx.tell() < eof: try: box = Box.parse_stream(fx) except: pass #print (box.type.decode("utf-8")) if box.type.decode("utf-8") == "free": length = len(box.data) offset = 0 while offset < length: inp = Box.parse(box.data[offset:]) #print (inp.type.decode("utf-8")) if inp.type.decode("utf-8") == "gps": #NMEA-based lines = inp.data for line in lines.splitlines(): m = str(line).lstrip("[]0123456789") if "$GPGGA" in m: device = "N" make = "NMEA-based video" model = "unknown" break offset += inp.end if box.type.decode( "utf-8") == "gps": #has Novatek-specific stuff fx.seek(0) largeelem = fx.read() startbytes = [ m.start() for m in re.finditer(b'freeGPS', largeelem) ] del largeelem if len(startbytes) > 0: make = "Novatek" model = "MP4" device = "T" break if box.type.decode("utf-8") == "moov": try: length = len(box.data) except: length = 0 offset = 0 while offset < length: inp = Box.parse(box.data[offset:]) #print (inp.type.decode("utf-8")) if inp.type.decode("utf-8") == "gps": #NMEA-based lines = inp.data print(len(inp.data)) for line in lines.splitlines(): m = str(line).lstrip("[]0123456789") if "$GPGGA" in m: device = "N" make = "NMEA-based video" model = "unknown" #break offset += inp.end else: pass if device == "X": fx.seek(0) largeelem = fx.read() startbytes = [ m.start() for m in re.finditer( b'\x00\x14\x50\x4E\x44\x4D\x00\x00\x00\x00', largeelem) ] del largeelem if len(startbytes) > 0: make = "Garmin" model = "unknown" device = "G" if device == "X": fx.seek(0) largeelem = fx.read() startbytes = [ m.start() for m in re.finditer(b'GPGGA', largeelem) ] del largeelem if len(startbytes) > 0: make = "NEXTBASE" model = "unknown" device = "NB" return device, make, model
def get_gps_data_nmea(input_file, device): packetno = 0 locdata = {} with open(input_file, "rb") as fx: if True: fx.seek(0, io.SEEK_END) eof = fx.tell() fx.seek(0) prevts = 0 lines = [] while fx.tell() < eof: try: box = Box.parse_stream(fx) except: pass if box.type.decode("utf-8") == "free": try: length = len(box.data) except: length = 0 offset = 0 while offset < length: inp = Box.parse(box.data[offset:]) #print (inp.type.decode("utf-8")) if inp.type.decode("utf-8") == "gps": #NMEA-based lines = inp.data for line in lines.splitlines(): m = str(line) if "$GPRMC" in m: currentdata = {} currentdata["ts"] = int(m[3:13]) #print (m) try: currentdata["lat"] = float( m.split(",")[3][0:2]) + float( m.split(",")[3][2:]) / 60 currentdata["latR"] = m.split(",")[4] if currentdata["latR"] == "S": currentdata[ "lat"] = -currentdata["lat"] currentdata["lon"] = float( m.split(",")[5][0:3]) + float( m.split(",")[5][3:]) / 60 currentdata["lonR"] = m.split(",")[6] if currentdata["lonR"] == "N": currentdata[ "lon"] = -currentdata["lon"] except: pass try: currentdata["bearing"] = float( m.split(",")[9]) currentdata["speed"] = float( m.split(",")[8]) * 1.6 / 3.6 except: currentdata["bearing"] = 0 currentdata["speed"] = 0 active = (m.split(",")[2]) nts = currentdata["ts"] currentdata["metric"] = 0 currentdata["prevdist"] = 0 try: currentdata["mx"], currentdata[ "my"] = lonlat_metric( currentdata["lon"], currentdata["lat"]) except: pass if active == "A" and nts > prevts: locdata[packetno] = currentdata prevts = nts packetno += 1 del currentdata offset += inp.end return locdata, packetno
def get_points_from_bv(path,use_nmea_stream_timestamp=False): points = [] fd = open(path, 'rb') fd.seek(0, io.SEEK_END) eof = fd.tell() fd.seek(0) date = None while fd.tell() < eof: try: box = Box.parse_stream(fd) except RangeError: print('error parsing blackvue GPS information, exiting') sys.exit(1) except ConstError: print('error parsing blackvue GPS information, exiting') sys.exit(1) if box.type.decode('utf-8') == 'free': length = len(box.data) offset = 0 while offset < length: newb = Box.parse(box.data[offset:]) if newb.type.decode('utf-8') == 'gps': lines = newb.data # Parse GPS trace for l in lines.splitlines(): # this utc millisecond timestamp seems to be the camera's # todo: unused? # match = re.search('\[([0-9]+)\]', l) # if match: # utcdate = match.group(1) #By default, use camera timestamp. Only use GPS Timestamp if camera was not set up correctly and date/time is wrong if use_nmea_stream_timestamp==False: m = l.lstrip('[]0123456789') if "$GPGGA" in m: match = re.search('\[([0-9]+)\]', l) if match: utcdate = match.group(1) date=datetime.datetime.utcfromtimestamp(int(utcdate)/1000.0) data = pynmea2.parse(m) if(data.is_valid): lat, lon, alt = data.latitude, data.longitude, data.altitude points.append((date, lat, lon, alt)) else: if "GPRMC" in m: try: data = pynmea2.parse(m) date = data.datetime.date() except Exception as e: print( "Error in parsing gps trace to extract date information, nmea parsing failed due to {}".format(e)) if "$GPGGA" in m: try: if not date: #discarding Lat/Lon messages if date has not been set yet. TODO: we could save the messages and add the date later continue data = pynmea2.parse(m) if(data.is_valid): timestamp = datetime.datetime.combine( date, data.timestamp) lat, lon, alt = data.latitude, data.longitude, data.altitude points.append((timestamp, lat, lon, alt)) except Exception as e: print( "Error in parsing gps trace to extract time and gps information, nmea parsing failed due to {}".format(e)) points.sort() offset += newb.end break return points
def read(self) -> Telemetry: tel = Telemetry() with open(self.source, 'rb') as fd: fd.seek(0, io.SEEK_END) eof = fd.tell() fd.seek(0) while fd.tell() < eof: try: box = Box.parse_stream(fd) except RangeError: print('error parsing blackvue GPS information, exiting') sys.exit(1) except ConstError: print('error parsing blackvue GPS information, exiting') sys.exit(1) if box.type.decode('utf-8') == 'free': length = len(box.data) offset = 0 while offset < length: newb = Box.parse(box.data[offset:]) if newb.type.decode('utf-8') == 'gps': lines = newb.data.decode('utf-8') # Parse GPS trace timestamp = None packet = None for l in lines.splitlines(): m = l.lstrip('[]0123456789') if not m: continue match = re.search('\[([0-9]+)\]', l) # If new timestamp found if match and match.group(1) != timestamp: if packet: tel.append(packet) packet = Packet() timestamp = match.group(1) packet[TimestampElement. name] = TimestampElement( float(timestamp) * 1e-3) #remove timestamp on tail if it exists try: m = m[:m.rindex('[')] except: pass try: m = m[:m.index("\x00")] except: pass try: nmea_data = pynmea2.parse(m) if nmea_data and nmea_data.sentence_type == 'GGA': packet[LatitudeElement. name] = LatitudeElement( nmea_data.latitude) packet[LongitudeElement. name] = LongitudeElement( nmea_data.longitude) if nmea_data.altitude: packet[AltitudeElement. name] = AltitudeElement( nmea_data.altitude) if nmea_data and nmea_data.sentence_type == 'VTG': packet[ SpeedElement.name] = SpeedElement( nmea_data.spd_over_grnd_kmph / 3.6) #convert to m/s except: self.logger.warn( "Couldn't parse nmea sentence. Skipping..." ) if packet: tel.append(packet) offset += newb.end break return tel