微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

ffmpeg:RGB到YUV转换失去颜色和比例

我试图在ffmpeg / libav中将RGB帧转换为YUV420P格式.以下是转换代码以及转换前后的图像.转换后的图像会丢失所有颜色信息,并且尺度也会发生显着变化.有谁知道如何处理这个?我是ffmpeg / libav的新手!
// Did we get a video frame?
   if(frameFinished)
   {
       i++;
       sws_scale(img_convert_ctx,(const uint8_t * const *)pFrame->data,pFrame->linesize,pCodecCtx->height,pFrameRGB->data,pFrameRGB->linesize);                   

       //==============================================================
       AVFrame *pFrameYUV = avcodec_alloc_frame();
       // Determine required buffer size and allocate buffer
       int numBytes2 = avpicture_get_size(PIX_FMT_RGB24,pCodecCtx->width,pCodecCtx->height);
       uint8_t *buffer = (uint8_t *)av_malloc(numBytes2*sizeof(uint8_t));

       avpicture_fill((AVPicture *)pFrameYUV,buffer,PIX_FMT_RGB24,pCodecCtx->height);


       rgb_to_yuv_ctx = sws_getContext(pCodecCtx->width,SWS_BICUBIC,NULL,NULL);

       sws_scale(rgb_to_yuv_ctx,pFrameRGB->linesize,pFrameYUV->data,pFrameYUV->linesize);

       sws_freeContext(rgb_to_yuv_ctx);

       SaveFrame(pFrameYUV,i);

       av_free(buffer);
       av_free(pFrameYUV);
   }

解决方法

对初学者来说,我会假设你拥有的地方:
rgb_to_yuv_ctx = sws_getContext(pCodecCtx->width,NULL);

你真的打算:

rgb_to_yuv_ctx = sws_getContext(pCodecCtx->width,PIX_FMT_YUV420P,NULL);

我也不确定你为什么两次打电话给swscale!

YUV是一种平面格式.这意味着所有三个通道都是独立存储的. RGB的存储方式如下:
RGBRGBRGB

YUV420P是这样的商店:
YYYYYYYYYYYYYYYY..UUUUUUUUUU..VVVVVVVV

所以swscale要求你给它三个指针.

接下来,您希望您的行间距为16或32的倍数,因此可以使用处理器的向量单位.最后,Y平面的尺寸需要被2整除(因为U和V平面是Y平面的四分之一尺寸).

所以,让我们改写一下:

#define RNDTO2(X) ( ( (X) & 0xFFFFFFFE )
#define RNDTO32(X) ( ( (X) % 32 ) ? ( ( (X) + 32 ) & 0xFFFFFFE0 ) : (X) )




if(frameFinished)
{
    static SwsContext *swsCtx = NULL;
    int width    = RNDTO2 ( pCodecCtx->width );
    int height   = RNDTO2 ( pCodecCtx->height );
    int ystride  = RNDTO32 ( width );
    int uvstride = RNDTO32 ( width / 2 );
    int ysize    = ystride * height;
    int vusize   = uvstride * ( height / 2 );
    int size     = ysize + ( 2 * vusize )

    void * pFrameYUV = malloc( size );
    void *plane[] = { pFrameYUV,pFrameYUV + ysize,pFrameYUV + ysize + vusize,0 };
    int *stride[] = { ystride,vustride,0 };

    swsCtx = sws_getCachedContext ( swsCtx,pCodecCtx->pixfmt,width,height,AV_PIX_FMT_YUV420P,SWS_lanczos | SWS_ACCURATE_RND,NULL );
    sws_scale ( swsCtx,pFrameRGB->height,plane,stride );
}

我还将您的算法切换为使用SWS_lanczos | SWS_ACCURATE_RND.这将为您提供更好看的图像.如果它要慢,请改回来.我还使用了源帧中的像素格式,而不是一直假设RGB.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。