LCOV - code coverage report
Current view: top level - nnstreamer-2.4.2/ext/nnstreamer/tensor_decoder - tensordec-directvideo.c (source / functions) Coverage Total Hit
Test: nnstreamer 2.4.2-0 nnstreamer/nnstreamer#eca68b8d050408568af95d831a8eef62aaee7784 Lines: 91.1 % 157 143
Test Date: 2025-03-13 05:38:21 Functions: 100.0 % 9 9

            Line data    Source code
       1              : /**
       2              :  * GStreamer / NNStreamer tensor_decoder subplugin, "direct video"
       3              :  * Copyright (C) 2018 Jijoong Moon <jijoong.moon@samsung.com>
       4              :  * Copyright (C) 2018 MyungJoo Ham <myungjoo.ham@samsung.com>
       5              :  *
       6              :  * This library is free software; you can redistribute it and/or
       7              :  * modify it under the terms of the GNU Library General Public
       8              :  * License as published by the Free Software Foundation;
       9              :  * version 2.1 of the License.
      10              :  *
      11              :  * This library is distributed in the hope that it will be useful,
      12              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14              :  * Library General Public License for more details.
      15              :  *
      16              :  */
      17              : /**
      18              :  * @file        tensordec-directvideo.c
      19              :  * @date        04 Nov 2018
      20              :  * @brief       NNStreamer tensor-decoder subplugin, "direct video",
      21              :  *              which converts tensors to video directly.
      22              :  *
      23              :  * @see         https://github.com/nnstreamer/nnstreamer
      24              :  * @author      Jijoong Moon <jijoong.moon@samsung.com>
      25              :  * @bug         If the element size is 2 or larger, padding won't work.
      26              :  *              GRAY16 types has size of 2 and if you have padding, it won't work.
      27              :  *              To correct this, dv_decode() should be fixed.
      28              :  */
      29              : 
      30              : #include <string.h>
      31              : #include <glib.h>
      32              : #include <gst/video/video-format.h>
      33              : #include <nnstreamer_plugin_api_decoder.h>
      34              : #include <nnstreamer_plugin_api.h>
      35              : #include <nnstreamer_log.h>
      36              : #include <nnstreamer_util.h>
      37              : #include "tensordecutil.h"
      38              : 
      39              : void init_dv (void) __attribute__ ((constructor));
      40              : void fini_dv (void) __attribute__ ((destructor));
      41              : 
      42              : #define DECODER_DV_FORMATS "{ GRAY8, RGB, BGR, RGBx, BGRx, xRGB, xBGR, RGBA, BGRA, ARGB, ABGR, GRAY16_BE, GRAY16_LE }"
      43              : 
      44              : #define DECODER_DV_VIDEO_CAPS_STR \
      45              :     GST_VIDEO_CAPS_MAKE (DECODER_DV_FORMATS) \
      46              :     ", views = (int) 1, interlace-mode = (string) progressive"
      47              : 
      48              : /**
      49              :  * @brief The supported video formats
      50              :  */
      51              : typedef enum
      52              : {
      53              :   DIRECT_VIDEO_FORMAT_UNKNOWN = 0,
      54              : 
      55              :   /* Single Channel, Default: GRAY8 */
      56              :   DIRECT_VIDEO_FORMAT_GRAY8 = 1,
      57              : 
      58              :   /* 3 Channels, Default: RGB */
      59              :   DIRECT_VIDEO_FORMAT_RGB = 2,
      60              :   DIRECT_VIDEO_FORMAT_BGR = 3,
      61              : 
      62              :   /* 4 Channels, Default: BGRx */
      63              :   DIRECT_VIDEO_FORMAT_RGBx = 4,
      64              :   DIRECT_VIDEO_FORMAT_BGRx = 5,
      65              :   DIRECT_VIDEO_FORMAT_xRGB = 6,
      66              :   DIRECT_VIDEO_FORMAT_xBGR = 7,
      67              :   DIRECT_VIDEO_FORMAT_RGBA = 8,
      68              :   DIRECT_VIDEO_FORMAT_BGRA = 9,
      69              :   DIRECT_VIDEO_FORMAT_ARGB = 10,
      70              :   DIRECT_VIDEO_FORMAT_ABGR = 11,
      71              :   DIRECT_VIDEO_FORMAT_GRAY16_BE = 12,
      72              :   DIRECT_VIDEO_FORMAT_GRAY16_LE = 13,
      73              : } direct_video_formats;
      74              : 
      75              : /**
      76              :  * @brief Data structure for direct video options.
      77              :  */
      78              : typedef struct
      79              : {
      80              :   /* From option1 */
      81              :   direct_video_formats format;
      82              : } direct_video_ops;
      83              : 
      84              : /**
      85              :  * @brief List of the formats of direct video
      86              :  */
      87              : static const char *dv_formats[] = {
      88              :   [DIRECT_VIDEO_FORMAT_UNKNOWN] = "UNKNOWN",
      89              :   [DIRECT_VIDEO_FORMAT_GRAY8] = "GRAY8",
      90              :   [DIRECT_VIDEO_FORMAT_RGB] = "RGB",
      91              :   [DIRECT_VIDEO_FORMAT_BGR] = "BGR",
      92              :   [DIRECT_VIDEO_FORMAT_RGBx] = "RGBx",
      93              :   [DIRECT_VIDEO_FORMAT_BGRx] = "BGRx",
      94              :   [DIRECT_VIDEO_FORMAT_xRGB] = "xRGB",
      95              :   [DIRECT_VIDEO_FORMAT_xBGR] = "xBGR",
      96              :   [DIRECT_VIDEO_FORMAT_RGBA] = "RGBA",
      97              :   [DIRECT_VIDEO_FORMAT_BGRA] = "BGRA",
      98              :   [DIRECT_VIDEO_FORMAT_ARGB] = "ARGB",
      99              :   [DIRECT_VIDEO_FORMAT_ABGR] = "ABGR",
     100              :   [DIRECT_VIDEO_FORMAT_GRAY16_BE] = "GRAY16_BE",
     101              :   [DIRECT_VIDEO_FORMAT_GRAY16_LE] = "GRAY16_LE",
     102              :   NULL,
     103              : };
     104              : 
     105              : /** @brief tensordec-plugin's GstTensorDecoderDef callback */
     106              : static int
     107           32 : dv_init (void **pdata)
     108              : {
     109              :   direct_video_ops *ddata;
     110           32 :   ddata = *pdata = g_try_new0 (direct_video_ops, 1);
     111              : 
     112           32 :   if (ddata == NULL) {
     113            0 :     GST_ERROR ("Failed to allocate memory for decoder subplugin.");
     114            0 :     return FALSE;
     115              :   }
     116              : 
     117           32 :   ddata->format = DIRECT_VIDEO_FORMAT_UNKNOWN;
     118              : 
     119           32 :   return TRUE;
     120              : }
     121              : 
     122              : /** @brief tensordec-plugin's GstTensorDecoderDef callback */
     123              : static void
     124           31 : dv_exit (void **pdata)
     125              : {
     126           31 :   if (pdata)
     127           31 :     g_free (*pdata);
     128           31 :   return;
     129              : }
     130              : 
     131              : /** @brief tensordec-plugin's GstTensorDecoderDef callback */
     132              : static int
     133           42 : dv_setOption (void **pdata, int opNum, const char *param)
     134              : {
     135              :   direct_video_ops *ddata;
     136              : 
     137           42 :   if (!pdata || !*pdata) {
     138            0 :     GST_ERROR ("There is no plugin data.");
     139            0 :     return FALSE;
     140              :   }
     141              : 
     142           42 :   if (NULL == param || *param == '\0') {
     143            0 :     GST_ERROR ("Please set the valid value at option.");
     144            0 :     return FALSE;
     145              :   }
     146              : 
     147           42 :   ddata = *pdata;
     148              : 
     149              :   /* When the dimension[0] is 4, the video format will be decided by option1. */
     150           42 :   switch (opNum) {
     151           18 :     case 0:
     152              :     {
     153           18 :       int f = find_key_strv (dv_formats, param);
     154              : 
     155           18 :       ddata->format = (f < 0) ? DIRECT_VIDEO_FORMAT_UNKNOWN : f;
     156           18 :       if (ddata->format == DIRECT_VIDEO_FORMAT_UNKNOWN) {
     157            3 :         return FALSE;
     158              :       }
     159           15 :       break;
     160              :     }
     161           24 :     default:
     162           24 :       break;
     163              :   }
     164              : 
     165           39 :   return TRUE;
     166              : }
     167              : 
     168              : /** @brief tensordec-plugin's GstTensorDecoderDef callback */
     169              : static GstCaps *
     170          205 : dv_getOutCaps (void **pdata, const GstTensorsConfig * config)
     171              : {
     172          205 :   direct_video_ops *ddata = *pdata;
     173              :   /* Old gst_tensordec_video_caps_from_config () had this */
     174              :   GstVideoFormat format;
     175              :   gint width, height, channel;
     176              :   GstCaps *caps;
     177          205 :   guint element_size_from_cap = 1; /** Assume 1 byte per element */
     178          205 :   tensor_type input_tensor_type = config->info.info[0].type;
     179              : 
     180          205 :   g_return_val_if_fail (config != NULL, NULL);
     181          205 :   GST_INFO ("Num Tensors = %d", config->info.num_tensors);
     182          205 :   g_return_val_if_fail (config->info.num_tensors >= 1, NULL);
     183              : 
     184              :   /* Direct video uses the first tensor only even if it's multi-tensor */
     185          205 :   channel = config->info.info[0].dimension[0];
     186          205 :   if (channel == 1) {
     187           32 :     switch (ddata->format) {
     188            4 :       case DIRECT_VIDEO_FORMAT_GRAY8:
     189            4 :         format = GST_VIDEO_FORMAT_GRAY8;
     190            4 :         break;
     191            8 :       case DIRECT_VIDEO_FORMAT_GRAY16_BE:
     192            8 :         format = GST_VIDEO_FORMAT_GRAY16_BE;
     193            8 :         element_size_from_cap = 2;
     194            8 :         break;
     195            8 :       case DIRECT_VIDEO_FORMAT_GRAY16_LE:
     196            8 :         format = GST_VIDEO_FORMAT_GRAY16_LE;
     197            8 :         element_size_from_cap = 2;
     198            8 :         break;
     199           12 :       case DIRECT_VIDEO_FORMAT_UNKNOWN:
     200              :       default:
     201           12 :         GST_WARNING ("Default format has been applied: GRAY8");
     202           12 :         format = GST_VIDEO_FORMAT_GRAY8;
     203           12 :         break;
     204              :     }
     205          173 :   } else if (channel == 3) {
     206           47 :     switch (ddata->format) {
     207            4 :       case DIRECT_VIDEO_FORMAT_RGB:
     208            4 :         format = GST_VIDEO_FORMAT_RGB;
     209            4 :         break;
     210            4 :       case DIRECT_VIDEO_FORMAT_BGR:
     211            4 :         format = GST_VIDEO_FORMAT_BGR;
     212            4 :         break;
     213           39 :       case DIRECT_VIDEO_FORMAT_UNKNOWN:
     214              :       default:
     215           39 :         GST_WARNING ("Default format has been applied: RGB");
     216           39 :         format = GST_VIDEO_FORMAT_RGB;
     217              :     }
     218          126 :   } else if (channel == 4) {
     219           56 :     switch (ddata->format) {
     220            4 :       case DIRECT_VIDEO_FORMAT_RGBx:
     221            4 :         format = GST_VIDEO_FORMAT_RGBx;
     222            4 :         break;
     223            4 :       case DIRECT_VIDEO_FORMAT_BGRx:
     224            4 :         format = GST_VIDEO_FORMAT_BGRx;
     225            4 :         break;
     226            4 :       case DIRECT_VIDEO_FORMAT_xRGB:
     227            4 :         format = GST_VIDEO_FORMAT_xRGB;
     228            4 :         break;
     229            4 :       case DIRECT_VIDEO_FORMAT_xBGR:
     230            4 :         format = GST_VIDEO_FORMAT_xBGR;
     231            4 :         break;
     232            4 :       case DIRECT_VIDEO_FORMAT_RGBA:
     233            4 :         format = GST_VIDEO_FORMAT_RGBA;
     234            4 :         break;
     235            4 :       case DIRECT_VIDEO_FORMAT_BGRA:
     236            4 :         format = GST_VIDEO_FORMAT_BGRA;
     237            4 :         break;
     238            4 :       case DIRECT_VIDEO_FORMAT_ARGB:
     239            4 :         format = GST_VIDEO_FORMAT_ARGB;
     240            4 :         break;
     241            4 :       case DIRECT_VIDEO_FORMAT_ABGR:
     242            4 :         format = GST_VIDEO_FORMAT_ABGR;
     243            4 :         break;
     244           24 :       case DIRECT_VIDEO_FORMAT_UNKNOWN:
     245              :       default:
     246           24 :         GST_WARNING ("Default format has been applied: BGRx");
     247           24 :         format = GST_VIDEO_FORMAT_BGRx;
     248           24 :         break;
     249              :     }
     250              :   } else {
     251           70 :     GST_ERROR ("%d channel is not supported", channel);
     252           70 :     return NULL;
     253              :   }
     254              : 
     255          135 :   if (gst_tensor_get_element_size (input_tensor_type) != element_size_from_cap) {
     256            0 :     GST_ERROR ("The element size of input tensor (%" G_GSIZE_FORMAT
     257              :         " byte / %s) for tensor_decoder::direct_video must be same as the element size of output (%u byte / %s). Note that except for GrayScale-16 format, it should be 1 byte / element, normally; i.e., RGB, RGBA, and BGRx. It is recommended to convert to UINT8 tensor stream or UINT16 tensor stream (GreyScale-16) before tensor_decoder::direct_video.",
     258              :         gst_tensor_get_element_size (input_tensor_type),
     259              :         gst_tensor_get_type_string (input_tensor_type),
     260              :         element_size_from_cap,
     261              :         ((element_size_from_cap == 2) ? "uint16" : "uint8"));
     262            0 :     return NULL;
     263              :   }
     264              : 
     265          135 :   if (input_tensor_type != _NNS_UINT8 && input_tensor_type != _NNS_UINT16) {
     266            0 :     GST_WARNING
     267              :         ("The input tensor type for tensor_decoder::direct_video is recommended to be either UINT8 or UINT16. The current type, %s, does not incur buffer size mismatch, but the actual behavior might be inconsistent. Try UINT8/UINT16, which is meant to be the video/x-raw element type.",
     268              :         gst_tensor_get_type_string (input_tensor_type));
     269              :   }
     270              : 
     271          135 :   width = config->info.info[0].dimension[1];
     272          135 :   height = config->info.info[0].dimension[2];
     273              : 
     274          135 :   caps = gst_caps_from_string (DECODER_DV_VIDEO_CAPS_STR);
     275              : 
     276          135 :   if (format != GST_VIDEO_FORMAT_UNKNOWN) {
     277          135 :     const char *format_string = gst_video_format_to_string (format);
     278          135 :     gst_caps_set_simple (caps, "format", G_TYPE_STRING, format_string, NULL);
     279              :   }
     280              : 
     281          135 :   if (width > 0) {
     282          131 :     gst_caps_set_simple (caps, "width", G_TYPE_INT, width, NULL);
     283              :   }
     284              : 
     285          135 :   if (height > 0) {
     286          131 :     gst_caps_set_simple (caps, "height", G_TYPE_INT, height, NULL);
     287              :   }
     288              : 
     289          135 :   setFramerateFromConfig (caps, config);
     290              : 
     291          135 :   return gst_caps_simplify (caps);
     292              : }
     293              : 
     294              : /** @brief get video output buffer size */
     295              : static size_t
     296          103 : _get_video_xraw_bufsize (const tensor_dim dim, gsize data_size)
     297              : {
     298              :   /* dim[0] is bpp and there is zeropadding only when dim[0]%4 > 0 */
     299          103 :   return (size_t) ((dim[0] * dim[1] - 1) / 4 + 1) * 4 * dim[2] * data_size;
     300              : }
     301              : 
     302              : /** @brief tensordec-plugin's GstTensorDecoderDef callback */
     303              : static size_t
     304           51 : dv_getTransformSize (void **pdata, const GstTensorsConfig * config,
     305              :     GstCaps * caps, size_t size, GstCaps * othercaps, GstPadDirection direction)
     306              : {
     307              :   /* Direct video uses the first tensor only even if it's multi-tensor */
     308           51 :   const uint32_t *dim = &(config->info.info[0].dimension[0]);
     309           51 :   gsize data_size = gst_tensor_get_element_size (config->info.info[0].type);
     310           51 :   gsize transform_size = 0;
     311              :   UNUSED (pdata);
     312              :   UNUSED (caps);
     313              :   UNUSED (size);
     314              :   UNUSED (othercaps);
     315              : 
     316           51 :   if (direction == GST_PAD_SINK)
     317           51 :     transform_size = _get_video_xraw_bufsize (dim, data_size);
     318              : 
     319           51 :   return transform_size;
     320              : }
     321              : 
     322              : /** @brief tensordec-plugin's GstTensorDecoderDef callback */
     323              : static GstFlowReturn
     324           52 : dv_decode (void **pdata, const GstTensorsConfig * config,
     325              :     const GstTensorMemory * input, GstBuffer * outbuf)
     326              : {
     327              :   GstMapInfo out_info;
     328              :   GstMemory *out_mem;
     329              :   /* Direct video uses the first tensor only even if it's multi-tensor */
     330           52 :   const uint32_t *dim = &(config->info.info[0].dimension[0]);
     331           52 :   gsize data_size = gst_tensor_get_element_size (config->info.info[0].type);
     332              : 
     333           52 :   size_t size = _get_video_xraw_bufsize (dim, data_size);
     334              :   UNUSED (pdata);
     335              : 
     336           52 :   g_assert (outbuf);
     337           52 :   if (gst_buffer_get_size (outbuf) > 0 && gst_buffer_get_size (outbuf) != size) {
     338            0 :     gst_buffer_set_size (outbuf, size);
     339              :   }
     340              : 
     341           52 :   if (gst_buffer_get_size (outbuf) == 0) {
     342            0 :     out_mem = gst_allocator_alloc (NULL, size, NULL);
     343              :   } else {
     344              :     /* Don't reallocate. Reuse what's already given */
     345           52 :     out_mem = gst_buffer_get_all_memory (outbuf);
     346              :   }
     347           52 :   if (!gst_memory_map (out_mem, &out_info, GST_MAP_WRITE)) {
     348            0 :     gst_memory_unref (out_mem);
     349            0 :     ml_loge ("Cannot map output memory / tensordec-directvideo.\n");
     350           52 :     return GST_FLOW_ERROR;
     351              :   }
     352              : 
     353           52 :   if (0 == ((dim[0] * dim[1]) % 4)) {
     354              :     /* No Padding Required */
     355           50 :     memcpy (out_info.data, input->data, input->size);
     356              :   } else {
     357              :     /* Do Padding */
     358              :     unsigned int h;
     359              :     uint8_t *ptr, *inp;
     360              : 
     361            2 :     ptr = (uint8_t *) out_info.data;
     362            2 :     inp = (uint8_t *) input->data;
     363          693 :     for (h = 0; h < dim[2]; h++) {
     364          691 :       memcpy (ptr, inp, (size_t) dim[0] * dim[1]);
     365          691 :       inp += (dim[0] * dim[1]);
     366          691 :       ptr += ((dim[0] * dim[1] - 1) / 4 + 1) * 4;
     367              :     }
     368              :   }
     369           52 :   gst_memory_unmap (out_mem, &out_info);
     370              : 
     371           52 :   if (gst_buffer_get_size (outbuf) == 0)
     372            0 :     gst_buffer_append_memory (outbuf, out_mem);
     373              :   else
     374           52 :     gst_buffer_replace_all_memory (outbuf, out_mem);
     375              : 
     376              :   /** @todo Caller of dv_decode in tensordec.c should call gst_memory_unmap to inbuf */
     377              : 
     378           52 :   return GST_FLOW_OK;
     379              : }
     380              : 
     381              : static gchar decoder_subplugin_direct_video[] = "direct_video";
     382              : 
     383              : /** @brief Direct-Video tensordec-plugin GstTensorDecoderDef instance */
     384              : static GstTensorDecoderDef directVideo = {
     385              :   .modename = decoder_subplugin_direct_video,
     386              :   .init = dv_init,
     387              :   .exit = dv_exit,
     388              :   .setOption = dv_setOption,
     389              :   .getOutCaps = dv_getOutCaps,
     390              :   .getTransformSize = dv_getTransformSize,
     391              :   .decode = dv_decode
     392              : };
     393              : 
     394              : /** @brief Initialize this object for tensordec-plugin */
     395              : void
     396           58 : init_dv (void)
     397              : {
     398           58 :   nnstreamer_decoder_probe (&directVideo);
     399           58 :   nnstreamer_decoder_set_custom_property_desc (decoder_subplugin_direct_video,
     400              :       "option1",
     401              :       "The output video format. If this is unspecified, it is 'GRAY8' (dim[0]/channel == 1), 'RGB' (dim[0]/channel == 3), or 'BGRx' (dim[0]/channel == 4). Available options are: "
     402              :       DECODER_DV_FORMATS, NULL);
     403           58 : }
     404              : 
     405              : /** @brief Destruct this object for tensordec-plugin */
     406              : void
     407           58 : fini_dv (void)
     408              : {
     409           58 :   nnstreamer_decoder_exit (directVideo.modename);
     410           58 : }
        

Generated by: LCOV version 2.0-1