-
-
Save alyssarosenzweig/7d8099cdb227d2de0a9e83b7de34c7f8 to your computer and use it in GitHub Desktop.
| /* | |
| * Copyright (C) 2021 Alyssa Rosenzweig <alyssa@rosenzweig.io> | |
| * | |
| * Permission is hereby granted, free of charge, to any person obtaining a | |
| * copy of this software and associated documentation files (the "Software"), | |
| * to deal in the Software without restriction, including without limitation | |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| * and/or sell copies of the Software, and to permit persons to whom the | |
| * Software is furnished to do so, subject to the following conditions: | |
| * | |
| * The above copyright notice and this permission notice (including the next | |
| * paragraph) shall be included in all copies or substantial portions of the | |
| * Software. | |
| * | |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
| * SOFTWARE. | |
| */ | |
| #include <stdio.h> | |
| #include <assert.h> | |
| #include <mach/mach.h> | |
| #include <IOKit/IOKitLib.h> | |
| #include <IOSurface/IOSurface.h> | |
| #import <Cocoa/Cocoa.h> | |
| @class NSNumber; | |
| struct JPEGDriverArgs { | |
| IOSurfaceID src_surface /*in*/; | |
| unsigned int input_jpeg_file_size /*in*/; // GOOD | |
| IOSurfaceID dest_surface /*in*/; | |
| unsigned int output_buffer_size /*in*/; // GOOD | |
| int unk10; | |
| int pixel_x; | |
| int pixel_y; | |
| int unk1C; | |
| int unk20; | |
| int x_offset; | |
| int y_offset; | |
| int subsampling_mode; | |
| int unk30; | |
| int unk34; | |
| int unk38; | |
| int unk3C; | |
| int unk40; | |
| int unk44; | |
| int unk48; | |
| unsigned int decode_width; | |
| unsigned int decode_height; | |
| int unk5C; | |
| } __attribute__((packed)); | |
| int main(int argc, char **argv) | |
| { | |
| (void) argc; | |
| (void) argv; | |
| kern_return_t ret; | |
| CFDictionaryRef matching = IOServiceMatching("AppleJPEGDriver"); | |
| io_service_t service = | |
| IOServiceGetMatchingService(kIOMasterPortDefault, matching); | |
| if (!service) { | |
| fprintf(stderr, "JPEG driver accelerator not found\n"); | |
| return 1; | |
| } | |
| io_connect_t connection = 0; | |
| ret = IOServiceOpen(service, mach_task_self(), 0, &connection); | |
| if (ret) { | |
| fprintf(stderr, "Error from IOServiceOpen: %u\n", ret); | |
| return 1; | |
| } | |
| IOSurfaceRef surfs[2]; | |
| char pixelFormat[4] = {'A', 'R', 'G', 'B'}; | |
| unsigned int p = 111; | |
| memcpy(&p, &pixelFormat[0], 4); | |
| printf("%X\n", p); | |
| /* input jpeg */ | |
| surfs[0] = IOSurfaceCreate((CFDictionaryRef)@{(id)kIOSurfaceWidth: @120, | |
| (id)kIOSurfaceHeight: @80, | |
| (id)kIOSurfacePixelFormat: @(p), | |
| (id)kIOSurfaceBytesPerElement: @4}); | |
| /* output image */ | |
| surfs[1] = IOSurfaceCreate((CFDictionaryRef)@{(id)kIOSurfaceWidth: @120, | |
| (id)kIOSurfaceHeight: @80, | |
| (id)kIOSurfaceBytesPerRow: @(120*4), | |
| (id)kIOSurfacePixelFormat: @(p), | |
| (id)kIOSurfaceBytesPerElement: @4}); | |
| void *base = IOSurfaceGetBaseAddress(surfs[0]); | |
| FILE *fp = fopen("dump.jpg", "rb"); | |
| fread(base, 1, 3178, fp); | |
| fclose(fp); | |
| printf("Connection %d\n", connection); | |
| size_t sz = sizeof(struct JPEGDriverArgs); | |
| struct JPEGDriverArgs args = { | |
| .src_surface = IOSurfaceGetID(surfs[0]), | |
| .input_jpeg_file_size = 3178, | |
| .dest_surface = IOSurfaceGetID(surfs[1]), | |
| .decode_width = 120, | |
| .decode_height = 80, | |
| .pixel_x = 120, | |
| .pixel_y = 80, | |
| .output_buffer_size = 1024*1024*16, | |
| .x_offset = 0, | |
| .y_offset = 0, | |
| }; | |
| ret = IOConnectCallStructMethod(connection, 1, &args, | |
| sizeof(args), &args, &sz); | |
| sleep(2); | |
| ret = IOServiceClose(connection); | |
| { | |
| base = IOSurfaceGetBaseAddress(surfs[1]); | |
| FILE *fp = fopen("dump.bin", "wb"); | |
| fwrite(base, 1, 120*80*4, fp); | |
| fclose(fp); | |
| } | |
| if (ret) { | |
| fprintf(stderr, "Error from IOServiceClose: %u\n", ret); | |
| return 1; | |
| } | |
| } |
You should be able to pass a four-character code
'abcd'to the pixel format parameter directly; Apple uses them all over the place. See for instance CoreVideo/CVPixelBuffer.h.
The only weird thing is that your code effectively setspto'BGRA'(orkCVPixelFormatType_32BGRA), not ARGB. So… which pixel format actually ends up being used?
BGRA, which is what I intended. Even though the endianness makes it looks like ARGB (which is a very odd format indeed..) I am just so used to reading fourcc's backwards at this point :p
BGRA, which is what I intended. Even though the endianness makes it looks like ARGB (which is a very odd format indeed..) I am just so used to reading fourcc's backwards at this point :p
The world would be a better place with big endian systems only 🙃.
I sometimes run software tests on powerpc BE via the free unicamp minicloud, just to probe for funky memory indexing and char/numeric type casting
You should be able to pass a four-character code
'abcd'to the pixel format parameter directly; Apple uses them all over the place. See for instance CoreVideo/CVPixelBuffer.h.The only weird thing is that your code effectively sets
pto'BGRA'(orkCVPixelFormatType_32BGRA), not ARGB. So… which pixel format actually ends up being used?