IOSurface - IOS Private API - Capture screenshot in background

后端 未结 1 1852
鱼传尺愫
鱼传尺愫 2020-12-13 16:26

I want to capture a screenshot from a background service. Private API is just fine as I don\'t need to submit to app store. I have already tried UIGetScreenImage and it does

相关标签:
1条回答
  • 2020-12-13 17:11

    After combining code from 2 places, I was able to save photo to photo album (with my application in background).

    IOSurfaces - Artefacts in video and unable to grab video surfaces

    https://github.com/tomcool420/SMFramework/blob/master/SMFScreenCapture.m

    Please try out and let me know if it works for you.

    -(void)SavePhoto
    {
        IOMobileFramebufferConnection connect;
        kern_return_t result;
        IOSurfaceRef screenSurface = NULL;
    
        io_service_t framebufferService = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleH1CLCD"));
        if(!framebufferService)
            framebufferService = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleM2CLCD"));
        if(!framebufferService)
            framebufferService = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleCLCD"));
    
        result = IOMobileFramebufferOpen(framebufferService, mach_task_self(), 0, &connect);
    
        result = IOMobileFramebufferGetLayerDefaultSurface(connect, 0, &screenSurface);
    
        uint32_t aseed;
        IOSurfaceLock(screenSurface, kIOSurfaceLockReadOnly, &aseed);
        uint32_t width = IOSurfaceGetWidth(screenSurface);
        uint32_t height = IOSurfaceGetHeight(screenSurface);
        //int m_width = 320;
        //int m_height = 480;
        CFMutableDictionaryRef dict;
        int pitch = width*4, size = width*height*4;
        int bPE=4;
        char pixelFormat[4] = {'A','R','G','B'};
        dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
        CFDictionarySetValue(dict, kIOSurfaceIsGlobal, kCFBooleanTrue);
        CFDictionarySetValue(dict, kIOSurfaceBytesPerRow, CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &pitch));
        CFDictionarySetValue(dict, kIOSurfaceBytesPerElement, CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &bPE));
        CFDictionarySetValue(dict, kIOSurfaceWidth, CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &width));
        CFDictionarySetValue(dict, kIOSurfaceHeight, CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &height));
        CFDictionarySetValue(dict, kIOSurfacePixelFormat, CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, pixelFormat));
        CFDictionarySetValue(dict, kIOSurfaceAllocSize, CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &size));
    
        IOSurfaceRef destSurf = IOSurfaceCreate(dict);
    
        void* outAcc;
        IOSurfaceAcceleratorCreate(NULL, 0, &outAcc);
    
        IOSurfaceAcceleratorTransferSurface(outAcc, screenSurface, destSurf, dict, NULL);
    
        IOSurfaceUnlock(screenSurface, kIOSurfaceLockReadOnly, &aseed);
        CFRelease(outAcc);
    
        CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, IOSurfaceGetBaseAddress(destSurf), (width * height * 4), NULL);
        CGImageRef cgImage=CGImageCreate(width, height, 8,
                                         8*4, IOSurfaceGetBytesPerRow(destSurf),
                                         CGColorSpaceCreateDeviceRGB(), kCGImageAlphaNoneSkipFirst |kCGBitmapByteOrder32Little,
                                         provider, NULL,
                                         YES, kCGRenderingIntentDefault);
        UIImage *img = [UIImage imageWithCGImage:cgImage];
        UIImageWriteToSavedPhotosAlbum(img, self, nil, nil);
    
        // MOST RELEVANT PART OF CODE
    
        //CVPixelBufferCreateWithBytes(NULL, width, height, kCVPixelFormatType_32BGRA, IOSurfaceGetBaseAddress(destSurf), IOSurfaceGetBytesPerRow(destSurf), NULL, NULL, NULL, &sampleBuffer);
    }
    
    0 讨论(0)
提交回复
热议问题