move sunshine to src
- this will allow for common cpp workflow files within org
This commit is contained in:
196
src/platform/macos/display.mm
Normal file
196
src/platform/macos/display.mm
Normal file
@@ -0,0 +1,196 @@
|
||||
#include "src/platform/common.h"
|
||||
#include "src/platform/macos/av_img_t.h"
|
||||
#include "src/platform/macos/av_video.h"
|
||||
#include "src/platform/macos/nv12_zero_device.h"
|
||||
|
||||
#include "src/config.h"
|
||||
#include "src/main.h"
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace platf {
|
||||
using namespace std::literals;
|
||||
|
||||
av_img_t::~av_img_t() {
|
||||
if(pixel_buffer != NULL) {
|
||||
CVPixelBufferUnlockBaseAddress(pixel_buffer, 0);
|
||||
}
|
||||
|
||||
if(sample_buffer != nullptr) {
|
||||
CFRelease(sample_buffer);
|
||||
}
|
||||
|
||||
data = nullptr;
|
||||
}
|
||||
|
||||
struct av_display_t : public display_t {
|
||||
AVVideo *av_capture;
|
||||
CGDirectDisplayID display_id;
|
||||
|
||||
~av_display_t() {
|
||||
[av_capture release];
|
||||
}
|
||||
|
||||
capture_e capture(snapshot_cb_t &&snapshot_cb, std::shared_ptr<img_t> img, bool *cursor) override {
|
||||
__block auto img_next = std::move(img);
|
||||
|
||||
auto signal = [av_capture capture:^(CMSampleBufferRef sampleBuffer) {
|
||||
auto av_img_next = std::static_pointer_cast<av_img_t>(img_next);
|
||||
|
||||
CFRetain(sampleBuffer);
|
||||
|
||||
CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
|
||||
CVPixelBufferLockBaseAddress(pixelBuffer, kCVPixelBufferLock_ReadOnly);
|
||||
|
||||
if(av_img_next->pixel_buffer != nullptr)
|
||||
CVPixelBufferUnlockBaseAddress(av_img_next->pixel_buffer, 0);
|
||||
|
||||
if(av_img_next->sample_buffer != nullptr)
|
||||
CFRelease(av_img_next->sample_buffer);
|
||||
|
||||
av_img_next->sample_buffer = sampleBuffer;
|
||||
av_img_next->pixel_buffer = pixelBuffer;
|
||||
img_next->data = (uint8_t *)CVPixelBufferGetBaseAddress(pixelBuffer);
|
||||
|
||||
size_t extraPixels[4];
|
||||
CVPixelBufferGetExtendedPixels(pixelBuffer, &extraPixels[0], &extraPixels[1], &extraPixels[2], &extraPixels[3]);
|
||||
|
||||
img_next->width = CVPixelBufferGetWidth(pixelBuffer) + extraPixels[0] + extraPixels[1];
|
||||
img_next->height = CVPixelBufferGetHeight(pixelBuffer) + extraPixels[2] + extraPixels[3];
|
||||
img_next->row_pitch = CVPixelBufferGetBytesPerRow(pixelBuffer);
|
||||
img_next->pixel_pitch = img_next->row_pitch / img_next->width;
|
||||
|
||||
img_next = snapshot_cb(img_next);
|
||||
|
||||
return img_next != nullptr;
|
||||
}];
|
||||
|
||||
dispatch_semaphore_wait(signal, DISPATCH_TIME_FOREVER);
|
||||
|
||||
return capture_e::ok;
|
||||
}
|
||||
|
||||
std::shared_ptr<img_t> alloc_img() override {
|
||||
return std::make_shared<av_img_t>();
|
||||
}
|
||||
|
||||
std::shared_ptr<hwdevice_t> make_hwdevice(pix_fmt_e pix_fmt) override {
|
||||
if(pix_fmt == pix_fmt_e::yuv420p) {
|
||||
av_capture.pixelFormat = kCVPixelFormatType_32BGRA;
|
||||
|
||||
return std::make_shared<hwdevice_t>();
|
||||
}
|
||||
else if(pix_fmt == pix_fmt_e::nv12) {
|
||||
auto device = std::make_shared<nv12_zero_device>();
|
||||
|
||||
device->init(static_cast<void *>(av_capture), setResolution, setPixelFormat);
|
||||
|
||||
return device;
|
||||
}
|
||||
else {
|
||||
BOOST_LOG(error) << "Unsupported Pixel Format."sv;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
int dummy_img(img_t *img) override {
|
||||
auto signal = [av_capture capture:^(CMSampleBufferRef sampleBuffer) {
|
||||
auto av_img = (av_img_t *)img;
|
||||
|
||||
CFRetain(sampleBuffer);
|
||||
|
||||
CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
|
||||
CVPixelBufferLockBaseAddress(pixelBuffer, kCVPixelBufferLock_ReadOnly);
|
||||
|
||||
// XXX: next_img->img should be moved to a smart pointer with
|
||||
// the CFRelease as custom deallocator
|
||||
if(av_img->pixel_buffer != nullptr)
|
||||
CVPixelBufferUnlockBaseAddress(((av_img_t *)img)->pixel_buffer, 0);
|
||||
|
||||
if(av_img->sample_buffer != nullptr)
|
||||
CFRelease(av_img->sample_buffer);
|
||||
|
||||
av_img->sample_buffer = sampleBuffer;
|
||||
av_img->pixel_buffer = pixelBuffer;
|
||||
img->data = (uint8_t *)CVPixelBufferGetBaseAddress(pixelBuffer);
|
||||
|
||||
size_t extraPixels[4];
|
||||
CVPixelBufferGetExtendedPixels(pixelBuffer, &extraPixels[0], &extraPixels[1], &extraPixels[2], &extraPixels[3]);
|
||||
|
||||
img->width = CVPixelBufferGetWidth(pixelBuffer) + extraPixels[0] + extraPixels[1];
|
||||
img->height = CVPixelBufferGetHeight(pixelBuffer) + extraPixels[2] + extraPixels[3];
|
||||
img->row_pitch = CVPixelBufferGetBytesPerRow(pixelBuffer);
|
||||
img->pixel_pitch = img->row_pitch / img->width;
|
||||
|
||||
return false;
|
||||
}];
|
||||
|
||||
dispatch_semaphore_wait(signal, DISPATCH_TIME_FOREVER);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* A bridge from the pure C++ code of the hwdevice_t class to the pure Objective C code.
|
||||
*
|
||||
* display --> an opaque pointer to an object of this class
|
||||
* width --> the intended capture width
|
||||
* height --> the intended capture height
|
||||
*/
|
||||
static void setResolution(void *display, int width, int height) {
|
||||
[static_cast<AVVideo *>(display) setFrameWidth:width frameHeight:height];
|
||||
}
|
||||
|
||||
static void setPixelFormat(void *display, OSType pixelFormat) {
|
||||
static_cast<AVVideo *>(display).pixelFormat = pixelFormat;
|
||||
}
|
||||
};
|
||||
|
||||
std::shared_ptr<display_t> display(platf::mem_type_e hwdevice_type, const std::string &display_name, int framerate) {
|
||||
if(hwdevice_type != platf::mem_type_e::system) {
|
||||
BOOST_LOG(error) << "Could not initialize display with the given hw device type."sv;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto display = std::make_shared<av_display_t>();
|
||||
|
||||
display->display_id = CGMainDisplayID();
|
||||
if(!display_name.empty()) {
|
||||
auto display_array = [AVVideo displayNames];
|
||||
|
||||
for(NSDictionary *item in display_array) {
|
||||
NSString *name = item[@"name"];
|
||||
if(name.UTF8String == display_name) {
|
||||
NSNumber *display_id = item[@"id"];
|
||||
display->display_id = [display_id unsignedIntValue];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
display->av_capture = [[AVVideo alloc] initWithDisplay:display->display_id frameRate:framerate];
|
||||
|
||||
if(!display->av_capture) {
|
||||
BOOST_LOG(error) << "Video setup failed."sv;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
display->width = display->av_capture.frameWidth;
|
||||
display->height = display->av_capture.frameHeight;
|
||||
|
||||
return display;
|
||||
}
|
||||
|
||||
std::vector<std::string> display_names(mem_type_e hwdevice_type) {
|
||||
__block std::vector<std::string> display_names;
|
||||
|
||||
auto display_array = [AVVideo displayNames];
|
||||
|
||||
display_names.reserve([display_array count]);
|
||||
[display_array enumerateObjectsUsingBlock:^(NSDictionary *_Nonnull obj, NSUInteger idx, BOOL *_Nonnull stop) {
|
||||
NSString *name = obj[@"name"];
|
||||
display_names.push_back(name.UTF8String);
|
||||
}];
|
||||
|
||||
return display_names;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user