@@ -21,11 +21,13 @@ static void SetupConversionInfo(avifImage * avif,
21
21
22
22
// Setup Matrix
23
23
matrix->Yp = 1 .0f ;
24
- matrix->Cr_R = 2 .0f * (1 .0f - state->kr );
25
- matrix->Cb_B = 2 .0f * (1 .0f - state->kb );
26
- matrix->Cb_G = -2 .0f * (1 .0f - state->kr ) * state->kr / state->kg ;
27
- matrix->Cr_G = -2 .0f * (1 .0f - state->kb ) * state->kb / state->kg ;
28
-
24
+
25
+ matrix->Cb_B = 2 .0f * (1 .0f - state->kb );
26
+ matrix->Cb_G = -2 .0f * (1 .0f - state->kb ) * state->kb / state->kg ;
27
+
28
+ matrix->Cr_R = 2 .0f * (1 .0f - state->kr );
29
+ matrix->Cr_G = -2 .0f * (1 .0f - state->kr ) * state->kr / state->kg ;
30
+
29
31
// Setup Pixel Range
30
32
switch (avif->depth ) {
31
33
case 8 :
@@ -141,8 +143,8 @@ static void ConvertAvifImagePlanar8ToRGB8(avifImage * avif, uint8_t * outPixels)
141
143
vImage_Buffer origCb = {
142
144
.data = avif->yuvPlanes [AVIF_CHAN_U],
143
145
.rowBytes = avif->yuvRowBytes [AVIF_CHAN_U],
144
- .width = avif->width >> state.formatInfo .chromaShiftX ,
145
- .height = avif->height >> state.formatInfo .chromaShiftY ,
146
+ .width = ( avif->width +state. formatInfo . chromaShiftX ) >> state.formatInfo .chromaShiftX ,
147
+ .height = ( avif->height +state. formatInfo . chromaShiftY ) >> state.formatInfo .chromaShiftY ,
146
148
};
147
149
148
150
if (!origCb.data ) { // allocate dummy data to convert monochrome images.
@@ -159,8 +161,8 @@ static void ConvertAvifImagePlanar8ToRGB8(avifImage * avif, uint8_t * outPixels)
159
161
vImage_Buffer origCr = {
160
162
.data = avif->yuvPlanes [AVIF_CHAN_V],
161
163
.rowBytes = avif->yuvRowBytes [AVIF_CHAN_V],
162
- .width = avif->width >> state.formatInfo .chromaShiftX ,
163
- .height = avif->height >> state.formatInfo .chromaShiftY ,
164
+ .width = ( avif->width +state. formatInfo . chromaShiftX ) >> state.formatInfo .chromaShiftX ,
165
+ .height = ( avif->height +state. formatInfo . chromaShiftY ) >> state.formatInfo .chromaShiftY ,
164
166
};
165
167
if (!origCr.data ) { // allocate dummy data to convert monochrome images.
166
168
dummyCr = calloc (origCr.width , sizeof (uint8_t ));
@@ -282,23 +284,38 @@ static void ConvertAvifImagePlanar8ToRGB8(avifImage * avif, uint8_t * outPixels)
282
284
return ;
283
285
}
284
286
287
+ ((uint8_t *)origY.data )[origY.rowBytes * (origY.height-1 ) + origY.width ] = 255 ;
288
+ const vImagePixelCount alignedWidth = (origY.width +1 ) & (~1 );
285
289
vImage_Buffer tmpY1 = {
286
- .data = calloc (origY. width /2 * origY.height , sizeof (uint8_t )),
287
- .width = origY. width /2 ,
290
+ .data = calloc (alignedWidth /2 * origY.height , sizeof (uint8_t )),
291
+ .width = alignedWidth /2 ,
288
292
.height = origY.height ,
289
- .rowBytes = origY. width /2 * sizeof (uint8_t ),
293
+ .rowBytes = alignedWidth /2 * sizeof (uint8_t ),
290
294
};
291
295
if (!tmpY1.data ) {
292
296
free (argbPixels);
293
297
free (dummyCb);
294
298
free (dummyCr);
295
299
return ;
296
300
}
301
+ err = vImageConvert_ChunkyToPlanar8 ((const void *[]){origY.data },
302
+ (const vImage_Buffer*[]){&tmpY1},
303
+ 1 /* channelCount */ , 2 /* src srcStrideBytes */ ,
304
+ alignedWidth/2 , origY.height ,
305
+ origY.rowBytes , kvImageNoFlags);
306
+ if (err != kvImageNoError) {
307
+ NSLog (@" Failed to separate first Y channel: %ld " , err);
308
+ free (argbPixels);
309
+ free (dummyCb);
310
+ free (dummyCr);
311
+ free (tmpY1.data );
312
+ return ;
313
+ }
297
314
vImage_Buffer tmpY2 = {
298
- .data = calloc (origY. width /2 * origY.height , sizeof (uint8_t )),
299
- .width = origY. width /2 ,
315
+ .data = calloc (alignedWidth /2 * origY.height , sizeof (uint8_t )),
316
+ .width = alignedWidth /2 ,
300
317
.height = origY.height ,
301
- .rowBytes = origY. width /2 * sizeof (uint8_t ),
318
+ .rowBytes = alignedWidth /2 * sizeof (uint8_t ),
302
319
};
303
320
if (!tmpY2.data ) {
304
321
free (argbPixels);
@@ -307,13 +324,15 @@ static void ConvertAvifImagePlanar8ToRGB8(avifImage * avif, uint8_t * outPixels)
307
324
free (tmpY1.data );
308
325
return ;
309
326
}
310
- err= vImageConvert_ChunkyToPlanar8 ((const void *[]){origY.data , origY.data +1 },
311
- (const vImage_Buffer*[]){&tmpY1, &tmpY2},
312
- 2 /* channelCount */ ,2 /* src srcStrideBytes */ ,
327
+ tmpY2.width = origY.width /2 ;
328
+ err = vImageConvert_ChunkyToPlanar8 ((const void *[]){origY.data + 1 },
329
+ (const vImage_Buffer*[]){&tmpY2},
330
+ 1 /* channelCount */ , 2 /* src srcStrideBytes */ ,
313
331
origY.width /2 , origY.height ,
314
332
origY.rowBytes , kvImageNoFlags);
333
+ tmpY2.width = alignedWidth/2 ;
315
334
if (err != kvImageNoError) {
316
- NSLog (@" Failed to separate Y channel: %ld " , err);
335
+ NSLog (@" Failed to separate second Y channel: %ld " , err);
317
336
free (argbPixels);
318
337
free (dummyCb);
319
338
free (dummyCr);
@@ -322,10 +341,10 @@ static void ConvertAvifImagePlanar8ToRGB8(avifImage * avif, uint8_t * outPixels)
322
341
return ;
323
342
}
324
343
vImage_Buffer tmpBuffer = {
325
- .data = calloc (avif-> width * avif->height * 2 , sizeof (uint8_t )),
326
- .width = avif-> width /2 ,
344
+ .data = calloc (alignedWidth * avif->height * 2 , sizeof (uint8_t )),
345
+ .width = alignedWidth /2 ,
327
346
.height = avif->height ,
328
- .rowBytes = avif-> width / 2 * 4 * sizeof (uint8_t ),
347
+ .rowBytes = alignedWidth / 2 * 4 * sizeof (uint8_t ),
329
348
};
330
349
if (!tmpBuffer.data ) {
331
350
free (argbPixels);
@@ -437,8 +456,8 @@ static void ConvertAvifImagePlanar16ToRGB16U(avifImage * avif, uint8_t * outPixe
437
456
vImage_Buffer origCb = {
438
457
.data = avif->yuvPlanes [AVIF_CHAN_U],
439
458
.rowBytes = avif->yuvRowBytes [AVIF_CHAN_U],
440
- .width = avif->width >> state.formatInfo .chromaShiftX ,
441
- .height = avif->height >> state.formatInfo .chromaShiftY ,
459
+ .width = ( avif->width +state. formatInfo . chromaShiftX ) >> state.formatInfo .chromaShiftX ,
460
+ .height = ( avif->height +state. formatInfo . chromaShiftY ) >> state.formatInfo .chromaShiftY ,
442
461
};
443
462
444
463
if (!origCb.data ) { // allocate dummy data to convert monochrome images.
@@ -465,8 +484,8 @@ static void ConvertAvifImagePlanar16ToRGB16U(avifImage * avif, uint8_t * outPixe
465
484
vImage_Buffer origCr = {
466
485
.data = avif->yuvPlanes [AVIF_CHAN_V],
467
486
.rowBytes = avif->yuvRowBytes [AVIF_CHAN_V],
468
- .width = avif->width >> state.formatInfo .chromaShiftX ,
469
- .height = avif->height >> state.formatInfo .chromaShiftY ,
487
+ .width = ( avif->width +state. formatInfo . chromaShiftX ) >> state.formatInfo .chromaShiftX ,
488
+ .height = ( avif->height +state. formatInfo . chromaShiftY ) >> state.formatInfo .chromaShiftY ,
470
489
};
471
490
472
491
if (!origCr.data ) { // allocate dummy data to convert monochrome images.
@@ -823,6 +842,10 @@ - (nullable CGImageRef)sd_createAVIFImageWithData:(nonnull NSData *)data CF_RETU
823
842
CGDataProviderRef provider = CGDataProviderCreateWithData (NULL , dest, rowBytes * height, FreeImageData);
824
843
CGBitmapInfo bitmapInfo = usesU16 ? kCGBitmapByteOrder16Host : kCGBitmapByteOrderDefault ;
825
844
bitmapInfo |= hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNone ;
845
+ // FIXME: (ledyba-z): Set appropriate color space.
846
+ // Currently, there is no way to get MatrixCoefficients, TransferCharacteristics and ColourPrimaries values
847
+ // in Sequence Header OBU.
848
+ // https://github.com/AOMediaCodec/libavif/blob/7d36984b2994210b/include/avif/avif.h#L149-L236
826
849
CGColorSpaceRef colorSpaceRef = [SDImageCoderHelper colorSpaceGetDeviceRGB ];
827
850
CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault ;
828
851
CGImageRef imageRef = CGImageCreate (width, height, bitsPerComponent, bitsPerPixel, rowBytes, colorSpaceRef, bitmapInfo, provider, NULL , NO , renderingIntent);
0 commit comments