如何使用libswscale库将YUV420P格式的图像序列转换为RGB24格式输出?
一.视频格式转换初始化
将视频中的图像帧按照一定比例缩放或指定宽高进行放大和缩小是视频编辑中最为常见的操作之一,这里我们将1920x1080的yuv图像序列转换成640x480的rgb图像序列,并输出到文件。视频图像转换的核心为一个SwsContext结构,其中保存了输入图像和输出图像的宽高以及像素格式等多种参数。我们通过调用sws_getContext()函数就可以十分方便地创建并获取SwsContext结构的实例。下面给出初始化的代码:
//video_swscale_core.cpp
static AVFrame *input_frame= nullptr;
static struct SwsContext *sws_ctx;
static int32_t src_width=0,src_height=0,dst_width=0,dst_height=0;
static enum AVPixelFormat src_pix_fmt=AV_PIX_FMT_NONE,dst_pix_fmt=AV_PIX_FMT_NONE;
int32_t init_video_swscale(const char *src_size,const char *src_fmt,const char *dst_size,const char *dst_fmt){
int32_t result=0;
result=av_parse_video_size(&src_width,&src_height,src_size);
if(result<0){
cerr<<"Error:av_parse_video_size failed."<<endl;
return -1;
}
result= av_parse_video_size(&dst_width,&dst_height,dst_size);
if(result<0){
cerr<<"Error:av_parse_video_size failed."<<endl;
return -1;
}
//选择输入视频和输出视频的图像格式
if(!strcasecmp(src_fmt,"YUV420P")){
src_pix_fmt=AV_PIX_FMT_YUV420P;
}
else if(!strcasecmp(src_fmt,"RGB24")){
src_pix_fmt=AV_PIX_FMT_RGB24;
}
else{
cerr<<"Error:Unsupported input pixel format."<<endl;
return -1;
}
if(!strcasecmp(dst_fmt,"YUV420P")){
dst_pix_fmt=AV_PIX_FMT_YUV420P;
}
else if(!strcasecmp(dst_fmt,"RGB24")){
dst_pix_fmt=AV_PIX_FMT_RGB24;
}
else{
cerr<<"Error:Unsupported output pixel format."<<endl;
return -1;
}
//获取SwsContext结构
sws_ctx=sws_getContext(src_width,src_height,src_pix_fmt,dst_width,dst_height,dst_pix_fmt,SWS_BILINEAR, nullptr,
nullptr, nullptr);
if(!sws_ctx){
cerr<<"Error:failed to get SwsContext."<<endl;
return -1;
}
//初始化AVFrame结构
result= init_frame(src_width,src_height,src_pix_fmt);
if(result<0){
cerr<<"Error:init_frame failed."<<endl;
return -1;
}
return 0;
}
初始化保存输入视频的AVFrame结构,并分配内存空间:
//video_swscale_core.cpp
static int32_t init_frame(int32_t width,int32_t height,enum AVPixelFormat pix_fmt){
int result=0;
input_frame=av_frame_alloc();
if(!input_frame){
cerr<<"Error:av_frame_alloc failed."<<endl;
return -1;
}
input_frame->width=width;
input_frame->height=height;
input_frame->format=pix_fmt;
result= av_frame_get_buffer(input_frame,0);
if(result<0){
cerr<<"Error:av_frame_get_buffer failed."<<endl;
return -1;
}
result= av_frame_make_writable(input_frame);
if(result<0){
cerr<<"Error:av_frame_make_writable failed."<<endl;
return -1;
}
return 0;
}
二.视频图像帧的循环转换
视频格式转换的核心函数是sws_scale(),我们需要给出输出图像的缓存地址和缓存宽度,然后循环处理即可。下面给出代码:
//video_swscale_core.cpp
int32_t transforming(int32_t frame_cnt){
int32_t result=0;
uint8_t *dst_data[4];
int32_t dst_linesize[4]={0},dst_bufsize=0;
result= av_image_alloc(dst_data,dst_linesize,dst_width,dst_height,dst_pix_fmt,1);
if(result<0){
cerr<<"Error:av_image_alloc failed."<<endl;
return -1;
}
dst_bufsize=result;
for(int i=0;i<frame_cnt;i++){
result= read_yuv_to_frame(input_frame);
if(result<0){
cerr<<"Error:read_yuv_to_frame failed."<<endl;
return -1;
}
sws_scale(sws_ctx,input_frame->data,input_frame->linesize,0,src_height,dst_data,dst_linesize);
//write_packed_data_to_file(dst_data[0],dst_bufsize);
write_packed_data_to_file2(dst_data[0],dst_linesize[0],dst_width,dst_height);
}
av_freep(&dst_data[0]);
return 0;
}
三.将转换后的图像帧写入输出文件
这里需要注意的是,由于我们转换后的图像格式是rgb24,是按packed方式存储的,也就是红绿蓝三个通道交错地存储在一个平面内,在内存中是连续存储的。也就是说,转换后的图像数据全部保存在dst_data[0]指向的内存空间中。下面给出代码:
//io_data.cpp
int32_t write_packed_data_to_file2(uint8_t *data,int32_t linesize,int32_t width,int32_t height){
for(int i=0;i<height;i++){
fwrite(data+i*linesize,1,width*3,output_file);
}
}
四.释放资源
void destroy_video_swscale(){
av_frame_free(&input_frame);
sws_freeContext(sws_ctx);
}
还有其他的文件打开和关闭以及将yuv图像读到AVFrame结构中的代码请看我之前的博客。
五.main函数实现
int main(){
int result=0;
const char *input_file_name="../input.yuv";
const char *input_pic_size="1920x1080";
const char *input_pix_fmt="YUV420P";
const char *output_file_name="../output.rgb";
const char *output_pic_size="640x480";
const char *output_pix_fmt="RGB24";
result= open_input_output_files(input_file_name,output_file_name);
if(result<0){
return -1;
}
result=init_video_swscale(input_pic_size,input_pix_fmt,output_pic_size,output_pix_fmt);
if(result<0){
return -1;
}
result=transforming(250);
if(result<0){
return -1;
}
destroy_video_swscale();
close_input_output_files();
return 0;
}
最后,可以用以下指令测试输出的output.rgb文件:
ffplay -f rawvideo -video_size 640x480 -pixel_format rgb24 -i output.rgb
如何使用libswscale库将YUV420P格式的图像序列转换为RGB24格式输出?的更多相关文章
- 优酷1080p的kux格式文件怎么转换为MP4格式?
直接使用优酷自己的FFMPEG解码! 格式为:"优酷ffmpeg.exe的安装地址" -y -i ".kux文件储存地址" -c:v copy -c:a cop ...
- JS如何将CST格式的日期转换为制定格式String
<html> <body> <script type="text/javascript"> var d = new Date() dateFor ...
- 将对象格式的style转换为字符串格式
var style = { position:'absolute', background:'red', width:'2px', height:'2px', color:'#fff', top:x, ...
- java 调用OpenOffice将word格式文件转换为pdf格式
一:环境搭建 OpenOffice 下载地址http://www.openoffice.org/ JodConverter 下载地址http://sourceforge.net/projects/jo ...
- Excel表格文本格式的数字和数字格式如何批量转换
Excel表格文本格式的数字和数字格式如何批量转换 在使用Excel表格对数据求和时,只能对单元格内常规格式的数据进行计算,而不能对单元格中的文本格式的数据进行计算,特点就是在单元格的左上角有一个绿色 ...
- 利用kindlegen实现txt格式小说转换为mobi格式小说(C++实现)
一直以来喜欢在kindle上看小说,kindle不伤眼,也可以帮助控制玩手机的时间.但在kindle上看txt格式的网络小说就很头疼了,这类小说在kindle上是没有目录的,而且篇幅巨长.所以一直以来 ...
- 如何将EDI报文转换为CSV格式文件?
如果您对EDI项目实施有一定的了解,想必您一定知道,在正式开始EDI项目实施之前,都会有EDI顾问与您接洽,沟通EDI项目需求.其中,会包含EDI通信双方使用哪种传输协议,传输的报文是符合什么标准的, ...
- web字体格式及几种在线格式转换工具介绍
原文地址:http://blog.csdn.net/xiaolongtotop/article/details/8316554 目前,文字信息仍是网站最主要的内容,随着CSS3技术的不断成熟,Web字 ...
- 使用Javascript/jQuery将javascript对象转换为json格式数据 - 海涛的CSDN博客 - 博客频道 - CSDN.NET
body{ font-family: "Microsoft YaHei UI","Microsoft YaHei",SimSun,"Segoe UI& ...
- (转) at&T语法格式 与 at&T - intel格式对比
原地址 示例: movl (%ebp), %eax, 等同于Intel格式中的 ] ,AT&T中,源操作数在左,目的操作数在右.“l”是Longword,相当于Intel格式中的dword p ...
随机推荐
- Centos 7安装Elasticsearch 7.6
Centos 7安装Elasticsearch 7.6 Elasticsearch与JDK版本对应关系 在安装 Elasticsearch 时,要注意 Elasticsearch 与 JDK 的版本对 ...
- Looper 源码分析
//可以看到我们的Looper是存放在线程独有的ThreadLocal进行隔离的 //也就是每个线程独有一份Looper static final ThreadLocal<Loope ...
- 搭建CTF动态靶场
前言 本文借鉴文章:https://www.yuque.com/dengfenglai-esbap/kb/mc4k41?#xOxNG 在此基础上修改了一点(照着原来的做没成功),感谢这位师傅给的资源. ...
- Mysql中如果建立了索引,索引所占的空间随着数据量增长而变大,这样无论写入还是查询,性能都会有所下降,怎么处理?
索引所占空间的增长确实会对MySQL数据库的写入性能和查询性能造成影响,这主要是由于索引数据过多时会导致磁盘I/O操作变得非常频繁,从而使性能下降.为此,可以采取以下几种方式来减缓这种影响: 1. 限 ...
- [C++提高编程] 3.4 案例-评委打分
文章目录 3.4 案例-评委打分 3.4.1 案例描述 3.4.2 实现步骤 3.4 案例-评委打分 3.4.1 案例描述 有5名选手:选手ABCDE,10个评委分别对每一名选手打分,去除最高分,去除 ...
- 2023-01-14:给定一个二维数组map,代表一个餐厅,其中只有0、1两种值 map[i][j] == 0 表示(i,j)位置是空座 map[i][j] == 1 表示(i,j)位置坐了人 根据防
2023-01-14:给定一个二维数组map,代表一个餐厅,其中只有0.1两种值 map[i][j] == 0 表示(i,j)位置是空座 map[i][j] == 1 表示(i,j)位置坐了人 根据防 ...
- vue全家桶进阶之路29:Element Plus
Element Plus是一个用于Vue.js的UI组件库,为开发人员提供了一组可重用和可定制化的组件,用于构建现代Web应用程序.它是流行的Element UI库的扩展,重点是提高性能和可访问性. ...
- 40% building 31/38 modules 7 active ...es\core-js\modules\es6.object.assign.jsBrowserslist: caniuse-lite is outdated.
一早运行项目发现不正常 虽然能运行,但是怎么看都不顺眼啊,那就照着提示先: npm update 一连串下来啥也看不懂是不是 我就直接npm install看看重新下载一下依赖结果直接给我来了个 :c ...
- pupstudy的使用
打开环境 点击管理--打开根目录 把靶场放在www文件夹里 网页打开127.0.0.1/靶场文件名即可
- UCOS II 源码分析一
再进行ucos操作系统源码分析前,先对ucos源码文件结构说个简单说明,只有掌握了源码文件结构才能在接下来的源码分析中逐渐感受到会当凌绝顶, 一览众山小,最后的感受就是RTOS也不是很神秘!下面以正点 ...