【发布时间】: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