QML----RK3568上使用QML直接播放RTP流视频学习总结

打印 上一主题 下一主题

主题 905|帖子 905|积分 2715

部分代码github
1 目标

怎样在qml窗口中直接播放RTP视频流
2 终端机直接通过Gstreamer播放RTP流视频

首先是尝试直接在终端机中拉取视频流并播放,确保我的视频流达到了终端机,能够举行后续的操纵.
2.1 本地视频文件推拉流

windows虚拟机推流本地视频文件,终端机继承推流
windows虚拟机推流 gst-launch-1.0 filesrc location=/home/firefly/Desktop/test.mp4 ! qtdemux ! rtph264pay config-interval=-1 ! udpsink host=224.224.224.224 port=5000
终端机拉流 gst-launch-1.0 -ve udpsrc uri=udp://224.224.224.224:5000 ! application/x-rtp,media=video,encoding-name=H264 ! rtph264depay ! h264parse ! mppvideodec ! videoconvert ! autovideosink sync=false
2.2 终端机摄像头推拉流

在终端机上插上摄像头后推拉流,在linux虚拟机上也插上了摄像头举行尝试,无法获取到
终端机推流 gst-launch-1.0 -ve v4l2src device=/dev/video0 ! image/jpeg,width=800,height=600,framerate=15/1 ! jpegdec ! mpph264enc ! h264parse ! rtph264pay ! udpsink host=224.224.224.224 port=5000
终端机拉流 gst-launch-1.0 -ve udpsrc uri=udp://224.224.224.224:5000 caps=\"application/x-rtp,media=video,encoding-name=H264\" ! rtph264depay ! h264parse ! mppvideodec fast-mode=true ! videoconvert ! autovideosink"
直接拉取摄像头的话只能够拉取一起,摄像头就会占用,所以只能通过推流的方式来获得多路摄像头流
gst-launch-1.0 -ve v4l2src device=/dev/video0 ! videoconvert ! autovideosink
2.3 testvideosrc推拉流

testvideosrc是gstreamer自带的视频流,虚拟机和终端机都能够举行推流
推流 gst-launch-1.0 videotestsrc ! video/x-raw ! vp8enc deadline=1 ! rtpvp8pay ! udpsink host=224.224.224.224 port=5000
终端机拉流 gst-launch-1.0 -ve udpsrc uri=udp://224.224.224.224:5000 ! application/x-rtp,media=video,encoding-name=VP8 ! rtpvp8depay ! mppvideodec ! videoscale ! video/x-raw,width=1200,height=800 ! videoconvert ! autovideosink sync=false
3 终端机在qml中播放RTP流视频

确定RTP流能够到达终端机后,就可以开始研究怎么在qml里播放RTP流视频
3.1 思路 1 使用MediaPlayer调用gstreamer

使用MediaPlayer+Videooutput组件来播放视频,可以直接拉取rtsp流,对于rtp流不支持(必要混用gstreamer)
代码就是将QT自带的MediaPlayer中的 source改为gstreamer的下令.在自己电脑的虚拟机上有 qtvideosink可以让视频表现在qml上,但是对于终端机没有这个插件,尝试安装后也照旧没有,因此该思路无法举行下去
  1. import QtQuick 2.15
  2. import QtQuick.Window 2.15
  3. import QtMultimedia 5.13
  4. Window {
  5.     width: 640
  6.     height: 480
  7.     visible: true
  8.     title: qsTr("Hello World")
  9.     Rectangle{
  10.             anchors.fill: parent
  11.             color: "gray"
  12.             MediaPlayer{
  13.                     id:mediaPlayer;
  14.                     source:"gst-pipeline:udpsrc uri=udp://224.224.224.224:5000 ! application/x-rtp,media=video,encoding-name=H264 ! rtph264depay ! h264parse ! mppvideodec ! videoconvert ! autovideosink"
  15.                     autoPlay: true
  16.          onError: {
  17.                         console.log(errorString);
  18.                     }
  19.                 }
  20.             VideoOutput{
  21.                 anchors.fill:parent;
  22.                 source: mediaPlayer;
  23.                 //flushMode: VideoOutput.LastFrame;
  24.             }
  25.         }
  26. }
