添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
#ifndef SRC_VIDEOCAPTURE_X11DESKTOPCAPTURE_H_
#define SRC_VIDEOCAPTURE_X11DESKTOPCAPTURE_H_
#include "VideoCapture/VideoCapture.h"
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/XShm.h>
#include <sys/shm.h>
#include <string>
#include <vector>
namespace RemoteServer {
class X11DesktopCapture: public VideoCapture {
public:
	X11DesktopCapture(std::shared_ptr<BufferQueue<unsigned char>>& buffer_queue);
	virtual ~X11DesktopCapture();
	void UpdateVideoCapture() final;
//	bool StopVideoCapture() final;
	bool DestroyVideoCapture() final;
private:
	bool InitVideoCapture();
    bool InitShmImages();
    Display* m_display = nullptr;
    Window m_desktop_window = 0;
	XShmSegmentInfo* m_shm_segment_info = nullptr;
	XImage* m_x_shm_image = nullptr;
	int m_screen_size = 0;
} /* namespace RemoteServer */
#endif /* SRC_VIDEOCAPTURE_X11DESKTOPCAPTURE_H_ */

实现.cpp

* X11DesktopCapture.cpp * Created on: Apr 3, 2020 * Author: zou #include "X11DesktopCapture.h" #include <cstring> namespace RemoteServer { X11DesktopCapture::X11DesktopCapture(std::shared_ptr<BufferQueue<unsigned char>>& buffer_queue) // TODO Auto-generated constructor stub m_buffer_queue = buffer_queue; InitVideoCapture(); X11DesktopCapture::~X11DesktopCapture() { // TODO Auto-generated destructor stub DestroyVideoCapture(); bool X11DesktopCapture::InitVideoCapture(){ m_display = XOpenDisplay(NULL); if(!m_display){ SIMLOG(SimLogger::Error, "can not connect a display"); return false; m_desktop_window = RootWindow(m_display, 0); if(!m_desktop_window){ SIMLOG(SimLogger::Error, "can not get the root window"); return false; m_video_format->pixel_type = RGBA8888; m_video_format->width = DisplayWidth(m_display, 0); m_video_format->height = DisplayHeight(m_display, 0); XImage* window_image = XGetImage(m_display, m_desktop_window, 0, 0, m_video_format->width, m_video_format->height, AllPlanes, ZPixmap); m_video_format->bits_per_pixel = window_image->bits_per_pixel; m_video_format->depth = window_image->depth; m_screen_size = m_video_format->width * m_video_format->height * m_video_format->bits_per_pixel / 8; SIMLOG(SimLogger::Info, "w/h/d/bpp/size: " << m_video_format->width <<"/" << m_video_format->height << "/" << m_video_format->depth << "/" << m_video_format->bits_per_pixel << "/" << m_screen_size); XDestroyImage(window_image); //create share memory image return InitShmImages(); bool X11DesktopCapture::InitShmImages(){ m_shm_segment_info = new XShmSegmentInfo(); m_shm_segment_info->shmid = -1; m_x_shm_image = XShmCreateImage(m_display, DefaultVisual(m_display,0), // Use a correct visual. Omitted for brevity m_video_format->depth, // Determine correct depth from the visual. Omitted for brevity ZPixmap, NULL, m_shm_segment_info, m_video_format->width, m_video_format->height); if(!m_x_shm_image){ SIMLOG(SimLogger::Error, "can not create XshmImage"); return false; m_shm_segment_info->shmid = shmget(IPC_PRIVATE, m_x_shm_image->bytes_per_line * m_x_shm_image->height, IPC_CREAT|0777); if(m_shm_segment_info->shmid == -1){ SIMLOG(SimLogger::Error, "shmid failed"); return false; m_shm_segment_info->shmaddr = m_x_shm_image->data = (char* )shmat(m_shm_segment_info->shmid, 0, 0); // m_shm_segment_info->readOnly = False; if(!XShmAttach(m_display, m_shm_segment_info)){ SIMLOG(SimLogger::Error, "XShmAttach failed"); return false; SIMLOG(SimLogger::Debug, "initShmImages success"); return true; void X11DesktopCapture::UpdateVideoCapture(){ while(m_start_capture){ if(!XShmGetImage(m_display, m_desktop_window, m_x_shm_image, 0, 0, AllPlanes)){ SIMLOG(SimLogger::Error, "update shmImage failed"); return ; std::vector<unsigned char> buffer(m_x_shm_image->data, m_x_shm_image->data + m_screen_size); m_buffer_queue->WaitePushBuffer(buffer); // memcpy(video_data, m_x_shm_image->data, m_screen_size ); bool X11DesktopCapture::DestroyVideoCapture(){ StopVideoCapture(); if(m_shm_segment_info && m_shm_segment_info->shmid != -1 && m_display){ if(!XShmDetach(m_display, m_shm_segment_info)){ SIMLOG(SimLogger::Error, "XShmDetach failed"); return false; if(m_x_shm_image){ XDestroyImage(m_x_shm_image); m_x_shm_image = nullptr; if(m_shm_segment_info && m_shm_segment_info->shmaddr != (char*)-1 && m_display){ shmdt(m_shm_segment_info->shmaddr); if(m_shm_segment_info && m_shm_segment_info->shmid != -1 && m_display){ shmctl(m_shm_segment_info->shmid, IPC_RMID, 0); m_display = nullptr; if(m_shm_segment_info){ m_shm_segment_info->shmaddr = (char*)-1; m_shm_segment_info->shmid = -1; delete m_shm_segment_info; m_shm_segment_info = nullptr; return true; } /* namespace RemoteServer */

首先是初始化InitVideoCapture
在初始化过程中,首先通过XOpenDisplay(NULL)获取X11的默认DISPLAY。参数可以直接设置为DISPLAY号,如图我的DISPLAY是:1。就可以写成XOpenDisplay(:1)

在这里插入图片描述
然后获取根窗口,也就是你的桌面窗口。

m_desktop_window = RootWindow(m_display, 0);

然后获取屏幕宽高

m_video_format->width = DisplayWidth(m_display, 0);
m_video_format->height = DisplayHeight(m_display, 0);

通过XGetImage获取到当前屏幕信息,包括宽、高、位深等信息。

XImage* window_image = XGetImage(m_display, m_desktop_window, 0, 0, m_video_format->width, m_video_format->height, AllPlanes, ZPixmap);

如果只是想要截屏,把window_image->data数据保存下来就是原始的RGB图像信息了。
使用后记得销毁,不然就内存泄露了

XDestroyImage(window_image);

如果想要录屏的话,用XGetImage的方式效率极低。要使用X共享内存的方式进行捕获。首先对X共享内存初始化。

InitShmImages()

在初始化过程中,对将X共享内存与当前DISPLAY进行绑定,这样以后可以通过读取共享内存数据直接捕获当前DISPLAY的屏幕

XShmAttach(m_display, m_shm_segment_info)

初始化以后,便可以通过XShmGetImage函数直接高效的捕获当前屏幕的数据了

XShmGetImage(m_display, m_desktop_window, m_x_shm_image, 0, 0, AllPlanes)

最后记得要释放掉共享内存

DestroyVideoCapture()

通过测试程序捕获屏幕

#include "VideoCapture/VideoCapture.h"
#include "Logger/Logger.h"
#include <fstream>
#include <memory>
#include <unistd.h>
#include "../../src/Base/BufferQueue/BufferQueue.hpp"
using namespace RemoteServer;
int main(){
	SimLogger::Logger::CreateLoggerInstance();
	SimLogger::Logger::InitLogger(SimLogger::ConsoleType, "LoggerTest", SimLogger::Info);
	std::ofstream file_stream("x11capture.rgb", std::ios::out | std::ios::binary);
	auto buffer_queue = std::make_shared< BufferQueue<unsigned char> >(5);
	auto video_capture = VideoCapture::CreateVideoCapture(X11Desktop, buffer_queue);
	auto format = video_capture->GetVideoFormat();
	int screen_size = format->width * format->height * format->bits_per_pixel / 8;
//	unsigned char* data = new unsigned char[screen_size];
	video_capture->StartVideoCapture();
	int count = 0;
	while(count++ < 500){
		std::vector<unsigned char> buffer;
		buffer_queue->WaitePopBuffer(buffer);
		file_stream.write(reinterpret_cast<char*>(buffer.data()), screen_size);
		usleep(20000);
	video_capture->StopVideoCapture();
	file_stream.close();
//	delete[] data;
	video_capture->DestroyVideoCapture();
	return 0;

捕获了500帧RGB原始数据存放在x11capture.rgb中。

githup地址

自己用C++写的一个多功能简易录屏软件Ericord(附源码) 由自己编写的一个简单的录屏软件,但功能样样齐全,可以满足日常需求。(可调整区域,可自动检测分辨率,可调整帧速率,可调整输出格式[mpg/avi格式都支持]) 本软件是开源的,提供源码以供学习交流。使用前请务必点击“关于”按钮,查看使用须知,非常重要!!! *实现方式:有Dev-c++生成,对FFmpeg那比较复杂的录屏功能进行了封装,使得操作简单程度大幅度上升。具体实现方式可以参看源码。 本课程主要讲解OBS源码的编译,OBS功能实现,初始化,显示器录制,窗口的实现录制,以及录制模块源码详细分析,最后基本OBS源码开发了一个录制软件,界面如下: 主要有如下功能 (1)实现桌面,显示器采集、录制 (2)指定应用程序窗口进行录制 (3)可以选择系统声音,麦克风进行录制 (4)稳定fps 60,高清原画,鼠标不闪,、音视频同步,无卡顿,无延时 (5)可以指定帧率录制,5-60 fps都可以 (6)显示了系统托盘,录制时可以最小化到系统托盘 课程链接:https://edu.csdn.net/co MIT-SHM—The MIT Shared Memory Extension How the shared memory extension works 1. REQUIREMENTS 2. WHAT IS PROVIDED 3. HOW TO USE THE SHARED MEMORY 代码是用libpng和x11绘制的一张图片,希望对你们有所帮助。#include &lt;X11/Xlib.h&gt; #include &lt;stdio.h&gt; #include &lt;stdlib.h&gt; #include &lt;unistd.h&gt; #include &lt;png.h&gt; #include &lt;X11/Xutil.h&gt; #in... /打开视频文件cv::VideoCapture capture("./video/蕾姆海边.mp4");//isOpen判断视频是否打开成功if (!return -1;}//获取视频帧频std::cout 在C++实现X11桌面录屏RGB文件一文中,我们已经实现X11桌面录屏RGB文件。本篇在此基础上利用ffmpeg将RGB编码为H264文件。 一、编译FFMPEG+x264 FFmpeg是一个是一个多媒体处理工具,但是原生的FFMPEG并不带有编码库。而x264是一个h264编解码的库,但是用起来没有ffmeg方便,所以需要我们下载ffmpeg的源码,并将x264编译进去。 具体方法可以参考Linux FFmpeg编译支持aac、h264、h265 二、使用ffmpeg进行编码 直接上代码 今天尝试编写了一个基于 v4l2 的摄像头应用, 目前仅仅实现从摄像头捕捉视频, 然后本地回显. 照例先上效果图, 其中左侧小点为预监窗口, 右侧为经过 x264 压缩, tcp 传输, libavcodec 解压, 再用 qt 显示的效果., 延迟很低很低 :)  主要就是以下几个知识点:     1. v4l2接口:    2. X11的本地回显:    3