2
* vdpau_image.c - VDPAU backend for VA API (VA images)
4
* vdpau-video (C) 2009-2010 Splitted-Desktop Systems
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22
#include "vdpau_image.h"
23
#include "vdpau_video.h"
24
#include "vdpau_buffer.h"
25
#include "vdpau_mixer.h"
31
// List of supported image formats
33
VdpImageFormatType vdp_format_type;
35
VAImageFormat va_format;
36
unsigned int num_palette_entries;
37
unsigned int entry_bytes;
38
char component_order[4];
39
} vdpau_image_format_map_t;
41
static const vdpau_image_format_map_t vdpau_image_formats_map[] = {
42
#define DEF(TYPE, FORMAT) \
43
VDP_IMAGE_FORMAT_TYPE_##TYPE, VDP_##TYPE##_FORMAT_##FORMAT
44
#define DEF_YUV(TYPE, FORMAT, FOURCC, ENDIAN, BPP) \
45
{ DEF(TYPE, FORMAT), { VA_FOURCC FOURCC, VA_##ENDIAN##_FIRST, BPP, }, }
46
#define DEF_RGB(TYPE, FORMAT, FOURCC, ENDIAN, BPP, DEPTH, R,G,B,A) \
47
{ DEF(TYPE, FORMAT), { VA_FOURCC FOURCC, VA_##ENDIAN##_FIRST, BPP, DEPTH, R,G,B,A }, }
48
#define DEF_IDX(TYPE, FORMAT, FOURCC, ENDIAN, BPP, NPE, EB, C0,C1,C2,C3) \
49
{ DEF(TYPE, FORMAT), { VA_FOURCC FOURCC, VA_##ENDIAN##_FIRST, BPP, }, \
50
NPE, EB, { C0, C1, C2, C3 } }
51
DEF_YUV(YCBCR, NV12, ('N','V','1','2'), LSB, 12),
52
DEF_YUV(YCBCR, YV12, ('Y','V','1','2'), LSB, 12),
53
DEF_YUV(YCBCR, UYVY, ('U','Y','V','Y'), LSB, 16),
54
DEF_YUV(YCBCR, YUYV, ('Y','U','Y','V'), LSB, 16),
55
DEF_YUV(YCBCR, V8U8Y8A8, ('A','Y','U','V'), LSB, 32),
56
#ifdef WORDS_BIGENDIAN
57
DEF_RGB(RGBA, B8G8R8A8, ('A','R','G','B'), MSB, 32,
58
32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000),
59
DEF_RGB(RGBA, R8G8B8A8, ('A','B','G','R'), MSB, 32,
60
32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000),
62
DEF_RGB(RGBA, B8G8R8A8, ('B','G','R','A'), LSB, 32,
63
32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000),
64
DEF_RGB(RGBA, R8G8B8A8, ('R','G','B','A'), LSB, 32,
65
32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000),
67
DEF_IDX(INDEXED, A4I4, ('A','I','4','4'), MSB, 8,
68
16, 3, 'R','G','B',0),
69
DEF_IDX(INDEXED, I4A4, ('I','A','4','4'), MSB, 8,
70
16, 3, 'R','G','B',0),
71
DEF_IDX(INDEXED, A8I8, ('A','I','8','8'), MSB, 16,
72
256, 3, 'R','G','B',0),
73
DEF_IDX(INDEXED, I8A8, ('I','A','8','8'), MSB, 16,
74
256, 3, 'R','G','B',0),
81
// Returns a suitable VDPAU image format for the specified VA image format
82
static const vdpau_image_format_map_t *get_format(const VAImageFormat *format)
85
for (i = 0; i < ARRAY_ELEMS(vdpau_image_formats_map); i++) {
86
const vdpau_image_format_map_t * const m = &vdpau_image_formats_map[i];
87
if (m->va_format.fourcc == format->fourcc &&
88
(m->vdp_format_type == VDP_IMAGE_FORMAT_TYPE_RGBA ?
89
(m->va_format.byte_order == format->byte_order &&
90
m->va_format.red_mask == format->red_mask &&
91
m->va_format.green_mask == format->green_mask &&
92
m->va_format.blue_mask == format->blue_mask &&
93
m->va_format.alpha_mask == format->alpha_mask) : 1))
99
// Checks whether the VDPAU implementation supports the specified image format
100
static inline VdpBool
102
vdpau_driver_data_t *driver_data,
103
VdpImageFormatType type,
107
VdpBool is_supported = VDP_FALSE;
108
VdpStatus vdp_status;
111
case VDP_IMAGE_FORMAT_TYPE_YCBCR:
113
vdpau_video_surface_query_ycbcr_caps(driver_data,
114
driver_data->vdp_device,
119
case VDP_IMAGE_FORMAT_TYPE_RGBA:
121
vdpau_output_surface_query_rgba_caps(driver_data,
122
driver_data->vdp_device,
127
vdp_status = VDP_STATUS_INVALID_VALUE;
130
return vdp_status == VDP_STATUS_OK && is_supported;
133
// vaQueryImageFormats
135
vdpau_QueryImageFormats(
136
VADriverContextP ctx,
137
VAImageFormat *format_list,
141
VDPAU_DRIVER_DATA_INIT;
146
if (format_list == NULL)
147
return VA_STATUS_SUCCESS;
150
for (i = 0; i < ARRAY_ELEMS(vdpau_image_formats_map); i++) {
151
const vdpau_image_format_map_t * const f = &vdpau_image_formats_map[i];
152
if (is_supported_format(driver_data, f->vdp_format_type, f->vdp_format))
153
format_list[n++] = f->va_format;
156
/* If the assert fails then VDPAU_MAX_IMAGE_FORMATS needs to be bigger */
157
ASSERT(n <= VDPAU_MAX_IMAGE_FORMATS);
161
return VA_STATUS_SUCCESS;
167
VADriverContextP ctx,
168
VAImageFormat *format,
174
VDPAU_DRIVER_DATA_INIT;
176
VAStatus va_status = VA_STATUS_ERROR_OPERATION_FAILED;
177
unsigned int i, width2, height2, size2, size;
179
if (!format || !out_image)
180
return VA_STATUS_ERROR_INVALID_PARAMETER;
182
out_image->image_id = VA_INVALID_ID;
183
out_image->buf = VA_INVALID_ID;
185
VAImageID image_id = object_heap_allocate(&driver_data->image_heap);
186
if (image_id == VA_INVALID_ID)
187
return VA_STATUS_ERROR_ALLOCATION_FAILED;
189
object_image_p obj_image = VDPAU_IMAGE(image_id);
191
return VA_STATUS_ERROR_ALLOCATION_FAILED;
193
const vdpau_image_format_map_t *m = get_format(format);
195
return VA_STATUS_ERROR_UNKNOWN; /* VA_STATUS_ERROR_UNSUPPORTED_FORMAT */
197
VAImage * const image = &obj_image->image;
198
image->image_id = image_id;
199
image->buf = VA_INVALID_ID;
201
size = width * height;
202
width2 = (width + 1) / 2;
203
height2 = (height + 1) / 2;
204
size2 = width2 * height2;
206
switch (format->fourcc) {
207
case VA_FOURCC('N','V','1','2'):
208
image->num_planes = 2;
209
image->pitches[0] = width;
210
image->offsets[0] = 0;
211
image->pitches[1] = width;
212
image->offsets[1] = size;
213
image->data_size = size + 2 * size2;
215
case VA_FOURCC('Y','V','1','2'):
216
image->num_planes = 3;
217
image->pitches[0] = width;
218
image->offsets[0] = 0;
219
image->pitches[1] = width2;
220
image->offsets[1] = size + size2;
221
image->pitches[2] = width2;
222
image->offsets[2] = size;
223
image->data_size = size + 2 * size2;
225
case VA_FOURCC('A','R','G','B'):
226
case VA_FOURCC('A','B','G','R'):
227
case VA_FOURCC('B','G','R','A'):
228
case VA_FOURCC('R','G','B','A'):
229
case VA_FOURCC('U','Y','V','Y'):
230
case VA_FOURCC('Y','U','Y','V'):
231
image->num_planes = 1;
232
image->pitches[0] = width * 4;
233
image->offsets[0] = 0;
234
image->data_size = image->offsets[0] + image->pitches[0] * height;
236
case VA_FOURCC('I','A','4','4'):
237
case VA_FOURCC('A','I','4','4'):
238
image->num_planes = 1;
239
image->pitches[0] = width;
240
image->offsets[0] = 0;
241
image->data_size = image->offsets[0] + image->pitches[0] * height;
243
case VA_FOURCC('I','A','8','8'):
244
case VA_FOURCC('A','I','8','8'):
245
image->num_planes = 1;
246
image->pitches[0] = width * 2;
247
image->offsets[0] = 0;
248
image->data_size = image->offsets[0] + image->pitches[0] * height;
254
va_status = vdpau_CreateBuffer(ctx, 0, VAImageBufferType,
255
image->data_size, 1, NULL,
257
if (va_status != VA_STATUS_SUCCESS)
260
obj_image->vdp_rgba_output_surface = VDP_INVALID_HANDLE;
261
obj_image->vdp_format_type = m->vdp_format_type;
262
obj_image->vdp_format = m->vdp_format;
263
obj_image->vdp_palette = NULL;
265
image->image_id = image_id;
266
image->format = *format;
267
image->width = width;
268
image->height = height;
269
image->num_palette_entries = m->num_palette_entries;
270
image->entry_bytes = m->entry_bytes;
271
for (i = 0; i < image->entry_bytes; i++)
272
image->component_order[i] = m->component_order[i];
274
image->component_order[i] = 0;
277
return VA_STATUS_SUCCESS;
280
vdpau_DestroyImage(ctx, image_id);
287
VADriverContextP ctx,
291
VDPAU_DRIVER_DATA_INIT;
293
object_image_p obj_image = VDPAU_IMAGE(image_id);
295
return VA_STATUS_ERROR_INVALID_IMAGE;
297
if (obj_image->vdp_rgba_output_surface != VDP_INVALID_HANDLE)
298
vdpau_output_surface_destroy(driver_data,
299
obj_image->vdp_rgba_output_surface);
301
if (obj_image->vdp_palette) {
302
free(obj_image->vdp_palette);
303
obj_image->vdp_palette = NULL;
306
VABufferID buf = obj_image->image.buf;
307
object_heap_free(&driver_data->image_heap, (object_base_p)obj_image);
308
return vdpau_DestroyBuffer(ctx, buf);
314
VADriverContextP ctx,
320
return VA_STATUS_ERROR_OPERATION_FAILED;
326
vdpau_driver_data_t *driver_data,
327
object_image_p obj_image,
328
const unsigned char *palette
331
if (obj_image->vdp_format_type != VDP_IMAGE_FORMAT_TYPE_INDEXED)
332
return VA_STATUS_ERROR_OPERATION_FAILED;
334
if (!obj_image->vdp_palette) {
335
obj_image->vdp_palette = malloc(4 * obj_image->image.num_palette_entries);
336
if (!obj_image->vdp_palette)
337
return VA_STATUS_ERROR_ALLOCATION_FAILED;
341
for (i = 0; i < obj_image->image.num_palette_entries; i++) {
342
/* B8G8R8X8 format */
343
obj_image->vdp_palette[i] = ((palette[3*i + 0] << 16) |
344
(palette[3*i + 1] << 8) |
347
return VA_STATUS_SUCCESS;
352
vdpau_SetImagePalette(
353
VADriverContextP ctx,
355
unsigned char *palette
358
VDPAU_DRIVER_DATA_INIT;
360
object_image_p obj_image = VDPAU_IMAGE(image);
362
return VA_STATUS_ERROR_INVALID_IMAGE;
364
return set_image_palette(driver_data, obj_image, palette);
367
// Get image from surface
370
vdpau_driver_data_t *driver_data,
371
object_surface_p obj_surface,
372
object_image_p obj_image,
373
const VARectangle *rect
376
VAImage * const image = &obj_image->image;
377
VdpStatus vdp_status;
379
unsigned int src_stride[3];
382
object_buffer_p obj_buffer = VDPAU_BUFFER(image->buf);
384
return VA_STATUS_ERROR_INVALID_BUFFER;
386
for (i = 0; i < image->num_planes; i++) {
387
src[i] = (uint8_t *)obj_buffer->buffer_data + image->offsets[i];
388
src_stride[i] = image->pitches[i];
391
switch (obj_image->vdp_format_type) {
392
case VDP_IMAGE_FORMAT_TYPE_YCBCR: {
393
/* VDPAU only supports full video surface readback */
396
obj_surface->width != rect->width ||
397
obj_surface->height != rect->height)
398
return VA_STATUS_ERROR_OPERATION_FAILED;
400
vdp_status = vdpau_video_surface_get_bits_ycbcr(
402
obj_surface->vdp_surface,
403
obj_image->vdp_format,
408
case VDP_IMAGE_FORMAT_TYPE_RGBA: {
409
if (obj_image->vdp_rgba_output_surface == VA_INVALID_ID) {
410
vdp_status = vdpau_output_surface_create(
412
driver_data->vdp_device,
413
obj_image->vdp_format,
414
obj_image->image.width,
415
obj_image->image.height,
416
&obj_image->vdp_rgba_output_surface
418
if (vdp_status != VDP_STATUS_OK)
419
return vdpau_get_VAStatus(driver_data, vdp_status);
423
vdp_rect.x0 = rect->x;
424
vdp_rect.y0 = rect->y;
425
vdp_rect.x1 = rect->x + rect->width;
426
vdp_rect.y1 = rect->y + rect->height;
427
vdp_status = video_mixer_render(
430
obj_image->vdp_rgba_output_surface,
435
if (vdp_status != VDP_STATUS_OK)
436
return vdpau_get_VAStatus(driver_data, vdp_status);
438
vdp_status = vdpau_output_surface_get_bits_native(
440
obj_image->vdp_rgba_output_surface,
447
return VA_STATUS_ERROR_OPERATION_FAILED;
449
return vdpau_get_VAStatus(driver_data, vdp_status);
455
VADriverContextP ctx,
464
VDPAU_DRIVER_DATA_INIT;
466
object_surface_p obj_surface = VDPAU_SURFACE(surface);
468
return VA_STATUS_ERROR_INVALID_SURFACE;
470
object_image_p obj_image = VDPAU_IMAGE(image);
472
return VA_STATUS_ERROR_INVALID_IMAGE;
478
rect.height = height;
479
return get_image(driver_data, obj_surface, obj_image, &rect);
482
// Put image to surface
485
vdpau_driver_data_t *driver_data,
486
object_surface_p obj_surface,
487
object_image_p obj_image,
488
const VARectangle *src_rect,
489
const VARectangle *dst_rect
492
VAImage * const image = &obj_image->image;
493
VdpStatus vdp_status;
495
unsigned int src_stride[3];
499
/* Don't do anything if the surface is used for rendering for example */
500
/* XXX: VDPAU has no API to inform when decoding is completed... */
501
if (obj_surface->va_surface_status != VASurfaceReady)
502
return VA_STATUS_ERROR_SURFACE_BUSY;
505
/* RGBA to video surface requires color space conversion */
506
if (obj_image->vdp_rgba_output_surface != VDP_INVALID_HANDLE)
507
return VA_STATUS_ERROR_OPERATION_FAILED;
509
/* VDPAU does not support partial video surface updates */
510
if (src_rect->x != 0 ||
512
src_rect->width != image->width ||
513
src_rect->height != image->height)
514
return VA_STATUS_ERROR_OPERATION_FAILED;
515
if (dst_rect->x != 0 ||
517
dst_rect->width != obj_surface->width ||
518
dst_rect->height != obj_surface->height)
519
return VA_STATUS_ERROR_OPERATION_FAILED;
520
if (src_rect->width != dst_rect->width ||
521
src_rect->height != dst_rect->height)
522
return VA_STATUS_ERROR_OPERATION_FAILED;
524
object_buffer_p obj_buffer = VDPAU_BUFFER(image->buf);
526
return VA_STATUS_ERROR_INVALID_BUFFER;
528
for (i = 0; i < image->num_planes; i++) {
529
src[i] = (uint8_t *)obj_buffer->buffer_data + image->offsets[i];
530
src_stride[i] = image->pitches[i];
533
/* XXX: only support YCbCr surfaces for now */
534
if (obj_image->vdp_format_type != VDP_IMAGE_FORMAT_TYPE_YCBCR)
535
return VA_STATUS_ERROR_OPERATION_FAILED;
537
vdp_status = vdpau_video_surface_put_bits_ycbcr(
539
obj_surface->vdp_surface,
540
obj_image->vdp_format,
543
return vdpau_get_VAStatus(driver_data, vdp_status);
549
VADriverContextP ctx,
560
VDPAU_DRIVER_DATA_INIT;
562
object_surface_p obj_surface = VDPAU_SURFACE(surface);
564
return VA_STATUS_ERROR_INVALID_SURFACE;
566
object_image_p obj_image = VDPAU_IMAGE(image);
568
return VA_STATUS_ERROR_INVALID_IMAGE;
570
VARectangle src_rect, dst_rect;
573
src_rect.width = width;
574
src_rect.height = height;
577
dst_rect.width = width;
578
dst_rect.height = height;
579
return put_image(driver_data, obj_surface, obj_image, &src_rect, &dst_rect);
585
VADriverContextP ctx,
590
unsigned int src_width,
591
unsigned int src_height,
594
unsigned int dest_width,
595
unsigned int dest_height
598
VDPAU_DRIVER_DATA_INIT;
600
object_surface_p obj_surface = VDPAU_SURFACE(surface);
602
return VA_STATUS_ERROR_INVALID_SURFACE;
604
object_image_p obj_image = VDPAU_IMAGE(image);
606
return VA_STATUS_ERROR_INVALID_IMAGE;
608
VARectangle src_rect, dst_rect;
611
src_rect.width = src_width;
612
src_rect.height = src_height;
615
dst_rect.width = dest_width;
616
dst_rect.height = dest_height;
617
return put_image(driver_data, obj_surface, obj_image, &src_rect, &dst_rect);