macos中的YUV420p内存布局...
来源:互联网 发布:红鸟房卡手机棋牌源码 编辑:程序博客网 时间:2024/06/06 00:04
- 前言
- 旧的方法
- 新的方法
- 我的yuv420p去哪了
- 显示的有问题
- 验证方式
- 怎么解决内存对齐的问题
- 总结
前言
最近在这折腾mac截屏。 中间遇到了一些坎坷特此记录一下。
旧的方法
之前经验不够,网上什么方法简单,就用什么。 因为项目是使用Qt编的,Qt也做了一些与ObjC类的一些兼容,就采取了如下方式:
QPixmap OsxFun::getMainScreenPixmap(){ int activeDisplay; size_t screenX, screenY; activeDisplay = CGMainDisplayID(); screenY = CGDisplayPixelsHigh(activeDisplay); screenX = CGDisplayPixelsWide(activeDisplay); qDebug()<<"robin:img cr befor time:"<<QDateTime::currentDateTime().toString("mm:ss:zzz")<<"-----------"; CGImageRef image = CGDisplayCreateImage(activeDisplay); qDebug()<<"robin:cover befort time:"<<QDateTime::currentDateTime().toString("mm:ss:zzz"); QPixmap t_outPixmap = QtMac::fromCGImageRef(image); qDebug()<<"robin:cover end time:"<<QDateTime::currentDateTime().toString("mm:ss:zzz"); if(m_bIsRetina) { t_outPixmap.setDevicePixelRatio(2); } CGImageRelease(image); return t_outPixmap;}
但是效率实在不怎么样。 CGDisplayCreateImage 花去了几十ms。 QtMac::fromCGImageRef 又花去了几十ms。 两个加起来在60ms~110ms之间, 我的MBP,1s中只有10帧的样子。而且发现一个问题,当我当前程序的窗口切换为其它程序的时候,系统自动将我这个程序的cpu占用率降低了,结果就进一步降低了截屏的帧数。 于是继续找新的方式。
新的方法
我主要参考的是《是怎么踩过在 OSX 上录屏的坑的》这篇文章,他的demo写的很不错,为作者点个赞。
我的yuv420p去哪了
在设置输出格式那里,先前的作者用的是kCVPixelFormatType_32BGRA,而我需要的是yuv420p。结果发现了mac不按套路出牌的地方(或者说是跟ffmpeg没商量好的地方)。
在这里我找到了对应
static const struct AVFPixelFormatSpec avf_pixel_formats[] = {{ AV_PIX_FMT_MONOBLACK, kCVPixelFormatType_1Monochrome },{ AV_PIX_FMT_RGB555BE, kCVPixelFormatType_16BE555 },{ AV_PIX_FMT_RGB555LE, kCVPixelFormatType_16LE555 },{ AV_PIX_FMT_RGB565BE, kCVPixelFormatType_16BE565 },{ AV_PIX_FMT_RGB565LE, kCVPixelFormatType_16LE565 },{ AV_PIX_FMT_RGB24, kCVPixelFormatType_24RGB },{ AV_PIX_FMT_BGR24, kCVPixelFormatType_24BGR },{ AV_PIX_FMT_0RGB, kCVPixelFormatType_32ARGB },{ AV_PIX_FMT_BGR0, kCVPixelFormatType_32BGRA },{ AV_PIX_FMT_0BGR, kCVPixelFormatType_32ABGR },{ AV_PIX_FMT_RGB0, kCVPixelFormatType_32RGBA },{ AV_PIX_FMT_BGR48BE, kCVPixelFormatType_48RGB },{ AV_PIX_FMT_UYVY422, kCVPixelFormatType_422YpCbCr8 },{ AV_PIX_FMT_YUVA444P, kCVPixelFormatType_4444YpCbCrA8R },{ AV_PIX_FMT_YUVA444P16LE, kCVPixelFormatType_4444AYpCbCr16 },{ AV_PIX_FMT_YUV444P, kCVPixelFormatType_444YpCbCr8 },{ AV_PIX_FMT_YUV422P16, kCVPixelFormatType_422YpCbCr16 },{ AV_PIX_FMT_YUV422P10, kCVPixelFormatType_422YpCbCr10 },{ AV_PIX_FMT_YUV444P10, kCVPixelFormatType_444YpCbCr10 },{ AV_PIX_FMT_YUV420P, kCVPixelFormatType_420YpCbCr8Planar },{ AV_PIX_FMT_NV12, kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange },{ AV_PIX_FMT_YUYV422, kCVPixelFormatType_422YpCbCr8_yuvs },#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080{ AV_PIX_FMT_GRAY8, kCVPixelFormatType_OneComponent8 },#endif{ AV_PIX_FMT_NONE, 0 }};
熟悉的yuv420p化为了kCVPixelFormatType_420YpCbCr8Planar。 我英文不好,从注释上我看不出来它俩一样。
//mac文档中的说明kCVPixelFormatType_420YpCbCr8Planar = 'y420', /* Planar Component Y'CbCr 8-bit 4:2:0. baseAddr points to a big-endian CVPlanarPixelBufferInfo_YCbCrPlanar struct *///ffmpeg文档中的说明 AV_PIX_FMT_YUV420P, ///< planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
按理说故事结束了……
显示的有问题
验证方式
将产生的yuv数据通过保存到字符串中,然后,写入文件中,然后用yuv播放器播放它,看看是否正常。
size_t width = CVPixelBufferGetWidth(imageBuffer);size_t height = CVPixelBufferGetHeight(imageBuffer);uint8_t *yBuffer = CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 0);size_t yPitch = CVPixelBufferGetBytesPerRowOfPlane(imageBuffer, 0);uint8_t *uBuffer = CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 1);size_t uPitch = CVPixelBufferGetBytesPerRowOfPlane(imageBuffer, 1);uint8_t *vBuffer = CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 2);size_t vPitch = CVPixelBufferGetBytesPerRowOfPlane(imageBuffer, 2);size_t t_planeCount = CVPixelBufferGetPlaneCount(imageBuffer);NSMutableData *t_willWriteData = [[NSMutableData alloc] init];[t_willWriteData appendBytes:yBuffer length:yPitch*height];[t_willWriteData appendBytes:uBuffer length:uPitch*height/2];[t_willWriteData appendBytes:vBuffer length:vPitch*height/2];
这样就将yuv数据保存到文件中。 然后用yuv播放器查看的时候,发现图像不对。y通道是对的,u通道、v通道不对。
注:我的屏幕分辨率是1440*900 按道理
yPitch 应该等于1440(为什么是应该呢,因为我遇到过 1366成为1376的情况)
uPitch 和 vPitch 应该等于yPitch的一半(720)。
谁知uPitch和vPitch的值为736。
我就有点懵逼了。
我尝试将数据的存入方式改为了
NSMutableData *t_willWriteData = [[NSMutableData alloc] init];[t_willWriteData appendBytes:yBuffer length:yPitch*height];for (int i = 0; i < height; i++) { [t_willWriteData appendBytes:uBuffer+i*uPitch length:yPitch/2];}for (int i = 0; i < height; i++) { [t_willWriteData appendBytes:vBuffer+i*uPitch length:yPitch/2];}
现在显示正常了。
现在确定了确实是内存对齐的问题。
怎么解决内存对齐的问题
像上面一样,写两个for循环,确实可以解决问题。但是又不能用for循环。
因为视频处理中用for循环处理像素数据,最后程序效率肯定不咋滴。
翻了很久的文档,没找打方式。又思考了良久(大半天时间),意识到了解决办法(还没验证) 从播放器端解决。播放器显示处理的时候,让它来处理这个对齐问题。
总结
想不到YUV420p的内存对齐还有这么多的问题。 不光是Y通道的大小不一定等于图片宽带,UV的大小也不一定等于Y的一半。
//来自ffmepg头文件/** * For video, size in bytes of each picture line. * For audio, size in bytes of each plane. * * For audio, only linesize[0] may be set. For planar audio, each channel * plane must be the same size. * * For video the linesizes should be multiples of the CPUs alignment * preference, this is 16 or 32 for modern desktop CPUs. * Some code requires such alignment other code can be slower without * correct alignment, for yet other it makes no difference. * * @note The linesize may be larger than the size of usable data -- there * may be extra padding present for performance reasons. */int AVFrame::linesize[AV_NUM_DATA_POINTERS];
从目前来看的情况是:
YUV420p实际有效的数据量:
- macos中的YUV420p内存布局...
- yuv420p
- YUV420P
- windw进程中的内存布局
- c++继承中的内存布局
- c++继承中的内存布局
- c++继承中的内存布局
- c++继承中的内存布局
- c++继承中的内存布局
- c++继承中的内存布局
- c++继承中的内存布局
- c++继承中的内存布局
- c++继承中的内存布局
- C++继承中的内存布局
- c++继承中的内存布局
- c++继承中的内存布局
- c++继承中的内存布局
- c++继承中的内存布局
- mysql5.7.18解压版启动mysql服务
- python select网络编程模块详解
- dom4j解析Xml文件工具类
- 分布式文件系统 FastDFS 与nginx 结合
- 递归分治与动态规划--上台阶的问题
- macos中的YUV420p内存布局...
- Linux下的git配置
- 【C++笔记】宏定义数据类型与typedef
- java.lang.UnsatisfiedLinkError 之 apk安装到系统目录
- KVM 实战虚拟机克隆
- linux自动加载模块,理解linux启动流程
- css背景
- 大型重构
- lua 调用C++动态库