[feat] remove dependence on ffmpeg for MacOSx

This commit is contained in:
dijunkun
2025-05-08 11:33:04 +08:00
parent e89d385f99
commit e2a469ed65
22 changed files with 10 additions and 2927 deletions

View File

@@ -1,212 +0,0 @@
#include "screen_capturer_avf.h"
#include <ApplicationServices/ApplicationServices.h>
#include <iostream>
#include "rd_log.h"
#define USE_SCALE_FACTOR 0
ScreenCapturerAvf::ScreenCapturerAvf() {}
ScreenCapturerAvf::~ScreenCapturerAvf() {
if (inited_ && capture_thread_.joinable()) {
capture_thread_.join();
inited_ = false;
}
if (nv12_frame_) {
delete[] nv12_frame_;
nv12_frame_ = nullptr;
}
if (pFormatCtx_) {
avformat_close_input(&pFormatCtx_);
pFormatCtx_ = nullptr;
}
if (pCodecCtx_) {
avcodec_free_context(&pCodecCtx_);
pCodecCtx_ = nullptr;
}
if (options_) {
av_dict_free(&options_);
options_ = nullptr;
}
if (pFrame_) {
av_frame_free(&pFrame_);
pFrame_ = nullptr;
}
if (packet_) {
av_packet_free(&packet_);
packet_ = nullptr;
}
#if USE_SCALE_FACTOR
if (img_convert_ctx_) {
sws_freeContext(img_convert_ctx_);
img_convert_ctx_ = nullptr;
}
#endif
}
int ScreenCapturerAvf::Init(const int fps, cb_desktop_data cb) {
if (cb) {
_on_data = cb;
}
av_log_set_level(AV_LOG_QUIET);
pFormatCtx_ = avformat_alloc_context();
avdevice_register_all();
// grabbing frame rate
av_dict_set(&options_, "framerate", "60", 0);
av_dict_set(&options_, "pixel_format", "nv12", 0);
// show remote cursor
av_dict_set(&options_, "capture_cursor", "0", 0);
// Make the grabbed area follow the mouse
// av_dict_set(&options_, "follow_mouse", "centered", 0);
// Video frame size. The default is to capture the full screen
// av_dict_set(&options_, "video_size", "1440x900", 0);
ifmt_ = (AVInputFormat *)av_find_input_format("avfoundation");
if (!ifmt_) {
printf("Couldn't find_input_format\n");
}
// Grab at position 10,20
if (avformat_open_input(&pFormatCtx_, "Capture screen 0", ifmt_, &options_) !=
0) {
printf("Couldn't open input stream.\n");
return -1;
}
if (avformat_find_stream_info(pFormatCtx_, NULL) < 0) {
printf("Couldn't find stream information.\n");
return -1;
}
videoindex_ = -1;
for (i_ = 0; i_ < pFormatCtx_->nb_streams; i_++)
if (pFormatCtx_->streams[i_]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
videoindex_ = i_;
break;
}
if (videoindex_ == -1) {
printf("Didn't find a video stream.\n");
return -1;
}
pCodecParam_ = pFormatCtx_->streams[videoindex_]->codecpar;
pCodecCtx_ = avcodec_alloc_context3(NULL);
avcodec_parameters_to_context(pCodecCtx_, pCodecParam_);
pCodec_ = const_cast<AVCodec *>(avcodec_find_decoder(pCodecCtx_->codec_id));
if (pCodec_ == NULL) {
printf("Codec not found.\n");
return -1;
}
if (avcodec_open2(pCodecCtx_, pCodec_, NULL) < 0) {
printf("Could not open codec.\n");
return -1;
}
const int screen_w = pFormatCtx_->streams[videoindex_]->codecpar->width;
const int screen_h = pFormatCtx_->streams[videoindex_]->codecpar->height;
pFrame_ = av_frame_alloc();
pFrame_->width = screen_w;
pFrame_->height = screen_h;
#if USE_SCALE_FACTOR
pFrame_resized_ = av_frame_alloc();
pFrame_resized_->width = CGDisplayPixelsWide(CGMainDisplayID());
pFrame_resized_->height = CGDisplayPixelsHigh(CGMainDisplayID());
img_convert_ctx_ =
sws_getContext(pFrame_->width, pFrame_->height, pCodecCtx_->pix_fmt,
pFrame_resized_->width, pFrame_resized_->height,
AV_PIX_FMT_NV12, SWS_BICUBIC, NULL, NULL, NULL);
#endif
if (!nv12_frame_) {
nv12_frame_ = new unsigned char[screen_w * screen_h * 3 / 2];
}
packet_ = (AVPacket *)av_malloc(sizeof(AVPacket));
inited_ = true;
return 0;
}
int ScreenCapturerAvf::Destroy() {
running_ = false;
return 0;
}
int ScreenCapturerAvf::Start() {
if (running_) {
return 0;
}
running_ = true;
capture_thread_ = std::thread([this]() {
while (running_) {
if (av_read_frame(pFormatCtx_, packet_) >= 0) {
if (packet_->stream_index == videoindex_) {
avcodec_send_packet(pCodecCtx_, packet_);
av_packet_unref(packet_);
got_picture_ = avcodec_receive_frame(pCodecCtx_, pFrame_);
if (!got_picture_) {
#if USE_SCALE_FACTOR
av_image_fill_arrays(pFrame_resized_->data,
pFrame_resized_->linesize, nv12_frame_,
AV_PIX_FMT_NV12, pFrame_resized_->width,
pFrame_resized_->height, 1);
sws_scale(img_convert_ctx_, pFrame_->data, pFrame_->linesize, 0,
pFrame_->height, pFrame_resized_->data,
pFrame_resized_->linesize);
_on_data((unsigned char *)nv12_frame_,
pFrame_resized_->width * pFrame_resized_->height * 3 / 2,
pFrame_resized_->width, pFrame_resized_->height);
#else
memcpy(nv12_frame_, pFrame_->data[0],
pFrame_->linesize[0] * pFrame_->height);
memcpy(nv12_frame_ + pFrame_->linesize[0] * pFrame_->height,
pFrame_->data[1],
pFrame_->linesize[1] * pFrame_->height / 2);
_on_data((unsigned char *)nv12_frame_,
pFrame_->width * pFrame_->height * 3 / 2, pFrame_->width,
pFrame_->height);
#endif
}
}
}
}
});
return 0;
}
int ScreenCapturerAvf::Stop() {
running_ = false;
return 0;
}
int ScreenCapturerAvf::Pause() { return 0; }
int ScreenCapturerAvf::Resume() { return 0; }
void ScreenCapturerAvf::OnFrame() {}
void ScreenCapturerAvf::CleanUp() {}