复制代码
3.2 思路 2 使用vlc-qt库

VLC-Qt 是一个 Qt 库,它封装了 VLC(VideoLAN)播放器的功能,使得在 Qt 应用中可以轻松地集成视频播放功能。具体来说,VLC-Qt 提供了一个可以嵌入到 Qt 应用中的组件,允许你在 QML 中表现视频,处置处罚播放、停息、音量调节、播放控制等功能。查询资料,相当于在qt里装了vlc这个播放器,资源斲丧会很大.
安装编译流程如下.在linux上编译vlc-qtgithub
下载源码,下载cmake,新建一个build文件夹,cd进去,实行代码 cmake .. -DCMAKE_BUILD_TYPE=Debug
遇到报错,没有qt5Coreconfig,运行 sudo apt-get install qtdeclarative5-dev举行安装

遇到报错 Could not find libVLC,实行以下代码
  1. sudo apt-get update  
  2. sudo apt-get install libvlc-dev libvlccore-dev
复制代码

实行完 cmake .. -DCMAKE_BUILD_TYPE=Debug,生成了一些文件,接着实行
  1. sudo make -j8
  2. sudo make install
复制代码
安装完成后就能在src文件夹里看到这几个文件夹,把这几个文件夹里的.so文件都移植到自己的项目

使用它的exmpale,克隆 https://github.com/vlc-qt/examples.git
把9个.so文件复制到lib文件夹,修改simpleplayer的src.pro文件为你编译的路径和lib文件夹,运行就能看到拉流视频
  1. LIBS       += -lVLCQtCore -lVLCQtWidgets
  2. # Edit below for custom library location
  3. LIBS       += -L/home/bft/vlc-qt/build/lib -lVLCQtCore -lVLCQtWidgets
  4. INCLUDEPATH += /home/bft/vlc-qt/build/include
复制代码

3.3 思路 3 qmlsink

qmlglsink 基于 OpenGL 来渲染视频帧。它利用 QML 的 OpenGL 支持,将接收到的视频数据直接传输给 GPU 举行渲染。视频数据通常是通过 GStreamer 管道解码和转换为 OpenGL 可以处置处罚的格式(如 NV12 或 RGBA)。它可以将 OpenGL 渲染的内容嵌入到 QML 中的 Item 上。
qmlsink官方demogithub,可以很容易的跑通,必要安装gstreamer-qt的相干库.
主要流程如下

主要用到的RTP拉流管道代码 "udpsrc uri=udp://224.224.224.224:5000 caps=\"application/x-rtp,media=video,encoding-name=H264\" ! rtph264depay ! h264parse ! mppvideodec ! glupload ! glcolorconvert ! qmlglsink name=sink0"
摄像头拉流代码 "v4l2src device=/dev/video0 ! image/jpeg,width=1920,height=1080,framerate=15/1 ! mppjpegdec fast-mode=true ! glupload ! glcolorconvert ! qmlglsink name=sink0"
由于摄像头直接来流只能够拉取一起,所以是把摄像头的流先推流在拉取9路,代码和上边RTP拉流的代码一样
3.3.1 表现多路RTP视频

多路表现RTP视频着实跟表现一个是一样的,就是把所有的步骤都在来一遍,同时在qml里创建多个VideoItem组件
3.3.1.1 方法一 使用一个函数createPipeline创建管道

