我正在通过openGL在GLSurfaceView
上呈现视频。 openGL部分是在C ++中以原生部分编写的。这是我的渲染例程:
void VideoRenderOpenGL2::Render(const unsigned char *pData)
{
......................
// GL_OPERATION is a macro, nothing special
GL_OPERATION(glUseProgram(m_program))
UpdateTextures(pData); // other routine, I will post the function if needed
bool bClear = true;
float vpx = 0.0f;
float vpy = 0.0f;
float vpw = 1.0f;
float vph = 1.0f;
int nOrientation = 0;
float uLeft, uRight, vTop, vBottom;
uLeft = vBottom = 0.0f;
uRight = m_uvx;
vTop = m_uvy;
GLfloat squareUvs[] = {
uLeft, vTop,
uRight, vTop,
uLeft, vBottom,
uRight, vBottom
};
if (bClear) {
GL_OPERATION(glViewport(0, 0, m_nDisplayWidth, m_nDisplayHeight))
GL_OPERATION(glClearColor(0, 0, 0, 1))
GL_OPERATION(glClear(GL_COLOR_BUFFER_BIT))
}
GLfloat squareVertices[8];
// drawing surface dimensions
int screenW = m_nDisplayWidth;
int screenH = m_nDisplayHeight;
if (nOrientation == 90 || nOrientation == 270) {
screenW = m_nDisplayHeight;
screenH = m_nDisplayWidth;
}
int x,y,w,h;
// Fill the smallest dimension, then compute the other one using the image ratio
if (screenW <= screenH) {
float ratio = m_nTextureHeight / (float)m_nTextureWidth;
w = screenW * vpw;
h = w * ratio;
if (h > screenH) {
w *= screenH /(float) h;
h = screenH;
}
x = vpx * m_nDisplayWidth;
y = vpy * m_nDisplayHeight;
} else {
float ratio = m_nTextureWidth / (float)m_nTextureHeight;
h = screenH * vph;
w = h * ratio;
if (w > screenW) {
h *= screenW / (float)w;
w = screenW;
}
x = vpx * screenW;
y = vpy * screenH;
}
// here m_nDisplayWidth = 5536, m_nDisplayHeight = 3114, w = 5536, h = 3114, x = 0, y = 0, screenW = 5536, screenH = 3114, m_nTextureWidth = 1280, m_nTextureHeight = 720
squareVertices[0] = (x - w * 0.5) / screenW - 0.;
squareVertices[1] = (y - h * 0.5) / screenH - 0.;
squareVertices[2] = (x + w * 0.5) / screenW - 0.;
squareVertices[3] = (y - h * 0.5) / screenH - 0.;
squareVertices[4] = (x - w * 0.5) / screenW - 0.;
squareVertices[5] = (y + h * 0.5) / screenH - 0.;
squareVertices[6] = (x + w * 0.5) / screenW - 0.;
squareVertices[7] = (y + h * 0.5) / screenH - 0.;
GL_OPERATION(glViewport(0, 0, m_nDisplayWidth, m_nDisplayHeight))
GLfloat mat[16];
#define VP_SIZE 1.0f
float vpDim = VP_SIZE / (2 * m_scaleFactor);
#define ENSURE_RANGE_A_INSIDE_RANGE_B(a, aSize, bMin, bMax) \
if (2 * aSize >= (bMax - bMin)) \
a = 0; \
else if ((a - aSize < bMin) || (a + aSize > bMax)) { \
float diff; \
if (a - aSize < bMin) diff = bMin - (a - aSize); \
else diff = bMax - (a + aSize); \
a += diff; \
}
float zoom_cx = 0.0f;
float zoom_cy = 0.0f;
ENSURE_RANGE_A_INSIDE_RANGE_B(zoom_cx, vpDim, squareVertices[0], squareVertices[2])
ENSURE_RANGE_A_INSIDE_RANGE_B(zoom_cy, vpDim, squareVertices[1], squareVertices[7])
LoadOrthographicMatrix(
zoom_cx - vpDim,
zoom_cx + vpDim,
zoom_cy - vpDim,
zoom_cy + vpDim,
0, 0.5, mat);
GL_OPERATION(glUniformMatrix4fv(m_uniforms[UNIFORM_PROJ_MATRIX], 1, GL_FALSE, mat))
#define degreesToRadians(d) (2.0 * 3.14157 * d / 360.0)
float rad = degreesToRadians(nOrientation);
GL_OPERATION(glUniform1f(m_uniforms[UNIFORM_ROTATION], rad))
GL_OPERATION(glActiveTexture(GL_TEXTURE0))
GL_OPERATION(glBindTexture(GL_TEXTURE_2D, m_textures[Y]))
GL_OPERATION(glUniform1i(m_uniforms[UNIFORM_TEXTURE_Y], 0))
GL_OPERATION(glActiveTexture(GL_TEXTURE1))
GL_OPERATION(glBindTexture(GL_TEXTURE_2D, m_textures[U]))
GL_OPERATION(glUniform1i(m_uniforms[UNIFORM_TEXTURE_U], 1))
GL_OPERATION(glActiveTexture(GL_TEXTURE2))
GL_OPERATION(glBindTexture(GL_TEXTURE_2D, m_textures[V]))
GL_OPERATION(glUniform1i(m_uniforms[UNIFORM_TEXTURE_V], 2))
GL_OPERATION(glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, squareVertices))
GL_OPERATION(glEnableVertexAttribArray(ATTRIB_VERTEX))
GL_OPERATION(glVertexAttribPointer(ATTRIB_UV, 2, GL_FLOAT, 1, 0, squareUvs))
GL_OPERATION(glEnableVertexAttribArray(ATTRIB_UV))
GL_OPERATION(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4))
}
这是LoadOrthographicMatrix
:
void VideoRenderOpenGL2::LoadOrthographicMatrix(float left, float right, float bottom, float top, float near, float far, float* mat)
{
float r_l = right - left;
float t_b = top - bottom;
float f_n = far - near;
float tx = - (right + left) / (right - left);
float ty = - (top + bottom) / (top - bottom);
float tz = - (far + near) / (far - near);
mat[0] = (2.0f / r_l);
mat[1] = mat[2] = mat[3] = 0.0f;
mat[4] = 0.0f;
mat[5] = (2.0f / t_b);
mat[6] = mat[7] = 0.0f;
mat[8] = mat[9] = 0.0f;
mat[10] = -2.0f / f_n;
mat[11] = 0.0f;
mat[12] = tx;
mat[13] = ty;
mat[14] = tz;
mat[15] = 1.0f;
}
假设我的设备维度为1080 x 1557
,我正在尝试在{{2768 x 1557
上呈现1280 x 720
(高度等于设备高度和相应的宽度,保持纵横比与GLSurfaceView
)大小的视频1}}。到目前为止一切正常,Render(const unsigned char *pData)
正确渲染,glViewport(0, 0, m_nDisplayWidth, m_nDisplayHeight)
工作正常。
但是,当我想加载两倍大小2768 x 1557
的视频时,我的意思是5536 x 3114
视频在X轴上闪烁/拥塞(未截断)。 Render(...)
正在绘制视频的全部内容,但未使用完整画布。我无法弄清楚这里有什么问题。为什么视频在X轴上拥挤?
需要注意的是,当我增加宽度和宽度时,视频会变得更加拥挤。身高超过2倍。可以直到2768 x 1557
答案 0 :(得分:2)
您可能超出了OpenGL实施的限制。特别是,最大纹理尺寸和最大视口尺寸可以发挥作用。
要查询最大纹理大小,请使用:
GLint maxTexSize = 0;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize);
并且对于最大视口尺寸:
GLint viewportDims[2] = {0};
glGetIntegerv(GL_MAX_VIEWPORT_DIMS, viewportDims);
对于当前的低端设备,这些限制的典型值低至2K,对于旧设备而言甚至可能更低。 4K和8K在当前主流设备中非常普遍。最近的高端移动GPU支持最大16K的大小。
因此,在尝试超过4K的尺寸之前,您一定要检查这些限制。您的5536x3114尺寸很可能会超出一些最新设备的限制。