-
-
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 setsp
to'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
p
to'BGRA'
(orkCVPixelFormatType_32BGRA
), not ARGB. So… which pixel format actually ends up being used?