View File

@@ -1,87 +0,0 @@
/*
* @Author: DI JUNKUN
* @Date: 2023-12-01
* Copyright (c) 2023 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _SCREEN_CAPTURER_AVF_H_
#define _SCREEN_CAPTURER_AVF_H_
#include <atomic>
#include <functional>
#include <string>
#include <thread>
#include "screen_capturer.h"
#ifdef __cplusplus
extern "C" {
#endif
#include <libavcodec/avcodec.h>
#include <libavdevice/avdevice.h>
#include <libavformat/avformat.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
#ifdef __cplusplus
};
#endif
class ScreenCapturerAvf : public ScreenCapturer {
public:
ScreenCapturerAvf();
~ScreenCapturerAvf();
public:
virtual int Init(const int fps, cb_desktop_data cb);
virtual int Destroy();
virtual int Start();
virtual int Stop();
int Pause();
int Resume();
void OnFrame();
protected:
void CleanUp();
private:
std::atomic_bool _paused;
std::atomic_bool _inited;
std::thread _thread;
std::string _device_name;
int _fps;
cb_desktop_data _on_data;
private:
int i_ = 0;
int videoindex_ = 0;
int got_picture_ = 0;
bool inited_ = false;
// ffmpeg
AVFormatContext *pFormatCtx_ = nullptr;
AVCodecContext *pCodecCtx_ = nullptr;
AVCodec *pCodec_ = nullptr;
AVCodecParameters *pCodecParam_ = nullptr;
AVDictionary *options_ = nullptr;
AVInputFormat *ifmt_ = nullptr;
AVFrame *pFrame_ = nullptr;
AVFrame *pFrame_resized_ = nullptr;
AVPacket *packet_ = nullptr;
struct SwsContext *img_convert_ctx_ = nullptr;
unsigned char *nv12_frame_ = nullptr;
// thread
std::thread capture_thread_;
std::atomic_bool running_;
};
#endif

View File

@@ -1,104 +0,0 @@
#include <IOSurface/IOSurface.h>
#include <utility>
#include "rd_log.h"
#include "screen_capturer_cgd.h"
ScreenCapturerCg::ScreenCapturerCg() {}
ScreenCapturerCg::~ScreenCapturerCg() {}
int ScreenCapturerCg::Init(const int fps, cb_desktop_data cb) {
if (cb) {
_on_data = cb;
}
size_t pixel_width = 1280;
size_t pixel_height = 720;
CGDirectDisplayID display_id = 0;
CGDisplayStreamFrameAvailableHandler handler =
^(CGDisplayStreamFrameStatus status, uint64_t display_time,
IOSurfaceRef frame_surface, CGDisplayStreamUpdateRef updateRef) {
if (status == kCGDisplayStreamFrameStatusStopped) return;
// Only pay attention to frame updates.
if (status != kCGDisplayStreamFrameStatusFrameComplete) return;
// size_t count = 0;
// const CGRect* rects = CGDisplayStreamUpdateGetRects(
// updateRef, kCGDisplayStreamUpdateDirtyRects, &count);
// 获取帧数据
void* frameData = IOSurfaceGetBaseAddressOfPlane(frame_surface, 0);
size_t width = IOSurfaceGetWidthOfPlane(frame_surface, 0);
size_t height = IOSurfaceGetHeightOfPlane(frame_surface, 0);
};
CFDictionaryRef properties_dictionary = CFDictionaryCreate(
kCFAllocatorDefault, (const void*[]){kCGDisplayStreamShowCursor},
(const void*[]){kCFBooleanFalse}, 1, &kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CGDisplayStreamRef display_stream =
CGDisplayStreamCreate(display_id, pixel_width, pixel_height, 'BGRA',
properties_dictionary, handler);
if (display_stream) {
CGError error = CGDisplayStreamStart(display_stream);
if (error != kCGErrorSuccess) return -1;
CFRunLoopSourceRef source = CGDisplayStreamGetRunLoopSource(display_stream);
CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopCommonModes);
display_streams_.push_back(display_stream);
}
CFRelease(properties_dictionary);
return 0;
}
int ScreenCapturerCg::Destroy() {
running_ = false;
return 0;
}
int ScreenCapturerCg::Start() {
if (_running) {
return 0;
}
running_ = true;
capture_thread_ = std::thread([this]() {
while (running_) {
CFRunLoopRun();
}
});
return 0;
}
int ScreenCapturerCg::Stop() {
running_ = false;
return 0;
}
int ScreenCapturerCg::Pause() { return 0; }
int ScreenCapturerCg::Resume() { return 0; }
void ScreenCapturerCg::OnFrame() {}
void ScreenCapturerCg::CleanUp() {}
//
void ScreenCapturerCg::UnregisterRefreshAndMoveHandlers() {
for (CGDisplayStreamRef stream : display_streams_) {
CFRunLoopSourceRef source = CGDisplayStreamGetRunLoopSource(stream);
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), source, kCFRunLoopCommonModes);
CGDisplayStreamStop(stream);
CFRelease(stream);
}
display_streams_.clear();
}

View File

@@ -1,56 +0,0 @@
/*
* @Author: DI JUNKUN
* @Date: 2024-10-16
* Copyright (c) 2024 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _SCREEN_CAPTURER_CGD_H_
#define _SCREEN_CAPTURER_CGD_H_
#include <CoreGraphics/CoreGraphics.h>
#include <atomic>
#include <functional>
#include <memory>
#include <string>
#include <thread>
#include <vector>
#include "screen_capturer.h"
class ScreenCapturerCg : public ScreenCapturer {
public:
ScreenCapturerCg();
~ScreenCapturerCg();
public:
virtual int Init(const int fps, cb_desktop_data cb);
virtual int Destroy();
virtual int Start();
virtual int Stop();
int Pause();
int Resume();
void OnFrame();
protected:
void CleanUp();
private:
int _fps;
cb_desktop_data _on_data;
// thread
std::thread capture_thread_;
std::atomic_bool running_;
private:
};
#endif