main.cpp
  1. void createPipeline(GstElement **pipeline, GstElement **src, GstElement **rtp_h264_depay, GstElement **h264_parse, GstElement **decoder, GstElement **videorate, GstElement **capsfilter1, GstElement **capsfilter2, GstElement **glupload, GstElement **glcolorconvert, GstElement **sink)
  2. {
  3.     // 创建一个新的 GStreamer 管道
  4.     *pipeline = gst_pipeline_new(NULL);
  5.   
  6.     // 创建 UDP 源元素
  7.     *src = gst_element_factory_make("udpsrc", NULL);
  8.     g_assert(src);
  9.     // 创建 RTP H.264 depayload 元素
  10.     *rtp_h264_depay = gst_element_factory_make("rtph264depay", NULL);
  11.     g_assert(rtp_h264_depay);
  12.     // 创建 H.264 解析器
  13.     *h264_parse = gst_element_factory_make("h264parse", NULL);
  14.     g_assert(h264_parse);
  15.     // 创建解码器(mpp 视频解码器)
  16.     *decoder = gst_element_factory_make("mppvideodec", NULL);
  17.     g_assert(decoder);
  18.     // 创建两个 CapsFilter,用于设置过滤条件
  19.     *capsfilter1 = gst_element_factory_make("capsfilter", NULL);
  20.     *capsfilter2 = gst_element_factory_make("capsfilter", NULL);
  21.     // 创建 OpenGL 上传和颜色转换元素
  22.     *glupload = gst_element_factory_make("glupload", NULL);
  23.     g_assert(glupload);
  24.     *glcolorconvert = gst_element_factory_make("glcolorconvert", NULL);
  25.     g_assert(glcolorconvert);
  26.     // 创建 QML 的视频渲染元素
  27.     *sink = gst_element_factory_make("qmlglsink", NULL);
  28.     g_assert(sink);
  29.     // 设置 sink 属性
  30.     g_object_set(G_OBJECT(*sink), "sync", FALSE, NULL);
  31.     // 设置 UDP 源的属性,包括 URI 和缓冲区大小
  32.     g_object_set(G_OBJECT(*src), "uri", "udp://224.224.224.224:5000", NULL);
  33.     g_object_set(G_OBJECT(*src), "buffer-size", "2097152", NULL);
  34.     // 设置 RTP caps 的过滤条件
  35.     GstCaps *rtpCaps = gst_caps_from_string("application/x-rtp,media=video,encoding-name=H264");
  36.     g_object_set(*capsfilter1, "caps", rtpCaps, NULL);
  37.     // 设置帧率过滤条件
  38.     GstCaps *scaleCaps = gst_caps_from_string("video/x-raw,framerate=15/1");
  39.     g_object_set(*capsfilter2, "caps", scaleCaps, NULL);
  40.     // 创建 videorate 元素,用于调整视频帧率
  41.     *videorate = gst_element_factory_make("videorate", NULL);
  42. }
  43. // 递归打印 QML 项目树
  44. void printChildren(QQuickItem *item, int depth = 0)
  45. {
  46.     QString indent = QString(" ").repeated(depth * 2);
  47.     qDebug() << indent + item->objectName();
  48.     // 遍历所有子项并递归打印
  49.     for (QQuickItem *child : item->childItems())
  50.     {
  51.         printChildren(child, depth + 1);
  52.     }
  53. }
  54. int main(int argc, char *argv[])
  55. {
  56.     int ret;
  57.     // 设置 QML 使用的 CPU 线程数
  58.     setenv("QML_CPU_THREAD_COUNT", "4", 1);
  59.     // 初始化 GStreamer 库
  60.     gst_init(&argc, &argv);
  61.     // 使用 Qt Quick 创建 GUI 应用
  62.     QGuiApplication app(argc, argv);
  63.     // 定义多个管道和其相关元素
  64.     GstElement *pipeline1, *src1, *rtp_h264_depay1, *h264_parse1, *decoder1, *videorate1, *capsfilter1_1, *capsfilter1_2, *glupload1, *glcolorconvert1, *sink1;
  65.     GstElement *pipeline2, *src2, *rtp_h264_depay2, *h264_parse2, *decoder2, *videorate2, *capsfilter2_1, *capsfilter2_2, *glupload2, *glcolorconvert2, *sink2;
  66.     // 初始化多个管道
  67.     createPipeline(&pipeline1, &src1, &rtp_h264_depay1, &h264_parse1, &decoder1, &videorate1, &capsfilter1_1, &capsfilter1_2, &glupload1, &glcolorconvert1, &sink1);
  68.     createPipeline(&pipeline2, &src2, &rtp_h264_depay2, &h264_parse2, &decoder2, &videorate2, &capsfilter2_1, &capsfilter2_2, &glupload2, &glcolorconvert2, &sink2);
  69.     // 将元素添加到相应管道中
  70.     gst_bin_add_many(GST_BIN(pipeline1), src1, capsfilter1_1, rtp_h264_depay1, h264_parse1, decoder1, videorate1, capsfilter1_2, glupload1, glcolorconvert1, sink1, NULL);
  71.     gst_bin_add_many(GST_BIN(pipeline2), src2, capsfilter2_1, rtp_h264_depay2, h264_parse2, decoder2, videorate2, capsfilter2_2, glupload2, glcolorconvert2, sink2, NULL);
  72.     // 链接管道内的所有元素
  73.     if (!gst_element_link_many(src1, capsfilter1_1, rtp_h264_depay1, h264_parse1, decoder1, videorate1, capsfilter1_2, glupload1, glcolorconvert1, sink1, NULL))
  74.     {
  75.         g_print("Failed to link elements in pipeline 1\n");
  76.     }
  77.     gst_element_link_many(src2, capsfilter2_1, rtp_h264_depay2, h264_parse2, decoder2, videorate2, capsfilter2_2, glupload2, glcolorconvert2, sink2, NULL);
  78.     // 加载 QML 界面
  79.     QQmlApplicationEngine engine;
  80.     engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
  81.     QQuickWindow *rootObject = static_cast<QQuickWindow *>(engine.rootObjects().first());
  82.     printChildren(rootObject->contentItem()); // 打印 QML 项目结构
  83.     QTimer::singleShot(10000, [&engine, &sink1, &sink2,
  84.                           &pipeline1, &pipeline2,
  85.                           &videoItem1, &videoItem2, ]() {
  86.     // 获取 QML 应用的根对象
  87.     QQuickWindow *rootObject = static_cast<QQuickWindow *>(engine.rootObjects().first());
  88.     // 打印 QML 的子项结构,方便调试
  89.     printChildren(rootObject->contentItem());
  90.     // 从 QML 对象中查找名为 "videoItem1" 至 "videoItem4" 的 QQuickItem
  91.     videoItem1 = rootObject->findChild<QQuickItem *>("videoItem1");
  92.     g_assert(videoItem1); // 确保找到 videoItem1,否则程序会中止
  93.     videoItem2 = rootObject->findChild<QQuickItem *>("videoItem2");
  94.     // 将找到的 QQuickItem 设置到对应的 GStreamer sink 上
  95.     g_object_set(sink1, "widget", videoItem1, NULL);
  96.     g_object_set(sink2, "widget", videoItem2, NULL);
  97.     // 使用 QQuickWindow 的渲染任务机制设置管道状态为播放
  98.     // 在渲染同步阶段之前执行 SetPlaying 操作
  99.     rootObject->scheduleRenderJob(new SetPlaying(pipeline1), QQuickWindow::BeforeSynchronizingStage);
  100.     rootObject->scheduleRenderJob(new SetPlaying(pipeline2), QQuickWindow::BeforeSynchronizingStage);
  101.         });
  102.     // 启动应用程序事件循环
  103.     ret = app.exec();
  104.     // 退出事件循环后,清理 GStreamer 管道资源
  105.     // 将所有管道设置为 NULL 状态以释放资源
  106.     gst_element_set_state(pipeline1, GST_STATE_NULL);
  107.     gst_element_set_state(pipeline2, GST_STATE_NULL);
  108.     // 释放管道对象的引用
  109.     gst_object_unref(pipeline1);
  110.     gst_object_unref(pipeline2);
  111.     // 关闭 GStreamer
  112.     gst_deinit();
  113.     return ret;
  114. }
