From a48b5c69abab420ab3b7107ebd24afd926bfee14 Mon Sep 17 00:00:00 2001
From: Sebastian <sebastian@baldr.asgard>
Date: Sun, 20 Oct 2019 20:17:13 +0300
Subject: [PATCH] python module

---
 python/ftl/__init__.py       |   1 +
 python/ftl/ftlstream.py      | 125 +++++++++++++++++++++++++++++++++++
 python/{ => ftl}/libde265.py |   0
 python/ftlstream.py          |  31 ---------
 4 files changed, 126 insertions(+), 31 deletions(-)
 create mode 100644 python/ftl/__init__.py
 create mode 100644 python/ftl/ftlstream.py
 rename python/{ => ftl}/libde265.py (100%)
 delete mode 100644 python/ftlstream.py

diff --git a/python/ftl/__init__.py b/python/ftl/__init__.py
new file mode 100644
index 000000000..963e374bd
--- /dev/null
+++ b/python/ftl/__init__.py
@@ -0,0 +1 @@
+from . ftlstream import FTLStream
\ No newline at end of file
diff --git a/python/ftl/ftlstream.py b/python/ftl/ftlstream.py
new file mode 100644
index 000000000..9869d50d5
--- /dev/null
+++ b/python/ftl/ftlstream.py
@@ -0,0 +1,125 @@
+import msgpack
+from collections import namedtuple
+from . libde265 import Decoder
+
+_packet = namedtuple("Packet", ["codec", "definition", "block_total", "block_number", "flags", "data"])
+_stream_packet = namedtuple("StreamPacket", ["timestamp", "streamID", "chanel_count", "channel"])
+
+_definition_t = {
+    0 : (),
+    1 : (),
+    2 : (1080, 1920),
+    3 : (720, 1280),
+    4 : (),
+    5 : (),
+    6 : (),
+    7 : (),
+    8 : ()
+}
+
+class FTLStream:
+    def __init__(self, file):
+        self._file = open(file, "br")
+        self._decoders = {}
+        self._frames = {}
+        
+        try:
+            magic = self._file.read(5)
+            if magic[:4] != bytearray(ord(c) for c in "FTLF"):
+                raise Exception("wrong magic")
+            
+            self._unpacker = msgpack.Unpacker(self._file, raw=True, use_list=False)
+            
+        except Exception as ex:
+            self._file.close()
+            raise ex
+            
+        self._packets_read = 0
+    
+    def __del__(self):
+        self._file.close()
+    
+    def _read_next(self):
+        v1, v2 = self._unpacker.unpack()
+        return _stream_packet._make(v1), _packet._make(v2)
+    
+    def _update_calib(self, sp, p):
+        ''' Update calibration '''
+        pass
+    
+    def _update_pose(self, sp, p):
+        ''' Update pose '''
+        pass
+    
+    def _decode_frame_hevc(self, sp, p):
+        ''' Decode HEVC frame '''
+        
+        k = (sp.streamID, sp.channel)
+        
+        if k not in self._decoders:
+            self._decoders[k] = Decoder(_definition_t[p.definition])
+        
+        decoder = self._decoders[k]
+        decoder.push_data(p.data)
+        decoder.decode()
+        img = decoder.get_next_picture()
+        
+        if img is not None:
+            self._frames[k] = img
+    
+    def read(self):
+        '''
+        Reads data for until the next timestamp. Returns False if there is no
+        more data to read, otherwise returns True.
+        '''
+        if self._packets_read == 0:
+            self._sp, self._p = self._read_next()
+            self._packets_read += 1
+            
+        self._frames = {}
+        
+        ts = self._sp.timestamp
+        ex = None
+        
+        while self._sp.timestamp == ts:
+            try:
+                if self._p.codec == 100: # JSON
+                    NotImplementedError("json decoding not implemented")
+
+                elif self._p.codec == 101: # CALIBRATION
+                    self._update_calib(self._sp, self._p)
+
+                elif self._p.codec == 102: # POSE
+                    self._update_pose(self._sp, self._p)
+
+                elif self._p.codec == 3: # HEVC
+                    self._decode_frame_hevc(self._sp, self._p)
+
+                else:
+                    raise ValueError("unkowno codec %i" % p.codec)
+            
+            except Exception as e:
+                ex = e
+            
+            try:
+                self._sp, self._p = self._read_next()
+                self._packets_read += 1
+            
+            except msgpack.OutOfData:
+                return False
+            
+        if ex is not None:
+            raise ex
+            
+        return True
+    
+    def get_frames(self):
+        ''' Returns all frames '''
+        return self._frames
+    
+    def get_frame(self, source, channel):
+        k = (source, channel)
+        if k in self._frames:
+            return self._frames[k]
+        else:
+            return None
diff --git a/python/libde265.py b/python/ftl/libde265.py
similarity index 100%
rename from python/libde265.py
rename to python/ftl/libde265.py
diff --git a/python/ftlstream.py b/python/ftlstream.py
deleted file mode 100644
index ec0155133..000000000
--- a/python/ftlstream.py
+++ /dev/null
@@ -1,31 +0,0 @@
-import msgpack
-from collections import namedtuple
-
-_packet = namedtuple("Packet", ["codec", "definition", "block_total", "block_number", "flags", "data"])
-_stream_packet = namedtuple("StreamPacket", ["timestamp", "streamID", "chanel_count", "channel"])
-
-class FTLStream:
-    def __init__(self, file):
-        self._file = open(file, "br")
-        
-        try:
-            magic = self._file.read(5)
-            if magic[:4] != bytearray(ord(c) for c in "FTLF"):
-                raise Exception("wrong magic")
-            
-            self._unpacker = msgpack.Unpacker(self._file, raw=True, use_list=False)
-            
-        except Exception as ex:
-            self._file.close()
-            raise ex
-    
-    def __del__(self):
-        self._file.close()
-    
-    def read(self):
-        # TODO: Different methods for reading different types?
-        return self._read_next()
-    
-    def _read_next(self):
-        v1, v2 = self._unpacker.unpack()
-        return _stream_packet._make(v1), _packet._make(v2)
\ No newline at end of file
-- 
GitLab