2 * Copyright (c) 2009 Intel Corporation. All Rights Reserved.
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:
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial portions
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.
27 #include "va_backend.h"
38 #include <sys/types.h>
44 * Do dummy decode/encode, ignore the input data
45 * In order to debug memory leak or low performance issues, we need to isolate driver problems
46 * We export env "VA_FOOL", with which, we can do fake decode/encode:
49 * . if set, decode does nothing, but fill in some YUV data
50 * LIBVA_FOOL_ENCODE=<clip name>:
51 * . if set, encode does nothing, but fill in the coded buffer from a H264 clip.
52 * . VA CONTEXT/CONFIG/SURFACE will call into drivers, but VA Buffer creation is done in here
53 * . Bypass all "vaBeginPic/vaRenderPic/vaEndPic"
55 * . if set, do nothing for vaPutSurface
61 /* LIBVA_FOOL_DECODE/LIBVA_FOOL_ENCODE/LIBVA_FOOL_POSTP */
68 #define NAL_BUF_SIZE 65536 // maximum NAL unit size
69 #define RING_BUF_SIZE 8192 // input ring buffer size, MUST be a power of two!
73 #define FOOL_CONTEXT_MAX 4
74 /* per context settings */
75 static struct _fool_context {
76 VADisplay dpy; /* should use context as the key */
78 VAProfile fool_profile; /* current profile for buffers */
79 VAEntrypoint fool_entrypoint; /* current entrypoint */
81 FILE *fool_fp_codedclip; /* load a clip from disk for fooling encode*/
83 VACodedBufferSegment *codebuf;
85 /* all buffers with same type share one malloc-ed memory
86 * bufferID = (buffer numbers with the same type << 8) || type
87 * the malloc-ed memory can be find by fool_buf[bufferID & 0xff]
88 * the size is ignored here
90 char *fool_buf[VABufferTypeMax]; /* memory of fool buffers */
91 unsigned int fool_buf_size[VABufferTypeMax]; /* size of memory of fool buffers */
92 unsigned int fool_buf_count[VABufferTypeMax]; /* count of created buffers */
94 } fool_context[FOOL_CONTEXT_MAX] = { {0} }; /* trace five context at the same time */
96 #define FOOL_DECODE(idx) (fool_decode && (fool_context[idx].fool_entrypoint == VAEntrypointVLD))
97 #define FOOL_ENCODE(idx) \
99 && (fool_context[idx].fool_entrypoint == VAEntrypointEncSlice) \
100 && (fool_context[idx].fool_profile >= VAProfileH264Baseline) \
101 && (fool_context[idx].fool_profile <= VAProfileH264High))
105 #define DPY2INDEX(dpy) \
108 for (idx = 0; idx < FOOL_CONTEXT_MAX; idx++) \
109 if (fool_context[idx].dpy == dpy) \
112 if (idx == FOOL_CONTEXT_MAX) \
113 return 0; /* let driver go */
116 /* Prototype declarations (functions defined in va.c) */
118 void va_errorMessage(const char *msg, ...);
119 void va_infoMessage(const char *msg, ...);
121 int va_parseConfig(char *env, char *env_value);
123 VAStatus vaBufferInfo(
125 VAContextID context, /* in */
126 VABufferID buf_id, /* in */
127 VABufferType *type, /* out */
128 unsigned int *size, /* out */
129 unsigned int *num_elements /* out */
132 VAStatus vaLockSurface(VADisplay dpy,
134 unsigned int *fourcc, /* following are output argument */
135 unsigned int *luma_stride,
136 unsigned int *chroma_u_stride,
137 unsigned int *chroma_v_stride,
138 unsigned int *luma_offset,
139 unsigned int *chroma_u_offset,
140 unsigned int *chroma_v_offset,
141 unsigned int *buffer_name,
145 VAStatus vaUnlockSurface(VADisplay dpy,
150 void va_FoolInit(VADisplay dpy)
152 char env_value[1024];
155 for (fool_index = 0; fool_index < FOOL_CONTEXT_MAX; fool_index++)
156 if (fool_context[fool_index].dpy == 0)
159 if (fool_index == FOOL_CONTEXT_MAX)
162 if (va_parseConfig("LIBVA_FOOL_POSTP", NULL) == 0) {
164 va_infoMessage("LIBVA_FOOL_POSTP is on, dummy vaPutSurface\n");
168 if (va_parseConfig("LIBVA_FOOL_DECODE", NULL) == 0) {
170 va_infoMessage("LIBVA_FOOL_DECODE is on, dummy decode\n");
174 if (va_parseConfig("LIBVA_FOOL_ENCODE", &env_value[0]) == 0) {
175 fool_context[fool_index].fool_fp_codedclip = fopen(env_value, "r");
177 if (fool_context[fool_index].fool_fp_codedclip) {
182 if (fool_encode) /* malloc the buffer for fake clip */
184 fool_context[fool_index].frame_buf = malloc(MAX_FRAME*SLICE_NUM*NAL_BUF_SIZE*sizeof(char));
185 fool_context[fool_index].codebuf = malloc(sizeof(VACodedBufferSegment));
188 if (fool_context[fool_index].frame_buf == NULL)
192 va_infoMessage("LIBVA_FOOL_ENCODE is on, dummy encode\n");
196 if (fool_encode || fool_decode)
197 fool_context[fool_index].dpy = dpy;
201 int va_FoolEnd(VADisplay dpy)
207 for (i = 0; i < VABufferTypeMax; i++) {/* free memory */
208 if (fool_context[idx].fool_buf[i])
209 free(fool_context[idx].fool_buf[i]);
211 if (fool_context[idx].fool_fp_codedclip)
212 fclose(fool_context[idx].fool_fp_codedclip);
214 if (fool_context[idx].frame_buf)
215 free(fool_context[idx].frame_buf);
217 if (fool_context[idx].codebuf)
218 free(fool_context[idx].codebuf);
220 memset(&fool_context[idx], sizeof(struct _fool_context), 0);
224 int va_FoolCodedBuf(VADisplay dpy)
231 int va_FoolCreateConfig(
234 VAEntrypoint entrypoint,
235 VAConfigAttrib *attrib_list,
237 VAConfigID *config_id /* out */
242 /* call into driver level to allocate real context/surface/buffers, etc */
243 fool_context[idx].fool_profile = profile;
244 fool_context[idx].fool_entrypoint = entrypoint;
248 static int yuvgen_planar(
249 int width, int height,
250 unsigned char *Y_start, int Y_pitch,
251 unsigned char *U_start, int U_pitch,
252 unsigned char *V_start, int V_pitch,
253 int UV_interleave, int box_width, int row_shift,
260 for (row=0;row<height;row++) {
261 unsigned char *Y_row = Y_start + row * Y_pitch;
264 ypos = (row / box_width) & 0x1;
266 /* fill garbage data into the other field */
267 if (((field == VA_TOP_FIELD) && (row &1))
268 || ((field == VA_BOTTOM_FIELD) && ((row &1)==0))) {
269 memset(Y_row, 0xff, width);
273 for (jj=0; jj<width; jj++) {
274 xpos = ((row_shift + jj) / box_width) & 0x1;
276 if ((xpos == 0) && (ypos == 0))
278 if ((xpos == 1) && (ypos == 1))
281 if ((xpos == 1) && (ypos == 0))
283 if ((xpos == 0) && (ypos == 1))
289 for( row =0; row < height/2; row++) {
290 unsigned short value = 0x80;
292 /* fill garbage data into the other field */
293 if (((field == VA_TOP_FIELD) && (row &1))
294 || ((field == VA_BOTTOM_FIELD) && ((row &1)==0))) {
299 unsigned short *UV_row = (unsigned short *)(U_start + row * U_pitch);
301 memset(UV_row, value, width);
303 unsigned char *U_row = U_start + row * U_pitch;
304 unsigned char *V_row = V_start + row * V_pitch;
306 memset (U_row,value,width/2);
307 memset (V_row,value,width/2);
315 int va_FoolCreateSurfaces(
321 VASurfaceID *surfaces /* out */
325 unsigned int fourcc; /* following are output argument */
326 unsigned int luma_stride;
327 unsigned int chroma_u_stride;
328 unsigned int chroma_v_stride;
329 unsigned int luma_offset;
330 unsigned int chroma_u_offset;
331 unsigned int chroma_v_offset;
332 unsigned int buffer_name;
334 unsigned char *Y_data, *U_data, *V_data;
336 int box_width = num_surfaces/2;
342 if (FOOL_DECODE(idx)) {
343 /* call into driver level to allocate real context/surface/buffers, etc
344 * fill in the YUV data, will be overwrite if it is encode context
346 for (i = 0; i < num_surfaces; i++) {
347 /* fool decoder: fill with auto-generated YUV data */
348 va_status = vaLockSurface(dpy, surfaces[i], &fourcc,
349 &luma_stride, &chroma_u_stride, &chroma_v_stride,
350 &luma_offset, &chroma_u_offset, &chroma_v_offset,
351 &buffer_name, &buffer);
353 if (va_status != VA_STATUS_SUCCESS)
357 vaUnlockSurface(dpy, surfaces[i]);
363 /* UV should be same for NV12 */
364 U_data = buffer + chroma_u_offset;
365 V_data = buffer + chroma_v_offset;
367 yuvgen_planar(width, height,
369 U_data, chroma_v_stride,
370 V_data, chroma_v_stride,
371 (fourcc==VA_FOURCC_NV12),
372 box_width, row_shift, 0);
374 vaUnlockSurface(dpy, surfaces[i]);
377 if (row_shift==(2*box_width))
380 return 0; /* the return value is ignored */
382 return 0; /* the return value is ignored */
385 VAStatus va_FoolCreateBuffer (
387 VAContextID context, /* in */
388 VABufferType type, /* in */
389 unsigned int size, /* in */
390 unsigned int num_elements, /* in */
392 VABufferID *buf_id /* out */
397 if (FOOL_ENCODE(idx) || FOOL_DECODE(idx)) { /* fool buffer creation */
398 int new_size = size * num_elements;
400 if (type == VAEncCodedBufferType) /* only a VACodedBufferSegment */
401 new_size = sizeof(VACodedBufferSegment);
403 if (fool_context[idx].fool_buf_size[type] == 0)
404 fool_context[idx].fool_buf[type] = calloc(1, new_size);
405 else if (fool_context[idx].fool_buf_size[type] <= new_size)
406 fool_context[idx].fool_buf[type] = realloc(fool_context[idx].fool_buf, new_size);
408 if (fool_context[idx].fool_buf[type] == NULL) {
410 return 0; /* let driver go */
413 /* because we ignore the vaRenderPicture,
414 * all buffers with same type share same real memory
415 * bufferID = (buffer count << 8) | type
417 fool_context[idx].fool_buf_count[type]++;
418 *buf_id = (fool_context[idx].fool_buf_count[type] << 8) | type;
420 return 1; /* don't call into driver */
423 return 0; /* let driver go ... */
426 VAStatus va_FoolMapBuffer (
428 VABufferID buf_id, /* in */
429 void **pbuf /* out */
433 unsigned int size,frame_size = 0;
434 unsigned int num_elements;
437 if (FOOL_ENCODE(idx) || FOOL_DECODE(idx)) { /* fool buffer creation */
438 unsigned int buf_idx = buf_id & 0xff;
441 vaBufferInfo(dpy, fool_context[idx].context, buf_id, &type, &size, &num_elements);
442 if (type == VAImageBufferType && FOOL_ENCODE(idx))
445 /* buf_id is the buffer type */
446 if (fool_context[idx].fool_buf[buf_idx] != NULL)
447 *pbuf = fool_context[idx].fool_buf[buf_idx];
451 /* expect APP to MapBuffer when get the the coded data */
452 if (*pbuf && (buf_idx == VAEncCodedBufferType)) { /* it is coded buffer */
453 /* read from a clip */
454 frame_size = va_FoolGetFrame(fool_context[idx].fool_fp_codedclip,
455 fool_context[idx].frame_buf);
457 memset(fool_context[idx].codebuf,0,sizeof(VACodedBufferSegment));
458 fool_context[idx].codebuf->size = frame_size;
459 fool_context[idx].codebuf->bit_offset = 0;
460 fool_context[idx].codebuf->status = 0;
461 fool_context[idx].codebuf->reserved = 0;
462 fool_context[idx].codebuf->buf = fool_context[idx].frame_buf;
463 fool_context[idx].codebuf->next = NULL;
464 *pbuf = fool_context[idx].codebuf;
466 return 1; /* don't call into driver */
469 return 0; /* let driver go ... */
473 int va_FoolBeginPicture(
476 VASurfaceID render_target
481 if (FOOL_ENCODE(idx) || FOOL_DECODE(idx)) {
482 if (fool_context[idx].context == 0)
483 fool_context[idx].context = context;
484 return 1; /* don't call into driver level */
487 return 0; /* let driver go ... */
490 int va_FoolRenderPicture(
499 if (FOOL_ENCODE(idx) || FOOL_DECODE(idx))
500 return 1; /* don't call into driver level */
502 return 0; /* let driver go ... */
506 int va_FoolEndPicture(
513 /* don't call into driver level */
515 /* do real fooling operation here */
517 /* only support H264 encoding currently */
518 if (FOOL_ENCODE(idx)) {
519 /* expect vaMapBuffer will handle it
520 * or else, need to save the codedbuf ID,
521 * and fool encode it here
523 /* va_FoolCodedBuf(dpy); */
524 return 1; /* don't call into driver level */
527 if (FOOL_DECODE(idx))
528 return 1; /* don't call into driver level */
530 return 0; /* let driver go ... */
533 int va_FoolSyncSurface(
535 VASurfaceID render_target
540 /*Fill in black and white squares. */
541 if (FOOL_DECODE(idx) || FOOL_DECODE(idx))
548 VAStatus va_FoolUnmapBuffer(
550 VABufferID buf_id /* in */
555 if (FOOL_ENCODE(idx) || FOOL_DECODE(idx))
556 return 1; /* fool buffer creation */
561 VAStatus va_FoolQuerySubpictureFormats(
563 VAImageFormat *format_list,
565 unsigned int *num_formats
570 if (FOOL_ENCODE(idx) || FOOL_DECODE(idx)) {