文档章节

YUV数据

S
 SimonXun
发布于 2016/11/09 18:35
字数 960
阅读 350
收藏 0
点赞 0
评论 0

视频是由一帧一帧的数据连接而成,而一帧视频数据其实就是一张图片。

yuv是一种图片储存格式,跟RGB格式类似。

RGB格式的图片很好理解,计算机中的大多数图片,都是以RGB格式存储的。

yuv中,y表示亮度,单独只有y数据就可以形成一张图片,只不过这张图片是灰色的。u和v表示色差(u和v也被称为:Cb-蓝色差,Cr-红色差)。

YUV 字节数

  • 一张yuv格式的图像,占用字节数为 (width height + (width height) / 4 + (width height) / 4) = (width height) 3 / 2
  • 一张RGB格式的图像,占用字节数为(width height) * 3

YUV 格式

  • yuv420也包含不同的数据排列格式:I420,NV12,NV21. 其格式分别如下,

    I420格式:y,u,v 3个部分分别存储:Y0,Y1...Yn,U0,U1...Un/2,V0,V1...Vn/2
    
    NV12格式:y和uv 2个部分分别存储:Y0,Y1...Yn,U0,V0,U1,V1...Un/2,Vn/2
    
    NV21格式:同NV12,只是U和V的顺序相反。
    

综合来说,除了存储顺序不同之外,上述格式对于显示来说没有任何区别。

使用哪种视频的格式,取决于初始化相机时设置的视频输出格式。

设置为kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange时,表示输出的视频格式为NV12;

设置为kCVPixelFormatType_420YpCbCr8Planar时,表示使用I420。

GPUImage设置相机输出数据时,使用的就是NV12.

NSData 转 CVPixelBufferRef

static OSType KVideoPixelFormatType = kCVPixelFormatType_420YpCbCr8BiPlanarFullRange;

 
+ (CVPixelBufferRef)yuvPixelBufferWithData:(NSData *)dataFrame
                          presentationTime:(CMTime)presentationTime
                                     width:(size_t)w
                                    heigth:(size_t)h
{
    unsigned char* buffer = (unsigned char*) dataFrame.bytes;
    CVPixelBufferRef getCroppedPixelBuffer = [self copyDataFromBuffer:buffer toYUVPixelBufferWithWidth:w Height:h];
    return getCroppedPixelBuffer;
}

+ (CVPixelBufferRef) copyDataFromBuffer:(const unsigned char*)buffer toYUVPixelBufferWithWidth:(size_t)w Height:(size_t)h
{
    NSDictionary *pixelBufferAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
//                                           [NSDictionary dictionary],kCVPixelBufferIOSurfacePropertiesKey,
                                           nil];
    
    CVPixelBufferRef pixelBuffer;
    CVPixelBufferCreate(NULL, w, h, KVideoPixelFormatType, (__bridge CFDictionaryRef)(pixelBufferAttributes), &pixelBuffer);
    
    CVPixelBufferLockBaseAddress(pixelBuffer, 0);
    
    size_t d = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 0);
    const unsigned char* src = buffer;
    unsigned char* dst = (unsigned char *)CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0);
    
    for (unsigned int rIdx = 0; rIdx < h; ++rIdx, dst += d, src += w) {
        memcpy(dst, src, w);
    }
    
    d = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 1);
    dst = (unsigned char *)CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1);
    h = h >> 1;
    for (unsigned int rIdx = 0; rIdx < h; ++rIdx, dst += d, src += w) {
        memcpy(dst, src, w);
    }
    
    CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
    
    return pixelBuffer;
 
}

CVPixelBufferRef 转 NSData

+ (NSData *)dataWithYUVPixelBuffer:(CVPixelBufferRef)pixelBuffer
{
    size_t width = CVPixelBufferGetWidth(pixelBuffer);
    size_t height  = CVPixelBufferGetHeight(pixelBuffer);
    unsigned char* buffer = (unsigned char*) malloc(width * height * 1.5);
    // 取视频YUV数据
    [self copyDataFromYUVPixelBuffer:pixelBuffer toBuffer:buffer];
    // 保存到本地
    NSData *retData = [NSData dataWithBytes:buffer length:sizeof(unsigned char)*(width*height*1.5)];
    free(buffer);
    buffer = nil;
    return retData;
}

