首页 > 其他分享 >像素格式转换

像素格式转换

时间:2023-12-15 16:59:12浏览次数:36  
标签:src convert 转换 int dst 像素 av 格式 data

使用ffmpeg,sws_scale接口做像素格式转换

参考雷神:https://blog.csdn.net/leixiaohua1020/article/details/42134965

** 主要功能:**

  • 转换像素格式

  • 转换后的数据填充到AVFrame中

#include <stdio.h>
#include <unistd.h>

#include <fstream>
#include <iostream>

/**
 * 最简单的基于FFmpeg的Swscale示例
 * Simplest FFmpeg Swscale
 *
 * 雷霄骅 Lei Xiaohua
 * [email protected]
 * 中国传媒大学/数字电视技术
 * Communication University of China / Digital TV Technology
 * http://blog.csdn.net/leixiaohua1020
 *
 * 本程序使用libswscale对像素数据进行缩放转换等处理。
 * 它中实现了YUV420P格式转换为RGB24格式,
 * 同时将分辨率从480x272拉伸为1280x720
 * 它是最简单的libswscale的教程。
 *
 * This software uses libswscale to scale / convert pixels.
 * It convert YUV420P format to RGB24 format,
 * and changes resolution from 480x272 to 1280x720.
 * It's the simplest tutorial about libswscale.
 */

#define __STDC_CONSTANT_MACROS

#ifdef _WIN32
//Windows
extern "C"
{
#include "libavutil/imgutils.h"
#include "libavutil/opt.h"
#include "libswscale/swscale.h"
};
#else
//Linux...
#ifdef __cplusplus
extern "C"
{
#endif
#include <libavutil/imgutils.h>
#include <libavutil/opt.h>
#include <libswscale/swscale.h>
#ifdef __cplusplus
};
#endif
#endif

int transfer(const char* infile, const char* outfile);

#pragma pack(push, 1) // 1字节对齐

// BMP文件头结构体
struct BMPFileHeader
{
    uint16_t type;      // 文件类型,必须为"BM"
    uint32_t size;      // 文件大小,单位为字节
    uint16_t reserved1; // 保留字段,必须为0
    uint16_t reserved2; // 保留字段,必须为0
    uint32_t offset;    // 像素数据起始位置,单位为字节
};

// BMP位图信息头结构体
struct BMPInfoHeader
{
    uint32_t size;            // 信息头大小,必须为40
    int32_t width;            // 图像宽度,单位为像素
    int32_t height;           // 图像高度,单位为像素
    uint16_t planes;          // 颜色平面数,必须为1
    uint16_t bit_count;       // 每个像素的位数,必须为24
    uint32_t compression;     // 压缩方式,必须为0
    uint32_t size_image;      // 像素数据大小,单位为字节
    int32_t x_pels_per_meter; // X方向像素数/米
    int32_t y_pels_per_meter; // Y方向像素数/米
    uint32_t clr_used;        // 使用的颜色数,必须为0
    uint32_t clr_important;   // 重要的颜色数,必须为0
};

#pragma pack(pop)

// 将RGB24格式像素数据封装为BMP图像
bool write_bmp(const char* filename, uint8_t* data, int32_t width, int32_t height)
{
    BMPFileHeader file_header = {0};
    BMPInfoHeader info_header = {0};
    std::ofstream ofs(filename, std::ios::binary);
    if (!ofs)
    {
        std::cerr << "Failed to create file: " << filename << std::endl;
        return false;
    }
    // BMP文件头
    file_header.type = 0x4D42; // BM
    file_header.size = sizeof(BMPFileHeader) + sizeof(BMPInfoHeader) + width * height * 3;
    file_header.offset = sizeof(BMPFileHeader) + sizeof(BMPInfoHeader);
    ofs.write(reinterpret_cast<char*>(&file_header), sizeof(file_header));
    // BMP位图信息头
    info_header.size = sizeof(BMPInfoHeader);
    info_header.width = width;
    info_header.height = height;
    info_header.planes = 1;
    info_header.bit_count = 24;
    info_header.size_image = width * height * 3;
    ofs.write(reinterpret_cast<char*>(&info_header), sizeof(info_header));
    // 像素数据
    int32_t row_size = ((width * 3 + 3) / 4) * 4; // 行字节数,必须为4的倍数
    uint8_t* row_data = new uint8_t[row_size];
    for (int32_t y = height - 1; y >= 0; --y)
    { // BMP图像的行是从下往上存储的
        for (int32_t x = 0; x < width; ++x)
        {
            row_data[x * 3 + 2] = data[(y * width + x) * 3 + 0]; // B
            row_data[x * 3 + 1] = data[(y * width + x) * 3 + 1]; // G
            row_data[x * 3 + 0] = data[(y * width + x) * 3 + 2]; // R
        }
        ofs.write(reinterpret_cast<char*>(row_data), row_size);
    }
    delete[] row_data;
    ofs.close();
    return true;
}

