@@ -21,11 +21,13 @@ static void SetupConversionInfo(avifImage * avif,
2121
2222 // Setup Matrix
2323 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+
2931 // Setup Pixel Range
3032 switch (avif->depth ) {
3133 case 8 :
@@ -141,8 +143,8 @@ static void ConvertAvifImagePlanar8ToRGB8(avifImage * avif, uint8_t * outPixels)
141143 vImage_Buffer origCb = {
142144 .data = avif->yuvPlanes [AVIF_CHAN_U],
143145 .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 ,
146148 };
147149
148150 if (!origCb.data ) { // allocate dummy data to convert monochrome images.
@@ -159,8 +161,8 @@ static void ConvertAvifImagePlanar8ToRGB8(avifImage * avif, uint8_t * outPixels)
159161 vImage_Buffer origCr = {
160162 .data = avif->yuvPlanes [AVIF_CHAN_V],
161163 .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 ,
164166 };
165167 if (!origCr.data ) { // allocate dummy data to convert monochrome images.
166168 dummyCr = calloc (origCr.width , sizeof (uint8_t ));
@@ -282,23 +284,38 @@ static void ConvertAvifImagePlanar8ToRGB8(avifImage * avif, uint8_t * outPixels)
282284 return ;
283285 }
284286
287+ ((uint8_t *)origY.data )[origY.rowBytes * (origY.height-1 ) + origY.width ] = 255 ;
288+ const vImagePixelCount alignedWidth = (origY.width +1 ) & (~1 );
285289 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 ,
288292 .height = origY.height ,
289- .rowBytes = origY. width /2 * sizeof (uint8_t ),
293+ .rowBytes = alignedWidth /2 * sizeof (uint8_t ),
290294 };
291295 if (!tmpY1.data ) {
292296 free (argbPixels);
293297 free (dummyCb);
294298 free (dummyCr);
295299 return ;
296300 }
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+ }
297314 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 ,
300317 .height = origY.height ,
301- .rowBytes = origY. width /2 * sizeof (uint8_t ),
318+ .rowBytes = alignedWidth /2 * sizeof (uint8_t ),
302319 };
303320 if (!tmpY2.data ) {
304321 free (argbPixels);
@@ -307,13 +324,15 @@ static void ConvertAvifImagePlanar8ToRGB8(avifImage * avif, uint8_t * outPixels)
307324 free (tmpY1.data );
308325 return ;
309326 }
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 */ ,
313331 origY.width /2 , origY.height ,
314332 origY.rowBytes , kvImageNoFlags);
333+ tmpY2.width = alignedWidth/2 ;
315334 if (err != kvImageNoError) {
316- NSLog (@" Failed to separate Y channel: %ld " , err);
335+ NSLog (@" Failed to separate second Y channel: %ld " , err);
317336 free (argbPixels);
318337 free (dummyCb);
319338 free (dummyCr);
@@ -322,10 +341,10 @@ static void ConvertAvifImagePlanar8ToRGB8(avifImage * avif, uint8_t * outPixels)
322341 return ;
323342 }
324343 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 ,
327346 .height = avif->height ,
328- .rowBytes = avif-> width / 2 * 4 * sizeof (uint8_t ),
347+ .rowBytes = alignedWidth / 2 * 4 * sizeof (uint8_t ),
329348 };
330349 if (!tmpBuffer.data ) {
331350 free (argbPixels);
@@ -437,8 +456,8 @@ static void ConvertAvifImagePlanar16ToRGB16U(avifImage * avif, uint8_t * outPixe
437456 vImage_Buffer origCb = {
438457 .data = avif->yuvPlanes [AVIF_CHAN_U],
439458 .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 ,
442461 };
443462
444463 if (!origCb.data ) { // allocate dummy data to convert monochrome images.
@@ -465,8 +484,8 @@ static void ConvertAvifImagePlanar16ToRGB16U(avifImage * avif, uint8_t * outPixe
465484 vImage_Buffer origCr = {
466485 .data = avif->yuvPlanes [AVIF_CHAN_V],
467486 .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 ,
470489 };
471490
472491 if (!origCr.data ) { // allocate dummy data to convert monochrome images.
@@ -823,6 +842,10 @@ - (nullable CGImageRef)sd_createAVIFImageWithData:(nonnull NSData *)data CF_RETU
823842 CGDataProviderRef provider = CGDataProviderCreateWithData (NULL , dest, rowBytes * height, FreeImageData);
824843 CGBitmapInfo bitmapInfo = usesU16 ? kCGBitmapByteOrder16Host : kCGBitmapByteOrderDefault ;
825844 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
826849 CGColorSpaceRef colorSpaceRef = [SDImageCoderHelper colorSpaceGetDeviceRGB ];
827850 CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault ;
828851 CGImageRef imageRef = CGImageCreate (width, height, bitsPerComponent, bitsPerPixel, rowBytes, colorSpaceRef, bitmapInfo, provider, NULL , NO , renderingIntent);
0 commit comments