//the size of buffer has to be width * height * 1.5 (yuv)
+ (void) copyDataFromYUVPixelBuffer:(CVPixelBufferRef)pixelBuffer toBuffer:(unsigned char*)buffer {
    CVPixelBufferLockBaseAddress(pixelBuffer, 0);
    if (CVPixelBufferIsPlanar(pixelBuffer)) {
        size_t w = CVPixelBufferGetWidth(pixelBuffer);
        size_t h = CVPixelBufferGetHeight(pixelBuffer);
        
        size_t d = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 0);
        unsigned char* src = (unsigned char*) CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0);
        unsigned char* dst = buffer;
        
        for (unsigned int rIdx = 0; rIdx < h; ++rIdx, dst += w, src += d) {
            memcpy(dst, src, w);
        }
        
        d = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 1);
        src = (unsigned char *) CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1);
        
        h = h >> 1;
        for (unsigned int rIdx = 0; rIdx < h; ++rIdx, dst += w, src += d) {
            memcpy(dst, src, w);
        }
    }
    CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
 
}

CVPixelBufferRef转UIImage

+ (UIImage *)makeUIImageWithYUVPixelBuffer:(CVPixelBufferRef)pixelBuffer
{
    //Lock the imagebuffer
    CVPixelBufferLockBaseAddress(pixelBuffer,0);
    size_t width = CVPixelBufferGetWidth(pixelBuffer);
    size_t height  = CVPixelBufferGetHeight(pixelBuffer);
    // Get information about the image
    uint8_t *baseAddress = (uint8_t *)CVPixelBufferGetBaseAddress(pixelBuffer);
    size_t bytesPerRow = CVPixelBufferGetBytesPerRow(pixelBuffer);
    CVPlanarPixelBufferInfo_YCbCrBiPlanar *bufferInfo = (CVPlanarPixelBufferInfo_YCbCrBiPlanar *)baseAddress;
    // This just moved the pointer past the offset
    baseAddress = (uint8_t *)CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0);
    CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
    UIImage *image = [NSData makeUIImage:baseAddress bufferInfo:bufferInfo width:width height:height bytesPerRow:bytesPerRow];
    return image;
}

+ (UIImage *)makeUIImage:(uint8_t *)inBaseAddress bufferInfo:(CVPlanarPixelBufferInfo_YCbCrBiPlanar *)inBufferInfo width:(size_t)inWidth height:(size_t)inHeight bytesPerRow:(size_t)inBytesPerRow {
    
    NSUInteger yOffset = EndianU32_BtoN(inBufferInfo->componentInfoY.offset);
    NSUInteger yPitch = EndianU32_BtoN(inBufferInfo->componentInfoY.rowBytes);
    
    NSUInteger cbCrOffset = EndianU32_BtoN(inBufferInfo->componentInfoCbCr.offset);
    NSUInteger cbCrPitch = EndianU32_BtoN(inBufferInfo->componentInfoCbCr.rowBytes);
    
    int bytesPerPixel = 4;
    
    uint8_t *yBuffer = inBaseAddress + yOffset;
    uint8_t *cbCrBuffer = inBaseAddress + cbCrOffset;
    uint8_t *rgbBuffer = (uint8_t *)malloc(inWidth * inHeight * bytesPerPixel);
    
    for(int y = 0; y < inHeight; y++)
    {
        uint8_t *rgbBufferLine = &rgbBuffer[y * inWidth * bytesPerPixel];
        uint8_t *yBufferLine = &yBuffer[y * yPitch];
        uint8_t *cbCrBufferLine = &cbCrBuffer[(y >> 1) * cbCrPitch];
        
        for(int x = 0; x < inWidth; x++)
        {
            int16_t y = yBufferLine[x];
            int16_t cb = cbCrBufferLine[x & ~1] - 128;
            int16_t cr = cbCrBufferLine[x | 1] - 128;
            
            uint8_t *rgbOutput = &rgbBufferLine[x*bytesPerPixel];
            
            int16_t r = (int16_t)roundf( y + cr *  1.4 );
            int16_t g = (int16_t)roundf( y + cb * -0.343 + cr * -0.711 );
            int16_t b = (int16_t)roundf( y + cb *  1.765);
            
            //ABGR
            rgbOutput[0] = 0xff;
            rgbOutput[1] = b > 0 ? (b < 255 ? b : 255) : 0;
            rgbOutput[2] = g > 0 ? (g < 255 ? g : 255) : 0;
            rgbOutput[3] = r > 0 ? (r < 255 ? r : 255) : 0;
        }
    }
    
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(rgbBuffer, yPitch, inHeight, 8,
                                                 yPitch*4, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedLast);
    
    CGImageRef quartzImage = CGBitmapContextCreateImage(context);
    
    CGContextRelease(context);
    CGColorSpaceRelease(colorSpace);
    
    UIImage *image = [UIImage imageWithCGImage:quartzImage];
    
    CGImageRelease(quartzImage);
    free(rgbBuffer);
    rgbBuffer = NULL;
    return  image;
 
}

