#include <iostream> #include <fstream> using namespace std; extern "C" { // 指定函数是C语言函数,以C语言的方式去编译 #include <libavcodec/avcodec.h> #include <libswscale/swscale.h> } // 以预处理指令的方式导入库 #pragma comment(lib, "avcodec.lib") #pragma comment(lib, "swscale.lib") #define YUV_FILE "400_300_25.yuv" #define RGBA_FILE "400_300_25.rgba" // 模拟把一个400*300的YUV图像转换成 800 * 600 的RGBA 图像 int main() { // 指定输入视频的宽和高 int yuv_width = 400; int yuv_height = 300; // 指定输出的RGBA图像的宽和高 int rgb_width = 800; int rgb_height = 600; // 申请一块内存用于存储YUV420P的图像 unsigned char* yuv[3] = {0}; int yuv_linesize[3] = {yuv_width, yuv_width / 2, yuv_width / 2}; yuv[0] = new unsigned char[yuv_width * yuv_height]; // Y yuv[1] = new unsigned char[yuv_width * yuv_height / 4]; // U yuv[2] = new unsigned char[yuv_width * yuv_height / 4]; // V // 申请一块内存用于存储转换完成后的RGBA的图像 unsigned char* rgba[1] = {0}; rgba[0] = new unsigned char[rgb_width * rgb_height * 4]; int rgba_linesize[1] = { rgb_width * 4}; //====================================== YUV 文件转 RGBA 文件 =============================================== // 定义输入流 ifstream ifs; ifs.open(YUV_FILE, ios::binary); if (!ifs) { cerr << "open " << YUV_FILE << " failed" << endl; return -1; } // 定义输出流 ofstream ofs; ofs.open(RGBA_FILE, ios::binary); if (!ofs) { cerr << "open " << RGBA_FILE << " failed" << endl; return -1; } SwsContext* yuv2rgb = nullptr; for (int i = 0; i < 10; i++) // 尝试转换10帧图像 { ifs.read((char*)yuv[0], yuv_width * yuv_height); // 读取Y ifs.read((char*)yuv[1], yuv_width * yuv_height /4); // 读取U ifs.read((char*)yuv[2], yuv_width * yuv_height / 4); // 读取V if (ifs.gcount() == 0) { break; } yuv2rgb = sws_getCachedContext(yuv2rgb, // 转换的上下文,NULL代表创建新创建上下文,非NULL会判断与现有参数是否一致,若不一致,则会删除现有参数,并重新创建上下文 yuv_width, yuv_height, // 输入视频的宽和高 AV_PIX_FMT_YUV420P, // 输入的像素格式 rgb_width, rgb_height, // 输出视频的宽和高 AV_PIX_FMT_RGBA, // 输出的像素格式 SWS_BILINEAR, // 选择尺寸变化的算法,这里我们选用双线性插值 0, 0, 0 // 过滤器参数,这里不指定 ); if (!yuv2rgb) { cerr << "sws_getCachedContext(yuv2rgb) failed" << endl; return -1; } // 输出的结果代表转换的高度 int re = sws_scale(yuv2rgb, yuv, // 输入的数据 yuv_linesize, // 输入数据的行字节数 0, // 输入数据的Y轴,这里没有 yuv_height, // 输入的高度 rgba, // 输出的数据 rgba_linesize // 输出的行大小 ); cout << re << " " << flush; ofs.write((char *)rgba[0], rgb_width * rgb_height * 4); } ifs.close(); ofs.close(); //====================================== RGBA 文件转 YUV 文件 =============================================== ifs.open(RGBA_FILE, ios::binary); if (!ifs) { cerr << "open " << RGBA_FILE << " failed" << endl; return -1; } SwsContext* rgb2yuv = nullptr; for (;;) { ifs.read((char *)rgba[0], rgb_width * rgb_height * 4); // 读取一帧RGBA数据 if (ifs.gcount() == 0) { break; } rgb2yuv = sws_getCachedContext(rgb2yuv, // 转换的上下文,NULL代表创建新创建上下文,非NULL会判断与现有参数是否一致,若不一致,则会删除现有参数,并重新创建上下文 rgb_width, rgb_height, // 输入视频的宽和高 AV_PIX_FMT_RGBA, // 输入的像素格式 yuv_width, yuv_height, // 输出视频的宽和高 AV_PIX_FMT_YUV420P, // 输出的像素格式 SWS_BILINEAR, // 选择尺寸变化的算法,这里我们选用双线性插值 0, 0, 0 // 过滤器参数,这里不指定 ); if (!rgb2yuv) { cerr << "sws_getCachedContext(rgb2yuv) failed" << endl; return -1; } // 输出的结果代表转换的高度 int re = sws_scale(rgb2yuv, rgba, // 输入的数据 rgba_linesize, // 输入数据的行字节数 0, // 输入数据的Y轴,这里没有 rgb_height, // 输入的高度 yuv, // 输出的数据 yuv_linesize // 输出的行大小 ); cout <<"("<< re <<") "<< flush; } delete yuv[0]; delete yuv[1]; delete yuv[2]; delete rgba[0]; return 0; }
运行结果:
另外分享一个YUV/RGB的播放器,用于播放转换完成后的YUV或RGB文件:
链接: https://pan.baidu.com/s/1sYjfCZLOTmhzXyG3gmn7ww 提取码: tcyw
软件界面如下:
可以直接拖动YUV文件到该播放器进行播放,但是需要选择对应的分辨率及像素格式:
分辨率:
输入该视频的分辨率:
像素格式:
一般指定完这两项后,点击下方的播放按钮就可以正常播放了。RGB文件类似。详情可参考雷神的博客:https://blog.csdn.net/leixiaohua1020/article/details/50466201