以下答案显示了如何使用sws_scale将 ARGB 转换为 YUV420p。
您必须进行一些调整以将转换集成到您的代码中。
代码示例是“独立”的 sws_scale 示例,它不使用 CAIRO。
使用 FFmpeg(命令行工具)创建 BGRA 输入样本:
ffmpeg -y -f lavfi -i testsrc=size=192x108:rate=1 -vcodec rawvideo -pix_fmt argb -frames 1 -f rawvideo argb_image.bin
以下代码示例应用以下阶段:
- 从二进制文件中读取 ARGB(样本)输入。
- 从存储 YUV420p 输出中分配内存缓冲区。
- 获取 SWS 上下文。
- 应用颜色转换。
- 将 YUV420p 输出图像写入二进制文件(用于测试)。
- 释放分配的内存。
C++ 代码示例:
#include <stdio.h>
#include <string.h>
#include <stdint.h>
extern "C"
{
#include <libswscale/swscale.h>
#include <libavutil/imgutils.h>
}
int main()
{
//Use FFmpeg for building raw ARGB image (used as input).
//ffmpeg -y -f lavfi -i testsrc=size=192x108:rate=1 -vcodec rawvideo -pix_fmt argb -frames 1 -f rawvideo argb_image.bin
const int width = 192;
const int height = 108;
unsigned char* argb_in = new uint8_t[width * height * 4]; //Allocate 4 bytes per pixel (applies ARGB)
const enum AVPixelFormat out_pix_fmt = AV_PIX_FMT_YUV420P;
//Read input image for binary file (for testing)
////////////////////////////////////////////////////////////////////////////
FILE* f = fopen("argb_image.bin", "rb"); //For using fopen in Visual Studio, define: _CRT_SECURE_NO_WARNINGS (or use fopen_s).
fread(argb_in, 1, width * height * 4, f);
fclose(f);
////////////////////////////////////////////////////////////////////////////
//Allocate output buffers:
////////////////////////////////////////////////////////////////////////////
// YUV420p data is separated in three planes
// 1. Y - intensity plane, resolution: width x height
// 2. U - Color plane, resolution: width/2 x height/2
// 3. V - Color plane, resolution: width/2 x height/2
int out_linesize[4] = {0, 0, 0, 0};
uint8_t* out_planes[4] = { nullptr, nullptr, nullptr, nullptr };
int sts = av_image_alloc(out_planes, //uint8_t * pointers[4],
out_linesize, //int linesizes[4],
width, //int w,
height, //int h,
out_pix_fmt, //enum AVPixelFormat pix_fmt,
32); //int align); //Align to 32 bytes address may result faster execution time compared to 1 byte aligenment.
if (sts < 0)
{
printf("Error: av_image_alloc response = %d\n", sts);
return -1;
}
////////////////////////////////////////////////////////////////////////////
//Get SWS context
////////////////////////////////////////////////////////////////////////////
struct SwsContext* sws_context = nullptr;
sws_context = sws_getCachedContext(sws_context, //struct SwsContext *context,
width, //int srcW,
height, //int srcH,
AV_PIX_FMT_ARGB, //enum AVPixelFormat srcFormat,
width, //int dstW,
height, //int dstH,
out_pix_fmt, //enum AVPixelFormat dstFormat,
SWS_BILINEAR, //int flags,
nullptr, //SwsFilter *srcFilter,
nullptr, //SwsFilter *dstFilter,
nullptr); //const double *param);
if (sws_context == nullptr)
{
printf("Error: sws_getCachedContext returned nullptr\n");
return -1;
}
////////////////////////////////////////////////////////////////////////////
//Apply color conversion
////////////////////////////////////////////////////////////////////////////
const int in_linesize[1] = { 4 * width }; // ARGB stride (4 bytes per pixel - assume data is continuous).
const uint8_t* in_planes[1] = { argb_in };
int response = sws_scale(sws_context, //struct SwsContext *c,
in_planes, //const uint8_t *const srcSlice[],
in_linesize, //const int srcStride[],
0, //int srcSliceY,
height, //int srcSliceH,
out_planes, //uint8_t *const dst[],
out_linesize); //const int dstStride[]);
if (response < 0)
{
printf("Error: sws_scale response = %d\n", response);
return -1;
}
////////////////////////////////////////////////////////////////////////////
//Write YUV420p output image to binary file (for testing)
//You may execute FFmpeg after conversion for testing the output:
//ffmpeg -y -f rawvideo -s 192x108 -pixel_format yuv420p -i yuv420p_image.bin rgb.png
////////////////////////////////////////////////////////////////////////////
f = fopen("yuv420p_image.bin", "wb");
fwrite(out_planes[0], 1, width * height, f);
fwrite(out_planes[1], 1, width * height / 4, f);
fwrite(out_planes[2], 1, width * height / 4, f);
fclose(f);
////////////////////////////////////////////////////////////////////////////
//Free allocated memory
////////////////////////////////////////////////////////////////////////////
av_freep(out_planes);
sws_freeContext(sws_context);
delete[] argb_in;
////////////////////////////////////////////////////////////////////////////
return 0;
}
为了测试输出,yuv420p_image.bin
使用 FFmpeg 转换为 PNG 图像:
ffmpeg -y -f rawvideo -s 192x108 -pixel_format yuv420p -i yuv420p_image.bin rgb.png
rgb.png
(FFmpeg转换的结果):