© 著作权归作者所有

共有 人打赏支持
S
粉丝 5
博文 53
码字总数 51198
作品 0
深圳
程序员
图文详解 YUV420 数据格式

YUV 格式有两大类:planar 和 packed。 对于 planar 的 YUV 格式,先连续存储所有像素点的 Y,紧接着存储所有像素点的 U,随后是所有像素点的 V。 对于 packed 的 YUV 格式,每个像素点的 Y,...

Jerikc ⋅ 2015/10/03 ⋅ 0

视音频数据处理入门:RGB、YUV像素数据处理

===================================================== 视音频数据处理入门系列文章: 视音频数据处理入门:RGB、YUV像素数据处理 视音频数据处理入门:PCM音频采样数据处理 视音频数据处理...

leixiaohua1020 ⋅ 2016/01/29 ⋅ 0

YV12和I420的区别

yuv420: yuv yuv yuv 本文出自 “Paul玩嵌入式Linux” 博客,请务必保留此出处http://zyg0227.blog.51cto.com/1043164/295479...

stefanliao ⋅ 2012/11/26 ⋅ 0

android视音频开发---视频格式nv21转换

引言 android 视音频操作一直是一个令安卓开发工程师感兴趣的技术,学习这方面的知识个人感觉还是蛮难的,本人也是在上家公司接触此类项目才知道的,之后通过看 雷晓华博士的博客来自学关于视...

君莫醉 ⋅ 2017/10/28 ⋅ 0

图文详解YUV420数据格式

完整的链接: http://www.xuebuyuan.com/1541892.html YUV格式有两大类:planar和packed。 对于planar的YUV格式,先连续存储所有像素点的Y,紧接着存储所有像素点的U,随后是所有像素点的V。...

aspirs ⋅ 2016/01/24 ⋅ 0

黄老邪/AVDataProcess

视音频数据处理入门 准备 yuv视频下载: http://trace.eas.asu.edu/yuv/ yuv播放器:修改了一个YUV/RGB播放器 注意: 本文中像素的采样位数一律为8bit。由于1Byte=8bit,所以一个像素的一个分...

黄老邪 ⋅ 2017/10/19 ⋅ 0

使用libyuv对YUV数据进行缩放,旋转,镜像,裁剪等操作

1.背景   在Android做过自定义Camera的朋友应该都知道,我们可以通过public void onPreviewFrame(byte[] data, Camera camera)回调中获取摄像头采集到的每一帧的数据,但是这个byte[] data...

请叫我百米冲刺 ⋅ 2017/11/21 ⋅ 0

