GStreamer开发笔记(二):GStreamer在ubnutn平台部署安装,测试gstreamer/cheese/ffmpeg/fmplayer打摄像头延迟和内存

前言

  本篇介绍ubuntu平台的GStreamer部署安装,然后测试摄像头,进行性能延迟对比。

 

准备ubuntu虚拟机

  略。

 

注意

  由于在虚拟机ubuntu上也会测试usb摄像头,因为不是直接硬件到ubuntu,而是先到windows然后虚拟机桥接到ubuntu,可能会到usb摄像头的延迟产生一定影响,但根据经验,大概率几毫秒到几十毫秒之间。

关于ubuntu离线安装

  离线安装比较难,首先就要安装几十个依赖工具和库,离线没有这些的话,就是套娃+套娃+套娃,需要费很大劲逐一安装,且解决各种依赖问题,所以就算离线安装也需要先把ubuntu的辅助工具都打上做成个镜像,再去离线安装gstreamer,这里不建议没依赖库的时候直接离线安装。

 

GStreamer在ubuntu部署

步骤一:下载解压

  

步骤二:更新,并安装gstreamer

sudo apt-get update sudo apt-get install libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libgstreamer-plugins-bad1.0-dev gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-libav gstreamer1.0-doc gstreamer1.0-tools gstreamer1.0-x gstreamer1.0-alsa gstreamer1.0-gl gstreamer1.0-gtk3 gstreamer1.0-qt5 gstreamer1.0-pulseaudio 

步骤三:运行gstreamer测试

  命令行打开usb摄像头

gst-launch-1.0.exe -v ksvideosrc do-stats=TRUE ! videoconvert ! autovideosink 

  命令行打开播放文件

gst-launch-1.0 playbin uri=file:///<你的视频> gst-launch-1.0 playbin uri=file:////home/yang/Desktop/test.avi 

  

  命令行打开usb摄像头

gst-launch-1.0 v4l2src device=/dev/video0 ! video/x-raw,framerate=30/1 ! videoconvert ! autovideosink 

  

 

延迟和内存对比

步骤一:gstreamer延迟和内存

  使用gstreamer:

gst-launch-1.0 v4l2src device=/dev/video0 ! video/x-raw,framerate=30/1 ! videoconvert ! autovideosink 

  图片[1]-GStreamer开发笔记(二):GStreamer在ubnutn平台部署安装,测试gstreamer/cheese/ffmpeg/fmplayer打摄像头延迟和内存-牛翰网
  内存占用:
  

步骤二:cheese延迟和内存

  cheese相机:

sudo apt-get install cheese sudo cheese 

  图片[2]-GStreamer开发笔记(二):GStreamer在ubnutn平台部署安装,测试gstreamer/cheese/ffmpeg/fmplayer打摄像头延迟和内存-牛翰网
  内存占用:
  

 

  Ubuntu打开usb摄像头
  

步骤三:ffmpeg的ffplay延迟和内存

sudo apt-get install ffmpeg ffplay -f v4l2 /dev/video0 

  图片[3]-GStreamer开发笔记(二):GStreamer在ubnutn平台部署安装,测试gstreamer/cheese/ffmpeg/fmplayer打摄像头延迟和内存-牛翰网
  对比内存
  

步骤四:fmplayer延迟和内存

sudo apt-get install fmplayer 

  图片[4]-GStreamer开发笔记(二):GStreamer在ubnutn平台部署安装,测试gstreamer/cheese/ffmpeg/fmplayer打摄像头延迟和内存-牛翰网
  对比内存:
  

 