int transfer(const char* infile, const char* outfile)
{
    //Parameters
    FILE* src_file = fopen(infile, "rb");
    const int src_w = 1920, src_h = 1440;
    AVPixelFormat src_pixfmt = AV_PIX_FMT_YUYV422;
    //获取一个像素点占的大小,bit
    int src_bpp = av_get_bits_per_pixel(av_pix_fmt_desc_get(src_pixfmt));

    FILE* dst_file = fopen(outfile, "wb");
    const int dst_w = 1920, dst_h = 1440;
    AVPixelFormat dst_pixfmt = AV_PIX_FMT_YUV420P;
    int dst_bpp = av_get_bits_per_pixel(av_pix_fmt_desc_get(dst_pixfmt));

    //Structures
    uint8_t* src_data[4];
    int src_linesize[4];

    uint8_t* dst_data[4];
    int dst_linesize[4];

    int rescale_method = SWS_BICUBIC;
    struct SwsContext* img_convert_ctx;
    uint8_t* temp_buffer = (uint8_t*)malloc(src_w * src_h * src_bpp / 8);

    int frame_idx = 0;
    int ret = 0;
    ret = av_image_alloc(src_data, src_linesize, src_w, src_h, src_pixfmt, 1);
    if (ret < 0)
    {
        printf("Could not allocate source image\n");
        return -1;
    }
    ret = av_image_alloc(dst_data, dst_linesize, dst_w, dst_h, dst_pixfmt, 1);
    if (ret < 0)
    {
        printf("Could not allocate destination image\n");
        return -1;
    }
    //-----------------------------
    //Init Method 1
    // img_convert_ctx = sws_alloc_context();
    // //Show AVOption
    // av_opt_show2(img_convert_ctx, stdout, AV_OPT_FLAG_VIDEO_PARAM, 0);
    // //Set Value
    // av_opt_set_int(img_convert_ctx, "sws_flags", SWS_BICUBIC | SWS_PRINT_INFO, 0);
    // av_opt_set_int(img_convert_ctx, "srcw", src_w, 0);
    // av_opt_set_int(img_convert_ctx, "srch", src_h, 0);
    // av_opt_set_int(img_convert_ctx, "src_format", src_pixfmt, 0);
    // //'0' for MPEG (Y:0-235);'1' for JPEG (Y:0-255)
    // av_opt_set_int(img_convert_ctx, "src_range", 1, 0);
    // av_opt_set_int(img_convert_ctx, "dstw", dst_w, 0);
    // av_opt_set_int(img_convert_ctx, "dsth", dst_h, 0);
    // av_opt_set_int(img_convert_ctx, "dst_format", dst_pixfmt, 0);
    // av_opt_set_int(img_convert_ctx, "dst_range", 1, 0);
    // sws_init_context(img_convert_ctx, NULL, NULL);

    //Init Method 2
    img_convert_ctx = sws_getContext(src_w, src_h, src_pixfmt, dst_w, dst_h, dst_pixfmt,
                                     rescale_method, NULL, NULL, NULL);
    //-----------------------------
    /*
	//Colorspace
	ret=sws_setColorspaceDetails(img_convert_ctx,sws_getCoefficients(SWS_CS_ITU601),0,
		sws_getCoefficients(SWS_CS_ITU709),0,
		 0, 1 << 16, 1 << 16);
	if (ret==-1) {
		printf( "Colorspace not support.\n");
		return -1;
	}
	*/

    //填充
    AVFrame* frame = av_frame_alloc();
    frame->width = dst_w;
    frame->height = dst_h;
    frame->format = AV_PIX_FMT_YUV420P;
    //申请用于保存图像数据的内存,不用单独释放,在av_frame_free的时候会自动释放
    av_frame_get_buffer(frame, 1);

    while (1)
    {
        if (fread(temp_buffer, 1, src_w * src_h * src_bpp / 8, src_file) != src_w * src_h * src_bpp / 8)
        {
            break;
        }

        switch (src_pixfmt)
        {
        case AV_PIX_FMT_GRAY8:
        {
            memcpy(src_data[0], temp_buffer, src_w * src_h);
            break;
        }
        case AV_PIX_FMT_YUV420P:
        {
            memcpy(src_data[0], temp_buffer, src_w * src_h);                             //Y
            memcpy(src_data[1], temp_buffer + src_w * src_h, src_w * src_h / 4);         //U
            memcpy(src_data[2], temp_buffer + src_w * src_h * 5 / 4, src_w * src_h / 4); //V
            break;
        }
        case AV_PIX_FMT_YUV422P:
        {
            memcpy(src_data[0], temp_buffer, src_w * src_h);                             //Y
            memcpy(src_data[1], temp_buffer + src_w * src_h, src_w * src_h / 2);         //U
            memcpy(src_data[2], temp_buffer + src_w * src_h * 3 / 2, src_w * src_h / 2); //V
            break;
        }
        case AV_PIX_FMT_YUV444P:
        {
            memcpy(src_data[0], temp_buffer, src_w * src_h);                     //Y
            memcpy(src_data[1], temp_buffer + src_w * src_h, src_w * src_h);     //U
            memcpy(src_data[2], temp_buffer + src_w * src_h * 2, src_w * src_h); //V
            break;
        }
        case AV_PIX_FMT_YUYV422:
        {
            memcpy(src_data[0], temp_buffer, src_w * src_h * 2); //Packed
            break;
        }
        case AV_PIX_FMT_RGB24:
        {
            memcpy(src_data[0], temp_buffer, src_w * src_h * 3); //Packed
            break;
        }
        default:
        {
            printf("Not Support Input Pixel Format.\n");
            break;
        }
        }

        //sws_scale(img_convert_ctx, src_data, src_linesize, 0, src_h, dst_data, dst_linesize);
        sws_scale(img_convert_ctx, src_data, src_linesize, 0, src_h, frame->data, frame->linesize);
        printf("Finish process frame %5d\n", frame_idx);
        frame_idx++;

        // switch (dst_pixfmt)
        // {
        // case AV_PIX_FMT_GRAY8:
        // {
        //     fwrite(dst_data[0], 1, dst_w * dst_h, dst_file);
        //     break;
        // }
        // case AV_PIX_FMT_YUV420P:
        // {
        //     fwrite(dst_data[0], 1, dst_w * dst_h, dst_file);     //Y
        //     fwrite(dst_data[1], 1, dst_w * dst_h / 4, dst_file); //U
        //     fwrite(dst_data[2], 1, dst_w * dst_h / 4, dst_file); //V
        //     break;
        // }
        // case AV_PIX_FMT_YUV422P:
        // {
        //     fwrite(dst_data[0], 1, dst_w * dst_h, dst_file);     //Y
        //     fwrite(dst_data[1], 1, dst_w * dst_h / 2, dst_file); //U
        //     fwrite(dst_data[2], 1, dst_w * dst_h / 2, dst_file); //V
        //     break;
        // }
        // case AV_PIX_FMT_YUV444P:
        // {
        //     fwrite(dst_data[0], 1, dst_w * dst_h, dst_file); //Y
        //     fwrite(dst_data[1], 1, dst_w * dst_h, dst_file); //U
        //     fwrite(dst_data[2], 1, dst_w * dst_h, dst_file); //V
        //     break;
        // }
        // case AV_PIX_FMT_YUYV422:
        // {
        //     fwrite(dst_data[0], 1, dst_w * dst_h * 2, dst_file); //Packed
        //     break;
        // }
        // case AV_PIX_FMT_RGB24:
        // {
        //     fwrite(dst_data[0], 1, dst_w * dst_h * 3, dst_file); //Packed
        //     break;
        // }
        // default:
        // {
        //     printf("Not Support Output Pixel Format.\n");
        //     break;
        // }
        // }
    }

    sws_freeContext(img_convert_ctx);

    //释放
    av_frame_free(&frame);

    free(temp_buffer);
    fclose(dst_file);
    av_freep(&src_data[0]);
    av_freep(&dst_data[0]);

    return 0;
}

