vaapidecode: handle flush() vmethod
[platform/upstream/gstreamer.git] / gst / vaapi / gstvaapivideometa_texture.c
1 /*
2  *  gstvaapivideometa_texture.c - GStreamer/VA video meta (GLTextureUpload)
3  *
4  *  Copyright (C) 2010-2011 Splitted-Desktop Systems
5  *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
6  *  Copyright (C) 2011-2014 Intel Corporation
7  *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
8  *  Copyright (C) 2013 Igalia
9  *    Author: Víctor Manuel Jáquez Leal <vjaquez@igalia.com>
10  *
11  *  This library is free software; you can redistribute it and/or
12  *  modify it under the terms of the GNU Lesser General Public License
13  *  as published by the Free Software Foundation; either version 2.1
14  *  of the License, or (at your option) any later version.
15  *
16  *  This library is distributed in the hope that it will be useful,
17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  *  Lesser General Public License for more details.
20  *
21  *  You should have received a copy of the GNU Lesser General Public
22  *  License along with this library; if not, write to the Free
23  *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24  *  Boston, MA 02110-1301 USA
25  */
26
27 #include "gst/vaapi/sysdeps.h"
28 #include "gst/vaapi/ogl_compat.h"
29 #include "gstvaapivideometa.h"
30 #include "gstvaapivideometa_texture.h"
31 #include "gstvaapipluginutil.h"
32
33 #if USE_GLX
34 #include <gst/vaapi/gstvaapitexture_glx.h>
35 #endif
36
37 #define DEFAULT_FORMAT GST_VIDEO_FORMAT_RGBA
38
39 #if GST_CHECK_VERSION(1,1,0) && (USE_GLX || USE_EGL)
40 struct _GstVaapiVideoMetaTexture
41 {
42   GstVaapiTexture *texture;
43   GstVideoGLTextureType texture_type;
44   guint gl_format;
45   guint width;
46   guint height;
47 };
48
49 static guint
50 get_texture_orientation_flags (GstVideoGLTextureOrientation orientation)
51 {
52   guint flags;
53
54   switch (orientation) {
55     case GST_VIDEO_GL_TEXTURE_ORIENTATION_X_NORMAL_Y_FLIP:
56       flags = GST_VAAPI_TEXTURE_ORIENTATION_FLAG_Y_INVERTED;
57       break;
58     case GST_VIDEO_GL_TEXTURE_ORIENTATION_X_FLIP_Y_NORMAL:
59       flags = GST_VAAPI_TEXTURE_ORIENTATION_FLAG_X_INVERTED;
60       break;
61     case GST_VIDEO_GL_TEXTURE_ORIENTATION_X_FLIP_Y_FLIP:
62       flags = GST_VAAPI_TEXTURE_ORIENTATION_FLAG_X_INVERTED |
63           GST_VAAPI_TEXTURE_ORIENTATION_FLAG_Y_INVERTED;
64       break;
65     default:
66       flags = 0;
67       break;
68   }
69   return flags;
70 }
71
72 static gboolean
73 meta_texture_ensure_format (GstVaapiVideoMetaTexture * meta,
74     GstVideoFormat format)
75 {
76   switch (format) {
77     case GST_VIDEO_FORMAT_RGBA:
78       meta->gl_format = GL_RGBA;
79       meta->texture_type = GST_VIDEO_GL_TEXTURE_TYPE_RGBA;
80       break;
81     case GST_VIDEO_FORMAT_BGRA:
82       meta->gl_format = GL_BGRA_EXT;
83       /* FIXME: add GST_VIDEO_GL_TEXTURE_TYPE_BGRA extension */
84       meta->texture_type = GST_VIDEO_GL_TEXTURE_TYPE_RGBA;
85       break;
86     default:
87       goto error_unsupported_format;
88   }
89   return TRUE;
90
91   /* ERRORS */
92 error_unsupported_format:
93   GST_ERROR ("unsupported texture format %s",
94       gst_video_format_to_string (format));
95   return FALSE;
96 }
97
98 static gboolean
99 meta_texture_ensure_info_from_buffer (GstVaapiVideoMetaTexture * meta,
100     GstBuffer * buffer)
101 {
102   GstVideoMeta *vmeta;
103   GstVideoFormat format;
104
105   if (!buffer || !(vmeta = gst_buffer_get_video_meta (buffer))) {
106     format = DEFAULT_FORMAT;
107     meta->width = 0;
108     meta->height = 0;
109   } else {
110     const GstVideoFormatInfo *const fmt_info =
111         gst_video_format_get_info (vmeta->format);
112     format = (fmt_info && GST_VIDEO_FORMAT_INFO_IS_RGB (fmt_info)) ?
113         vmeta->format : DEFAULT_FORMAT;
114     meta->width = vmeta->width;
115     meta->height = vmeta->height;
116   }
117   return meta_texture_ensure_format (meta, format);
118 }
119
120 static void
121 meta_texture_free (GstVaapiVideoMetaTexture * meta)
122 {
123   if (G_UNLIKELY (!meta))
124     return;
125
126   gst_vaapi_texture_replace (&meta->texture, NULL);
127   g_slice_free (GstVaapiVideoMetaTexture, meta);
128 }
129
130 static GstVaapiVideoMetaTexture *
131 meta_texture_new (void)
132 {
133   GstVaapiVideoMetaTexture *meta;
134
135   meta = g_slice_new (GstVaapiVideoMetaTexture);
136   if (!meta)
137     return NULL;
138
139   meta->texture = NULL;
140   if (!meta_texture_ensure_info_from_buffer (meta, NULL))
141     goto error;
142   return meta;
143
144 error:
145   meta_texture_free (meta);
146   return NULL;
147 }
148
149 static GstVaapiVideoMetaTexture *
150 meta_texture_copy (GstVaapiVideoMetaTexture * meta)
151 {
152   GstVaapiVideoMetaTexture *copy;
153
154   copy = meta_texture_new ();
155   if (!copy)
156     return NULL;
157
158   copy->texture_type = meta->texture_type;
159   copy->gl_format = meta->gl_format;
160   copy->width = meta->width;
161   copy->height = meta->height;
162   gst_vaapi_texture_replace (&copy->texture, meta->texture);
163   return copy;
164 }
165
166 static gboolean
167 gst_vaapi_texture_upload (GstVideoGLTextureUploadMeta * meta,
168     guint texture_id[4])
169 {
170   GstVaapiVideoMeta *const vmeta =
171       gst_buffer_get_vaapi_video_meta (meta->buffer);
172   GstVaapiVideoMetaTexture *const meta_texture = meta->user_data;
173   GstVaapiSurfaceProxy *const proxy =
174       gst_vaapi_video_meta_get_surface_proxy (vmeta);
175   GstVaapiSurface *const surface = gst_vaapi_surface_proxy_get_surface (proxy);
176   GstVaapiDisplay *const dpy = GST_VAAPI_OBJECT_DISPLAY (surface);
177
178   if (!gst_vaapi_display_has_opengl (dpy))
179     return FALSE;
180
181   if (!meta_texture->texture ||
182       /* Check whether VA display changed */
183       GST_VAAPI_OBJECT_DISPLAY (meta_texture->texture) != dpy ||
184       /* Check whether texture id changed */
185       gst_vaapi_texture_get_id (meta_texture->texture) != texture_id[0]) {
186     /* FIXME: should we assume target? */
187     GstVaapiTexture *const texture =
188         gst_vaapi_texture_new_wrapped (dpy, texture_id[0],
189         GL_TEXTURE_2D, meta_texture->gl_format, meta_texture->width,
190         meta_texture->height);
191     gst_vaapi_texture_replace (&meta_texture->texture, texture);
192     if (!texture)
193       return FALSE;
194     gst_vaapi_texture_unref (texture);
195   }
196
197   gst_vaapi_texture_set_orientation_flags (meta_texture->texture,
198       get_texture_orientation_flags (meta->texture_orientation));
199
200   return gst_vaapi_texture_put_surface (meta_texture->texture, surface,
201       gst_vaapi_surface_proxy_get_crop_rect (proxy),
202       gst_vaapi_video_meta_get_render_flags (vmeta));
203 }
204
205 gboolean
206 gst_buffer_add_texture_upload_meta (GstBuffer * buffer)
207 {
208   GstVideoGLTextureUploadMeta *meta = NULL;
209   GstVaapiVideoMetaTexture *meta_texture;
210
211   if (!buffer)
212     return FALSE;
213
214   meta_texture = meta_texture_new ();
215   if (!meta_texture)
216     return FALSE;
217
218   if (!meta_texture_ensure_info_from_buffer (meta_texture, buffer))
219     goto error;
220
221   meta = gst_buffer_add_video_gl_texture_upload_meta (buffer,
222       GST_VIDEO_GL_TEXTURE_ORIENTATION_X_NORMAL_Y_NORMAL,
223       1, &meta_texture->texture_type, gst_vaapi_texture_upload,
224       meta_texture, (GBoxedCopyFunc) meta_texture_copy,
225       (GBoxedFreeFunc) meta_texture_free);
226   if (!meta)
227     goto error;
228   return TRUE;
229
230 error:
231   meta_texture_free (meta_texture);
232   return FALSE;
233 }
234
235 gboolean
236 gst_buffer_ensure_texture_upload_meta (GstBuffer * buffer)
237 {
238   GstVideoGLTextureUploadMeta *const meta =
239       gst_buffer_get_video_gl_texture_upload_meta (buffer);
240
241   return meta ?
242       meta_texture_ensure_info_from_buffer (meta->user_data, buffer) :
243       gst_buffer_add_texture_upload_meta (buffer);
244 }
245 #endif