Demo

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <sys/ioctl.h> #include <sys/mman.h> #include <linux/videodev2.h> #include <errno.h> #include <SDL2/SDL.h> #include <SDL2/SDL_pixels.h> #define WIDTH 640 #define HEIGHT 480 int main() { setbuf(stdout, NULL); int fd; struct v4l2_format fmt; struct v4l2_requestbuffers req; struct v4l2_buffer buf; void *buffer_start; unsigned int buffer_length; // 打开摄像头设备 fd = open("/dev/video0", O_RDWR); if (fd == -1) { perror("打开摄像头设备失败"); return EXIT_FAILURE; } // 设置视频格式 memset(&fmt, 0, sizeof(fmt)); fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.fmt.pix.width = WIDTH; fmt.fmt.pix.height = HEIGHT; fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; if (ioctl(fd, VIDIOC_S_FMT, &fmt) == -1) { perror("设置视频格式失败"); close(fd); return EXIT_FAILURE; } // 请求缓冲区 memset(&req, 0, sizeof(req)); req.count = 1; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_MMAP; if (ioctl(fd, VIDIOC_REQBUFS, &req) == -1) { perror("请求缓冲区失败"); close(fd); return EXIT_FAILURE; } // 映射缓冲区 memset(&buf, 0, sizeof(buf)); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = 0; if (ioctl(fd, VIDIOC_QUERYBUF, &buf) == -1) { perror("查询缓冲区失败"); close(fd); return EXIT_FAILURE; } buffer_length = buf.length; buffer_start = mmap(NULL, buffer_length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset); if (buffer_start == MAP_FAILED) { perror("映射缓冲区失败"); close(fd); return EXIT_FAILURE; } // 将缓冲区放入队列 if (ioctl(fd, VIDIOC_QBUF, &buf) == -1) { perror("缓冲区入队失败"); munmap(buffer_start, buffer_length); close(fd); return EXIT_FAILURE; } // 开始视频捕获 enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (ioctl(fd, VIDIOC_STREAMON, &type) == -1) { perror("开始视频捕获失败"); munmap(buffer_start, buffer_length); close(fd); return EXIT_FAILURE; } // 初始化 SDL if (SDL_Init(SDL_INIT_VIDEO) < 0) { fprintf(stderr, "SDL 初始化失败: %s\n", SDL_GetError()); munmap(buffer_start, buffer_length); close(fd); return EXIT_FAILURE; } SDL_Window *window = SDL_CreateWindow("V4L2 Camera", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WIDTH, HEIGHT, 0); if (!window) { fprintf(stderr, "创建 SDL 窗口失败: %s\n", SDL_GetError()); SDL_Quit(); munmap(buffer_start, buffer_length); close(fd); return EXIT_FAILURE; } SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, 0); // SDL_PIXELFORMAT_YV12 = /**< Planar mode: Y + V + U (3 planes) */ // SDL_PIXELFORMAT_IYUV = /**< Planar mode: Y + U + V (3 planes) */ // SDL_PIXELFORMAT_YUY2 = /**< Packed mode: Y0+U0+Y1+V0 (1 plane) */ // SDL_PIXELFORMAT_UYVY = /**< Packed mode: U0+Y0+V0+Y1 (1 plane) */ // SDL_PIXELFORMAT_YVYU = /**< Packed mode: Y0+V0+Y1+U0 (1 plane) */ // SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_YV12, SDL_TEXTUREACCESS_STREAMING, WIDTH, HEIGHT); // SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, WIDTH, HEIGHT); SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_YUY2, SDL_TEXTUREACCESS_STREAMING, WIDTH, HEIGHT); // SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_UYVY, SDL_TEXTUREACCESS_STREAMING, WIDTH, HEIGHT); // SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_YVYU, SDL_TEXTUREACCESS_STREAMING, WIDTH, HEIGHT); int running = 1; SDL_Event event; while (running) { // 处理事件 while (SDL_PollEvent(&event)) { if (event.type == SDL_QUIT) { running = 0; } } // 捕获帧 memset(&buf, 0, sizeof(buf)); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; if (ioctl(fd, VIDIOC_DQBUF, &buf) == -1) { perror("出队缓冲区失败"); break; } // 更新 SDL 纹理 SDL_UpdateTexture(texture, NULL, buffer_start, WIDTH); // 渲染纹理 SDL_RenderClear(renderer); SDL_RenderCopy(renderer, texture, NULL, NULL); SDL_RenderPresent(renderer); // 将缓冲区重新入队 if (ioctl(fd, VIDIOC_QBUF, &buf) == -1) { perror("缓冲区入队失败"); break; } } // 清理资源 SDL_DestroyTexture(texture); SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); SDL_Quit(); munmap(buffer_start, buffer_length); close(fd); return EXIT_SUCCESS; } 

 

总结

  到这里,我们得出结论,gstreamer基本是最优秀的框架之一了,初步测试不是特别严谨,但是基本能反应情况(比如ffmpeg得fmplay本轮测试是最差,但是ffmpeg写代码可以进行ffmpeg源码和编程代码的优化,达到150ms左右,诸如这类情况不考虑)。
  gstreamer优于ffmplayer优于cheese优于ffmpeg。
  下一篇将使用代码v4l2+SDL以及v4l2+QtOpenGL做进一步测试延迟内存。

 

入坑

入坑一:摄像头使用cheese打开为黑色

问题

  打开黑色,有设备,拔了就提示没设备
  

尝试

  更新安装驱动,未解决,排除驱动问题。
  测试sudo cheese,还是黑色,排除权限问题。
  修改虚拟机usb兼容性,换不是自己当前的就好了:
  

  然后可以了。

解决

  虚拟机兼容性从2.0改成USB3.1,然后:
  

来源链接:https://www.cnblogs.com/qq21497936/p/18824202

请登录后发表评论

    没有回复内容