#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)
m_buffer_queue = buffer_queue;
InitVideoCapture();
X11DesktopCapture::~X11DesktopCapture() {
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);
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),
m_video_format->depth,
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);
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);
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;
}
首先是初始化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;
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();
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 <X11/Xlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <png.h>
#include <X11/Xutil.h>
#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