From 8ee5ff42ccf8c6e499800db75a14db48d89d2382 Mon Sep 17 00:00:00 2001 From: gichan-jang Date: Tue, 9 Jun 2020 14:18:52 +0900 Subject: [PATCH] [Converter] Add tensor converter sub-plugin protobuf Add tensor converter subplugin protobuf Add protobuf unittest Signed-off-by: gichan-jang --- debian/control | 4 +- ext/nnstreamer/include/nnstreamer.proto | 2 +- ext/nnstreamer/tensor_converter/meson.build | 19 +++ .../tensor_converter/tensor_converter_protobuf.cc | 164 +++++++++++++++++++++ ext/nnstreamer/tensor_decoder/meson.build | 3 + .../tensor_decoder/tensordec-protobuf.cc | 14 +- packaging/nnstreamer.spec | 9 +- tests/nnstreamer_protobuf/runTest.sh | 112 ++++++++++++++ 8 files changed, 318 insertions(+), 9 deletions(-) create mode 100644 ext/nnstreamer/tensor_converter/tensor_converter_protobuf.cc create mode 100755 tests/nnstreamer_protobuf/runTest.sh diff --git a/debian/control b/debian/control index db29497..33ecd0b 100644 --- a/debian/control +++ b/debian/control @@ -9,8 +9,8 @@ Build-Depends: gcc-9 | gcc-8 | gcc-7 | gcc-6 | gcc-5 (>=5.4), libgtest-dev, ssat, libpng-dev, libopencv-dev, liborc-0.4-dev, python, python-numpy, python3, python3-dev, python3-numpy, tensorflow-lite-dev, pytorch, libedgetpu1-std (>=12), libedgetpu-dev (>=12), - libflatbuffers-dev, flatbuffers-compiler, - tensorflow-dev [amd64], python2.7-dev, libprotobuf-dev [amd64 arm64 armhf] + libflatbuffers-dev, flatbuffers-compiler, protobuf-compiler17, + tensorflow-dev [amd64], python2.7-dev, libprotobuf-dev [amd64 arm64 armhf], Standards-Version: 3.9.6 Homepage: https://github.com/nnstreamer/nnstreamer diff --git a/ext/nnstreamer/include/nnstreamer.proto b/ext/nnstreamer/include/nnstreamer.proto index 034e5a9..710c521 100644 --- a/ext/nnstreamer/include/nnstreamer.proto +++ b/ext/nnstreamer/include/nnstreamer.proto @@ -1,6 +1,6 @@ syntax = "proto3"; -package NNStreamer; +package nnstreamer.protobuf; message Tensor { string name = 1; diff --git a/ext/nnstreamer/tensor_converter/meson.build b/ext/nnstreamer/tensor_converter/meson.build index 96802a9..e887176 100644 --- a/ext/nnstreamer/tensor_converter/meson.build +++ b/ext/nnstreamer/tensor_converter/meson.build @@ -17,3 +17,22 @@ if flatbuf_support_is_available install_dir: converter_subplugin_install_dir ) endif + +# protocol buffer +if protobuf_support_is_available + converter_sub_protobuf_sources = [ + 'tensor_converter_protobuf.cc' + ] + + nnstreamer_converter_protobuf_sources = [pb_gen_src] + foreach s : converter_sub_protobuf_sources + nnstreamer_converter_protobuf_sources += join_paths(meson.current_source_dir(), s) + endforeach + + shared_library('nnstreamer_converter_protobuf', + nnstreamer_converter_protobuf_sources, + dependencies: [nnstreamer_dep, glib_dep, gst_dep, protobuf_dep], + install: true, + install_dir: converter_subplugin_install_dir + ) +endif diff --git a/ext/nnstreamer/tensor_converter/tensor_converter_protobuf.cc b/ext/nnstreamer/tensor_converter/tensor_converter_protobuf.cc new file mode 100644 index 0000000..079bfac --- /dev/null +++ b/ext/nnstreamer/tensor_converter/tensor_converter_protobuf.cc @@ -0,0 +1,164 @@ +/* SPDX-License-Identifier: LGPL-2.1-only */ +/** + * GStreamer / NNStreamer tensor_converter subplugin, "protobuf" + * Copyright (C) 2020 Gichan Jang + */ + /** + * @file tensor_converter_protobuf.cc + * @date 2 June 2020 + * @brief NNStreamer tensor-converter subplugin, "protobuf", + * which converts protobuf byte stream to tensors. + * @see https://github.com/nnsuite/nnstreamer + * @author Gichan Jang + * @bug No known bugs except for NYI items + * + */ + + /** + * Install protobuf + * We assume that you use Ubuntu linux distribution. + * You may simply download binary packages from PPA + * + * $ sudo apt-add-repository ppa:nnstreamer + * $ sudo apt update + * $ sudo apt install libprotobuf-dev libprotobuf-lite17 libprotobuf17 protobuf-compiler17 + */ + +#include +#include +#include +#include +#include +#include +#include +#include "nnstreamer_plugin_api_converter.h" +#include +#include "nnstreamer.pb.h" /* Generated by `protoc` */ + +namespace nnstreamer { +namespace protobuf { + + void init_pbc (void) __attribute__ ((constructor)); + void fini_pbc (void) __attribute__ ((destructor)); + +/** @brief tensor converter plugin's NNStreamerExternalConverter callback */ +static GstCaps *pbc_query_caps (const GstTensorsConfig * config) +{ + return gst_caps_from_string (GST_PROTOBUF_TENSOR_CAP_DEFAULT); +} + +/** @brief tensor converter plugin's NNStreamerExternalConverter callback */ +static gboolean + pbc_get_out_config (const GstCaps * in_cap, GstTensorsConfig * config) +{ + GstStructure *structure; + + g_return_val_if_fail (config != NULL, FALSE); + gst_tensors_config_init (config); + g_return_val_if_fail (in_cap != NULL, FALSE); + + structure = gst_caps_get_structure (in_cap, 0); + g_return_val_if_fail (structure != NULL, FALSE); + + /* All tensor info should be updated later in chain function. */ + config->info.info[0].type = _NNS_UINT8; + config->info.num_tensors = 1; + if (gst_tensor_parse_dimension ("1:1:1:1", + config->info.info[0].dimension) == 0) { + ml_loge ("Failed to set initial dimension for subplugin"); + return FALSE; + } + + if (gst_structure_has_field (structure, "framerate")) + { + gst_structure_get_fraction (structure, "framerate", &config->rate_n, + &config->rate_d); + } else { + /* cannot get the framerate */ + config->rate_n = 0; + config->rate_d = 1; + } + return TRUE; +} + +/** @brief tensor converter plugin's NNStreamerExternalConverter callback */ + static GstBuffer *pbc_convert (GstBuffer * in_buf, gsize * frame_size, + guint * frames_in, GstTensorsConfig * config) + { + Tensors tensors; + Tensors::frame_rate * fr = NULL; + GstMemory *in_mem, *out_mem; + GstMapInfo in_info; + GstBuffer *out_buf; + guint mem_size; + gpointer mem_data; + + in_mem = gst_buffer_peek_memory (in_buf, 0); + g_assert (gst_memory_map (in_mem, &in_info, GST_MAP_READ)); + + tensors.ParseFromArray (in_info.data, in_info.size); + + config->info.num_tensors = tensors.num_tensor (); + fr = tensors.mutable_fr (); + config->rate_n = fr->rate_n (); + config->rate_d = fr->rate_d (); + + out_buf = gst_buffer_new (); + + for (guint i = 0; i < config->info.num_tensors; i++) { + const Tensor *tensor = &tensors.tensor (i); + config->info.info[i].name = g_strdup (tensor->name ().c_str ()); + config->info.info[i].type = (tensor_type) tensor->type (); + for (guint j = 0; j < NNS_TENSOR_RANK_LIMIT; j++) { + config->info.info[i].dimension[j] = tensor->dimension (j); + } + *frames_in = 1; + *frame_size = mem_size = tensor->data ().length (); + + mem_data = g_memdup (tensor->data ().c_str (), mem_size); + + out_mem = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY, + mem_data, mem_size, 0, mem_size, NULL, NULL); + + gst_buffer_append_memory (out_buf, out_mem); + } + + /** copy timestamps */ + gst_buffer_copy_into (out_buf, in_buf, + (GstBufferCopyFlags) GST_BUFFER_COPY_METADATA, 0, -1); + gst_memory_unmap (in_mem, &in_info); + + return out_buf; + } + + static gchar converter_subplugin_protobuf[] = + "libnnstreamer_converter_protobuf"; + +/** @brief protobuf tensor converter sub-plugin NNStreamerExternalConverter instance */ + static NNStreamerExternalConverter protobuf = { + .name = converter_subplugin_protobuf, + .convert = pbc_convert, + .get_out_config = pbc_get_out_config, + .query_caps = pbc_query_caps + }; + +/** @brief Initialize this object for tensor converter sub-plugin */ + void init_pbc (void) + { + /** + * Verify that the version of the library we linked is + * compatibile with the headers. + */ + GOOGLE_PROTOBUF_VERIFY_VERSION; + registerExternalConverter (&protobuf); + } + +/** @brief Destruct this object for tensor converter sub-plugin */ + void fini_pbc (void) + { + unregisterExternalConverter (protobuf.name); + google::protobuf::ShutdownProtobufLibrary (); + } + +}; /* Namespace protobuf */ +}; /* Namespace nnstreamer */ diff --git a/ext/nnstreamer/tensor_decoder/meson.build b/ext/nnstreamer/tensor_decoder/meson.build index c87b1de..00a6cb8 100644 --- a/ext/nnstreamer/tensor_decoder/meson.build +++ b/ext/nnstreamer/tensor_decoder/meson.build @@ -135,6 +135,7 @@ if protobuf_support_is_available install: true, install_dir: decoder_subplugin_install_dir ) +<<<<<<< c5239c0bfc9a1af65cecc494f1ffc1daa121d6fd endif # flatbuffer @@ -154,4 +155,6 @@ if flatbuf_support_is_available install: true, install_dir: decoder_subplugin_install_dir, ) +======= +>>>>>>> [Converter] Add tensor converter sub-plugin protobuf endif diff --git a/ext/nnstreamer/tensor_decoder/tensordec-protobuf.cc b/ext/nnstreamer/tensor_decoder/tensordec-protobuf.cc index dfbfd52..4f7d2aa 100644 --- a/ext/nnstreamer/tensor_decoder/tensordec-protobuf.cc +++ b/ext/nnstreamer/tensor_decoder/tensordec-protobuf.cc @@ -23,6 +23,9 @@ #include "nnstreamer.pb.h" /* Generated by `protoc` */ +namespace nnstreamer { +namespace protobuf { + void init_pb (void) __attribute__ ((constructor)); void fini_pb (void) __attribute__ ((destructor)); @@ -78,8 +81,8 @@ pb_decode (void **pdata, const GstTensorsConfig * config, GstMemory *out_mem; size_t size, outbuf_size; - NNStreamer::Tensors tensors; - NNStreamer::Tensors::frame_rate *fr = NULL; + Tensors tensors; + Tensors::frame_rate *fr = NULL; const unsigned int num_tensors = config->info.num_tensors; g_assert (num_tensors > 0); @@ -95,7 +98,7 @@ pb_decode (void **pdata, const GstTensorsConfig * config, fr->set_rate_d (config->rate_d); for (unsigned int i = 0; i < num_tensors; ++i) { - NNStreamer::Tensor *tensor = tensors.add_tensor (); + Tensor *tensor = tensors.add_tensor (); gchar *name = NULL; name = config->info.info[i].name; @@ -105,7 +108,7 @@ pb_decode (void **pdata, const GstTensorsConfig * config, tensor->set_name (name); } - tensor->set_type ((NNStreamer::Tensor::Tensor_type) + tensor->set_type ((Tensor::Tensor_type) config->info.info[i].type); for (int j = 0; j < NNS_TENSOR_RANK_LIMIT; ++j) { @@ -174,3 +177,6 @@ fini_pb (void) { nnstreamer_decoder_exit (protobuf.modename); } + +}; /* Namespace protobuf */ +}; /* Namespace nnstreamer */ diff --git a/packaging/nnstreamer.spec b/packaging/nnstreamer.spec index c71b4a0..23050e6 100644 --- a/packaging/nnstreamer.spec +++ b/packaging/nnstreamer.spec @@ -2,11 +2,12 @@ %define gstpostfix gstreamer-1.0 %define gstlibdir %{_libdir}/%{gstpostfix} %define nnstexampledir /usr/lib/nnstreamer/bin -%define tensorflow_support 0 +%define tensorflow_support 0 %define tensorflow_lite_support 1 %define armnn_support 0 %define vivante_support 0 %define flatbuf_support 1 +%define protobuf_support 1 %if 0%{tizen_version_major} >= 5 %define python_support 1 @@ -107,9 +108,12 @@ BuildRequires: tensorflow-lite-devel BuildRequires: opencv-devel # For './testAll.sh' time limit. BuildRequires: procps +# for protobuf +%if 0%{?protobuf_support} +BuildRequires: protobuf-devel >= 3.4.0 +%endif # for tensorflow %if 0%{?tensorflow_support} -BuildRequires: protobuf-devel >= 3.4.0 BuildRequires: tensorflow BuildRequires: tensorflow-devel %endif @@ -564,6 +568,7 @@ cp -r result %{buildroot}%{_datadir}/nnstreamer/unittest/ %{_prefix}/lib/nnstreamer/decoders/libnnstreamer_decoder_*.so %{_prefix}/lib/nnstreamer/converters/libnnstreamer_converter_*.so %{_prefix}/lib/nnstreamer/filters/libnnstreamer_filter_cpp.so +%{_prefix}/lib/nnstreamer/converters/libnnstreamer_converter_*.so %{gstlibdir}/libnnstreamer.so %{_libdir}/libnnstreamer.so %{_sysconfdir}/nnstreamer.ini diff --git a/tests/nnstreamer_protobuf/runTest.sh b/tests/nnstreamer_protobuf/runTest.sh new file mode 100755 index 0000000..0b48856 --- /dev/null +++ b/tests/nnstreamer_protobuf/runTest.sh @@ -0,0 +1,112 @@ +#!/usr/bin/env bash +## +## SPDX-License-Identifier: LGPL-2.1-only +## +## @file runTest.sh +## @author Gichan Jang +## @date June 08 2020 +## @brief SSAT Test Cases for protobuf subplugin of tensor converter and decoder +## @details After decoding the tensor into protobuf, convert it to tensor again to check if it matches the original +## +if [[ "$SSATAPILOADED" != "1" ]]; then + SILENT=0 + INDEPENDENT=1 + search="ssat-api.sh" + source $search + printf "${Blue}Independent Mode${NC} +" +fi + +# This is compatible with SSAT (https://github.com/myungjoo/SSAT) +testInit $1 + +if [ "$SKIPGEN" == "YES" ]; then + echo "Test Case Generation Skipped" + sopath=$2 +else + echo "Test Case Generation Started" + python ../nnstreamer_converter/generateGoldenTestResult.py + python ../nnstreamer_merge/generateTest.py + sopath=$1 +fi +convertBMP2PNG + +PATH_TO_PLUGIN="../../build" + +gst-launch-1.0 -m -v --gst-plugin-path=${PATH_TO_PLUGIN} videotestsrc num-buffers=1 ! video/x-raw,format=RGB,width=280,height=40,framerate=0/1 ! tee name=t ! queue ! videoconvert ! video/x-raw, format=BGRx ! tensor_converter silent=TRUE ! filesink location="test.bgrx.log" sync=true t. ! queue ! filesink location="test.rgb.log" sync=true + +gstTest "--gst-plugin-path=${PATH_TO_PLUGIN} videotestsrc num-buffers=1 ! video/x-raw,format=RGB,width=280,height=40,framerate=0/1 ! tee name=t ! queue ! videoconvert ! video/x-raw, format=BGRx ! tensor_converter silent=TRUE ! tensor_decoder mode=protobuf ! other/protobuf-tensor ! tensor_converter ! filesink location=\"test.bgrx.log\" sync=true t. ! queue ! filesink location=\"test.rgb.log\" sync=true" 1R 0 0 $PERFORMANCE + +gstTest "--gst-plugin-path=${PATH_TO_PLUGIN} videotestsrc num-buffers=1 ! video/x-raw,format=GRAY8,width=280,height=40,framerate=0/1 ! queue ! tensor_converter silent=TRUE ! tensor_decoder mode=protobuf ! other/protobuf-tensor ! tensor_converter ! filesink location=\"test.gray8.log\" sync=true" 1G 0 0 $PERFORMANCE + +callCompareTest testcase01.bgrx.golden test.bgrx.log 1-1 "BGRX Golden Test" 1 0 +callCompareTest testcase01.rgb.golden test.rgb.log 1-2 "RGB Golden Test" 1 0 +callCompareTest testcase01.gray8.golden test.gray8.log 1-3 "Gray8 Golden Test" 1 0 + +## +## @brief Execute gstreamer pipeline and do golden-test with the output of the pipeline. +## @param $1 Colorspace +## @param $2 Width +## @param $3 Height +## @param $4 Test Case Number +function do_test() { + gstTest "--gst-plugin-path=${PATH_TO_PLUGIN} filesrc location=testcase02_${1}_${2}x${3}.png ! pngdec ! videoscale ! imagefreeze ! videoconvert ! video/x-raw,format=${1},width=${2},height=${3},framerate=0/1 ! tensor_converter silent=TRUE ! tensor_decoder mode=protobuf ! other/protobuf-tensor ! tensor_converter ! filesink location=\"testcase02_${1}_${2}x${3}.log\" sync=true" ${4} 0 0 $PERFORMANCE + + callCompareTest testcase02_${1}_${2}x${3}.golden testcase02_${1}_${2}x${3}.log ${4} "PNG Golden Testing ${4}" 1 0 +} + +do_test BGRx 640 480 2-1 +do_test RGB 640 480 2-2 +do_test GRAY8 640 480 2-3 +do_test BGRx 642 480 2-4 +do_test RGB 642 480 2-5 +do_test GRAY8 642 480 2-6 + +# Fail Test: YUV is given +gstTest "--gst-plugin-path=${PATH_TO_PLUGIN} videotestsrc num-buffers=1 ! video/x-raw,format=YUV,width=280,height=40,framerate=0/1 ! videoconvert ! video/x-raw, format=YUV ! tensor_converter silent=TRUE ! tensor_decoder mode=protobuf ! other/protobuf-tensor ! tensor_converter ! filesink location=\"test.yuv.fail.log\" sync=true" 5F_n 0 1 $PERFORMANCE + +# Fail Test: Unknown property is given +gstTest "--gst-plugin-path=${PATH_TO_PLUGIN} videotestsrc num-buffers=1 ! video/x-raw,format=RGB,width=280,height=40,framerate=0/1 ! videoconvert ! video/x-raw, format=RGB ! tensor_converter silent=TRUE whatthehell=isthis ! tensor_decoder mode=protobuf ! other/protobuf-tensor ! tensor_converter ! filesink location=\"test.yuv.fail.log\" sync=true" 6F_n 0 1 $PERFORMANCE + +# audio format S16LE, 8k sample rate, samples per buffer 8000 +gstTest "--gst-plugin-path=${PATH_TO_PLUGIN} audiotestsrc num-buffers=1 samplesperbuffer=8000 ! audioconvert ! audio/x-raw,format=S16LE,rate=8000 ! tee name=t ! queue ! audioconvert ! tensor_converter frames-per-tensor=8000 ! tensor_decoder mode=protobuf ! other/protobuf-tensor ! tensor_converter ! filesink location=\"test.audio8k.s16le.log\" sync=true t. ! queue ! filesink location=\"test.audio8k.s16le.origin.log\" sync=true" 7-1 0 0 $PERFORMANCE +callCompareTest test.audio8k.s16le.origin.log test.audio8k.s16le.log 7-2 "Audio8k-s16le Golden Test" 0 0 + +# audio format U8, 16k sample rate, samples per buffer 8000 +gstTest "--gst-plugin-path=${PATH_TO_PLUGIN} audiotestsrc num-buffers=1 samplesperbuffer=8000 ! audioconvert ! audio/x-raw,format=U8,rate=16000 ! tee name=t ! queue ! audioconvert ! tensor_converter frames-per-tensor=8000 ! tensor_decoder mode=protobuf ! other/protobuf-tensor ! tensor_converter ! filesink location=\"test.audio16k.u8.log\" sync=true t. ! queue ! filesink location=\"test.audio16k.u8.origin.log\" sync=true" 7-3 0 0 $PERFORMANCE +callCompareTest test.audio16k.u8.origin.log test.audio16k.u8.log 7-4 "Audio16k-u8 Golden Test" 0 0 + +# audio format U16LE, 16k sample rate, 2 channels, samples per buffer 8000 +gstTest "--gst-plugin-path=${PATH_TO_PLUGIN} audiotestsrc num-buffers=1 samplesperbuffer=8000 ! audioconvert ! audio/x-raw,format=U16LE,rate=16000,channels=2 ! tee name=t ! queue ! audioconvert ! tensor_converter frames-per-tensor=8000 ! tensor_decoder mode=protobuf ! other/protobuf-tensor ! tensor_converter ! filesink location=\"test.audio16k2c.u16le.log\" sync=true t. ! queue ! filesink location=\"test.audio16k2c.u16le.origin.log\" sync=true" 7-5 0 0 $PERFORMANCE +callCompareTest test.audio16k2c.u16le.origin.log test.audio16k2c.u16le.log 7-6 "Audio16k2c-u16le Golden Test" 0 0 + +# Stream test case (genCase08 in generateGoldenTestResult.py) +gstTest "--gst-plugin-path=${PATH_TO_PLUGIN} multifilesrc location=\"testsequence_%1d.png\" index=0 caps=\"image/png,framerate=\(fraction\)30/1\" ! pngdec ! videoconvert ! tensor_converter ! tensor_decoder mode=protobuf ! other/protobuf-tensor ! tensor_converter ! filesink location=\"testcase08.log\"" 8 0 0 $PERFORMANCE +callCompareTest testcase08.golden testcase08.log 8 "PNG Stream Test" 0 0 + +# tensor merge test (The output is always in the format of other/tensor) +gstTest "--gst-plugin-path=${PATH_TO_PLUGIN} tensor_merge name=merge mode=linear option=2 silent=true sync_mode=basepad sync_option=0:0 ! multifilesink location=testsynch08_%1d.log multifilesrc location=\"testsequence03_%1d.png\" index=0 caps=\"image/png, framerate=(fraction)10/1\" ! pngdec ! tensor_converter ! tensor_decoder mode=protobuf ! other/protobuf-tensor ! tensor_converter ! merge.sink_0 multifilesrc location=\"testsequence03_%1d.png\" index=0 caps=\"image/png, framerate=(fraction)30/1\" ! pngdec ! tensor_converter ! tensor_decoder mode=protobuf ! other/protobuf-tensor ! tensor_converter ! merge.sink_1" 9 0 0 $PERFORMANCE +callCompareTest testsynch08_0.golden testsynch08_0.log 9-1 "Tensor merge Compare 9-1" 1 0 +callCompareTest testsynch08_1.golden testsynch08_1.log 9-2 "Tensor merge Compare 9-2" 1 0 +callCompareTest testsynch08_2.golden testsynch08_2.log 9-3 "Tensor merge Compare 9-3" 1 0 +callCompareTest testsynch08_3.golden testsynch08_3.log 9-4 "Tensor merge Compare 9-4" 1 0 + +# tensor mux test (The output is always in the format of other/tensors) +gstTest "--gst-plugin-path=${PATH_TO_PLUGIN} tensor_mux name=tensors_mux sync_mode=basepad sync_option=1:50000000 ! multifilesink location=testsynch19_%1d.log \ + tensor_mux name=tensor_mux0 sync_mode=slowest ! tensors_mux.sink_0 \ + tensor_mux name=tensor_mux1 sync_mode=slowest ! tensors_mux.sink_1 \ + multifilesrc location=\"testsequence03_%1d.png\" index=0 caps=\"image/png, framerate=(fraction)10/1\" ! pngdec ! \ + tensor_converter ! tensor_decoder mode=protobuf ! other/protobuf-tensor ! tensor_converter ! tensor_mux0.sink_0 \ + multifilesrc location=\"testsequence03_%1d.png\" index=0 caps=\"image/png, framerate=(fraction)20/1\" ! pngdec ! \ + tensor_converter ! tensor_decoder mode=protobuf ! other/protobuf-tensor ! tensor_converter ! tensor_mux0.sink_1 \ + multifilesrc location=\"testsequence03_%1d.png\" index=0 caps=\"image/png, framerate=(fraction)30/1\" ! pngdec ! \ + tensor_converter ! tensor_decoder mode=protobuf ! other/protobuf-tensor ! tensor_converter ! tensor_mux1.sink_0 \ + multifilesrc location=\"testsequence03_%1d.png\" index=0 caps=\"image/png, framerate=(fraction)20/1\" ! pngdec ! \ + tensor_converter ! tensor_decoder mode=protobuf ! other/protobuf-tensor ! tensor_converter ! tensor_mux1.sink_1" 10 0 0 $PERFORMANCE +callCompareTest testsynch19_0.golden testsynch19_0.log 10-1 "Tensor mux Compare 10-1" 1 0 +callCompareTest testsynch19_1.golden testsynch19_1.log 10-2 "Tensor mux Compare 10-2" 1 0 +callCompareTest testsynch19_2.golden testsynch19_2.log 10-3 "Tensor mux Compare 10-3" 1 0 +callCompareTest testsynch19_3.golden testsynch19_3.log 10-4 "Tensor mux Compare 10-4" 1 0 +callCompareTest testsynch19_4.golden testsynch19_4.log 10-5 "Tensor mux Compare 10-5" 1 0 + +report -- 2.7.4