我试图在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.