首页 > 其他分享 >如何使用libswscale库将YUV420P格式的图像序列转换为RGB24格式输出?

如何使用libswscale库将YUV420P格式的图像序列转换为RGB24格式输出?

时间:2023-07-04 10:22:25浏览次数:42  
标签:int32 dst RGB24 YUV420P input 格式 data frame result

一.视频格式转换初始化

  将视频中的图像帧按照一定比例缩放或指定宽高进行放大和缩小是视频编辑中最为常见的操作之一,这里我们将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

  

  

标签:int32,dst,RGB24,YUV420P,input,格式,data,frame,result
From: https://www.cnblogs.com/luqman/p/swscale.html

相关文章

  • 常见证书文件如何转成crt和key格式
    1常见证书文件*.DER或*.CER文件:该文件是二进制格式,它只含有证书信息,不包含私钥。*.CRT文件:该文件是二进制格式或文本格式,它也只含有证书信息,不包含私钥。*.PEM文件:该文件是文本格式,它一般存放证书或私钥,或同时包含证书和私钥。*.PEM文件如果只包含私钥,一般用*.KEY文件代替。*.PF......
  • 由Spine出现黑边说起纹理格式问题
    项目中的纹理一直使用的ETC2格式,以前主要是考虑到兼容性问题。最近在Spine使用PMA方案的时候出现了部分接缝位置黑边的情况,像下图这样: 怀疑了spine的导出,怀疑了shader,怀疑了材质的设置,最后发现是ETC2格式导致的问题。使用RGBA或者ASTC格式,显示正常了。附几张不同ASTC格式下的......
  • js格式化货币方法
    ......
  • input 上传图片 Base64 格式的 可预览
      <inputtype="file"@change="aas"name=""id="">   aas(e){//console.log(e.target.files)//leta=newFormData        letfile=e.target.files[0]        letreader=newFileReader......
  • django.db.models.query.QuerySet格式的数据输出
    1、deffindmtm2(request):importserializerimportjson#多对多跨表正向查询#res=softlist.objects.filter(hostlists__ip="10.116.6.177").values("softname")res2=softlist.objects.filter(hostlists__ip="10.116.9.233"......
  • notepad++如何快速格式化代码
     2023-03-25 4505 广东举报简介: notepad++如何快速格式化代码Notepad++可以使用插件来快速格式化代码,以下是一种使用插件进行代码格式化的方法:打开Notepad++编辑器,并打开需要格式化的代码文件。在菜单栏中选择“插件”->“PluginManager”->“ShowPluginManag......
  • 在Windows 11/10/8/7中将U盘快速格式化为FAT32的好方法
    链接:https://www.disktool.cn/content-center/how-to-format-pendrive-in-windows-7-666.html使用磁盘管理工具格式化U盘步骤1. 打开电脑,“Win+R”打开运行框。输入diskmgmt.msc再按Enter键打开磁盘管理工具。步骤2. 右键单击您想要格式化的U盘并选择“格式化”。步骤3. ......
  • JAVA生成xml文件格式
    publicboolean A(参数1,……){Documentdocument=DocumentHelper.createDocument();Namespacena=Namespace.get("");Strings=null;na=new Namespace(xxxxxxxxxxxxxxxxxxxxx);//命名空间Elementroot=document.addElement(newQName(“A......
  • js 数字格式化,只能输入正负整数,小数
     1、只能输入正整数<inputname="columnValue"class="input96required"type="text"size="50"onkeyup="if(this.value.length==1){this.value=this.value.replace(/[^1-9]/g,'')}else{this.value=this.value.replac......
  • 获取系统时间在java中怎么操作,还可以指定格式
    ​ 要在Java中获取当前时间并将其格式化为指定形式,可以使用java.time包中的LocalDateTime和DateTimeFormatter类。下面是一个示例代码,演示如何获取系统时间并将其格式化为指定的字符串格式: importjava.time.LocalDateTime;importjava.time.format.DateTimeFormatter;p......