Skip to content

Commit e852994

Browse files
committed
Fix leak of parallel runner && use libjxl default thread count
1 parent 1abc2ca commit e852994

File tree

2 files changed

+29
-37
lines changed

2 files changed

+29
-37
lines changed

Example/SDWebImageJPEGXLCoder/SDViewController.m

+12-10
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@
1111
#import <SDWebImage/SDWebImage.h>
1212
#import <libjxl/jxl/encode.h>
1313

14+
static void WriteTempJXLFile(NSData *data, NSString *filename) {
15+
NSString *tempOutputPath = [NSTemporaryDirectory() stringByAppendingPathComponent:filename];
16+
[data writeToFile:tempOutputPath atomically:YES];
17+
NSLog(@"Written encoded JXL to : %@", tempOutputPath);
18+
}
19+
1420
@interface SDViewController ()
1521
@property (nonatomic, strong) UIImageView *imageView1;
1622
@property (nonatomic, strong) UIImageView *imageView2;
@@ -48,10 +54,7 @@ - (void)viewDidLoad {
4854
NSData *jxlData = [SDImageJPEGXLCoder.sharedCoder encodedDataWithImage:image format:SDImageFormatJPEGXL options:@{SDImageCoderEncodeMaxFileSize : @(maxFileSize)}];
4955
if (jxlData) {
5056
NSLog(@"Static JPEG-XL encode success, bytes: %lu", (unsigned long)jxlData.length);
51-
dispatch_async(dispatch_get_main_queue(), ^{
52-
UIImage *animatedImage = [UIImage sd_imageWithData:jxlData];
53-
self.imageView2.image = animatedImage;
54-
});
57+
WriteTempJXLFile(jxlData, imageURL.lastPathComponent);
5558
}
5659
});
5760
}];
@@ -66,6 +69,7 @@ - (void)viewDidLoad {
6669
}];
6770
if (jxlData) {
6871
NSLog(@"Animated JPEG-XL encode success, bytes: %lu", (unsigned long)jxlData.length);
72+
WriteTempJXLFile(jxlData, imageURL.lastPathComponent);
6973
}
7074
});
7175
}];
@@ -92,19 +96,17 @@ - (void)testHDREncoding {
9296
- (void)encodeJXLWithImage:(UIImage *)image {
9397
NSCParameterAssert(image);
9498
NSDictionary *frameSetting = @{
95-
@(JXL_ENC_FRAME_SETTING_EFFORT) : @(10),
96-
@(JXL_ENC_FRAME_SETTING_BROTLI_EFFORT) : @(11)
99+
@(JXL_ENC_FRAME_SETTING_EFFORT) : @(7),
100+
// @(JXL_ENC_FRAME_SETTING_BROTLI_EFFORT) : @(11)
97101
};
98102
// fastest encoding speed but largest compressed size, you can adjust options here
99103
NSData *data = [SDImageJPEGXLCoder.sharedCoder encodedDataWithImage:image format:SDImageFormatJPEGXL options:@{
100104
// SDImageCoderEncodeCompressionQuality : @0.68,
101-
SDImageCoderEncodeJXLDistance : @(3.0),
105+
SDImageCoderEncodeJXLDistance : @(1.0),
102106
SDImageCoderEncodeJXLFrameSetting : frameSetting,
103107
}];
104108
NSCParameterAssert(data);
105-
NSString *tempOutputPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"iso-hdr-demo.jxl"];
106-
[data writeToFile:tempOutputPath atomically:YES];
107-
NSLog(@"Written encoded JXL to : %@", tempOutputPath);
109+
WriteTempJXLFile(data, @"iso-hdr-demo.jxl");
108110

109111
CIImage *ciimage = [CIImage imageWithData:data];
110112
NSString *desc = [ciimage description];

SDWebImageJPEGXLCoder/Classes/SDImageJPEGXLCoder.m

+17-27
Original file line numberDiff line numberDiff line change
@@ -29,23 +29,6 @@
2929
}
3030
#endif
3131

32-
// Should moved to SDWebImage Core
33-
#include <sys/sysctl.h>
34-
static int computeHostNumLogicalCores(void) {
35-
uint32_t count;
36-
size_t len = sizeof(count);
37-
sysctlbyname("hw.logicalcpu", &count, &len, NULL, 0);
38-
if (count < 1) {
39-
int nm[2];
40-
nm[0] = CTL_HW;
41-
nm[1] = HW_AVAILCPU;
42-
sysctl(nm, 2, &count, &len, NULL, 0);
43-
if (count < 1)
44-
return -1;
45-
}
46-
return count;
47-
}
48-
4932
static void FreeImageData(void *info, const void *data, size_t size) {
5033
free((void *)data);
5134
}
@@ -386,6 +369,11 @@ - (NSData *)encodedDataWithFrames:(NSArray<SDImageFrame *> *)frames loopCount:(N
386369
}
387370
distance = JxlEncoderDistanceFromQuality(compressionQuality * 100.0);
388371
}
372+
// calculate multithread count
373+
size_t threadCount = [options[SDImageCoderEncodeJXLThreadCount] unsignedIntValue];
374+
if (threadCount == 0) {
375+
threadCount = JxlThreadParallelRunnerDefaultNumWorkerThreads();
376+
}
389377

