psb_output.c revision f31d5416a60f83e184b0906a7ec77ba021840531
1/*
2 * Copyright (c) 2011 Intel Corporation. All Rights Reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sub license, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial portions
14 * of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
19 * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
20 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 *    Shengquan Yuan  <shengquan.yuan@intel.com>
26 *    Zhaohan Ren  <zhaohan.ren@intel.com>
27 *    Jason Hu <jason.hu@intel.com>
28 *
29 */
30
31#ifndef ANDROID
32#include <X11/Xutil.h>
33#include <X11/extensions/Xrandr.h>
34#include <va/va_dricommon.h>
35#include "x11/psb_x11.h"
36#include "x11/psb_xrandr.h"
37#endif
38#include <va/va_backend.h>
39#include <dlfcn.h>
40#include <stdlib.h>
41#include "psb_output.h"
42#include "psb_surface.h"
43#include "psb_buffer.h"
44#include "psb_surface_ext.h"
45#include "pnw_rotate.h"
46#include <stdio.h>
47#include <string.h>
48#include <stdarg.h>
49#include <wsbm/wsbm_manager.h>
50#include "psb_drv_debug.h"
51#include <string.h>
52#include <unistd.h>
53#include <sys/ioctl.h>
54
55#define INIT_DRIVER_DATA        psb_driver_data_p driver_data = (psb_driver_data_p) ctx->pDriverData;
56
57#define SURFACE(id)     ((object_surface_p) object_heap_lookup( &driver_data->surface_heap, id ))
58#define BUFFER(id)  ((object_buffer_p) object_heap_lookup( &driver_data->buffer_heap, id ))
59#define IMAGE(id)  ((object_image_p) object_heap_lookup( &driver_data->image_heap, id ))
60#define SUBPIC(id)  ((object_subpic_p) object_heap_lookup( &driver_data->subpic_heap, id ))
61#define CONTEXT(id) ((object_context_p) object_heap_lookup( &driver_data->context_heap, id ))
62
63
64/* surfaces link list associated with a subpicture */
65typedef struct _subpic_surface {
66    VASurfaceID surface_id;
67    struct _subpic_surface *next;
68} subpic_surface_s, *subpic_surface_p;
69
70
71static VAImageFormat psb__SubpicFormat[] = {
72    psb__ImageRGBA,
73    //psb__ImageAYUV,
74    //psb__ImageAI44
75};
76
77static VAImageFormat psb__CreateImageFormat[] = {
78    psb__ImageNV12,
79    psb__ImageRGBA,
80    //psb__ImageAYUV,
81    //psb__ImageAI44,
82    psb__ImageYV16,
83    psb__ImageYV32
84};
85
86unsigned char *psb_x11_output_init(VADriverContextP ctx);
87VAStatus psb_x11_output_deinit(VADriverContextP ctx);
88unsigned char *psb_android_output_init(VADriverContextP ctx);
89VAStatus psb_android_output_deinit(VADriverContextP ctx);
90
91int psb_coverlay_init(VADriverContextP ctx);
92int psb_coverlay_deinit(VADriverContextP ctx);
93
94VAStatus psb_initOutput(VADriverContextP ctx)
95{
96    INIT_DRIVER_DATA;
97    unsigned char *ws_priv = NULL;
98    char *fps = NULL;
99    char env_value[1024];
100
101    pthread_mutex_init(&driver_data->output_mutex, NULL);
102
103    if (psb_parse_config("PSB_VIDEO_PUTSURFACE_DUMMY", &env_value[0]) == 0) {
104        drv_debug_msg(VIDEO_DEBUG_GENERAL, "vaPutSurface: dummy mode, return directly\n");
105        driver_data->dummy_putsurface = 0;
106
107        return VA_STATUS_SUCCESS;
108    }
109
110    if (psb_parse_config("PSB_VIDEO_FPS", &env_value[0]) == 0) {
111        driver_data->fixed_fps = atoi(env_value);
112        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Throttling at FPS=%d\n", driver_data->fixed_fps);
113    } else
114        driver_data->fixed_fps = 0;
115
116    driver_data->outputmethod_checkinterval = 1;
117    if (psb_parse_config("PSB_VIDEO_INTERVAL", &env_value[0]) == 0) {
118        driver_data->outputmethod_checkinterval = atoi(env_value);
119        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Check output method at %d frames interval\n",
120                                 driver_data->outputmethod_checkinterval);
121    }
122
123    driver_data->cur_displaying_surface = VA_INVALID_SURFACE;
124    driver_data->last_displaying_surface = VA_INVALID_SURFACE;
125
126    psb_InitRotate(ctx);
127
128#ifdef ANDROID
129    ws_priv = psb_android_output_init(ctx);
130    driver_data->is_android = 1;
131#else
132    ws_priv = psb_x11_output_init(ctx);
133    driver_data->is_android = 0;
134#endif
135    driver_data->ws_priv = ws_priv;
136
137
138    //use client textureblit
139    if (driver_data->ctexture == 1) {
140        int ret = psb_ctexture_init(ctx);
141        if (ret != 0)
142            driver_data->ctexture = 0;
143    }
144
145    /*
146    //use texture streaming
147    if (driver_data->ctexstreaming == 1)
148    psb_ctexstreaing_init(ctx);
149    */
150
151    return VA_STATUS_SUCCESS;
152}
153
154VAStatus psb_deinitOutput(
155    VADriverContextP ctx
156)
157{
158    INIT_DRIVER_DATA;
159
160    //use client textureblit
161    if (driver_data->ctexture == 1)
162        psb_ctexture_deinit(ctx);
163
164    if (driver_data->coverlay_init) {
165        psb_coverlay_deinit(ctx);
166        driver_data->coverlay_init = 0;
167    }
168
169#ifndef ANDROID
170    psb_x11_output_deinit(ctx);
171#else
172    psb_android_output_deinit(ctx);
173#endif
174
175    /* free here, but allocate in window system specific */
176    free(driver_data->ws_priv);
177    /*
178    //use texture streaming
179    if (driver_data->ctexstreaming == 1)
180        psb_ctexstreaing_deinit(ctx);
181    */
182    /* clean the displaying surface information in kernel */
183#ifndef _FOR_FPGA_
184    psb_surface_set_displaying(driver_data, 0, 0, NULL);
185#endif
186    pthread_mutex_destroy(&driver_data->output_mutex);
187
188    return VA_STATUS_SUCCESS;
189}
190
191#ifndef VA_STATUS_ERROR_INVALID_IMAGE_FORMAT
192#define VA_STATUS_ERROR_INVALID_IMAGE_FORMAT VA_STATUS_ERROR_UNKNOWN
193#endif
194
195static VAImageFormat *psb__VAImageCheckFourCC(
196    VAImageFormat       *src_format,
197    VAImageFormat       *dst_format,
198    int                 dst_num
199)
200{
201    int i;
202    if (NULL == src_format || dst_format == NULL) {
203        return NULL;
204    }
205
206    /* check VAImage at first */
207    for (i = 0; i < dst_num; i++) {
208        if (dst_format[i].fourcc == src_format->fourcc)
209            return &dst_format[i];
210    }
211
212    drv_debug_msg(VIDEO_DEBUG_ERROR, "Unsupport fourcc 0x%x\n", src_format->fourcc);
213    return NULL;
214}
215
216static void psb__VAImageCheckRegion(
217    object_surface_p surface,
218    VAImage *image,
219    int *src_x,
220    int *src_y,
221    int *dest_x,
222    int *dest_y,
223    int *width,
224    int *height
225)
226{
227    /* check for image */
228    if (*src_x < 0) *src_x = 0;
229    if (*src_x > image->width) *src_x = image->width - 1;
230    if (*src_y < 0) *src_y = 0;
231    if (*src_y > image->height) *src_y = image->height - 1;
232
233    if (((*width) + (*src_x)) > image->width) *width = image->width - *src_x;
234    if (((*height) + (*src_y)) > image->height) *height = image->height - *src_x;
235
236    /* check for surface */
237    if (*dest_x < 0) *dest_x = 0;
238    if (*dest_x > surface->width) *dest_x = surface->width - 1;
239    if (*dest_y < 0) *dest_y = 0;
240    if (*dest_y > surface->height) *dest_y = surface->height - 1;
241
242    if (((*width) + (*dest_x)) > surface->width) *width = surface->width - *dest_x;
243    if (((*height) + (*dest_y)) > surface->height) *height = surface->height - *dest_x;
244}
245
246
247VAStatus psb_QueryImageFormats(
248    VADriverContextP ctx,
249    VAImageFormat *format_list,        /* out */
250    int *num_formats           /* out */
251)
252{
253    VAStatus vaStatus = VA_STATUS_SUCCESS;
254
255    if (NULL == format_list) {
256        vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
257        DEBUG_FAILURE;
258        return vaStatus;
259    }
260    if (NULL == num_formats) {
261        vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
262        DEBUG_FAILURE;
263        return vaStatus;
264    }
265    memcpy(format_list, psb__CreateImageFormat, sizeof(psb__CreateImageFormat));
266    *num_formats = PSB_MAX_IMAGE_FORMATS;
267
268    return VA_STATUS_SUCCESS;
269}
270
271inline int min_POT(int n)
272{
273    if ((n & (n - 1)) == 0) /* already POT */
274        return n;
275
276    return n |= n >> 16, n |= n >> 8, n |= n >> 4, n |= n >> 2, n |= n >> 1, n + 1;
277    /* return ((((n |= n>>16) |= n>>8) |= n>>4) |= n>>2) |= n>>1, n + 1; */
278}
279
280VAStatus psb_CreateImage(
281    VADriverContextP ctx,
282    VAImageFormat *format,
283    int width,
284    int height,
285    VAImage *image     /* out */
286)
287{
288    INIT_DRIVER_DATA;
289    VAImageID imageID;
290    object_image_p obj_image;
291    VAStatus vaStatus = VA_STATUS_SUCCESS;
292    VAImageFormat *img_fmt;
293    int pitch_pot;
294
295    (void)driver_data;
296
297    img_fmt = psb__VAImageCheckFourCC(format, psb__CreateImageFormat,
298                                      sizeof(psb__CreateImageFormat) / sizeof(VAImageFormat));
299    if (img_fmt == NULL)
300        return VA_STATUS_ERROR_UNKNOWN;
301
302    if (NULL == image) {
303        vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
304        return vaStatus;
305    }
306
307    imageID = object_heap_allocate(&driver_data->image_heap);
308    obj_image = IMAGE(imageID);
309    if (NULL == obj_image) {
310        vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
311        return vaStatus;
312    }
313
314    MEMSET_OBJECT(obj_image, struct object_image_s);
315
316    obj_image->image.image_id = imageID;
317    obj_image->image.format = *img_fmt;
318    obj_image->subpic_ref = 0;
319
320    pitch_pot = min_POT(width);
321
322    switch (format->fourcc) {
323    case VA_FOURCC_NV12: {
324        obj_image->image.width = width;
325        obj_image->image.height = height;
326        obj_image->image.data_size = pitch_pot * height /*Y*/ + 2 * (pitch_pot / 2) * (height / 2);/*UV*/
327        obj_image->image.num_planes = 2;
328        obj_image->image.pitches[0] = pitch_pot;
329        obj_image->image.pitches[1] = pitch_pot;
330        obj_image->image.offsets[0] = 0;
331        obj_image->image.offsets[1] = pitch_pot * height;
332        obj_image->image.num_palette_entries = 0;
333        obj_image->image.entry_bytes = 0;
334        obj_image->image.component_order[0] = 'Y';
335        obj_image->image.component_order[1] = 'U';/* fixed me: packed UV packed here! */
336        obj_image->image.component_order[2] = 'V';
337        obj_image->image.component_order[3] = '\0';
338        break;
339    }
340    case VA_FOURCC_AYUV: {
341        obj_image->image.width = width;
342        obj_image->image.height = height;
343        obj_image->image.data_size = 4 * pitch_pot * height;
344        obj_image->image.num_planes = 1;
345        obj_image->image.pitches[0] = 4 * pitch_pot;
346        obj_image->image.num_palette_entries = 0;
347        obj_image->image.entry_bytes = 0;
348        obj_image->image.component_order[0] = 'V';
349        obj_image->image.component_order[1] = 'U';
350        obj_image->image.component_order[2] = 'Y';
351        obj_image->image.component_order[3] = 'A';
352        break;
353    }
354    case VA_FOURCC_RGBA: {
355        obj_image->image.width = width;
356        obj_image->image.height = height;
357        obj_image->image.data_size = 4 * pitch_pot * height;
358        obj_image->image.num_planes = 1;
359        obj_image->image.pitches[0] = 4 * pitch_pot;
360        obj_image->image.num_palette_entries = 0;
361        obj_image->image.entry_bytes = 0;
362        obj_image->image.component_order[0] = 'R';
363        obj_image->image.component_order[1] = 'G';
364        obj_image->image.component_order[2] = 'B';
365        obj_image->image.component_order[3] = 'A';
366        break;
367    }
368    case VA_FOURCC_AI44: {
369        obj_image->image.width = width;
370        obj_image->image.height = height;
371        obj_image->image.data_size = pitch_pot * height;/* one byte one element */
372        obj_image->image.num_planes = 1;
373        obj_image->image.pitches[0] = pitch_pot;
374        obj_image->image.num_palette_entries = 16;
375        obj_image->image.entry_bytes = 4; /* AYUV */
376        obj_image->image.component_order[0] = 'I';
377        obj_image->image.component_order[1] = 'A';
378        obj_image->image.component_order[2] = '\0';
379        obj_image->image.component_order[3] = '\0';
380        break;
381    }
382    case VA_FOURCC_IYUV: {
383        obj_image->image.width = width;
384        obj_image->image.height = height;
385        obj_image->image.data_size = pitch_pot * height /*Y*/ + 2 * (pitch_pot / 2) * (height / 2);/*UV*/
386        obj_image->image.num_planes = 3;
387        obj_image->image.pitches[0] = pitch_pot;
388        obj_image->image.pitches[1] = pitch_pot / 2;
389        obj_image->image.pitches[2] = pitch_pot / 2;
390        obj_image->image.offsets[0] = 0;
391        obj_image->image.offsets[1] = pitch_pot * height;
392        obj_image->image.offsets[2] = pitch_pot * height + (pitch_pot / 2) * (height / 2);
393        obj_image->image.num_palette_entries = 0;
394        obj_image->image.entry_bytes = 0;
395        obj_image->image.component_order[0] = 'Y';
396        obj_image->image.component_order[1] = 'U';
397        obj_image->image.component_order[2] = 'V';
398        obj_image->image.component_order[3] = '\0';
399        break;
400    }
401    case VA_FOURCC_YV32: {
402        obj_image->image.width = width;
403        obj_image->image.height = height;
404        obj_image->image.data_size = 4 * pitch_pot * height;
405        obj_image->image.num_planes = 4;
406        obj_image->image.pitches[0] = pitch_pot;
407        obj_image->image.pitches[1] = pitch_pot;
408        obj_image->image.pitches[2] = pitch_pot;
409        obj_image->image.pitches[3] = pitch_pot;
410        obj_image->image.offsets[0] = 0;
411        obj_image->image.offsets[1] = pitch_pot * height;
412        obj_image->image.offsets[2] = pitch_pot * height * 2;
413        obj_image->image.offsets[3] = pitch_pot * height * 3;
414        obj_image->image.num_palette_entries = 0;
415        obj_image->image.entry_bytes = 0;
416        obj_image->image.component_order[0] = 'V';
417        obj_image->image.component_order[1] = 'U';
418        obj_image->image.component_order[2] = 'Y';
419        obj_image->image.component_order[3] = 'A';
420        break;
421    }
422    default: {
423        vaStatus = VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
424        break;
425    }
426    }
427
428    if (VA_STATUS_SUCCESS == vaStatus) {
429        /* create the buffer */
430        vaStatus = psb__CreateBuffer(driver_data, NULL, VAImageBufferType,
431                                     obj_image->image.data_size, 1, NULL, &obj_image->image.buf);
432    }
433
434    obj_image->derived_surface = 0;
435
436    if (VA_STATUS_SUCCESS != vaStatus) {
437        object_heap_free(&driver_data->image_heap, (object_base_p) obj_image);
438    } else {
439        memcpy(image, &obj_image->image, sizeof(VAImage));
440    }
441
442    return vaStatus;
443}
444
445static int psb_CheckIEDStatus(VADriverContextP ctx)
446{
447    INIT_DRIVER_DATA;
448    struct drm_lnc_video_getparam_arg arg;
449    unsigned long temp;
450    int ret = 0;
451    int ied_status = 0;
452
453    /* not settled, we get it from current HW FRAMESKIP flag */
454    arg.key = IMG_VIDEO_IED_STATE;
455    arg.value = (uint64_t)((unsigned long) & temp);
456    ret = drmCommandWriteRead(driver_data->drm_fd, driver_data->getParamIoctlOffset,
457                              &arg, sizeof(arg));
458    if (ret == 0) {
459        if (temp == 1) {
460            drv_debug_msg(VIDEO_DEBUG_ERROR, "IED is enabled, image is encrypted.\n");
461            return 1;
462        } else {
463            return 0;
464        }
465    } else {
466        drv_debug_msg(VIDEO_DEBUG_ERROR, "Failed to call IMG_VIDEO_IED_STATE.\n");
467        return -1;
468    }
469}
470
471VAStatus psb_DeriveImage(
472    VADriverContextP ctx,
473    VASurfaceID surface,
474    VAImage *image     /* out */
475)
476{
477    INIT_DRIVER_DATA;
478    VAStatus vaStatus = VA_STATUS_SUCCESS;
479    VABufferID bufferID;
480    object_buffer_p obj_buffer;
481    VAImageID imageID;
482    object_image_p obj_image;
483    object_surface_p obj_surface = SURFACE(surface);
484    unsigned int fourcc, fourcc_index = ~0, i;
485    uint32_t srf_buf_ofs = 0;
486    uint32_t ied_state;
487
488    if (NULL == obj_surface) {
489        vaStatus = VA_STATUS_ERROR_INVALID_SURFACE;
490        DEBUG_FAILURE;
491        return vaStatus;
492    }
493
494    if (NULL == image) {
495        vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
496        return vaStatus;
497    }
498
499    if (IS_MFLD(driver_data) && (psb_CheckIEDStatus(ctx) == 1)) {
500        vaStatus = VA_STATUS_ERROR_INVALID_SURFACE;
501        return vaStatus;
502    }
503
504    fourcc = obj_surface->psb_surface->extra_info[4];
505    for (i = 0; i < PSB_MAX_IMAGE_FORMATS; i++) {
506        if (psb__CreateImageFormat[i].fourcc == fourcc) {
507            fourcc_index = i;
508            break;
509        }
510    }
511    if (i == PSB_MAX_IMAGE_FORMATS) {
512        drv_debug_msg(VIDEO_DEBUG_ERROR, "Can't support the Fourcc\n");
513        vaStatus = VA_STATUS_ERROR_OPERATION_FAILED;
514        return vaStatus;
515    }
516
517    /* create the image */
518    imageID = object_heap_allocate(&driver_data->image_heap);
519    obj_image = IMAGE(imageID);
520    if (NULL == obj_image) {
521        vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
522        return vaStatus;
523    }
524
525    MEMSET_OBJECT(obj_image, struct object_image_s);
526
527    /* create a buffer to represent surface buffer */
528    bufferID = object_heap_allocate(&driver_data->buffer_heap);
529    obj_buffer = BUFFER(bufferID);
530    if (NULL == obj_buffer) {
531        object_heap_free(&driver_data->image_heap, (object_base_p) obj_image);
532        vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
533        DEBUG_FAILURE;
534        return vaStatus;
535    }
536    MEMSET_OBJECT(obj_buffer, struct object_buffer_s);
537
538    obj_buffer->type = VAImageBufferType;
539    obj_buffer->buffer_data = NULL;
540    obj_buffer->psb_buffer = &obj_surface->psb_surface->buf;
541    obj_buffer->size = obj_surface->psb_surface->size;
542    obj_buffer->max_num_elements = 0;
543    obj_buffer->alloc_size = obj_buffer->size;
544
545    /* fill obj_image data structure */
546    obj_image->image.image_id = imageID;
547    obj_image->image.format = psb__CreateImageFormat[fourcc_index];
548    obj_image->subpic_ref = 0;
549
550    obj_image->image.buf = bufferID;
551    obj_image->image.width = obj_surface->width;
552    obj_image->image.height = obj_surface->height;
553    obj_image->image.data_size = obj_surface->psb_surface->size;
554
555    srf_buf_ofs = obj_surface->psb_surface->buf.buffer_ofs;
556
557    switch (fourcc) {
558    case VA_FOURCC_NV12: {
559        obj_image->image.num_planes = 2;
560        obj_image->image.pitches[0] = obj_surface->psb_surface->stride;
561        obj_image->image.pitches[1] = obj_surface->psb_surface->stride;
562
563        obj_image->image.offsets[0] = srf_buf_ofs;
564        obj_image->image.offsets[1] = srf_buf_ofs + obj_surface->height * obj_surface->psb_surface->stride;
565        obj_image->image.num_palette_entries = 0;
566        obj_image->image.entry_bytes = 0;
567        obj_image->image.component_order[0] = 'Y';
568        obj_image->image.component_order[1] = 'U';/* fixed me: packed UV packed here! */
569        obj_image->image.component_order[2] = 'V';
570        obj_image->image.component_order[3] = '\0';
571        break;
572    }
573    case VA_FOURCC_YV16: {
574        obj_image->image.num_planes = 3;
575        obj_image->image.pitches[0] = obj_surface->psb_surface->stride;
576        obj_image->image.pitches[1] = obj_surface->psb_surface->stride / 2;
577        obj_image->image.pitches[2] = obj_surface->psb_surface->stride / 2;
578
579        obj_image->image.offsets[0] = srf_buf_ofs;
580        obj_image->image.offsets[1] = srf_buf_ofs + obj_surface->height * obj_surface->psb_surface->stride;
581        obj_image->image.offsets[2] = srf_buf_ofs + obj_surface->height * obj_surface->psb_surface->stride * 3 / 2;
582        obj_image->image.num_palette_entries = 0;
583        obj_image->image.entry_bytes = 0;
584        obj_image->image.component_order[0] = 'Y';
585        obj_image->image.component_order[1] = 'V';/* fixed me: packed UV packed here! */
586        obj_image->image.component_order[2] = 'U';
587        obj_image->image.component_order[3] = '\0';
588        break;
589    }
590    default:
591        break;
592    }
593
594    obj_image->derived_surface = surface; /* this image is derived from a surface */
595    obj_surface->derived_imgcnt++;
596
597    memcpy(image, &obj_image->image, sizeof(VAImage));
598
599    return vaStatus;
600}
601
602VAStatus psb__destroy_image(psb_driver_data_p driver_data, object_image_p obj_image)
603{
604    VAStatus vaStatus = VA_STATUS_SUCCESS;
605
606    if (obj_image->subpic_ref > 0) {
607        vaStatus = VA_STATUS_ERROR_OPERATION_FAILED;
608        return vaStatus;
609    }
610
611    object_surface_p obj_surface = SURFACE(obj_image->derived_surface);
612
613    if (obj_surface == NULL) { /* destroy the buffer */
614        object_buffer_p obj_buffer = BUFFER(obj_image->image.buf);
615        if (NULL == obj_buffer) {
616            vaStatus = VA_STATUS_ERROR_INVALID_BUFFER;
617            DEBUG_FAILURE;
618            return vaStatus;
619        }
620        psb__suspend_buffer(driver_data, obj_buffer);
621    } else {
622        object_buffer_p obj_buffer = BUFFER(obj_image->image.buf);
623        object_heap_free(&driver_data->buffer_heap, &obj_buffer->base);
624        obj_surface->derived_imgcnt--;
625    }
626    object_heap_free(&driver_data->image_heap, (object_base_p) obj_image);
627
628    return VA_STATUS_SUCCESS;
629}
630
631VAStatus psb_DestroyImage(
632    VADriverContextP ctx,
633    VAImageID image
634)
635{
636    INIT_DRIVER_DATA
637    VAStatus vaStatus = VA_STATUS_SUCCESS;
638    object_image_p obj_image;
639
640    obj_image = IMAGE(image);
641    if (NULL == obj_image) {
642        vaStatus = VA_STATUS_ERROR_INVALID_IMAGE;
643        DEBUG_FAILURE;
644        return vaStatus;
645    }
646    return psb__destroy_image(driver_data, obj_image);
647}
648
649VAStatus psb_SetImagePalette(
650    VADriverContextP ctx,
651    VAImageID image,
652    /*
653     * pointer to an array holding the palette data.  The size of the array is
654     * num_palette_entries * entry_bytes in size.  The order of the components
655     * in the palette is described by the component_order in VAImage struct
656     */
657    unsigned char *palette
658)
659{
660    INIT_DRIVER_DATA;
661    VAStatus vaStatus = VA_STATUS_SUCCESS;
662
663    object_image_p obj_image = IMAGE(image);
664    if (NULL == obj_image) {
665        vaStatus = VA_STATUS_ERROR_INVALID_IMAGE;
666        DEBUG_FAILURE;
667        return vaStatus;
668    }
669
670    if (obj_image->image.format.fourcc != VA_FOURCC_AI44) {
671        /* only support AI44 palette */
672        vaStatus = VA_STATUS_ERROR_OPERATION_FAILED;
673        return vaStatus;
674    }
675
676    if (obj_image->image.num_palette_entries > 16) {
677        drv_debug_msg(VIDEO_DEBUG_ERROR, "image.num_palette_entries(%d) is too big\n", obj_image->image.num_palette_entries);
678        memcpy(obj_image->palette, palette, 16);
679    } else
680        memcpy(obj_image->palette, palette, obj_image->image.num_palette_entries * sizeof(unsigned int));
681
682    return vaStatus;
683}
684
685static VAStatus lnc_unpack_topaz_rec(int src_width, int src_height,
686                                     unsigned char *p_srcY, unsigned char *p_srcUV,
687                                     unsigned char *p_dstY, unsigned char *p_dstU, unsigned char *p_dstV,
688                                     int dstY_stride, int dstU_stride, int dstV_stride,
689                                     int surface_height)
690{
691    unsigned char *tmp_dstY = NULL;
692    unsigned char *tmp_dstUV = NULL;
693
694    int n, i, index;
695
696    drv_debug_msg(VIDEO_DEBUG_GENERAL, "Unpack reconstructed frame to image\n");
697
698    /* do this one column at a time. */
699    tmp_dstY = (unsigned char *)calloc(1, 16 * src_height);
700    if (tmp_dstY == NULL)
701        return  VA_STATUS_ERROR_ALLOCATION_FAILED;
702
703    tmp_dstUV = (unsigned char*)calloc(1, 16 * src_height / 2);
704    if (tmp_dstUV == NULL) {
705        free(tmp_dstY);
706        return VA_STATUS_ERROR_ALLOCATION_FAILED;
707    }
708
709    /*  Copy Y data */
710    for (n = 0; n < src_width / 16; n++) {
711        memcpy((void*)tmp_dstY, p_srcY, 16 * src_height);
712        p_srcY += (16 * surface_height);
713        for (i = 0; i < src_height; i++) {
714            memcpy(p_dstY + dstY_stride * i + n * 16, tmp_dstY + 16 * i, 16);
715        }
716    }
717
718    /* Copy U/V data */
719    for (n = 0; n < src_width / 16; n++) {
720        memcpy((void*)tmp_dstUV, p_srcUV, 16 * src_height / 2);
721        p_srcUV += (16 * surface_height / 2);
722        for (i = 0; i < src_height / 2; i++) {
723            for (index = 0; index < 8; index++) {
724                p_dstU[i*dstU_stride + n*8 + index] = tmp_dstUV[index*2 + i*16];
725                p_dstV[i*dstV_stride + n*8 + index] = tmp_dstUV[index*2 + i*16+1];
726            }
727        }
728    }
729    if (tmp_dstY)
730        free(tmp_dstY);
731    if (tmp_dstUV)
732        free(tmp_dstUV);
733
734    return VA_STATUS_SUCCESS;
735}
736
737
738VAStatus psb_GetImage(
739    VADriverContextP ctx,
740    VASurfaceID surface,
741    int x,     /* coordinates of the upper left source pixel */
742    int y,
743    unsigned int width, /* width and height of the region */
744    unsigned int height,
745    VAImageID image_id
746)
747{
748    INIT_DRIVER_DATA;
749    VAStatus vaStatus = VA_STATUS_SUCCESS;
750    int ret, src_x = 0, src_y = 0, dest_x = 0, dest_y = 0;
751
752    (void)driver_data;
753    (void)lnc_unpack_topaz_rec;
754
755    object_image_p obj_image = IMAGE(image_id);
756    if (NULL == obj_image) {
757        drv_debug_msg(VIDEO_DEBUG_ERROR, "Invalidate Image\n");
758
759        vaStatus = VA_STATUS_ERROR_INVALID_IMAGE;
760        DEBUG_FAILURE;
761        return vaStatus;
762    }
763
764    if (IS_MFLD(driver_data) && (psb_CheckIEDStatus(ctx) == 1)) {
765        vaStatus = VA_STATUS_ERROR_INVALID_SURFACE;
766        return vaStatus;
767    }
768
769    if (obj_image->image.format.fourcc != VA_FOURCC_NV12) {
770        drv_debug_msg(VIDEO_DEBUG_ERROR, "target VAImage fourcc should be NV12 or IYUV\n");
771        vaStatus = VA_STATUS_ERROR_OPERATION_FAILED;
772        return vaStatus;
773    }
774
775    object_surface_p obj_surface = SURFACE(surface);
776    if (NULL == obj_surface) {
777        vaStatus = VA_STATUS_ERROR_INVALID_SURFACE;
778        DEBUG_FAILURE;
779        return vaStatus;
780    }
781
782    psb__VAImageCheckRegion(obj_surface, &obj_image->image, &src_x, &src_y, &dest_x, &dest_y,
783                            (int *)&width, (int *)&height);
784
785    psb_surface_p psb_surface = obj_surface->psb_surface;
786    unsigned char *surface_data;
787    ret = psb_buffer_map(&psb_surface->buf, &surface_data);
788    if (ret) {
789        return VA_STATUS_ERROR_UNKNOWN;
790    }
791
792    object_buffer_p obj_buffer = BUFFER(obj_image->image.buf);
793    if (NULL == obj_buffer) {
794        vaStatus = VA_STATUS_ERROR_INVALID_BUFFER;
795        DEBUG_FAILURE;
796        return vaStatus;
797    }
798
799    unsigned char *image_data;
800    ret = psb_buffer_map(obj_buffer->psb_buffer, &image_data);
801    if (ret) {
802        drv_debug_msg(VIDEO_DEBUG_ERROR, "Map buffer failed\n");
803
804        psb_buffer_unmap(&psb_surface->buf);
805        return VA_STATUS_ERROR_UNKNOWN;
806    }
807
808    image_data += obj_surface->psb_surface->buf.buffer_ofs;
809
810    switch (obj_image->image.format.fourcc) {
811    case VA_FOURCC_NV12: {
812        unsigned char *source_y, *src_uv, *dst_y, *dst_uv;
813        unsigned int i;
814        /* copy Y plane */
815        dst_y = image_data;
816        source_y = surface_data + y * psb_surface->stride + x;
817        for (i = 0; i < height; i++)  {
818            memcpy(dst_y, source_y, width);
819            dst_y += obj_image->image.pitches[0];
820            source_y += psb_surface->stride;
821        }
822
823        /* copy UV plane */
824        dst_uv = image_data + obj_image->image.offsets[1];
825        src_uv = surface_data + psb_surface->stride * obj_surface->height + (y / 2) * psb_surface->stride + x;;
826        for (i = 0; i < obj_image->image.height / 2; i++) {
827            memcpy(dst_uv, src_uv, width);
828            dst_uv += obj_image->image.pitches[1];
829            src_uv += psb_surface->stride;
830        }
831        break;
832    }
833#if 0
834    case VA_FOURCC_IYUV: {
835        unsigned char *source_y, *dst_y;
836        unsigned char *source_uv, *source_u, *source_v, *dst_u, *dst_v;
837        unsigned int i;
838
839        if (psb_surface->extra_info[4] == VA_FOURCC_IREC) {
840            /* copy Y plane */
841            dst_y = image_data + obj_image->image.offsets[0] + src_y * obj_image->image.pitches[0] + src_x;
842            dst_u = image_data + obj_image->image.offsets[1] + src_y * obj_image->image.pitches[1] + src_x;
843            dst_v = image_data + obj_image->image.offsets[2] + src_y * obj_image->image.pitches[2] + src_x;
844
845            source_y = surface_data + dest_y * psb_surface->stride + dest_x;
846            source_uv = surface_data + obj_surface->height * psb_surface->stride
847                        + dest_y * (psb_surface->stride / 2) + dest_x;
848
849            vaStatus = lnc_unpack_topaz_rec(width, height, source_y, source_uv,
850                                            dst_y, dst_u, dst_v,
851                                            obj_image->image.pitches[0],
852                                            obj_image->image.pitches[1],
853                                            obj_image->image.pitches[2],
854                                            obj_surface->height);
855        }
856
857        break;
858    }
859#endif
860    default:
861        break;
862    }
863    psb_buffer_unmap(obj_buffer->psb_buffer);
864    psb_buffer_unmap(&psb_surface->buf);
865
866    return vaStatus;
867}
868
869static VAStatus psb_PutImage2(
870    VADriverContextP ctx,
871    VASurfaceID surface,
872    VAImageID image_id,
873    int src_x,
874    int src_y,
875    unsigned int width,
876    unsigned int height,
877    int dest_x,
878    int dest_y
879)
880{
881    INIT_DRIVER_DATA;
882    VAStatus vaStatus = VA_STATUS_SUCCESS;
883    int ret;
884
885    object_image_p obj_image = IMAGE(image_id);
886    if (NULL == obj_image) {
887        vaStatus = VA_STATUS_ERROR_INVALID_IMAGE;
888        DEBUG_FAILURE;
889        return vaStatus;
890    }
891
892    object_surface_p obj_surface = SURFACE(surface);
893    if (NULL == obj_surface) {
894        vaStatus = VA_STATUS_ERROR_INVALID_SURFACE;
895        DEBUG_FAILURE;
896        return vaStatus;
897    }
898
899    if (obj_image->image.format.fourcc != VA_FOURCC_NV12) {
900        drv_debug_msg(VIDEO_DEBUG_ERROR, "target VAImage fourcc should be NV12 or IYUV\n");
901        vaStatus = VA_STATUS_ERROR_OPERATION_FAILED;
902        return vaStatus;
903    }
904
905    psb__VAImageCheckRegion(obj_surface, &obj_image->image, &src_x, &src_y, &dest_x, &dest_y,
906                            (int *)&width, (int *)&height);
907
908    psb_surface_p psb_surface = obj_surface->psb_surface;
909    unsigned char *surface_data;
910    ret = psb_buffer_map(&psb_surface->buf, &surface_data);
911    if (ret) {
912        return VA_STATUS_ERROR_UNKNOWN;
913    }
914
915    object_buffer_p obj_buffer = BUFFER(obj_image->image.buf);
916    if (NULL == obj_buffer) {
917        vaStatus = VA_STATUS_ERROR_INVALID_BUFFER;
918        DEBUG_FAILURE;
919        return vaStatus;
920    }
921
922    unsigned char *image_data;
923    ret = psb_buffer_map(obj_buffer->psb_buffer, &image_data);
924    if (ret) {
925        psb_buffer_unmap(&psb_surface->buf);
926        return VA_STATUS_ERROR_UNKNOWN;
927    }
928
929    image_data += obj_surface->psb_surface->buf.buffer_ofs;
930
931    switch (obj_image->image.format.fourcc) {
932    case VA_FOURCC_NV12: {
933        unsigned char *source_y, *src_uv, *dst_y, *dst_uv;
934        unsigned int i;
935
936        /* copy Y plane */
937        source_y = image_data + obj_image->image.offsets[0] + src_y * obj_image->image.pitches[0] + src_x;
938        dst_y = surface_data + dest_y * psb_surface->stride + dest_x;
939        for (i = 0; i < height; i++)  {
940            memcpy(dst_y, source_y, width);
941            source_y += obj_image->image.pitches[0];
942            dst_y += psb_surface->stride;
943        }
944
945        /* copy UV plane */
946        src_uv = image_data + obj_image->image.offsets[1] + (src_y / 2) * obj_image->image.pitches[1] + src_x;
947        dst_uv = surface_data + psb_surface->stride * obj_surface->height + (dest_y / 2) * psb_surface->stride + dest_x;
948        for (i = 0; i < obj_image->image.height / 2; i++) {
949            memcpy(dst_uv, src_uv, width);
950            src_uv += obj_image->image.pitches[1];
951            dst_uv += psb_surface->stride;
952        }
953        break;
954    }
955#if 0
956    case VA_FOURCC_IYUV: {
957        char *source_y, *dst_y;
958        char *source_u, *source_v, *dst_u, *dst_v;
959        unsigned int i;
960
961        /* copy Y plane */
962        source_y = image_data + obj_image->image.offsets[0] + src_y * obj_image->image.pitches[0] + src_x;
963        source_u = image_data + obj_image->image.offsets[1] + src_y * obj_image->image.pitches[1] + src_x;
964        source_v = image_data + obj_image->image.offsets[2] + src_y * obj_image->image.pitches[2] + src_x;
965
966        dst_y = surface_data + dest_y * psb_surface->stride + dest_x;
967        dst_u = surface_data + obj_surface->height * psb_surface->stride
968                + dest_y * (psb_surface->stride / 2) + dest_x;
969        dst_v = surface_data + obj_surface->height * psb_surface->stride
970                + (obj_surface->height / 2) * (psb_surface->stride / 2)
971                + dest_y * (psb_surface->stride / 2) + dest_x;
972
973        for (i = 0; i < height; i++)  {
974            memcpy(dst_y, source_y, width);
975            source_y += obj_image->image.pitches[0];
976            dst_y += psb_surface->stride;
977        }
978
979        /* copy UV plane */
980        for (i = 0; i < obj_image->image.height / 2; i++) {
981            memcpy(dst_u, source_u, width);
982            memcpy(dst_v, source_v, width);
983
984            source_u += obj_image->image.pitches[1];
985            source_v += obj_image->image.pitches[2];
986
987            dst_u += psb_surface->stride / 2;
988            dst_v += psb_surface->stride / 2;
989        }
990        break;
991    }
992#endif
993    default:
994        break;
995    }
996
997    psb_buffer_unmap(obj_buffer->psb_buffer);
998    psb_buffer_unmap(&psb_surface->buf);
999
1000    return VA_STATUS_SUCCESS;
1001}
1002
1003
1004static void psb__VAImageCheckRegion2(
1005    object_surface_p surface,
1006    VAImage *image,
1007    int *src_x,
1008    int *src_y,
1009    unsigned int *src_width,
1010    unsigned int *src_height,
1011    int *dest_x,
1012    int *dest_y,
1013    int *dest_width,
1014    int *dest_height
1015)
1016{
1017    /* check for image */
1018    if (*src_x < 0) *src_x = 0;
1019    if (*src_x > image->width) *src_x = image->width - 1;
1020    if (*src_y < 0) *src_y = 0;
1021    if (*src_y > image->height) *src_y = image->height - 1;
1022
1023    if (((*src_width) + (*src_x)) > image->width) *src_width = image->width - *src_x;
1024    if (((*src_height) + (*src_y)) > image->height) *src_height = image->height - *src_x;
1025
1026    /* check for surface */
1027    if (*dest_x < 0) *dest_x = 0;
1028    if (*dest_x > surface->width) *dest_x = surface->width - 1;
1029    if (*dest_y < 0) *dest_y = 0;
1030    if (*dest_y > surface->height) *dest_y = surface->height - 1;
1031
1032    if (((*dest_width) + (*dest_x)) > (int)surface->width) *dest_width = surface->width - *dest_x;
1033    if (((*dest_height) + (*dest_y)) > (int)surface->height) *dest_height = surface->height - *dest_x;
1034}
1035
1036VAStatus psb_PutImage(
1037    VADriverContextP ctx,
1038    VASurfaceID surface,
1039    VAImageID image_id,
1040    int src_x,
1041    int src_y,
1042    unsigned int src_width,
1043    unsigned int src_height,
1044    int dest_x,
1045    int dest_y,
1046    unsigned int dest_width,
1047    unsigned int dest_height
1048)
1049{
1050    INIT_DRIVER_DATA;
1051    VAStatus vaStatus = VA_STATUS_SUCCESS;
1052    int ret;
1053
1054    if ((src_width == dest_width) && (src_height == dest_height)) {
1055        /* Shortcut if scaling is not required */
1056        return psb_PutImage2(ctx, surface, image_id, src_x, src_y, src_width, src_height, dest_x, dest_y);
1057    }
1058
1059    object_image_p obj_image = IMAGE(image_id);
1060    if (NULL == obj_image) {
1061        vaStatus = VA_STATUS_ERROR_INVALID_IMAGE;
1062        DEBUG_FAILURE;
1063        return vaStatus;
1064    }
1065
1066    if (obj_image->image.format.fourcc != VA_FOURCC_NV12) {
1067        /* only support NV12 getImage/putImage */
1068        vaStatus = VA_STATUS_ERROR_OPERATION_FAILED;
1069        return vaStatus;
1070    }
1071
1072    object_surface_p obj_surface = SURFACE(surface);
1073    if (NULL == obj_surface) {
1074        vaStatus = VA_STATUS_ERROR_INVALID_SURFACE;
1075        DEBUG_FAILURE;
1076        return vaStatus;
1077    }
1078
1079    psb__VAImageCheckRegion2(obj_surface, &obj_image->image,
1080                             &src_x, &src_y, &src_width, &src_height,
1081                             &dest_x, &dest_y, (int *)&dest_width, (int *)&dest_height);
1082
1083    psb_surface_p psb_surface = obj_surface->psb_surface;
1084    unsigned char *surface_data;
1085    ret = psb_buffer_map(&psb_surface->buf, &surface_data);
1086    if (ret) {
1087        return VA_STATUS_ERROR_UNKNOWN;
1088    }
1089
1090    object_buffer_p obj_buffer = BUFFER(obj_image->image.buf);
1091    if (NULL == obj_buffer) {
1092        vaStatus = VA_STATUS_ERROR_INVALID_BUFFER;
1093        DEBUG_FAILURE;
1094        return vaStatus;
1095    }
1096
1097    unsigned char *image_data;
1098    ret = psb_buffer_map(obj_buffer->psb_buffer, &image_data);
1099    if (ret) {
1100        psb_buffer_unmap(&psb_surface->buf);
1101        return VA_STATUS_ERROR_UNKNOWN;
1102    }
1103
1104    /* just a prototype, the algorithm is ugly and not optimized */
1105    switch (obj_image->image.format.fourcc) {
1106    case VA_FOURCC_NV12: {
1107        unsigned char *source_y, *dst_y;
1108        unsigned short *source_uv, *dst_uv;
1109        unsigned int i, j;
1110        float xratio = (float) src_width / dest_width;
1111        float yratio = (float) src_height / dest_height;
1112
1113        /* dst_y/dst_uv: Y/UV plane of destination */
1114        dst_y = (unsigned char *)(surface_data + dest_y * psb_surface->stride + dest_x);
1115        dst_uv = (unsigned short *)(surface_data + psb_surface->stride * obj_surface->height
1116                                    + (dest_y / 2) * psb_surface->stride + dest_x);
1117
1118        for (j = 0; j < dest_height; j++)  {
1119            unsigned char *dst_y_tmp = dst_y;
1120            unsigned short *dst_uv_tmp = dst_uv;
1121
1122            for (i = 0; i < dest_width; i++)  {
1123                int x = (int)(i * xratio);
1124                int y = (int)(j * yratio);
1125
1126                source_y = image_data + obj_image->image.offsets[0]
1127                           + (src_y + y) * obj_image->image.pitches[0]
1128                           + (src_x + x);
1129                *dst_y_tmp = *source_y;
1130                dst_y_tmp++;
1131
1132                if (((i & 1) == 0)) {
1133                    source_uv = (unsigned short *)(image_data + obj_image->image.offsets[1]
1134                                                   + ((src_y + y) / 2) * obj_image->image.pitches[1])
1135                                + ((src_x + x) / 2);
1136                    *dst_uv_tmp = *source_uv;
1137                    dst_uv_tmp++;
1138                }
1139            }
1140            dst_y += psb_surface->stride;
1141
1142            if (j & 1)
1143                dst_uv = (unsigned short *)((unsigned char *)dst_uv + psb_surface->stride);
1144        }
1145        break;
1146    }
1147    default:/* will not reach here */
1148        break;
1149    }
1150
1151    psb_buffer_unmap(obj_buffer->psb_buffer);
1152    psb_buffer_unmap(&psb_surface->buf);
1153
1154    return VA_STATUS_SUCCESS;
1155}
1156
1157/*
1158 * Link supbicture into one surface, when update is zero, not need to
1159 * update the location information
1160 * The image informatio and its BO of subpicture will copied to surface
1161 * so need to update it when a vaSetSubpictureImage is called
1162 */
1163static VAStatus psb__LinkSubpictIntoSurface(
1164    psb_driver_data_p driver_data,
1165    object_surface_p obj_surface,
1166    object_subpic_p obj_subpic,
1167    short src_x,
1168    short src_y,
1169    unsigned short src_w,
1170    unsigned short src_h,
1171    short dest_x,
1172    short dest_y,
1173    unsigned short dest_w,
1174    unsigned short dest_h,
1175    int update /* update subpicture location */
1176)
1177{
1178    PsbVASurfaceRec *surface_subpic;
1179    object_image_p obj_image = IMAGE(obj_subpic->image_id);
1180    if (NULL == obj_image) {
1181        return VA_STATUS_ERROR_INVALID_IMAGE;
1182    }
1183
1184    VAImage *image = &obj_image->image;
1185    object_buffer_p obj_buffer = BUFFER(image->buf);
1186    if (NULL == obj_buffer) {
1187        return VA_STATUS_ERROR_INVALID_BUFFER;
1188    }
1189
1190    int found = 0;
1191
1192    if (obj_surface->subpictures != NULL) {
1193        surface_subpic = (PsbVASurfaceRec *)obj_surface->subpictures;
1194        do {
1195            if (surface_subpic->subpic_id == obj_subpic->subpic_id) {
1196                found = 1;
1197                break;
1198            } else
1199                surface_subpic = surface_subpic->next;
1200        } while (surface_subpic);
1201    }
1202
1203    if (found == 0) { /* new node */
1204        if (obj_surface->subpic_count >= PSB_SUBPIC_MAX_NUM) {
1205            drv_debug_msg(VIDEO_DEBUG_ERROR, "can't support so many sub-pictures for the surface\n");
1206            return VA_STATUS_ERROR_UNKNOWN;
1207        }
1208
1209        surface_subpic = (PsbVASurfaceRec *)calloc(1, sizeof(*surface_subpic));
1210        if (NULL == surface_subpic)
1211            return VA_STATUS_ERROR_ALLOCATION_FAILED;
1212    }
1213
1214    surface_subpic->subpic_id = obj_subpic->subpic_id;
1215    surface_subpic->fourcc = image->format.fourcc;
1216    surface_subpic->size = image->data_size;
1217    surface_subpic->bo = obj_buffer->psb_buffer->drm_buf;
1218    surface_subpic->bufid = wsbmKBufHandle(wsbmKBuf(obj_buffer->psb_buffer->drm_buf));
1219    surface_subpic->pl_flags = obj_buffer->psb_buffer->pl_flags;
1220    surface_subpic->subpic_flags = obj_subpic->flags;
1221
1222    surface_subpic->width = image->width;
1223    surface_subpic->height = image->height;
1224    switch (surface_subpic->fourcc) {
1225    case VA_FOURCC_AYUV:
1226        surface_subpic->stride = image->pitches[0] / 4;
1227        break;
1228    case VA_FOURCC_RGBA:
1229        surface_subpic->stride = image->pitches[0] / 4;
1230        break;
1231    case VA_FOURCC_AI44:
1232        surface_subpic->stride = image->pitches[0];
1233        /* point to Image palette */
1234        surface_subpic->palette_ptr = (PsbAYUVSample8 *) & obj_image->palette[0];
1235        break;
1236    }
1237
1238    if (update) {
1239        surface_subpic->subpic_srcx = src_x;
1240        surface_subpic->subpic_srcy = src_y;
1241        surface_subpic->subpic_dstx = dest_x;
1242        surface_subpic->subpic_dsty = dest_y;
1243        surface_subpic->subpic_srcw = src_w;
1244        surface_subpic->subpic_srch = src_h;
1245        surface_subpic->subpic_dstw = dest_w;
1246        surface_subpic->subpic_dsth = dest_h;
1247    }
1248
1249    if (found == 0) { /* new node, link into the list */
1250        if (NULL == obj_surface->subpictures) {
1251            obj_surface->subpictures = (void *)surface_subpic;
1252        } else { /* insert as the head */
1253            surface_subpic->next = (PsbVASurfacePtr)obj_surface->subpictures;
1254            obj_surface->subpictures = (void *)surface_subpic;
1255        }
1256        obj_surface->subpic_count++;
1257    }
1258
1259    return VA_STATUS_SUCCESS;
1260}
1261
1262
1263static VAStatus psb__LinkSurfaceIntoSubpict(
1264    object_subpic_p obj_subpic,
1265    VASurfaceID surface_id
1266)
1267{
1268    subpic_surface_s *subpic_surface;
1269    int found = 0;
1270
1271    if (obj_subpic->surfaces != NULL) {
1272        subpic_surface = (subpic_surface_s *)obj_subpic->surfaces;
1273        do  {
1274            if (subpic_surface->surface_id == surface_id) {
1275                found = 1;
1276                return VA_STATUS_SUCCESS; /* reture directly */
1277            } else
1278                subpic_surface = subpic_surface->next;
1279        } while (subpic_surface);
1280    }
1281
1282    /* not found */
1283    subpic_surface = (subpic_surface_s *)calloc(1, sizeof(*subpic_surface));
1284    if (NULL == subpic_surface)
1285        return VA_STATUS_ERROR_ALLOCATION_FAILED;
1286
1287    subpic_surface->surface_id = surface_id;
1288    subpic_surface->next = NULL;
1289
1290    if (NULL == obj_subpic->surfaces) {
1291        obj_subpic->surfaces = (void *)subpic_surface;
1292    } else { /* insert as the head */
1293        subpic_surface->next = (subpic_surface_p)obj_subpic->surfaces;
1294        obj_subpic->surfaces = (void *)subpic_surface;
1295    }
1296
1297    return VA_STATUS_SUCCESS;
1298}
1299
1300static VAStatus psb__DelinkSubpictFromSurface(
1301    object_surface_p obj_surface,
1302    VASubpictureID subpic_id
1303)
1304{
1305    PsbVASurfaceRec *surface_subpic, *pre_surface_subpic = NULL;
1306    int found = 0;
1307
1308    if (obj_surface->subpictures != NULL) {
1309        surface_subpic = (PsbVASurfaceRec *)obj_surface->subpictures;
1310        do  {
1311            if (surface_subpic->subpic_id == subpic_id) {
1312                found = 1;
1313                break;
1314            } else {
1315                pre_surface_subpic = surface_subpic;
1316                surface_subpic = surface_subpic->next;
1317            }
1318        } while (surface_subpic);
1319    }
1320
1321    if (found == 1) {
1322        if (pre_surface_subpic == NULL) { /* remove the first node */
1323            obj_surface->subpictures = (void *)surface_subpic->next;
1324        } else {
1325            pre_surface_subpic->next = surface_subpic->next;
1326        }
1327        free(surface_subpic);
1328        obj_surface->subpic_count--;
1329    }
1330
1331    return VA_STATUS_SUCCESS;
1332}
1333
1334
1335static VAStatus psb__DelinkSurfaceFromSubpict(
1336    object_subpic_p obj_subpic,
1337    VASurfaceID surface_id
1338)
1339{
1340    subpic_surface_s *subpic_surface, *pre_subpic_surface = NULL;
1341    int found = 0;
1342
1343    if (obj_subpic->surfaces != NULL) {
1344        subpic_surface = (subpic_surface_s *)obj_subpic->surfaces;
1345        do {
1346            if (subpic_surface->surface_id == surface_id) {
1347                found = 1;
1348                break;
1349            } else {
1350                pre_subpic_surface = subpic_surface;
1351                subpic_surface = subpic_surface->next;
1352            }
1353        } while (subpic_surface);
1354    }
1355
1356    if (found == 1) {
1357        if (pre_subpic_surface == NULL) { /* remove the first node */
1358            obj_subpic->surfaces = (void *)subpic_surface->next;
1359        } else {
1360            pre_subpic_surface->next = subpic_surface->next;
1361        }
1362        free(subpic_surface);
1363    }
1364
1365    return VA_STATUS_SUCCESS;
1366}
1367
1368
1369VAStatus psb_QuerySubpictureFormats(
1370    VADriverContextP ctx,
1371    VAImageFormat *format_list,        /* out */
1372    unsigned int *flags,       /* out */
1373    unsigned int *num_formats  /* out */
1374)
1375{
1376    VAStatus vaStatus = VA_STATUS_SUCCESS;
1377
1378    if (NULL == format_list) {
1379        vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
1380        DEBUG_FAILURE;
1381        return vaStatus;
1382    }
1383    if (NULL == flags) {
1384        vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
1385        DEBUG_FAILURE;
1386        return vaStatus;
1387    }
1388    if (NULL == num_formats) {
1389        vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
1390        DEBUG_FAILURE;
1391        return vaStatus;
1392    }
1393    memcpy(format_list, psb__SubpicFormat, sizeof(psb__SubpicFormat));
1394    *num_formats = PSB_MAX_SUBPIC_FORMATS;
1395    *flags = PSB_SUPPORTED_SUBPIC_FLAGS;
1396
1397    return VA_STATUS_SUCCESS;
1398}
1399
1400
1401VAStatus psb_CreateSubpicture(
1402    VADriverContextP ctx,
1403    VAImageID image,
1404    VASubpictureID *subpicture   /* out */
1405)
1406{
1407    INIT_DRIVER_DATA;
1408    VASubpictureID subpicID;
1409    object_subpic_p obj_subpic;
1410    object_image_p obj_image;
1411    VAStatus vaStatus = VA_STATUS_SUCCESS;
1412    VAImageFormat *img_fmt;
1413
1414    obj_image = IMAGE(image);
1415
1416    if (NULL == subpicture) {
1417        vaStatus = VA_STATUS_ERROR_INVALID_SUBPICTURE;
1418        DEBUG_FAILURE;
1419        return vaStatus;
1420    }
1421
1422    if (NULL == obj_image) {
1423        vaStatus = VA_STATUS_ERROR_INVALID_IMAGE;
1424        return vaStatus;
1425    }
1426
1427    img_fmt = psb__VAImageCheckFourCC(&obj_image->image.format, psb__SubpicFormat,
1428                                      sizeof(psb__SubpicFormat) / sizeof(VAImageFormat));
1429    if (img_fmt == NULL)
1430        return VA_STATUS_ERROR_UNKNOWN;
1431
1432    subpicID = object_heap_allocate(&driver_data->subpic_heap);
1433    obj_subpic = SUBPIC(subpicID);
1434    if (NULL == obj_subpic) {
1435        vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
1436        return vaStatus;
1437    }
1438    MEMSET_OBJECT(obj_subpic, struct object_subpic_s);
1439
1440    obj_subpic->subpic_id = subpicID;
1441    obj_subpic->image_id = obj_image->image.image_id;
1442    obj_subpic->surfaces = NULL;
1443    obj_subpic->global_alpha = 255;
1444
1445    obj_image->subpic_ref ++;
1446
1447    *subpicture = subpicID;
1448
1449    return VA_STATUS_SUCCESS;
1450}
1451
1452
1453
1454VAStatus psb__destroy_subpicture(psb_driver_data_p driver_data, object_subpic_p obj_subpic)
1455{
1456    subpic_surface_s *subpic_surface = (subpic_surface_s *)obj_subpic->surfaces;
1457    VASubpictureID subpicture = obj_subpic->subpic_id;
1458
1459    if (subpic_surface) {
1460        do {
1461            subpic_surface_s *tmp = subpic_surface;
1462            object_surface_p obj_surface = SURFACE(subpic_surface->surface_id);
1463
1464            if (obj_surface) { /* remove subpict from surface */
1465                psb__DelinkSubpictFromSurface(obj_surface, subpicture);
1466            }
1467            subpic_surface = subpic_surface->next;
1468            free(tmp);
1469        } while (subpic_surface);
1470    }
1471
1472    object_heap_free(&driver_data->subpic_heap, (object_base_p) obj_subpic);
1473    return VA_STATUS_SUCCESS;
1474}
1475
1476
1477VAStatus psb_DestroySubpicture(
1478    VADriverContextP ctx,
1479    VASubpictureID subpicture
1480)
1481{
1482    INIT_DRIVER_DATA;
1483    object_subpic_p obj_subpic;
1484    VAStatus vaStatus = VA_STATUS_SUCCESS;
1485
1486    obj_subpic = SUBPIC(subpicture);
1487    if (NULL == obj_subpic) {
1488        vaStatus = VA_STATUS_ERROR_INVALID_SUBPICTURE;
1489        return vaStatus;
1490    }
1491
1492
1493    return psb__destroy_subpicture(driver_data, obj_subpic);
1494}
1495
1496VAStatus psb_SetSubpictureImage(
1497    VADriverContextP ctx,
1498    VASubpictureID subpicture,
1499    VAImageID image
1500)
1501{
1502    INIT_DRIVER_DATA;
1503    object_subpic_p obj_subpic;
1504    object_image_p obj_image;
1505    VAStatus vaStatus = VA_STATUS_SUCCESS;
1506    subpic_surface_s *subpic_surface;
1507    VAImageFormat *img_fmt;
1508
1509    obj_image = IMAGE(image);
1510    if (NULL == obj_image) {
1511        vaStatus = VA_STATUS_ERROR_INVALID_IMAGE;
1512        return vaStatus;
1513    }
1514
1515    img_fmt = psb__VAImageCheckFourCC(&obj_image->image.format,
1516                                      psb__SubpicFormat,
1517                                      sizeof(psb__SubpicFormat) / sizeof(VAImageFormat));
1518    if (img_fmt == NULL)
1519        return VA_STATUS_ERROR_INVALID_IMAGE;
1520
1521    obj_subpic = SUBPIC(subpicture);
1522    if (NULL == obj_subpic) {
1523        vaStatus = VA_STATUS_ERROR_INVALID_SUBPICTURE;
1524        return vaStatus;
1525    }
1526
1527    object_image_p old_obj_image = IMAGE(obj_subpic->image_id);
1528    if (old_obj_image) {
1529        old_obj_image->subpic_ref--;/* decrease reference count */
1530    }
1531
1532    /* reset the image */
1533    obj_subpic->image_id = obj_image->image.image_id;
1534    obj_image->subpic_ref ++;
1535
1536    /* relink again */
1537    if (obj_subpic->surfaces != NULL) {
1538        /* the subpicture already linked into surfaces
1539         * so not check the return value of psb__LinkSubpictIntoSurface
1540         */
1541        subpic_surface = (subpic_surface_s *)obj_subpic->surfaces;
1542        do {
1543            object_surface_p obj_surface = SURFACE(subpic_surface->surface_id);
1544            if (NULL == obj_surface) {
1545                vaStatus = VA_STATUS_ERROR_INVALID_SURFACE;
1546                return vaStatus;
1547            }
1548
1549            psb__LinkSubpictIntoSurface(driver_data, obj_surface, obj_subpic,
1550                                        0, 0, 0, 0, 0, 0, 0, 0,
1551                                        0 /* not update location */
1552                                       );
1553            subpic_surface = subpic_surface->next;
1554        } while (subpic_surface);
1555    }
1556
1557
1558    return VA_STATUS_SUCCESS;
1559}
1560
1561
1562VAStatus psb_SetSubpictureChromakey(
1563    VADriverContextP ctx,
1564    VASubpictureID subpicture,
1565    unsigned int chromakey_min,
1566    unsigned int chromakey_max,
1567    unsigned int chromakey_mask
1568)
1569{
1570    INIT_DRIVER_DATA;
1571    (void)driver_data;
1572    /* TODO */
1573    if ((chromakey_mask < chromakey_min) || (chromakey_mask > chromakey_max)) {
1574        drv_debug_msg(VIDEO_DEBUG_ERROR, "Invalid chromakey value %d, chromakey value should between min and max\n", chromakey_mask);
1575        return VA_STATUS_ERROR_INVALID_PARAMETER;
1576    }
1577    object_subpic_p obj_subpic = SUBPIC(subpicture);
1578    if (NULL == obj_subpic) {
1579        drv_debug_msg(VIDEO_DEBUG_ERROR, "Invalid subpicture value %d\n", subpicture);
1580        return VA_STATUS_ERROR_INVALID_SUBPICTURE;
1581    }
1582
1583    return VA_STATUS_SUCCESS;
1584}
1585
1586VAStatus psb_SetSubpictureGlobalAlpha(
1587    VADriverContextP ctx,
1588    VASubpictureID subpicture,
1589    float global_alpha
1590)
1591{
1592    INIT_DRIVER_DATA;
1593
1594    if (global_alpha < 0 || global_alpha > 1) {
1595        drv_debug_msg(VIDEO_DEBUG_ERROR, "Invalid global alpha value %07f, global alpha value should between 0 and 1\n", global_alpha);
1596        return VA_STATUS_ERROR_INVALID_PARAMETER;
1597    }
1598
1599    object_subpic_p obj_subpic = SUBPIC(subpicture);
1600    if (NULL == obj_subpic) {
1601        drv_debug_msg(VIDEO_DEBUG_ERROR, "Invalid subpicture value %d\n", subpicture);
1602        return VA_STATUS_ERROR_INVALID_SUBPICTURE;
1603    }
1604
1605    obj_subpic->global_alpha = global_alpha * 255;
1606
1607    return VA_STATUS_SUCCESS;
1608}
1609
1610
1611VAStatus psb__AssociateSubpicture(
1612    VADriverContextP ctx,
1613    VASubpictureID subpicture,
1614    VASurfaceID *target_surfaces,
1615    int num_surfaces,
1616    short src_x, /* upper left offset in subpicture */
1617    short src_y,
1618    unsigned short src_w,
1619    unsigned short src_h,
1620    short dest_x, /* upper left offset in surface */
1621    short dest_y,
1622    unsigned short dest_w,
1623    unsigned short dest_h,
1624    /*
1625     * whether to enable chroma-keying or global-alpha
1626     * see VA_SUBPICTURE_XXX values
1627     */
1628    unsigned int flags
1629)
1630{
1631    INIT_DRIVER_DATA;
1632
1633    object_subpic_p obj_subpic;
1634    VAStatus vaStatus = VA_STATUS_SUCCESS;
1635    int i;
1636
1637    if (num_surfaces <= 0) {
1638        vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
1639        DEBUG_FAILURE;
1640        return vaStatus;
1641    }
1642
1643    obj_subpic = SUBPIC(subpicture);
1644    if (NULL == obj_subpic) {
1645        vaStatus = VA_STATUS_ERROR_INVALID_SUBPICTURE;
1646        DEBUG_FAILURE;
1647        return vaStatus;
1648    }
1649
1650    if (NULL == target_surfaces) {
1651        vaStatus = VA_STATUS_ERROR_INVALID_SURFACE;
1652        DEBUG_FAILURE;
1653        return vaStatus;
1654    }
1655
1656    if (flags & ~PSB_SUPPORTED_SUBPIC_FLAGS) {
1657#ifdef VA_STATUS_ERROR_FLAG_NOT_SUPPORTED
1658        vaStatus = VA_STATUS_ERROR_FLAG_NOT_SUPPORTED;
1659#else
1660        vaStatus = VA_STATUS_ERROR_UNKNOWN;
1661#endif
1662        DEBUG_FAILURE;
1663        return vaStatus;
1664    } else {
1665
1666        /* If flags are ok, copy them to the subpicture object */
1667        obj_subpic->flags = flags;
1668
1669    }
1670
1671    /* Validate input params */
1672    for (i = 0; i < num_surfaces; i++) {
1673        object_surface_p obj_surface = SURFACE(target_surfaces[i]);
1674        if (NULL == obj_surface) {
1675            vaStatus = VA_STATUS_ERROR_INVALID_SURFACE;
1676            DEBUG_FAILURE;
1677            return vaStatus;
1678        }
1679    }
1680
1681    VASurfaceID *surfaces = target_surfaces;
1682    for (i = 0; i < num_surfaces; i++) {
1683        object_surface_p obj_surface = SURFACE(*surfaces);
1684        if (obj_surface) {
1685            vaStatus = psb__LinkSubpictIntoSurface(driver_data, obj_surface, obj_subpic,
1686                                                   src_x, src_y, src_w, src_h,
1687                                                   dest_x, dest_y, dest_w, dest_h, 1);
1688            if (VA_STATUS_SUCCESS == vaStatus) {
1689                vaStatus = psb__LinkSurfaceIntoSubpict(obj_subpic, *surfaces);
1690            }
1691            if (VA_STATUS_SUCCESS != vaStatus) { /* failed with malloc */
1692                DEBUG_FAILURE;
1693                return vaStatus;
1694            }
1695        } else {
1696            /* Should never get here */
1697            drv_debug_msg(VIDEO_DEBUG_ERROR, "Invalid surfaces,SurfaceID=0x%x\n", *surfaces);
1698        }
1699
1700        surfaces++;
1701    }
1702
1703    return VA_STATUS_SUCCESS;
1704}
1705
1706
1707VAStatus psb_AssociateSubpicture(
1708    VADriverContextP ctx,
1709    VASubpictureID subpicture,
1710    VASurfaceID *target_surfaces,
1711    int num_surfaces,
1712    short src_x, /* upper left offset in subpicture */
1713    short src_y,
1714    unsigned short src_width,
1715    unsigned short src_height,
1716    short dest_x, /* upper left offset in surface */
1717    short dest_y,
1718    unsigned short dest_width,
1719    unsigned short dest_height,
1720    /*
1721     * whether to enable chroma-keying or global-alpha
1722     * see VA_SUBPICTURE_XXX values
1723     */
1724    unsigned int flags
1725)
1726{
1727    return psb__AssociateSubpicture(ctx, subpicture, target_surfaces, num_surfaces,
1728                                    src_x, src_y, src_width, src_height,
1729                                    dest_x, dest_y, dest_width, dest_height,
1730                                    flags
1731                                   );
1732}
1733
1734
1735VAStatus psb_DeassociateSubpicture(
1736    VADriverContextP ctx,
1737    VASubpictureID subpicture,
1738    VASurfaceID *target_surfaces,
1739    int num_surfaces
1740)
1741{
1742    INIT_DRIVER_DATA;
1743
1744    object_subpic_p obj_subpic;
1745    VAStatus vaStatus = VA_STATUS_SUCCESS;
1746    object_image_p obj_image;
1747    int i;
1748
1749    if (num_surfaces <= 0) {
1750        vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
1751        DEBUG_FAILURE;
1752        return vaStatus;
1753    }
1754
1755    obj_subpic = SUBPIC(subpicture);
1756    if (NULL == obj_subpic) {
1757        vaStatus = VA_STATUS_ERROR_INVALID_SUBPICTURE;
1758        DEBUG_FAILURE;
1759        return vaStatus;
1760    }
1761
1762    if (NULL == target_surfaces) {
1763        vaStatus = VA_STATUS_ERROR_INVALID_SURFACE;
1764        DEBUG_FAILURE;
1765        return vaStatus;
1766    }
1767
1768    VASurfaceID *surfaces = target_surfaces;
1769    for (i = 0; i < num_surfaces; i++) {
1770        object_surface_p obj_surface = SURFACE(*surfaces);
1771
1772        if (obj_surface) {
1773            psb__DelinkSubpictFromSurface(obj_surface, subpicture);
1774            psb__DelinkSurfaceFromSubpict(obj_subpic, obj_surface->surface_id);
1775        } else {
1776            drv_debug_msg(VIDEO_DEBUG_ERROR, "vaDeassociateSubpicture: Invalid surface, VASurfaceID=0x%08x\n", *surfaces);
1777        }
1778
1779        surfaces++;
1780    }
1781
1782    obj_image = IMAGE(obj_subpic->image_id);
1783    if (obj_image)
1784        obj_image->subpic_ref--;/* decrease reference count */
1785
1786    return VA_STATUS_SUCCESS;
1787}
1788
1789
1790void psb_SurfaceDeassociateSubpict(
1791    psb_driver_data_p driver_data,
1792    object_surface_p obj_surface
1793)
1794{
1795    PsbVASurfaceRec *surface_subpic = (PsbVASurfaceRec *)obj_surface->subpictures;
1796
1797    if (surface_subpic != NULL) {
1798        do  {
1799            PsbVASurfaceRec *tmp = surface_subpic;
1800            object_subpic_p obj_subpic = SUBPIC(surface_subpic->subpic_id);
1801            if (obj_subpic)
1802                psb__DelinkSurfaceFromSubpict(obj_subpic, obj_surface->surface_id);
1803            surface_subpic = surface_subpic->next;
1804            free(tmp);
1805        } while (surface_subpic);
1806    }
1807}
1808
1809
1810static  VADisplayAttribute psb__DisplayAttribute[] = {
1811    {
1812        VADisplayAttribBrightness,
1813        BRIGHTNESS_MIN,
1814        BRIGHTNESS_MAX,
1815        BRIGHTNESS_DEFAULT_VALUE,
1816        VA_DISPLAY_ATTRIB_GETTABLE | VA_DISPLAY_ATTRIB_SETTABLE
1817    },
1818
1819    {
1820        VADisplayAttribContrast,
1821        CONTRAST_MIN,
1822        CONTRAST_MAX,
1823        CONTRAST_DEFAULT_VALUE,
1824        VA_DISPLAY_ATTRIB_GETTABLE | VA_DISPLAY_ATTRIB_SETTABLE
1825    },
1826
1827    {
1828        VADisplayAttribHue,
1829        HUE_MIN,
1830        HUE_MAX,
1831        HUE_DEFAULT_VALUE,
1832        VA_DISPLAY_ATTRIB_GETTABLE | VA_DISPLAY_ATTRIB_SETTABLE
1833    },
1834
1835    {
1836        VADisplayAttribSaturation,
1837        SATURATION_MIN,
1838        SATURATION_MAX,
1839        SATURATION_DEFAULT_VALUE,
1840        VA_DISPLAY_ATTRIB_GETTABLE | VA_DISPLAY_ATTRIB_SETTABLE
1841    },
1842    {
1843        VADisplayAttribBackgroundColor,
1844        0x00000000,
1845        0xffffffff,
1846        0x00000000,
1847        VA_DISPLAY_ATTRIB_GETTABLE | VA_DISPLAY_ATTRIB_SETTABLE
1848    },
1849    {
1850        VADisplayAttribRotation,
1851        VA_ROTATION_NONE,
1852        VA_ROTATION_270,
1853        VA_ROTATION_NONE,
1854        VA_DISPLAY_ATTRIB_GETTABLE | VA_DISPLAY_ATTRIB_SETTABLE
1855    },
1856    {
1857        VADisplayAttribOutofLoopDeblock,
1858        VA_OOL_DEBLOCKING_FALSE,
1859        VA_OOL_DEBLOCKING_TRUE,
1860        VA_OOL_DEBLOCKING_FALSE,
1861        VA_DISPLAY_ATTRIB_GETTABLE | VA_DISPLAY_ATTRIB_SETTABLE
1862    },
1863    {
1864        VADisplayAttribBlendColor,
1865        0x00000000,
1866        0xffffffff,
1867        0x00000000,
1868        VA_DISPLAY_ATTRIB_GETTABLE | VA_DISPLAY_ATTRIB_SETTABLE
1869    },
1870    {
1871        VADisplayAttribOverlayColorKey,
1872        0x00000000,
1873        0xffffffff,
1874        0x00000000,
1875        VA_DISPLAY_ATTRIB_GETTABLE | VA_DISPLAY_ATTRIB_SETTABLE
1876    },
1877    {
1878        VADisplayAttribOverlayAutoPaintColorKey,
1879        0x00000000,
1880        0xffffffff,
1881        0x00000000,
1882        VA_DISPLAY_ATTRIB_GETTABLE | VA_DISPLAY_ATTRIB_SETTABLE
1883    },
1884    {
1885        VADisplayAttribCSCMatrix,
1886        0x00000000,
1887        0xffffffff,
1888        0x00000000,
1889        VA_DISPLAY_ATTRIB_GETTABLE | VA_DISPLAY_ATTRIB_SETTABLE
1890    },
1891    {
1892        VADisplayAttribRenderDevice,
1893        0x00000000,
1894        0xffffffff,
1895        0x00000000,
1896        VA_DISPLAY_ATTRIB_GETTABLE | VA_DISPLAY_ATTRIB_SETTABLE
1897    },
1898    {
1899        VADisplayAttribRenderMode,
1900        0x00000000,
1901        0xffffffff,
1902        0x00000000,
1903        VA_DISPLAY_ATTRIB_GETTABLE | VA_DISPLAY_ATTRIB_SETTABLE
1904    },
1905    {
1906        VADisplayAttribRenderRect,
1907        0x00000000,
1908        0xffffffff,
1909        0x00000000,
1910        VA_DISPLAY_ATTRIB_GETTABLE | VA_DISPLAY_ATTRIB_SETTABLE
1911    }
1912};
1913
1914/*
1915 * Query display attributes
1916 * The caller must provide a "attr_list" array that can hold at
1917 * least vaMaxNumDisplayAttributes() entries. The actual number of attributes
1918 * returned in "attr_list" is returned in "num_attributes".
1919 */
1920VAStatus psb_QueryDisplayAttributes(
1921    VADriverContextP ctx,
1922    VADisplayAttribute *attr_list,      /* out */
1923    int *num_attributes         /* out */
1924)
1925{
1926    VAStatus vaStatus = VA_STATUS_SUCCESS;
1927
1928    if (NULL == attr_list) {
1929        vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
1930        DEBUG_FAILURE;
1931        return vaStatus;
1932    }
1933    if (NULL == num_attributes) {
1934        vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
1935        DEBUG_FAILURE;
1936        return vaStatus;
1937    }
1938    *num_attributes = min(*num_attributes, PSB_MAX_DISPLAY_ATTRIBUTES);
1939    memcpy(attr_list, psb__DisplayAttribute, (*num_attributes)*sizeof(VADisplayAttribute));
1940    return VA_STATUS_SUCCESS;
1941}
1942
1943/*
1944 * Get display attributes
1945 * This function returns the current attribute values in "attr_list".
1946 * Only attributes returned with VA_DISPLAY_ATTRIB_GETTABLE set in the "flags" field
1947 * from vaQueryDisplayAttributes() can have their values retrieved.
1948 */
1949VAStatus psb_GetDisplayAttributes(
1950    VADriverContextP ctx,
1951    VADisplayAttribute *attr_list,      /* in/out */
1952    int num_attributes
1953)
1954{
1955    INIT_DRIVER_DATA;
1956    VADisplayAttribute *p = attr_list;
1957    int i;
1958    VAStatus vaStatus = VA_STATUS_SUCCESS;
1959
1960    if (NULL == attr_list) {
1961        vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
1962        DEBUG_FAILURE;
1963        return vaStatus;
1964    }
1965
1966    if (num_attributes <= 0) {
1967        return VA_STATUS_ERROR_INVALID_PARAMETER;
1968    }
1969
1970    for (i = 0; i < num_attributes; i++) {
1971        switch (p->type) {
1972        case VADisplayAttribBrightness:
1973            /* -50*(1<<10) ~ 50*(1<<10) ==> 0~100*/
1974            p->value = (driver_data->brightness.value / (1 << 10)) + 50;
1975            p->min_value = 0;
1976            p->max_value = 100;
1977            break;
1978        case VADisplayAttribContrast:
1979            /* 0 ~ 2*(1<<25) ==> 0~100 */
1980            p->value = (driver_data->contrast.value / (1 << 25)) * 50;
1981            p->min_value = 0;
1982            p->max_value = 100;
1983            break;
1984        case VADisplayAttribHue:
1985            /* -30*(1<<25) ~ 30*(1<<25) ==> 0~100*/
1986            p->value = ((driver_data->hue.value / (1 << 25)) + 30) * 10 / 6;
1987            p->min_value = 0;
1988            p->max_value = 100;
1989            break;
1990        case VADisplayAttribSaturation:
1991            /* 0 ~ 2*(1<<25) ==> 0~100 */
1992            p->value = (driver_data->saturation.value / (1 << 25)) * 50;
1993            p->min_value = 0;
1994            p->max_value = 100;
1995            break;
1996        case VADisplayAttribBackgroundColor:
1997            p->value = driver_data->clear_color;
1998            break;
1999        case VADisplayAttribBlendColor:
2000            p->value = driver_data->blend_color;
2001            break;
2002        case VADisplayAttribOverlayColorKey:
2003            p->value = driver_data->color_key;
2004            p->min_value = 0;
2005            p->max_value = 0xFFFFFF;
2006            break;
2007        case VADisplayAttribOverlayAutoPaintColorKey:
2008            p->value = driver_data->overlay_auto_paint_color_key;
2009            p->min_value = 0;
2010            p->max_value = 1;
2011            break;
2012        case VADisplayAttribRotation:
2013            p->value = driver_data->va_rotate = p->value;
2014            p->min_value = VA_ROTATION_NONE;
2015            p->max_value = VA_ROTATION_270;
2016            break;
2017        case VADisplayAttribOutofLoopDeblock:
2018            p->value = driver_data->is_oold = p->value;
2019            p->min_value = VA_OOL_DEBLOCKING_FALSE;
2020            p->max_value = VA_OOL_DEBLOCKING_TRUE;
2021            break;
2022        case VADisplayAttribCSCMatrix:
2023            p->value = driver_data->load_csc_matrix = p->value;
2024            p->min_value = 0;
2025            p->max_value = 255;
2026            break;
2027        case VADisplayAttribRenderDevice:
2028            p->value = driver_data->render_device = p->value;
2029            p->min_value = 0;
2030            p->max_value = 255;
2031            break;
2032        case VADisplayAttribRenderMode:
2033            p->value = driver_data->render_mode = p->value;
2034            p->min_value = 0;
2035            p->max_value = 255;
2036            break;
2037        case VADisplayAttribRenderRect:
2038            ((VARectangle *)(p->value))->x = driver_data->render_rect.x = ((VARectangle *)(p->value))->x;
2039            ((VARectangle *)(p->value))->y = driver_data->render_rect.y = ((VARectangle *)(p->value))->y;
2040            ((VARectangle *)(p->value))->width = driver_data->render_rect.width = ((VARectangle *)(p->value))->width;
2041            ((VARectangle *)(p->value))->height = driver_data->render_rect.height = ((VARectangle *)(p->value))->height;
2042            p->min_value = 0;
2043            p->max_value = 255;
2044            break;
2045
2046        default:
2047            break;
2048        }
2049        p++;
2050    }
2051
2052    return VA_STATUS_SUCCESS;
2053}
2054
2055/*
2056 * Set display attributes
2057 * Only attributes returned with VA_DISPLAY_ATTRIB_SETTABLE set in the "flags" field
2058 * from vaQueryDisplayAttributes() can be set.  If the attribute is not settable or
2059 * the value is out of range, the function returns VA_STATUS_ERROR_ATTR_NOT_SUPPORTED
2060 */
2061#define CLAMP_ATTR(a,max,min) (a>max?max:(a<min?min:a))
2062VAStatus psb_SetDisplayAttributes(
2063    VADriverContextP ctx,
2064    VADisplayAttribute *attr_list,
2065    int num_attributes
2066)
2067{
2068    INIT_DRIVER_DATA;
2069    VAStatus vaStatus = VA_STATUS_SUCCESS;
2070    struct psb_texture_s *texture_priv = &driver_data->ctexture_priv;
2071    PsbPortPrivPtr overlay_priv = (PsbPortPrivPtr)(&driver_data->coverlay_priv);
2072    int j, k;
2073
2074    if (NULL == attr_list) {
2075        vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
2076        DEBUG_FAILURE;
2077        return vaStatus;
2078    }
2079
2080    VADisplayAttribute *p = attr_list;
2081    int i, update_coeffs = 0;
2082    unsigned int *p_tmp;
2083
2084    if (num_attributes <= 0) {
2085        return VA_STATUS_ERROR_INVALID_PARAMETER;
2086    }
2087
2088    for (i = 0; i < num_attributes; i++) {
2089        switch (p->type) {
2090        case VADisplayAttribBrightness:
2091            /* 0~100 ==> -50*(1<<10) ~ 50*(1<<10)*/
2092            driver_data->brightness.value = (p->value - 50) * (1 << 10);
2093            /* 0~100 ==> -50~50 */
2094            overlay_priv->brightness.Value = texture_priv->brightness.Value = p->value - 50;
2095            update_coeffs = 1;
2096            break;
2097        case VADisplayAttribContrast:
2098            /* 0~100 ==> 0 ~ 2*(1<<25) */
2099            driver_data->contrast.value = (p->value / 50) * (1 << 25);
2100            /* 0~100 ==> -100~100 */
2101            overlay_priv->contrast.Value = texture_priv->contrast.Value = p->value * 2 - 100;
2102            update_coeffs = 1;
2103            break;
2104        case VADisplayAttribHue:
2105            /* 0~100 ==> -30*(1<<25) ~ 30*(1<<25) */
2106            driver_data->hue.value = ((p->value * 2 - 100) * 3 / 10) * (1 << 25);
2107            /* 0~100 ==> -30~30 */
2108            overlay_priv->hue.Value = texture_priv->hue.Value = (p->value * 2 - 100) * 3 / 10;
2109            update_coeffs = 1;
2110            break;
2111        case VADisplayAttribSaturation:
2112            /* 0~100 ==> 0 ~ 2*(1<<25) */
2113            driver_data->contrast.value = (p->value / 50) * (1 << 25);
2114            /* 0~100 ==> 100~200 */
2115            overlay_priv->saturation.Value = texture_priv->saturation.Value = p->value + 100;
2116            update_coeffs = 1;
2117            break;
2118        case VADisplayAttribBackgroundColor:
2119            driver_data->clear_color = p->value;
2120            break;
2121        case VADisplayAttribOutofLoopDeblock:
2122            driver_data->is_oold = p->value;
2123            break;
2124        case VADisplayAttribRotation:
2125            driver_data->va_rotate = p->value;
2126            driver_data->rotation_dirty |= PSB_NEW_VA_ROTATION;
2127            break;
2128
2129        case VADisplayAttribCSCMatrix:
2130            driver_data->load_csc_matrix = 1;
2131            p_tmp = (unsigned int *)p->value;
2132            for (j = 0; j < CSC_MATRIX_Y; j++)
2133                for (k = 0; k < CSC_MATRIX_X; k++) {
2134                    if (p_tmp)
2135                        driver_data->csc_matrix[j][k] = *p_tmp;
2136                   p_tmp++;
2137                }
2138            break;
2139
2140        case VADisplayAttribBlendColor:
2141            driver_data->blend_color = p->value;
2142            break;
2143        case VADisplayAttribOverlayColorKey:
2144            overlay_priv->colorKey = driver_data->color_key = p->value;
2145            break;
2146        case VADisplayAttribOverlayAutoPaintColorKey:
2147            driver_data->overlay_auto_paint_color_key = p->value;
2148            break;
2149
2150        case VADisplayAttribRenderDevice:
2151            driver_data->render_device = p->value & VA_RENDER_DEVICE_MASK;
2152        case VADisplayAttribRenderMode:
2153#ifndef ANDROID
2154            if (p->value & VA_RENDER_MODE_EXTERNAL_GPU) {
2155                drv_debug_msg(VIDEO_DEBUG_ERROR, "%s:Invalid parameter.VARenderModeExternalGPU is not supported.\n", __FUNCTION__);
2156                return VA_STATUS_ERROR_INVALID_PARAMETER;
2157            }
2158            if (((p->value & VA_RENDER_MODE_LOCAL_OVERLAY) && (p->value & VA_RENDER_MODE_LOCAL_GPU)) ||
2159                ((p->value & VA_RENDER_MODE_EXTERNAL_OVERLAY) && (p->value & VA_RENDER_MODE_EXTERNAL_GPU))) {
2160                drv_debug_msg(VIDEO_DEBUG_ERROR, "%s:Invalid parameter. Conflict setting for VADisplayAttribRenderMode.\n", __FUNCTION__);
2161                return VA_STATUS_ERROR_INVALID_PARAMETER;
2162            }
2163#endif
2164            driver_data->render_mode = p->value & VA_RENDER_MODE_MASK;
2165            break;
2166        case VADisplayAttribRenderRect:
2167            driver_data->render_rect.x = ((VARectangle *)(p->value))->x;
2168            driver_data->render_rect.y = ((VARectangle *)(p->value))->y;
2169            driver_data->render_rect.width = ((VARectangle *)(p->value))->width;
2170            driver_data->render_rect.height = ((VARectangle *)(p->value))->height;
2171            break;
2172
2173        default:
2174            break;
2175        }
2176        p++;
2177    }
2178
2179    if (update_coeffs) {
2180        /* TODO */
2181#ifndef ANDROID
2182        texture_priv->update_coeffs = 1;
2183#endif
2184    }
2185
2186    return VA_STATUS_SUCCESS;
2187}
2188
2189