1 /* 2 * Copyright (c) 2009 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 25 #define _GNU_SOURCE 1 26 #include "va.h" 27 #include "va_backend.h" 28 #include "va_trace.h" 29 #include "va_fool.h" 30 31 #include <assert.h> 32 #include <stdarg.h> 33 #include <stdlib.h> 34 #include <stdio.h> 35 #include <errno.h> 36 #include <string.h> 37 #include <dlfcn.h> 38 #include <unistd.h> 39 #include <sys/types.h> 40 #include <sys/stat.h> 41 #include <unistd.h> 42 #include <time.h> 43 #include <fcntl.h> 44 45 /* 46 * Do dummy decode/encode, ignore the input data 47 * In order to debug memory leak or low performance issues, we need to isolate driver problems 48 * We export env "VA_FOOL", with which, we can do fake decode/encode: 49 * 50 * LIBVA_FOOL_DECODE: 51 * . if set, decode does nothing 52 * LIBVA_FOOL_ENCODE=<framename>: 53 * . if set, encode does nothing, but fill in the coded buffer from the content of files with 54 * name framename.0,framename.1,..., framename.N, framename.0,..., framename.N,...repeatly 55 * Use file name to determine h264 or vp8 56 * LIBVA_FOOL_JPEG=<framename>:fill the content of filename to codedbuf for jpeg encoding 57 * LIBVA_FOOL_POSTP: 58 * . if set, do nothing for vaPutSurface 59 */ 60 61 62 /* global settings */ 63 int fool_codec = 0; 64 int fool_postp = 0; 65 66 #define FOOL_BUFID_MAGIC 0x12345600 67 #define FOOL_BUFID_MASK 0xffffff00 68 69 struct fool_context { 70 int enabled; /* fool_codec is global, and it is for concurent encode/decode */ 71 char *fn_enc;/* file pattern with codedbuf content for encode */ 72 char *segbuf_enc; /* the segment buffer of coded buffer, load frome fn_enc */ 73 int file_count; 74 75 char *fn_jpg;/* file name of JPEG fool with codedbuf content */ 76 char *segbuf_jpg; /* the segment buffer of coded buffer, load frome fn_jpg */ 77 78 VAEntrypoint entrypoint; /* current entrypoint */ 79 80 /* all buffers with same type share one malloc-ed memory 81 * bufferID = (buffer numbers with the same type << 8) || type 82 * the malloc-ed memory can be find by fool_buf[bufferID & 0xff] 83 * the size is ignored here 84 */ 85 char *fool_buf[VABufferTypeMax]; /* memory of fool buffers */ 86 unsigned int fool_buf_size[VABufferTypeMax]; /* size of memory of fool buffers */ 87 unsigned int fool_buf_element[VABufferTypeMax]; /* element count of created buffers */ 88 unsigned int fool_buf_count[VABufferTypeMax]; /* count of created buffers */ 89 VAContextID context; 90 }; 91 92 #define FOOL_CTX(dpy) ((struct fool_context *)((VADisplayContextP)dpy)->vafool) 93 94 #define DPY2FOOLCTX(dpy) \ 95 struct fool_context *fool_ctx = FOOL_CTX(dpy); \ 96 if (fool_ctx == NULL) \ 97 return 0; /* no fool for the context */ \ 98 99 #define DPY2FOOLCTX_CHK(dpy) \ 100 struct fool_context *fool_ctx = FOOL_CTX(dpy); \ 101 if ((fool_ctx == NULL) || (fool_ctx->enabled == 0)) \ 102 return 0; /* no fool for the context */ \ 103 104 /* Prototype declarations (functions defined in va.c) */ 105 106 void va_errorMessage(const char *msg, ...); 107 void va_infoMessage(const char *msg, ...); 108 109 int va_parseConfig(char *env, char *env_value); 110 111 void va_FoolInit(VADisplay dpy) 112 { 113 char env_value[1024]; 114 115 struct fool_context *fool_ctx = calloc(sizeof(struct fool_context), 1); 116 117 if (fool_ctx == NULL) 118 return; 119 120 if (va_parseConfig("LIBVA_FOOL_POSTP", NULL) == 0) { 121 fool_postp = 1; 122 va_infoMessage("LIBVA_FOOL_POSTP is on, dummy vaPutSurface\n"); 123 } 124 125 if (va_parseConfig("LIBVA_FOOL_DECODE", NULL) == 0) { 126 fool_codec |= VA_FOOL_FLAG_DECODE; 127 va_infoMessage("LIBVA_FOOL_DECODE is on, dummy decode\n"); 128 } 129 if (va_parseConfig("LIBVA_FOOL_ENCODE", &env_value[0]) == 0) { 130 fool_codec |= VA_FOOL_FLAG_ENCODE; 131 fool_ctx->fn_enc = strdup(env_value); 132 va_infoMessage("LIBVA_FOOL_ENCODE is on, load encode data from file with patten %s\n", 133 fool_ctx->fn_enc); 134 } 135 if (va_parseConfig("LIBVA_FOOL_JPEG", &env_value[0]) == 0) { 136 fool_codec |= VA_FOOL_FLAG_JPEG; 137 fool_ctx->fn_jpg = strdup(env_value); 138 va_infoMessage("LIBVA_FOOL_JPEG is on, load encode data from file with patten %s\n", 139 fool_ctx->fn_jpg); 140 } 141 142 ((VADisplayContextP)dpy)->vafool = fool_ctx; 143 } 144 145 146 int va_FoolEnd(VADisplay dpy) 147 { 148 int i; 149 DPY2FOOLCTX(dpy); 150 151 for (i = 0; i < VABufferTypeMax; i++) {/* free memory */ 152 if (fool_ctx->fool_buf[i]) 153 free(fool_ctx->fool_buf[i]); 154 } 155 if (fool_ctx->segbuf_enc) 156 free(fool_ctx->segbuf_enc); 157 if (fool_ctx->segbuf_jpg) 158 free(fool_ctx->segbuf_jpg); 159 if (fool_ctx->fn_enc) 160 free(fool_ctx->fn_enc); 161 if (fool_ctx->fn_jpg) 162 free(fool_ctx->fn_jpg); 163 164 free(fool_ctx); 165 ((VADisplayContextP)dpy)->vafool = NULL; 166 167 return 0; 168 } 169 170 int va_FoolCreateConfig( 171 VADisplay dpy, 172 VAProfile profile, 173 VAEntrypoint entrypoint, 174 VAConfigAttrib __maybe_unused *attrib_list, 175 int __maybe_unused num_attribs, 176 VAConfigID __maybe_unused *config_id /* out */ 177 ) 178 { 179 DPY2FOOLCTX(dpy); 180 181 fool_ctx->entrypoint = entrypoint; 182 183 /* 184 * check fool_codec to align with current context 185 * e.g. fool_codec = decode then for encode, the 186 * vaBegin/vaRender/vaEnd also run into fool path 187 * which is not desired 188 */ 189 if (((fool_codec & VA_FOOL_FLAG_DECODE) && (entrypoint == VAEntrypointVLD)) || 190 ((fool_codec & VA_FOOL_FLAG_JPEG) && (entrypoint == VAEntrypointEncPicture))) 191 fool_ctx->enabled = 1; 192 else if ((fool_codec & VA_FOOL_FLAG_ENCODE) && (entrypoint == VAEntrypointEncSlice)) { 193 /* H264 is desired */ 194 if (((profile == VAProfileH264Baseline || 195 profile == VAProfileH264Main || 196 profile == VAProfileH264High || 197 profile == VAProfileH264ConstrainedBaseline)) && 198 strstr(fool_ctx->fn_enc, "h264")) 199 fool_ctx->enabled = 1; 200 201 /* vp8 is desired */ 202 if ((profile == VAProfileVP8Version0_3) && 203 strstr(fool_ctx->fn_enc, "vp8")) 204 fool_ctx->enabled = 1; 205 } 206 if (fool_ctx->enabled) 207 va_infoMessage("FOOL is enabled for this context\n"); 208 else 209 va_infoMessage("FOOL is not enabled for this context\n"); 210 211 return 0; /* continue */ 212 } 213 214 215 VAStatus va_FoolCreateBuffer( 216 VADisplay dpy, 217 VAContextID __maybe_unused context, /* in */ 218 VABufferType type, /* in */ 219 unsigned int size, /* in */ 220 unsigned int num_elements, /* in */ 221 void __maybe_unused *data, /* in */ 222 VABufferID *buf_id /* out */ 223 ) 224 { 225 unsigned int new_size = size * num_elements; 226 unsigned int old_size; 227 DPY2FOOLCTX_CHK(dpy); 228 229 old_size = fool_ctx->fool_buf_size[type] * fool_ctx->fool_buf_element[type]; 230 231 if (old_size < new_size) 232 fool_ctx->fool_buf[type] = realloc(fool_ctx->fool_buf[type], new_size); 233 234 fool_ctx->fool_buf_size[type] = size; 235 fool_ctx->fool_buf_element[type] = num_elements; 236 fool_ctx->fool_buf_count[type]++; 237 /* because we ignore the vaRenderPicture, 238 * all buffers with same type share same real memory 239 * bufferID = (magic number) | type 240 */ 241 *buf_id = FOOL_BUFID_MAGIC | type; 242 243 return 1; /* don't call into driver */ 244 } 245 246 VAStatus va_FoolBufferInfo( 247 VADisplay dpy, 248 VABufferID buf_id, /* in */ 249 VABufferType *type, /* out */ 250 unsigned int *size, /* out */ 251 unsigned int *num_elements /* out */ 252 ) 253 { 254 unsigned int magic; 255 256 DPY2FOOLCTX_CHK(dpy); 257 258 magic = buf_id & FOOL_BUFID_MASK; 259 if (magic != FOOL_BUFID_MAGIC) 260 return 0; /* could be VAImageBufferType from vaDeriveImage */ 261 262 *type = buf_id & 0xff; 263 *size = fool_ctx->fool_buf_size[*type]; 264 *num_elements = fool_ctx->fool_buf_element[*type];; 265 266 return 1; /* fool is valid */ 267 } 268 269 static int va_FoolFillCodedBufEnc(struct fool_context *fool_ctx) 270 { 271 char file_name[1024]; 272 struct stat file_stat = {0}; 273 VACodedBufferSegment *codedbuf; 274 int i, fd = -1; 275 276 /* try file_name.file_count, if fail, try file_name.file_count-- */ 277 for (i=0; i<=1; i++) { 278 snprintf(file_name, 1024, "%s.%d", 279 fool_ctx->fn_enc, 280 fool_ctx->file_count); 281 282 if ((fd = open(file_name, O_RDONLY)) != -1) { 283 fstat(fd, &file_stat); 284 fool_ctx->file_count++; /* open next file */ 285 break; 286 } else /* fall back to the first file file */ 287 fool_ctx->file_count = 0; 288 } 289 if (fd != -1) { 290 fool_ctx->segbuf_enc = realloc(fool_ctx->segbuf_enc, file_stat.st_size); 291 read(fd, fool_ctx->segbuf_enc, file_stat.st_size); 292 close(fd); 293 } else 294 va_errorMessage("Open file %s failed:%s\n", file_name, strerror(errno)); 295 296 codedbuf = (VACodedBufferSegment *)fool_ctx->fool_buf[VAEncCodedBufferType]; 297 codedbuf->size = file_stat.st_size; 298 codedbuf->bit_offset = 0; 299 codedbuf->status = 0; 300 codedbuf->reserved = 0; 301 codedbuf->buf = fool_ctx->segbuf_enc; 302 codedbuf->next = NULL; 303 304 return 0; 305 } 306 307 static int va_FoolFillCodedBufJPG(struct fool_context *fool_ctx) 308 { 309 struct stat file_stat = {0}; 310 VACodedBufferSegment *codedbuf; 311 int fd = -1; 312 313 if ((fd = open(fool_ctx->fn_jpg, O_RDONLY)) != -1) { 314 fstat(fd, &file_stat); 315 fool_ctx->segbuf_jpg = realloc(fool_ctx->segbuf_jpg, file_stat.st_size); 316 read(fd, fool_ctx->segbuf_jpg, file_stat.st_size); 317 close(fd); 318 } else 319 va_errorMessage("Open file %s failed:%s\n", fool_ctx->fn_jpg, strerror(errno)); 320 321 codedbuf = (VACodedBufferSegment *)fool_ctx->fool_buf[VAEncCodedBufferType]; 322 codedbuf->size = file_stat.st_size; 323 codedbuf->bit_offset = 0; 324 codedbuf->status = 0; 325 codedbuf->reserved = 0; 326 codedbuf->buf = fool_ctx->segbuf_jpg; 327 codedbuf->next = NULL; 328 329 return 0; 330 } 331 332 333 static int va_FoolFillCodedBuf(struct fool_context *fool_ctx) 334 { 335 if (fool_ctx->entrypoint == VAEntrypointEncSlice) 336 va_FoolFillCodedBufEnc(fool_ctx); 337 else if (fool_ctx->entrypoint == VAEntrypointEncPicture) 338 va_FoolFillCodedBufJPG(fool_ctx); 339 340 return 0; 341 } 342 343 344 VAStatus va_FoolMapBuffer( 345 VADisplay dpy, 346 VABufferID buf_id, /* in */ 347 void **pbuf /* out */ 348 ) 349 { 350 unsigned int magic, buftype; 351 DPY2FOOLCTX_CHK(dpy); 352 353 magic = buf_id & FOOL_BUFID_MASK; 354 if (magic != FOOL_BUFID_MAGIC) 355 return 0; /* could be VAImageBufferType from vaDeriveImage */ 356 357 buftype = buf_id & 0xff; 358 *pbuf = fool_ctx->fool_buf[buftype]; 359 360 /* it is coded buffer, fill coded segment from file */ 361 if (*pbuf && (buftype == VAEncCodedBufferType)) 362 va_FoolFillCodedBuf(fool_ctx); 363 364 return 1; /* fool is valid */ 365 } 366 367 VAStatus va_FoolCheckContinuity(VADisplay dpy) 368 { 369 DPY2FOOLCTX_CHK(dpy); 370 371 return 1; /* fool is valid */ 372 } 373 374