使用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