YUV数据讲解

网上YUV如出一辙都是翻译的:
https://msdn.microsoft.com/en-us/library/windows/desktop/dd206750(v=vs.85).aspx

YUV有两大类型:planar 和 packed

对于planar的YUV ,先连续存储所有像素点的Y,接着存储所有像素点的U,接着存储像素点的V。

对于packed的YUV,每个像素点的Y,U,V是连续交叉存储的。

YUV主流采样方式有三种:YUV4:4:4,YUV 4:2:2 ,YUV 4:2:0

YUV4:4:4 每一个Y对应一组UV分量。

YUV4:2:2 每两个Y 公用一组UV分量

YUV4:2:0 每四个Y 公用一组UV分量

存储方式

(1)YUYV格式(YUV422)
YUYV为YUV422采样的存储方式的一种,相邻的两个Y公用其相邻的两个Cb,Cr,对于像素点Y’00,Y’01而言,其Cb,Cr的值均为Cb00,Cr00

(2)UYVY(YUV422)
每两个Y公用一个UV

(3)YUV422P(YUV422)
YUV422P也属于YUV422的一种,它是Plane模式,先存放所有的Y分量,然后存储所有的U(Cb)分量,最后存储所有的V(Cr)分量,两个Y公用一个UV,比如Y’00,Y’01而言,其Cb,Cr的值均为Cb00,Cr00

(4)YV12,YU12格式(YUV420)
YU12和YV12属于YUV420格式,也是一种Plane模式,将Y,U,V分量分别打包,一次存储。4个Y分量公用一组UV,Y’00,Y’01,Y’10,Y’11公用Cr00,Cb00

(5)NV12,NV21(YUV420)
NV12和NV21属于YUV420格式,是一种two-plane模式,即Y和UV分为两个Plane,但是UV(CbCr)为交错存储,而不是分为三个Plane,其提取方式与上一种类似,即
Y’00,Y’01,Y’10,Y’11公用Cr00,Cb00

I420: YYYYYYYY UU VV =>YUV420P

YV12: YYYYYYYY VV UU =>YUV420P

NV12: YYYYYYYY UVUV =>YUV420SP

NV21: YYYYYYYY VUVU =>YUV420SP

YUV420planer数据

以1280*960大小图像YUV420 planar为例
其存储格式是:共大小为(1280*960*3>>1)字节,即w*h*1.5
分为三个部分:Y,U,V

其中
Y分量:1280*960
U分量:1280*960>>2
V分量:1280*960>>2

三个部分内部均是优先存储,三个部分之间是Y,U,V顺序存储
即YUV数据的0~1280*960字节是Y分量值
1280*960~1280*960*(1+1/4)字节是U分量
1280*960*(1+1/4)~1280*960*(1+1/4+1/4)字节是V分量

ImageStride(内存图像行跨度)

当视频图像存储在内存时,图像的每一行末尾也许包含一些扩展的内容,这些扩展的内容值影响图像如何存储在内存中,啊电脑是不影响图像如何显示出来。

Stride就是这些扩展内容的名称,Stride也被称作Pitch,如果图像的每一行像素末尾拥有扩展内容,Stride的值一定大于图像的宽度值 Stride =(Image width + padding).

两个缓冲区包含同样大小(宽度和高度)的视频帧,却不一定拥有同样的Stride值,如果你处理一个视频帧,你必须在计算的时候把Stride考虑进去;

另外,一张图象在内存中有两种不同的存储序列,对于一个从上而下存储的图像,最顶行的像素保存在内存中最开头的部分,对于一张从下而上存储的图像,最后一行的像素保存在内存中最开始的部分。

一张从下而上的图像拥有一个负的Stride值,因为Stride定义为[从一行像素一动到下一行像素时需要跨国多少个像素],仅相对于被显示出来的图像而言;而YUV图像永远都是从上而下表示的,RGB图像保存在系统内存时通常是从下而上;

尤其是视频变换,特别需要处理不同Stride值的图像,因为输入缓冲也许与输出缓冲不匹配,举个例子,假设你想要将视频源图像转换并且将结果写入到目标图像,假设两个图像拥有相同的宽度和高度,但是其像素格式与Stride值也许不同;

补充一点: 如果图片大小也就是图片字节是4的整数倍,那么Stride与Width是相同的,
否则Stride就是大于Width的最小4的整数倍。在处理过程中,Stride肯定是4个整数倍。

当不是4的倍数的时候Stride = Stride + (4 – Stride mod 4);

每个Y为一个像素 8bit = 1Byte
U = 2bit = 1/4 (Y)
V = 2bit = 1/4 (Y)

补充:

当像素处理单行的时候(暂时没有遇到过单处理单列的情况),对于U,V的取值为1/2 Y

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MFC是一个Microsoft Foundation Class的缩写,是一种应用程序框架,可用于创建Windows桌面应用程序。海康是一家提供视频监控设备和解决方案的公司。在这里我们将介绍如何使用MFC将海康的视频流数据转码为FLV视频流格式。 首先,我们需要安装海康SDK和FFmpeg库。海康SDK可以从官方网站上下载,而FFmpeg库可以从官方网站或者其他第三方网站下载。 接下来,我们需要使用MFC创建一个Windows桌面应用程序。在Visual Studio中,我们选择“新建项目”->“MFC应用程序”,并选择“桌面应用程序”作为应用程序类型。 在创建项目后,我们需要在项目中添加海康SDK和FFmpeg库的头文件和库文件。我们可以在项目属性中添加这些文件,或者直接将这些文件复制到项目文件夹中。 接下来,我们需要编写代码来获取海康设备的视频流数据,并将其转码为FLV格式。以下是代码示例: ```c++ #include <Windows.h> #include <iostream> #include <fstream> #include <string> #include "HCNetSDK.h" #include "ffmpeg.h" using namespace std; void CALLBACK DecCBFun(LONG nPort, char * pBuf, LONG nSize, FRAME_INFO * pFrameInfo, void* nReserved1, LONG nReserved2) { //将海康视频流数据转码为FLV格式 AVPacket pkt; av_init_packet(&pkt); pkt.data = (uint8_t *)pBuf; pkt.size = nSize; pkt.flags |= AV_PKT_FLAG_KEY; pkt.stream_index = 0; //打开输出文件 ofstream outfile("output.flv", ios::out | ios::binary | ios::app); //将AVPacket写入输出文件 if (outfile.is_open()) { av_interleaved_write_frame(ofmt_ctx, &pkt); outfile.write((char *)pkt.data, pkt.size); outfile.close(); } } void main() { //初始化海康SDK NET_DVR_Init(); //登录海康设备 NET_DVR_DEVICEINFO_V30 struDeviceInfo; LONG lUserID = NET_DVR_Login_V30("192.168.1.64", 8000, "admin", "12345", &struDeviceInfo); //启动海康视频流 LONG lRealPlayHandle = NET_DVR_RealPlay_V30(lUserID, &struPlayInfo, NULL, NULL); //初始化FFmpeg av_register_all(); //创建输出AVFormatContext avformat_alloc_output_context2(&ofmt_ctx, NULL, "flv", NULL); //创建视频AVStream AVStream * video_st = avformat_new_stream(ofmt_ctx, NULL); video_st->codec->codec_id = AV_CODEC_ID_H264; video_st->codec->codec_type = AVMEDIA_TYPE_VIDEO; video_st->codec->bit_rate = 400000; video_st->codec->width = 640; video_st->codec->height = 480; video_st->codec->time_base = (AVRational){ 1, 25 }; video_st->codec->gop_size = 10; video_st->codec->pix_fmt = AV_PIX_FMT_YUV420P; //打开输出文件 avio_open(&ofmt_ctx->pb, "output.flv", AVIO_FLAG_WRITE); //写入输出文件头 avformat_write_header(ofmt_ctx, NULL); //设置海康视频流回调函数 NET_DVR_SetDecCallBack(lRealPlayHandle, DecCBFun, NULL); //等待用户按下任意键退出程序 getchar(); //关闭输出文件 av_write_trailer(ofmt_ctx); avio_close(ofmt_ctx->pb); //关闭海康视频流 NET_DVR_StopRealPlay(lRealPlayHandle); //注销海康设备 NET_DVR_Logout(lUserID); //释放海康SDK NET_DVR_Cleanup(); } ``` 在上面的代码中,我们首先初始化海康SDK,并使用用户信息登录海康设备。然后,我们启动海康视频流,并初始化FFmpeg,创建输出文件和视频流。接下来,我们设置海康视频流回调函数,以便在获取数据时将其转换为FLV格式。最后,我们等待用户按下任意键退出程序,并关闭所有相关资源。 需要注意的是,这只是一个示例代码,实际应用中需要根据具体的情况进行修改和调整。同时,由于海康SDK和FFmpeg库的版本不同,可能会导致代码无法正常运行,需要进行相应的修改和调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值