1

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

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

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

4

1 回答 1

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 开销,我将所有解码流分离到它们自己的线程中。

祝你好运。其他的,随便问问。

于 2017-08-09T07:56:26.360 回答