最近接手公司的新任务:实现yuv420与RGB24色彩之间的相互转换,网上有很多现成代码,但是不知道怎么验证其准确性,后来从网上找到了yuv格式的播放神器:YUV Player Deluxe,下载地址为"http://www.yuvplayer.com/", 显示效果如下:
yuv播放器找到了,但是怎么制造一张内容为yuv格式的图片呢?答案是使用神器ffmpeg,下载ffmpeg工具,执行:
" ffmpeg -i a.jpg -s 640x480 -pix_fmt yuv420p a.yuv "
如上图所示,完成转换,此时可以在当前目录下生成a.yuv文件,将其拖入YUV Player Deluxe播放器即可得到第一张图片的效果,此处需要注意的是在转换时一定要将输出文件的大小设置成与原文件一样大小,否则ffmpeg会进行拉伸,导致转换后的图片与原图片显示差别较大。
最重要的是如何使用代码完成yuv420p与RGB24转换呢?
bool my_pixel_format_convert(unsigned char *pdata_src, int src_width, int src_height, AVPixelFormat src_pixfmt,
unsigned char *pdata_dst, int dst_size, AVPixelFormat dst_pixfmt)
{
const int src_w = src_width, src_h = src_height;
const int dst_w = src_width, dst_h = src_height;
AVFrame* srcFrame; //编码前数据,如yuv420,rgb24等
AVFrame* dstFrame; //编码前数据,如yuv420,rgb24等
struct SwsContext *img_convert_ctx;
img_convert_ctx = sws_alloc_context();
//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);
srcFrame = av_frame_alloc();
if (NULL != srcFrame)
{
srcFrame->width = src_w;
srcFrame->height = src_h;
srcFrame->format = AV_PIX_FMT_YUV420P;
}
if (av_frame_get_buffer(srcFrame, 1) < 0)
{
printf("get media buff failure.\n");
return false;
}
av_image_fill_arrays(srcFrame->data, srcFrame->linesize, pdata_src, AV_PIX_FMT_YUV420P, srcFrame->width, srcFrame->height, 1);
dstFrame = av_frame_alloc();
if (NULL != dstFrame)
{
dstFrame->width = src_w;
dstFrame->height = src_h;
dstFrame->format = AV_PIX_FMT_RGB24;
}
//获取存储媒体数据空间
if (av_frame_get_buffer(dstFrame, 1) < 0)
{
printf("get media buff failure.\n");
return false;
}
//do transform
sws_scale(img_convert_ctx, srcFrame->data, srcFrame->linesize, 0, dstFrame->height, dstFrame->data, dstFrame->linesize);
av_image_copy_to_buffer(pdata_dst, dst_size, dstFrame->data, dstFrame->linesize, AV_PIX_FMT_RGB24, dstFrame->width, dstFrame->height, 1);
av_frame_free(&srcFrame);
av_frame_free(&dstFrame);
sws_freeContext(img_convert_ctx);
return true;
}
YUV存储格式分成三大类:
packed:将Y、U、V分量交织存放在一起,和RGB的存放方式类似。内存中排列形式类似:YVYUYVYUYVYUYVYU...。在具体的存储模式命名中,packed格式不带后缀P。
planar:将Y、U、V的三个分量分别存放在不同的矩阵(平面)中。内存中排列形式类似:YYYYYY...,UUUUUU...,VVVVVV...。在具体的存储模式命名中,planar格式带后缀P。
semi-planar:将Y、U、V三个分量放在两个矩阵(平面)中。Y占用一个平面,UV共用一个平面。内存中排列形式类似:YYYYYY...,UVUVUV...。在具体的存储模式命名中,semi-planar格式带后缀SP。
参考:https://www.cnblogs.com/leisure_chn/p/10290575.html