所以,基本上,我正在使用c ++中的FFmpeg lib渲染视频。可以使用哪种优化技术来渲染快速帧,以便在视频渲染中获得更好的o / p?
// app data structure
typedef struct {
AVFormatContext *fmt_ctx;
int stream_idx;
AVRational time_base;
AVStream *video_stream;
AVCodecContext *codec_ctx;
AVCodecContext *pCodecCtxOrig;
AVCodec *decoder;
AVPacket *packet;
AVFrame *av_frame;
AVFrame *gl_frame;
AVStream *pStream;
struct SwsContext *conv_ctx;
} AppData;
if (!data->conv_ctx) {
data->conv_ctx = sws_getContext(data->codec_ctx->width,
data->codec_ctx->height, data->codec_ctx->pix_fmt,
data->codec_ctx->width, data->codec_ctx->height,
AV_PIX_FMT_RGB0,
SWS_FAST_BILINEAR, NULL, NULL, NULL);
}
if (!data->conv_ctx) {
printf("Couldn't initialize sw scaler\n");
return false;
}
sws_scale(data->conv_ctx, data->av_frame->data, data->av_frame->linesize, 0,
data->codec_ctx->height, data->gl_frame->data, data->gl_frame->linesize);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, data->codec_ctx->width,
data->codec_ctx->height, GL_RGBA, GL_UNSIGNED_BYTE,
data->gl_frame->data[0]);
此功能正在映射视频帧,对我来说映射视频帧的效率相当低。如何避免在sws_scale和OpenGL中映射视频帧?
代替调用sws_scale
,您可以在将帧绘制到目标位置时将数据上传到纹理并在片段着色器中进行颜色转换。由于codec_ctx->pix_fmt
可能会遇到许多不同的格式,因此您需要手动支持许多不同的转换。对于平面格式,例如YUV420,可能需要在每个平面上创建单独的纹理。
[进一步改进,如果FFMPEG在GPU上解码,则可以通过在FFMPEG后端和OpenGL之间使用适当的互操作来避免GPU-> CPU-> GPU数据往返。参见How to convert an ffmpeg texture to Open GL texture without copying to CPU memory。不用说,由于后端的多样性,它很复杂。