390378
NSMutableData *output = [NSMutableData data];
391379
BOOL success = NO;
@@ -402,9 +390,14 @@ - (NSData *)encodedDataWithFrames:(NSArray<SDImageFrame *> *)frames loopCount:(N
402390
}
403391
JxlEncoderFrameSettings* frame_settings = JxlEncoderFrameSettingsCreate(enc, NULL);
404392
// setup basic info for whole encoding
405-
JxlEncoderStatus jret = SetupEncoderForPrimaryImage(enc, frame_settings, imageRef, orientation, distance, hasAnimation, loopCount, options);
393+
void* runner = NULL;
394+
if (threadCount > 1) {
395+
runner = JxlThreadParallelRunnerCreate(NULL, threadCount);
396+
}
397+
JxlEncoderStatus jret = SetupEncoderForPrimaryImage(enc, frame_settings, runner, imageRef, orientation, distance, hasAnimation, loopCount, options);
406398
if (jret != JXL_ENC_SUCCESS) {
407399
JxlEncoderDestroy(enc);
400+
JxlThreadParallelRunnerDestroy(runner);
408401
return nil;
409402
}
410403

@@ -413,6 +406,7 @@ - (NSData *)encodedDataWithFrames:(NSArray<SDImageFrame *> *)frames loopCount:(N
413406
success = [self sd_encodeFrameWithEnc:enc frameSettings:frame_settings frame:imageRef orientation:orientation duration:0 options:options output:output];
414407
if (!success) {
415408
JxlEncoderDestroy(enc);
409+
JxlThreadParallelRunnerDestroy(runner);
416410
return nil;
417411
}
418412
// finish input and ready for output
@@ -430,6 +424,7 @@ - (NSData *)encodedDataWithFrames:(NSArray<SDImageFrame *> *)frames loopCount:(N
430424
// earily break
431425
if (!success) {
432426
JxlEncoderDestroy(enc);
427+
JxlThreadParallelRunnerDestroy(runner);
433428
return nil;
434429
}
435430
// last frame
@@ -448,6 +443,7 @@ - (NSData *)encodedDataWithFrames:(NSArray<SDImageFrame *> *)frames loopCount:(N
448443
// destroying the decoder also frees JxlEncoderFrameSettings
449444
// free(frame_settings);
450445
JxlEncoderDestroy(enc);
446+
JxlThreadParallelRunnerDestroy(runner);
451447

452448
if (jret != JXL_ENC_SUCCESS) {
453449
return nil;
@@ -456,7 +452,7 @@ - (NSData *)encodedDataWithFrames:(NSArray<SDImageFrame *> *)frames loopCount:(N
456452
}
457453

458454
// see: https://github.com/libjxl/libjxl/blob/main/lib/jxl/roundtrip_test.cc#L165
459-
JxlEncoderStatus EncodeWithEncoder(JxlEncoder* enc, NSMutableData *compressed) {
455+
static JxlEncoderStatus EncodeWithEncoder(JxlEncoder* enc, NSMutableData *compressed) {
460456
// increase output buffer by 64 bytes once a time
461457
[compressed increaseLengthBy:64];
462458
uint8_t* next_out = compressed.mutableBytes;
@@ -482,7 +478,7 @@ JxlEncoderStatus EncodeWithEncoder(JxlEncoder* enc, NSMutableData *compressed) {
482478
return JXL_ENC_SUCCESS;
483479
}
484480

485-
JxlEncoderStatus SetupEncoderForPrimaryImage(JxlEncoder *enc, JxlEncoderFrameSettings *frame_settings, CGImageRef imageRef, CGImagePropertyOrientation orientation, float distance, BOOL hasAnimation, NSUInteger loopCount, NSDictionary *options) {
481+
static JxlEncoderStatus SetupEncoderForPrimaryImage(JxlEncoder *enc, JxlEncoderFrameSettings *frame_settings, void* runner, CGImageRef imageRef, CGImagePropertyOrientation orientation, float distance, BOOL hasAnimation, NSUInteger loopCount, NSDictionary *options) {
486482
// bitmap info from CGImage
487483
size_t width = CGImageGetWidth(imageRef);
488484
size_t height = CGImageGetHeight(imageRef);
@@ -625,13 +621,7 @@ JxlEncoderStatus SetupEncoderForPrimaryImage(JxlEncoder *enc, JxlEncoderFrameSet
625621
return jret;
626622
}
627623

628-
/* This needs to be set each time the encoder is reset */
629-
size_t threadCount = [options[SDImageCoderEncodeJXLThreadCount] unsignedIntValue];
630-
if (threadCount == 0) {
631-
threadCount = computeHostNumLogicalCores();
632-
}
633-
if (threadCount > 1) {
634-
void* runner = JxlThreadParallelRunnerCreate(NULL, threadCount);
624+
if (runner) {
635625
jret = JxlEncoderSetParallelRunner(enc, JxlThreadParallelRunner, runner);
636626
}
637627

0 commit comments

Comments
 (0)