This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

J784S4XEVM: Dynamic Property Updates in GStreamer tiovx and v4l2h265enc elements

Part Number: J784S4XEVM

Tool/software:

Hi,

We are porting our video processing pipeline to the TI platform and have encountered an issue with the dynamic reconfiguration of GStreamer elements. Our pipeline utilizes the tiovxtiovxmultiscaler  and v4l2h265enc GStreamer modules. We have observed that several of these modules do not correctly support dynamic property changes, a standard GStreamer feature crucial for our application. When new property values are set, they are not applied, and the modules continue to operate with the previous settings.

Currently, we have identified tiovxmultiscaler, tivxldc, and v4l2h265enc as being affected by this issue.

  • For tiovxmultiscaler, changing the "roi" property does not affect the output video.
  • For tivxldc, updating the "lut-file" property is ineffective. Furthermore, we have observed that changing the resolution is also not working as expected.
  • The v4l2h265enc module also exhibits issues with dynamic resolution updates.

Restarting the entire pipeline to update these properties is not a viable solution for us, as the stop/start sequence introduces an unacceptable delay.

We have attached a simplified example code(test.cpp) demonstrating this issue. The code functions correctly when using software-based modules, such as videoscale (instead of tiovxmultiscaler) and avenc_mjpeg (instead of v4l2h265enc). This serves to isolate the problem to the TI-specific hardware acceleration modules.

The program can be compiled using the following command:

g++ -o test test.cpp `pkg-config --cflags --libs gstreamer-1.0`

And then run with the following options:

  • Using software scaler and encoder: ./test useV4L2=0 useScaler=1 useSwScaler=1
  • Using hardware encoder and scaler: ./test useV4L2=1 useScaler=1 useSwScaler=0

The output video is saved as vid.out. Analysis of this video will demonstrate that the resolution and ROI are not updated, even though the new values are set correctly within the application.

We are using SDK 10 - > oe-layersetup/configs/processor-sdk-analytics  /processor-sdk-analytics-10.00.00-config.txt

We would greatly appreciate your assistance in resolving this issue. Please let us know if you require any further information.

Thank you for your time and attention to this matter.

#include <gst/gst.h>
#include <iostream>
#include <thread>
#include <chrono>
#include <map>

