st/va: MPEG4 populate the PPS structure
[mesa.git] / src / gallium / state_trackers / va / image.c
1 /**************************************************************************
2 *
3 * Copyright 2010 Thomas Balling Sørensen & Orasanu Lucian.
4 * Copyright 2014 Advanced Micro Devices, Inc.
5 * All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sub license, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial portions
17 * of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22 * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR
23 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 *
27 **************************************************************************/
28
29 #include "pipe/p_screen.h"
30
31 #include "util/u_memory.h"
32 #include "util/u_handle_table.h"
33 #include "util/u_surface.h"
34 #include "util/u_video.h"
35
36 #include "vl/vl_winsys.h"
37
38 #include "va_private.h"
39
40 static const VAImageFormat formats[VL_VA_MAX_IMAGE_FORMATS] =
41 {
42 {VA_FOURCC('N','V','1','2')},
43 {VA_FOURCC('I','4','2','0')},
44 {VA_FOURCC('Y','V','1','2')},
45 {VA_FOURCC('Y','U','Y','V')},
46 {VA_FOURCC('U','Y','V','Y')},
47 };
48
49 static void
50 vlVaVideoSurfaceSize(vlVaSurface *p_surf, int component,
51 unsigned *width, unsigned *height)
52 {
53 *width = p_surf->templat.width;
54 *height = p_surf->templat.height;
55
56 if (component > 0) {
57 if (p_surf->templat.chroma_format == PIPE_VIDEO_CHROMA_FORMAT_420) {
58 *width /= 2;
59 *height /= 2;
60 } else if (p_surf->templat.chroma_format == PIPE_VIDEO_CHROMA_FORMAT_422)
61 *width /= 2;
62 }
63 if (p_surf->templat.interlaced)
64 *height /= 2;
65 }
66
67 VAStatus
68 vlVaQueryImageFormats(VADriverContextP ctx, VAImageFormat *format_list, int *num_formats)
69 {
70 struct pipe_screen *pscreen;
71 enum pipe_format format;
72 int i;
73
74 if (!ctx)
75 return VA_STATUS_ERROR_INVALID_CONTEXT;
76
77 if (!(format_list && num_formats))
78 return VA_STATUS_ERROR_INVALID_PARAMETER;
79
80 *num_formats = 0;
81 pscreen = VL_VA_PSCREEN(ctx);
82 for (i = 0; i < VL_VA_MAX_IMAGE_FORMATS; ++i) {
83 format = YCbCrToPipe(formats[i].fourcc);
84 if (pscreen->is_video_format_supported(pscreen, format,
85 PIPE_VIDEO_PROFILE_UNKNOWN,
86 PIPE_VIDEO_ENTRYPOINT_BITSTREAM))
87 format_list[(*num_formats)++] = formats[i];
88 }
89
90 return VA_STATUS_SUCCESS;
91 }
92
93 VAStatus
94 vlVaCreateImage(VADriverContextP ctx, VAImageFormat *format, int width, int height, VAImage *image)
95 {
96 vlVaDriver *drv;
97 int w, h;
98
99 if (!ctx)
100 return VA_STATUS_ERROR_INVALID_CONTEXT;
101
102 if (!(format && image && width && height))
103 return VA_STATUS_ERROR_INVALID_PARAMETER;
104
105 drv = VL_VA_DRIVER(ctx);
106
107 image->image_id = handle_table_add(drv->htab, image);
108 image->format = *format;
109 image->width = width;
110 image->height = height;
111 w = align(width, 2);
112 h = align(width, 2);
113
114 switch (format->fourcc) {
115 case VA_FOURCC('N','V','1','2'):
116 image->num_planes = 2;
117 image->pitches[0] = w;
118 image->offsets[0] = 0;
119 image->pitches[1] = w;
120 image->offsets[1] = w * h;
121 image->data_size = w * h * 3 / 2;
122 break;
123
124 case VA_FOURCC('I','4','2','0'):
125 case VA_FOURCC('Y','V','1','2'):
126 image->num_planes = 3;
127 image->pitches[0] = w;
128 image->offsets[0] = 0;
129 image->pitches[1] = w / 2;
130 image->offsets[1] = w * h;
131 image->pitches[2] = w / 2;
132 image->offsets[2] = w * h * 5 / 4;
133 image->data_size = w * h * 3 / 2;
134 break;
135
136 case VA_FOURCC('U','Y','V','Y'):
137 case VA_FOURCC('Y','U','Y','V'):
138 image->num_planes = 1;
139 image->pitches[0] = w * 2;
140 image->offsets[0] = 0;
141 image->data_size = w * h * 2;
142 break;
143
144 default:
145 return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
146 }
147
148 return vlVaCreateBuffer(ctx, 0, VAImageBufferType,
149 align(image->data_size, 16),
150 1, NULL, &image->buf);
151 }
152
153 VAStatus
154 vlVaDeriveImage(VADriverContextP ctx, VASurfaceID surface, VAImage *image)
155 {
156 if (!ctx)
157 return VA_STATUS_ERROR_INVALID_CONTEXT;
158
159 return VA_STATUS_ERROR_UNIMPLEMENTED;
160 }
161
162 VAStatus
163 vlVaDestroyImage(VADriverContextP ctx, VAImageID image)
164 {
165 VAImage *vaimage;
166
167 if (!ctx)
168 return VA_STATUS_ERROR_INVALID_CONTEXT;
169
170 vaimage = handle_table_get(VL_VA_DRIVER(ctx)->htab, image);
171 if (!vaimage)
172 return VA_STATUS_ERROR_INVALID_IMAGE;
173
174 return vlVaDestroyBuffer(ctx, vaimage->buf);
175 }
176
177 VAStatus
178 vlVaSetImagePalette(VADriverContextP ctx, VAImageID image, unsigned char *palette)
179 {
180 if (!ctx)
181 return VA_STATUS_ERROR_INVALID_CONTEXT;
182
183 return VA_STATUS_ERROR_UNIMPLEMENTED;
184 }
185
186 VAStatus
187 vlVaGetImage(VADriverContextP ctx, VASurfaceID surface, int x, int y,
188 unsigned int width, unsigned int height, VAImageID image)
189 {
190 vlVaDriver *drv;
191 vlVaSurface *surf;
192 vlVaBuffer *img_buf;
193 VAImage *vaimage;
194 struct pipe_sampler_view **views;
195 enum pipe_format format;
196 bool convert = false;
197 void *data[3];
198 unsigned pitches[3], i, j;
199
200 if (!ctx)
201 return VA_STATUS_ERROR_INVALID_CONTEXT;
202
203 drv = VL_VA_DRIVER(ctx);
204
205 surf = handle_table_get(drv->htab, surface);
206 if (!surf || !surf->buffer)
207 return VA_STATUS_ERROR_INVALID_SURFACE;
208
209 vaimage = handle_table_get(drv->htab, image);
210 if (!vaimage)
211 return VA_STATUS_ERROR_INVALID_IMAGE;
212
213 img_buf = handle_table_get(drv->htab, vaimage->buf);
214 if (!img_buf)
215 return VA_STATUS_ERROR_INVALID_BUFFER;
216
217 format = YCbCrToPipe(vaimage->format.fourcc);
218 if (format == PIPE_FORMAT_NONE)
219 return VA_STATUS_ERROR_OPERATION_FAILED;
220
221 if (format != surf->buffer->buffer_format) {
222 /* support NV12 to YV12 conversion now only */
223 if (format == PIPE_FORMAT_YV12 &&
224 surf->buffer->buffer_format == PIPE_FORMAT_NV12)
225 convert = true;
226 else
227 return VA_STATUS_ERROR_OPERATION_FAILED;
228 }
229
230 views = surf->buffer->get_sampler_view_planes(surf->buffer);
231 if (!views)
232 return VA_STATUS_ERROR_OPERATION_FAILED;
233
234 for (i = 0; i < vaimage->num_planes; i++) {
235 data[i] = img_buf->data + vaimage->offsets[i];
236 pitches[i] = vaimage->pitches[i];
237 }
238 if (vaimage->format.fourcc == VA_FOURCC('I','4','2','0')) {
239 void *tmp_d;
240 unsigned tmp_p;
241 tmp_d = data[1];
242 data[1] = data[2];
243 data[2] = tmp_d;
244 tmp_p = pitches[1];
245 pitches[1] = pitches[2];
246 pitches[2] = tmp_p;
247 }
248
249 for (i = 0; i < vaimage->num_planes; i++) {
250 unsigned width, height;
251 if (!views[i]) continue;
252 vlVaVideoSurfaceSize(surf, i, &width, &height);
253 for (j = 0; j < views[i]->texture->array_size; ++j) {
254 struct pipe_box box = {0, 0, j, width, height, 1};
255 struct pipe_transfer *transfer;
256 uint8_t *map;
257 map = drv->pipe->transfer_map(drv->pipe, views[i]->texture, 0,
258 PIPE_TRANSFER_READ, &box, &transfer);
259 if (!map)
260 return VA_STATUS_ERROR_OPERATION_FAILED;
261
262 if (i == 1 && convert) {
263 u_copy_nv12_to_yv12(data, pitches, i, j,
264 transfer->stride, views[i]->texture->array_size,
265 map, box.width, box.height);
266 } else {
267 util_copy_rect(data[i] + pitches[i] * j,
268 views[i]->texture->format,
269 pitches[i] * views[i]->texture->array_size, 0, 0,
270 box.width, box.height, map, transfer->stride, 0, 0);
271 }
272 pipe_transfer_unmap(drv->pipe, transfer);
273 }
274 }
275
276 return VA_STATUS_SUCCESS;
277 }
278
279 VAStatus
280 vlVaPutImage(VADriverContextP ctx, VASurfaceID surface, VAImageID image,
281 int src_x, int src_y, unsigned int src_width, unsigned int src_height,
282 int dest_x, int dest_y, unsigned int dest_width, unsigned int dest_height)
283 {
284 vlVaDriver *drv;
285 vlVaSurface *surf;
286 vlVaBuffer *img_buf;
287 VAImage *vaimage;
288 struct pipe_sampler_view **views;
289 enum pipe_format format;
290 void *data[3];
291 unsigned pitches[3], i, j;
292
293 if (!ctx)
294 return VA_STATUS_ERROR_INVALID_CONTEXT;
295
296 drv = VL_VA_DRIVER(ctx);
297
298 surf = handle_table_get(drv->htab, surface);
299 if (!surf || !surf->buffer)
300 return VA_STATUS_ERROR_INVALID_SURFACE;
301
302 vaimage = handle_table_get(drv->htab, image);
303 if (!vaimage)
304 return VA_STATUS_ERROR_INVALID_IMAGE;
305
306 img_buf = handle_table_get(drv->htab, vaimage->buf);
307 if (!img_buf)
308 return VA_STATUS_ERROR_INVALID_BUFFER;
309
310 format = YCbCrToPipe(vaimage->format.fourcc);
311 if (format == PIPE_FORMAT_NONE)
312 return VA_STATUS_ERROR_OPERATION_FAILED;
313
314 if (surf->buffer == NULL || format != surf->buffer->buffer_format) {
315 if (surf->buffer)
316 surf->buffer->destroy(surf->buffer);
317 surf->templat.buffer_format = format;
318 surf->buffer = drv->pipe->create_video_buffer(drv->pipe, &surf->templat);
319 if (!surf->buffer)
320 return VA_STATUS_ERROR_ALLOCATION_FAILED;
321 }
322
323 views = surf->buffer->get_sampler_view_planes(surf->buffer);
324 if (!views)
325 return VA_STATUS_ERROR_OPERATION_FAILED;
326
327 for (i = 0; i < vaimage->num_planes; i++) {
328 data[i] = img_buf->data + vaimage->offsets[i];
329 pitches[i] = vaimage->pitches[i];
330 }
331 if (vaimage->format.fourcc == VA_FOURCC('I','4','2','0')) {
332 void *tmp_d;
333 unsigned tmp_p;
334 tmp_d = data[1];
335 data[1] = data[2];
336 data[2] = tmp_d;
337 tmp_p = pitches[1];
338 pitches[1] = pitches[2];
339 pitches[2] = tmp_p;
340 }
341
342 for (i = 0; i < vaimage->num_planes; ++i) {
343 unsigned width, height;
344 if (!views[i]) continue;
345 vlVaVideoSurfaceSize(surf, i, &width, &height);
346 for (j = 0; j < views[i]->texture->array_size; ++j) {
347 struct pipe_box dst_box = {0, 0, j, width, height, 1};
348 drv->pipe->transfer_inline_write(drv->pipe, views[i]->texture, 0,
349 PIPE_TRANSFER_WRITE, &dst_box,
350 data[i] + pitches[i] * j,
351 pitches[i] * views[i]->texture->array_size, 0);
352 }
353 }
354
355 return VA_STATUS_SUCCESS;
356 }