일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- Python
- Numpy
- C++
- JSON
- YOLO
- pip
- label
- 명령어
- 오류
- SSH
- C#
- 기타 연주
- Docker
- C
- pytorch
- Visual Studio
- LIST
- 채보
- OpenCV
- VS Code
- 핑거스타일
- paramiko
- windows forms
- mysql
- error
- pandas
- 프로그래머스
- Selenium
- ubuntu
- Linux
- Today
- Total
기계는 거짓말하지 않는다
DeepStream Python Smart Record filesink location 얻기 본문
DeepStream Python Smart Record filesink location 얻기
KillinTime 2024. 12. 18. 22:40NVIDIA 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을 얻을 수 없고, 저장되는 디렉터리에서 파일 이름을 찾으라고 답변했다.
Python App에서 Smart Record를 사용하기 위해서는
직접 C++ 코드를 수정하여 바인딩 하여야 한다.
Smart record in Python - Intelligent Video Analytics / DeepStream SDK - NVIDIA Developer Forums
바인딩 예제는 아래 FAQ를 참고하면 된다.
DeepStream SDK FAQ - Intelligent Video Analytics / DeepStream SDK - NVIDIA Developer Forums
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이고, 시작되면 저장되는 파일 경로를 반환한다.