Fix screen capture on MacOS

This commit is contained in:
dijunkun
2023-12-01 17:16:38 +08:00
parent 5febe99bc2
commit 47a2dc85f9
7 changed files with 65 additions and 171 deletions

View File

@@ -49,6 +49,8 @@ extern "C" {
#include "screen_capture_wgc.h" #include "screen_capture_wgc.h"
#elif __linux__ #elif __linux__
#include "screen_capture_x11.h" #include "screen_capture_x11.h"
#elif __APPLE__
#include "screen_capture_avf.h"
#endif #endif
#include "../../thirdparty/projectx/src/interface/x.h" #include "../../thirdparty/projectx/src/interface/x.h"
@@ -157,6 +159,8 @@ static bool done = false;
ScreenCaptureWgc *screen_capture = nullptr; ScreenCaptureWgc *screen_capture = nullptr;
#elif __linux__ #elif __linux__
ScreenCaptureX11 *screen_capture = nullptr; ScreenCaptureX11 *screen_capture = nullptr;
#elif __APPLE__
ScreenCaptureAvf *screen_capture = nullptr;
#endif #endif
char *nv12_buffer = nullptr; char *nv12_buffer = nullptr;
@@ -824,6 +828,31 @@ int main() {
rect.right = 0; rect.right = 0;
rect.bottom = 0; rect.bottom = 0;
last_frame_time_ = std::chrono::high_resolution_clock::now();
screen_capture->Init(
rect, 60,
[](unsigned char *data, int size, int width, int height) -> void {
auto now_time = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> duration =
now_time - last_frame_time_;
auto tc = duration.count() * 1000;
if (tc >= 0) {
SendData(peer_server, DATA_TYPE::VIDEO, (const char *)data,
NV12_BUFFER_SIZE);
last_frame_time_ = now_time;
}
});
screen_capture->Start();
#elif __APPLE__
screen_capture = new ScreenCaptureAvf();
RECORD_DESKTOP_RECT rect;
rect.left = 0;
rect.top = 0;
rect.right = 0;
rect.bottom = 0;
last_frame_time_ = std::chrono::high_resolution_clock::now(); last_frame_time_ = std::chrono::high_resolution_clock::now();
screen_capture->Init( screen_capture->Init(
rect, 60, rect, 60,

View File

@@ -1,4 +1,4 @@
#include "screen_capture_x11.h" #include "screen_capture_avf.h"
#include <iostream> #include <iostream>
@@ -7,21 +7,17 @@
#define NV12_BUFFER_SIZE 1280 * 720 * 3 / 2 #define NV12_BUFFER_SIZE 1280 * 720 * 3 / 2
unsigned char nv12_buffer_[NV12_BUFFER_SIZE]; unsigned char nv12_buffer_[NV12_BUFFER_SIZE];
ScreenCaptureX11::ScreenCaptureX11() {} ScreenCaptureAvf::ScreenCaptureAvf() {}
ScreenCaptureX11::~ScreenCaptureX11() ScreenCaptureAvf::~ScreenCaptureAvf() {
{ if (capture_thread_->joinable()) {
if (capture_thread_->joinable())
{
capture_thread_->join(); capture_thread_->join();
} }
} }
int ScreenCaptureX11::Init(const RECORD_DESKTOP_RECT &rect, const int fps, int ScreenCaptureAvf::Init(const RECORD_DESKTOP_RECT &rect, const int fps,
cb_desktop_data cb) cb_desktop_data cb) {
{ if (cb) {
if (cb)
{
_on_data = cb; _on_data = cb;
} }
@@ -37,33 +33,29 @@ int ScreenCaptureX11::Init(const RECORD_DESKTOP_RECT &rect, const int fps,
// Video frame size. The default is to capture the full screen // Video frame size. The default is to capture the full screen
// av_dict_set(&options_, "video_size", "1280x720", 0); // av_dict_set(&options_, "video_size", "1280x720", 0);
ifmt_ = (AVInputFormat *)av_find_input_format("avfoundation"); ifmt_ = (AVInputFormat *)av_find_input_format("avfoundation");
if (!ifmt_) if (!ifmt_) {
{
printf("Couldn't find_input_format\n"); printf("Couldn't find_input_format\n");
} }
// Grab at position 10,20 // Grab at position 10,20
if (avformat_open_input(&pFormatCtx_, "Capture screen 0", ifmt_, &options_) != 0) if (avformat_open_input(&pFormatCtx_, "Capture screen 0", ifmt_, &options_) !=
{ 0) {
printf("Couldn't open input stream.\n"); printf("Couldn't open input stream.\n");
return -1; return -1;
} }
if (avformat_find_stream_info(pFormatCtx_, NULL) < 0) if (avformat_find_stream_info(pFormatCtx_, NULL) < 0) {
{
printf("Couldn't find stream information.\n"); printf("Couldn't find stream information.\n");
return -1; return -1;
} }
videoindex_ = -1; videoindex_ = -1;
for (i_ = 0; i_ < pFormatCtx_->nb_streams; i_++) for (i_ = 0; i_ < pFormatCtx_->nb_streams; i_++)
if (pFormatCtx_->streams[i_]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) if (pFormatCtx_->streams[i_]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
{
videoindex_ = i_; videoindex_ = i_;
break; break;
} }
if (videoindex_ == -1) if (videoindex_ == -1) {
{
printf("Didn't find a video stream.\n"); printf("Didn't find a video stream.\n");
return -1; return -1;
} }
@@ -74,13 +66,11 @@ int ScreenCaptureX11::Init(const RECORD_DESKTOP_RECT &rect, const int fps,
avcodec_parameters_to_context(pCodecCtx_, pCodecParam_); avcodec_parameters_to_context(pCodecCtx_, pCodecParam_);
pCodec_ = const_cast<AVCodec *>(avcodec_find_decoder(pCodecCtx_->codec_id)); pCodec_ = const_cast<AVCodec *>(avcodec_find_decoder(pCodecCtx_->codec_id));
if (pCodec_ == NULL) if (pCodec_ == NULL) {
{
printf("Codec not found.\n"); printf("Codec not found.\n");
return -1; return -1;
} }
if (avcodec_open2(pCodecCtx_, pCodec_, NULL) < 0) if (avcodec_open2(pCodecCtx_, pCodec_, NULL) < 0) {
{
printf("Could not open codec.\n"); printf("Could not open codec.\n");
return -1; return -1;
} }
@@ -105,10 +95,8 @@ int ScreenCaptureX11::Init(const RECORD_DESKTOP_RECT &rect, const int fps,
return 0; return 0;
} }
int ScreenCaptureX11::Start() int ScreenCaptureAvf::Start() {
{ capture_thread_.reset(new std::thread([this]() {
capture_thread_.reset(new std::thread([this]()
{
while (1) { while (1) {
if (av_read_frame(pFormatCtx_, packet_) >= 0) { if (av_read_frame(pFormatCtx_, packet_) >= 0) {
if (packet_->stream_index == videoindex_) { if (packet_->stream_index == videoindex_) {
@@ -131,17 +119,18 @@ int ScreenCaptureX11::Start()
} }
} }
} }
} })); }
}));
return 0; return 0;
} }
int ScreenCaptureX11::Pause() { return 0; } int ScreenCaptureAvf::Pause() { return 0; }
int ScreenCaptureX11::Resume() { return 0; } int ScreenCaptureAvf::Resume() { return 0; }
int ScreenCaptureX11::Stop() { return 0; } int ScreenCaptureAvf::Stop() { return 0; }
void ScreenCaptureX11::OnFrame() {} void ScreenCaptureAvf::OnFrame() {}
void ScreenCaptureX11::CleanUp() {} void ScreenCaptureAvf::CleanUp() {}

View File

@@ -1,5 +1,11 @@
#ifndef _SCREEN_CAPTURE_X11_H_ /*
#define _SCREEN_CAPTURE_X11_H_ * @Author: DI JUNKUN
* @Date: 2023-12-01
* Copyright (c) 2023 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _SCREEN_CAPTURE_AVF_H_
#define _SCREEN_CAPTURE_AVF_H_
#include <atomic> #include <atomic>
#include <functional> #include <functional>
@@ -28,10 +34,10 @@ typedef struct {
typedef std::function<void(unsigned char *, int, int, int)> cb_desktop_data; typedef std::function<void(unsigned char *, int, int, int)> cb_desktop_data;
typedef std::function<void(int)> cb_desktop_error; typedef std::function<void(int)> cb_desktop_error;
class ScreenCaptureX11 { class ScreenCaptureAvf {
public: public:
ScreenCaptureX11(); ScreenCaptureAvf();
~ScreenCaptureX11(); ~ScreenCaptureAvf();
public: public:
int Init(const RECORD_DESKTOP_RECT &rect, const int fps, cb_desktop_data cb); int Init(const RECORD_DESKTOP_RECT &rect, const int fps, cb_desktop_data cb);

View File

@@ -1,37 +0,0 @@
#ifndef _X11_SESSION_H_
#define _X11_SESSION_H_
class X11Session {
public:
struct x11_session_frame {
unsigned int width;
unsigned int height;
unsigned int row_pitch;
const unsigned char *data;
};
class x11_session_observer {
public:
virtual ~x11_session_observer() {}
virtual void OnFrame(const x11_session_frame &frame) = 0;
};
public:
virtual void Release() = 0;
virtual int Initialize() = 0;
virtual void RegisterObserver(x11_session_observer *observer) = 0;
virtual int Start() = 0;
virtual int Stop() = 0;
virtual int Pause() = 0;
virtual int Resume() = 0;
protected:
virtual ~X11Session(){};
};
#endif

View File

@@ -1,49 +0,0 @@
#include "x11_session_impl.h"
#include <atomic>
#include <functional>
#include <iostream>
#include <memory>
#define CHECK_INIT \
if (!is_initialized_) { \
std::cout << "AE_NEED_INIT" << std::endl; \
return 4; \
}
X11SessionImpl::X11SessionImpl() {}
X11SessionImpl::~X11SessionImpl() {
Stop();
CleanUp();
}
void X11SessionImpl::Release() { delete this; }
int X11SessionImpl::Initialize() { return 0; }
void X11SessionImpl::RegisterObserver(x11_session_observer *observer) {
observer_ = observer;
}
int X11SessionImpl::Start() {
if (is_running_) return 0;
int error = 1;
CHECK_INIT;
return error;
}
int X11SessionImpl::Stop() { return 0; }
int X11SessionImpl::Pause() { return 0; }
int X11SessionImpl::Resume() { return 0; }
void X11SessionImpl::OnFrame() {}
void X11SessionImpl::OnClosed() {}
void X11SessionImpl::CleanUp() {}

View File

@@ -1,44 +0,0 @@
#ifndef _WGC_SESSION_IMPL_H_
#define _WGC_SESSION_IMPL_H_
#include <mutex>
#include <thread>
#include "x11_session.h"
class X11SessionImpl : public X11Session {
public:
X11SessionImpl();
~X11SessionImpl() override;
public:
void Release() override;
int Initialize() override;
void RegisterObserver(x11_session_observer *observer) override;
int Start() override;
int Stop() override;
int Pause() override;
int Resume() override;
private:
void OnFrame();
void OnClosed();
void CleanUp();
// void message_func();
private:
std::mutex lock_;
bool is_initialized_ = false;
bool is_running_ = false;
bool is_paused_ = false;
x11_session_observer *observer_ = nullptr;
};
#endif