转化前准备
视频、图片格式介绍
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
| #define YUV_FILE "400_300_25.yuv" #define RGBA_FILE "800_600_25.rgba"
int width = 400, height = 300;
int rgb_width = 800, rgb_height = 600;
unsigned char *yuv[3] = { 0 }; int yuv_linesize[3] = { width, width / 2, width / 2 }; yuv[0] = new unsigned char[width * height]; yuv[1] = new unsigned char[width * height / 4]; yuv[2] = new unsigned char[width * height / 4];
unsigned char *rgba = new unsigned char[rgb_width * rgb_height * 4]; int rgba_linesize = rgb_width * 4;
ifstream ifs; ifs.open(YUV_FILE, ios::binary);
ofstream ofs; ofs.open(RGBA_FILE, ios::binary);
SwsContext *yuvTorgb = nullptr;
|
SwsContext *yuvTorgb = nullptr;
SwsContext
是 FFmpeg 中 libswscale 库的一部分。libswscale 是一个用于图像缩放和像素格式转换的库。
SwsContext
保存了图像转换操作的上下文信息,包括输入输出格式、大小、缩放选项等。
YUV转RGBA
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
| for (;;) { ifs.read((char*)yuv[0], width * height); ifs.read((char*)yuv[1], width * height / 4); ifs.read((char*)yuv[2], width * height / 4);
if (ifs.gcount() == 0) break;
yuvTorgb = sws_getCachedContext( yuvTorgb, width, height, AV_PIX_FMT_YUV420P, rgb_width, rgb_height, AV_PIX_FMT_RGBA, SWS_BILINEAR, 0, 0, 0 );
if (!yuvTorgb) { cerr << "sws_getCachedContext failed!" << endl; return 1; }
unsigned char* data[1]; data[0] = rgba; int lines[1] = { rgba_linesize };
int re = sws_scale( yuvTorgb, yuv, yuv_linesize, 0, height, data, lines ); std::cout << re << " " << flush;
ofs.write((char*)rgba, rgb_width * rgb_height * 4); }
ifs.close(); ofs.close();
|
【重要函数】
sws_getCachedContext
sws_getCachedContext
是一个非常有用的函数,可以简化和优化图像缩放和格式转换过程中的上下文管理。它允许你在不同的参数设置之间动态调整 SwsContext
,而无需手动管理内存,同时提供了对图像缩放算法的灵活选择。
函数原型
1 2 3 4 5 6 7
| struct SwsContext *sws_getCachedContext( struct SwsContext *context, int srcW, int srcH, enum AVPixelFormat srcFormat, int dstW, int dstH, enum AVPixelFormat dstFormat, int flags, SwsFilter *srcFilter, SwsFilter *dstFilter, const double *param );
|
参数解释
- context: 之前创建的 SwsContext 上下文指针。如果是 NULL,函数会创建一个新的上下文。
- srcW: 源图像的宽度。
- srcH: 源图像的高度。
- srcFormat: 源图像的像素格式(如 AV_PIX_FMT_YUV420P 等)。
- dstW: 目标图像的宽度。
- dstH: 目标图像的高度。
- dstFormat: 目标图像的像素格式。
- flags: 用于指定缩放和转换的算法,比如 SWS_BILINEAR(双线性插值)或 SWS_BICUBIC(三次插值)等。
- srcFilter: 源图像的过滤器,通常可以是 NULL。
- dstFilter: 目标图像的过滤器,通常可以是 NULL。
- param: 一个指向双精度浮点数组的指针,用于设置特定的缩放参数,可以为 NULL。
1 2 3 4 5 6 7 8 9 10
| yuvTorgb = sws_getCachedContext( yuvTorgb, width, height, AV_PIX_FMT_YUV420P, rgb_width, rgb_height, AV_PIX_FMT_RGBA, SWS_BILINEAR, 0, 0, 0 );
|
sws_scale
sws_scale
是 FFmpeg 中 libswscale
库的核心函数之一,用于执行图像缩放和像素格式转换操作。它利用 SwsContext
上下文中的配置信息,将源图像数据转换为目标图像数据。
函数原型
1 2 3 4 5 6 7 8 9
| int sws_scale( struct SwsContext *c, const uint8_t *const srcSlice[], const int srcStride[], int srcSliceY, int srcSliceH, uint8_t *const dst[], const int dstStride[] );
|
参数解释
- c:
- 类型:
struct SwsContext *
- 说明: 这是一个指向
SwsContext
的指针,用于图像缩放和色彩空间转换。SwsContext
包含了图像处理所需的所有参数和状态信息。可以使用 sws_getCachedContext
或 sws_getContext
来创建这个上下文。
- srcSlice:
- 类型:
const uint8_t *const srcSlice[]
- 说明: 源图像数据的数组,每个元素都是一个指向源图像某个平面的指针(例如,对于 YUV420P 格式,指向 Y、U 和 V 平面)。对于平面图像格式,数组的每个元素对应一个色彩分量(如 Y、U、V);对于非平面格式(如 RGB),通常只使用数组的第一个元素指向整个图像数据。
- srcStride:
- 类型:
const int srcStride[]
- 说明: 源图像每一行的字节数的数组,表示每个平面(或通道)在每行的步幅(字节数)。步幅是指相邻行在内存中相距的字节数。对于 YUV420P 图像,
srcStride[0]
通常是图像宽度,srcStride[1]
和 srcStride[2]
是色度平面的宽度(通常是亮度平面宽度的一半)。
- srcSliceY:
- 类型:
int
- 说明: 源图像的起始行的 Y 坐标,表示从图像的哪一行开始处理。通常情况下,值为 0 表示从图像的第一行开始。
- srcSliceH:
- 类型:
int
- 说明: 要处理的源图像的行数。这决定了
sws_scale
函数在源图像中从 srcSliceY
开始读取多少行进行缩放和转换。
- dst:
- 类型:
uint8_t *const dst[]
- 说明: 目标图像数据的数组,每个元素是一个指向目标图像某个平面的指针。类似于
srcSlice
,对于平面图像格式,数组的每个元素对应一个色彩分量(例如 RGB 格式只有一个平面);对于非平面格式,通常只使用数组的第一个元素指向整个图像数据。
- dstStride:
- 类型:
const int dstStride[]
- 说明: 目标图像每一行的字节数的数组,表示每个平面(或通道)在每行的步幅(字节数)。这个值决定了写入目标图像时每行数据在内存中占据的字节数。通常情况下,对于 RGB 图像,
dstStride[0]
是图像的宽度乘以 3(因为 RGB 每个像素占用 3 个字节)。
1 2 3 4 5 6 7 8 9
| int re = sws_scale( yuvTorgb, yuv, yuv_linesize, 0, height, data, lines );
|
两者关系
-
sws_getCachedContext
是 sws_scale
的准备步骤。你必须先使用 sws_getCachedContext
获取一个 SwsContext
,然后才能使用这个上下文来调用 sws_scale
进行图像转换。
-
sws_getCachedContext
确保你得到一个正确配置的 SwsContext
,其中包含了源图像和目标图像的所有必要信息(如尺寸、格式、缩放算法等)。
-
sws_scale
使用 sws_getCachedContext
创建或获取的 SwsContext
进行具体的转换操作。
RGBA转YUV
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
| ifs.open(RGBA_FILE, ios::binary); ofs.open(YUV_FILE, ios::binary); SwsContext *rgbToyuv = nullptr; for (;;) { ifs.read((char*)rgba, rgb_width * rgb_height * 4);
if (ifs.gcount() == 0) break;
rgbToyuv = sws_getCachedContext( rgbToyuv, rgb_width, rgb_height, AV_PIX_FMT_RGBA, width, height, AV_PIX_FMT_YUV420P, SWS_BILINEAR, 0, 0, 0 );
if (!rgbToyuv) { cerr << "sws_getCachedContext failed!" << endl; return 1; }
unsigned char*data[1]; data[0] = rgba; int lines[1] = { rgba_linesize }; int re = sws_scale( rgbToyuv, data, lines, 0, rgb_height, yuv, yuv_linesize ); std::cout << "(re)" << flush;
ofs.write((char*)yuv[0], width * height); ofs.write((char*)yuv[1], width * height / 4); ofs.write((char*)yuv[2], width * height / 4); }
|
清理内存数据
1 2 3 4 5 6
| delete yuv[0]; delete yuv[1]; delete yuv[2]; delete rgba; ifs.close(); ofs.close();
|