Using hailopython on multi stream pipeline

Hello!

I’ve trying to implement a multi stream pipeline using GStreamer and Python, where I have the hailotracker detecting the objects, and I would like to use the detection information inside a callback function.

I tried the pipeline below, but the callback isn’t happening. Is that correct? Should I use the hailopython in another way?

‘’’
def get_pipeline_string(self):

    sources = ''
    for i in range(0,len(self.video_source)):
        source_element = f"filesrc location={self.video_source[i]} name=src_{i} ! "
        source_element += QUEUE(f"queue_dec264_{i}", max_size_buffers=30)
        source_element += f" qtdemux ! h264parse ! avdec_h264 max-threads=2 ! "
        source_element += f" video/x-raw,format=I420 "

        sources += f"{source_element} ! "
        sources += f"queue name=hailo_preprocess_q_{i} leaky=no max-size-buffers=5 max-size-bytes=0 max-size-time=0 ! "
        sources += f"videoconvert ! videoscale ! "
        sources += f"fun.sink_{i} "
        sources += f"sid.src_{i} ! queue name=comp_q_{i} leaky=downstream max-size-buffers=30 "
        sources += f"max-size-bytes=0 max-size-time=0 ! comp.sink_{i} "

    pipeline_string = ""
    
    #pipeline_string = "gst-launch-1.0 "
    pipeline_string = "funnel name=fun ! "
    
    pipeline_string += "queue name=hailo_pre_infer_q_0 leaky=no max-size-buffers=30 max-size-bytes=0 max-size-time=0 ! "
    pipeline_string += f"hailonet hef-path={self.hef_path} batch-size=2 {thresholds_str} multi-process-service=true device-count=1 vdevice-key=1 ! "
    
    pipeline_string += QUEUE("queue_hailofilter", max_size_buffers=30)
    pipeline_string += f"hailofilter function-name={self.default_network_name} so-path={self.default_postprocess_so} qos=false ! "
    pipeline_string += "queue leaky=no max-size-buffers=30 max-size-bytes=0 max-size-time=0 ! "
    pipeline_string += QUEUE("queue_hailotracker", max_size_buffers=30)
    pipeline_string += "hailotracker name=hailo_tracker class-id=-1 keep-past-metadata=true kalman-dist-thr=.5 iou-thr=.6 keep-tracked-frames=10 keep-lost-frames=5 ! "

    pipeline_string += QUEUE("queue_hailopython", max_size_buffers=30)
    pipeline_string += f"hailopython qos=false module={self.options_menu.python_module} ! "

    pipeline_string += QUEUE("queue_hailooverlay", max_size_buffers=30)
    pipeline_string += "hailooverlay ! "

    pipeline_string += "streamiddemux name=sid "
    pipeline_string += "compositor name=comp start-time-selection=0 ! "

    pipeline_string += "queue name=hailo_video_q_0 leaky=no max-size-buffers=30 max-size-bytes=0 max-size-time=0 ! "
    pipeline_string += "videoconvert ! queue name=hailo_display_q_0 leaky=no max-size-buffers=30 max-size-bytes=0 max-size-time=0 ! "

    pipeline_string += f"fpsdisplaysink video-sink={video_sink} name=hailo_display sync={self.sync} text-overlay={self.options_menu.show_fps} signal-fps-measurements=true "
    
    pipeline_string += sources

    return pipeline_string

‘’’

Any help on this?
I tried several variations, nothing worked…

Hi @diulhio,

Could you please also show us the Python module code?

Hi @nina-vilela ! Thank you for your reply!

I’m using the Gstreamer detection_python as basis: Hailo-Application-Code-Examples/runtime/gstreamer/detection_python at main · hailo-ai/Hailo-Application-Code-Examples · GitHub

I modified the GStremer pipeline as showed on previous post, the entire detection.py file a kept the same. The callback_template.py is below:

# This is a template for a callback function that can be used with hailo detection.py
# Note that you must be in hailo virtual environment to run use these imports
import hailo
# Importing VideoFrame before importing GST is must
from gsthailo import VideoFrame
from gi.repository import Gst
import numpy as np
import sys
import time
import numpy as np


def run(video_frame: VideoFrame):
    global frame

    print("Hello!")
    
    # get the detections from the frame
    detections = video_frame.roi.get_objects_typed(hailo.HAILO_DETECTION)
    print("# detection: ", len(detections))
    if (detections is None) or (len(detections) == 0):
        return Gst.FlowReturn.OK
    
    # Get the video info from the video frame
    width = video_frame.video_info.width
    height = video_frame.video_info.height

    # Get the numpy array from the video frame
    with video_frame.map_buffer() as map_info:
        # Create a NumPy array from the buffer data
        numpy_frame_ro = VideoFrame.numpy_array_from_buffer(map_info, video_info=video_frame.video_info)
        # Note this is a read only copy of the frame
        # If you want to modify the frame you need to make a copy
        # numpy_frame = numpy_frame_ro.copy()
        # Note the modifing the frame will not change the original frame (for this you'll need to replave the buffer data)
    # parse the detections
        
    for detection in detections:
        label = detection.get_label()
        bbox = detection.get_bbox()
        confidence = detection.get_confidence()
        #print(label)
        if (label == "car" or 
            label == "bus" or
            label == "truck" or
            label == "motorcycle"):
            track = detection.get_objects_typed(hailo.HAILO_UNIQUE_ID)
            track_id = track[0].get_id()
            string_to_print = (f"Detection: {label} {confidence} {track_id}")
            print(string_to_print)
    print("")
        
    return Gst.FlowReturn.OK


# This function will be called when the pipeline is closed
def close():
    print("Python close function called")

When the “hailopython” is right after “hailotracker”, nothing happens, even the “Hello!” doesn’t happen. When I put “hailopython” after “compositor” the “Hello!” and the number of detections is 0.

I’m using the last version of docker image on x86 device with Hailo8L M.2 :slight_smile:

Thank you!

Hi @nina-vilela !
Any update on this issue?

Hi @diulhio,

The following pipeline has both hailotracker and hailopython elements successfully working together:

gst-launch-1.0 filesrc location="tappas/apps/h8/gstreamer/general/detection/resources/detection.mp4" name=src_0 ! decodebin ! queue leaky=no max-size-buffers=30 max-size-bytes=0 max-size-time=0 ! videoscale qos=false n-threads=2 ! queue leaky=no max-size-buffers=30 max-size-bytes=0 max-size-time=0 ! videoconvert n-threads=2 qos=false ! queue leaky=no max-size-buffers=30 max-size-bytes=0 max-size-time=0 ! hailonet hef-path="tappas/apps/h8/gstreamer/general/detection/resources/yolov5m_wo_spp_60p.hef" ! queue leaky=no max-size-buffers=30 max-size-bytes=0 max-size-time=0 ! hailofilter function-name="yolov5" so-path="tappas/apps/h8/gstreamer/libs/post_processes/libyolo_hailortpp_post.so" config-path="null" qos=false ! queue leaky=no max-size-buffers=30 max-size-bytes=0 max-size-time=0 ! hailotracker name=hailo_tracker class-id=-1 keep-past-metadata=true kalman-dist-thr=.5 iou-thr=.6 keep-tracked-frames=10 keep-lost-frames=5 ! hailopython qos=false module="module.py" ! hailooverlay qos=false ! queue leaky=no max-size-buffers=30 max-size-bytes=0 max-size-time=0 ! videoconvert n-threads=2 qos=false ! queue leaky=no max-size-buffers=30 max-size-bytes=0 max-size-time=0 ! fpsdisplaysink video-sink= xvimagesink text-overlay=false

It seems like the issue might be with other aspects of your pipeline. You can try doing something more similar to the pipeline above.

Hi @nina-vilela,

Yeah, I know that, I made that works previously. But as I mentioned my application have multiple cameras, so I need to create a multi stream pipeline. However it doesn’t work when I use multi stream.