标签:src,convert,转换,int,dst,像素,av,格式,data
From: https://www.cnblogs.com/linxisuo/p/17903672.html

相关文章

  • 电脑跟服务器都能读取的u盘格式是什么
    U盘的三种格式1、FAT32格式:FAT32格式兼容性相对好一些,几乎可以应对所有主流的操作系统(比如Windows、MacOS、Linux等),并且可以快速读写。但它的缺点是不能设置权限,安全等级较低;而且这个格式下的U盘最高只能支持4G以下的单个文件传输。linux下使用命令将U盘格式为FAT32:2、NTFS......
  • MySQL往数据库插时间格式的数据时,只保存年月日,不保存时分秒。
     MySQL往数据库插时间格式的数据时,只保存年月日,不保存时分秒。今天在写项目时候,需要将数据insert到数据库中。但是,看到插入数据库中的时间只有年月日,没有时分秒。 查看实体类没毛病 查看xml文件也没有问题  timestamp和datetime区别: 最后经过排查发现问题......
  • 世微 AP9166 DC-DC同步降压恒压芯片 18V 2A同步降压转换器
     600KHz,18V,2A同步降压转换器概述AP9166是一款完全集成的效率2A同步整流降压转换器。AP9166运行在宽输出电流上以高效率负载范围。此设备提供两个操作模式、PWM控制和PFM模式切换控制,允许更宽范围的高效率负载AP9166至少需要现成标准的数量外部组件,在中可用符合SOT23-6标准的6针......
  • DAY 6 文件处理与编码转换
    一、Python文件操作对文件的操作有2种,文本文件、二进制文件(视频、图片等)1.1open方法基本使用open(file,mode='r',encoding=None);几种打开模式'r' openforreading(default)'w' openforwriting,truncatingthefilefirst(写模式,如果文件在,先清空【危险】)'x' creat......
  • Excel-设定格式化条件
    1.设定格式化选取想筛选的栏位所在列--功能区右上角“条件格式”--自行设定条件和突出显示样式栏位下方单元格新增突出显示的内容会自动填充显示样式2.更改/删除条件选取要更改的列--条件格式--管理规则--编辑规则--可重新指定条件删除条件--在管理规则內直接选取规则--点“—”......
  • 关于EthernetIP转ModbusTCP协议转换的成熟应用
    在现代工业自动化领域,以太网和互联网的集成已经成为一种趋势。Ethernet/IP转ModbusTCP网关作为一种关键的通信设备,能够实现以太网和ModbusTCP协议之间的转换,从而在工业自动化领域中发挥重要作用。本文将详细介绍Ethernet/IP转ModbusTCP网关的应用和配置方法。Ethernet/IP转Mo......
  • 实现XML与JSON转换,实测这个方法最便捷
    XML和JSON是当今最常用的两种数据格式,在数据交换和存储领域占有重要地位。XML以其树状结构和可扩展性被广泛使用,而JSON则以其轻量级和易读性受到开发者的青睐。有时候,为了更好地利用它们的优点解决数据共享、数据处理和数据存储等问题,我们需要将这两种格式进行转换。本文将介绍如......
  • C++学习笔记十一:数据类型的转换
    一个表达式里的所有变量应该具有相同的类型。上溢和下溢(overflowandunderflow):1.隐式转换(implicitly):编译器自动进行。总是把占用内存小的数据类型转化为占用大的数据类型。int类型转换为doubledoubleprice{45.6};intunits{10};autototal_price=price*un......
  • SpringBoot中项目启动及定时任务缓存数据库常用数据至内存变量并转换后高频调用
    场景定时任务中需要获取数据库中数据进行数据转换成需要的格式并进行后续的业务处理。数据库中的数据更新频率不高。可将数据库中数据在项目启动后读取一遍数据,然后再通过定时任务定时查询数据库更新数据。实现数据库缓存的方式有多种,比如以下:SpringBoot中通过自定义缓存注解......
  • 浅谈 JSON 对象和 FormData 相互转换
    前言大家都知道,前端在和后台进行交互联调时,肯定避免不了要传递参数,一般情况下,params在get请求中使用,而post请求下,我们有两种常见的传参方式:JSON对象格式和formData格式,但是一些场景是需要我们对这两种数据格式进行转换的,例如表单提交,有些是JSON对象格式的数据,有些是F......