复制代码
3.3.1.2 方法二 使用管道字符串(更简单)

通过循环来创建管道和元素,淘汰代码量,修改方便
main.cpp
  1. #define MAX_CHANNEL (9)  // 定义最大的视频流通道数(9路视频流)
  2. // 这些是GStreamer命令,用于从UDP流中拉取视频流并显示
  3. const char gstLaunchCmd[][600]=
  4. {
  5.     "udpsrc uri=udp://224.224.224.224:5000 buffer-size=2097152 caps="application/x-rtp,media=video,encoding-name=H264" ! rtph264depay ! queue ! h264parse ! mppvideodec fast-mode=true ! videoscale ! video/x-raw,width=640,height=480 ! glupload ! glcolorconvert ! qmlglsink name=sink0",
  6.     "udpsrc uri=udp://224.224.224.224:5000 buffer-size=2097152 caps="application/x-rtp,media=video,encoding-name=H264" ! rtph264depay ! queue ! h264parse ! mppvideodec fast-mode=true ! videoscale ! video/x-raw,width=640,height=480 ! glupload ! glcolorconvert ! qmlglsink name=sink1",
  7.     "udpsrc uri=udp://224.224.224.224:5000 buffer-size=2097152 caps="application/x-rtp,media=video,encoding-name=H264" ! rtph264depay ! queue ! h264parse ! mppvideodec fast-mode=true ! videoscale ! video/x-raw,width=640,height=480 ! glupload ! glcolorconvert ! qmlglsink name=sink2",
  8.     "udpsrc uri=udp://224.224.224.224:5000 buffer-size=2097152 caps="application/x-rtp,media=video,encoding-name=H264" ! rtph264depay ! queue ! h264parse ! mppvideodec fast-mode=true ! videoscale ! video/x-raw,width=640,height=480 ! glupload ! glcolorconvert ! qmlglsink name=sink3",
  9.     "udpsrc uri=udp://224.224.224.224:5000 buffer-size=2097152 caps="application/x-rtp,media=video,encoding-name=H264" ! rtph264depay ! queue ! h264parse ! mppvideodec fast-mode=true ! glupload ! glcolorconvert ! qmlglsink name=sink4",
  10.     "udpsrc uri=udp://224.224.224.224:5000 buffer-size=2097152 caps="application/x-rtp,media=video,encoding-name=H264" ! rtph264depay ! queue ! h264parse ! mppvideodec fast-mode=true ! glupload ! glcolorconvert ! qmlglsink name=sink5",
  11.     "udpsrc uri=udp://224.224.224.224:5000 buffer-size=2097152 caps="application/x-rtp,media=video,encoding-name=H264" ! rtph264depay ! queue ! h264parse ! mppvideodec fast-mode=true ! glupload ! glcolorconvert ! qmlglsink name=sink6",
  12.     "udpsrc uri=udp://224.224.224.224:5000 buffer-size=2097152 caps="application/x-rtp,media=video,encoding-name=H264" ! rtph264depay ! queue ! h264parse ! mppvideodec fast-mode=true ! glupload ! glcolorconvert ! qmlglsink name=sink7",
  13.     "udpsrc uri=udp://224.224.224.224:5000 buffer-size=2097152 caps="application/x-rtp,media=video,encoding-name=H264" ! rtph264depay ! queue ! h264parse ! mppvideodec fast-mode=true ! glupload ! glcolorconvert ! qmlglsink name=sink8"
  14. };
  15. // 定义每个视频通道的GStreamer元素名称
  16. const char sinkName[][20]=
  17. {
  18.     "sink0", "sink1", "sink2", "sink3", "sink4", "sink5", "sink6", "sink7", "sink8"
  19. };
  20. // 每个视频Item的名称,用于在QML中查找并绑定
  21. const char videoItemName[][20]=
  22. {
  23.     "videoItem0", "videoItem1", "videoItem2", "videoItem3", "videoItem4", "videoItem5", "videoItem6", "videoItem7", "videoItem8"
  24. };
  25. // 用于设置视频流播放状态的线程类
  26. class SetPlaying : public QRunnable
  27. {
  28. public:
  29.   SetPlaying(GstElement *);  // 构造函数,接收GStreamer元素
  30.   ~SetPlaying();             // 析构函数
  31.   void run ();  // 执行设置播放状态的函数
  32. private:
  33.   GstElement * pipeline_;  // GStreamer管道
  34. };
  35. // 构造函数,初始化pipeline指针
  36. SetPlaying::SetPlaying (GstElement * pipeline)
  37. {
  38.   this->pipeline_ = pipeline ? static_cast<GstElement *> (gst_object_ref (pipeline)) : NULL;
  39. }
  40. // 析构函数,释放资源
  41. SetPlaying::~SetPlaying ()
  42. {
  43.   if (this->pipeline_)
  44.     gst_object_unref (this->pipeline_);
  45. }
  46. // 运行方法,设置GStreamer管道的播放状态为`PLAYING`
  47. void
  48. SetPlaying::run ()
  49. {
  50.   if (this->pipeline_)
  51.     gst_element_set_state (this->pipeline_, GST_STATE_PLAYING);
  52. }
  53. // 递归打印QQuickItem及其子项(用于调试查看QML树结构)
  54. void printChildren(QQuickItem *item ,int depth = 0)
  55. {
  56.     QString indent = QString(" ").repeated(depth*2);  // 添加缩进
  57.     qDebug() << indent + item->objectName();  // 打印当前项的名称
  58.     // 递归打印所有子项
  59.     for(QQuickItem *child : item->childItems())
  60.     {
  61.         printChildren(child, depth + 1);
  62.     }
  63. }
  64. int main(int argc, char *argv[])
  65. {
  66.   int ret;
  67.   // 设置多线程环境变量
  68.   setenv("QML_CPU_THREAD_COUNT","4",1);
  69.   gst_init (&argc, &argv);  // 初始化GStreamer
  70.   {
  71.     QGuiApplication app(argc, argv);  // 创建Qt应用程序
  72.     GstElement *pipeline[MAX_CHANNEL];  // 用于存储每路视频流的管道
  73.     GstElement *sink[MAX_CHANNEL];      // 用于存储每路视频流的渲染sink
  74.     // 遍历所有视频通道,初始化管道并启动播放
  75.     for(int i = 0; i < MAX_CHANNEL; i++)
  76.     {
  77.         // 通过解析GStreamer命令字符串来创建每个视频流的管道
  78.         pipeline[i] = gst_parse_launch(gstLaunchCmd[i], NULL);
  79.   
  80.         // 获取视频渲染sink元素(与GStreamer命令中的sink名称一致)
  81.         sink[i] = gst_bin_get_by_name(GST_BIN(pipeline[i]), sinkName[i]);
  82.   
  83.         // 启动视频流的播放
  84.         gst_element_set_state(pipeline[i], GST_STATE_PLAYING);
  85.     }
  86.     QQmlApplicationEngine engine;  // 创建QML应用引擎
  87.     engine.load(QUrl(QStringLiteral("qrc:/main.qml")));  // 加载QML文件
  88.     QQuickItem *videoItem[MAX_CHANNEL];  // 用于存储每路视频的QML项
  89.     QQuickWindow *rootObject = static_cast<QQuickWindow *> (engine.rootObjects().first());  // 获取QML的根对象
  90.     printChildren(rootObject->contentItem());  // 打印QML树结构(调试)
  91.     // 遍历所有视频通道,找到对应的QML项并绑定GStreamer的sink元素
  92.     for(int i = 0; i < MAX_CHANNEL; i++)
  93.     {
  94.         // 查找QML中与视频通道相关的项
  95.         videoItem[i] = rootObject->findChild<QQuickItem *>(videoItemName[i]);
  96.         g_assert(videoItem[i]);  // 确保QML项被正确找到
  97.         // 设置GStreamer的sink元素,指向对应的视频QML项
  98.         g_object_set(sink[i], "widget", videoItem[i], NULL);
  99.         // 在渲染前将播放状态设置为`PLAYING`,确保视频能够播放
  100.         rootObject->scheduleRenderJob(new SetPlaying(pipeline[i]), QQuickWindow::BeforeRenderingStage);
  101.     }
  102.     ret = app.exec();  // 启动Qt应用事件循环
  103.     // 退出时停止每路视频流的播放并释放资源
  104.     for(int i = 0; i < MAX_CHANNEL; i++)
  105.     {
  106.         gst_element_set_state(pipeline[i], GST_STATE_NULL);  // 停止播放
  107.         gst_object_unref(pipeline[i]);  // 释放GStreamer管道资源
  108.     }
  109.   }
  110.   gst_deinit ();  // 清理GStreamer资源
  111.   return ret;  // 返回程序的退出状态
  112. }
