libswscale
里面实现了各种图像像素格式的转换。
主要函数如下:
//使用参数初始化SwsContext结构体
sws_getContext()
//转换一帧图像
sws_scale()
//释放SwsContext结构体
sws_freeContext()
初始化函数:
//为SwsContext结构体分配内存
sws_alloc_context()
//设置SwsContext结构体的值
av_opt_set()/av_opt_set_XXX()
//初始化SwsContext结构体。
sws_init_context()
这种复杂的方法可以配置一些sws_getContext()
配置不了的参数。比如说设置图像的YUV
像素的取值范围是JPEG
标准(Y、U、V取值范围都是0-255)还是MPEG
标准(Y取值范围是16-235,U、V的取值范围是16-240)
获取像素格式信息:
//可以获得指定像素格式的AVPixFmtDescriptor结构体
av_pix_fmt_desc_get()
//通过AVPixFmtDescriptor获取值
av_get_bits_per_pixel() //获取比特数(bpp)
图像拉伸:
SWS_BICUBIC性能比较好;SWS_FAST_BILINEAR在性能和速度之间有一个比好好的平衡。
示例将通过yuv
文件生成rgb
文件,代码如下:
#include "stdafx.h"
extern "C" {
#include <libswscale/swscale.h>
#include <libavutil/opt.h>
#include <libavutil/imgutils.h>
}
void p(const char * msg, int d = -1123) {
if (d == -1123) {
printf_s("%s\n", msg);
}
else {
printf_s("%s %d \n", msg, d);
}
}
int yuv2Rgb(FILE *yuvFile,FILE * rgbFile) {
SwsContext *img_convert_ctx = NULL;
const AVPixelFormat srcPixelFormat = AV_PIX_FMT_YUV420P;
const AVPixelFormat dstPixelFormat = AV_PIX_FMT_RGB24;
const int srcW = 1080;
const int srcH= 720;
const int dstW = 540;
const int dstH = 360;
uint8_t *src_data[4];
int src_linesize[4];
uint8_t *dst_data[4];
int dst_linesize[4];
//1. 获得指定像素格式的AVPixFmtDescriptor结构体
const AVPixFmtDescriptor * pSrcPixFmtDes = av_pix_fmt_desc_get(srcPixelFormat);
//2. 获得指定像素格式每个像素占用的比特数bpp(Bit Per Pixel)
int srcBpp= av_get_bits_per_pixel(pSrcPixFmtDes);
const AVPixFmtDescriptor * pDstPixFmtDes = av_pix_fmt_desc_get(dstPixelFormat);
int dstBpp = av_get_bits_per_pixel(pDstPixFmtDes);
//3. 根据宽高,像素格式分配buffer大小
if (av_image_alloc(src_data, src_linesize, srcW, srcH, srcPixelFormat, 1) < 0) {
p("Could not allocate source image");
return -1;
}
if (av_image_alloc(dst_data, dst_linesize, dstW, dstH, dstPixelFormat, 1) < 0) {
p("Could not allocate source image");
return -1;
}
//4. 为SwsContext结构体分配内存。
img_convert_ctx = sws_alloc_context();
//Show AVOption
av_opt_show2(img_convert_ctx, stdout, AV_OPT_FLAG_VIDEO_PARAM, 0);
//图像拉伸 SWS_BICUBIC性能比较好;SWS_FAST_BILINEAR在性能和速度之间有一个比好好的平衡。
//const int rescale_method = SWS_BICUBIC;
//5. 设置值
av_opt_set_int(img_convert_ctx, "sws_flags", SWS_BICUBIC | SWS_PRINT_INFO, 0);
av_opt_set_int(img_convert_ctx, "srcw", srcW, 0);
av_opt_set_int(img_convert_ctx, "srch", srcH, 0);
av_opt_set_int(img_convert_ctx, "src_format", srcPixelFormat, 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", dstW, 0);
av_opt_set_int(img_convert_ctx, "dsth", dstH, 0);
av_opt_set_int(img_convert_ctx, "dst_format", dstPixelFormat, 0);
av_opt_set_int(img_convert_ctx, "dst_range", 1, 0);
sws_init_context(img_convert_ctx, NULL, NULL);//对SwsContext中的各种变量进行赋值
uint8_t *temp_buffer = (uint8_t *)malloc(srcW *srcH *srcBpp / 8);
int frame_idx = 0;
while (1){
if (fread(temp_buffer, 1, srcW*srcH*srcBpp / 8, yuvFile) != srcW * srcH*srcBpp / 8) {
break;
}
switch (srcPixelFormat) {
case AV_PIX_FMT_GRAY8: {
memcpy(src_data[0], temp_buffer, srcW*srcH);
break;
}
case AV_PIX_FMT_YUV420P: {
memcpy(src_data[0], temp_buffer, srcW*srcH); //Y
memcpy(src_data[1], temp_buffer + srcW * srcH, srcW*srcH / 4); //U
memcpy(src_data[2], temp_buffer + srcW * srcH * 5 / 4, srcW*srcH / 4); //V
break;
}
case AV_PIX_FMT_YUV422P: {
memcpy(src_data[0], temp_buffer, srcW*srcH); //Y
memcpy(src_data[1], temp_buffer + srcW * srcH, srcW*srcH / 2); //U
memcpy(src_data[2], temp_buffer + srcW * srcH * 3 / 2, srcW*srcH / 2); //V
break;
}
case AV_PIX_FMT_YUV444P: {
memcpy(src_data[0], temp_buffer, srcW*srcH); //Y
memcpy(src_data[1], temp_buffer + srcW * srcH, srcW*srcH); //U
memcpy(src_data[2], temp_buffer + srcW * srcH * 2, srcW*srcH); //V
break;
}
case AV_PIX_FMT_YUYV422: {
memcpy(src_data[0], temp_buffer, srcW*srcH * 2); //Packed
break;
}
case AV_PIX_FMT_RGB24: {
memcpy(src_data[0], temp_buffer, srcW*srcH * 3); //Packed
break;
}
default: {
printf("Not Support Input Pixel Format.\n");
break;
}
}
sws_scale(img_convert_ctx, src_data, src_linesize, 0, srcH, dst_data, dst_linesize);//转换像素
printf("Finish process frame %5d\n", frame_idx);
frame_idx++;
switch (dstPixelFormat) {
case AV_PIX_FMT_GRAY8: {
fwrite(dst_data[0], 1, dstW*dstH, rgbFile);
break;
}
case AV_PIX_FMT_YUV420P: {
fwrite(dst_data[0], 1, dstW*dstH, rgbFile); //Y
fwrite(dst_data[1], 1, dstW*dstH / 4, rgbFile); //U
fwrite(dst_data[2], 1, dstW*dstH / 4, rgbFile); //V
break;
}
case AV_PIX_FMT_YUV422P: {
fwrite(dst_data[0], 1, dstW*dstH, rgbFile); //Y
fwrite(dst_data[1], 1, dstW*dstH / 2, rgbFile); //U
fwrite(dst_data[2], 1, dstW*dstH / 2, rgbFile); //V
break;
}
case AV_PIX_FMT_YUV444P: {
fwrite(dst_data[0], 1, dstW*dstH, rgbFile); //Y
fwrite(dst_data[1], 1, dstW*dstH, rgbFile); //U
fwrite(dst_data[2], 1, dstW*dstH, rgbFile); //V
break;
}
case AV_PIX_FMT_YUYV422: {
fwrite(dst_data[0], 1, dstW*dstH * 2, rgbFile); //Packed
break;
}
case AV_PIX_FMT_RGB24: {
fwrite(dst_data[0], 1, dstW*dstH * 3, rgbFile); //Packed
break;
}
default: {
p("Not Support Output Pixel Format.\n");
break;
}
}
}
sws_freeContext(img_convert_ctx);
free(temp_buffer);
av_freep(&src_data[0]);
av_freep(&dst_data[0]);
return 0;
}
int main() {
FILE* inFile;
FILE* outFile;
fopen_s(&inFile,"F:/视频资源/gxsp.yuv", "rb");
fopen_s(&outFile, "F:/视频资源/gxsp.rgb", "wb");
yuv2Rgb(inFile,outFile);
fclose(inFile);
fclose(outFile);
getchar();
return 0;
}
参考链接: libswscale实现YUV转RGB
相关格式转换: 视音频数据处理入门:RGB、YUV像素数据处理