/* * 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 #include #include #include #include #include #include #include #include #include #include /* * 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, but fill in some YUV data * LIBVA_FOOL_ENCODE=: * . if set, encode does nothing, but fill in the coded buffer from a H264 clip. * . VA CONTEXT/CONFIG/SURFACE will call into drivers, but VA Buffer creation is done in here * . Bypass all "vaBeginPic/vaRenderPic/vaEndPic" * LIBVA_FOOL_POSTP: * . if set, do nothing for vaPutSurface */ /* global settings */ /* LIBVA_FOOL_DECODE/LIBVA_FOOL_ENCODE/LIBVA_FOOL_POSTP */ int fool_decode = 0; int fool_encode = 0; int fool_postp = 0; #define NAL_BUF_SIZE 65536 // maximum NAL unit size #define RING_BUF_SIZE 8192 // input ring buffer size, MUST be a power of two! #define MAX_FRAME 16 #define SLICE_NUM 4 #define FOOL_CONTEXT_MAX 4 /* per context settings */ static struct _fool_context { VADisplay dpy; /* should use context as the key */ VAProfile fool_profile; /* current profile for buffers */ VAEntrypoint fool_entrypoint; /* current entrypoint */ FILE *fool_fp_codedclip; /* load a clip from disk for fooling encode*/ char *frame_buf; VACodedBufferSegment *codebuf; /* 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_count[VABufferTypeMax]; /* count of created buffers */ VAContextID context; } fool_context[FOOL_CONTEXT_MAX] = { {0} }; /* trace five context at the same time */ #define FOOL_DECODE(idx) (fool_decode && (fool_context[idx].fool_entrypoint == VAEntrypointVLD)) #define FOOL_ENCODE(idx) \ (fool_encode \ && (fool_context[idx].fool_entrypoint == VAEntrypointEncSlice) \ && (fool_context[idx].fool_profile >= VAProfileH264Baseline) \ && (fool_context[idx].fool_profile <= VAProfileH264High)) #define DPY2INDEX(dpy) \ int idx; \ \ for (idx = 0; idx < FOOL_CONTEXT_MAX; idx++) \ if (fool_context[idx].dpy == dpy) \ break; \ \ if (idx == FOOL_CONTEXT_MAX) \ return 0; /* let driver go */ /* 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); VAStatus vaBufferInfo( VADisplay dpy, VAContextID context, /* in */ VABufferID buf_id, /* in */ VABufferType *type, /* out */ unsigned int *size, /* out */ unsigned int *num_elements /* out */ ); VAStatus vaLockSurface(VADisplay dpy, VASurfaceID surface, unsigned int *fourcc, /* following are output argument */ unsigned int *luma_stride, unsigned int *chroma_u_stride, unsigned int *chroma_v_stride, unsigned int *luma_offset, unsigned int *chroma_u_offset, unsigned int *chroma_v_offset, unsigned int *buffer_name, void **buffer ); VAStatus vaUnlockSurface(VADisplay dpy, VASurfaceID surface ); void va_FoolInit(VADisplay dpy) { char env_value[1024]; int fool_index = 0; for (fool_index = 0; fool_index < FOOL_CONTEXT_MAX; fool_index++) if (fool_context[fool_index].dpy == 0) break; if (fool_index == FOOL_CONTEXT_MAX) 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_decode = 1; va_infoMessage("LIBVA_FOOL_DECODE is on, dummy decode\n"); } if (va_parseConfig("LIBVA_FOOL_ENCODE", &env_value[0]) == 0) { fool_context[fool_index].fool_fp_codedclip = fopen(env_value, "r"); if (fool_context[fool_index].fool_fp_codedclip) { fool_encode = 1; } else fool_encode = 0; if (fool_encode) /* malloc the buffer for fake clip */ { fool_context[fool_index].frame_buf = malloc(MAX_FRAME*SLICE_NUM*NAL_BUF_SIZE*sizeof(char)); fool_context[fool_index].codebuf = malloc(sizeof(VACodedBufferSegment)); } if (fool_context[fool_index].frame_buf == NULL) fool_encode = 0; if (fool_encode) va_infoMessage("LIBVA_FOOL_ENCODE is on, dummy encode\n"); } if (fool_encode || fool_decode) fool_context[fool_index].dpy = dpy; } int va_FoolEnd(VADisplay dpy) { int i; DPY2INDEX(dpy); for (i = 0; i < VABufferTypeMax; i++) {/* free memory */ if (fool_context[idx].fool_buf[i]) free(fool_context[idx].fool_buf[i]); } if (fool_context[idx].fool_fp_codedclip) fclose(fool_context[idx].fool_fp_codedclip); if (fool_context[idx].frame_buf) free(fool_context[idx].frame_buf); if (fool_context[idx].codebuf) free(fool_context[idx].codebuf); memset(&fool_context[idx], sizeof(struct _fool_context), 0); return 0; } int va_FoolCodedBuf(VADisplay dpy) { /* do nothing */ return 0; } int va_FoolCreateConfig( VADisplay dpy, VAProfile profile, VAEntrypoint entrypoint, VAConfigAttrib *attrib_list, int num_attribs, VAConfigID *config_id /* out */ ) { DPY2INDEX(dpy); /* call into driver level to allocate real context/surface/buffers, etc */ fool_context[idx].fool_profile = profile; fool_context[idx].fool_entrypoint = entrypoint; return 0; } static int yuvgen_planar( int width, int height, unsigned char *Y_start, int Y_pitch, unsigned char *U_start, int U_pitch, unsigned char *V_start, int V_pitch, int UV_interleave, int box_width, int row_shift, int field ) { int row; /* copy Y plane */ for (row=0;rowsize = frame_size; fool_context[idx].codebuf->bit_offset = 0; fool_context[idx].codebuf->status = 0; fool_context[idx].codebuf->reserved = 0; fool_context[idx].codebuf->buf = fool_context[idx].frame_buf; fool_context[idx].codebuf->next = NULL; *pbuf = fool_context[idx].codebuf; } return 1; /* don't call into driver */ } return 0; /* let driver go ... */ } int va_FoolBeginPicture( VADisplay dpy, VAContextID context, VASurfaceID render_target ) { DPY2INDEX(dpy); if (FOOL_ENCODE(idx) || FOOL_DECODE(idx)) { if (fool_context[idx].context == 0) fool_context[idx].context = context; return 1; /* don't call into driver level */ } return 0; /* let driver go ... */ } int va_FoolRenderPicture( VADisplay dpy, VAContextID context, VABufferID *buffers, int num_buffers ) { DPY2INDEX(dpy); if (FOOL_ENCODE(idx) || FOOL_DECODE(idx)) return 1; /* don't call into driver level */ return 0; /* let driver go ... */ } int va_FoolEndPicture( VADisplay dpy, VAContextID context ) { DPY2INDEX(dpy); /* don't call into driver level */ /* do real fooling operation here */ /* only support H264 encoding currently */ if (FOOL_ENCODE(idx)) { /* expect vaMapBuffer will handle it * or else, need to save the codedbuf ID, * and fool encode it here */ /* va_FoolCodedBuf(dpy); */ return 1; /* don't call into driver level */ } if (FOOL_DECODE(idx)) return 1; /* don't call into driver level */ return 0; /* let driver go ... */ } int va_FoolSyncSurface( VADisplay dpy, VASurfaceID render_target ) { DPY2INDEX(dpy); /*Fill in black and white squares. */ if (FOOL_DECODE(idx) || FOOL_DECODE(idx)) return 1; return 0; } VAStatus va_FoolUnmapBuffer( VADisplay dpy, VABufferID buf_id /* in */ ) { DPY2INDEX(dpy); if (FOOL_ENCODE(idx) || FOOL_DECODE(idx)) return 1; /* fool buffer creation */ return 0; } VAStatus va_FoolQuerySubpictureFormats( VADisplay dpy, VAImageFormat *format_list, unsigned int *flags, unsigned int *num_formats ) { DPY2INDEX(dpy); if (FOOL_ENCODE(idx) || FOOL_DECODE(idx)) { if (num_formats) *num_formats = 0; return 1; } return 0; }