├── .gitignore ├── DotEnginePixelBuffer.h ├── DotEnginePixelBuffer.m └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | # CocoaPods 32 | # 33 | # We recommend against adding the Pods directory to your .gitignore. However 34 | # you should judge for yourself, the pros and cons are mentioned at: 35 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 36 | # 37 | # Pods/ 38 | 39 | # Carthage 40 | # 41 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 42 | # Carthage/Checkouts 43 | 44 | Carthage/Build 45 | 46 | # fastlane 47 | # 48 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 49 | # screenshots whenever they are needed. 50 | # For more information about the recommended setup visit: 51 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 52 | 53 | fastlane/report.xml 54 | fastlane/Preview.html 55 | fastlane/screenshots 56 | fastlane/test_output 57 | 58 | # Code Injection 59 | # 60 | # After new code Injection tools there's a generated folder /iOSInjectionProject 61 | # https://github.com/johnno1962/injectionforxcode 62 | 63 | iOSInjectionProject/ 64 | -------------------------------------------------------------------------------- /DotEnginePixelBuffer.h: -------------------------------------------------------------------------------- 1 | // 2 | // DotEnginePixelBufferConvert.h 3 | // dot-engine-ios 4 | // 5 | // Created by xiang on 15/01/2017. 6 | // Copyright © 2017 dotEngine. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface DotEnginePixelBuffer : NSObject 13 | 14 | +(CMSampleBufferRef)convertPixelBuffer:(CVPixelBufferRef)pixelBuffer; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /DotEnginePixelBuffer.m: -------------------------------------------------------------------------------- 1 | // 2 | // DotEnginePixelBufferConvert.m 3 | // dot-engine-ios 4 | // 5 | // Created by xiang on 15/01/2017. 6 | // Copyright © 2017 dotEngine. All rights reserved. 7 | // 8 | 9 | #import "DotEnginePixelBuffer.h" 10 | #import "libyuv.h" 11 | 12 | @implementation DotEnginePixelBuffer 13 | 14 | 15 | +(CVPixelBufferRef)convertPixelBuffer:(CVPixelBufferRef)pixelBuffer 16 | { 17 | 18 | OSType pixelFormatType = CVPixelBufferGetPixelFormatType(pixelBuffer); 19 | 20 | 21 | if (pixelFormatType == kCVPixelFormatType_32BGRA) { 22 | // argb it is a little confused 23 | 24 | CVPixelBufferLockBaseAddress(pixelBuffer, 0); 25 | 26 | int width = CVPixelBufferGetWidth(pixelBuffer); 27 | int height = CVPixelBufferGetHeight(pixelBuffer); 28 | 29 | int half_width = (width + 1) / 2; 30 | int half_height = (height + 1) / 2; 31 | 32 | const int y_size = width * height; 33 | const int uv_size = half_width * half_height * 2 ; 34 | const size_t total_size = y_size + uv_size; 35 | 36 | uint8_t* outputBytes = calloc(1,total_size); 37 | 38 | uint8_t* interMiediateBytes = calloc(1,total_size); 39 | 40 | uint8_t *srcAddress = CVPixelBufferGetBaseAddress(pixelBuffer); 41 | 42 | 43 | ARGBToI420(srcAddress, 44 | width * 4, 45 | interMiediateBytes, 46 | half_width * 2, 47 | interMiediateBytes + y_size, 48 | half_width, 49 | interMiediateBytes + y_size + y_size/4, 50 | half_width, 51 | width, height); 52 | 53 | I420ToNV12(interMiediateBytes, 54 | half_width * 2, 55 | interMiediateBytes + y_size, 56 | half_width, 57 | interMiediateBytes + y_size + y_size/4, 58 | half_width, 59 | outputBytes, 60 | half_width * 2, 61 | outputBytes + y_size, 62 | half_width * 2, 63 | width, height); 64 | 65 | free(interMiediateBytes); 66 | 67 | CVPixelBufferUnlockBaseAddress(pixelBuffer, 0); 68 | 69 | CVPixelBufferRef pixel_buffer = NULL; 70 | 71 | CVPixelBufferCreate(kCFAllocatorDefault, width , height, 72 | kCVPixelFormatType_420YpCbCr8BiPlanarFullRange, 73 | NULL, &pixel_buffer); 74 | 75 | CVPixelBufferLockBaseAddress(pixel_buffer, 0); 76 | 77 | uint8_t * plan1 = CVPixelBufferGetBaseAddressOfPlane(pixel_buffer,0); 78 | size_t plan1_height = CVPixelBufferGetHeightOfPlane(pixel_buffer,0); 79 | size_t plan1_sizePerRow = CVPixelBufferGetBytesPerRowOfPlane(pixel_buffer,0); 80 | 81 | memcpy(plan1, outputBytes, plan1_height * plan1_sizePerRow); 82 | 83 | uint8_t * plan2 = CVPixelBufferGetBaseAddressOfPlane(pixel_buffer,1); 84 | size_t plan2_height = CVPixelBufferGetHeightOfPlane(pixel_buffer,1); 85 | size_t plan2_sizePerRow = CVPixelBufferGetBytesPerRowOfPlane(pixel_buffer,1); 86 | 87 | memcpy(plan2, outputBytes + plan1_height * plan1_sizePerRow, plan2_height * plan2_sizePerRow); 88 | 89 | CVPixelBufferUnlockBaseAddress(pixel_buffer, 0); 90 | 91 | free(outputBytes); 92 | 93 | return pixel_buffer; 94 | 95 | } else if(pixelFormatType == kCVPixelFormatType_420YpCbCr8PlanarFullRange) { 96 | // i420 97 | 98 | NSLog(@"send kCVPixelFormatType_420YpCbCr8PlanarFullRange"); 99 | 100 | 101 | CVPixelBufferLockBaseAddress(pixelBuffer, 0); 102 | 103 | int width = CVPixelBufferGetWidth(pixelBuffer); 104 | int height = CVPixelBufferGetHeight(pixelBuffer); 105 | 106 | int half_width = (width + 1) / 2; 107 | int half_height = (height + 1) / 2; 108 | 109 | const int y_size = width * height; 110 | const int uv_size = half_width * half_height * 2 ; 111 | const size_t total_size = y_size + uv_size; 112 | 113 | uint8_t* outputBytes = calloc(1,total_size); 114 | 115 | uint8_t* srcBase = CVPixelBufferGetBaseAddress(pixelBuffer); 116 | 117 | I420ToNV12(CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0), 118 | half_width * 2, 119 | CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1), 120 | half_width, 121 | CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 2), 122 | half_width, 123 | outputBytes, 124 | half_width * 2, 125 | outputBytes + y_size, 126 | half_width * 2, 127 | width, height); 128 | 129 | CVPixelBufferUnlockBaseAddress(pixelBuffer, 0); 130 | 131 | CVPixelBufferRef pixel_buffer = NULL; 132 | 133 | CVPixelBufferCreate(kCFAllocatorDefault, width , height, 134 | kCVPixelFormatType_420YpCbCr8BiPlanarFullRange, 135 | NULL, &pixel_buffer); 136 | 137 | CVPixelBufferLockBaseAddress(pixel_buffer, 0); 138 | 139 | uint8_t * plan1 = CVPixelBufferGetBaseAddressOfPlane(pixel_buffer,0); 140 | size_t plan1_height = CVPixelBufferGetHeightOfPlane(pixel_buffer,0); 141 | size_t plan1_sizePerRow = CVPixelBufferGetBytesPerRowOfPlane(pixel_buffer,0); 142 | 143 | memcpy(plan1, outputBytes, plan1_height * plan1_sizePerRow); 144 | 145 | uint8_t * plan2 = CVPixelBufferGetBaseAddressOfPlane(pixel_buffer,1); 146 | size_t plan2_height = CVPixelBufferGetHeightOfPlane(pixel_buffer,1); 147 | size_t plan2_sizePerRow = CVPixelBufferGetBytesPerRowOfPlane(pixel_buffer,1); 148 | 149 | memcpy(plan2, outputBytes + plan1_height * plan1_sizePerRow, plan2_height * plan2_sizePerRow); 150 | 151 | CVPixelBufferUnlockBaseAddress(pixel_buffer, 0); 152 | 153 | free(outputBytes); 154 | 155 | return pixel_buffer; 156 | 157 | } 158 | 159 | return NULL; 160 | } 161 | 162 | 163 | @end 164 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CVPixelBuffer-Convert 2 | CVPixelBuffer convert NV12 I420 BGRA 3 | --------------------------------------------------------------------------------