screen capture using CGDisplayStreamCreateWithDispatchQueue

来源:互联网 发布:淘宝打假赚钱 编辑:程序博客网 时间:2024/06/06 16:29
#include <sstream> #include <Cocoa/Cocoa.h> #include <CoreFoundation/CoreFoundation.h> #include <screencapture/mac/ScreenCaptureDisplayStream.h>   namespace sc {   ScreenCaptureDisplayStream::ScreenCaptureDisplayStream() :Base() ,stream_ref(NULL) { dq = dispatch_queue_create("com.roxlu.screengrabber", DISPATCH_QUEUE_SERIAL); }   int ScreenCaptureDisplayStream::init() {   /* Fill our cached list of displays.*/ CGDirectDisplayID display_ids[10]; uint32_t found_displays =0CGError err = CGGetActiveDisplayList(10, display_ids, &found_displays);   if (kCGErrorSuccess != err) { printf("Error: failed to retrieve a list of active displays in `ScreenCaptureDisplayStream`.\n"); return -1; }   if (0 == found_displays) { printf("Error: we didn't find any active display.\n"); return -2; }   for (uint32_t i =0; i < found_displays; ++i) { Display* display = new Display(); ScreenCaptureDisplayStreamDisplayInfo* info = new ScreenCaptureDisplayStreamDisplayInfo(); std::stringstream ss; ss << "Monitor" << i; info->id = display_ids[i]; display->info = (void*)info; display->name = ss.str(); displays.push_back(display); }   return 0; }   int ScreenCaptureDisplayStream::shutdown() {   /* Release the stream.*/ if (NULL != stream_ref) { CFRelease(stream_ref); stream_ref = NULL; }   /* Clear our cached list of displays.*/ for (size_t i =0; i < displays.size(); ++i) {   ScreenCaptureDisplayStreamDisplayInfo* info = static_cast<ScreenCaptureDisplayStreamDisplayInfo*>(displays[i]->info); if (NULL == info) { printf("Error: failed to cast back to `ScreenCaptureDisplayStreamDisplayInfo` in `ScreenCaptureDisplayStream`. Not supposed to happen. Leaking memory"); } elsedelete info; info = NULL; }   delete displays[i]; displays[i] = NULL; }   displays.clear();   return 0; }   int ScreenCaptureDisplayStream::configure(Settings settings) {   /* Get the implementation specific display id.*/ ScreenCaptureDisplayStreamDisplayInfo* info = static_cast<ScreenCaptureDisplayStreamDisplayInfo*>(displays[settings.display]->info); if (NULL == info) { printf("Error: failed to cast the display info of stream screen capture. Failed to setup\n"); return -1; }   /* Already a stream? Reset.*/ if (NULL != stream_ref) { if (0 ==isStarted()) { if (0 !=stop()) { printf("We're reconfiguring/setupping the display stream but we were captureing; stopping failed. Not supposed to happen; and you may leak memory here. We continue capturing though.\n"); } }   state &= ~SC_STATE_STARTED; state |= SC_STATE_STOPPED;   CFRelease(stream_ref); stream_ref = NULL; }   uint32_t pixel_format = 0switch (settings.pixel_format) { case SC_420F: { pixel_format = '420f'break; } case SC_420V: { pixel_format = '420v'break; } case SC_BGRA: { pixel_format = 'BGRA'break; } case SC_L10R: { pixel_format = 'l10r'break; } default: { printf("Error: unsupported pixel format; cannot configure display stream.\n"); return -2; } }   __block PixelBuffer pixel_buffer; if (0 != pixel_buffer.init(settings.output_width, settings.output_height, settings.pixel_format)) { printf("Error: failed to setup the the pixel format.\n"); return -3; }   /* @todo > WE DON'T WANT TO MAKE THIS THE RESPONSIBILITY OF AN IMPLEMENTATION!*/ pixel_buffer.user = user;   /* @todo make some settings available through API.*/ void* keys[2]; void* values[2]; CFDictionaryRef opts; keys[0] = (void *)kCGDisplayStreamShowCursor; values[0] = (void *)kCFBooleanTrue; opts = CFDictionaryCreate(kCFAllocatorDefault, (constvoid **) keys, (constvoid **) values, 1, NULL, NULL);   /* UPDATE USING THIS CLEAN CODE: https://gist.github.com/roxlu/60f2f635347863d6384d TEST IF UPDATING THE CHANGED RECTS ONLY IS FASTER */   stream_ref = CGDisplayStreamCreateWithDispatchQueue(info->id, settings.output_width, settings.output_height, pixel_format, opts, dq, ^(CGDisplayStreamFrameStatus status,/* kCGDisplayStreamFrameComplete, *FrameIdle, *FrameBlank, *Stopped*/ uint64_t time, /* Mach absolute time when the event occurred.*/ IOSurfaceRef frame, /* opaque pixel buffer, can be backed by GL, CL, etc.. This may be NULL in some cases. See the docs if you want to keep access to this.*/ CGDisplayStreamUpdateRef ref) { if (kCGDisplayStreamFrameStatusFrameComplete == status && NULL != frame) {   /* n.b. when the user needs to handle the pixel buffer after the call, it needs to make a copy. CGDisplayStream* supports a feature where you can increment the in-use-count, see the documention: https://developer.apple.com/library/mac/documentation/GraphicsImaging/Reference/Quartz_Services_Ref/index.html#//apple_ref/doc/c_ref/CGDisplayStreamFrameAvailableHandler */   IOSurfaceLock(frame, kIOSurfaceLockReadOnly, NULL);   size_t plane_count = IOSurfaceGetPlaneCount(frame);   if (2 == plane_count) { pixel_buffer.plane[0] = (uint8_t*)IOSurfaceGetBaseAddressOfPlane(frame,0); pixel_buffer.stride[0] =IOSurfaceGetBytesPerRowOfPlane(frame,0); pixel_buffer.plane[1] = (uint8_t*)IOSurfaceGetBaseAddressOfPlane(frame,1); pixel_buffer.stride[1] =IOSurfaceGetBytesPerRowOfPlane(frame,1); } else if (0 == plane_count) { pixel_buffer.plane[0] = (uint8_t*)IOSurfaceGetBaseAddress(frame); pixel_buffer.stride[0] =IOSurfaceGetBytesPerRow(frame); } elseprintf("Error: unsupported plane count in the displaystream capture. Cannot setup the pixel buffer. Exiting now.\n"); exit(EXIT_FAILURE); }   callback(pixel_buffer);   IOSurfaceUnlock(frame, kIOSurfaceLockReadOnly, NULL); } } ); if (NULL == stream_ref) { printf("Error: failed to create a display stream that we use to capture the screen.\n"); return -4; }   return 0; }   int ScreenCaptureDisplayStream::start() {   CGError err = CGDisplayStreamStart(stream_ref);   if (kCGErrorSuccess != err) { printf("Error: failed to start the display stream capturer. CGDisplayStreamStart failed: %d .\n", err); return -1; }   return 0; }   int ScreenCaptureDisplayStream::stop() {   CGError err = CGDisplayStreamStop(stream_ref);   if (kCGErrorSuccess != err) { printf("Error: failed to stop the display stream capturer. CGDisplayStreamStart failed: %d .\n", err); return -1; }   return 0; }   int ScreenCaptureDisplayStream::getDisplays(std::vector<Display*>& result) { result = displays; return 0; }   int ScreenCaptureDisplayStream::getPixelFormats(std::vector<int>& formats) {   formats.clear();   formats.push_back(SC_420V); formats.push_back(SC_420F); formats.push_back(SC_BGRA); formats.push_back(SC_L10R);   return 0; }   }; /* namespace sc*/      
0 0
原创粉丝点击