libyuv NV12镜像

从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;
}

© 版权声明

相关文章

4 条评论

您必须登录才能参与评论!
立即登录
  • 头像
    凭栏听雨 读者

    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 就没问题 。具体不知道哪里的原因 😂

    无记录