-
Notifications
You must be signed in to change notification settings - Fork 53
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
345 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,238 @@ | ||
#!/usr/bin/env python3 | ||
import platform | ||
import sys | ||
|
||
sys.path.append('../../') | ||
|
||
import cv2 | ||
import gi | ||
|
||
gi.require_version('Gst', '1.0') | ||
from gi.repository import GLib, Gst | ||
import pyds | ||
|
||
|
||
def is_aarch64(): | ||
return platform.uname()[4] == 'aarch64' | ||
|
||
|
||
def bus_call(bus, message, loop): | ||
t = message.type | ||
if t == Gst.MessageType.EOS: | ||
sys.stdout.write("End-of-stream\n") | ||
loop.quit() | ||
elif t == Gst.MessageType.WARNING: | ||
err, debug = message.parse_warning() | ||
sys.stderr.write("Warning: %s: %s\n" % (err, debug)) | ||
elif t == Gst.MessageType.ERROR: | ||
err, debug = message.parse_error() | ||
sys.stderr.write("Error: %s: %s\n" % (err, debug)) | ||
loop.quit() | ||
return True | ||
|
||
|
||
def log_nvds_buf_surface(element_name: str, buffer: Gst.Buffer): | ||
# mapped, map_info = buffer.map(Gst.MapFlags.READ) | ||
# assert mapped, f'failed to map buffer {buffer.pts}' | ||
# nvbufsurface_p = ctypes.cast(map_info.data, ctypes.c_void_p) | ||
# nvbufsurface = pyds.NvBufSurface.cast(nvbufsurface_p.value) | ||
print() | ||
print('log_nvds_buf_surface') | ||
print() | ||
gpu_mat = cv2.savant.createGpuMat(hash(buffer), 0) | ||
print(gpu_mat) | ||
print(gpu_mat.size()) | ||
print(gpu_mat.channels()) | ||
|
||
gpu_mat.rowRange(100, 400).colRange(300, 308).setTo((0, 255, 255, 255)) | ||
gpu_mat.rowRange(100, 400).colRange(792, 800).setTo((0, 255, 255, 255)) | ||
gpu_mat.rowRange(100, 108).colRange(300, 800).setTo((0, 255, 255, 255)) | ||
gpu_mat.rowRange(392, 400).colRange(300, 800).setTo((0, 255, 255, 255)) | ||
|
||
|
||
def pad_buffer_probe(pad: Gst.Pad, info: Gst.PadProbeInfo): | ||
gst_buffer: Gst.Buffer = info.get_buffer() | ||
log_nvds_buf_surface(pad.get_parent().get_name(), gst_buffer) | ||
# batch_meta = pyds.gst_buffer_get_nvds_batch_meta(hash(gst_buffer)) | ||
# l_frame = batch_meta.frame_meta_list | ||
# while l_frame is not None: | ||
# try: | ||
# frame_meta = pyds.NvDsFrameMeta.cast(l_frame.data) | ||
# except StopIteration: | ||
# break | ||
# | ||
# n_frame: np.ndarray = pyds.get_nvds_buf_surface( | ||
# hash(gst_buffer), frame_meta.batch_id | ||
# ) | ||
# | ||
# cv2.rectangle(n_frame, (150, 50), (600, 300), (0, 255, 0, 0), 4) | ||
# frame_bytes = n_frame.tobytes() | ||
# print( | ||
# f'{pad.get_parent().get_name()} | #{frame_meta.frame_num}' | ||
# f' resolution: {n_frame.shape}' | ||
# f' size: {len(frame_bytes)} bytes' | ||
# ) | ||
# | ||
# del n_frame | ||
# del frame_bytes | ||
# | ||
# pyds.unmap_nvds_buf_surface(hash(gst_buffer), frame_meta.batch_id) | ||
# | ||
# try: | ||
# l_frame = l_frame.next | ||
# except StopIteration: | ||
# break | ||
|
||
return Gst.PadProbeReturn.OK | ||
|
||
|
||
def main(args): | ||
if len(args) > 1: | ||
n_frames = int(args[0]) | ||
else: | ||
n_frames = 1 | ||
|
||
Gst.init(None) | ||
|
||
print("Creating Pipeline") | ||
pipeline = Gst.Pipeline() | ||
is_live = False | ||
|
||
print("Creating streammux") | ||
streammux = Gst.ElementFactory.make("nvstreammux", "streammux") | ||
pipeline.add(streammux) | ||
|
||
print("Creating source") | ||
source = Gst.ElementFactory.make("videotestsrc", "source") | ||
pipeline.add(source) | ||
|
||
print("Creating source converter") | ||
source_converter = Gst.ElementFactory.make("nvvideoconvert", "source-converter") | ||
pipeline.add(source_converter) | ||
|
||
print("Creating source capsfilter") | ||
source_capsfilter = Gst.ElementFactory.make("capsfilter", "source-capsfilter") | ||
pipeline.add(source_capsfilter) | ||
|
||
print("Creating workload") | ||
workload = Gst.ElementFactory.make("identity", "workload") | ||
pipeline.add(workload) | ||
|
||
print("Creating streamdemux") | ||
streamdemux = Gst.ElementFactory.make("nvstreamdemux", "streamdemux") | ||
pipeline.add(streamdemux) | ||
|
||
print("Creating queue") | ||
queue = Gst.ElementFactory.make("queue", "queue") | ||
pipeline.add(queue) | ||
|
||
print("Creating converter") | ||
converter = Gst.ElementFactory.make("nvvideoconvert", "converter") | ||
pipeline.add(converter) | ||
|
||
print("Creating sink_capsfilter") | ||
sink_capsfilter = Gst.ElementFactory.make("capsfilter", "sink_capsfilter") | ||
pipeline.add(sink_capsfilter) | ||
|
||
print("Creating encoder") | ||
encoder = Gst.ElementFactory.make("nvv4l2h264enc", "encoder") | ||
pipeline.add(encoder) | ||
|
||
print("Creating parser") | ||
parser = Gst.ElementFactory.make("h264parse", "parser") | ||
pipeline.add(parser) | ||
|
||
print("Creating sink") | ||
sink = Gst.ElementFactory.make("filesink", "sink") | ||
# sink = Gst.ElementFactory.make("fakesink", "sink") | ||
pipeline.add(sink) | ||
|
||
source.set_property('num-buffers', n_frames) | ||
|
||
if is_live: | ||
streammux.set_property('live-source', 1) | ||
streammux.set_property('width', 1280) | ||
streammux.set_property('height', 720) | ||
streammux.set_property('batch-size', 1) | ||
streammux.set_property('batched-push-timeout', 4000000) | ||
|
||
sink.set_property("sync", 0) | ||
sink.set_property("qos", 0) | ||
sink.set_property("enable-last-sample", 0) | ||
sink.set_property("location", "result.h264") | ||
|
||
if not is_aarch64(): | ||
nv_buf_memory_type = int(pyds.NVBUF_MEM_CUDA_UNIFIED) | ||
source_converter.set_property("nvbuf-memory-type", nv_buf_memory_type) | ||
streammux.set_property("nvbuf-memory-type", nv_buf_memory_type) | ||
converter.set_property("nvbuf-memory-type", nv_buf_memory_type) | ||
|
||
source_capsfilter.set_property( | ||
'caps', | ||
Gst.Caps.from_string( | ||
'video/x-raw(memory:NVMM), format=RGBA, width=1280, height=720' | ||
), | ||
) | ||
sink_capsfilter.set_property( | ||
'caps', | ||
Gst.Caps.from_string( | ||
'video/x-raw(memory:NVMM), format=RGBA, width=480, height=480' | ||
), | ||
) | ||
|
||
print("Linking elements in the Pipeline") | ||
|
||
assert source.link(source_converter) | ||
assert source_converter.link(source_capsfilter) | ||
|
||
assert ( | ||
source_capsfilter.get_static_pad('src').link( | ||
streammux.get_request_pad('sink_0') | ||
) | ||
== Gst.PadLinkReturn.OK | ||
) | ||
|
||
assert streammux.link(workload) | ||
assert workload.link(streamdemux) | ||
|
||
streamdemux_src_pad = streamdemux.get_request_pad('src_0') | ||
streamdemux.get_request_pad('src_1') | ||
streamdemux.get_request_pad('src_2') | ||
streamdemux.get_request_pad('src_3') | ||
# workload_3_sink_pad = workload_3.get_static_pad('sink') | ||
# assert streamdemux_src_pad.link(workload_3_sink_pad) == Gst.PadLinkReturn.OK | ||
queue_sink_pad = queue.get_static_pad('sink') | ||
assert streamdemux_src_pad.link(queue_sink_pad) == Gst.PadLinkReturn.OK | ||
|
||
assert queue.link(converter) | ||
# assert converter.link(sink_capsfilter) | ||
# assert sink_capsfilter.link(sink) | ||
assert converter.link(encoder) | ||
assert encoder.link(parser) | ||
assert parser.link(sink) | ||
# assert streammux.link(sink) | ||
|
||
# create an event loop and feed gstreamer bus messages to it | ||
loop = GLib.MainLoop() | ||
bus = pipeline.get_bus() | ||
bus.add_signal_watch() | ||
bus.connect("message", bus_call, loop) | ||
|
||
sink_pad = workload.get_static_pad("sink") | ||
if not sink_pad: | ||
sys.stderr.write("Unable to get sink pad") | ||
else: | ||
sink_pad.add_probe(Gst.PadProbeType.BUFFER, pad_buffer_probe) | ||
|
||
print("Starting pipeline") | ||
pipeline.set_state(Gst.State.PLAYING) | ||
try: | ||
loop.run() | ||
except: | ||
pass | ||
print("Exiting app\n") | ||
pipeline.set_state(Gst.State.NULL) | ||
|
||
|
||
if __name__ == '__main__': | ||
sys.exit(main(sys.argv)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
set(the_description "Savant OpenCV module") | ||
|
||
set(WITH_GSTREAMER ON) | ||
message(STATUS "Using GStreamer: ${GSTREAMER_VERSION}") | ||
|
||
# find_package(PkgConfig REQUIRED) | ||
# find_package(CUDA REQUIRED) | ||
|
||
if(NOT DEFINED DeepStream_DIR) | ||
set(DeepStream_DIR /opt/nvidia/deepstream/deepstream) | ||
endif() | ||
|
||
# pkg_check_modules(GLIB REQUIRED glib-2.0) | ||
# pkg_check_modules(GSTREAMER REQUIRED gstreamer-1.0) | ||
|
||
ocv_define_module(savant opencv_core cudev ocv.3rdparty.gstreamer "GStreamer" WRAP python) | ||
|
||
ocv_include_directories(${DeepStream_DIR}/sources/includes) | ||
ocv_target_link_libraries(${the_module} "${DeepStream_DIR}/lib") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// | ||
// Created by pavel on 11/01/23. | ||
// | ||
|
||
#ifndef OPENCV_SAVANT_HPP | ||
#define OPENCV_SAVANT_HPP | ||
|
||
#include "opencv2/core.hpp" | ||
#include "opencv2/core/cuda.hpp" | ||
|
||
namespace cv { | ||
namespace savant { | ||
CV_EXPORTS_W cuda::GpuMat createGpuMat(int rows, int cols, int type, uint64 dataAddr, size_t step = Mat::AUTO_STEP); | ||
CV_EXPORTS_W cuda::GpuMat createGpuMat(size_t gst_buffer, int batch_id); | ||
} | ||
} | ||
|
||
#endif //OPENCV_SAVANT_HPP |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
// | ||
// Created by pavel on 11/01/23. | ||
// | ||
|
||
#include "opencv2/savant.hpp" | ||
#include "opencv2/core.hpp" | ||
#include "opencv2/core/cuda.hpp" | ||
|
||
#include <gst/gst.h> | ||
#include "nvbufsurface.h" | ||
|
||
namespace cv { | ||
namespace savant { | ||
cuda::GpuMat createGpuMat(int rows, int cols, int type, uint64 dataAddr, size_t step) { | ||
cuda::GpuMat gpuMat(rows, cols, type, (void *) dataAddr, step); | ||
return gpuMat; | ||
} | ||
|
||
cuda::GpuMat createGpuMat(size_t gst_buffer, int batch_id) { | ||
auto * buffer = (GstBuffer *)(gst_buffer); | ||
GstMapInfo map_info; | ||
gst_buffer_map(buffer, &map_info, GST_MAP_READ); | ||
auto * nvsurface = (NvBufSurface *)(map_info.data); | ||
gst_buffer_unmap(buffer, &map_info); | ||
const NvBufSurfaceParams &surface = nvsurface->surfaceList[batch_id]; | ||
cv::cuda::GpuMat gpuMat(surface.height, surface.width, CV_8UC4, (void *)surface.dataPtr); | ||
return gpuMat; | ||
} | ||
} | ||
} |