Hi @diulhio,

There shouldn’t be any issues with multiple streams either. You can confirm that by starting with this example, and then changing this block to:

    pipeline="gst-launch-1.0 \
           hailoroundrobin mode=0 name=fun ! \
           queue name=hailo_pre_infer_q_0 leaky=no max-size-buffers=30 max-size-bytes=0 max-size-time=0 ! \
           hailonet hef-path=$hef_path device-count=$device_count scheduling-algorithm=0 nms-score-threshold=0.3 nms-iou-threshold=0.45 output-format-type=HAILO_FORMAT_TYPE_FLOAT32 ! \
           queue name=hailo_postprocess0 leaky=no max-size-buffers=30 max-size-bytes=0 max-size-time=0 ! \
           hailofilter function-name=$network_name so-path=$POSTPROCESS_SO qos=false ! \
           queue name=hailo_draw0 leaky=no max-size-buffers=30 max-size-bytes=0 max-size-time=0 ! \
           hailotracker name=hailo_tracker class-id=-1 keep-past-metadata=true kalman-dist-thr=.5 iou-thr=.6 keep-tracked-frames=10 keep-lost-frames=5 ! \
           hailopython module=module.py ! \
           hailooverlay ! \
           hailostreamrouter name=sid $streamrouter_input_streams compositor name=comp start-time-selection=0 $compositor_locations ! \
           queue name=hailo_video_q_0 leaky=no max-size-buffers=30 max-size-bytes=0 max-size-time=0 ! \
           videoconvert ! queue name=hailo_display_q_0 leaky=no max-size-buffers=30 max-size-bytes=0 max-size-time=0 ! \
           fpsdisplaysink video-sink=$video_sink_element name=hailo_display sync=false text-overlay=false \
           $sources ${additional_parameters}"

I used the same module as yours for module.py, and everything worked as expected.

Maybe you can use that example from TAPPAS as a starting point and build from there.

Thank you, very much!
It solved my problem! :slight_smile:

1 Like

gst-launch-1.0 filesrc location=“apps/h8/gstreamer/general/detection/resources/detection.mp4” name=src_0 ! decodebin ! queue leaky=no max-size-buffers=30 max-size-bytes=0 max-size-time=0 ! videoscale qos=false n-threads=2 ! queue leaky=no max-size-buffers=30 max-size-bytes=0 max-size-time=0 ! videoconvert n-threads=2 qos=false ! queue leaky=no max-size-buffers=30 max-size-bytes=0 max-size-time=0 ! hailonet hef-path=“/home/jk/Downloads/yolov5m_wo_spp.hef” ! queue leaky=no max-size-buffers=30 max-size-bytes=0 max-size-time=0 ! hailofilter function-name=“yolov5” so-path=“apps/h8/gstreamer/libs/post_processes/libyolo_hailortpp_post.so” config-path=“null” qos=false ! queue leaky=no max-size-buffers=30 max-size-bytes=0 max-size-time=0 ! hailotracker name=hailo_tracker class-id=-1 keep-past-metadata=true kalman-dist-thr=.5 iou-thr=.6 keep-tracked-frames=10 keep-lost-frames=5 ! hailopython qos=false module=“/home/jk/my_module.py” ! hailooverlay qos=false ! queue leaky=no max-size-buffers=30 max-size-bytes=0 max-size-time=0 ! videoconvert n-threads=2 qos=false ! queue leaky=no max-size-buffers=30 max-size-bytes=0 max-size-time=0 ! fpsdisplaysink video-sink= xvimagesink text-overlay=false
Setting pipeline to PAUSED …
Pipeline is PREROLLING …
Redistribute latency…
Redistribute latency…
Redistribute latency…
Redistribute latency…
Fatal Python error: init_threadstate: thread state already initialized
Python runtime state: initialized

Thread 0x00007fff9a610c00 (most recent call first):

Aborted
I tried same pipeline but I am getting this issue.Please solve