ffmpeg如何高效解码视频帧?
ffmpeg how to efficiently decode the video frame?
这是我用来在工作线程中解码 rtsp 流的代码:
while(1)
{
// Read a frame
if(av_read_frame(pFormatCtx, &packet)<0)
break; // Frame read failed (e.g. end of stream)
if(packet.stream_index==videoStream)
{
// Is this a packet from the video stream -> decode video frame
int frameFinished;
avcodec_decode_video2(pCodecCtx,pFrame,&frameFinished,&packet);
// Did we get a video frame?
if (frameFinished)
{
if (LastFrameOk == false)
{
LastFrameOk = true;
}
// Convert the image format (init the context the first time)
int w = pCodecCtx->width;
int h = pCodecCtx->height;
img_convert_ctx = ffmpeg::sws_getCachedContext(img_convert_ctx, w, h, pCodecCtx->pix_fmt, w, h, ffmpeg::PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);
if (img_convert_ctx == NULL)
{
printf("Cannot initialize the conversion context!\n");
return false;
}
ffmpeg::sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);
// Convert the frame to QImage
LastFrame = QImage(w, h, QImage::Format_RGB888);
for (int y = 0; y < h; y++)
memcpy(LastFrame.scanLine(y), pFrameRGB->data[0] + y*pFrameRGB->linesize[0], w * 3);
LastFrameOk = true;
} // frameFinished
} // stream_index==videoStream
av_free_packet(&packet); // Free the packet that was allocated by av_read_frame
}
我按照ffmpeg的教程使用了while循环来读取数据包并解码视频。
但是有没有更有效的方法来做到这一点,比如收到数据包时的事件触发函数?
我还没有看到任何事件驱动的方法来读取帧,但是读取 RTSP 流的目的是什么?但是我可以给出一些提高性能的建议。首先,您可以在循环中添加一个非常短的睡眠(例如 Sleep(1);)。在您的程序中,如果您的目的是:
向用户显示图像:不使用转RGB,解码后的结果帧为YUV420P格式,可以直接使用GPU显示给用户,无需任何CPU 用法。几乎所有的显卡都支持 YUV420P(或 YV12)格式。转换为 RGB 是一项非常耗费 CPU 的操作,尤其是对于大图像。
Record (save) to disk: 我想录流稍后播放,不需要解码帧。您可以使用 OpenRTSP 直接录制到磁盘而无需任何 CPU 使用。
处理实时图像:您可能会找到替代算法来处理 YUV420P 格式而不是 RGB。 YUV420P中的Y平面实际上是彩色RGB图像的灰度版本。
这是我用来在工作线程中解码 rtsp 流的代码:
while(1)
{
// Read a frame
if(av_read_frame(pFormatCtx, &packet)<0)
break; // Frame read failed (e.g. end of stream)
if(packet.stream_index==videoStream)
{
// Is this a packet from the video stream -> decode video frame
int frameFinished;
avcodec_decode_video2(pCodecCtx,pFrame,&frameFinished,&packet);
// Did we get a video frame?
if (frameFinished)
{
if (LastFrameOk == false)
{
LastFrameOk = true;
}
// Convert the image format (init the context the first time)
int w = pCodecCtx->width;
int h = pCodecCtx->height;
img_convert_ctx = ffmpeg::sws_getCachedContext(img_convert_ctx, w, h, pCodecCtx->pix_fmt, w, h, ffmpeg::PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);
if (img_convert_ctx == NULL)
{
printf("Cannot initialize the conversion context!\n");
return false;
}
ffmpeg::sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);
// Convert the frame to QImage
LastFrame = QImage(w, h, QImage::Format_RGB888);
for (int y = 0; y < h; y++)
memcpy(LastFrame.scanLine(y), pFrameRGB->data[0] + y*pFrameRGB->linesize[0], w * 3);
LastFrameOk = true;
} // frameFinished
} // stream_index==videoStream
av_free_packet(&packet); // Free the packet that was allocated by av_read_frame
}
我按照ffmpeg的教程使用了while循环来读取数据包并解码视频。 但是有没有更有效的方法来做到这一点,比如收到数据包时的事件触发函数?
我还没有看到任何事件驱动的方法来读取帧,但是读取 RTSP 流的目的是什么?但是我可以给出一些提高性能的建议。首先,您可以在循环中添加一个非常短的睡眠(例如 Sleep(1);)。在您的程序中,如果您的目的是:
向用户显示图像:不使用转RGB,解码后的结果帧为YUV420P格式,可以直接使用GPU显示给用户,无需任何CPU 用法。几乎所有的显卡都支持 YUV420P(或 YV12)格式。转换为 RGB 是一项非常耗费 CPU 的操作,尤其是对于大图像。
Record (save) to disk: 我想录流稍后播放,不需要解码帧。您可以使用 OpenRTSP 直接录制到磁盘而无需任何 CPU 使用。
处理实时图像:您可能会找到替代算法来处理 YUV420P 格式而不是 RGB。 YUV420P中的Y平面实际上是彩色RGB图像的灰度版本。