2
* vdpau_subpic.c - VDPAU backend for VA API (VA subpictures)
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_subpic.h"
23
#include "vdpau_video.h"
24
#include "vdpau_image.h"
25
#include "vdpau_buffer.h"
32
// List of supported subpicture formats
34
VdpImageFormatType vdp_format_type;
36
VAImageFormat va_format;
37
unsigned int va_flags;
38
} vdpau_subpic_format_map_t;
40
static const vdpau_subpic_format_map_t
41
vdpau_subpic_formats_map[VDPAU_MAX_SUBPICTURE_FORMATS + 1] = {
42
{ VDP_IMAGE_FORMAT_TYPE_INDEXED, VDP_INDEXED_FORMAT_A4I4,
43
{ VA_FOURCC('A','I','4','4'), VA_MSB_FIRST, 8, },
45
{ VDP_IMAGE_FORMAT_TYPE_INDEXED, VDP_INDEXED_FORMAT_I4A4,
46
{ VA_FOURCC('I','A','4','4'), VA_MSB_FIRST, 8, },
48
{ VDP_IMAGE_FORMAT_TYPE_INDEXED, VDP_INDEXED_FORMAT_A8I8,
49
{ VA_FOURCC('A','I','8','8'), VA_MSB_FIRST, 16, },
51
{ VDP_IMAGE_FORMAT_TYPE_INDEXED, VDP_INDEXED_FORMAT_I8A8,
52
{ VA_FOURCC('I','A','8','8'), VA_MSB_FIRST, 16, },
54
#ifdef WORDS_BIGENDIAN
55
{ VDP_IMAGE_FORMAT_TYPE_RGBA, VDP_RGBA_FORMAT_B8G8R8A8,
56
{ VA_FOURCC('A','R','G','B'), VA_MSB_FIRST, 32,
57
32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 },
59
{ VDP_IMAGE_FORMAT_TYPE_RGBA, VDP_RGBA_FORMAT_R8G8B8A8,
60
{ VA_FOURCC('A','B','G','R'), VA_MSB_FIRST, 32,
61
32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 },
64
{ VDP_IMAGE_FORMAT_TYPE_RGBA, VDP_RGBA_FORMAT_B8G8R8A8,
65
{ VA_FOURCC('B','G','R','A'), VA_LSB_FIRST, 32,
66
32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 },
68
{ VDP_IMAGE_FORMAT_TYPE_RGBA, VDP_RGBA_FORMAT_R8G8B8A8,
69
{ VA_FOURCC('R','G','B','A'), VA_LSB_FIRST, 32,
70
32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 },
73
{ 0, VDP_INVALID_HANDLE, }
76
// Returns a suitable VDPAU subpicture format for the specified VA image format
77
static const vdpau_subpic_format_map_t *get_format(const VAImageFormat *format)
80
for (i = 0; vdpau_subpic_formats_map[i].va_format.fourcc != 0; i++) {
81
const vdpau_subpic_format_map_t * const m = &vdpau_subpic_formats_map[i];
82
if (m->va_format.fourcc == format->fourcc &&
83
(m->vdp_format_type == VDP_IMAGE_FORMAT_TYPE_RGBA ?
84
(m->va_format.byte_order == format->byte_order &&
85
m->va_format.red_mask == format->red_mask &&
86
m->va_format.green_mask == format->green_mask &&
87
m->va_format.blue_mask == format->blue_mask &&
88
m->va_format.alpha_mask == format->alpha_mask) : 1))
94
// Checks whether the VDPAU implementation supports the specified image format
97
vdpau_driver_data_t *driver_data,
98
const vdpau_subpic_format_map_t *format)
100
VdpBool is_supported = VDP_FALSE;
101
VdpStatus vdp_status;
102
uint32_t max_width, max_height;
104
switch (format->vdp_format_type) {
105
case VDP_IMAGE_FORMAT_TYPE_RGBA:
106
vdp_status = vdpau_bitmap_surface_query_capabilities(
108
driver_data->vdp_device,
115
case VDP_IMAGE_FORMAT_TYPE_INDEXED:
116
vdp_status = vdpau_output_surface_query_put_bits_indexed_capabilities(
118
driver_data->vdp_device,
119
VDP_RGBA_FORMAT_B8G8R8A8,
121
VDP_COLOR_TABLE_FORMAT_B8G8R8X8,
126
vdp_status = VDP_STATUS_ERROR;
129
return vdp_status == VDP_STATUS_OK && is_supported;
132
// Append association to the subpicture
134
subpicture_add_association(
135
object_subpicture_p obj_subpicture,
136
SubpictureAssociationP assoc
139
SubpictureAssociationP *assocs;
140
assocs = realloc_buffer(&obj_subpicture->assocs,
141
&obj_subpicture->assocs_count_max,
142
1 + obj_subpicture->assocs_count,
143
sizeof(obj_subpicture->assocs[0]));
147
assocs[obj_subpicture->assocs_count++] = assoc;
151
// Remove association at the specified index from the subpicture
153
subpicture_remove_association_at(object_subpicture_p obj_subpicture, int index)
155
ASSERT(obj_subpicture->assocs && obj_subpicture->assocs_count > 0);
156
if (!obj_subpicture->assocs || obj_subpicture->assocs_count == 0)
159
/* Replace with the last association */
160
const unsigned int last = obj_subpicture->assocs_count - 1;
161
obj_subpicture->assocs[index] = obj_subpicture->assocs[last];
162
obj_subpicture->assocs[last] = NULL;
163
obj_subpicture->assocs_count--;
167
// Remove association from the subpicture
169
subpicture_remove_association(
170
object_subpicture_p obj_subpicture,
171
SubpictureAssociationP assoc
174
ASSERT(obj_subpicture->assocs && obj_subpicture->assocs_count > 0);
175
if (!obj_subpicture->assocs || obj_subpicture->assocs_count == 0)
179
for (i = 0; i < obj_subpicture->assocs_count; i++) {
180
if (obj_subpicture->assocs[i] == assoc)
181
return subpicture_remove_association_at(obj_subpicture, i);
186
// Associate one surface to the subpicture
188
subpicture_associate_1(
189
object_subpicture_p obj_subpicture,
190
object_surface_p obj_surface,
191
const VARectangle *src_rect,
192
const VARectangle *dst_rect,
196
/* XXX: flags are not supported */
198
return VA_STATUS_ERROR_FLAG_NOT_SUPPORTED;
200
SubpictureAssociationP assoc = malloc(sizeof(*assoc));
202
return VA_STATUS_ERROR_ALLOCATION_FAILED;
204
assoc->subpicture = obj_subpicture->base.id;
205
assoc->surface = obj_surface->base.id;
206
assoc->src_rect = *src_rect;
207
assoc->dst_rect = *dst_rect;
208
assoc->flags = flags;
210
VAStatus status = surface_add_association(obj_surface, assoc);
211
if (status != VA_STATUS_SUCCESS) {
216
if (subpicture_add_association(obj_subpicture, assoc) < 0) {
217
surface_remove_association(obj_surface, assoc);
219
return VA_STATUS_ERROR_ALLOCATION_FAILED;
221
return VA_STATUS_SUCCESS;
224
// Associate surfaces to the subpicture
226
associate_subpicture(
227
vdpau_driver_data_t *driver_data,
228
object_subpicture_p obj_subpicture,
229
VASurfaceID *surfaces,
230
unsigned int num_surfaces,
231
const VARectangle *src_rect,
232
const VARectangle *dst_rect,
239
for (i = 0; i < num_surfaces; i++) {
240
object_surface_p const obj_surface = VDPAU_SURFACE(surfaces[i]);
242
return VA_STATUS_ERROR_INVALID_SURFACE;
243
status = subpicture_associate_1(obj_subpicture, obj_surface,
244
src_rect, dst_rect, flags);
245
if (status != VA_STATUS_SUCCESS)
248
return VA_STATUS_SUCCESS;
251
// Deassociate one surface from the subpicture
253
subpicture_deassociate_1(
254
object_subpicture_p obj_subpicture,
255
object_surface_p obj_surface
258
ASSERT(obj_subpicture->assocs && obj_subpicture->assocs_count > 0);
259
if (!obj_subpicture->assocs || obj_subpicture->assocs_count == 0)
260
return VA_STATUS_ERROR_OPERATION_FAILED;
263
for (i = 0; i < obj_subpicture->assocs_count; i++) {
264
SubpictureAssociationP const assoc = obj_subpicture->assocs[i];
266
if (assoc && assoc->surface == obj_surface->base.id) {
267
surface_remove_association(obj_surface, assoc);
268
subpicture_remove_association_at(obj_subpicture, i);
270
return VA_STATUS_SUCCESS;
273
return VA_STATUS_ERROR_OPERATION_FAILED;
276
// Deassociate surfaces from the subpicture
278
deassociate_subpicture(
279
vdpau_driver_data_t *driver_data,
280
object_subpicture_p obj_subpicture,
281
VASurfaceID *surfaces,
282
unsigned int num_surfaces
285
VAStatus status, error = VA_STATUS_SUCCESS;
288
for (i = 0; i < num_surfaces; i++) {
289
object_surface_p const obj_surface = VDPAU_SURFACE(surfaces[i]);
291
return VA_STATUS_ERROR_INVALID_SURFACE;
292
status = subpicture_deassociate_1(obj_subpicture, obj_surface);
293
if (status != VA_STATUS_SUCCESS) {
294
/* Simply report the first error to the user */
295
if (error == VA_STATUS_SUCCESS)
302
// Commit subpicture to VDPAU surface
305
vdpau_driver_data_p driver_data,
306
object_subpicture_p obj_subpicture
309
object_image_p obj_image = VDPAU_IMAGE(obj_subpicture->image_id);
311
return VA_STATUS_ERROR_INVALID_IMAGE;
313
ASSERT(obj_subpicture->width == obj_image->image.width);
314
if (obj_subpicture->width != obj_image->image.width)
315
return VA_STATUS_ERROR_OPERATION_FAILED;
317
ASSERT(obj_subpicture->height == obj_image->image.height);
318
if (obj_subpicture->height != obj_image->image.height)
319
return VA_STATUS_ERROR_OPERATION_FAILED;
321
object_buffer_p obj_buffer = VDPAU_BUFFER(obj_image->image.buf);
323
return VA_STATUS_ERROR_INVALID_BUFFER;
325
/* Update video surface only if the image (hence its buffer) was
326
updated since our last synchronisation.
328
NOTE: this assumes the user really unmaps the buffer when he is
329
done with it, as it is actually required */
330
if (obj_subpicture->last_commit >= obj_buffer->mtime)
331
return VA_STATUS_SUCCESS;
334
dirty_rect.x0 = obj_subpicture->width;
335
dirty_rect.y0 = obj_subpicture->height;
340
for (i = 0; i < obj_subpicture->assocs_count; i++) {
341
const VARectangle * const rect = &obj_subpicture->assocs[i]->src_rect;
342
dirty_rect.x0 = MIN(dirty_rect.x0, rect->x);
343
dirty_rect.y0 = MIN(dirty_rect.y0, rect->y);
344
dirty_rect.x1 = MAX(dirty_rect.x1, rect->x + rect->width);
345
dirty_rect.y1 = MAX(dirty_rect.y1, rect->y + rect->height);
350
src_stride = obj_image->image.pitches[0];
351
src = ((uint8_t *)obj_buffer->buffer_data + obj_image->image.offsets[0] +
352
dirty_rect.y0 * obj_image->image.pitches[0] +
353
dirty_rect.x0 * ((obj_image->image.format.bits_per_pixel + 7) / 8));
355
VdpStatus vdp_status;
356
switch (obj_subpicture->vdp_format_type) {
357
case VDP_IMAGE_FORMAT_TYPE_RGBA:
358
vdp_status = vdpau_bitmap_surface_put_bits_native(
360
obj_subpicture->vdp_bitmap_surface,
365
case VDP_IMAGE_FORMAT_TYPE_INDEXED:
366
vdp_status = vdpau_output_surface_put_bits_indexed(
368
obj_subpicture->vdp_output_surface,
369
obj_subpicture->vdp_format,
372
VDP_COLOR_TABLE_FORMAT_B8G8R8X8,
373
obj_image->vdp_palette
377
vdp_status = VDP_STATUS_ERROR;
380
if (vdp_status != VDP_STATUS_OK)
381
return vdpau_get_VAStatus(driver_data, vdp_status);
383
obj_subpicture->last_commit = obj_buffer->mtime;
384
return VA_STATUS_SUCCESS;
387
// Create subpicture with image
390
vdpau_driver_data_t *driver_data,
391
object_image_p obj_image,
392
VASubpictureID *subpicture
395
*subpicture = object_heap_allocate(&driver_data->subpicture_heap);
396
if (*subpicture == VA_INVALID_ID)
397
return VA_STATUS_ERROR_ALLOCATION_FAILED;
399
object_subpicture_p obj_subpicture = VDPAU_SUBPICTURE(*subpicture);
400
ASSERT(obj_subpicture);
402
return VA_STATUS_ERROR_ALLOCATION_FAILED;
404
const vdpau_subpic_format_map_t *m = get_format(&obj_image->image.format);
405
if (!is_supported_format(driver_data, m))
406
return VA_STATUS_ERROR_UNKNOWN; /* VA_STATUS_ERROR_UNSUPPORTED_FORMAT */
408
obj_subpicture->image_id = obj_image->base.id;
409
obj_subpicture->assocs = NULL;
410
obj_subpicture->assocs_count = 0;
411
obj_subpicture->assocs_count_max = 0;
412
obj_subpicture->width = obj_image->image.width;
413
obj_subpicture->height = obj_image->image.height;
414
obj_subpicture->vdp_bitmap_surface = VDP_INVALID_HANDLE;
415
obj_subpicture->vdp_output_surface = VDP_INVALID_HANDLE;
416
obj_subpicture->last_commit = 0;
417
obj_subpicture->vdp_format_type = m->vdp_format_type;
418
obj_subpicture->vdp_format = m->vdp_format;
420
VdpStatus vdp_status;
421
switch (obj_subpicture->vdp_format_type) {
422
case VDP_IMAGE_FORMAT_TYPE_RGBA:
423
vdp_status = vdpau_bitmap_surface_create(
425
driver_data->vdp_device,
426
obj_subpicture->vdp_format,
427
obj_subpicture->width,
428
obj_subpicture->height,
430
&obj_subpicture->vdp_bitmap_surface
433
case VDP_IMAGE_FORMAT_TYPE_INDEXED:
434
vdp_status = vdpau_output_surface_create(
436
driver_data->vdp_device,
437
VDP_RGBA_FORMAT_B8G8R8A8,
438
obj_subpicture->width,
439
obj_subpicture->height,
440
&obj_subpicture->vdp_output_surface
444
vdp_status = VDP_STATUS_ERROR;
447
return vdpau_get_VAStatus(driver_data, vdp_status);
450
// Destroy subpicture
453
vdpau_driver_data_t *driver_data,
454
object_subpicture_p obj_subpicture
457
object_surface_p obj_surface;
461
if (obj_subpicture->assocs) {
462
const unsigned int n_assocs = obj_subpicture->assocs_count;
463
for (i = 0, n = 0; i < n_assocs; i++) {
464
SubpictureAssociationP const assoc = obj_subpicture->assocs[0];
467
obj_surface = VDPAU_SURFACE(assoc->surface);
471
status = subpicture_deassociate_1(obj_subpicture, obj_surface);
472
if (status == VA_STATUS_SUCCESS)
476
vdpau_error_message("vaDestroySubpicture(): subpicture 0x%08x still "
477
"has %d surfaces associated to it\n",
478
obj_subpicture->base.id, n_assocs - n);
479
free(obj_subpicture->assocs);
480
obj_subpicture->assocs = NULL;
482
obj_subpicture->assocs_count = 0;
483
obj_subpicture->assocs_count_max = 0;
485
if (obj_subpicture->vdp_bitmap_surface != VDP_INVALID_HANDLE) {
486
vdpau_bitmap_surface_destroy(
488
obj_subpicture->vdp_bitmap_surface
490
obj_subpicture->vdp_bitmap_surface = VDP_INVALID_HANDLE;
493
if (obj_subpicture->vdp_output_surface != VDP_INVALID_HANDLE) {
494
vdpau_output_surface_destroy(
496
obj_subpicture->vdp_output_surface
498
obj_subpicture->vdp_output_surface = VDP_INVALID_HANDLE;
501
obj_subpicture->image_id = VA_INVALID_ID;
502
object_heap_free(&driver_data->subpicture_heap,
503
(object_base_p)obj_subpicture);
506
// vaQuerySubpictureFormats
508
vdpau_QuerySubpictureFormats(
509
VADriverContextP ctx,
510
VAImageFormat *format_list,
512
unsigned int *num_formats
515
VDPAU_DRIVER_DATA_INIT;
518
for (n = 0; vdpau_subpic_formats_map[n].va_format.fourcc != 0; n++) {
519
const vdpau_subpic_format_map_t * const m = &vdpau_subpic_formats_map[n];
520
if (is_supported_format(driver_data, m)) {
522
format_list[n] = m->va_format;
524
flags[n] = m->va_flags;
531
return VA_STATUS_SUCCESS;
534
// vaCreateSubpicture
536
vdpau_CreateSubpicture(
537
VADriverContextP ctx,
539
VASubpictureID *subpicture
542
VDPAU_DRIVER_DATA_INIT;
545
return VA_STATUS_ERROR_INVALID_PARAMETER;
547
object_image_p obj_image = VDPAU_IMAGE(image);
549
return VA_STATUS_ERROR_INVALID_IMAGE;
551
return create_subpicture(driver_data, obj_image, subpicture);
554
// vaDestroySubpicture
556
vdpau_DestroySubpicture(
557
VADriverContextP ctx,
558
VASubpictureID subpicture
561
VDPAU_DRIVER_DATA_INIT;
563
object_subpicture_p obj_subpicture = VDPAU_SUBPICTURE(subpicture);
565
return VA_STATUS_ERROR_INVALID_SUBPICTURE;
567
destroy_subpicture(driver_data, obj_subpicture);
568
return VA_STATUS_SUCCESS;
571
// vaSetSubpictureImage
573
vdpau_SetSubpictureImage(
574
VADriverContextP ctx,
575
VASubpictureID subpicture,
579
VDPAU_DRIVER_DATA_INIT;
581
object_subpicture_p obj_subpicture = VDPAU_SUBPICTURE(subpicture);
583
return VA_STATUS_ERROR_INVALID_SUBPICTURE;
585
object_image_p obj_image = VDPAU_IMAGE(image);
587
return VA_STATUS_ERROR_INVALID_IMAGE;
589
obj_subpicture->image_id = obj_image->base.id;
590
return VA_STATUS_SUCCESS;
593
// vaSetSubpicturePalette (not a PUBLIC interface)
595
vdpau_SetSubpicturePalette(
596
VADriverContextP ctx,
597
VASubpictureID subpicture,
598
unsigned char *palette
602
return VA_STATUS_ERROR_OPERATION_FAILED;
605
// vaSetSubpictureChromaKey
607
vdpau_SetSubpictureChromakey(
608
VADriverContextP ctx,
609
VASubpictureID subpicture,
610
unsigned int chromakey_min,
611
unsigned int chromakey_max,
612
unsigned int chromakey_mask
615
VDPAU_DRIVER_DATA_INIT;
617
object_subpicture_p obj_subpicture = VDPAU_SUBPICTURE(subpicture);
619
return VA_STATUS_ERROR_INVALID_SUBPICTURE;
621
obj_subpicture->chromakey_min = chromakey_min;
622
obj_subpicture->chromakey_max = chromakey_max;
623
obj_subpicture->chromakey_mask = chromakey_mask;
624
return VA_STATUS_SUCCESS;
627
// vaSetSubpictureGlobalAlpha
629
vdpau_SetSubpictureGlobalAlpha(
630
VADriverContextP ctx,
631
VASubpictureID subpicture,
635
VDPAU_DRIVER_DATA_INIT;
637
object_subpicture_p obj_subpicture = VDPAU_SUBPICTURE(subpicture);
639
return VA_STATUS_ERROR_INVALID_SUBPICTURE;
641
obj_subpicture->alpha = global_alpha;
642
return VA_STATUS_SUCCESS;
645
// vaAssociateSubpicture
647
vdpau_AssociateSubpicture(
648
VADriverContextP ctx,
649
VASubpictureID subpicture,
650
VASurfaceID *target_surfaces,
656
unsigned short width,
657
unsigned short height,
661
VDPAU_DRIVER_DATA_INIT;
663
if (!target_surfaces || num_surfaces == 0)
664
return VA_STATUS_SUCCESS;
666
object_subpicture_p obj_subpicture = VDPAU_SUBPICTURE(subpicture);
668
return VA_STATUS_ERROR_INVALID_SUBPICTURE;
670
VARectangle src_rect, dst_rect;
673
src_rect.width = width;
674
src_rect.height = height;
677
dst_rect.width = width;
678
dst_rect.height = height;
679
return associate_subpicture(driver_data, obj_subpicture,
680
target_surfaces, num_surfaces,
681
&src_rect, &dst_rect, flags);
684
// vaAssociateSubpicture2
686
vdpau_AssociateSubpicture_full(
687
VADriverContextP ctx,
688
VASubpictureID subpicture,
689
VASurfaceID *target_surfaces,
693
unsigned short src_width,
694
unsigned short src_height,
697
unsigned short dest_width,
698
unsigned short dest_height,
702
VDPAU_DRIVER_DATA_INIT;
704
if (!target_surfaces || num_surfaces == 0)
705
return VA_STATUS_SUCCESS;
707
object_subpicture_p obj_subpicture = VDPAU_SUBPICTURE(subpicture);
709
return VA_STATUS_ERROR_INVALID_SUBPICTURE;
711
VARectangle src_rect, dst_rect;
714
src_rect.width = src_width;
715
src_rect.height = src_height;
718
dst_rect.width = dest_width;
719
dst_rect.height = dest_height;
720
return associate_subpicture(driver_data, obj_subpicture,
721
target_surfaces, num_surfaces,
722
&src_rect, &dst_rect, flags);
725
// vaDeassociateSubpicture
727
vdpau_DeassociateSubpicture(
728
VADriverContextP ctx,
729
VASubpictureID subpicture,
730
VASurfaceID *target_surfaces,
734
VDPAU_DRIVER_DATA_INIT;
736
if (!target_surfaces || num_surfaces == 0)
737
return VA_STATUS_SUCCESS;
739
object_subpicture_p obj_subpicture = VDPAU_SUBPICTURE(subpicture);
741
return VA_STATUS_ERROR_INVALID_SUBPICTURE;
743
return deassociate_subpicture(driver_data, obj_subpicture,
744
target_surfaces, num_surfaces);