From 86a69d111f7a925645ca626e4600804f4125402c Mon Sep 17 00:00:00 2001
From: Sebastian Hahta <joseha@utu.fi>
Date: Fri, 25 Oct 2019 15:24:35 +0300
Subject: [PATCH] new format, buffered writer

---
 python/ftl/ftlstream.py | 97 +++++++++++++++++++++++++++++++++++++++--
 python/ftl/ftltypes.py  | 10 +++++
 2 files changed, 103 insertions(+), 4 deletions(-)

diff --git a/python/ftl/ftlstream.py b/python/ftl/ftlstream.py
index 45b0f8c31..a47a2cd2c 100644
--- a/python/ftl/ftlstream.py
+++ b/python/ftl/ftlstream.py
@@ -43,8 +43,8 @@ class FTLStreamWriter:
     def __init__(self, file):
         self._file = open(file, "wb")
         self._file.write(bytes(ord(c) for c in "FTLF"))
-        self._file.write(bytes([0]))
-
+        self._file.write(bytes([2]))
+        self._file.write(bytes([0]*64))
         self._packer = msgpack.Packer(strict_types=False, use_bin_type=True)
 
     def __del__(self):
@@ -65,8 +65,79 @@ class FTLStreamWriter:
     def add_frame(self, timestamp, src, channel, codec, data, encode=True):
         pass
 
-    def add_depth(self, timestamp, src, data):
-        pass
+class FTLStreamBufferedWriter(FTLStreamWriter):
+    def __init__(self, file, fps=25.0):
+        super(FTLStreamWriter, file)
+        self._ts = 0
+        self._frame_t = int(1.0/fps)
+        self._n_sources = 0
+        self._frames = []
+    
+    def add_source(self, count=1):
+        self._n_sources += count
+        return self._n_sources
+
+    def add_calibration(self, source):
+        if not 0 < source < self._n_sources:
+            raise ValueError("invalid source id")
+
+    def add_frame(self, source, channel, data, codec, definition=None, flags=0, encode=True):
+        if not 0 < source < self._n_sources:
+            raise ValueError("invalid source id")
+
+        if channel not in ftl.Channel:
+            raise ValueError("invalid channel")
+        
+        if codec not in ftl.codec_t:
+            raise ValueError("invalid codec")
+
+        if encode:
+            if definition is not None:
+                definition = ftl.get_definition(data.shape)
+
+            if definition is None:
+                raise ValueError("unsupported resolution")
+            
+            if definition != ftl.get_definition(data.shape):
+                # todo: could replace definition or scale
+                raise ValueError("definition does not match frame resolution")
+
+            if codec == ftl.codec_t.PNG:
+                if ftl.is_float_channel(channel):
+                    # scaling always same (???)
+                    data = data.astype(np.float) / 1000.0
+                
+                params = [cv.IMWRITE_PNG_COMPRESSION, 9]
+                retval, data = cv.imencode(".png", data, params)
+                
+                if not retval:
+                    raise Exception("encoding error (PNG)")
+            
+            elif codec == ftl.codec_t.JPG:
+                params = []
+                retval, data = cv.imencode(".jpg", data, params)
+
+                if not retval:
+                    raise Exception("encoding error (JPG)")
+            
+            else:
+                raise ValueError("unsupported codec")
+
+            data = data.tobytes()
+        
+        if definition is None:
+            raise ValueError("definition required")
+
+        if not isinstance(data, bytes):
+            raise ValueError("expected bytes")
+
+        ftl.Packet(int(codec), int(definition), 1, 0, int(flags), data)
+
+    def push_frames(self):
+        for frame in self._frames:
+            self.add_raw(sp, p)
+        
+        self._ts += self._frame_t
 
 class FTLStreamReader:
     ''' FTL file reader '''
@@ -86,9 +157,13 @@ class FTLStreamReader:
 
         try:
             magic = self._file.read(5)
+            version = int(magic[4])
             if magic[:4] != bytes(ord(c) for c in "FTLF"):
                 raise Exception("wrong magic")
             
+            if  == 2:
+
+
             self._unpacker = msgpack.Unpacker(self._file, raw=True, use_list=False)
             
         except Exception as ex:
@@ -159,6 +234,17 @@ class FTLStreamReader:
         self._frame = _ycrcb2rgb(img)
         self._frameset_new[k] = self._frame
 
+    def _decode_png(self, sp, p):
+        try:
+            cv
+        except NameError:
+            raise Exception("OpenCV required for PNG decoding")
+
+        self._frame = cv.imdecode(np.frombuffer(p.data, dtype=np.uint8),
+                                  cv.IMREAD_ANYDEPTH)
+        self._frame = self._frame.astype(np.float) / 1000.0
+        self._frameset_new[(sp.streamID, sp.channel)] = self._frame
+
     def _flush_decoders(self):
         for decoder in self._decoders.values():
             decoder.flush_data()
@@ -212,6 +298,9 @@ class FTLStreamReader:
         elif self._p.codec == ftl.codec_t.HEVC:
             self._decode_hevc(self._sp, self._p)
 
+        elif self._p.codec == ftl.codec_t.PNG:
+            self._decode_png(self._sp, self._p)
+
         else:
             raise Exception("unkowno codec %i" % self._p.codec)
 
diff --git a/python/ftl/ftltypes.py b/python/ftl/ftltypes.py
index 3481d248e..de85e1664 100644
--- a/python/ftl/ftltypes.py
+++ b/python/ftl/ftltypes.py
@@ -45,6 +45,16 @@ class Channel(IntEnum):
     Pose            = 66
     Data            = 67
 
+_float_channels = [
+    Channel.Depth,
+    Channel.Confidence,
+    Channel.Density,
+    Channel.Energy
+]
+
+def is_float_channel(channel):
+    return channel in _float_channels
+
 # components/codecs/include/ftl/codecs/bitrates.hpp
 class codec_t(IntEnum):
     JPG = 0
-- 
GitLab