AVFrame到QImage的高效转换

S B*_*S B 6 qt ffmpeg

我需要在基于Qt的应用程序中从视频中提取帧.使用ffmpeg库我能够将帧作为AVFrames获取,我需要将其转换为QImage以在我的应用程序的其他部分中使用.这种转换需要高效.到目前为止似乎sws_scale()是正确的功能使用,但我不确定要指定什么源和目标像素格式.

S B*_*S B 5

得出以下两步过程,首先在RGB颜色空间中将解码转换AVFame为另一个AVFrame,然后转换为QImage.它的工作原理相当快.

src_frame = get_decoded_frame();

AVFrame *pFrameRGB = avcodec_alloc_frame(); // intermediate pframe
if(pFrameRGB==NULL) {
    ;// Handle error
}

int numBytes= avpicture_get_size(PIX_FMT_RGB24,
      is->video_st->codec->width, is->video_st->codec->height);
uint8_t *buffer = (uint8_t*)malloc(numBytes);

avpicture_fill((AVPicture*)pFrameRGB, buffer, PIX_FMT_RGB24,
              is->video_st->codec->width, is->video_st->codec->height);

int dst_fmt = PIX_FMT_RGB24;
int dst_w = is->video_st->codec->width;
int dst_h = is->video_st->codec->height;

// TODO: cache following conversion context for speedup,
//       and recalculate only on dimension changes
SwsContext *img_convert_ctx_temp;
img_convert_ctx_temp = sws_getContext(
is->video_st->codec->width, is->video_st->codec->height,
is->video_st->codec->pix_fmt,
dst_w, dst_h, (PixelFormat)dst_fmt,
SWS_BICUBIC, NULL, NULL, NULL);


QImage *myImage = new QImage(dst_w, dst_h, QImage::Format_RGB32);

sws_scale(img_convert_ctx_temp,
          src_frame->data, src_frame->linesize, 0, is->video_st->codec->height,
          pFrameRGB->data,
          pFrameRGB->linesize);

uint8_t *src = (uint8_t *)(pFrameRGB->data[0]);
for (int y = 0; y < dst_h; y++)
{
    QRgb *scanLine = (QRgb *) myImage->scanLine(y);
    for (int x = 0; x < dst_w; x=x+1)
    {
        scanLine[x] = qRgb(src[3*x], src[3*x+1], src[3*x+2]);
    }
    src += pFrameRGB->linesize[0];
}
Run Code Online (Sandbox Code Playgroud)

如果您找到更有效的方法,请在评论中告诉我


kop*_*ich 4

我知道,为时已晚,但也许有人会发现它有用。从这里我得到了进行相同转换的线索,它看起来有点短。

所以我创建了 QImage ,它可被每个解码帧重用:

QImage img( width, height, QImage::Format_RGB888 );
Run Code Online (Sandbox Code Playgroud)

创建的帧RGB:

frameRGB = av_frame_alloc();    
//Allocate memory for the pixels of a picture and setup the AVPicture fields for it.
avpicture_alloc( ( AVPicture *) frameRGB, AV_PIX_FMT_RGB24, width, height);
Run Code Online (Sandbox Code Playgroud)

第一帧解码后,我以这种方式创建转换上下文 SwsContext (它将用于所有下一帧):

mImgConvertCtx = sws_getContext( codecContext->width, codecContext->height, codecContext->pix_fmt, width, height, AV_PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);
Run Code Online (Sandbox Code Playgroud)

最后对每个解码帧执行转换:

if( 1 == framesFinished && nullptr != imgConvertCtx )
{
//conversion frame to frameRGB
sws_scale(imgConvertCtx, frame->data, frame->linesize, 0, codecContext->height, frameRGB->data, frameRGB->linesize);
//setting QImage from frameRGB
for( int y = 0; y < height; ++y )
   memcpy( img.scanLine(y), frameRGB->data[0]+y * frameRGB->linesize[0], mWidth * 3 );
}
Run Code Online (Sandbox Code Playgroud)

具体内容请参见链接。