复制代码
3.3.2 popup弹窗表现RTP视频流

一开始直接在popup里嵌入videoItem运行代码不表现.就开始思考是不是main.cpp里没有绑定上videoitem
在main.cpp打印了rootObject初始的item,可以看到只有一个,popup和它里边的videoItem组件根本就不表现
  1. void printChildren(QQuickItem *item, int depth = 0) {
  2.     // 打印当前项的名称
  3.     QString indent = QString(" ").repeated(depth * 2);
  4.     qDebug() << indent + item->objectName();
  5.     // 递归遍历所有子项
  6.     for (QQuickItem *child : item->childItems()) {
  7.         printChildren(child, depth + 1);
  8.     }
  9. }
  10. QQuickWindow *rootObject = static_cast<QQuickWindow *>(engine.rootObjects().first());
  11.         printChildren(rootObject->contentItem());
复制代码

手动打开弹窗,耽误10s打印就是找到了,也就是说弹窗界面不出现,rootobject就找不到在popup的videoitem2,所以也就播放不了视频

将探求,绑定和播放的代码放入延时里,我们打开弹窗,等待一会就可以望见popup表现了视频
  1. QTimer::singleShot(10000, [&engine,&sink2,&pipeline2](){
  2.             QQuickWindow *rootObject = static_cast<QQuickWindow *>(engine.rootObjects().first());
  3.             printChildren(rootObject->contentItem());
  4.             QQuickItem* videoItem2 = rootObject->findChild<QQuickItem*>("videoItem2");
  5.             g_object_set(sink2, "widget", videoItem2, nullptr);
  6.             rootObject->scheduleRenderJob(new SetPlaying(pipeline2), QQuickWindow::BeforeSynchronizingStage);
  7.         });