int main(int argc, char *argv[]) {
  // Default parameter values
  bool useScaler{true};
  bool useSwScaler{true};
  bool useV4L2{false};
  
  // Parse command line arguments
  std::map<std::string, std::string> args;
  std::cout << "argc: " << argc << std::endl;
  for (int i = 1; i < argc; i++) {
    std::string arg = argv[i];
    size_t pos = arg.find('=');
    
    if (pos != std::string::npos) {
      std::string key = arg.substr(0, pos);
      std::string value = arg.substr(pos + 1);
      std::cout << "key: " << key << ", value: " << value << std::endl;
      args[key] = value;
    }
  }
  
  // Process arguments
  if (args.count("useScaler")) {
    std::string val = args["useScaler"];
    useScaler = (val == "true" || val == "1" || val == "yes");
  }
  if (args.count("useSwScaler")) {
    std::string val = args["useSwScaler"];
    useSwScaler = (val == "true" || val == "1" || val == "yes");
  }
  if (args.count("useV4L2")) {
    std::string val = args["useV4L2"];
    useV4L2 = (val == "true" || val == "1" || val == "yes");
  }

  gst_init(&argc, &argv);

  // Create pipeline elements
  auto pipeline = gst_pipeline_new("test-pipeline");
  auto source = gst_element_factory_make("videotestsrc", "source");
  auto capsfilter = gst_element_factory_make("capsfilter", "capsfilter");
  auto tiovxldc =  gst_element_factory_make("tiovxldc", "tiovxldc");
  auto scaler =  gst_element_factory_make(useSwScaler ? "videoscale" : "tiovxmultiscaler", "scaler");
  auto capsfilter2 = gst_element_factory_make("capsfilter", "capsfilter2");
  auto videoconvert = gst_element_factory_make("videoconvert", "videoconvert");
  auto encoder = gst_element_factory_make(useV4L2? "v4l2h265enc" : "avenc_mjpeg", "encoder");
  auto sink = gst_element_factory_make("filesink", "sink");

  // Check if all elements were created successfully
  if (!pipeline || !source || !capsfilter || !encoder || !capsfilter2 || !tiovxldc  || ! scaler || !videoconvert || !sink) {
    std::cerr << "Failed to create all elements!" << std::endl;
    return -1;
  }

  // Configure elements
  g_object_set(source, "pattern", 19, nullptr); // 19 = smpte100
  
  auto caps = gst_caps_new_simple("video/x-raw",
                                 "width", G_TYPE_INT, 2896,
                                 "height", G_TYPE_INT, 1876,
                                 "framerate", GST_TYPE_FRACTION, 30, 1,
                                 nullptr);
  g_object_set(capsfilter, "caps", caps, nullptr);
  gst_caps_unref(caps);


  auto caps2 = gst_caps_new_simple("video/x-raw",
                                 "width", G_TYPE_INT, 1280,
                                 "height", G_TYPE_INT, 720,
                                 "format", G_TYPE_STRING, "NV12",
                                 nullptr);
  g_object_set(capsfilter2, "caps", caps2, nullptr);
  gst_caps_unref(caps2);



  g_object_set(sink, "location", "vid.out", nullptr);

  if (useScaler)
  {
      if (!useSwScaler)
      {
        g_object_set(scaler, "target", 2,  nullptr);
        g_signal_connect(
          scaler, "pad-added", G_CALLBACK(+[](GstElement * /*compositor*/, GstPad *new_pad, void *) {
            std::string const sNewPadName{GST_PAD_NAME(new_pad)};
            if (sNewPadName == "src_0")
            {
              std::cout << "Update ROI" << std::endl;
              g_object_set(new_pad, "roi-starty", 320, "roi-height", 720, "roi-startx", 320, "roi-width", 1280, NULL);
            }
          }),
          NULL);
        }
  }
  else
  {
    g_object_set(tiovxldc, "target", 1, "ldc-ds-factor", 3,"ldc-table-width", 1920, "ldc-table-height", 1080, "lut-file" , "/root/btomc/mesh.txt.bin1080_zero",  nullptr);
  }

  // Add elements to pipeline
  gst_bin_add_many(GST_BIN(pipeline), source, capsfilter, useScaler ? scaler : tiovxldc, capsfilter2, videoconvert , encoder, sink, nullptr);
  
  // Link elements
  if (!gst_element_link_many(source, capsfilter, useScaler ? scaler : tiovxldc, capsfilter2, videoconvert, encoder, sink, nullptr)) {
    std::cerr << "Failed to link elements!" << std::endl;
    gst_object_unref(pipeline);
    return -1;
  }

  // Start pipeline
  GstStateChangeReturn ret = gst_element_set_state(pipeline, GST_STATE_PLAYING);
  if (ret == GST_STATE_CHANGE_FAILURE) {
    std::cerr << "Failed to start pipeline!" << std::endl;
    gst_object_unref(pipeline);
    return -1;
  }

  // Wait for pipeline to reach PLAYING state
  GstState state;
  ret = gst_element_get_state(pipeline, &state, nullptr, GST_CLOCK_TIME_NONE);
  if (ret == GST_STATE_CHANGE_FAILURE || state != GST_STATE_PLAYING) {
    std::cerr << "Pipeline failed to reach PLAYING state!" << std::endl;
    gst_element_set_state(pipeline, GST_STATE_NULL);
    gst_object_unref(pipeline);
    return -1;
  }

  std::cout << "Pipeline is now playing. Pattern is smpte100 (19)." << std::endl;
  
  // Wait for 5 second
  std::this_thread::sleep_for(std::chrono::seconds(5));
  
  std::cout << "Dynamic update start" << std::endl;

  // Change pattern to 18 (ball)
  //g_object_set(source, "pattern", 18, nullptr);
  //std::cout << "Changed pattern to ball (18)" << std::endl;

  if (useScaler)
  {
      if (!useSwScaler)
      {
        std::cout << "Update ROI" << std::endl;
        auto pad{gst_element_get_static_pad(scaler, "src_0")};
        g_object_set(pad, "roi-starty", 0, "roi-height", 1080, "roi-startx", 0, "roi-width", 1920, NULL);
        gst_object_unref(pad);
      }
      auto caps3 = gst_caps_new_simple("video/x-raw",
                                 "width", G_TYPE_INT, 1920,
                                 "height", G_TYPE_INT, 1080,
                                 "format", G_TYPE_STRING, "NV12",
                                 nullptr);
      g_object_set(capsfilter2, "caps", caps3, nullptr);
  }
  else
  {
      std::cout << "Update Lut file and output size" << std::endl;
      g_object_set(tiovxldc, "target", 1, "ldc-ds-factor",3 ,"ldc-table-width", 1920, "ldc-table-height", 1080, "lut-file" , "/root/btomc/mesh.txt.bin1080",  nullptr);
       auto caps3 = gst_caps_new_simple("video/x-raw",
                                 "width", G_TYPE_INT, 1920,
                                 "height", G_TYPE_INT, 1080,
                                 "format", G_TYPE_STRING, "NV12",
                                 nullptr);
      g_object_set(capsfilter2, "caps", caps3, nullptr);
  }
  std::cout << "Dynamic update done" << std::endl;

  // Wait for 5 second
  std::this_thread::sleep_for(std::chrono::seconds(5));

  # if 0
  // Wait for EOS or error
  auto bus = gst_element_get_bus(pipeline);
  auto msg = gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE,
      static_cast<GstMessageType>(GST_MESSAGE_ERROR | GST_MESSAGE_EOS));
      if (msg != nullptr)
    gst_message_unref(msg);
    gst_object_unref(bus);
  #endif

  // Clean up

  gst_element_set_state(pipeline, GST_STATE_NULL);
  gst_object_unref(pipeline);
  
  return 0;
}
  • Hi Bartosz,

    Have you seen this issue with the edgeai-gst-plugins in previous releases? Please allow me some time to run a few tests on my end and I will share my findings with you tomorrow.

    Thank you,

    Fabiana

  • Our testing with older SDK versions has been limited to basic validation, and we haven't run a full pipeline like the one we're using now.  Therefore, we can't definitively say whether the issue existed previously, but based on our current understanding, it's likely it was present in earlier SDK versions as well.

  • Hi Bartosz,

    I ran some basic GStreamer pipeline tests for tiovxmultiscaler and was able to validate the ROI property functionality.

    With crop:

    gst-launch-1.0 videotestsrc is-live=true num-buffers=5 ! "video/x-raw,format=NV12,width=1280,height=720" ! tiovxmultiscaler name=multi src_0::roi-startx=100 src_0::roi-starty=100 src_0::roi-width=640 src_0::roi-height=480 multi. ! "video/x-raw,format=NV12,width=320,height=240" ! queue ! kmssink driver-name=tidss

    Without crop for comparison:

    gst-launch-1.0 videotestsrc is-live=true num-buffers=5 ! "video/x-raw,format=NV12,width=1280,height=720" ! tiovxmultiscaler name=multi multi. ! "video/x-raw,format=NV12,width=320,height=240" ! queue ! kmssink driver-name=tidss

    I am still looking into the other edgeai-gst-plugins you have mentioned. Please expect a response from me with more information next week.

    Thank you,

    Fabiana

  • To clarify, the initial configuration of ROI and LUT properties within the GStreamer pipeline is functioning as expected, with changes being successfully applied. However, subsequent dynamic updates to these properties during runtime are not taking effect, as showed in the provided 'test.cpp' example.

    For context we use wide angle camera, and we need to update "lut-file" dynamically during runtime, to change LDC setting and show different part of the source image.

  • Hi Bartosz,

    I appreciate the clarification! I am working on getting you more details. Thank you for your patience.

    Best,

    Fabiana

  • Any updates on this?