├── README.md ├── doc ├── DataFlowDiagram.png ├── Pipeline.png └── rtsp流媒体服务器汇总文档.docx ├── src ├── Makefile ├── README.md ├── cmdinput ├── cmdinput.cpp ├── config.ini ├── debug.sh ├── debug_viewer.sh ├── start ├── start.cpp ├── start_gpu ├── start_gpu.cpp └── test_gpu │ ├── Makefile │ ├── README.md │ ├── main.out │ └── opencv_cuda.cpp ├── test.py └── test_udp_jpegenc.cpp /README.md: -------------------------------------------------------------------------------- 1 | # RTSP流媒体服务器 2 | 3 | 1. 利用opencv videoCapture实现RTSP解码; 4 | 2. 实现对解码出的cv::Mat帧进行处理,如区域选择; 5 | 3. 实现对解码出的cv::Mat帧进行本地存储; 6 | 4. 基于Gstreamer的gst-rtsp-server套件实现对Mat帧进行H.264编码、组流、推流至服务器指指定url(端口、index); 7 | 5. 利用互斥线程锁将解码、处理、编码、组流等步骤封装成管线,每一路管线对应一路RTSP流; 8 | 6. 利用多进程管理实现同时处理多路流; 9 | 7. 交叉编译opencv和cuda,使用nvidia video codec sdk加速RTSP解码,解放CPU资源、降低延迟; 10 | 8. 通过init配置文件启动系统,其中包括rtsp路数以及每一路流各自的参数; 11 | 12 | # 系统数据流图如下 13 | 14 | ![系统数据流图](https://github.com/chicleee/rtsp-server/blob/master/doc/DataFlowDiagram.png) 15 | 16 | # 每一路RTSP流的处理管线如下 17 | 18 | ![管线](https://github.com/chicleee/rtsp-server/blob/master/doc/Pipeline.png) 19 | 20 | # 结果 21 | 22 | 本RTSP流媒体服务器实现了预期的系统功能,但由于cv::Ptr解码一路4K的RTSP视频流需要占用580M的显存,解码一路1080P的视频流需要约200M的显存,故在11GB显存的1080Ti显卡上,最多只能同时处理18路4K流、或者50路1080P流。 23 | 24 | # 源码请见src 25 | # 详细文档请见doc 26 | -------------------------------------------------------------------------------- /doc/DataFlowDiagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicleee/rtsp-server/3b9230dc13d9f5302c4b8749a8702d0f9b19d9bc/doc/DataFlowDiagram.png -------------------------------------------------------------------------------- /doc/Pipeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicleee/rtsp-server/3b9230dc13d9f5302c4b8749a8702d0f9b19d9bc/doc/Pipeline.png -------------------------------------------------------------------------------- /doc/rtsp流媒体服务器汇总文档.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicleee/rtsp-server/3b9230dc13d9f5302c4b8749a8702d0f9b19d9bc/doc/rtsp流媒体服务器汇总文档.docx -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | opencv_cuda.o:opencv_cuda.cpp 2 | g++ -std=c++11 -g -o main.out opencv_cuda.cpp `pkg-config opencv4 --cflags --libs` \ 3 | -I/usr/local/opencv4/include/opencv4/opencv2 \ 4 | -I/usr/local/cuda/include \ 5 | -L/usr/local/cuda/lib64 \ 6 | -I/usr/include/eigen3 \ 7 | -L/usr/lib/x86_64-linux-gnu -lcuda -ldl -lnvcuvid 8 | 9 | clean: 10 | rm *.o main.out 11 | 12 | -------------------------------------------------------------------------------- /src/README.md: -------------------------------------------------------------------------------- 1 | 其中有以下重要文件, 2 | 3 | 1)Start.cpp是只使用CPU的版本 4 | 5 | 编译命令: 6 | g++ -std=c++11 start.cpp -o start -lboost_system -lboost_filesystem -lpthread -lgstapp-1.0 `pkg-config --libs --cflags opencv gstreamer-1.0 gstreamer-rtsp-server-1.0` 7 | 8 | 运行命令: 9 | ./start 10 | 11 | 2)start_gpu.cpp是GPU版本 12 | 13 | 编译命令: 14 | g++ -std=c++11 start_gpu.cpp -g -o start_gpu -lboost_system -lboost_filesystem -lpthread -lgstapp-1.0 `pkg-config --libs --cflags opencv4 gstreamer-1.0 gstreamer-rtsp-server-1.0` \ 15 | -I/usr/local/opencv4/include/opencv4/opencv2 \ 16 | -I/usr/local/cuda/include \ 17 | -L/usr/local/cuda/lib64 \ 18 | -I/usr/include/eigen3 \ 19 | -L/usr/lib/x86_64-linux-gnu -lcuda -ldl -lnvcuvid 20 | 21 | 运行命令: 22 | ./start_gpu 23 | 24 | 3)Config.ini是系统的配置文件 25 | -------------------------------------------------------------------------------- /src/cmdinput: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicleee/rtsp-server/3b9230dc13d9f5302c4b8749a8702d0f9b19d9bc/src/cmdinput -------------------------------------------------------------------------------- /src/cmdinput.cpp: -------------------------------------------------------------------------------- 1 | //compile: g++ -std=c++11 cmdinput.cpp -o cmdinput -lpthread -lgstapp-1.0 `pkg-config --libs --cflags opencv gstreamer-1.0 gstreamer-rtsp-server-1.0` 2 | //cmd : ./cmdinput "0" "rtsp://admin:kuangping108@192.168.1.64/h264/ch1/main/av_stream" 1280 720 1 "10000" 3 | //view: gst-launch-1.0 rtspsrc location=rtsp://127.0.0.1:10000/index/0 latency=10 ! rtph264depay ! avdec_h264 ! videoconvert ! autovideosink 4 | //vlc rtsp://127.0.0.1:10000/index/0 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | // //config 28 | // #include 29 | // #include 30 | // #include 31 | // #include 32 | 33 | #include 34 | 35 | // #include 36 | // #include 37 | // #include 38 | 39 | //vector xContours; 40 | //vector saveContours; 41 | 42 | //debug: 43 | /* 44 | #define GST_CAT_DEFAULT appsrc_pipeline_debug 45 | GST_DEBUG_CATEGORY (appsrc_pipeline_debug); 46 | //GST_DEBUG_CATEGORY (pipeline_debug); 47 | */ 48 | 49 | using namespace std; 50 | using namespace cv; 51 | 52 | 53 | //paramates 54 | // #define cameraWidth 1280 55 | // #define cameraHeight 720 56 | // #define outFps 5 57 | // #define inputRtsp "rtsp://admin:kuangping108@192.168.1.64/h264/ch1/main/av_stream" 58 | // #define RTSP_PORT "8554" 59 | // #define index "0" 60 | 61 | 62 | static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; //创建互斥进程 63 | GMainLoop *loop; 64 | typedef struct _App App; 65 | 66 | //用于gstreamer线程的结构:: 67 | struct _App{ 68 | GstElement *ffmpeg; 69 | //GstElement *ffmpeg2; 70 | //GstElement *rtppay, *gdppay; 71 | GstElement *rtppay; 72 | GstElement *videoenc; 73 | GstElement *videosrc; 74 | GstElement *sink; 75 | GstElement *videoscale; 76 | GstElement *filter; 77 | guint sourceid; 78 | GstElement *queue; 79 | GTimer *timer; 80 | }; 81 | 82 | typedef struct 83 | { 84 | string INDEX; 85 | string in_rtsp; 86 | int out_width; 87 | int out_height; 88 | int out_fps; 89 | string out_port; 90 | } Params; 91 | 92 | App s_app; 93 | 94 | typedef struct 95 | { 96 | gboolean white; 97 | GstClockTime timestamp; 98 | int out_width; 99 | int out_height; 100 | int out_fps; 101 | string INDEX; 102 | } MyContext; 103 | 104 | int counter = 0; 105 | 106 | //两个线程之间共享的帧: 107 | Mat frameimage; 108 | 109 | //"example of frame-processing" 110 | void processing( Mat frame ) 111 | { 112 | srand((int)time(0)); 113 | 114 | int dynamic = rand()%200; 115 | //cout<<"dynamic rand:"<INTER_CUBIC>INTER_AREA 143 | //缩小图像,避免出现波纹现象通常使用#INTER_AREA;放大图像通常使用INTER_CUBIC(速度较慢,但效果最好),或INTER_LINEAR(速度较快,效果还可以)。INTER_NEAREST,一般不推荐 144 | resize(frameimage,frameimage,Size(int(ctx->out_width), int(ctx->out_height)),0,0,INTER_AREA); 145 | 146 | /* frame image processing */ 147 | processing( frameimage ); 148 | 149 | 150 | 151 | 152 | /* allocate buffer */ 153 | buffersize = frameimage.cols * frameimage.rows * frameimage.channels(); 154 | //cout<<"frameimage.cols:"<white = !ctx->white; 168 | 169 | //increment the timestamp every {duration = 1/outFps} second 170 | GST_BUFFER_PTS (buffer) = ctx->timestamp; 171 | // std::cout<<"Gctx->timestamp:"<< ctx->timestamp <out_fps)); 173 | ctx->timestamp += GST_BUFFER_DURATION (buffer); 174 | 175 | //std::cout<<"GST_BUFFER_DURATION (buffer):"<INDEX<<" Frame:"<white = FALSE; 241 | ctx->timestamp = 0; 242 | ctx->out_fps = p.out_fps; 243 | ctx->out_width = p.out_width; 244 | ctx->out_height = p.out_height; 245 | ctx->INDEX = p.INDEX; 246 | 247 | 248 | /* make sure ther datais freed when the media is gone */ 249 | g_object_set_data_full (G_OBJECT (media), "my-extra-data", ctx, 250 | (GDestroyNotify) g_free); 251 | 252 | /* install the callback that will be called when a buffer is needed */ 253 | g_signal_connect (appsrc, "need-data", (GCallback) need_data, ctx); 254 | //g_signal_connect (appsrc, "need-data", G_CALLBACK (start_feed), ); 255 | //g_signal_connect (appsrc, "enough-data", G_CALLBACK (stop_feed), ); 256 | gst_object_unref (appsrc); 257 | gst_object_unref (element); 258 | } 259 | 260 | 261 | /***** 262 | thread2: push stream 263 | */ 264 | void *thread2new(void *arg){ 265 | Params p = *((Params*)arg); 266 | App * app = &s_app; 267 | GstCaps * caps2; 268 | GstCaps * caps3; 269 | GstFlowReturn ret; 270 | //GstBus *bus; 271 | GstElement *pipeline; 272 | 273 | GstRTSPServer *server; 274 | GstRTSPMountPoints *mounts; 275 | GstRTSPMediaFactory *factory; 276 | 277 | gst_init (NULL,NULL); 278 | loop = g_main_loop_new (NULL, FALSE); 279 | server = gst_rtsp_server_new (); 280 | g_object_set (server, "service", p.out_port.c_str(), NULL); 281 | mounts = gst_rtsp_server_get_mount_points (server); 282 | 283 | factory = gst_rtsp_media_factory_new (); 284 | char *outAppsrc = new char[200]; 285 | sprintf(outAppsrc, "( appsrc name=mysrc is-live=true block=true format=GST_FORMAT_TIME caps=video/x-raw,format=BGR,width=%d,height=%d,framerate=%d/1 ! videoconvert ! video/x-raw,format=I420 ! x264enc speed-preset=ultrafast tune=zerolatency ! rtph264pay config-interval=1 name=pay0 pt=96 )", 286 | int(p.out_width), int(p.out_height), int(p.out_fps)); 287 | gst_rtsp_media_factory_set_launch (factory, outAppsrc); 288 | 289 | g_signal_connect (factory, "media-configure", (GCallback) media_configure, (void*)&p); 290 | //g_signal_connect (app->videosrc, "need-data", G_CALLBACK (start_feed), app); 291 | //g_signal_connect (app->videosrc, "enough-data", G_CALLBACK (stop_feed),app); 292 | 293 | char index_url[16] = {0}; 294 | /* attach the test factory to the /test url */ 295 | sprintf(index_url, "/index/%s", p.INDEX.c_str()); 296 | gst_rtsp_mount_points_add_factory (mounts, index_url, factory); 297 | g_print ("stream ready at rtsp://127.0.0.1:%s%s\n",p.out_port.c_str(),index_url); 298 | 299 | 300 | /* don't need the ref to the mounts anymore */ 301 | g_object_unref (mounts); 302 | /* attach the server to the default maincontext */ 303 | gst_rtsp_server_attach (server, NULL); 304 | /* start serving */ 305 | g_main_loop_run (loop); 306 | pthread_exit(NULL); 307 | } 308 | 309 | /***** 310 | thread1: fetch stream 311 | */ 312 | void *thread1(void *arg){ 313 | Params p = *((Params*)arg); 314 | VideoCapture cap(p.in_rtsp); 315 | Mat tempframe, result; 316 | 317 | if (!cap.isOpened()) { 318 | throw "Error when reading steam from camera"; 319 | } 320 | int width = cap.get(CAP_PROP_FRAME_WIDTH); 321 | int height = cap.get(CAP_PROP_FRAME_HEIGHT); 322 | int frameRate = cap.get(CAP_PROP_FPS); 323 | int totalFrames = cap.get(CAP_PROP_FRAME_COUNT); 324 | 325 | cout<<"input_width="< paramatesList; 353 | Params paramates_each; 354 | 355 | Params paramates_1; 356 | 357 | paramates_1.INDEX = "0"; 358 | paramates_1.in_rtsp = "rtsp://admin:kuangping108@192.168.1.64/h264/ch1/main/av_stream"; 359 | paramates_1.out_width = 1280; 360 | paramates_1.out_height = 720; 361 | paramates_1.out_fps = 1; 362 | paramates_1.out_port = "10000"; 363 | 364 | 365 | for(int i = 0; i < argc; i++) 366 | { 367 | puts(argv[i]); 368 | } 369 | if (argc > 1) 370 | { 371 | paramates_1.INDEX = argv[1]; 372 | paramates_1.in_rtsp = argv[2]; 373 | paramates_1.out_width = atoi(argv[3]); 374 | paramates_1.out_height = atoi(argv[4]); 375 | paramates_1.out_fps = atoi(argv[5]); 376 | paramates_1.out_port = argv[6]; 377 | } 378 | 379 | int rc11, rc21; 380 | pthread_t CaptureImageThread1, StreamThread1; 381 | 382 | if( (rc11 = pthread_create(&CaptureImageThread1, NULL, thread1, (void*)¶mates_1)) ) 383 | cout << "Thread creation failed: " << rc11 << endl; 384 | if( (rc21 = pthread_create(&StreamThread1, NULL, thread2new, (void*)¶mates_1)) ) 385 | cout << "Thread creation failed: " << rc21 << endl; 386 | 387 | pthread_join( CaptureImageThread1, NULL ); 388 | pthread_join( StreamThread1, NULL ); 389 | 390 | cap.release(); 391 | return 0; 392 | }; 393 | -------------------------------------------------------------------------------- /src/config.ini: -------------------------------------------------------------------------------- 1 | [System] 2 | rtsp_camera=6 3 | 4 | [Camera0] 5 | INDEX=0 6 | in_rtsp=rtsp://admin:kuangping108@192.168.1.64/h264/ch1/main/av_stream 7 | out_port=8554 8 | out_fps=1 9 | out_width=1280 10 | out_height=720 11 | 12 | [Camera1] 13 | INDEX=0 14 | in_rtsp=1700 15 | out_port=8555 16 | out_fps=1 17 | out_width=1280 18 | out_height=720 19 | 20 | [Camera2] 21 | INDEX=0 22 | in_rtsp=1700 23 | out_port=8556 24 | out_fps=1 25 | out_width=1280 26 | out_height=720 27 | 28 | [Camera3] 29 | INDEX=0 30 | in_rtsp=1700 31 | out_port=8557 32 | out_fps=1 33 | out_width=1280 34 | out_height=720 35 | 36 | [Camera4] 37 | INDEX=0 38 | in_rtsp=1700 39 | out_port=8558 40 | out_fps=1 41 | out_width=1280 42 | out_height=720 43 | 44 | [Camera5] 45 | INDEX=0 46 | in_rtsp=1700 47 | out_port=8559 48 | out_fps=1 49 | out_width=1280 50 | out_height=720 51 | 52 | [Camera6] 53 | INDEX=0 54 | in_rtsp=1700 55 | out_port=8560 56 | out_fps=1 57 | out_width=1280 58 | out_height=720 59 | 60 | [Camera7] 61 | INDEX=0 62 | in_rtsp=1700 63 | out_port=8561 64 | out_fps=1 65 | out_width=1280 66 | out_height=720 67 | 68 | [Camera8] 69 | INDEX=0 70 | in_rtsp=1700 71 | out_port=8562 72 | out_fps=1 73 | out_width=1280 74 | out_height=720 75 | 76 | [Camera9] 77 | INDEX=0 78 | in_rtsp=1700 79 | out_port=8563 80 | out_fps=1 81 | out_width=1280 82 | out_height=720 83 | 84 | [Camera10] 85 | INDEX=0 86 | in_rtsp=1700 87 | out_port=8564 88 | out_fps=1 89 | out_width=1280 90 | out_height=720 91 | 92 | [Camera11] 93 | INDEX=0 94 | in_rtsp=1700 95 | out_port=8565 96 | out_fps=1 97 | out_width=1280 98 | out_height=720 99 | 100 | [Camera12] 101 | INDEX=0 102 | in_rtsp=1700 103 | out_port=8566 104 | out_fps=1 105 | out_width=1280 106 | out_height=720 107 | 108 | [Camera13] 109 | INDEX=0 110 | in_rtsp=1700 111 | out_port=8567 112 | out_fps=1 113 | out_width=1280 114 | out_height=720 115 | 116 | [Camera14] 117 | INDEX=0 118 | in_rtsp=1700 119 | out_port=8568 120 | out_fps=1 121 | out_width=1280 122 | out_height=720 123 | 124 | [Camera15] 125 | INDEX=0 126 | in_rtsp=1700 127 | out_port=8569 128 | out_fps=1 129 | out_width=1280 130 | out_height=720 131 | 132 | [Camera16] 133 | INDEX=0 134 | in_rtsp=1700 135 | out_port=8570 136 | out_fps=1 137 | out_width=1280 138 | out_height=720 139 | 140 | [Camera17] 141 | INDEX=0 142 | in_rtsp=1700 143 | out_port=8571 144 | out_fps=1 145 | out_width=1280 146 | out_height=720 147 | 148 | [Camera18] 149 | INDEX=0 150 | in_rtsp=1700 151 | out_port=8572 152 | out_fps=1 153 | out_width=1280 154 | out_height=720 155 | 156 | [Camera19] 157 | INDEX=0 158 | in_rtsp=1700 159 | out_port=8573 160 | out_fps=1 161 | out_width=1280 162 | out_height=720 163 | 164 | [Camera20] 165 | INDEX=0 166 | in_rtsp=1700 167 | out_port=8574 168 | out_fps=1 169 | out_width=1280 170 | out_height=720 171 | 172 | [Camera21] 173 | INDEX=0 174 | in_rtsp=1700 175 | out_port=8575 176 | out_fps=1 177 | out_width=1280 178 | out_height=720 179 | 180 | [Camera22] 181 | INDEX=0 182 | in_rtsp=1700 183 | out_port=8576 184 | out_fps=1 185 | out_width=1280 186 | out_height=720 187 | 188 | [Camera23] 189 | INDEX=0 190 | in_rtsp=1700 191 | out_port=8577 192 | out_fps=1 193 | out_width=1280 194 | out_height=720 195 | 196 | [Camera24] 197 | INDEX=0 198 | in_rtsp=1700 199 | out_port=8578 200 | out_fps=1 201 | out_width=1280 202 | out_height=720 203 | 204 | [Camera25] 205 | INDEX=0 206 | in_rtsp=1700 207 | out_port=8579 208 | out_fps=1 209 | out_width=1280 210 | out_height=720 211 | 212 | [Camera26] 213 | INDEX=0 214 | in_rtsp=1700 215 | out_port=8580 216 | out_fps=1 217 | out_width=1280 218 | out_height=720 219 | 220 | [Camera27] 221 | INDEX=0 222 | in_rtsp=1700 223 | out_port=8581 224 | out_fps=1 225 | out_width=1280 226 | out_height=720 227 | 228 | [Camera28] 229 | INDEX=0 230 | in_rtsp=1700 231 | out_port=8582 232 | out_fps=1 233 | out_width=1280 234 | out_height=720 235 | 236 | [Camera29] 237 | INDEX=0 238 | in_rtsp=1700 239 | out_port=8583 240 | out_fps=1 241 | out_width=1280 242 | out_height=720 243 | 244 | [Camera30] 245 | INDEX=0 246 | in_rtsp=1700 247 | out_port=8584 248 | out_fps=1 249 | out_width=1280 250 | out_height=720 251 | 252 | [Camera31] 253 | INDEX=0 254 | in_rtsp=1700 255 | out_port=8585 256 | out_fps=1 257 | out_width=1280 258 | out_height=720 259 | -------------------------------------------------------------------------------- /src/debug.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #-------------------------------------------------------------------------------------------- 3 | echo "--- START RTSP SERVER ---" 4 | g++ -std=c++11 cmdinput.cpp -o cmdinput -lpthread -lgstapp-1.0 `pkg-config --libs --cflags opencv gstreamer-1.0 gstreamer-rtsp-server-1.0` ; 5 | 6 | ./debug_viewer.sh & 7 | clipid=$! 8 | 9 | ./cmdinput & bash 10 | kill $clipid 11 | -------------------------------------------------------------------------------- /src/debug_viewer.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #-------------------------------------------------------------------------------------------- 3 | sleep 2 4 | echo "--- START RTSP VIEWER ---" 5 | vlc rtsp://127.0.0.1:8554/index/0 6 | 7 | -------------------------------------------------------------------------------- /src/start: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chicleee/rtsp-server/3b9230dc13d9f5302c4b8749a8702d0f9b19d9bc/src/start -------------------------------------------------------------------------------- /src/start.cpp: -------------------------------------------------------------------------------- 1 | //compile: g++ -std=c++11 start.cpp -o start -lboost_system -lboost_filesystem -lpthread -lgstapp-1.0 `pkg-config --libs --cflags opencv gstreamer-1.0 gstreamer-rtsp-server-1.0` 2 | //view: gst-launch-1.0 rtspsrc location=rtsp://127.0.0.1:8554/test latency=10 ! rtph264depay ! avdec_h264 ! videoconvert ! autovideosink 3 | //vlc rtsp://127.0.0.1:8554/test 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | //compile : g++ -o start start.cpp -lboost_system -lboost_filesystem 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include 34 | #include //wait functionwait:父进程等待子进程结束,并销毁子进程,如果父进程不调用wait函数,子进程就会一直留在linux内核中,变成了僵尸进程。 35 | #include 36 | // #include 37 | // #include 38 | // #include 39 | 40 | //vector xContours; 41 | //vector saveContours; 42 | 43 | //debug: 44 | /* 45 | #define GST_CAT_DEFAULT appsrc_pipeline_debug 46 | GST_DEBUG_CATEGORY (appsrc_pipeline_debug); 47 | //GST_DEBUG_CATEGORY (pipeline_debug); 48 | */ 49 | 50 | using namespace std; 51 | using namespace cv; 52 | 53 | 54 | //paramates 55 | // #define cameraWidth 1280 56 | // #define cameraHeight 720 57 | // #define outFps 5 58 | // #define inputRtsp "rtsp://admin:kuangping108@192.168.1.64/h264/ch1/main/av_stream" 59 | // #define RTSP_PORT "8554" 60 | // #define index "0" 61 | 62 | 63 | static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; //创建互斥进程 64 | GMainLoop *loop; 65 | typedef struct _App App; 66 | 67 | //用于gstreamer线程的结构:: 68 | struct _App{ 69 | GstElement *ffmpeg; 70 | //GstElement *ffmpeg2; 71 | //GstElement *rtppay, *gdppay; 72 | GstElement *rtppay; 73 | GstElement *videoenc; 74 | GstElement *videosrc; 75 | GstElement *sink; 76 | GstElement *videoscale; 77 | GstElement *filter; 78 | guint sourceid; 79 | GstElement *queue; 80 | GTimer *timer; 81 | }; 82 | 83 | typedef struct 84 | { 85 | string INDEX; 86 | string in_rtsp; 87 | int out_width; 88 | int out_height; 89 | int out_fps; 90 | string out_port; 91 | } Params; 92 | 93 | App s_app; 94 | 95 | typedef struct 96 | { 97 | gboolean white; 98 | GstClockTime timestamp; 99 | int out_width; 100 | int out_height; 101 | int out_fps; 102 | string INDEX; 103 | } MyContext; 104 | 105 | int counter = 0; 106 | 107 | //两个线程之间共享的帧: 108 | Mat frameimage; 109 | 110 | //"example of frame-processing" 111 | void processing( Mat frame ) 112 | { 113 | srand((int)time(0)); 114 | 115 | int dynamic = rand()%200; 116 | //cout<<"dynamic rand:"<INTER_CUBIC>INTER_AREA 144 | //缩小图像,避免出现波纹现象通常使用#INTER_AREA;放大图像通常使用INTER_CUBIC(速度较慢,但效果最好),或INTER_LINEAR(速度较快,效果还可以)。INTER_NEAREST,一般不推荐 145 | resize(frameimage,frameimage,Size(int(ctx->out_width), int(ctx->out_height)),0,0,INTER_AREA); 146 | 147 | /* frame image processing */ 148 | processing( frameimage ); 149 | 150 | 151 | 152 | 153 | /* allocate buffer */ 154 | buffersize = frameimage.cols * frameimage.rows * frameimage.channels(); 155 | //cout<<"frameimage.cols:"<white = !ctx->white; 169 | 170 | //increment the timestamp every {duration = 1/outFps} second 171 | GST_BUFFER_PTS (buffer) = ctx->timestamp; 172 | // std::cout<<"Gctx->timestamp:"<< ctx->timestamp <out_fps)); 174 | ctx->timestamp += GST_BUFFER_DURATION (buffer); 175 | 176 | //std::cout<<"GST_BUFFER_DURATION (buffer):"<INDEX<<" Frame:"<white = FALSE; 242 | ctx->timestamp = 0; 243 | ctx->out_fps = p.out_fps; 244 | ctx->out_width = p.out_width; 245 | ctx->out_height = p.out_height; 246 | ctx->INDEX = p.INDEX; 247 | 248 | 249 | /* make sure ther datais freed when the media is gone */ 250 | g_object_set_data_full (G_OBJECT (media), "my-extra-data", ctx, 251 | (GDestroyNotify) g_free); 252 | 253 | /* install the callback that will be called when a buffer is needed */ 254 | g_signal_connect (appsrc, "need-data", (GCallback) need_data, ctx); 255 | //g_signal_connect (appsrc, "need-data", G_CALLBACK (start_feed), ); 256 | //g_signal_connect (appsrc, "enough-data", G_CALLBACK (stop_feed), ); 257 | gst_object_unref (appsrc); 258 | gst_object_unref (element); 259 | } 260 | 261 | 262 | /***** 263 | thread2: push stream 264 | */ 265 | void *thread2new(void *arg){ 266 | Params p = *((Params*)arg); 267 | App * app = &s_app; 268 | GstCaps * caps2; 269 | GstCaps * caps3; 270 | GstFlowReturn ret; 271 | //GstBus *bus; 272 | GstElement *pipeline; 273 | 274 | GstRTSPServer *server; 275 | GstRTSPMountPoints *mounts; 276 | GstRTSPMediaFactory *factory; 277 | 278 | gst_init (NULL,NULL); 279 | loop = g_main_loop_new (NULL, FALSE); 280 | server = gst_rtsp_server_new (); 281 | g_object_set (server, "service", p.out_port.c_str(), NULL); 282 | mounts = gst_rtsp_server_get_mount_points (server); 283 | factory = gst_rtsp_media_factory_new (); 284 | 285 | /* gst_rtsp_media_factory_set_launch (factory, 286 | "( appsrc name=mysrc ! videoconvert ! capsfilter caps=video/x-raw,format=I420,width=640,height=480,framerate=15/1,pixel-aspect-ratio=1/1 ! x264enc noise-reduction=10000 tune=zerolatency ! rtph264pay config-interval=1 name=pay0 pt=96 )"); 287 | */ 288 | /* 289 | gst_rtsp_media_factory_set_launch (factory, 290 | "( appsrc name=mysrc ! videoconvert ! capsfilter caps=video/x-raw,format=I420,width=640,height=480,framerate=15/1,pixel-aspect-ratio=1/1 ! jpegenc tune=zerolatency ! rtpjpegpay name=pay0 pt=96 )");*/ 291 | 292 | /* gst_rtsp_media_factory_set_launch (factory, 293 | "( appsrc name=mysrc ! videoconvert ! capsfilter caps=video/x-raw,format=RGB,width=1920,height=1080,framerate=25/1,pixel-aspect-ratio=1/1 ! tee name=\"local\" ! queue ! ximagesink local. ! queue ! x264enc noise-reduction=10000 tune=zerolatency ! rtph264pay config-interval=1 name=pay0 pt=96 )"); 294 | */ 295 | /* gst_rtsp_media_factory_set_launch (factory, 296 | "( v4l2src ! video/x-raw,width=640,height=480 ! timeoverlay ! tee name=\"local\" ! queue ! autovideosink local. ! queue ! jpegenc ! rtpjpegpay name=pay0 pt=96 )");*/ 297 | char *outAppsrc = new char[200]; 298 | sprintf(outAppsrc, "( appsrc name=mysrc is-live=true block=true format=GST_FORMAT_TIME caps=video/x-raw,format=BGR,width=%d,height=%d,framerate=%d/1 ! videoconvert ! video/x-raw,format=I420 ! x264enc speed-preset=ultrafast tune=zerolatency ! rtph264pay config-interval=1 name=pay0 pt=96 )", 299 | int(p.out_width), int(p.out_height), int(p.out_fps)); 300 | gst_rtsp_media_factory_set_launch (factory, outAppsrc); 301 | 302 | g_signal_connect (factory, "media-configure", (GCallback) media_configure, (void*)&p); 303 | //g_signal_connect (app->videosrc, "need-data", G_CALLBACK (start_feed), app); 304 | //g_signal_connect (app->videosrc, "enough-data", G_CALLBACK (stop_feed),app); 305 | 306 | char index_url[16] = {0}; 307 | /* attach the test factory to the /test url */ 308 | sprintf(index_url, "/index/%s", p.INDEX.c_str()); 309 | gst_rtsp_mount_points_add_factory (mounts, index_url, factory); 310 | 311 | /* don't need the ref to the mounts anymore */ 312 | g_object_unref (mounts); 313 | 314 | /* attach the server to the default maincontext */ 315 | gst_rtsp_server_attach (server, NULL); 316 | 317 | /* start serving */ 318 | g_print ("stream ready at rtsp://127.0.0.1:%s%s\n",p.out_port.c_str(),index_url); 319 | g_main_loop_run (loop); 320 | 321 | pthread_exit(NULL); 322 | } 323 | /***** 324 | thread1: fetch stream 325 | */ 326 | void *thread1(void *arg){ 327 | Params p = *((Params*)arg); 328 | VideoCapture cap(p.in_rtsp); 329 | Mat tempframe, result; 330 | 331 | if (!cap.isOpened()) { 332 | throw "Error when reading steam from camera"; 333 | } 334 | // int width = cap.get(CAP_PROP_FRAME_WIDTH); 335 | // int height = cap.get(CAP_PROP_FRAME_HEIGHT); 336 | // int frameRate = cap.get(CAP_PROP_FPS); 337 | // int totalFrames = cap.get(CAP_PROP_FRAME_COUNT); 338 | 339 | // cout<<"input_width="< paramatesList; 361 | Params paramates_each; 362 | if (!boost::filesystem::exists("config.ini")) { 363 | std::cerr << "config.ini not exists." << std::endl; 364 | return -1; 365 | } 366 | boost::property_tree::ptree root_node, tag_system, Camera0; 367 | boost::property_tree::ini_parser::read_ini("config.ini", root_node); 368 | tag_system = root_node.get_child("System"); 369 | if(tag_system.count("rtsp_camera") != 1) { 370 | std::cerr << "rtsp_camera node not exists." << std::endl; 371 | return -1; 372 | } 373 | int cameras = tag_system.get("rtsp_camera"); 374 | std::cout << "rtsp_camera: " << cameras << std::endl; 375 | int fork_num[cameras] = {}; 376 | for(int i = 0; i("INDEX"); 384 | paramates_1.in_rtsp = Camera0.get("in_rtsp"); 385 | paramates_1.out_width = Camera0.get("out_width"); 386 | paramates_1.out_height = Camera0.get("out_height"); 387 | paramates_1.out_fps = Camera0.get("out_fps"); 388 | paramates_1.out_port = Camera0.get("out_port"); 389 | paramatesList.push_back(paramates_1); 390 | } 391 | 392 | cout<<"main process,id="<::iterator it = paramatesList.begin(); it != paramatesList.end(); ++it) 394 | { 395 | paramates_each=*it; 396 | pid = fork(); 397 | //子进程退出循环,不再创建子进程,全部由主进程创建子进程,这里是关键所在 398 | if(pid==0||pid==-1) 399 | { 400 | break; 401 | } 402 | } 403 | if(pid==-1) 404 | { 405 | cout<<"fail to fork!"< 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | //compile : g++ -o start start.cpp -lboost_system -lboost_filesystem 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include 39 | #include //wait functionwait:父进程等待子进程结束,并销毁子进程,如果父进程不调用wait函数,子进程就会一直留在linux内核中,变成了僵尸进程。 40 | #include 41 | 42 | #include "opencv2/opencv_modules.hpp" 43 | 44 | // #if defined(HAVE_OPENCV_CUDACODEC) 45 | 46 | #include 47 | #include 48 | #include 49 | 50 | #include 51 | #include 52 | #include 53 | #include 54 | 55 | // #include 56 | // #include 57 | // #include 58 | 59 | //vector xContours; 60 | //vector saveContours; 61 | 62 | //debug: 63 | /* 64 | #define GST_CAT_DEFAULT appsrc_pipeline_debug 65 | GST_DEBUG_CATEGORY (appsrc_pipeline_debug); 66 | //GST_DEBUG_CATEGORY (pipeline_debug); 67 | */ 68 | 69 | using namespace std; 70 | using namespace cv; 71 | 72 | 73 | //paramates 74 | // #define cameraWidth 1280 75 | // #define cameraHeight 720 76 | // #define outFps 5 77 | // #define inputRtsp "rtsp://admin:kuangping108@192.168.1.64/h264/ch1/main/av_stream" 78 | // #define RTSP_PORT "8554" 79 | // #define index "0" 80 | 81 | 82 | static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; //创建互斥进程 83 | GMainLoop *loop; 84 | typedef struct _App App; 85 | 86 | //用于gstreamer线程的结构:: 87 | struct _App{ 88 | GstElement *ffmpeg; 89 | //GstElement *ffmpeg2; 90 | //GstElement *rtppay, *gdppay; 91 | GstElement *rtppay; 92 | GstElement *videoenc; 93 | GstElement *videosrc; 94 | GstElement *sink; 95 | GstElement *videoscale; 96 | GstElement *filter; 97 | guint sourceid; 98 | GstElement *queue; 99 | GTimer *timer; 100 | }; 101 | 102 | typedef struct 103 | { 104 | string INDEX; 105 | string in_rtsp; 106 | int out_width; 107 | int out_height; 108 | int out_fps; 109 | string out_port; 110 | } Params; 111 | 112 | App s_app; 113 | 114 | typedef struct 115 | { 116 | gboolean white; 117 | GstClockTime timestamp; 118 | int out_width; 119 | int out_height; 120 | int out_fps; 121 | string INDEX; 122 | string out_port; 123 | } MyContext; 124 | 125 | int counter = 0; 126 | 127 | //两个线程之间共享的帧: 128 | cv::cuda::GpuMat share_frameimage; 129 | 130 | //"example of frame-processing" 131 | void processing( cv::Mat frame ) 132 | { 133 | srand((int)time(0)); 134 | 135 | int dynamic = rand()%200; 136 | //cout<<"dynamic rand:"<INTER_CUBIC>INTER_AREA 163 | //缩小图像,避免出现波纹现象通常使用#INTER_AREA;放大图像通常使用INTER_CUBIC(速度较慢,但效果最好),或INTER_LINEAR(速度较快,效果还可以)。INTER_NEAREST,一般不推荐 164 | cv::resize(need_frame,need_frame,Size(int(ctx->out_width), int(ctx->out_height)),0,0,INTER_AREA); 165 | /* frame image processing */ 166 | processing( need_frame ); 167 | /* allocate buffer */ 168 | buffersize = need_frame.cols * need_frame.rows * need_frame.channels(); 169 | //cout<<"share_frameimage.cols:"<white = !ctx->white; 183 | 184 | //increment the timestamp every {duration = 1/outFps} second 185 | GST_BUFFER_PTS (buffer) = ctx->timestamp; 186 | // std::cout<<"Gctx->timestamp:"<< ctx->timestamp <out_fps)); 188 | ctx->timestamp += GST_BUFFER_DURATION (buffer); 189 | 190 | //std::cout<<"GST_BUFFER_DURATION (buffer):"<out_port<<"/"<INDEX<<" Frame:"<white = FALSE; 256 | ctx->timestamp = 0; 257 | ctx->out_fps = p.out_fps; 258 | ctx->out_width = p.out_width; 259 | ctx->out_height = p.out_height; 260 | ctx->INDEX = p.INDEX; 261 | ctx->out_port = p.out_port; 262 | 263 | 264 | /* make sure ther datais freed when the media is gone */ 265 | g_object_set_data_full (G_OBJECT (media), "my-extra-data", ctx, 266 | (GDestroyNotify) g_free); 267 | 268 | /* install the callback that will be called when a buffer is needed */ 269 | g_signal_connect (appsrc, "need-data", (GCallback) need_data, ctx); 270 | //g_signal_connect (appsrc, "need-data", G_CALLBACK (start_feed), ); 271 | //g_signal_connect (appsrc, "enough-data", G_CALLBACK (stop_feed), ); 272 | gst_object_unref (appsrc); 273 | gst_object_unref (element); 274 | } 275 | 276 | 277 | /***** 278 | thread2: push stream 279 | */ 280 | void *thread2new(void *arg){ 281 | Params p = *((Params*)arg); 282 | App * app = &s_app; 283 | GstCaps * caps2; 284 | GstCaps * caps3; 285 | GstFlowReturn ret; 286 | //GstBus *bus; 287 | GstElement *pipeline; 288 | 289 | GstRTSPServer *server; 290 | GstRTSPMountPoints *mounts; 291 | GstRTSPMediaFactory *factory; 292 | 293 | gst_init (NULL,NULL); 294 | loop = g_main_loop_new (NULL, FALSE); 295 | server = gst_rtsp_server_new (); 296 | g_object_set (server, "service", p.out_port.c_str(), NULL); 297 | mounts = gst_rtsp_server_get_mount_points (server); 298 | factory = gst_rtsp_media_factory_new (); 299 | 300 | /* gst_rtsp_media_factory_set_launch (factory, 301 | "( appsrc name=mysrc ! videoconvert ! capsfilter caps=video/x-raw,format=I420,width=640,height=480,framerate=15/1,pixel-aspect-ratio=1/1 ! x264enc noise-reduction=10000 tune=zerolatency ! rtph264pay config-interval=1 name=pay0 pt=96 )"); 302 | */ 303 | /* 304 | gst_rtsp_media_factory_set_launch (factory, 305 | "( appsrc name=mysrc ! videoconvert ! capsfilter caps=video/x-raw,format=I420,width=640,height=480,framerate=15/1,pixel-aspect-ratio=1/1 ! jpegenc tune=zerolatency ! rtpjpegpay name=pay0 pt=96 )");*/ 306 | 307 | /* gst_rtsp_media_factory_set_launch (factory, 308 | "( appsrc name=mysrc ! videoconvert ! capsfilter caps=video/x-raw,format=RGB,width=1920,height=1080,framerate=25/1,pixel-aspect-ratio=1/1 ! tee name=\"local\" ! queue ! ximagesink local. ! queue ! x264enc noise-reduction=10000 tune=zerolatency ! rtph264pay config-interval=1 name=pay0 pt=96 )"); 309 | */ 310 | /* gst_rtsp_media_factory_set_launch (factory, 311 | "( v4l2src ! video/x-raw,width=640,height=480 ! timeoverlay ! tee name=\"local\" ! queue ! autovideosink local. ! queue ! jpegenc ! rtpjpegpay name=pay0 pt=96 )");*/ 312 | char *outAppsrc = new char[200]; 313 | sprintf(outAppsrc, "( appsrc name=mysrc is-live=true block=true format=GST_FORMAT_TIME caps=video/x-raw,format=BGRA,width=%d,height=%d,framerate=%d/1 ! videoconvert ! video/x-raw,format=I420 ! x264enc speed-preset=ultrafast tune=zerolatency ! rtph264pay config-interval=1 name=pay0 pt=96 )", 314 | int(p.out_width), int(p.out_height), int(p.out_fps)); 315 | gst_rtsp_media_factory_set_launch (factory, outAppsrc); 316 | 317 | g_signal_connect (factory, "media-configure", (GCallback) media_configure, (void*)&p); 318 | //g_signal_connect (app->videosrc, "need-data", G_CALLBACK (start_feed), app); 319 | //g_signal_connect (app->videosrc, "enough-data", G_CALLBACK (stop_feed),app); 320 | 321 | char index_url[16] = {0}; 322 | /* attach the test factory to the /test url */ 323 | sprintf(index_url, "/index/%s", p.INDEX.c_str()); 324 | gst_rtsp_mount_points_add_factory (mounts, index_url, factory); 325 | 326 | /* don't need the ref to the mounts anymore */ 327 | g_object_unref (mounts); 328 | 329 | /* attach the server to the default maincontext */ 330 | gst_rtsp_server_attach (server, NULL); 331 | 332 | /* start serving */ 333 | g_print ("stream ready at rtsp://127.0.0.1:%s%s\n",p.out_port.c_str(),index_url); 334 | g_main_loop_run (loop); 335 | 336 | pthread_exit(NULL); 337 | } 338 | /***** 339 | thread1: fetch stream 340 | */ 341 | void *thread1(void *arg){ 342 | Params p = *((Params*)arg); 343 | // const std::string fname = "rtsp://admin:kuangping108@192.168.1.64/h264/ch1/main/av_stream"; 344 | //显示视频 345 | //cv::namedWindow("CPU", cv::WINDOW_NORMAL); 346 | // cv::namedWindow("GPU", cv::WINDOW_OPENGL); 347 | // cv::cuda::setGlDevice(); 348 | cv::cuda::setDevice(0); 349 | cv::cuda::GpuMat d_frame; 350 | cv::Ptr d_reader = cv::cudacodec::createVideoReader(p.in_rtsp); 351 | // VideoCapture cap(p.in_rtsp); 352 | // Mat tempframe, result; 353 | 354 | // int width = cap.get(CAP_PROP_FRAME_WIDTH); 355 | // int height = cap.get(CAP_PROP_FRAME_HEIGHT); 356 | // int frameRate = cap.get(CAP_PROP_FPS); 357 | // int totalFrames = cap.get(CAP_PROP_FRAME_COUNT); 358 | 359 | // cout<<"input_width="< 0) 373 | // break; 374 | 375 | pthread_mutex_lock( &m ); 376 | // d_frame.download(temp_frame); 377 | share_frameimage = d_frame; 378 | pthread_mutex_unlock( &m ); 379 | } 380 | 381 | pthread_exit(NULL); 382 | } 383 | 384 | 385 | 386 | int main(int argc, char** argv){ 387 | 388 | pid_t pid; 389 | vector paramatesList; 390 | Params paramates_each; 391 | if (!boost::filesystem::exists("config.ini")) { 392 | std::cerr << "config.ini not exists." << std::endl; 393 | return -1; 394 | } 395 | boost::property_tree::ptree root_node, tag_system, Camera0; 396 | boost::property_tree::ini_parser::read_ini("config.ini", root_node); 397 | tag_system = root_node.get_child("System"); 398 | if(tag_system.count("rtsp_camera") != 1) { 399 | std::cerr << "rtsp_camera node not exists." << std::endl; 400 | return -1; 401 | } 402 | int cameras = tag_system.get("rtsp_camera"); 403 | std::cout << "rtsp_camera: " << cameras << std::endl; 404 | int fork_num[cameras] = {}; 405 | for(int i = 0; i("INDEX"); 413 | paramates_1.in_rtsp = Camera0.get("in_rtsp"); 414 | paramates_1.out_width = Camera0.get("out_width"); 415 | paramates_1.out_height = Camera0.get("out_height"); 416 | paramates_1.out_fps = Camera0.get("out_fps"); 417 | paramates_1.out_port = Camera0.get("out_port"); 418 | paramatesList.push_back(paramates_1); 419 | } 420 | 421 | cout<<"main process,id="<::iterator it = paramatesList.begin(); it != paramatesList.end(); ++it) 423 | { 424 | paramates_each=*it; 425 | pid = fork(); 426 | //子进程退出循环,不再创建子进程,全部由主进程创建子进程,这里是关键所在 427 | if(pid==0||pid==-1) 428 | { 429 | break; 430 | } 431 | } 432 | if(pid==-1) 433 | { 434 | cout<<"fail to fork!"< 2 | 3 | #include "opencv2/opencv_modules.hpp" 4 | 5 | #if defined(HAVE_OPENCV_CUDACODEC) 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | int main(int argc, const char* argv[]) 18 | { 19 | if (argc != 2) 20 | return -1; 21 | 22 | const std::string fname(argv[1]); 23 | 24 | //显示视频 25 | //cv::namedWindow("CPU", cv::WINDOW_NORMAL); 26 | cv::namedWindow("GPU", cv::WINDOW_OPENGL); 27 | cv::cuda::setGlDevice(); 28 | 29 | //cv::Mat frame; 30 | //cv::VideoCapture reader(fname); 31 | 32 | cv::cuda::GpuMat d_frame; 33 | cv::Ptr d_reader = cv::cudacodec::createVideoReader(fname); 34 | 35 | cv::TickMeter tm; 36 | std::vector cpu_times; 37 | std::vector gpu_times; 38 | 39 | int gpu_frame_count=0, cpu_frame_count=0; 40 | 41 | /* 42 | for (;;) 43 | { 44 | tm.reset(); tm.start(); 45 | if (!reader.read(frame)) 46 | break; 47 | tm.stop(); 48 | cpu_times.push_back(tm.getTimeMilli()); 49 | cpu_frame_count++; 50 | 51 | cv::imshow("CPU", frame); 52 | 53 | if (cv::waitKey(3) > 0) 54 | break; 55 | } 56 | */ 57 | for (;;) 58 | { 59 | tm.reset(); tm.start(); 60 | if (!d_reader->nextFrame(d_frame)) 61 | break; 62 | tm.stop(); 63 | gpu_times.push_back(tm.getTimeMilli()); 64 | gpu_frame_count++; 65 | 66 | cv::imshow("GPU", d_frame); 67 | 68 | if (cv::waitKey(3) > 0) 69 | break; 70 | } 71 | 72 | if (!cpu_times.empty() || !gpu_times.empty()) 73 | { 74 | std::cout << std::endl << "Results:" << std::endl; 75 | 76 | //std::sort(cpu_times.begin(), cpu_times.end()); 77 | std::sort(gpu_times.begin(), gpu_times.end()); 78 | 79 | //double cpu_avg = std::accumulate(cpu_times.begin(), cpu_times.end(), 0.0) / cpu_times.size(); 80 | double gpu_avg = std::accumulate(gpu_times.begin(), gpu_times.end(), 0.0) / gpu_times.size(); 81 | 82 | //std::cout << "CPU : Avg : " << cpu_avg << " ms FPS : " << 1000.0 / cpu_avg << " Frames " << cpu_frame_count << std::endl; 83 | std::cout << "GPU : Avg : " << gpu_avg << " ms FPS : " << 1000.0 / gpu_avg << " Frames " << gpu_frame_count << std::endl; 84 | } 85 | 86 | return 0; 87 | } 88 | 89 | #else 90 | 91 | int main() 92 | { 93 | std::cout << "OpenCV was built without CUDA Video decoding support\n" << std::endl; 94 | return 0; 95 | } 96 | 97 | #endif 98 | 99 | -------------------------------------------------------------------------------- /test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import cv2 4 | import gi 5 | 6 | gi.require_version('Gst', '1.0') 7 | gi.require_version('GstRtspServer', '1.0') 8 | from gi.repository import Gst, GstRtspServer, GObject 9 | 10 | 11 | class SensorFactory(GstRtspServer.RTSPMediaFactory): 12 | def __init__(self, **properties): 13 | super(SensorFactory, self).__init__(**properties) 14 | self.cap = cv2.VideoCapture("rtsp://admin:kuangping108@192.168.1.64/h264/ch1/main/av_stream") 15 | self.number_frames = 0 16 | self.fps = 1 17 | self.duration = 1 / self.fps * Gst.SECOND # duration of a frame in nanoseconds 18 | self.launch_string = 'appsrc name=source is-live=true block=true format=GST_FORMAT_TIME ' \ 19 | 'caps=video/x-raw,format=BGR,width=960,height=540,framerate={}/1 ' \ 20 | '! videoconvert ! video/x-raw,format=I420 ' \ 21 | '! x264enc speed-preset=ultrafast tune=zerolatency ' \ 22 | '! rtph264pay config-interval=1 name=pay0 pt=96'.format(self.fps) 23 | 24 | def on_need_data(self, src, lenght):#3840/4 2160/4 25 | if self.cap.isOpened(): 26 | ret, frame = self.cap.read() 27 | if ret: 28 | if self.number_frames % 25 == 0: 29 | # 缩放到原来的四分之一 30 | frame = cv2.resize(frame, (960,540),interpolation=cv2.INTER_AREA) 31 | data = frame.tostring() 32 | 33 | else: 34 | data='' 35 | 36 | buf = Gst.Buffer.new_allocate(None, len(data), None) 37 | buf.fill(0, data) 38 | self.duration = 1 / 25 * Gst.SECOND 39 | buf.duration = self.duration 40 | timestamp = self.number_frames * self.duration 41 | buf.pts = buf.dts = int(timestamp) 42 | buf.offset = timestamp 43 | self.number_frames += 1 44 | retval = src.emit('push-buffer', buf) 45 | if (self.number_frames-1) % 25 == 0: 46 | print('pushed buffer, frame {}, duration {} ns, durations {} s'.format(self.number_frames, 47 | self.duration, 48 | self.duration / Gst.SECOND)) 49 | if retval != Gst.FlowReturn.OK: 50 | print(retval) 51 | 52 | def do_create_element(self, url): 53 | return Gst.parse_launch(self.launch_string) 54 | 55 | def do_configure(self, rtsp_media): 56 | self.number_frames = 0 57 | appsrc = rtsp_media.get_element().get_child_by_name('source') 58 | appsrc.connect('need-data', self.on_need_data) 59 | 60 | 61 | class GstServer(GstRtspServer.RTSPServer): 62 | def __init__(self, **properties): 63 | super(GstServer, self).__init__(**properties) 64 | self.factory = SensorFactory() 65 | self.factory.set_shared(True) 66 | self.get_mount_points().add_factory("/test", self.factory) 67 | self.attach(None) 68 | 69 | 70 | GObject.threads_init() 71 | Gst.init(None) 72 | 73 | server = GstServer() 74 | print("Running as - rtsp://127.0.0.1:8554/test") 75 | 76 | loop = GObject.MainLoop() 77 | loop.run() 78 | -------------------------------------------------------------------------------- /test_udp_jpegenc.cpp: -------------------------------------------------------------------------------- 1 | //compile: g++ -std=c++11 udp_jpegenc.cpp -o udp -lpthread -lgstapp-1.0 `pkg-config --libs --cflags opencv gstreamer-1.0` 2 | //view: gst-launch-1.0 udpsrc port=5000 ! application/x-rtp, encoding-name=JPEG, payload=26 ! rtpjpegdepay ! jpegdec ! videoconvert ! autovideosink 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | using namespace std; 25 | using namespace cv; 26 | 27 | static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; //mutex per la mutua esclusione 28 | GMainLoop *loop; //loop di gstreamer 29 | typedef struct _App App; 30 | 31 | //struttura da usare per il thread di gstreamer: 32 | struct _App{ 33 | GstElement *ffmpeg; 34 | //GstElement *ffmpeg2; 35 | //GstElement *rtppay, *gdppay; 36 | GstElement *rtppay; 37 | GstElement *videoenc; 38 | GstElement *videosrc; 39 | GstElement *sink; 40 | GstElement *videoscale; 41 | GstElement *filter; 42 | guint sourceid; 43 | GstElement *queue1; 44 | GstElement *timeoverlay; 45 | GstElement *tee; 46 | GstElement *queue2; 47 | GstElement *videosink; 48 | GTimer *timer; 49 | }; 50 | App s_app; 51 | 52 | int counter = 0; 53 | 54 | //frame condiviso tra i due thread: 55 | 56 | //cv::Mat frameimage (2,2,CV_8UC1,cv::Scalar(255)); 57 | //cv::Mat dst (320,240,CV_8UC1,cv::Scalar(255)); 58 | //cv::Mat dii3; 59 | //cv::Mat dst_roi; 60 | //cv::Mat win; 61 | 62 | Mat frameimage; 63 | 64 | /* 65 | cb_need_data: funzione che inserisce nel buffer il frame ricevuto dal thread 66 | OpenCVthread e lo passa all'elemento appsrc di gstreamer 67 | @app: è un puntatore alla struttura App (che contiene gli elementi di gstreamer) 68 | @return: ritorna un valore booleano per indicare se c'è stato qualche errore 69 | */ 70 | 71 | static gboolean cb_need_data (App * app){ 72 | 73 | //cvNamedWindow( "iplimage", CV_WINDOW_AUTOSIZE ); 74 | static GstClockTime timestamp = 0; 75 | GstBuffer *buffer; 76 | guint buffersize; 77 | GstFlowReturn ret; 78 | GstMapInfo info; 79 | 80 | counter++; 81 | //m.lock(); 82 | pthread_mutex_lock( &m ); 83 | /* 84 | //logo dii 85 | dii3 = imread("/home/style/groovy_workspace/sandbox/maris_hmi/resources/diilogo.jpg"); 86 | if(! dii3.data ){ 87 | cout << "Could not open or find image" << std::endl ; 88 | } 89 | dst_roi = frameimage(Rect(5,5, dii3.cols, dii3.rows)); 90 | dii3.copyTo(dst_roi); 91 | */ 92 | /* 93 | //finestra: 94 | //win = imread("/home/style/groovy_workspace/sandbox/maris_hmi/resources/window17_contorno.png"); 95 | if(! win.data ){ 96 | cout << "Could not open or find image" << std::endl ; 97 | } 98 | overlayImage(frameimage,win,dst,cv::Point(0,0)); 99 | */ 100 | 101 | buffersize = frameimage.cols * frameimage.rows * frameimage.channels(); 102 | 103 | buffer = gst_buffer_new_and_alloc(buffersize); 104 | 105 | uchar * IMG_data = frameimage.data; 106 | //m.unlock(); 107 | pthread_mutex_unlock( &m ); 108 | 109 | if (gst_buffer_map (buffer, &info, (GstMapFlags)GST_MAP_WRITE)) { 110 | memcpy(info.data, IMG_data, buffersize); 111 | gst_buffer_unmap (buffer, &info); 112 | } 113 | else g_print("OPS! ERROR."); 114 | 115 | 116 | //segnalo che ho abbastanza dati da fornire ad appsrc: 117 | g_signal_emit_by_name (app->videosrc, "push-buffer", buffer, &ret); 118 | 119 | //GST_DEBUG ("everything allright in cb_need_data"); 120 | 121 | //nel caso di errore esce dal loop: 122 | if (ret != GST_FLOW_OK) { 123 | g_print("ops\n"); 124 | GST_DEBUG ("something wrong in cb_need_data"); 125 | g_main_loop_quit (loop); 126 | } 127 | //g_print("end gstreamer \n"); 128 | 129 | gst_buffer_unref (buffer); 130 | 131 | //delete img; 132 | //return TRUE; 133 | 134 | } 135 | 136 | /* 137 | start_feed:richiama la funzione cb_need_data in modo continuo ogni ms 138 | @app: è un puntatore alla struttura App (che contiene gli elementi di gstreamer) 139 | @pipeline: la pipeline di gstreamer 140 | @size: ... 141 | @return: void 142 | */ 143 | 144 | 145 | static void start_feed (GstElement * pipeline, guint size, App * app){ 146 | if (app->sourceid == 0){ 147 | //GST_DEBUG ("start feeding"); 148 | //esegue all'infinito cb_need_data (si ferma qui): 149 | app->sourceid = g_timeout_add (67, (GSourceFunc) cb_need_data, app); //67ms 150 | //app->sourceid = g_timeout_add (1, (GSourceFunc) cb_need_data, app); 151 | 152 | //app->sourceid = g_idle_add ((GSourceFunc) cb_need_data, app); 153 | } 154 | } 155 | 156 | /* 157 | stop_feed: ferma il flusso (vedi start_feed) 158 | @app: è un puntatore alla struttura App (che contiene gli elementi di gstreamer) 159 | @pipeline: la pipeline di gstreamer 160 | @return: void 161 | */ 162 | 163 | 164 | static void stop_feed (GstElement * pipeline, App * app){ 165 | if (app->sourceid != 0) { 166 | //GST_DEBUG ("stop feeding"); 167 | g_source_remove (app->sourceid); 168 | app->sourceid = 0; 169 | } 170 | } 171 | /* 172 | bus_call: funzione che gestisce gli eventi relativi al loop di gstreamer 173 | @bus: è un puntatore al bus di gstreamer 174 | * @message: è il messaggio di errore da mostrare 175 | * @data: è la struttura che viene passata (a volte si vuole mostrare l'errore 176 | * relativo ad uno specifico elemento della pipeline) 177 | @return: ritorna un valore booleano per indicare se c'è stato qualche errore 178 | */ 179 | 180 | /* 181 | static gboolean bus_call (GstBus *bus, GstMessage *message, gpointer data) { 182 | GError *err = NULL; 183 | gchar *dbg_info = NULL; 184 | GST_DEBUG ("got message %s",gst_message_type_get_name (GST_MESSAGE_TYPE (message))); 185 | 186 | switch (GST_MESSAGE_TYPE (message)) { 187 | case GST_MESSAGE_ERROR: { 188 | gst_message_parse_error (message, &err, &dbg_info); 189 | g_printerr ("ERROR from element %s: %s\n", 190 | GST_OBJECT_NAME (message->src), err->message); 191 | g_printerr ("Debugging info: %s\n", (dbg_info) ? dbg_info : "none"); 192 | g_error_free (err); 193 | g_free (dbg_info); 194 | g_main_loop_quit (loop); 195 | break; 196 | } 197 | case GST_MESSAGE_EOS: 198 | g_main_loop_quit (loop); 199 | break; 200 | default: 201 | break; 202 | } 203 | return TRUE; 204 | }*/ 205 | 206 | /* 207 | check_log_handler: funzione per il debug 208 | @log_domain: .. 209 | @message: .. 210 | @user_data: struttura dati dell'utente (in questo caso sarebbe App) 211 | @return: void 212 | */ 213 | 214 | /* 215 | static void check_log_handler (const gchar * const log_domain, 216 | const GLogLevelFlags log_level, const gchar * const message, 217 | gpointer const user_data){ 218 | GstDebugLevel level; 219 | switch (log_level & G_LOG_LEVEL_MASK) { 220 | case G_LOG_LEVEL_ERROR: 221 | level = GST_LEVEL_ERROR; 222 | break; 223 | case G_LOG_LEVEL_CRITICAL: 224 | level = GST_LEVEL_WARNING; 225 | break; 226 | case G_LOG_LEVEL_WARNING: 227 | level = GST_LEVEL_WARNING; 228 | break; 229 | case G_LOG_LEVEL_MESSAGE: 230 | level = GST_LEVEL_INFO; 231 | break; 232 | case G_LOG_LEVEL_INFO: 233 | level = GST_LEVEL_INFO; 234 | break; 235 | case G_LOG_LEVEL_DEBUG: 236 | level = GST_LEVEL_DEBUG; 237 | break; 238 | default: 239 | level = GST_LEVEL_LOG; 240 | break; 241 | } 242 | gst_debug_log (GST_CAT_DEFAULT, level, "?", "?", 0, NULL, "%s", message); 243 | }*/ 244 | 245 | /***** 246 | thread2: thread per la gestione della pipeline di gstreamer 247 | */ 248 | 249 | 250 | bool start = false; 251 | void *thread2(void *arg){ 252 | 253 | App * app = &s_app; //struttura dati di gstramer 254 | GstCaps * caps2; 255 | GstCaps * caps3; 256 | GstFlowReturn ret; 257 | //GstBus *bus; 258 | GstElement *pipeline; 259 | GstPad * tee_app, * tee_udp; 260 | GstPad * queue_app, * queue_udp; 261 | 262 | gst_init (NULL,NULL); 263 | 264 | loop = g_main_loop_new (NULL, FALSE); 265 | 266 | //creazione della pipeline: 267 | pipeline = gst_pipeline_new ("gstreamer-encoder"); 268 | if( ! pipeline ) { 269 | g_print("Error creating Pipeline, exiting..."); 270 | } 271 | 272 | //creazione elemento appsrc: 273 | app-> videosrc = gst_element_factory_make ("appsrc", "videosrc"); 274 | if( ! app->videosrc ) { 275 | g_print( "Error creating source element, exiting..."); 276 | } 277 | 278 | //creazione elemento queue: 279 | app-> queue1 = gst_element_factory_make ("queue", "queue1"); 280 | if( ! app->queue1 ) { 281 | g_print( "Error creating queue element, exiting..."); 282 | } 283 | 284 | app-> queue2 = gst_element_factory_make ("queue", "queue2"); 285 | if( ! app->queue2 ) { 286 | g_print( "Error creating queue element, exiting..."); 287 | } 288 | 289 | //creazione elemento filter: 290 | app->filter = gst_element_factory_make ("capsfilter", "filter"); 291 | if( ! app->filter ) { 292 | g_print( "Error creating filter, exiting..."); 293 | } 294 | 295 | //creazione elemento videoscale (ridimensiona il video): 296 | app->videoscale = gst_element_factory_make ("videoscale", "videoscale"); 297 | if( ! app->videoscale ) { 298 | g_print( "Error creating videoscale, exiting..."); 299 | } 300 | 301 | //creazione elemento videoenc (per la codifica h264) 302 | /* 303 | app->videoenc = gst_element_factory_make ("x264enc", "videoenc"); 304 | if( !app->videoenc ) { 305 | std::cout << "Error creating encoder, exiting..."; 306 | }*/ 307 | 308 | app->videoenc = gst_element_factory_make ("jpegenc", "videoenc"); 309 | if( !app->videoenc ) { 310 | std::cout << "Error creating encoder, exiting..."; 311 | } 312 | 313 | //creazione elemento rtppay (flusso streaming real-time) 314 | /* 315 | app->rtppay = gst_element_factory_make ("rtph264pay", "rtppay"); 316 | if( !app->rtppay ) { 317 | std::cout << "Error creating rtppay, exiting..."; 318 | }*/ 319 | 320 | app->rtppay = gst_element_factory_make ("rtpjpegpay", "rtppay"); 321 | if( !app->rtppay ) { 322 | std::cout << "Error creating rtppay, exiting..."; 323 | } 324 | 325 | //creazione elemento gdppay (payload di buffer ed eventi usando il protocollo dati di Gstreamer) 326 | /* 327 | app->gdppay = gst_element_factory_make ("gdppay", "gdppay"); 328 | if( !app->gdppay) { 329 | std::cout << "Error creating gdppay, exiting..."; 330 | }*/ 331 | 332 | //creazione elemento videoconvert (in gstreamer-0.10 si chiamava ffmpegcolorspace) 333 | app-> ffmpeg = gst_element_factory_make( "videoconvert", "ffmpeg" ); //!!!!!! ffenc_mpeg2video 334 | if( ! app-> ffmpeg ) { 335 | g_print( "Error creating ffmpegcolorspace, exiting..."); 336 | } 337 | /* 338 | app-> ffmpeg2 = gst_element_factory_make( "videoconvert", "ffmpeg2" ); //!!!!!! ffenc_mpeg2video 339 | if( ! app-> ffmpeg ) { 340 | g_print( "Error creating ffmpegcolorspace, exiting..."); 341 | }*/ 342 | //creazione elemento sink: 343 | /* 344 | app-> sink = gst_element_factory_make ("tcpserversink", "sink"); 345 | if( ! app-> sink) { 346 | g_print( "Error creating sink, exiting..."); 347 | }*/ 348 | app-> sink = gst_element_factory_make ("udpsink", "sink"); 349 | if( ! app-> sink) { 350 | g_print( "Error creating sink, exiting..."); 351 | } 352 | 353 | 354 | app-> videosink = gst_element_factory_make ("autovideosink", "videosink"); 355 | if( ! app-> videosink) { 356 | g_print( "Error creating sink, exiting..."); 357 | } 358 | 359 | app-> timeoverlay = gst_element_factory_make ("timeoverlay", "timeoverlay"); 360 | if( ! app-> timeoverlay) { 361 | g_print( "Error creating sink, exiting..."); 362 | } 363 | 364 | app-> tee = gst_element_factory_make ("tee", "tee"); 365 | if( ! app-> tee) { 366 | g_print( "Error creating sink, exiting..."); 367 | } 368 | 369 | g_print ("Elements are created\n"); 370 | 371 | 372 | 373 | 374 | //Config elements 375 | 376 | //impostazione delle proprietà dei vari elementi: 377 | g_object_set (G_OBJECT (app->sink), "host" , "127.0.0.1" , NULL); // 378 | g_object_set (G_OBJECT (app->sink), "port" , 5000 , NULL); 379 | g_object_set (G_OBJECT (app->sink), "sync" , FALSE , NULL); 380 | 381 | 382 | g_object_set (G_OBJECT (app->videoenc), "bitrate", 256, NULL); 383 | g_object_set (G_OBJECT (app->videoenc), "noise-reduction", 10000, NULL); 384 | gst_util_set_object_arg (G_OBJECT (app->videoenc), "tune", "zerolatency"); 385 | gst_util_set_object_arg (G_OBJECT (app->videoenc), "pass" , "qual"); 386 | g_object_set (G_OBJECT (app->rtppay), "config-interval", 1, NULL); 387 | 388 | 389 | 390 | 391 | 392 | //proprietà da associare al filtro della pipeline(bisogna convertire in yuv): 393 | //caps3 -> capsfilter 394 | caps3 = gst_caps_new_simple("video/x-raw", 395 | "format", G_TYPE_STRING, "I420", 396 | "width", G_TYPE_INT, 640, 397 | "height", G_TYPE_INT, 480, 398 | //"width", G_TYPE_INT, 225, 399 | //"height", G_TYPE_INT, 225, 400 | "framerate", GST_TYPE_FRACTION, 15, 1, 401 | "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1, 402 | NULL); 403 | g_object_set (G_OBJECT (app->filter), "caps", caps3, NULL); 404 | 405 | //caps2 -> appsrc 406 | caps2 = gst_caps_new_simple("video/x-raw", 407 | "format", G_TYPE_STRING, "RGB", 408 | "width", G_TYPE_INT, 640, 409 | "height", G_TYPE_INT, 480, 410 | //"width", G_TYPE_INT, 800, 411 | //"height", G_TYPE_INT, 600, 412 | "framerate", GST_TYPE_FRACTION, 15, 1, 413 | "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1, 414 | NULL); 415 | gst_app_src_set_caps(GST_APP_SRC( app->videosrc), caps2); 416 | // g_object_set (G_OBJECT (app->videosrc), "is-live" , TRUE , NULL); 417 | // g_object_set (G_OBJECT (app->videosrc), "min-latency" , 200000000 , NULL); 418 | g_object_set (G_OBJECT ( app->videosrc),"stream-type", 0,"format", GST_FORMAT_TIME, NULL); 419 | 420 | //gestisco il flusso di immisione dei buffer nell'elemento sorgente (appsrc): 421 | g_signal_connect (app->videosrc, "need-data", G_CALLBACK (start_feed), app); 422 | g_signal_connect (app->videosrc, "enough-data", G_CALLBACK (stop_feed),app); 423 | 424 | g_print ("end of settings\n"); 425 | 426 | 427 | 428 | 429 | //associo il bus alla pipeline: 430 | //bus = gst_pipeline_get_bus (GST_PIPELINE ( pipeline)); 431 | //g_assert(bus); 432 | //gst_bus_add_watch ( bus, (GstBusFunc) bus_call, app); 433 | 434 | //metto i vari elementi nella pipeline 435 | // appsrc: opencv frames 436 | //gst_bin_add_many (GST_BIN ( pipeline), app-> videosrc, app->ffmpeg, app-> filter, app->videoenc, app->rtppay, app->gdppay, app-> sink, NULL); 437 | gst_bin_add_many (GST_BIN ( pipeline), app-> videosrc, app->ffmpeg, app-> filter, app->tee, app->queue1, app->videoenc, app->rtppay, app-> sink, app->queue2, app->videosink, NULL); 438 | //gst_bin_add_many (GST_BIN ( pipeline), app-> videosrc, app->ffmpeg, app-> filter, app-> videosink, NULL); 439 | //gst_bin_add_many (GST_BIN ( pipeline), app-> videosrc, app->ffmpeg, app-> filter, app-> videoenc, app->rtppay, app->sink, NULL); 440 | g_print ("Added all the Elements into the pipeline\n"); 441 | 442 | //collego i vari elementi fra loro: 443 | //int ok = false; 444 | //ok = gst_element_link_many ( app->videosrc, app->ffmpeg, app->filter, app->videoenc, app->rtppay, app->sink, NULL); 445 | //ok = gst_element_link_many ( app-> videosrc, app->ffmpeg, app-> filter, app-> videosink, NULL); 446 | 447 | //if(ok)g_print ("Linked all the Elements together\n"); 448 | //else g_print("*** Linking error ***\n"); 449 | 450 | 451 | if(gst_element_link_many(app->videosrc, app->ffmpeg, app->filter, app->tee, NULL) != TRUE || 452 | gst_element_link_many(app->queue1, app->videoenc, app->rtppay, app->sink, NULL) != TRUE || 453 | gst_element_link_many(app->queue2, app->videosink, NULL) != TRUE ) { 454 | g_printerr("Elements could not be linked.\n"); 455 | gst_object_unref(pipeline); 456 | pthread_exit(NULL); 457 | } 458 | 459 | 460 | //g_assert(app->videosrc); 461 | //g_assert(GST_IS_APP_SRC(app->videosrc)); 462 | 463 | tee_udp = gst_element_get_request_pad (app->tee, "src_%u"); 464 | g_print("Obtained request pad %s for branch 1. \n",gst_pad_get_name(tee_udp)); 465 | queue_udp = gst_element_get_static_pad(app->queue1, "sink"); 466 | 467 | tee_app = gst_element_get_request_pad (app->tee, "src_%u"); 468 | g_print("Obtained request pad %s for branch 2. \n",gst_pad_get_name(tee_app)); 469 | queue_app = gst_element_get_static_pad(app->queue2, "sink"); 470 | 471 | if(gst_pad_link (tee_udp, queue_udp) != GST_PAD_LINK_OK || gst_pad_link (tee_app, queue_app) != GST_PAD_LINK_OK){ 472 | g_printerr("Tee could not be linked\n"); 473 | gst_object_unref(pipeline); 474 | pthread_exit(NULL); 475 | } 476 | 477 | gst_object_unref(queue_udp); 478 | gst_object_unref(queue_app); 479 | 480 | 481 | //metto lo stato della pipeline a playing: 482 | g_print ("Playing the video\n"); 483 | gst_element_set_state (pipeline, GST_STATE_PLAYING); 484 | 485 | g_print ("Running...\n"); 486 | g_main_loop_run ( loop); 487 | 488 | gst_element_release_request_pad(app->tee, tee_udp); 489 | gst_element_release_request_pad(app->tee, tee_app); 490 | gst_object_unref(tee_udp); 491 | gst_object_unref(tee_app); 492 | 493 | g_print ("Returned, stopping playback\n"); 494 | gst_element_set_state (pipeline, GST_STATE_NULL); 495 | //gst_object_unref ( bus); 496 | //g_main_loop_unref (loop); 497 | g_print ("Deleting pipeline\n"); 498 | gst_object_unref (pipeline); 499 | pthread_exit(NULL); 500 | } 501 | 502 | 503 | void *thread1(void *arg){ 504 | VideoCapture cap(0); 505 | Mat tempframe, result; 506 | //FireDetection FD; 507 | 508 | if (!cap.isOpened()) { 509 | throw "Error when reading steam_avi"; 510 | } 511 | 512 | while (1) { 513 | 514 | cap.read(tempframe); 515 | //tempframe = imread("2.jpg"); 516 | //if(! tempframe.data ){ //nel caso in cui non la trova 517 | // cout << "Could not open or find image" << std::endl ; 518 | //} 519 | //FD.fireDetection(tempframe,result); 520 | 521 | pthread_mutex_lock( &m ); 522 | 523 | frameimage = tempframe; 524 | //frameimage = result; 525 | 526 | cv::cvtColor(frameimage, frameimage,CV_BGR2RGB); 527 | 528 | 529 | pthread_mutex_unlock( &m ); 530 | //imshow("frame",tempframe); 531 | //waitKey(20); 532 | } 533 | pthread_exit(NULL); 534 | } 535 | 536 | int main(int argc, char** argv){ 537 | int rc1, rc2; 538 | pthread_t CaptureImageThread, StreamThread; 539 | 540 | if( (rc1 = pthread_create(&CaptureImageThread, NULL, thread1, NULL)) ) 541 | cout << "Thread creation failed: " << rc1 << endl; 542 | if( (rc2 = pthread_create(&StreamThread, NULL, thread2, NULL)) ) 543 | cout << "Thread creation failed: " << rc2 << endl; 544 | 545 | pthread_join( CaptureImageThread, NULL ); 546 | pthread_join( StreamThread, NULL ); 547 | return 0; 548 | }; 549 | --------------------------------------------------------------------------------