You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
373 lines
12 KiB
373 lines
12 KiB
/* |
|
* 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 */ |
|
} |
|
|
|
|