Improving SSTV parser.

This commit is contained in:
Marat Fayzullin 2023-03-01 15:33:50 -05:00
parent 04804f8e96
commit 6ad3bee963
1 changed files with 69 additions and 74 deletions

View File

@ -135,89 +135,84 @@ class SstvParser(ThreadModule):
def process(self): def process(self):
try: try:
# Parse bitmap (BMP) file header starting with 'BM' # Parse bitmap file data (scanlines)
if len(self.data)>=54 and self.data[0]==ord(b'B') and self.data[1]==ord(b'M'): if self.width>0:
self.width = self.data[18] + (self.data[19]<<8) + (self.data[20]<<16) + (self.data[21]<<24) w = self.width * 3
self.height = self.data[22] + (self.data[23]<<8) + (self.data[24]<<16) + (self.data[25]<<24) if len(self.data)>=w:
# BMP height value is negative
self.height = 0x100000000 - self.height
# SSTV mode is passed via reserved area at offset 6
self.mode = self.data[6]
self.line = 0
# Find mode name and time
modeName = modeNames.get(self.mode) if self.mode in modeNames else "Unknown Mode %d" % self.mode
timeStamp = datetime.utcnow().strftime("%H:%M:%S")
fileName = Storage().makeFileName("SSTV-{0}", self.frequency)
logger.debug("Receiving %dx%d %s frame as '%s'." % (self.width, self.height, modeName, fileName))
# If running as a service...
if self.service:
# Create a new image file and write BMP header
self.newFile(fileName)
self.writeFile(self.data[0:54])
# Remove parsed data
del self.data[0:54]
# Return parsed values
return {
"mode": "SSTV",
"width": self.width,
"height": self.height,
"sstvMode": modeName,
"timestamp": timeStamp,
"filename": fileName,
"frequency": self.frequency
}
# Parse debug messages enclosed in ' [...]'
elif len(self.data)>=2 and self.data[0]==ord(b' ') and self.data[1]==ord(b'['):
# Wait until we find the closing bracket
w = self.data.find(b']')
if w>=0:
# Extract message contents
msg = self.data[2:w].decode()
# Log message
logger.debug("SSTV: %s" % msg)
# Compose result # Compose result
out = { out = {
"mode": "SSTV", "mode": "SSTV",
"message": msg "pixels": base64.b64encode(self.data[0:w]).decode(),
"line": self.line,
"width": self.width,
"height": self.height
} }
# Advance scanline
self.line = self.line + 1
# If running as a service...
if self.service:
# Write a scanline into open image file
self.writeFile(self.data[0:w])
# Close once the last scanline reached
if self.line>=self.height:
self.closeFile()
# If we reached the end of frame, finish scan
if self.line>=self.height:
self.width = 0
self.height = 0
self.line = 0
self.mode = 0
# Remove parsed data # Remove parsed data
del self.data[0:w+1] del self.data[0:w]
# Return parsed values # Return parsed values
return out return out
# Parse bitmap file data (scanlines) # Parse bitmap (BMP) file header starting with 'BM'
elif self.width>0 and len(self.data)>=self.width*3: elif len(self.data)>=54:
w = self.width * 3 # Search for the leading 'BM'
# Compose result w = self.data.find(b'BM')
out = { # If not found...
"mode": "SSTV", if w<0:
"pixels": base64.b64encode(self.data[0:w]).decode(), # Skip all but last character (may have 'B')
"line": self.line, del self.data[0:len(self.data)-1]
"width": self.width, else:
"height": self.height # Skip everything until 'BM'
} del self.data[0:w]
# Advance scanline # If got the entire header...
self.line = self.line + 1 if len(self.data)>=54:
# If running as a service... self.width = self.data[18] + (self.data[19]<<8) + (self.data[20]<<16) + (self.data[21]<<24)
if self.service: self.height = self.data[22] + (self.data[23]<<8) + (self.data[24]<<16) + (self.data[25]<<24)
# Write a scanline into open image file # BMP height value is negative
self.writeFile(self.data[0:w]) self.height = 0x100000000 - self.height
# Close once the last scanline reached # SSTV mode is passed via reserved area at offset 6
if self.line>=self.height: self.mode = self.data[6]
self.closeFile() self.line = 0
# If we reached the end of frame, finish scan # Find mode name and time
if self.line>=self.height: modeName = modeNames.get(self.mode) if self.mode in modeNames else "Unknown Mode %d" % self.mode
self.width = 0 timeStamp = datetime.utcnow().strftime("%H:%M:%S")
self.height = 0 fileName = Storage().makeFileName("SSTV-{0}", self.frequency)
self.line = 0 logger.debug("Receiving %dx%d %s frame as '%s'." % (self.width, self.height, modeName, fileName))
self.mode = 0 # If running as a service...
# Remove parsed data if self.service:
del self.data[0:w] # Create a new image file and write BMP header
# Return parsed values self.newFile(fileName)
return out self.writeFile(self.data[0:54])
# Remove parsed data
del self.data[0:54]
# Return parsed values
return {
"mode": "SSTV",
"width": self.width,
"height": self.height,
"sstvMode": modeName,
"timestamp": timeStamp,
"filename": fileName,
"frequency": self.frequency
}
# Could not parse input data (yet) # Could not parse input data (yet)
if len(self.data)>1:
logger.debug("Got %d bytes of data..." % len(self.data))
return None return None
except Exception: except Exception: