音视频基础——libyuv格式转换
http://blog.csdn.net/fengbingchun/article/details/50323273
libyuv是Google开源的实现各种YUV与RGB之间相互转换、旋转、缩放的库。它是跨平台的,可在Windows、Linux、Mac、Android等操作系统,x86、x64、arm架构上进行编译运行,支持SSE、AVX、NEON等SIMD指令加速。
下面说一下libyuv在Windows7VS2013 x64上的编译步骤及使用:
1. 从https://code.google.com/p/libyuv/source/checkout或者https://github.com/lemenkov/libyuv下载libyuv源码;我是通过svn直接从google下载的,版本号是1433,更新日期2015年6月13日;
2. 通过cmake gui生成vs2013 x64工程,不需要额外的配置;
3. 打开Project.sln工程,重新编译,即可生成yuv.lib静态库;
4. 新添加一个test_libyuv控制台工程,用于测试yuv.lib的正确性,测试代码如下:
- #include <iostream>
- #include <assert.h>
- #include "libyuv.h"
- #include <cmath>
- #include <opencv2/opencv.hpp>
- void test_BGRAToI420(const cv::Mat& matSrc, int width, int height, int size_frame, cv::Mat& matDst);
- void test_BGRAToNV21(const cv::Mat& matSrc, int width, int height, int size_frame, cv::Mat& matDst);
- void test_BGRAToNV12(const cv::Mat& matSrc, int width, int height, int size_frame, cv::Mat& matDst);
- int main(int argc, char* argv[])
- {
- cv::Mat matSrc = cv::imread("cat.jpg");
- if (!matSrc.data) {
- std::cout << "read src image error" << std::endl;
- return -1;
- }
- //cv::resize(matSrc, matSrc, cv::Size(500, 111));
- int width = matSrc.cols;
- int height = matSrc.rows;
- int size_frame = width * height;
- cv::Mat matI420, matNV21, matNV12;
- test_BGRAToI420(matSrc, width, height, size_frame, matI420);
- test_BGRAToNV21(matSrc, width, height, size_frame, matNV21);
- test_BGRAToNV12(matSrc, width, height, size_frame, matNV12);
- assert((matI420.depth() == matNV21.depth()) && (matI420.depth() == matNV12.depth()));
- assert((matI420.channels() == matNV21.channels()) && (matI420.channels() == matNV12.channels()));
- for (int i = 0; i < height; i++) {
- const unsigned char* pI420 = matI420.ptr(i);
- const unsigned char* pNV21 = matNV21.ptr(i);
- const unsigned char* pNV12 = matNV12.ptr(i);
- for (int j = 0, m = 0; j < width; j++, m+=4) {
- if ((pI420[m] != pNV21[m]) || (pI420[m] != pNV12[m]) ||
- (pI420[m + 1] != pNV21[m + 1]) || (pI420[m + 1] != pNV12[m + 1]) ||
- (pI420[m + 2] != pNV21[m + 2]) || (pI420[m + 2] != pNV12[m + 2]) ||
- (pI420[m + 3] != pNV21[m + 3]) || (pI420[m + 3] != pNV12[m + 3])) {
- std::cout << "convert error" << std::endl;
- }
- }
- }
- std::cout << "ok" << std::endl;
- return 0;
- }
- void test_BGRAToI420(const cv::Mat& matSrc, int width, int height, int size_frame, cv::Mat& matDst)
- {
- // BGRA <--> I420(YUV420P)
- cv::Mat matBGRA, matI420, matARGB;
- cv::cvtColor(matSrc, matBGRA, cv::COLOR_BGR2BGRA);
- matARGB = cv::Mat(height, width, CV_8UC4, cv::Scalar::all(0));
- libyuv::BGRAToARGB(matBGRA.data, width * 4, matARGB.data, width * 4, width, height);
- uchar* pI420 = new uchar[width * height + (width + 1) / 2 * (height + 1) / 2 * 2];
- memset(pI420, 0, sizeof(uchar) * (width * height + (width + 1) / 2 * (height + 1) / 2 * 2));
- uchar* dst_y = pI420;
- int dst_y_stride = width;
- uchar* dst_u = pI420 + size_frame;
- int dst_u_stride = (width + 1) / 2;
- uchar* dst_v = pI420 + size_frame + dst_u_stride * (height + 1) / 2;
- int dst_v_stride = (width + 1) / 2;
- libyuv::BGRAToI420(matARGB.data, width * 4, dst_y, dst_y_stride, dst_u, dst_u_stride, dst_v, dst_v_stride, width, height);
- matI420 = cv::Mat(height, width, CV_8UC4, cv::Scalar::all(0));
- libyuv::I420ToBGRA(dst_y, dst_y_stride, dst_u, dst_u_stride, dst_v, dst_v_stride, matI420.data, width * 4, width, height);
- cv::Mat matBGRA_ = cv::Mat(height, width, CV_8UC4, cv::Scalar::all(0));
- libyuv::ARGBToBGRA(matI420.data, width * 4, matBGRA_.data, width * 4, width, height);
- cv::imwrite("I420_bgra.jpg", matBGRA_);
- matBGRA_.copyTo(matDst);
- int count_diff = 0;
- int max_diff = 0;
- int threshold = 20;//
- for (int i = 0; i < height; i++) {
- uchar* pSrc = matBGRA.ptr(i);
- uchar* pDst = matBGRA_.ptr(i);
- for (int j = 0, m = 0; j < width; j++, m += 4) {
- int tmp = std::max(abs(pSrc[m] - pDst[m]), abs(pSrc[m + 1] - pDst[m + 1]));
- tmp = std::max(tmp, abs(pSrc[m + 2] - pDst[m + 2]));
- if (tmp > max_diff)
- max_diff = tmp;
- if (abs(pSrc[m] - pDst[m]) > threshold ||
- abs(pSrc[m + 1] - pDst[m + 1]) > threshold ||
- abs(pSrc[m + 2] - pDst[m + 2]) > threshold) {
- count_diff++;
- //std::cout << i << " " << j << std::endl;
- }
- }
- }
- std::cout << "convert I420 to BGRA diff max: " << max_diff << std::endl;
- if (count_diff > width + height) {//
- std::cout << "convert I420 to BGRA error." << std::endl;
- std::cout << "diff num: " << count_diff << std::endl;
- }
- delete[] pI420;
- }
- void test_BGRAToNV12(const cv::Mat& matSrc, int width, int height, int size_frame, cv::Mat& matDst)
- {
- // BGRA <--> NV12
- cv::Mat matBGRA, matNV12;
- cv::cvtColor(matSrc, matBGRA, cv::COLOR_BGR2BGRA);
- uchar* pNV12 = new uchar[width * height + ((width + 1) / 2) * ((height + 1) / 2) * 2];
- memset(pNV12, 0, sizeof(uchar) * (width * height + ((width + 1) / 2) * ((height + 1) / 2) * 2));
- uchar* dst_y = pNV12;
- int dst_y_stride = width;
- uchar* dst_vu = pNV12 + size_frame;
- int dst_vu_stride = (width + 1) / 2 * 2;
- libyuv::ARGBToNV12(matBGRA.data, width * 4, dst_y, dst_y_stride, dst_vu, dst_vu_stride, width, height);
- matNV12 = cv::Mat(height, width, CV_8UC4, cv::Scalar::all(0));
- libyuv::NV12ToARGB(dst_y, dst_y_stride, dst_vu, dst_vu_stride, matNV12.data, width * 4, width, height);
- cv::imwrite("NV12_bgra.jpg", matNV12);
- matNV12.copyTo(matDst);
- int count_diff = 0;
- int max_diff = 0;
- int threshold = 20;//
- for (int i = 0; i < height; i++) {
- uchar* pSrc = matBGRA.ptr(i);
- uchar* pDst = matNV12.ptr(i);
- for (int j = 0, m = 0; j < width; j++, m += 4) {
- int tmp = std::max(abs(pSrc[m] - pDst[m]), abs(pSrc[m + 1] - pDst[m + 1]));
- tmp = std::max(tmp, abs(pSrc[m + 2] - pDst[m + 2]));
- if (tmp > max_diff)
- max_diff = tmp;
- if (abs(pSrc[m] - pDst[m]) > threshold ||
- abs(pSrc[m + 1] - pDst[m + 1]) > threshold ||
- abs(pSrc[m + 2] - pDst[m + 2]) > threshold) {
- count_diff++;
- //std::cout << i << " " << j << std::endl;
- }
- }
- }
- std::cout << "convert NV12 to BGRA diff max: " << max_diff << std::endl;
- if (count_diff > width + height) {//
- std::cout << "convert NV12 to BGRA error." << std::endl;
- std::cout << "diff num: " << count_diff << std::endl;
- }
- delete[] pNV12;
- }
- void test_BGRAToNV21(const cv::Mat& matSrc, int width, int height, int size_frame, cv::Mat& matDst)
- {
- // BGRA <--> NV21
- cv::Mat matBGRA, matNV21;
- cv::cvtColor(matSrc, matBGRA, cv::COLOR_BGR2BGRA);
- uchar* pNV21 = new uchar[width * height + ((width + 1) / 2) * ((height + 1) / 2) * 2];
- memset(pNV21, 0, sizeof(uchar) * (width * height + ((width + 1) / 2) * ((height + 1) / 2) * 2));
- uchar* dst_y = pNV21;
- int dst_y_stride = width;
- uchar* dst_vu = pNV21 + size_frame;
- int dst_vu_stride = (width + 1) / 2 * 2;
- libyuv::ARGBToNV21(matBGRA.data, width * 4, dst_y, dst_y_stride, dst_vu, dst_vu_stride, width, height);
- matNV21 = cv::Mat(height, width, CV_8UC4, cv::Scalar::all(0));
- libyuv::NV21ToARGB(dst_y, dst_y_stride, dst_vu, dst_vu_stride, matNV21.data, width * 4, width, height);
- cv::imwrite("NV21_bgra.jpg", matNV21);
- matNV21.copyTo(matDst);
- int count_diff = 0;
- int max_diff = 0;
- int threshold = 20;//
- for (int i = 0; i < height; i++) {
- uchar* pSrc = matBGRA.ptr(i);
- uchar* pDst = matNV21.ptr(i);
- for (int j = 0, m = 0; j < width; j++, m += 4) {
- int tmp = std::max(abs(pSrc[m] - pDst[m]), abs(pSrc[m + 1] - pDst[m + 1]));
- tmp = std::max(tmp, abs(pSrc[m + 2] - pDst[m + 2]));
- if (tmp > max_diff)
- max_diff = tmp;
- if (abs(pSrc[m] - pDst[m]) > threshold ||
- abs(pSrc[m + 1] - pDst[m + 1]) > threshold ||
- abs(pSrc[m + 2] - pDst[m + 2]) > threshold) {
- count_diff++;
- //std::cout << i << " " << j << std::endl;
- }
- }
- }
- std::cout << "convert NV21 to BGRA diff max: " << max_diff << std::endl;
- if (count_diff > width + height) {//
- std::cout << "convert NV21 to BGRA error." << std::endl;
- std::cout << "diff num: " << count_diff << std::endl;
- }
- delete[] pNV21;
- }
音视频基础——libyuv格式转换相关推荐
- 音视频基础——封装格式
封装格式 概念 封装格式(也叫容器)就是将已经编码压缩好的视频流.音频流及字幕按照一定的方案放到一个文件中,便于播放软件播放.一般来说,视频文件的后缀名就是它的封装格式. 封装的格式不一样,后缀名也就 ...
- 音视频流媒体高级开发进阶:从音视频基础知识到技术实践
站在音视频行业风口 站在风口,猪也能飞".在已经到来的2022年,音视频行业依旧是怎么也绕不过去的风口. 一方面,随着各项5G政策的落实,音视频+5G风口,将会深入挖掘音视频产业的无限潜力, ...
- 音视频基础知识---像素格式RGB
音视频基础知识汇总: 音视频基础知识---协议相关RTSP RTMP HLS 音视频基础知识---封装格式 音视频基础知识---视频编码格式 音视频基础知识---音频编码格式 音视频基础知识---像素 ...
- ffmpeg音视频基础知识
ffmpeg音视频基础知识 前言 一.图像的基础知识 二.视频编码基础知识 1.视频和图片之间的关系 2.为什么要编码? 3.什么是编码? 视频相关专业术语 提示:文章写完后,目录可以自动生成,如何生 ...
- 【音视频基础】视频基础理论
[音视频基础]视频基础理论 图像基本概念 图像 屏幕 图像码流如何计算? 分辨率 帧率 码流计算 图像显示 YUV YUV格式 RGB与YUV的转换 YUV存储 YUV查看工具 参考资料 个人简介
- 音视频基础学习之【01.基于ffmpeg的简单播放器demo实现】
目录 1.项目配置 2.显示界面设计 3.视频解码显示 流程描述 4.演示 最近在学习音视频基础知识,在这里感谢雷神留下的一系列指引新手入门的宝贵资源,虽然他英年早逝,但他的硕果永存.不由感慨真是天妒 ...
- 音视频开发--音视频基础
音视频基础 一.音视频录制原理 视频录制流程 1.准备摄像头 2.图像帧阶段 从摄像头采集视频数据(图像帧),采集数据格式:YUV或者RGB,YUV和RGB细分的话还包括YUV 4:4:4.YUV 4 ...
- 《音视频开发进阶指南》读书笔记(一) —— 音视频基础概念
前言 最近要学音视频,在图书馆借到这本<音视频开发进阶指南>,读了一段时间觉得挺好就在某宝买了. 以后一段时间应该都会沉浸在研究音视频中,开个专题记录哈每一章的读书笔记吧(以iOS开发的角 ...
- 【网络通信 -- 直播】音视频常见封装格式 -- MEPG2 TS
[网络通信 -- 直播]音视频常见封装格式 -- MEPG2 TS [1]相关码流基本概念 ES 流(Elementary Stream)基本码流,直接取自编码器的数据流,可以为音频(AAC 等).视 ...
最新文章
- AutoCAD如何输入文字
- 【软考-软件设计师】汇编程序基本原理
- java 日期处理 口诀_java时间处理常用方法工具类
- 第十一周项目3-程序的多文件组织
- ajax获取qq音乐源码,ajax请求QQ音乐
- mysql数据库开发要求_MYSQL数据库开发规范
- lazarus开发android应用程序指南,Lazarus开发Android应用程序指南(2)
- Visual Basic十年风云
- 电子商务数据运营的五大应用
- 软件测试自学好还是培训好?软件测试自学与培训的优劣势对比
- TextInput组件练习 - QQLogin界面
- haimeiktv服务器系统,海媚 Haimei KTV8001 智能网络效果器
- python用turtle画一个苹果
- T检验是做什么的? --ttest--ttest2--matlab
- 隐语义模型(Latent Factor Model, LFM)原理以及代码实现
- java实现二维码的生成和解析包含工具类
- 个人发卡程序手机版自适应源码 完美版对接免签约支付
- [网络安全课程实验]:基于nmap 的网络扫描和信息分析
- 神经网络与深度学习(入门篇)
- 【算法基础四】C语言小项目实战---通讯录管理系统(单链表)
热门文章
- gmod服务器文件,Garry’s Mod|Gmod服务器架设教程(四)挂载创意工坊插件
- python selenium 点击 报错v_python执行selenium报错
- Kubernetes探针检测
- mysql timestamp 比较_解析mysql TIMESTAMP(时间戳)和datetime不同之处比较
- ProxmoxVE7.0+Ceph15.2集群搭建
- stm32f103rct6引脚功能表格
- Android:技术在线面试还是屡次撞板,过来人告诉你不及时
- IE8适配总结(一)
- maven安装异常 Failure to find xxx in 中央仓库
- 什么是大数据?大数据能做什么?