YUV420的数据格式

1.YUV数据简介: YUV定义:分为三个分量,Y表示明亮度(Luma),UV表示色度(Chroma) YUV格式:planar和packed。planar:先存储所有像素的Y,再存储所有像素的U,然后V;packed:每个像素的...

HeroHY ⋅ 02/04 ⋅ 0

YUV420如何扣取指定区域的图像数据

YUV420数据的存储方式有两类:planar和packed。planar的YUV格式,先连续存储所有像素点的Y,紧接着存储所有像素点的U,随后是所有像素点的V。对于packed的YUV格式,每个像素点的Y,U,V是连续交...

Gobert ⋅ 2014/12/04 ⋅ 0

利用简单工具进行客观视频质量分析

利用简单工具进行客观视频质量分析 1. 主要工具: ffmpeg, eavlvid 其中eavlvid的下载地址:http://www2.tkn.tu-berlin.de/research/evalvid/EvalVid/evalvid-2.7.tar.bz2 其实只使用了psnr,...

张旭0512 ⋅ 2016/07/11 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

JVM堆的理解

在JVM中,我们经常提到的就是堆了,堆确实很重要,其实,除了堆之外,还有几个重要的模块,看下图: 大 多数情况下,我们并不需要关心JVM的底层,但是如果了解它的话,对于我们系统调优是非常...

不羁之后 ⋅ 昨天 ⋅ 0

推荐:并发情况下:Java HashMap 形成死循环的原因

在淘宝内网里看到同事发了贴说了一个CPU被100%的线上故障,并且这个事发生了很多次,原因是在Java语言在并发情况下使用HashMap造成Race Condition,从而导致死循环。这个事情我4、5年前也经历...

码代码的小司机 ⋅ 昨天 ⋅ 1

聊聊spring cloud gateway的RetryGatewayFilter

序 本文主要研究一下spring cloud gateway的RetryGatewayFilter GatewayAutoConfiguration spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/config/G......

go4it ⋅ 昨天 ⋅ 0

创建新用户和授予MySQL中的权限教程

导读 MySQL是一个开源数据库管理软件,可帮助用户存储,组织和以后检索数据。 它有多种选项来授予特定用户在表和数据库中的细微的权限 - 本教程将简要介绍一些选项。 如何创建新用户 在MySQL...

问题终结者 ⋅ 昨天 ⋅ 0

android -------- 颜色的半透明效果配置

最近有朋友问我 Android 背景颜色的半透明效果配置,我网上看资料,总结了一下, 开发中也是常常遇到的,所以来写篇博客 常用的颜色值格式有: RGB ARGB RRGGBB AARRGGBB 这4种 透明度 透明度...

切切歆语 ⋅ 昨天 ⋅ 0

CentOS开机启动subversion

建立自启动脚本: vim /etc/init.d/subversion 输入如下内容: #!/bin/bash## subversion startup script for the server## chkconfig: 2345 90 10# description: start the subve......

随风而飘 ⋅ 昨天 ⋅ 0

Nginx + uwsgi @ubuntu

uwsgi 安装 sudo apt-get install python3-pip # 注意 ubuntu python3默认没有安装pippython3 -m pip install uwsgi 代码(test.py) def application(env, start_response): start_res......

袁祾 ⋅ 昨天 ⋅ 0

版本控制工具

CSV , SVN , GIT ,VSS

颖伙虫 ⋅ 昨天 ⋅ 0

【2018.06.19学习笔记】【linux高级知识 13.1-13.3】

13.1 设置更改root密码 13.2 连接mysql 13.3 mysql常用命令

lgsxp ⋅ 昨天 ⋅ 0

LVM

LVM: 硬盘划分分区成物理卷->物理卷组成卷组->卷组划分逻辑分区。 1.磁盘分区: fdisk /dev/sdb 划分几个主分区 输入t更改每个分区类型为8e(LVM) 使用partprobe生成分区的文件:如/dev/sd...

ZHENG-JY ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部