first commit

This commit is contained in:
wdp
2024-12-15 20:42:32 +08:00
commit 986b2fca12
586 changed files with 154149 additions and 0 deletions

View File

@@ -0,0 +1,304 @@
/***************************************************************************************
*
* IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
*
* By downloading, copying, installing or using the software you agree to this license.
* If you do not agree to this license, do not download, install,
* copy or use the software.
*
* Copyright (C) 2014-2022, Happytimesoft Corporation, all rights reserved.
*
* Redistribution and use in binary forms, with or without modification, are permitted.
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*
****************************************************************************************/
#include "sys_inc.h"
#include "window_capture_avf.h"
#include <libavutil/pixfmt.h>
#import <AVFoundation/AVFoundation.h>
/***************************************************************************************/
typedef struct
{
double framerate;
int width;
int height;
char window_title[256];
int window_id;
enum AVPixelFormat pixel_format;
avf_window_callback callback;
void * userdata;
} AVFWindowContext;
/***************************************************************************************/
#define WINDOW_NAME ((NSString *)kCGWindowName)
#define WINDOW_NUMBER ((NSString *)kCGWindowNumber)
#define WINDOW_LAYER ((NSString *)kCGWindowLayer)
#define OWNER_NAME ((NSString *)kCGWindowOwnerName)
#define OWNER_PID ((NSNumber *)kCGWindowOwnerPID)
static NSComparator win_info_cmp = ^(NSDictionary *o1, NSDictionary *o2)
{
NSComparisonResult res = [o1[OWNER_NAME] compare:o2[OWNER_NAME]];
if (res != NSOrderedSame)
return res;
res = [o1[OWNER_PID] compare:o2[OWNER_PID]];
if (res != NSOrderedSame)
return res;
res = [o1[WINDOW_NAME] compare:o2[WINDOW_NAME]];
if (res != NSOrderedSame)
return res;
return [o1[WINDOW_NUMBER] compare:o2[WINDOW_NUMBER]];
};
static CGImageRef avf_window_get_image(int window_id)
{
NSArray *arr = (NSArray *)CGWindowListCreate(
kCGWindowListOptionIncludingWindow, window_id);
[arr autorelease];
if (!arr.count)
{
return NULL;
}
return CGWindowListCreateImage(CGRectNull,
kCGWindowListOptionIncludingWindow,
window_id, kCGWindowImageDefault);
}
NSArray * avf_window_enumerate()
{
NSArray *arr = (NSArray *)CGWindowListCopyWindowInfo(
kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements, kCGNullWindowID);
[arr autorelease];
return [arr sortedArrayUsingComparator:win_info_cmp];
}
void avf_window_list()
{
NSArray *arr = avf_window_enumerate();
printf("\r\nAvailable window name : \r\n\r\n");
for (NSDictionary *dict in arr)
{
NSNumber *layer = (NSNumber *)dict[WINDOW_LAYER];
if (0 != layer.intValue)
{
continue;
}
NSString *name = (NSString *)dict[WINDOW_NAME];
printf("%s\r\n", name.UTF8String);
}
}
void * avf_window_init(char * title, int width, int height, double framerate)
{
AVFWindowContext * context = (AVFWindowContext *)malloc(sizeof(AVFWindowContext));
if (NULL == context)
{
return NULL;
}
memset(context, 0, sizeof(AVFWindowContext));
strncpy(context->window_title, title, sizeof(context->window_title));
context->width = width;
context->height = height;
context->framerate = framerate;
NSArray *arr = avf_window_enumerate();
for (NSDictionary *dict in arr)
{
NSNumber *layer = (NSNumber *)dict[WINDOW_LAYER];
if (0 != layer.intValue)
{
continue;
}
NSString *name = (NSString *)dict[WINDOW_NAME];
NSNumber *wid = (NSNumber *)dict[WINDOW_NUMBER];
if (strncasecmp(name.UTF8String, title, strlen(title)) == 0)
{
context->window_id = wid.intValue;
break;
}
}
if (0 == context->window_id)
{
free(context);
log_print(HT_LOG_ERR, "%s, not found window, %s\r\n", __FUNCTION__, title);
return NULL;
}
CGImageRef img = avf_window_get_image(context->window_id);
if (!img)
{
free(context);
log_print(HT_LOG_ERR, "%s, avf_window_get_image failed\r\n", __FUNCTION__);
return NULL;
}
size_t img_width = CGImageGetWidth(img);
size_t img_height = CGImageGetHeight(img);
if (!img_width || !img_height || CGImageGetBitsPerPixel(img) != 32 ||
CGImageGetBitsPerComponent(img) != 8)
{
CGImageRelease(img);
free(context);
log_print(HT_LOG_ERR, "%s, invalid image format!\r\n", __FUNCTION__);
return NULL;
}
CGImageRelease(img);
context->width = img_width;
context->height = img_height;
context->pixel_format = AV_PIX_FMT_BGR0;
return context;
}
void avf_window_uninit(void * ctx)
{
if (NULL == ctx)
{
return;
}
AVFWindowContext * context = (AVFWindowContext *)ctx;
free(context);
}
void avf_window_set_callback(void * ctx, avf_window_callback cb, void * userdata)
{
if (NULL == ctx)
{
return;
}
AVFWindowContext * context = (AVFWindowContext *)ctx;
context->callback = cb;
context->userdata = userdata;
}
int avf_window_get_width(void * ctx)
{
if (NULL == ctx)
{
return 0;
}
AVFWindowContext * context = (AVFWindowContext *)ctx;
return context->width;
}
int avf_window_get_height(void * ctx)
{
if (NULL == ctx)
{
return 0;
}
AVFWindowContext * context = (AVFWindowContext *)ctx;
return context->height;
}
int avf_window_get_pixfmt(void * ctx)
{
if (NULL == ctx)
{
return AV_PIX_FMT_NONE;
}
AVFWindowContext * context = (AVFWindowContext *)ctx;
return context->pixel_format;
}
BOOL avf_window_capture(AVFWindowContext * context)
{
CGImageRef img = avf_window_get_image(context->window_id);
if (!img)
{
return FALSE;
}
size_t width = CGImageGetWidth(img);
size_t height = CGImageGetHeight(img);
if (!width || !height || CGImageGetBitsPerPixel(img) != 32 ||
CGImageGetBitsPerComponent(img) != 8)
{
CGImageRelease(img);
return FALSE;
}
CGDataProviderRef provider = CGImageGetDataProvider(img);
CFDataRef data = CGDataProviderCopyData(provider);
avf_window_data frame;
memset(&frame, 0, sizeof(frame));
frame.width = width;
frame.height = height;
frame.format = context->pixel_format;
frame.data[0] = (uint8 *)CFDataGetBytePtr(data);
frame.linesize[0] = CGImageGetBytesPerRow(img);
if (context->callback)
{
context->callback(&frame, context->userdata);
}
CGImageRelease(img);
CFRelease(data);
return TRUE;
}
BOOL avf_window_read(void * ctx)
{
if (NULL == ctx)
{
return FALSE;
}
BOOL ret = FALSE;
AVFWindowContext * context = (AVFWindowContext *)ctx;
@autoreleasepool {
ret = avf_window_capture(context);
}
return ret;
}