lavd/opengl_enc: factorize deinit_context function
[ffmpeg.git] / libavdevice / opengl_enc.c
index f214585..ff9ffc0 100644 (file)
@@ -188,6 +188,8 @@ typedef struct OpenGLContext {
 
     /* Current OpenGL configuration */
     GLuint program;                    ///< Shader program
+    GLuint vertex_shader;              ///< Vertex shader
+    GLuint fragment_shader;            ///< Fragment shader for current pix_pmt
     GLuint texture_name[4];            ///< Textures' IDs
     GLuint index_buffer;               ///< Index buffer
     GLuint vertex_buffer;              ///< Vertex buffer
@@ -270,6 +272,32 @@ static av_cold int opengl_prepare_vertex(AVFormatContext *s);
 static int opengl_draw(AVFormatContext *h, AVPacket *pkt, int repaint);
 static av_cold int opengl_init_context(OpenGLContext *opengl);
 
+static av_cold void opengl_deinit_context(OpenGLContext *opengl)
+{
+    glDeleteTextures(4, opengl->texture_name);
+    opengl->texture_name[0] = opengl->texture_name[1] =
+    opengl->texture_name[2] = opengl->texture_name[3] = 0;
+    if (opengl->glprocs.glUseProgram)
+        opengl->glprocs.glUseProgram(0);
+    if (opengl->glprocs.glDeleteProgram) {
+        opengl->glprocs.glDeleteProgram(opengl->program);
+        opengl->program = 0;
+    }
+    if (opengl->glprocs.glDeleteShader) {
+        opengl->glprocs.glDeleteShader(opengl->vertex_shader);
+        opengl->glprocs.glDeleteShader(opengl->fragment_shader);
+        opengl->vertex_shader = opengl->fragment_shader = 0;
+    }
+    if (opengl->glprocs.glBindBuffer) {
+        opengl->glprocs.glBindBuffer(FF_GL_ARRAY_BUFFER, 0);
+        opengl->glprocs.glBindBuffer(FF_GL_ELEMENT_ARRAY_BUFFER, 0);
+    }
+    if (opengl->glprocs.glDeleteBuffers) {
+        opengl->glprocs.glDeleteBuffers(2, &opengl->index_buffer);
+        opengl->vertex_buffer = opengl->index_buffer = 0;
+    }
+}
+
 static int opengl_resize(AVFormatContext *h, int width, int height)
 {
     int ret = 0;
@@ -349,8 +377,7 @@ static int opengl_sdl_process_events(AVFormatContext *h)
             SDL_VideoDriverName(buffer, sizeof(buffer));
             reinit = !av_strncasecmp(buffer, "quartz", sizeof(buffer));
             if (reinit) {
-                glDeleteTextures(4, opengl->texture_name);
-                opengl->glprocs.glDeleteBuffers(2, &opengl->index_buffer);
+                opengl_deinit_context(opengl);
             }
             if ((ret = opengl_sdl_recreate_window(opengl, event.resize.w, event.resize.h)) < 0)
                 return ret;
@@ -731,7 +758,6 @@ static av_cold GLuint opengl_load_shader(OpenGLContext *opengl, GLenum type, con
 
 static av_cold int opengl_compile_shaders(OpenGLContext *opengl, enum AVPixelFormat pix_fmt)
 {
-    GLuint vertex_shader = 0, fragment_shader = 0;
     GLint result;
     const char *fragment_shader_code = opengl_get_fragment_shader_code(pix_fmt);
 
@@ -741,15 +767,15 @@ static av_cold int opengl_compile_shaders(OpenGLContext *opengl, enum AVPixelFor
         return AVERROR(EINVAL);
     }
 
-    vertex_shader = opengl_load_shader(opengl, FF_GL_VERTEX_SHADER,
-                                       FF_OPENGL_VERTEX_SHADER);
-    if (!vertex_shader) {
+    opengl->vertex_shader = opengl_load_shader(opengl, FF_GL_VERTEX_SHADER,
+                                               FF_OPENGL_VERTEX_SHADER);
+    if (!opengl->vertex_shader) {
         av_log(opengl, AV_LOG_ERROR, "Vertex shader loading failed.\n");
         goto fail;
     }
-    fragment_shader = opengl_load_shader(opengl, FF_GL_FRAGMENT_SHADER,
-                                         fragment_shader_code);
-    if (!fragment_shader) {
+    opengl->fragment_shader = opengl_load_shader(opengl, FF_GL_FRAGMENT_SHADER,
+                                                 fragment_shader_code);
+    if (!opengl->fragment_shader) {
         av_log(opengl, AV_LOG_ERROR, "Fragment shader loading failed.\n");
         goto fail;
     }
@@ -758,8 +784,8 @@ static av_cold int opengl_compile_shaders(OpenGLContext *opengl, enum AVPixelFor
     if (!opengl->program)
         goto fail;
 
-    opengl->glprocs.glAttachShader(opengl->program, vertex_shader);
-    opengl->glprocs.glAttachShader(opengl->program, fragment_shader);
+    opengl->glprocs.glAttachShader(opengl->program, opengl->vertex_shader);
+    opengl->glprocs.glAttachShader(opengl->program, opengl->fragment_shader);
     opengl->glprocs.glLinkProgram(opengl->program);
 
     opengl->glprocs.glGetProgramiv(opengl->program, FF_GL_LINK_STATUS, &result);
@@ -792,10 +818,10 @@ static av_cold int opengl_compile_shaders(OpenGLContext *opengl, enum AVPixelFor
     OPENGL_ERROR_CHECK(opengl);
     return 0;
   fail:
-    opengl->glprocs.glDeleteShader(vertex_shader);
-    opengl->glprocs.glDeleteShader(fragment_shader);
+    opengl->glprocs.glDeleteShader(opengl->vertex_shader);
+    opengl->glprocs.glDeleteShader(opengl->fragment_shader);
     opengl->glprocs.glDeleteProgram(opengl->program);
-    opengl->program = 0;
+    opengl->fragment_shader = opengl->vertex_shader = opengl->program = 0;
     return AVERROR_EXTERNAL;
 }
 
@@ -889,25 +915,59 @@ static int opengl_prepare(OpenGLContext *opengl)
     return AVERROR_EXTERNAL;
 }
 
-static av_cold int opengl_write_trailer(AVFormatContext *h)
+static int opengl_create_window(AVFormatContext *h)
 {
     OpenGLContext *opengl = h->priv_data;
+    int ret;
 
-    if (opengl->no_window &&
-        avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_PREPARE_WINDOW_BUFFER, NULL , 0) < 0)
-        av_log(opengl, AV_LOG_ERROR, "Application failed to prepare window buffer.\n");
-
-    glDeleteTextures(4, opengl->texture_name);
-    if (opengl && opengl->glprocs.glDeleteBuffers)
-        opengl->glprocs.glDeleteBuffers(2, &opengl->index_buffer);
+    if (!opengl->no_window) {
+#if HAVE_SDL
+        if ((ret = opengl_sdl_create_window(h)) < 0) {
+            av_log(opengl, AV_LOG_ERROR, "Cannot create default SDL window.\n");
+            return ret;
+        }
+#else
+        av_log(opengl, AV_LOG_ERROR, "FFmpeg is compiled without SDL. Cannot create default window.\n");
+        return AVERROR(ENOSYS);
+#endif
+    } else {
+        if ((ret = avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_CREATE_WINDOW_BUFFER, NULL , 0)) < 0) {
+            av_log(opengl, AV_LOG_ERROR, "Application failed to create window buffer.\n");
+            return ret;
+        }
+        if ((ret = avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_PREPARE_WINDOW_BUFFER, NULL , 0)) < 0) {
+            av_log(opengl, AV_LOG_ERROR, "Application failed to prepare window buffer.\n");
+            return ret;
+        }
+    }
+    return 0;
+}
 
+static int opengl_release_window(AVFormatContext *h)
+{
+    int ret;
+    OpenGLContext *opengl = h->priv_data;
+    if (!opengl->no_window) {
 #if HAVE_SDL
-    if (!opengl->no_window)
         SDL_Quit();
 #endif
-    if (opengl->no_window &&
-        avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_DESTROY_WINDOW_BUFFER, NULL , 0) < 0)
+    } else if ((ret = avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_DESTROY_WINDOW_BUFFER, NULL , 0) < 0)) {
         av_log(opengl, AV_LOG_ERROR, "Application failed to release window buffer.\n");
+        return ret;
+    }
+    return 0;
+}
+
+static av_cold int opengl_write_trailer(AVFormatContext *h)
+{
+    OpenGLContext *opengl = h->priv_data;
+
+    if (opengl->no_window &&
+        avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_PREPARE_WINDOW_BUFFER, NULL , 0) < 0)
+        av_log(opengl, AV_LOG_ERROR, "Application failed to prepare window buffer.\n");
+
+    opengl_deinit_context(opengl);
+    opengl_release_window(h);
 
     return 0;
 }
@@ -991,25 +1051,8 @@ static av_cold int opengl_write_header(AVFormatContext *h)
     if (!opengl->window_title && !opengl->no_window)
         opengl->window_title = av_strdup(h->filename);
 
-    if (!opengl->no_window) {
-#if HAVE_SDL
-        if ((ret = opengl_sdl_create_window(h)) < 0)
-            goto fail;
-#else
-        av_log(opengl, AV_LOG_ERROR, "FFmpeg is compiled without SDL. Cannot create default window.\n");
-        ret = AVERROR(ENOSYS);
+    if ((ret = opengl_create_window(h)))
         goto fail;
-#endif
-    } else {
-        if ((ret = avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_CREATE_WINDOW_BUFFER, NULL , 0)) < 0) {
-            av_log(opengl, AV_LOG_ERROR, "Application failed to create window buffer.\n");
-            goto fail;
-        }
-        if ((ret = avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_PREPARE_WINDOW_BUFFER, NULL , 0)) < 0) {
-            av_log(opengl, AV_LOG_ERROR, "Application failed to prepare window buffer.\n");
-            goto fail;
-        }
-    }
 
     if ((ret = opengl_read_limits(opengl)) < 0)
         goto fail;