从CMSampleBufferRef中取出NV12数据,转换为i420,对i420数据做镜像,然后把镜像的i420转换为NV12,再把NV12包装成CVPixelBufferRef。
+ (CVPixelBufferRef)mirrorSampleBuffler:(CMSampleBufferRef)sampleBufRef {
//CVPixelBufferRef是CVImageBufferRef的别名,两者操作几乎一致。
//获取CMSampleBuffer的图像地址
CVImageBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBufRef);
if (!pixelBuffer) {
return nil;
}
//表明开始操作数据
CVPixelBufferLockBaseAddress(pixelBuffer, 0);
//图像宽度(像素)
size_t buffer_width = CVPixelBufferGetWidth(pixelBuffer);
//图像高度(像素)
size_t buffer_height = CVPixelBufferGetHeight(pixelBuffer);
//获取CVImageBufferRef中的y数据
uint8_t *src_y_frame = (unsigned char *)CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0);
//获取CMVImageBufferRef中的uv数据
uint8_t *src_uv_frame =(unsigned char *) CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1);
//y stride
size_t plane1_stride = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 0);
//uv stride
size_t plane2_stride = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 1);
//y height
size_t plane1_height = CVPixelBufferGetHeightOfPlane(pixelBuffer, 0);
//uv height
size_t plane2_height = CVPixelBufferGetHeightOfPlane(pixelBuffer, 1);
//y_size
size_t plane1_size = plane1_stride * plane1_height;
//uv_size
size_t plane2_size = plane2_stride * plane2_height;
//yuv_size(内存空间)
size_t frame_size = plane1_size + plane2_size;
// 1.NV12转换为I420
// 开辟buffer_frame大小的内存空间用于存放转换好的i420数据
uint8* buffer_y = (unsigned char *)malloc(frame_size);
uint8* buffer_u = buffer_y + plane1_size;
uint8* buffer_v = buffer_u + plane1_size / 4;
libyuv::NV12ToI420(/*const uint8 *src_y*/ src_y_frame,
/*int src_stride_y*/ (int)plane1_stride,
/*const uint8 *src_uv*/ src_uv_frame,
/*int src_stride_uv*/ (int)plane2_stride,
/*uint8 *dst_y*/ buffer_y,
/*int dst_stride_y*/ (int)plane1_stride,
/*uint8 *dst_u*/ buffer_u,
/*int dst_stride_u*/ (int)plane1_stride >> 1,
/*uint8 *dst_v*/ buffer_v,
/*int dst_stride_v*/ (int)plane1_stride >> 1,
/*int width*/ (int)buffer_width,
/*int height*/ (int)buffer_height);
CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
uint8* mirror_y = (unsigned char *)malloc(frame_size);
uint8* mirror_u = mirror_y + plane1_size;
uint8* mirror_v = mirror_u + plane1_size / 4;
libyuv::I420Mirror(/*const uint8* src_y*/buffer_y,
/*int src_stride_y*/(int)plane1_stride,
/*const uint8* src_u*/buffer_u,
/*int src_stride_u*/(int)plane1_stride >> 1,
/*const uint8* src_v*/buffer_v,
/*int src_stride_v*/(int)plane1_stride >> 1,
/*uint8* dst_y*/mirror_y,
/*int dst_stride_y*/(int)plane1_stride,
/*uint8* dst_u*/mirror_u,
/*int dst_stride_u*/(int)plane1_stride >> 1,
/*uint8* dst_v*/mirror_v,
/*int dst_stride_v*/(int)plane1_stride >> 1,
/*int width*/(int)buffer_width,
/*int height*/(int)buffer_height);
free(buffer_y);
uint8 *nv12_y = (uint8 *)malloc(frame_size);
uint8* nv12_uv = nv12_y + plane1_stride * plane1_height;
libyuv::I420ToNV12(/*const uint8 *src_y*/ mirror_y,
/*int src_stride_y*/ (int)plane1_stride,
/*const uint8 *src_u*/ mirror_u,
/*int src_stride_u*/ (int)plane1_stride >> 1,
/*const uint8 *src_v*/ mirror_v,
/*int src_stride_v*/ (int)plane1_stride >> 1,
/*uint8 *dst_y*/ nv12_y,
/*int dst_stride_y*/ (int)plane1_stride,
/*uint8 *dst_uv*/ nv12_uv,
/*int dst_stride_uv*/ (int)plane1_stride,
/*int width*/ (int)buffer_width,
/*int height*/ (int)buffer_height);
free(mirror_y);
// 4.NV12转换为CVPixelBufferRef
NSDictionary *pixelAttributes = @{(id)kCVPixelBufferIOSurfacePropertiesKey : @{}};
CVPixelBufferRef dstPixelBuffer = NULL;
CVReturn result = CVPixelBufferCreate(kCFAllocatorDefault,
buffer_width, buffer_height, kCVPixelFormatType_420YpCbCr8BiPlanarFullRange,
(__bridge CFDictionaryRef)pixelAttributes, &dstPixelBuffer);
CVPixelBufferLockBaseAddress(dstPixelBuffer, 0);
uint8_t *yDstPlane = (uint8*)CVPixelBufferGetBaseAddressOfPlane(dstPixelBuffer, 0);
memcpy(yDstPlane, nv12_y, plane1_size);
uint8_t *uvDstPlane = (uint8*)CVPixelBufferGetBaseAddressOfPlane(dstPixelBuffer, 1);
memcpy(uvDstPlane, nv12_uv, plane2_size);
if (result != kCVReturnSuccess) {
NSLog(@"Unable to create cvpixelbuffer %d", result);
}
CVPixelBufferUnlockBaseAddress(dstPixelBuffer, 0);
free(nv12_y);
return dstPixelBuffer;
}
© 版权声明
文章版权归作者所有,未经允许请勿转载。
相关文章
您必须登录才能参与评论!
立即登录
nv12可以直接转镜像吧
int NV12Mirror(const uint8_t* src_y, int src_stride_y, const uint8_t* src_uv, int src_stride_uv, uint8_t* dst_y, int dst_stride_y, uint8_t* dst_uv, int dst_stride_uv, int width, int height) { int halfwidth = (width + 1) >> 1; int halfheight = (height + 1) >> 1; if (!src_y || !src_uv || !dst_uv || width <= 0 || height == 0) { return -1; } // Negative height means invert the image. if (height < 0) { height = -height; halfheight = (height + 1) >> 1; src_y = src_y + (height – 1) * src_stride_y; src_uv = src_uv + (halfheight – 1) * src_stride_uv; src_stride_y = -src_stride_y; src_stride_uv = -src_stride_uv; } if (dst_y) { MirrorPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height); } MirrorUVPlane(src_uv, src_stride_uv, dst_uv, dst_stride_uv, halfwidth, halfheight); return 0;}
是的,libyuv有提供接口。
@Leoeoo 直接nv12 mirror 部分机型会绿屏 用你这种先转i420 再 mirror 就没问题 。具体不知道哪里的原因 😂