返回
视频H264解码原理与详细流程探讨
IOS
2024-02-07 03:23:49
##视频H264解码详解(下)##
前言
本篇接着005 - 视频H264编码详解(中),主要做H264编解码流程中的最后2环 👇
- 继续封装解码工具类
- 拿到解码的流数据之后,渲染显示视频帧画面
一、初始化
初始化分为2个方法执行👇🏻
1. public static void init(Surface surface) {
2. prepareGLComponents();
3. createNativeWindow(surface);
4. }
1. private static void createNativeWindow(Surface surface) {
2. // 1. 创建一个本地窗口
3. mANativeWindow = surface.getNativeWindow();
4. // 2. 绑定渲染器(缓冲区)与本地窗口
5. mEGLDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
6. // 3. 初始化渲染器配置
7. int[] attrs = {
8. EGL14.EGL_RED_SIZE, 8,
9. EGL14.EGL_GREEN_SIZE, 8,
10. EGL14.EGL_BLUE_SIZE, 8,
11. EGL14.EGL_ALPHA_SIZE, 8,
12. EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
13. EGL14.EGL_SURFACE_TYPE, EGL14.EGL_WINDOW_BIT,
14. EGL14.EGL_NONE
15. };
16. EGLConfig[] configs = new EGLConfig[1];
17. int[] numConfigs = new int[1];
18. EGL14.eglChooseConfig(mEGLDisplay, attrs, configs, 1, numConfigs);
19. EGLConfig config = configs[0];
20. // 4. 创建渲染器表面
21. mEGLSurface = EGL14.eglCreateWindowSurface(mEGLDisplay, config, mANativeWindow, null);
22. // 5. 创建上下文
23. EGLContext context = EGL14.eglCreateContext(mEGLDisplay, config, EGL14.EGL_NO_CONTEXT, null);
24. // 6. 使我们创建的EGLContext成为当前线程的current context
25. EGL14.eglMakeCurrent(mEGLDisplay, mEGLSurface, mEGLSurface, context);
26. }
二、解码后显示视频画面
1. public static void render(int textureId, int width, int height) {
2. GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
3. GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
4. GLES20.glViewport(0, 0, width, height);
5. // GLES20.glUseProgram(mProgram);
6. GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
7. GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
8. // glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
9. // glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
10. // glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
11. // glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
12. GLES20.glUniform1i(mSamplerLoc, 0);
13. GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
14. GLES20.eglSwapBuffers(mEGLDisplay, mEGLSurface);
15. }
- 上述方法
render
:1.~3.
清除帧缓冲区并设置视口大小。4.
激活纹理并绑定纹理对象。5.
使用我们创建的着色器程序。6.~12.
配置纹理参数并激活纹理单元。13.
绘制图像。14.
交换帧缓冲区。
三、解码数据并显示视频
1. private void decodeData() {
2. byte[] h264 = new byte[1024 * 1024];
3. while (!mIsExit) {
4. int len = mInputStream.read(h264, 0, h264.length);
5. if (len > 0) {
6. byte[] temp = new byte[len];
7. System.arraycopy(h264, 0, temp, 0, len);
8. nativeDecodeData(temp);
9. } else {
10. mIsExit = true;
11. }
12. }
13. nativeRelease();
14. }
- 上述方法
decodeData
:1.
创建一个用于存储H.264数据缓冲区的数组。2.
循环读取输入流中的数据。3.
如果读取到的数据长度大于0,则将数据复制到临时数组中。4.
调用本机方法nativeDecodeData
解码数据。5.
如果读取到的数据长度为0,则退出循环。6.
调用本机方法nativeRelease
释放资源。
总结
至此,我们已经完成了H.264解码器的实现,它可以将H.264数据解码成视频帧,然后将这些视频帧渲染到屏幕上。