【问题标题】:Convert individual pixel values from RGB to YUV420 and save the frame - C++将单个像素值从 RGB 转换为 YUV420 并保存帧 - C++
【发布时间】:2014-05-02 05:19:42
【问题描述】:

我一直在使用 FFmpeg 库进行 RGB->YUV420 转换。已经尝试过sws_scale 功能,但效果不佳。现在,我决定使用色彩空间转换公式单独转换每个像素。因此,以下是让我获得几帧并允许我访问每个像素的单个 R、G、B 值的代码:

// Read frames and save first five frames to disk
    i=0;
    while((av_read_frame(pFormatCtx, &packet)>=0) && (i<5)) 
    {
        // Is this a packet from the video stream?
        if(packet.stream_index==videoStreamIdx) 
        {   
            /// Decode video frame            
            avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);

            // Did we get a video frame?
            if(frameFinished) 
            {
                i++;
                sws_scale(img_convert_ctx, (const uint8_t * const *)pFrame->data,
                          pFrame->linesize, 0, pCodecCtx->height,
                          pFrameRGB->data, pFrameRGB->linesize);

                int x, y, R, G, B;
                uint8_t *p = pFrameRGB->data[0];
                for(y = 0; y < h; y++)
                {  
                    for(x = 0; x < w; x++) 
                    {
                        R = *p++;
                        G = *p++;
                        B = *p++;
                        printf(" %d-%d-%d ",R,G,B);
                    }
                }

                SaveFrame(pFrameRGB, pCodecCtx->width, pCodecCtx->height, i);
            }
        }

        // Free the packet that was allocated by av_read_frame
        av_free_packet(&packet);
    }

我读到online 说要转换 RGB->YUV420 或反之亦然,首先应转换为 YUV444 格式。所以,它就像:RGB->YUV444->YUV420。如何在 C++ 中实现它?

另外,这里是上面使用的SaveFrame() 函数。我想这也必须改变一点,因为 YUV420 以不同的方式存储数据。怎么处理?

void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame)
{
    FILE *pFile;
    char szFilename[32];
    int  y;

    // Open file
    sprintf(szFilename, "frame%d.ppm", iFrame);
    pFile=fopen(szFilename, "wb");
    if(pFile==NULL)
        return;

    // Write header
    fprintf(pFile, "P6\n%d %d\n255\n", width, height);

    // Write pixel data
    for(y=0; y<height; y++)
        fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, width*3, pFile);

    // Close file
    fclose(pFile);
}

有人可以建议吗?非常感谢!!!

【问题讨论】:

  • 为什么要重新发明轮子?您对 ffmpeg 功能有什么问题?因为它应该工作!
  • @alexbuisson 我试过了,但它会丢失颜色和比例信息。就是这样:stackoverflow.com/questions/21938674/…有人提出了解决方案,但出现的问题无法解决。
  • 即使你手动将平面转换为YUV444,你打算用什么来降低U/V平面的分辨率来实现YUV420?完成这项工作的最佳工具是……您猜对了 sws_scale!您的 RGB/YUV444 实现也会慢得多。您需要学习如何使用 sws_scale。此时您基本上是在向 stackoverflow 发送垃圾邮件。
  • @szatmary 我想我可以平均 U 和 V 通道的 2x2 块。这不会有帮助吗?关于 sws_scale,您确实为我提供了解决方案。但是,由于我在您提出的解决方案中遇到了错误,我对此提出了进一步的疑问,但没有得到回答。当错误消息与您的解决方案相关时,我不明白要提出什么新问题。它仍然张贴在那里...希望您能提供帮助...
  • 它会工作,但它并不理想。您也可以忽略 U/V 位置并编码黑白。那也会“工作”。你真的是在重新发明一个低级的轮子,以避免学习如何使用 sw_scale。

标签: c++ c ffmpeg video-encoding libavcodec


【解决方案1】:
void SaveFrameYUV420P(AVFrame *pFrame, int width, int height, int iFrame)
{
    FILE *pFile;
    char szFilename[32];
    int  y;

    // Open file
    sprintf(szFilename, "frame%d.yuv", iFrame);
    pFile=fopen(szFilename, "wb");
    if(pFile==NULL)
        return;

    // Write pixel data
    fwrite(pFrame->data[0], 1, width*height, pFile);
    fwrite(pFrame->data[1], 1, width*height/4, pFile);
    fwrite(pFrame->data[2], 1, width*height/4, pFile);

    // Close file
    fclose(pFile);
}

在 Windows 上,您可以使用 irfanview 查看以这种方式保存的帧。您以 RAW、24bpp 格式打开帧,提供宽度和高度,并选中“yuv420”框。

【讨论】:

    猜你喜欢
    • 2022-12-22
    • 2023-02-14
    • 2021-04-13
    • 2019-11-12
    • 2012-11-28
    • 2016-02-06
    • 2020-03-04
    • 2020-12-18
    • 2011-09-27
    相关资源
    最近更新 更多