sws_scale、YUV转RGB
sws_scale, YUV to RGB conversion
我需要将 YUV 转换为 RGB。我还需要 RGB 值在有限范围内 (16-235)。
我尝试使用 sws_scale 函数来完成这项任务。
我的代码你可以在下面看到。但是转换后我得到的黑色像素是 (0, 0, 0) 而不是 (16, 16, 16).
也许有一些选项可以告诉sws_scale函数计算有限的范围。
AVFrame* frameRGB = avFrameConvertPixelFormat(_decodedBuffer[i].pAVFrame, AV_PIX_FMT_RGB24);
AVFrame* Decoder::avFrameConvertPixelFormat(const AVFrame* src, AVPixelFormat dstFormat) {
int width = src->width;
int height = src->height;
AVFrame* dst = allocPicture(dstFormat, width, height);
SwsContext* conversion = sws_getContext(width,
height,
(AVPixelFormat)src->format,
width,
height,
dstFormat,
SWS_FAST_BILINEAR,
NULL,
NULL,
NULL);
sws_scale(conversion, src->data, src->linesize, 0, height, dst->data, dst->linesize);
sws_freeContext(conversion);
dst->format = dstFormat;
dst->width = src->width;
dst->height = src->height;
return dst;
}
我还尝试使用公式手动将 YUV 像素转换为 RGB 像素,我得到了正确的结果。从 YUV (16, 128, 128) 我得到 (16, 16, 16) in RGB.
cmpR = y + 1.402 * (v - 128);
cmpG = y - 0.3441 * (u - 128) - 0.7141 * (v - 128);
cmpB = y + 1.772 * (u - 128);
您可以将源格式设为“全尺寸”YUVJ。
据我所知,sws_scale 没有选择 Studio RGB 作为输出格式的选项。
更改输入格式是我能想到的最好的解决方案。
“JPEG: YUV -> RGB”的颜色转换formula与你post中的公式相同
源格式设置示例:
- 如果
src->format
是PIX_FMT_YUV420P
,设置格式为PIX_FMT_YUVJ420P
。
- 如果
src->format
是PIX_FMT_YUV422P
,设置格式为PIX_FMT_YUVJ422P
。
- 如果
src->format
是PIX_FMT_YUV444P
,设置格式为PIX_FMT_YUVJ444P
。
- 如果
PIX_FMT_YUV440P
,使用PIX_FMT_YUVJ440P
。
我知道解决方案并没有涵盖所有的可能性,可能会有一些输出像素超出[16, 235]的范围,所以这不是最通用的解决方案...
yuv to rgb conversion using FFMPEG 我看到上面已经给出了很多信息。然而,为了代码的完整性,我 re-sharing 缺少 allocPicture() 函数的代码,header 和要包含的库,它对我来说就像一个魅力。感谢@Валентин Никин 和@Rotem 提供大部分信息和代码。
Headers:
#include <libswscale/swscale.h>
Link FFMPEG 库:
libswscale
static AVFrame* allocPicture(enum AVPixelFormat pix_fmt, int width, int height)
{
// Allocate a frame
AVFrame* frame = av_frame_alloc();
if (frame == NULL)
{
fprintf(stderr, "avcodec_alloc_frame failed");
}
if (av_image_alloc(frame->data, frame->linesize, width, height, pix_fmt, 1) < 0)
{
fprintf(stderr, "av_image_alloc failed");
}
frame->width = width;
frame->height = height;
frame->format = pix_fmt;
return frame;
}
static AVFrame* avFrameConvertPixelFormat(const AVFrame* src, enum AVPixelFormat dstFormat)
{
int width = src->width;
int height = src->height;
AVFrame* dst = allocPicture(dstFormat, width, height);
struct SwsContext* conversion = sws_getContext(width,
height,
(enum AVPixelFormat)src->format,
width,
height,
dstFormat,
SWS_FAST_BILINEAR | SWS_FULL_CHR_H_INT | SWS_ACCURATE_RND,
NULL,
NULL,
NULL);
sws_scale(conversion, src->data, src->linesize, 0, height, dst->data, dst->linesize);
sws_freeContext(conversion);
dst->format = dstFormat;
dst->width = src->width;
dst->height = src->height;
return dst;
}
// convert yuv420p10le to rgb24 (or any other RGB formats)
AVFrame* frame = avFrameConvertPixelFormat(frame, AV_PIX_FMT_RGB24);
我需要将 YUV 转换为 RGB。我还需要 RGB 值在有限范围内 (16-235)。 我尝试使用 sws_scale 函数来完成这项任务。
我的代码你可以在下面看到。但是转换后我得到的黑色像素是 (0, 0, 0) 而不是 (16, 16, 16).
也许有一些选项可以告诉sws_scale函数计算有限的范围。
AVFrame* frameRGB = avFrameConvertPixelFormat(_decodedBuffer[i].pAVFrame, AV_PIX_FMT_RGB24);
AVFrame* Decoder::avFrameConvertPixelFormat(const AVFrame* src, AVPixelFormat dstFormat) {
int width = src->width;
int height = src->height;
AVFrame* dst = allocPicture(dstFormat, width, height);
SwsContext* conversion = sws_getContext(width,
height,
(AVPixelFormat)src->format,
width,
height,
dstFormat,
SWS_FAST_BILINEAR,
NULL,
NULL,
NULL);
sws_scale(conversion, src->data, src->linesize, 0, height, dst->data, dst->linesize);
sws_freeContext(conversion);
dst->format = dstFormat;
dst->width = src->width;
dst->height = src->height;
return dst;
}
我还尝试使用公式手动将 YUV 像素转换为 RGB 像素,我得到了正确的结果。从 YUV (16, 128, 128) 我得到 (16, 16, 16) in RGB.
cmpR = y + 1.402 * (v - 128);
cmpG = y - 0.3441 * (u - 128) - 0.7141 * (v - 128);
cmpB = y + 1.772 * (u - 128);
您可以将源格式设为“全尺寸”YUVJ。
据我所知,sws_scale 没有选择 Studio RGB 作为输出格式的选项。
更改输入格式是我能想到的最好的解决方案。
“JPEG: YUV -> RGB”的颜色转换formula与你post中的公式相同
源格式设置示例:
- 如果
src->format
是PIX_FMT_YUV420P
,设置格式为PIX_FMT_YUVJ420P
。 - 如果
src->format
是PIX_FMT_YUV422P
,设置格式为PIX_FMT_YUVJ422P
。 - 如果
src->format
是PIX_FMT_YUV444P
,设置格式为PIX_FMT_YUVJ444P
。 - 如果
PIX_FMT_YUV440P
,使用PIX_FMT_YUVJ440P
。
我知道解决方案并没有涵盖所有的可能性,可能会有一些输出像素超出[16, 235]的范围,所以这不是最通用的解决方案...
yuv to rgb conversion using FFMPEG 我看到上面已经给出了很多信息。然而,为了代码的完整性,我 re-sharing 缺少 allocPicture() 函数的代码,header 和要包含的库,它对我来说就像一个魅力。感谢@Валентин Никин 和@Rotem 提供大部分信息和代码。
Headers:
#include <libswscale/swscale.h>
Link FFMPEG 库:
libswscale
static AVFrame* allocPicture(enum AVPixelFormat pix_fmt, int width, int height)
{
// Allocate a frame
AVFrame* frame = av_frame_alloc();
if (frame == NULL)
{
fprintf(stderr, "avcodec_alloc_frame failed");
}
if (av_image_alloc(frame->data, frame->linesize, width, height, pix_fmt, 1) < 0)
{
fprintf(stderr, "av_image_alloc failed");
}
frame->width = width;
frame->height = height;
frame->format = pix_fmt;
return frame;
}
static AVFrame* avFrameConvertPixelFormat(const AVFrame* src, enum AVPixelFormat dstFormat)
{
int width = src->width;
int height = src->height;
AVFrame* dst = allocPicture(dstFormat, width, height);
struct SwsContext* conversion = sws_getContext(width,
height,
(enum AVPixelFormat)src->format,
width,
height,
dstFormat,
SWS_FAST_BILINEAR | SWS_FULL_CHR_H_INT | SWS_ACCURATE_RND,
NULL,
NULL,
NULL);
sws_scale(conversion, src->data, src->linesize, 0, height, dst->data, dst->linesize);
sws_freeContext(conversion);
dst->format = dstFormat;
dst->width = src->width;
dst->height = src->height;
return dst;
}
// convert yuv420p10le to rgb24 (or any other RGB formats)
AVFrame* frame = avFrameConvertPixelFormat(frame, AV_PIX_FMT_RGB24);