Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge pull request #1267 from karlvr/gpuimagepicture-redraw

GPUImagePicture: don't redraw using CoreGraphics unless you have to
  • Loading branch information...
commit b662c2e479a6713e26a632ca908a477ed87acb62 2 parents 024b442 + 62c8311
@BradLarson authored
Showing with 33 additions and 3 deletions.
  1. +33 −3 framework/Source/iOS/GPUImagePicture.m
View
36 framework/Source/iOS/GPUImagePicture.m
@@ -74,7 +74,7 @@ - (id)initWithCGImage:(CGImageRef)newImageSource smoothlyScaleOutput:(BOOL)smoot
pixelSizeOfImage = CGSizeMake(widthOfImage, heightOfImage);
CGSize pixelSizeToUseForTexture = pixelSizeOfImage;
- BOOL shouldRedrawUsingCoreGraphics = YES;
+ BOOL shouldRedrawUsingCoreGraphics = NO;
// For now, deal with images larger than the maximum texture size by resizing to be within that limit
CGSize scaledImageSizeToFitOnGPU = [GPUImageContext sizeThatFitsWithinATextureForSize:pixelSizeOfImage];
@@ -98,12 +98,42 @@ - (id)initWithCGImage:(CGImageRef)newImageSource smoothlyScaleOutput:(BOOL)smoot
GLubyte *imageData = NULL;
CFDataRef dataFromImageDataProvider;
+ GLenum format = GL_BGRA;
+
+ if (!shouldRedrawUsingCoreGraphics) {
+ /* Check that the bitmap pixel format is compatible with GL */
+ CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(newImageSource);
+ if ((bitmapInfo & kCGBitmapFloatComponents) != 0) {
+ /* We don't support float components for use directly in GL */
+ shouldRedrawUsingCoreGraphics = YES;
+ } else {
+ CGBitmapInfo byteOrderInfo = bitmapInfo & kCGBitmapByteOrderMask;
+ if (byteOrderInfo == kCGBitmapByteOrder32Little) {
+ /* Little endian, for alpha-first we can use this bitmap directly in GL */
+ CGImageAlphaInfo alphaInfo = bitmapInfo & kCGBitmapAlphaInfoMask;
+ if (alphaInfo != kCGImageAlphaPremultipliedFirst && alphaInfo != kCGImageAlphaFirst &&
+ alphaInfo != kCGImageAlphaNoneSkipFirst) {
+ shouldRedrawUsingCoreGraphics = YES;
+ }
+ } else if (byteOrderInfo == kCGBitmapByteOrderDefault || byteOrderInfo == kCGBitmapByteOrder32Big) {
+ /* Big endian, for alpha-last we can use this bitmap directly in GL */
+ CGImageAlphaInfo alphaInfo = bitmapInfo & kCGBitmapAlphaInfoMask;
+ if (alphaInfo != kCGImageAlphaPremultipliedLast && alphaInfo != kCGImageAlphaLast &&
+ alphaInfo != kCGImageAlphaNoneSkipLast) {
+ shouldRedrawUsingCoreGraphics = YES;
+ } else {
+ /* Can access directly using GL_RGBA pixel format */
+ format = GL_RGBA;
+ }
+ }
+ }
+ }
// CFAbsoluteTime elapsedTime, startTime = CFAbsoluteTimeGetCurrent();
if (shouldRedrawUsingCoreGraphics)
{
- // For resized image, redraw
+ // For resized or incompatible image: redraw
imageData = (GLubyte *) calloc(1, (int)pixelSizeToUseForTexture.width * (int)pixelSizeToUseForTexture.height * 4);
CGColorSpaceRef genericRGBColorspace = CGColorSpaceCreateDeviceRGB();
@@ -148,7 +178,7 @@ - (id)initWithCGImage:(CGImageRef)newImageSource smoothlyScaleOutput:(BOOL)smoot
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
}
// no need to use self.outputTextureOptions here since pictures need this texture formats and type
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (int)pixelSizeToUseForTexture.width, (int)pixelSizeToUseForTexture.height, 0, GL_BGRA, GL_UNSIGNED_BYTE, imageData);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (int)pixelSizeToUseForTexture.width, (int)pixelSizeToUseForTexture.height, 0, format, GL_UNSIGNED_BYTE, imageData);
if (self.shouldSmoothlyScaleOutput)
{

6 comments on commit b662c2e

@keremerkan

This commit breaks compatibility with "kCVPixelFormatType_32BGRA" type images from an AVCaptureSession when "shouldRedrawUsingCoreGraphics" is set to YES. If it is set to NO, there is no problem, but when it is set to YES, the resulting image from a "GPUImageContrastFilter" returns a corrupted image, most probably as a result of wrong pixel matching. I think it will return corrupt images with other filters also, but I could not test it yet. 2 example images (untouched and filtered) are attached.

img_2427
img_2428

@karlvr

Sorry, that is my fault. I'm a little confused with your comment though, the change in this commit was to sometimes set shouldRedrawUsingCoreGraphics to NO. Previously it was always set to YES. Is it in fact the case that the corruption occurs when shouldRedrawUsingCoreGraphics is NO?

@karlvr

I'm guessing this is the case, and I'm wondering if it is related to the rotation of the image. Could you try with some different image orientations?

@keremerkan

You are right, sorry, I confused the boolean value. When it is set to NO, the corruption occurs. When it is set to YES, there is no problem. I tried all four orientations on my app on iPad and unfortunately with all orientations the issue is apparent. I think the RGBA channels are selected wrongly.

When the image info is parsed with the newly added code block between lines 101 and 130, it matches the else block on line 124. It selects format GL_RGBA there but the image is BGRA. I tried changing all GL_RGBA values to GL_BGRA to see if it works but it did not help.

@karlvr

No problem, are you able to try out this branch which I've just pushed?

https://github.com/karlvr/GPUImage/tree/gpuimagepicture-redraw2

I neglected to check the memory layout of the bitmap, and it is getting confused when the row length is not width * 4. I've put in a few other memory layout checks that I believe should resolve this. I'm going to do some more testing and then send Brad another pull request, so it would be great to know if this resolves the issue for you.

My apologies for busting this!
cheers,
Karl

@keremerkan

Just tested the new commit with all image orientations and I can confirm that it resolves the problem.

Thanks for the hard work, it is much appreciated.

Please sign in to comment.
Something went wrong with that request. Please try again.