【问题标题】:FFMpeg, libav, Problem with sws_scale and yuv to rgb conversion - colors are not correctFFMpeg、libav、sws_scale 和 yuv 到 rgb 转换的问题 - 颜色不正确
【发布时间】:2020-07-19 21:06:29
【问题描述】:

我一直在尝试在 Delphi 中创建自己的视频播放器,而 ffmpeg 效果很好,直到我遇到了色彩空间或颜色转换的障碍。

已经尝试了几天,但无法弄清楚。 我正在使用 AV_PIX_FMT_RGB48LE 作为输出...

旧上下文创建:

      videoConvContext := sws_getContext(AVStreamInit.codec.width, AVStreamInit.codec.height, AVStreamInit.codec.pix_fmt, AVStreamInit.codec.width, AVStreamInit.codec.height, AV_PIX_FMT_RGB48LE, SWS_POINT, nil, nil, nil);

新的上下文创建:

    dstRange := 1;
    srcRange := 1;
    if AVStreamInit.codec.color_range = AVCOL_RANGE_MPEG then
      srcRange := 0;

    videoConvContext := sws_alloc_context();

    av_opt_set_int(videoConvContext, 'sws_flags', SWS_POINT or SWS_PRINT_INFO, 0);

    av_opt_set_int(videoConvContext, 'srcw', AVStreamInit.codec.width, 0);
    av_opt_set_int(videoConvContext, 'srch', AVStreamInit.codec.height, 0);
    av_opt_set_int(videoConvContext, 'src_format', Integer(AVStreamInit.codec.pix_fmt), 0);

    av_opt_set_int(videoConvContext, 'dstw', AVStreamInit.codec.width, 0);
    av_opt_set_int(videoConvContext, 'dsth', AVStreamInit.codec.height, 0);
    av_opt_set_int(videoConvContext, 'dst_format', Integer(AV_PIX_FMT_RGB48LE), 0);

    i1 := sws_getCoefficients2(Integer(AVStreamInit.codec.colorspace));
    i2 := sws_getCoefficients2(SWS_CS_ITU709);

    ret := sws_setColorspaceDetails2(videoConvContext, i1, srcRange, i2, dstRange, 0, 1 shl 16, 1 shl 16);

    sws_init_context(videoConvContext, nil, nil);

结果完全一样......

sws_scale 的输出没有正确的颜色,这里有 2 个屏幕截图

好的 - 来自 mpc-hc

不好 - 从我的播放器通过 sws_scale (直接原始提取,所以没有完成颜色处理)

此视频有 pix_fmt AV_PIX_FMT_YUV420P10LE,但它发生在其他 YUV 输入上,但不是那么明显。同样在其他 RGB 输出(8 位等)... 此处 Netflix 徽标是纯红色的,但 sws_scale 输出呈橙色...

Sws_scale 代码仅供参考:

sws_scale(videoConvContext, @AVPacketBuffer.AVFrameCopy.Data, @AVPacketBuffer.AVFrameCopy.linesize, 0, AVStream.codec.height, @BitmapXBuffer.data, @linesize);

BitmapXBuffer.data 是一个大小正确的信号缓冲区...

AVFrameCopy - 是原始帧的副本:

  if Assigned(AVPacketBuffer.AVFrameCopy) then
      av_frame_free(@AVPacketBuffer.AVFrameCopy);

    AVPacketBuffer.AVFrameCopy := av_frame_alloc();
    AVPacketBuffer.AVFrameCopy.format := AVPacketBuffer.AVFrame.format;
    AVPacketBuffer.AVFrameCopy.width := AVPacketBuffer.AVFrame.width;
    AVPacketBuffer.AVFrameCopy.height := AVPacketBuffer.AVFrame.height;
    AVPacketBuffer.AVFrameCopy.channels := AVPacketBuffer.AVFrame.channels;
    AVPacketBuffer.AVFrameCopy.channel_layout := AVPacketBuffer.AVFrame.channel_layout;
    AVPacketBuffer.AVFrameCopy.nb_samples := AVPacketBuffer.AVFrame.nb_samples;
    av_frame_get_buffer(AVPacketBuffer.AVFrameCopy, 32);
    av_frame_copy(AVPacketBuffer.AVFrameCopy, AVPacketBuffer.AVFrame);
    av_frame_copy_props(AVPacketBuffer.AVFrameCopy, AVPacketBuffer.AVFrame);

谢谢!

【问题讨论】:

  • 从黑暗中拍摄(我正在处理类似的事情,但仍然不理解您的一半代码):也许两个颜色通道被切换了。您是否尝试过 AV_PIX_FMT_BGR48LE?但既然你什么都试过了,这可能不是正确的答案......
  • 抱歉,on 的 rgb 值在 bg 上总是像 fe0000, 0000,在坏的时候像 ce5000,我找不到 ligic :)
  • 也许你不应该碰色彩空间。
  • 这是我做的第一件事。结果相同。

标签: c delphi ffmpeg libav


【解决方案1】:

回答我自己的问题 - 上面的代码是正确的, 让我感到困惑的是 dst_table,但它仅在目标颜色空间为 YUV 时才相关。

Netflix 徽标也是橙色的,但不是正确的橙色。从 sRGB 转换为线性 RGB 为我解决了这个问题,但这只是我的情况。

所以,以上面的代码为例:D

【讨论】:

    猜你喜欢
    • 2021-05-28
    • 2018-02-19
    • 2012-08-02
    • 1970-01-01
    • 1970-01-01
    • 2017-04-21
    • 2021-07-10
    • 2012-08-25
    • 2021-11-25
    相关资源
    最近更新 更多