기계는 거짓말하지 않는다

DeepStream Python Smart Record filesink location 얻기 본문

SDK/NVIDIA DeepStream

DeepStream Python Smart Record filesink location 얻기

KillinTime 2024. 12. 18. 22:40

NVIDIA DeepStream SDK Python App에서 Smart Record start 시그널이 실행된 후,

현재 저장되는 영상 파일의 경로(location)와 이름을 얻기 위해 고민하고 해결했던 과정이다.

기존 DeepStream C++ 코드에서는 NvDsSRContext 내의 filesink에 Gstreamer Element로 저장된다.

그래서 아래와 같이 이 filesink를 이용하면 현재 저장되고 있는 경로를 얻을 수 있다.

g_object_get(G_OBJECT(ctx->filesink), "location", recording_video_file_path, NULL);

그러나 NVIDIA DeepStream SDK Python App에서 Smart Record 진행 중

filesink의 location을 얻을 수 없고, 저장되는 디렉터리에서 파일 이름을 찾으라고 답변했다.

How to get a filename of smart recorded videos in python? - Intelligent Video Analytics / DeepStream SDK - NVIDIA Developer Forums

 

How to get a filename of smart recorded videos in python?

Continuing the discussion from DeepStream SDK FAQ: Please provide complete information as applicable to your setup. • Hardware Platform (Jetson / GPU) - Jetson Nano • DeepStream Version - 6.0.1 • JetPack Version (valid for Jetson only) - 4.6.1 • Te

forums.developer.nvidia.com

Python App에서 Smart Record를 사용하기 위해서는

직접 C++ 코드를 수정하여 바인딩 하여야 한다.

Smart record in Python - Intelligent Video Analytics / DeepStream SDK - NVIDIA Developer Forums

 

Smart record in Python

Please provide complete information as applicable to your setup. • Hardware Platform (Jetson / GPU) A10 • DeepStream Version 6.2 • JetPack Version (valid for Jetson only) • TensorRT Version 8.6.9 • NVIDIA GPU Driver Version (valid for GPU only) 5

forums.developer.nvidia.com

바인딩 예제는 아래 FAQ를 참고하면 된다.

DeepStream SDK FAQ - Intelligent Video Analytics / DeepStream SDK - NVIDIA Developer Forums

 

DeepStream SDK FAQ

31.[DSx_All_App] Use nvurisrcbin plugin to do smart record in Python 31.1 Apply the following patch and rebuild the pyds diff --git a/bindings/src/bindfunctions.cpp b/bindings/src/bindfunctions.cpp index eade8d5..7a4b459 100644 --- a/bindings/src/bindfunct

forums.developer.nvidia.com

Python App에서 nvurisrcbin의 smart-record property를 아래와 같이 설정하면 smart-record 기능이 on 된다.

nvurisrcbin.set_property("smart-record", 2)

Python App에서 Smart Record를 사용하기 위해서는

바인딩 후에는 아래와 같이 nvurisrcbin으로 record signal을 사용하면 된다.

nvurisrcbin.connect("sr-done", record_done, pipeline)
nvurisrcbin.emit("start-sr", sessionid, start, duration, sr_user_context_buf)
nvurisrcbin.emit("stop-sr", 0)

start-sr signal을 사용하면 스마트 레코드가 실행된다.

 

여기서 의문은 record-bin과 record-bin 내부의 filesink는 생성되었을 것이라는 것이다.

아래는 filesink를 얻었던 과정이다.

def decodebin_child_added(child_proxy, Object, name, user_data):
    print("Decodebin child added:", name, "\n")
    if name.find("decodebin") != -1:
        Object.connect("child-added", decodebin_child_added, user_data)
    if not platform_info.is_integrated_gpu() and name.find("nvv4l2decoder") != -1:
        # Use CUDA unified memory in the pipeline so frames
        # can be easily accessed on CPU in Python.
        Object.set_property("cudadec-memtype", 2)
    #    print("Seting bufapi_version\n")
    #    Object.set_property("bufapi-version", True)


def create_source_bin(index, uri):
    print("Creating source bin")

    # Create a source GstBin to abstract this bin's content from the rest of the
    # pipeline
    bin_name = "source-bin-%02d" % index
    print(bin_name)
    nbin = Gst.Bin.new(bin_name)
    if not nbin:
        sys.stderr.write(" Unable to create source bin \n")

    # Source element for reading from the uri.
    # We will use decodebin and let it figure out the container format of the
    # stream and the codec and plug the appropriate demux and decode plugins.
    uri_decode_bin = Gst.ElementFactory.make("uridecodebin", "uri-decode-bin")
    if not uri_decode_bin:
        sys.stderr.write(" Unable to create uri decode bin \n")
    # We set the input uri to the source element
    uri_decode_bin.set_property("uri", uri)
    # Connect to the "pad-added" signal of the decodebin which generates a
    # callback once a new pad for raw data has beed created by the decodebin
    uri_decode_bin.connect("pad-added", cb_newpad, nbin)
    uri_decode_bin.connect("child-added", decodebin_child_added, nbin)

    # We need to create a ghost pad for the source bin which will act as a proxy
    # for the video decoder src pad. The ghost pad will not have a target right
    # now. Once the decode bin creates the video decoder and generates the
    # cb_newpad callback, we will set the ghost pad target to the video decoder
    # src pad.
    Gst.Bin.add(nbin, uri_decode_bin)
    bin_pad = nbin.add_pad(Gst.GhostPad.new_no_target("src", Gst.PadDirection.SRC))
    if not bin_pad:
        sys.stderr.write(" Failed to add ghost pad in source bin \n")
        return None
    return nbin

DeepStream Python 샘플에서 create_source_bin 함수를 보면 이와 비슷하다.

smart-record property가 on으로 설정되면 decodebin_child_added 함수에서

source-bin에 record-bin이 연결되는 것을 확인했다.

decodebin_child_added 함수를 조금 변경하여 record-bin 내의 filesink를 얻어올 수 있다.

def has_filesink(bin_element, parent_bin_name: str, source_index: int):
    if bin_element.numchildren == 0:
        return False

    for i in range(bin_element.numchildren):
        child = bin_element.get_child_by_index(i)

        if isinstance(child, Gst.Element) and child.get_name().find('filesink') != -1:
            # filesink 저장
            filesink_list[source_index] = child
            return True
        elif isinstance(child, Gst.Bin):
            if has_filesink(child, child.get_name(), source_index):
                return True
    return False

def decodebin_child_added(child_proxy, Object, name, user_data):
    print("Decodebin child added:", name, "\n")

    nbin = user_data
    # source-bin의 name에서 source index 가져옴
    source_index = bin_index(nbin.get_name())
    
    # record-bin일 경우 filsink를 찾음
    if name.find("record") != -1 and has_filesink(nbin, nbin.get_name(), source_index):
        print(f"filesink in {nbin.get_name()}")
        
    if name.find("decodebin") != -1:
        Object.connect("child-added", decodebin_child_added, user_data)
    if not platform_info.is_integrated_gpu() and name.find("nvv4l2decoder") != -1:
        # Use CUDA unified memory in the pipeline so frames
        # can be easily accessed on CPU in Python.
        Object.set_property("cudadec-memtype", 2)
    #    print("Seting bufapi_version\n")
    #    Object.set_property("bufapi-version", True)

has_filesink 함수에서 bin 내의 child를 재귀적으로 확인하면서 filesink를 찾고 저장한다.

location = filesink_list[source_index].get_property("location")

location은 이와 같이 가져올 수 있고, record 중이지 않으면 /dev/null이고, 시작되면 저장되는 파일 경로를 반환한다.

Comments