2013年11月28日星期四

转换QImage到FFmpeg的internal YUV format

今天正巧有时间,在家里修改并整理一下我3年前写的视频播放和储存代码。FFmpeg更新非常快,突然发现我还在使用2011年09月23日的FFmpeg版本。最新版本已经到了2.1.1(http://ffmpeg.zeranoe.com/builds/win32/dev/),刚刚下载了,试着编译以前写的代码,发现很多API都变了,无法编译了,懒得再进行调整了,放弃使用新版本了,新的特性暂时用不到。我将2011年09月23日的FFmpeg版本作为项目的标准lib,打包上传到服务器上,还有SVN里。

刚刚在修改“转换QImage到FFmpeg的internal YUV format的方法”,这个方法是从QtFFmpegWrapper项目抄来的,https://code.google.com/p/qtffmpegwrapper/。我发现,我刚刚写的新代码中使用的是QImage::Format_RGB888,如果直接使用这个方法转换的frame就会不正确,是黑白的而且尺寸也不对,想了一下,其实只需要将ffmpeg::sws_getCachedContext这个API里的Source PixelFormat 改成PIX_FMT_RGB24就行了,简单而言只要注意将QImage的PixelFormat和AVFrame的PixelFormat正确对应就行了,具体代码如下面所示。

void convertImage_sws(const QImage &img)
{
   // Check if the image matches the size
   if(img.width() != getWidth() || img.height() != getHeight())
   {
      printf("Wrong image size!\n");
      return false;
   }
   if(img.format() != QImage::Format_RGB32 && img.format() != QImage::Format_ARGB32 && img.format() != QImage::Format_RGB888)    
   {
      printf("Wrong image format\n");
      return false;
   }

   //img_convert_ctx = ffmpeg::sws_getCachedContext(img_convert_ctx, getWidth(), getHeight(),
      // ffmpeg::PIX_FMT_BGRA, getWidth(),getHeight(), ffmpeg::PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);

   img_convert_ctx = ffmpeg::sws_getCachedContext(img_convert_ctx, getWidth(), getHeight(),  ffmpeg::PIX_FMT_RGB24,  getWidth(), getHeight(), ffmpeg::PIX_FMT_YUV420P,  SWS_BICUBIC,  NULL,  NULL,  NULL);

   if (img_convert_ctx == NULL)
   {
      printf("Cannot initialize the conversion context\n");
      return false;
   }

   uint8_t *srcplanes[3];
   srcplanes[0] = (uint8_t*)img.bits();
   srcplanes[1] = 0;
   srcplanes[2] = 0;

   int srcstride[3];
   srcstride[0] = img.bytesPerLine();
   srcstride[1] = 0;
   srcstride[2] = 0;

   ffmpeg::sws_scale(img_convert_ctx, srcplanes, srcstride, 0, getHeight(), ppicture->data, ppicture->linesize);

   return true;
}

没有评论: