HgDeepStream使用指南(v2.1)
1. 概述
HgDeepStream是基于Gstreamer开源框架,用来构建AI及多媒体应用的插件工具包。目前已支持编解码、图像格式转换等功能,同时对外提供Python适配和接口。后续会提供更多AI及多媒体相关功能的插件。
2. 安装部署
总共分为4个步骤,分别是Gstreamer依赖安装、Gstreamer安装、HgDeepStream插件安装、运行时环境变量设置。
2.1 项目适配及依赖说明
|
操作系统 |
主流GPU接口版本 |
Python版本 |
Gstreamer版本 |
|
Ubuntu 22.04 |
12.6 |
3.10 |
1.20.3 |
|
Ubuntu 24.04 |
12.8 |
3.12 |
1.24.2 |
|
Ubuntu 24.04 |
12.9 |
3.12 |
1.24.2 |
2.2 Gstreamer依赖安装
Ubuntu:
apt-get update &&
apt-get install -y autoconf automake libtool autopoint pkg-config \
bison nasm meson python3-pip flex libxml2-dev \
libglib2.0-dev libjson-glib-dev \
libgirepository1.0-dev \
python3-gi python-gi-dev
pip install --upgrade pip==26.0.1
pip3 install --upgrade setuptools==69.5.0
PYGOBJECT_WITHOUT_PYCAIRO=1 pip3 install pygobject==3.44.2 --no-build-isolation
2.3 Gstreamer编译安装
Ubuntu用户可选择源码安装或apt安装
2.3.1 源码编译安装(Ubuntu)
以Gstreamer 1.20.3版本为例,用户可根据需求修改版本或增删配置。请根据开发环境【2.1. 项目适配及依赖】编译对应的版本。
git clone -b 1.20.3 --depth 1 https://github.com/GStreamer/gstreamer.git
GENERAL_OPTIONS="-Dbase=enabled \
-Dgood=enabled \
-Dlibav=disabled \
-Dges=disabled \
-Drtsp_server=enabled \
-Dugly=enabled \
-Dgtk_doc=disabled \
-Dgst-examples=disabled \
-Dtests=disabled \
-Dexamples=disabled \
-Dgpl=enabled \
-Dqt5=disabled \
-Dlibnice=disabled \
-Dtls=disabled \
-Dpython=enabled \
"
BASE_OPTIONS="-Dgst-plugins-base:gl=disabled \
-Dgst-plugins-base:x11=disabled \
-Dgst-plugins-base:examples=disabled \
-Dgst-plugins-base:tests=disabled \
-Dgst-plugins-base:orc=disabled \
-Dgst-plugins-base:ogg=disabled \
-Dgst-plugins-base:opus=disabled \
-Dgst-plugins-base:vorbis=disabled \
"
GOOD_OPTIONS="-Dgst-plugins-good:doc=disabled \
-Dgst-plugins-good:examples=disabled \
-Dgst-plugins-good:tests=disabled \
-Dgst-plugins-good:alpha=disabled \
-Dgst-plugins-good:goom=disabled \
-Dgst-plugins-good:goom2k1=disabled \
-Dgst-plugins-good:oss=disabled \
-Dgst-plugins-good:oss4=disabled \
-Dgst-plugins-good:v4l2=disabled \
-Dgst-plugins-good:cairo=disabled \
"
BAD_OPTIONS="-Dgst-plugins-bad:doc=disabled \
-Dgst-plugins-bad:examples=disabled \
-Dgst-plugins-bad:tests=disabled \
-Dgst-plugins-bad:orc=disabled \
-Dgst-plugins-bad:openh264=disabled \
-Dgst-plugins-bad:openjpeg=disabled \
-Dgst-plugins-bad:openmpt=disabled \
-Dgst-plugins-bad:gl=disabled \
-Dgst-plugins-bad:x11=disabled \
-Dgst-plugins-bad:opencv=disabled \
-Dgst-plugins-bad:openal=disabled \
-Dgst-plugins-bad:openexr=disabled \
-Dgst-plugins-bad:wayland=disabled \
-Dgst-plugins-bad:vulkan=disabled \
-Dgst-plugins-bad:nvcodec=disabled \
-Dgst-plugins-bad:videoparsers=enabled \
-Dgst-plugins-bad:ivfparse=enabled \
-Dgst-plugins-bad:x265=disabled \
"
UGLY_OPTIONS="-Dgst-plugins-ugly:orc=disabled \
-Dgst-plugins-ugly:doc=disabled \
-Dgst-plugins-ugly:x264=disabled \
"
RTSP_SERVER_OPTIONS="-Dgst-rtsp-server:doc=disabled \
-Dgst-rtsp-server:examples=enabled \
-Dgst-rtsp-server:tests=enabled"
PYTHON_OPTIONS="-Dgst-python:python=python3 \
-Dgst-python:plugin=enabled"
meson setup ${GENERAL_OPTIONS} \
${BASE_OPTIONS} \
${GOOD_OPTIONS} \
${BAD_OPTIONS} \
${RTSP_SERVER_OPTIONS} \
${UGLY_OPTIONS} \
${PYTHON_OPTIONS} \
build \
gstreamer
ninja -C build install
2.3.2 apt安装(Ubuntu)
适用于Ubuntu 22.04和Ubuntu 24.04。
apt-get update && apt-get install -y libgstreamer1.0-dev \
gstreamer1.0-plugins-good \
gstreamer1.0-plugins-bad \
gstreamer1.0-plugins-ugly \
gstreamer1.0-tools \
libgstreamer-plugins-bad1.0-dev \
gstreamer1.0-rtsp \
gir1.2-gst-rtsp-server-1.0 \
python3-gst-1.0
2.4 HgDeepstream pip安装
通过安装T-Head pip源里的pyhgds安装使用。
2.5 运行时环境变量配置
Ubuntu:
#获取python版本号,3.10或3.12
PY_VERSION=$(python3 -c "import sys; print('.'.join(map(str, sys.version_info[:2])))")
#插件搜索路径
export GST_PLUGIN_PATH=/usr/local/lib/x86_64-linux-gnu/:/usr/local/lib/python${PY_VERSION}/site-packages/pyhgds_extlibs/gst-plugins:$GST_PLUGIN_PATH
export LD_LIBRARY_PATH=/usr/local/lib/x86_64-linux-gnu:$LD_LIBRARY_PATH
#python gir搜索路径
export GI_TYPELIB_PATH=/usr/lib/x86_64-linux-gnu/girepository-1.0:/usr/local/lib/x86_64-linux-gnu/girepository-1.0/:/usr/local/lib/girepository-1.0:$GI_TYPELIB_PATH
3. 发布插件说明
3.1 video硬件解码
|
名称 |
功能说明 |
|
av1_hgdec |
av1 8bit/10bit解码 |
|
h264_hgdec |
h264 8bit/10bit解码 |
|
h265_hgdec |
h265 8bit/10bit解码 |
3.2 video硬件编码
|
名称 |
功能说明 |
|
h264_hgenc |
编码8bit/10bit h264视频 |
|
h265_hgenc |
编码8bit/10bit h265视频 |
3.3 内存/显存转换
|
名称 |
功能说明 |
|
hgcudadownload |
将device显存搬运到host中 |
|
hgcudaupload |
将host内存搬运到device中 |
3.4 使用硬件进行图像变换
|
名称 |
功能说明 |
|
hgvideoconvert |
图像像素格式转换,包括NV12、P016_LE等19种图像像素格式 |
|
图像旋转,包括clockwise、horizontal-flip等6种方式 |
|
|
输入输出图像裁剪 |
|
|
图像缩放 |
4. Python使用示例
4.1 转码+格式转换
输入一个h264 mp4文件,使用硬件解码后将图像格式转换为P010_10LE,最后使用硬件编码为10bit h265 mp4文件。
import sys
import os
import gi
import argparse
gi.require_version('Gst', '1.0')
gi.require_version('GLib', '2.0')
gi.require_version('GObject', '2.0')
from gi.repository import GLib, GObject, Gst
python_version = f"{sys.version_info.major}.{sys.version_info.minor}"
gst_env_value = f"/usr/local/lib/python{python_version}/site-packages/pyhgds_extlibs/gst-plugins"
if 'GST_PLUGIN_PATH' in os.environ:
os.environ['GST_PLUGIN_PATH'] = gst_env_value + ':'+ os.environ['GST_PLUGIN_PATH']
else:
os.environ['GST_PLUGIN_PATH'] = gst_env_value
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.ERROR:
err, debug = message.parse_error()
sys.stderr.write("Error: %s: %s\n" % (err, debug))
loop.quit()
return True
def transcode_main(args):
# Parse command line arguments
parser = argparse.ArgumentParser(description='Transcode MP4 file from H.264 to H.265')
parser.add_argument('-i', '--input', required=True, help='Input MP4 file path')
parser.add_argument('-o', '--output', required=True, help='Output MP4 file path')
parsed_args = parser.parse_args(args[1:])
# Check if input file exists
if not os.path.exists(parsed_args.input):
print(f"Error: Input file '{parsed_args.input}' does not exist.")
return -1
# Initialize GStreamer
GObject.threads_init()
Gst.init(None)
# Create the pipeline
pipeline = Gst.Pipeline.new('video-transcoder')
# Create elements
filesrc = Gst.ElementFactory.make('filesrc', 'file-source')
qtdemux = Gst.ElementFactory.make('qtdemux', 'qtdemux')
h264parse = Gst.ElementFactory.make('h264parse', 'h264-parser')
h264_hgdec = Gst.ElementFactory.make('h264_hgdec', 'h264-decoder')
hgvideoconvert = Gst.ElementFactory.make('hgvideoconvert', 'video-converter')
filter1 = Gst.ElementFactory.make("capsfilter", "filter1")
h265_hgenc = Gst.ElementFactory.make('h265_hgenc', 'h265-encoder')
h265_parse = Gst.ElementFactory.make('h265parse', 'h265-parse')
mux = Gst.ElementFactory.make('mp4mux', 'mp4-mux')
filesink = Gst.ElementFactory.make('filesink', 'file-sink')
# Check if all elements were created successfully
if not all([pipeline, filesrc, qtdemux, h264parse, h264_hgdec, hgvideoconvert, h265_hgenc, mux, h265_parse, filesink]):
sys.stderr.write("Failed to create one or more elements\n")
return -1
# Add elements to the pipeline
pipeline.add(filesrc)
pipeline.add(qtdemux)
pipeline.add(h264parse)
pipeline.add(h264_hgdec)
pipeline.add(hgvideoconvert)
pipeline.add(filter1)
pipeline.add(h265_hgenc)
pipeline.add(mux)
pipeline.add(h265_parse)
pipeline.add(filesink)
# Set properties
filesrc.set_property('location', parsed_args.input)
caps1 = Gst.Caps.from_string('video/x-raw(memory:NVMM), format=P010_10LE')
filter1.set_property("caps", caps1)
def on_pad_added(demuxer, pad):
print("on_pad_added")
if pad.get_property("template").name_template == "video_%u":
pad.link(h264parse.get_static_pad("sink"))
elif pad.get_property("template").name_template == "audio_%u":
# ignore audio stream
pass
qtdemux.connect("pad-added", on_pad_added)
# Set the output location
filesink.set_property('location', parsed_args.output)
filesrc.link(qtdemux)
h264parse.link(h264_hgdec)
h264_hgdec.link(hgvideoconvert)
hgvideoconvert.link(filter1)
filter1.link(h265_hgenc)
h265_hgenc.link(h265_parse)
h265_parse.link(mux)
mux.link(filesink)
# Create a GLib loop to handle events
loop = GLib.MainLoop()
# Add a message handler to the bus
bus = pipeline.get_bus()
bus.add_signal_watch()
bus.connect("message", bus_call, loop)
# Start playing the pipeline
ret = pipeline.set_state(Gst.State.PLAYING)
if ret == Gst.StateChangeReturn.FAILURE:
sys.stderr.write("Unable to set the pipeline to the playing state.\n")
return -1
# Wait until error or EOS
try:
loop.run()
except KeyboardInterrupt:
pass
# Clean up
pipeline.set_state(Gst.State.NULL)
# Print output file location
print(f"Transcoding completed. Output file saved to: {os.path.abspath(parsed_args.output)}")
if __name__ == '__main__':
sys.exit(transcode_main(sys.argv))
使用命令python3 transcode_mp4.py -i input.mp4 -o output.mp4。
5. gst-launch-1.0使用示例
在执行【2.5 运行环境变量配置】后,也可以使用gst-launch-1.0命令加载插件。
插件参数可使用gst-inspect-1.0查看,例如:gst-inspect-1.0 hgvideoconvert。
5.1. 转码+格式转换
将h264 mp4文件解码,解码后的图像进行裁切并顺时针旋转90°,并转为P010_10LE数据格式,最后编码为10bit h265 mp4文件。
gst-launch-1.0 filesrc location=input.mp4 ! qtdemux ! h264parse ! h264_hgdec gpu-id=0 ! queue ! hgvideoconvert src-crop=100:100:1280:720 dest-crop=100:100:640:360 flip-method=clockwise ! 'video/x-raw(memory:NVMM), format=P010_10LE, width=1920, height=1080' ! queue ! h265_hgenc gpu-id=0 ! h265parse ! mp4mux ! filesink location=output.mp4
6. Q&A
Q1:安装pygobject 3.44.2报错
检查pip和setuptools的版本。
在alios python3.10建议使用setuptools 59.8.0,其余建议使用setuptools 69.5.0。
Q2:报错 ModuleNotFoundError: No module named 'gi'
请确保已正确安装pygobject:
PYGOBJECT_WITHOUT_PYCAIRO=1 pip3 install pygobject==3.44.2 --no-build-isolation
如果还有报错,请检查环境变量LD_LIBRARY_PATH和PYTHONPATH是否正确设置。
Q3:报错 No such element or plugin 'hgvideoconvert', 或者其它hg plugin找不到
请检查环境变量GST_PLUGIN_PATH是否正确设置。
如果插件在环境变量的路径中,可以使用gst-inspect-1.0 -b检查是否在黑名单中。如果在黑名单中,可根据以下步骤排查解决错误:
-
1、
GST_DEBUG=2 gst-inspect-1.0 xxx.so查看具体报错。 -
2、如果是依赖库没有加载,查看其路径是否在环境变量
LD_LIBRARY_PATH中。 -
3、清理插件缓存
rm ~/.cache/gstreamer-1.0/registry.x86_64.bin。
Q4:Gstreamer编译时可以使用本地缓存的第三方安装包吗?
Gstreamer在编译时,如果发现依赖项不存在或者版本不满足的情况下,会从网络下载第三方安装包。在无法直接从网络下载的情况下,可以将本地的安装包放在缓存目录gstreamer/subprojects/packagecache/中,编译时会直接使用。
7. 附录
7.1 链接
7.2 x11图像显示配置
本地有X server的情况下,可以使用GStreamer官方插件ximagesink显示图像。
操作步骤如下:
1、在执行【2.3 Gstreamer编译】时,打开x11配置-Dgst-plugins-base:x11=enabled。
2、配置环境变量DISPLAY。
3、将图像格式转为BGRx,并且将显存数据搬运到host后,传送给ximagesink插件。
使用命令举例:
gst-launch-1.0 filesrc location=input.mp4 ! qtdemux ! h264parse ! h264_hgdec gpu-id=0 ! hgvideoconvert flip-method=clockwise ! 'video/x-raw(memory:NVMM), format=BGRx, width=1920, height=1080' ! hgcudadownload ! ximagesink
7.3 rtsp推拉流
GStreamer提供rtsp工具,方便开发者搭建rtsp server。需要在执行【2.3 Gstreamer编译】时打开编译选项-Drtsp_server=enabled。
7.3.1 rtsp server示例
#!/usr/bin/python3
"""
The server will stream test video at rtsp://127.0.0.1:8554/test
"""
import sys
import gi
import os
gi.require_version('Gst', '1.0')
gi.require_version('GLib', '2.0')
gi.require_version('GObject', '2.0')
try:
gi.require_version('GstRtspServer', '1.0')
except ValueError:
sys.stderr.write("GstRtspServer 1.0 not found. Install gstreamer1.0-rtsp-server.\n")
sys.exit(1)
from gi.repository import GLib, GObject, Gst, GstRtspServer
python_version = f"{sys.version_info.major}.{sys.version_info.minor}"
gst_env_value = f"/usr/local/lib/python{python_version}/site-packages/pyhgds_extlibs/gst-plugins"
if 'GST_PLUGIN_PATH' in os.environ:
os.environ['GST_PLUGIN_PATH'] = gst_env_value + ':'+ os.environ['GST_PLUGIN_PATH']
else:
os.environ['GST_PLUGIN_PATH'] = gst_env_value
def main():
Gst.init(None)
loop = GLib.MainLoop()
server = GstRtspServer.RTSPServer.new()
mounts = server.get_mount_points()
factory = GstRtspServer.RTSPMediaFactory.new()
factory.set_launch(
"( videotestsrc is-live=1 ! video/x-raw, format=NV12, width=1280, height=720 ! "
"hgcudaupload ! h264_hgenc ! rtph264pay name=pay0 pt=96 )"
)
factory.set_shared(True)
mounts.add_factory("/test", factory)
mounts = None
server.attach(None)
print("stream ready at rtsp://127.0.0.1:8554/test")
try:
loop.run()
except KeyboardInterrupt:
print("Interrupted by user")
loop = None
server = None
return 0
if __name__ == '__main__':
sys.exit(main())
7.3.2 rtsp拉流示例
gst-launch-1.0 rtspsrc location=rtsp://127.0.0.1:8554/test ! queue ! rtph264depay ! h264parse ! h264_hgdec ! hgvideoconvert ! ximagesink
7.4 glib升级
# e.g. 2.78.3
git clone -b 2.78.3 --depth 1 https://github.com/GNOME/glib.git
cd glib
meson build --prefix=/usr
ninja -C build install
7.5 FFmpeg相关插件使用说明
Gstreamer提供FFmpeg相关插件,需要在执行【2.3 Gstreamer编译】时打开编译选项-Dlibav=enabled。同时在编译时需要配置环境变量export PKG_CONFIG_PATH=/xxx/ffmpeg/lib/pkgconfig:$PKG_CONFIG_PATH。
参考【Video FFmpeg使用指南】,在使用FFmpeg版本6.1.2 编译 Gstreamer1.20.3时需要如下patch:
diff --git a/subprojects/gst-libav/ext/libav/gstavviddec.c b/subprojects/gst-libav/ext/libav/gstavviddec.c
index b957d22..cc38398
--- a/subprojects/gst-libav/ext/libav/gstavviddec.c
+++ b/subprojects/gst-libav/ext/libav/gstavviddec.c
@@ -567,7 +567,7 @@ gst_ffmpegviddec_set_format (GstVideoDecoder * decoder,
if (ffmpegdec->max_threads == 0) {
/* When thread type is FF_THREAD_FRAME, extra latency is introduced equal
* to one frame per thread. We thus need to calculate the thread count ourselves */
- if ((!(oclass->in_plugin->capabilities & AV_CODEC_CAP_AUTO_THREADS)) ||
+ if ((!(oclass->in_plugin->capabilities & AV_CODEC_CAP_OTHER_THREADS)) ||
(ffmpegdec->context->thread_type & FF_THREAD_FRAME))
ffmpegdec->context->thread_count =
MIN (gst_ffmpeg_auto_max_threads (), 16);