From 9cc478603d31ff4dd8afa02ae4d97c3391fa7667 Mon Sep 17 00:00:00 2001 From: MyungJoo Ham Date: Tue, 24 Jul 2018 08:34:59 +0900 Subject: [PATCH] [Tensorsave] Findtype file format definition. To allow save tensors as files with its medata in tact, we define "other/tensorsave" type for gstreamer. It can be used to share tensors with non-gstreamer programs, or used to create testcases for nnstreamer plugins. To be completed, we need to implement load and save plugins in gst/tensor_saveload directory. Fixes #29 Signed-off-by: MyungJoo Ham --- common/tensor_common.c | 20 ++++++++++++++++++++ gst/tensor_converter/README.md | 34 ++++++++++++++++++++++++++++++++++ gst/tensor_saveload/README.md | 2 ++ include/tensor_common.h | 13 +++++++++++++ 4 files changed, 69 insertions(+) create mode 100644 gst/tensor_saveload/README.md diff --git a/common/tensor_common.c b/common/tensor_common.c index 7e9b7a2..23041ec 100644 --- a/common/tensor_common.c +++ b/common/tensor_common.c @@ -245,3 +245,23 @@ get_tensor_from_padcap (const GstCaps * caps, tensor_dim dim, } return ret; } + +/** + * @brief A callback for typefind, trying to find whether a file is other/tensors or not. + * For the concrete definition of headers, please look at the wiki page of nnstreamer: + * https://github.com/nnsuite/nnstreamer/wiki/Design-External-Save-Format-for-other-tensor-and-other-tensors-Stream-for-TypeFind + */ +void +gst_tensors_typefind_function (GstTypeFind * tf, gpointer pdata) +{ + const guint8 *data = gst_type_find_peek (tf, 0, 40); /* The first 40 bytes are header-0 in v.1 protocol */ + const char formatstr[] = "TENSORST"; + const unsigned int *supported_version = (const unsigned int *) (&data[8]); + const unsigned int *num_tensors = (const unsigned int *) (&data[12]); + if (data && + memcmp (data, formatstr, 8) == 0 && + *supported_version == 1 && *num_tensors <= 16 && *num_tensors >= 1) { + gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, + gst_caps_new_simple ("other/tensorsave", NULL, NULL)); + } +} diff --git a/gst/tensor_converter/README.md b/gst/tensor_converter/README.md index cee5164..57a4c76 100644 --- a/gst/tensor_converter/README.md +++ b/gst/tensor_converter/README.md @@ -25,3 +25,37 @@ From higher priority - framerate; fraction - data: (binary data, can be treated as an C array of [dim4][dim3][dim2][dim1]) + +# other/tensors File Data Format, Version 1.0 Draft + +``` +Header-0: The first 20 bytes, global header +============================================================================================================= +| 8 bytes | 4 bytes | 4 bytes | 4 bytes | +| The type header | Protocol Version | Number of tensors per frame | Frame size in bytes | +| "TENSORST" | (uint32) 1 | (uint32) 1~16 (N) | (uint32) 1 ~ MAXUINT (S) | +| | | (v.1 supports up to 16) | Counting data only (no meta) | +============================================================================================================= +| 20 bytes. RESERVED in v1. | +============================================================================================================= +| Header-1: Following Header-1, Description of Tensor-1 of each frame (24 bytes) | +| 4 bytes | 4 bytes | 4 bytes | 4 bytes | 4 bytes | 4 bytes | +| Element Type (enum) | RANK (uint32) | Dim-1 | Dime-2 | Dim-3 | Dim-4 | +| "tensor_type" in tensor_typedef.h | v.1 supports 1 to 4. | | | | | +==================================================================================================== +| ... | +==================================================================================================== +| Header-N | +==================================================================================================== +Data of frame-1, tensor-1 starts at the offset of (40 + 24 x N). +Data of frame-1, tensor-i starts at the offset of (40 + 24 x N + Sum(x=1..i-1)(tensor_element_size[tensor-type of Tx] x dim1-of-Tx x dim2-of-Tx x dim3-of-Tx x dim4-of-Tx)). +... +Data of frame-F, tensor-1 starts at the offset of (40 + 24 x N + S x (F - 1)) +... +Assert (S = Sum(x=1..N)(tensor_element_size[tensor-type of Tx] x dim1-of-Tx x dim2-of-Tx x dim3-of-Tx x dim4-of-Tx)) + +Add a custom footer +``` + +Note that once the stream is loaded in GStreamer, tensor\_\* elements uses the data parts only without the headers. +The header exists only when the tensor stream is stored as a file. diff --git a/gst/tensor_saveload/README.md b/gst/tensor_saveload/README.md new file mode 100644 index 0000000..705e9cc --- /dev/null +++ b/gst/tensor_saveload/README.md @@ -0,0 +1,2 @@ +- tensor\_load: other/tensorsave to other/tensors or other/tensor +- tensor\_save: other/tensors or other/tensor to other/tensorsave diff --git a/include/tensor_common.h b/include/tensor_common.h index 95e43f3..df61133 100644 --- a/include/tensor_common.h +++ b/include/tensor_common.h @@ -157,6 +157,19 @@ get_tensor_from_padcap(const GstCaps * caps, tensor_dim dim, tensor_type *type, */ #define err_print(...) dlog_print(DLOG_ERROR, "nnstreamer", __VA_ARGS__) +/** + * @brief A callback for typefind, trying to find whether a file is other/tensors or not. + * For the concrete definition of headers, please look at the wiki page of nnstreamer: + * https://github.com/nnsuite/nnstreamer/wiki/Design-External-Save-Format-for-other-tensor-and-other-tensors-Stream-for-TypeFind + */ +extern void gst_tensors_typefind_function (GstTypeFind *tf, gpointer pdata); + +#define GST_TENSOR_TYPEFIND_REGISTER(plugin) do { \ + gst_type_find_register (plugin, "other/tensorsave", \ + GST_RANK_PRIMARY, gst_tensors_typefind_function, "tnsr", \ + gst_caps_new_simple ("other/tensorsave", NULL, NULL), NULL, NULL)); \ + } while (0) + G_END_DECLS #endif /* __GST_TENSOR_COMMON_H__ */ -- 2.7.4