复制代码

通过Repeater重复生成的videItem,rootObject延时也拿不到,9路只能是一个个创建
main.qml
  1.    Popup{
  2.        id:videopopup
  3.        width:parent.width*0.8
  4.        height:parent.height*0.8
  5.        focus:true;
  6.        objectName:"popup"
  7.        Column{
  8.            spacing:10
  9.            anchors.fill:parent
  10.            Repeater{
  11.                id:firstrepeater
  12.                model:3
  13.                delegate:Row{
  14.                    property int rowIndex :modelData
  15.                    spacing:10
  16.                    Repeater{
  17.                        model:3
  18.                            GstGLVideoItem {
  19.                                anchors.centerIn:parent
  20.                                objectName: "videoItem"+(index+1+rowIndex*3)
  21.                                width:parent.width/3
  22.                                height:parent.height/3
  23.                        }
  24.                    }
  25.                }
  26.            }
  27.        }
复制代码
3.3.3 拉流视频优化

在拉流的过程中出现了视频卡顿,CPU占用率高的问题,一些优化会淘汰卡顿,但会增长cpu斲丧
1.在src设置 buffer-size 来调整缓冲区巨细 uri=udp://224.224.224.224:5000 buffer-size=1048576
2.rtpjitterbuffer 元素用于缓冲 RTP 数据包以应对网络抖动。latency 参数指定了缓冲区的巨细(以毫秒为单位),其作用是允许一定时间的耽误来确保平滑播放.设置后视频会丝滑一些,但会增长cpu斲丧
3.videoscale元素来调整视频分辨率和帧率.videoscale ! video/x-raw,width=640,height=480,framerate=15/1
4.使用 queue元素可以在不同的处置处罚阶段之间引入缓冲区,减缓数据流的速率,避免瓶颈。! rtph264depay! queue ! h264parse !
5.设置 sink的时钟同步属性. sync=true:当渲染速率跟不上播放时,qmlglsink 会丢弃一些过时的帧,以保持与时间的同步,避免耽误堆积,cpu斲丧小,看着流畅一些。sync=false:所有帧都尽可能渲染,可能导致视频卡顿或播放耽误渐渐累积,cpu斲丧大,对于大分辨率的视频会直接卡住。
4 最闭幕果

qmlglsink使用 OpenGL 渲染帧,帧作为纹理嵌入到QML 场景中,与其他 QML 图形叠加,资源斲丧大,得当1-4路视频。
waylandsink直接使用 Wayland 渲染帧,视频输出到独立的 Wayland 表面,直接调用系统播放器,资源斲丧小。
相比于qmlglsink,waylandsink直接调用系统播放器,cpu斲丧小,更流畅
分辨率,帧率%cpuRES视觉结果一推9解,摄像头,qmlglsink640*480,15160360M流畅800*600,15230430M流畅1280*720,15260600M一些卡顿1920*1080,153201.1g明显卡顿2路1080p120350M一些卡顿+rtpjitterbuffer latency=100250350M流畅1推9解摄像头,waylandsink1280*720,1570100M流畅1920*1080,15110170M流畅 额外

开发版检察gpu频率

最高频率800Mhz cat /sys/devices/platform/fde60000.gpu/devfreq/fde60000.gpu/load
检察cpu等参数,top按下大写P参数列表会从高到低排列
在终端表现帧率

  1. std::chrono::steady_clock::time_point last_frame_time;
  2. int frame_count = 0;
  3. static GstPadProbeReturn frame_probe_callback(GstPad *pad, GstPadProbeInfo *info, gpointer user_data) {
  4.     auto now = std::chrono::steady_clock::now();
  5.     frame_count++;
  6.     if (last_frame_time.time_since_epoch().count() > 0) {
  7.         auto duration = std::chrono::duration_cast[std::chrono::milliseconds](std::chrono::milliseconds)(now - last_frame_time).count();
  8.         if (duration > 1000) {
  9.             float fps = frame_count * 1000.0 / duration;
  10.             g_print("FPS: %.2f\n", fps);
  11.             frame_count = 0;
  12.             last_frame_time = now;
  13.         }
  14.     } else {
  15.         last_frame_time = now;
  16.     }
  17.     return GST_PAD_PROBE_OK;
  18. }
  19. // 在链接 glcolorconvert 和 sink 后添加帧探针
  20. GstPad *pad = gst_element_get_static_pad(glcolorconvert, "src");
  21. gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER, frame_probe_callback, NULL, NULL);
  22. gst_object_unref(pad);
复制代码
vlc推拉流

首先先能够获取到RTP流,VLC->媒体->串流->添加一个视屏文件->选择RTP点击添加一个

ip输入224.224.224.224,取消激活转码转码->选择video-h264

播放的话,打开一个新的vlc,打开网络串流,输入 rtp://224.224.224.224:5004

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

卖不甜枣

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表