libswscale
里面实现了各种图像像素格式的转换。
主要函数如下:1
2
3
4
5
6//使用参数初始化SwsContext结构体
sws_getContext()
//转换一帧图像
sws_scale()
//释放SwsContext结构体
sws_freeContext()
初始化函数:
1 | //为SwsContext结构体分配内存 |
这种复杂的方法可以配置一些sws_getContext()
配置不了的参数。比如说设置图像的YUV
像素的取值范围是JPEG
标准(Y、U、V取值范围都是0-255)还是MPEG
标准(Y取值范围是16-235,U、V的取值范围是16-240)
获取像素格式信息:1
2
3
4//可以获得指定像素格式的AVPixFmtDescriptor结构体
av_pix_fmt_desc_get()
//通过AVPixFmtDescriptor获取值
av_get_bits_per_pixel() //获取比特数(bpp)
图像拉伸:
1 | SWS_BICUBIC性能比较好;SWS_FAST_BILINEAR在性能和速度之间有一个比好好的平衡。 |
示例将通过yuv
文件生成rgb
文件,代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
extern "C" {
}
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像素数据处理