将视频直接解码为单独线程中的纹理

时间:2017-07-18 05:30:39

标签: ffmpeg opengl-es gpu mpv

是否可以使用ffmpeg功能将视频异步解码到纹理中?我需要将视频输出到几何体上。

mpv个视频播放器,它可以直接将视频输出到帧缓冲区并使用其他接近金属的功能,但是是否有简约的例子,适用于嵌入式设备(OpenGL ES 2.0或3.0)?

如果纹理在整个帧时间内不会留下GPU内存,那就太好了。

1 个答案:

答案 0 :(得分:1)

我目前使用sws_scale修剪mpegts流帧的边缘,因为某些帧在解码时使用的边缘将有16或甚至32个额外像素。对于大多数用途而言,这不是必需的。相反,我用它来直接复制到我自己的缓冲区。

ff->scale_context = sws_getContext(wid, hgt, ff->vid_ctx->pix_fmt,  // usually YUV420
                               wid, hgt, AV_PIX_FMT_YUV420P,        // trim edges and copy
                               SWS_FAST_BILINEAR, NULL, NULL, NULL);

// setup my buffer to copy the frame into

uint8_t *data[] = { vframe->yframe, vframe->uframe, vframe->vframe };
int linesize[4] = { vid_ctx->width, vid_ctx->width / 2, vid_ctx->width / 2, 0 };

int ret = sws_scale(scale_context,
          (const uint8_t **)frame->data, frame->linesize,
          0, vid_ctx->height,
          data, linesize);

如果帧是另一种格式,您需要调整。

使用openGL ES的GPU着色器可节省大量开销:

// YUV shader (converts YUV planes to RGB on the fly)

static char vertexYUV[] = "attribute vec4 qt_Vertex; \
attribute vec2 qt_InUVCoords; \
varying vec2 qt_TexCoord0; \
 \
void main(void) \
{ \
    gl_Position = qt_Vertex; \
    gl_Position.z = 0.0;\
    qt_TexCoord0 = qt_InUVCoords; \
} \
";

static char fragmentYUV[] = "precision mediump float; \
uniform sampler2D qt_TextureY; \
uniform sampler2D qt_TextureU; \
uniform sampler2D qt_TextureV; \
varying vec2 qt_TexCoord0; \
void main(void) \
{ \
    float y = texture2D(qt_TextureY, qt_TexCoord0).r; \
    float u = texture2D(qt_TextureU, qt_TexCoord0).r - 0.5; \
    float v = texture2D(qt_TextureV, qt_TexCoord0).r - 0.5; \
    gl_FragColor = vec4( y + 1.403 * v, \
                         y - 0.344 * u - 0.714 * v, \
                         y + 1.770 * u, 1.0); \
}";

如果使用NV12格式而不是YUV420,那么UV帧是交错的,您只需使用" r,g"来获取值。或" x,y"你曾经调侃过。

缓冲区中的每个YUV帧都会上传到" qt_TextureY,U和V"。

如评论中所述,FFMpegs构建将自动使用硬件解码。

另外,为了减少CPU开销,我将所有解码流分离到它们自己的线程中。

祝你好运。别的,只要问一下。