| /* |
| * Copyright (c) 2009 Intel Corporation. All Rights Reserved. |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the |
| * "Software"), to deal in the Software without restriction, including |
| * without limitation the rights to use, copy, modify, merge, publish, |
| * distribute, sub license, and/or sell copies of the Software, and to |
| * permit persons to whom the Software is furnished to do so, subject to |
| * the following conditions: |
| * |
| * The above copyright notice and this permission notice (including the |
| * next paragraph) shall be included in all copies or substantial portions |
| * of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. |
| * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR |
| * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
| * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
| * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| */ |
| |
| #define _GNU_SOURCE 1 |
| #include "va.h" |
| #include "va_backend.h" |
| #include "va_trace.h" |
| #include "va_fool.h" |
| |
| #include <assert.h> |
| #include <stdarg.h> |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <errno.h> |
| #include <string.h> |
| #include <dlfcn.h> |
| #include <unistd.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <unistd.h> |
| #include <time.h> |
| #include <fcntl.h> |
| |
| /* |
| * Do dummy decode/encode, ignore the input data |
| * In order to debug memory leak or low performance issues, we need to isolate driver problems |
| * We export env "VA_FOOL", with which, we can do fake decode/encode: |
| * |
| * LIBVA_FOOL_DECODE: |
| * . if set, decode does nothing |
| * LIBVA_FOOL_ENCODE=<framename>: |
| * . if set, encode does nothing, but fill in the coded buffer from the content of files with |
| * name framename.0,framename.1,..., framename.N, framename.0,..., framename.N,...repeatly |
| * Use file name to determine h264 or vp8 |
| * LIBVA_FOOL_JPEG=<framename>:fill the content of filename to codedbuf for jpeg encoding |
| * LIBVA_FOOL_POSTP: |
| * . if set, do nothing for vaPutSurface |
| */ |
| |
| |
| /* global settings */ |
| int fool_codec = 0; |
| int fool_postp = 0; |
| |
| #define FOOL_BUFID_MAGIC 0x12345600 |
| #define FOOL_BUFID_MASK 0xffffff00 |
| |
| struct fool_context { |
| int enabled; /* fool_codec is global, and it is for concurent encode/decode */ |
| char *fn_enc;/* file pattern with codedbuf content for encode */ |
| char *segbuf_enc; /* the segment buffer of coded buffer, load frome fn_enc */ |
| int file_count; |
| |
| char *fn_jpg;/* file name of JPEG fool with codedbuf content */ |
| char *segbuf_jpg; /* the segment buffer of coded buffer, load frome fn_jpg */ |
| |
| VAEntrypoint entrypoint; /* current entrypoint */ |
| |
| /* all buffers with same type share one malloc-ed memory |
| * bufferID = (buffer numbers with the same type << 8) || type |
| * the malloc-ed memory can be find by fool_buf[bufferID & 0xff] |
| * the size is ignored here |
| */ |
| char *fool_buf[VABufferTypeMax]; /* memory of fool buffers */ |
| unsigned int fool_buf_size[VABufferTypeMax]; /* size of memory of fool buffers */ |
| unsigned int fool_buf_element[VABufferTypeMax]; /* element count of created buffers */ |
| unsigned int fool_buf_count[VABufferTypeMax]; /* count of created buffers */ |
| VAContextID context; |
| }; |
| |
| #define FOOL_CTX(dpy) ((struct fool_context *)((VADisplayContextP)dpy)->vafool) |
| |
| #define DPY2FOOLCTX(dpy) \ |
| struct fool_context *fool_ctx = FOOL_CTX(dpy); \ |
| if (fool_ctx == NULL) \ |
| return 0; /* no fool for the context */ \ |
| |
| #define DPY2FOOLCTX_CHK(dpy) \ |
| struct fool_context *fool_ctx = FOOL_CTX(dpy); \ |
| if ((fool_ctx == NULL) || (fool_ctx->enabled == 0)) \ |
| return 0; /* no fool for the context */ \ |
| |
| /* Prototype declarations (functions defined in va.c) */ |
| |
| void va_errorMessage(const char *msg, ...); |
| void va_infoMessage(const char *msg, ...); |
| |
| int va_parseConfig(char *env, char *env_value); |
| |
| void va_FoolInit(VADisplay dpy) |
| { |
| char env_value[1024]; |
| |
| struct fool_context *fool_ctx = calloc(sizeof(struct fool_context), 1); |
| |
| if (fool_ctx == NULL) |
| return; |
| |
| if (va_parseConfig("LIBVA_FOOL_POSTP", NULL) == 0) { |
| fool_postp = 1; |
| va_infoMessage("LIBVA_FOOL_POSTP is on, dummy vaPutSurface\n"); |
| } |
| |
| if (va_parseConfig("LIBVA_FOOL_DECODE", NULL) == 0) { |
| fool_codec |= VA_FOOL_FLAG_DECODE; |
| va_infoMessage("LIBVA_FOOL_DECODE is on, dummy decode\n"); |
| } |
| if (va_parseConfig("LIBVA_FOOL_ENCODE", &env_value[0]) == 0) { |
| fool_codec |= VA_FOOL_FLAG_ENCODE; |
| fool_ctx->fn_enc = strdup(env_value); |
| va_infoMessage("LIBVA_FOOL_ENCODE is on, load encode data from file with patten %s\n", |
| fool_ctx->fn_enc); |
| } |
| if (va_parseConfig("LIBVA_FOOL_JPEG", &env_value[0]) == 0) { |
| fool_codec |= VA_FOOL_FLAG_JPEG; |
| fool_ctx->fn_jpg = strdup(env_value); |
| va_infoMessage("LIBVA_FOOL_JPEG is on, load encode data from file with patten %s\n", |
| fool_ctx->fn_jpg); |
| } |
| |
| ((VADisplayContextP)dpy)->vafool = fool_ctx; |
| } |
| |
| |
| int va_FoolEnd(VADisplay dpy) |
| { |
| int i; |
| DPY2FOOLCTX(dpy); |
| |
| for (i = 0; i < VABufferTypeMax; i++) {/* free memory */ |
| if (fool_ctx->fool_buf[i]) |
| free(fool_ctx->fool_buf[i]); |
| } |
| if (fool_ctx->segbuf_enc) |
| free(fool_ctx->segbuf_enc); |
| if (fool_ctx->segbuf_jpg) |
| free(fool_ctx->segbuf_jpg); |
| if (fool_ctx->fn_enc) |
| free(fool_ctx->fn_enc); |
| if (fool_ctx->fn_jpg) |
| free(fool_ctx->fn_jpg); |
| |
| free(fool_ctx); |
| ((VADisplayContextP)dpy)->vafool = NULL; |
| |
| return 0; |
| } |
| |
| int va_FoolCreateConfig( |
| VADisplay dpy, |
| VAProfile profile, |
| VAEntrypoint entrypoint, |
| VAConfigAttrib __maybe_unused *attrib_list, |
| int __maybe_unused num_attribs, |
| VAConfigID __maybe_unused *config_id /* out */ |
| ) |
| { |
| DPY2FOOLCTX(dpy); |
| |
| fool_ctx->entrypoint = entrypoint; |
| |
| /* |
| * check fool_codec to align with current context |
| * e.g. fool_codec = decode then for encode, the |
| * vaBegin/vaRender/vaEnd also run into fool path |
| * which is not desired |
| */ |
| if (((fool_codec & VA_FOOL_FLAG_DECODE) && (entrypoint == VAEntrypointVLD)) || |
| ((fool_codec & VA_FOOL_FLAG_JPEG) && (entrypoint == VAEntrypointEncPicture))) |
| fool_ctx->enabled = 1; |
| else if ((fool_codec & VA_FOOL_FLAG_ENCODE) && (entrypoint == VAEntrypointEncSlice)) { |
| /* H264 is desired */ |
| if (((profile == VAProfileH264Baseline || |
| profile == VAProfileH264Main || |
| profile == VAProfileH264High || |
| profile == VAProfileH264ConstrainedBaseline)) && |
| strstr(fool_ctx->fn_enc, "h264")) |
| fool_ctx->enabled = 1; |
| |
| /* vp8 is desired */ |
| if ((profile == VAProfileVP8Version0_3) && |
| strstr(fool_ctx->fn_enc, "vp8")) |
| fool_ctx->enabled = 1; |
| } |
| if (fool_ctx->enabled) |
| va_infoMessage("FOOL is enabled for this context\n"); |
| else |
| va_infoMessage("FOOL is not enabled for this context\n"); |
| |
| return 0; /* continue */ |
| } |
| |
| |
| VAStatus va_FoolCreateBuffer( |
| VADisplay dpy, |
| VAContextID __maybe_unused context, /* in */ |
| VABufferType type, /* in */ |
| unsigned int size, /* in */ |
| unsigned int num_elements, /* in */ |
| void __maybe_unused *data, /* in */ |
| VABufferID *buf_id /* out */ |
| ) |
| { |
| unsigned int new_size = size * num_elements; |
| unsigned int old_size; |
| DPY2FOOLCTX_CHK(dpy); |
| |
| old_size = fool_ctx->fool_buf_size[type] * fool_ctx->fool_buf_element[type]; |
| |
| if (old_size < new_size) |
| fool_ctx->fool_buf[type] = realloc(fool_ctx->fool_buf[type], new_size); |
| |
| fool_ctx->fool_buf_size[type] = size; |
| fool_ctx->fool_buf_element[type] = num_elements; |
| fool_ctx->fool_buf_count[type]++; |
| /* because we ignore the vaRenderPicture, |
| * all buffers with same type share same real memory |
| * bufferID = (magic number) | type |
| */ |
| *buf_id = FOOL_BUFID_MAGIC | type; |
| |
| return 1; /* don't call into driver */ |
| } |
| |
| VAStatus va_FoolBufferInfo( |
| VADisplay dpy, |
| VABufferID buf_id, /* in */ |
| VABufferType *type, /* out */ |
| unsigned int *size, /* out */ |
| unsigned int *num_elements /* out */ |
| ) |
| { |
| unsigned int magic; |
| |
| DPY2FOOLCTX_CHK(dpy); |
| |
| magic = buf_id & FOOL_BUFID_MASK; |
| if (magic != FOOL_BUFID_MAGIC) |
| return 0; /* could be VAImageBufferType from vaDeriveImage */ |
| |
| *type = buf_id & 0xff; |
| *size = fool_ctx->fool_buf_size[*type]; |
| *num_elements = fool_ctx->fool_buf_element[*type];; |
| |
| return 1; /* fool is valid */ |
| } |
| |
| static int va_FoolFillCodedBufEnc(struct fool_context *fool_ctx) |
| { |
| char file_name[1024]; |
| struct stat file_stat = {0}; |
| VACodedBufferSegment *codedbuf; |
| int i, fd = -1; |
| |
| /* try file_name.file_count, if fail, try file_name.file_count-- */ |
| for (i=0; i<=1; i++) { |
| snprintf(file_name, 1024, "%s.%d", |
| fool_ctx->fn_enc, |
| fool_ctx->file_count); |
| |
| if ((fd = open(file_name, O_RDONLY)) != -1) { |
| fstat(fd, &file_stat); |
| fool_ctx->file_count++; /* open next file */ |
| break; |
| } else /* fall back to the first file file */ |
| fool_ctx->file_count = 0; |
| } |
| if (fd != -1) { |
| fool_ctx->segbuf_enc = realloc(fool_ctx->segbuf_enc, file_stat.st_size); |
| read(fd, fool_ctx->segbuf_enc, file_stat.st_size); |
| close(fd); |
| } else |
| va_errorMessage("Open file %s failed:%s\n", file_name, strerror(errno)); |
| |
| codedbuf = (VACodedBufferSegment *)fool_ctx->fool_buf[VAEncCodedBufferType]; |
| codedbuf->size = file_stat.st_size; |
| codedbuf->bit_offset = 0; |
| codedbuf->status = 0; |
| codedbuf->reserved = 0; |
| codedbuf->buf = fool_ctx->segbuf_enc; |
| codedbuf->next = NULL; |
| |
| return 0; |
| } |
| |
| static int va_FoolFillCodedBufJPG(struct fool_context *fool_ctx) |
| { |
| struct stat file_stat = {0}; |
| VACodedBufferSegment *codedbuf; |
| int fd = -1; |
| |
| if ((fd = open(fool_ctx->fn_jpg, O_RDONLY)) != -1) { |
| fstat(fd, &file_stat); |
| fool_ctx->segbuf_jpg = realloc(fool_ctx->segbuf_jpg, file_stat.st_size); |
| read(fd, fool_ctx->segbuf_jpg, file_stat.st_size); |
| close(fd); |
| } else |
| va_errorMessage("Open file %s failed:%s\n", fool_ctx->fn_jpg, strerror(errno)); |
| |
| codedbuf = (VACodedBufferSegment *)fool_ctx->fool_buf[VAEncCodedBufferType]; |
| codedbuf->size = file_stat.st_size; |
| codedbuf->bit_offset = 0; |
| codedbuf->status = 0; |
| codedbuf->reserved = 0; |
| codedbuf->buf = fool_ctx->segbuf_jpg; |
| codedbuf->next = NULL; |
| |
| return 0; |
| } |
| |
| |
| static int va_FoolFillCodedBuf(struct fool_context *fool_ctx) |
| { |
| if (fool_ctx->entrypoint == VAEntrypointEncSlice) |
| va_FoolFillCodedBufEnc(fool_ctx); |
| else if (fool_ctx->entrypoint == VAEntrypointEncPicture) |
| va_FoolFillCodedBufJPG(fool_ctx); |
| |
| return 0; |
| } |
| |
| |
| VAStatus va_FoolMapBuffer( |
| VADisplay dpy, |
| VABufferID buf_id, /* in */ |
| void **pbuf /* out */ |
| ) |
| { |
| unsigned int magic, buftype; |
| DPY2FOOLCTX_CHK(dpy); |
| |
| magic = buf_id & FOOL_BUFID_MASK; |
| if (magic != FOOL_BUFID_MAGIC) |
| return 0; /* could be VAImageBufferType from vaDeriveImage */ |
| |
| buftype = buf_id & 0xff; |
| *pbuf = fool_ctx->fool_buf[buftype]; |
| |
| /* it is coded buffer, fill coded segment from file */ |
| if (*pbuf && (buftype == VAEncCodedBufferType)) |
| va_FoolFillCodedBuf(fool_ctx); |
| |
| return 1; /* fool is valid */ |
| } |
| |
| VAStatus va_FoolCheckContinuity(VADisplay dpy) |
| { |
| DPY2FOOLCTX_CHK(dpy); |
| |
| return 1; /* fool is valid */ |
| } |
| |