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 
va_FoolInit(VADisplay dpy)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 
va_FoolEnd(VADisplay dpy)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 
va_FoolCreateConfig(VADisplay dpy,VAProfile profile,VAEntrypoint entrypoint,VAConfigAttrib __maybe_unused * attrib_list,int __maybe_unused num_attribs,VAConfigID __maybe_unused * config_id)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 
va_FoolCreateBuffer(VADisplay dpy,VAContextID __maybe_unused context,VABufferType type,unsigned int size,unsigned int num_elements,void __maybe_unused * data,VABufferID * buf_id)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 
va_FoolBufferInfo(VADisplay dpy,VABufferID buf_id,VABufferType * type,unsigned int * size,unsigned int * num_elements)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 
va_FoolFillCodedBufEnc(struct fool_context * fool_ctx)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 
va_FoolFillCodedBufJPG(struct fool_context * fool_ctx)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 
va_FoolFillCodedBuf(struct fool_context * fool_ctx)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 
va_FoolMapBuffer(VADisplay dpy,VABufferID buf_id,void ** pbuf)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 
va_FoolCheckContinuity(VADisplay dpy)367 VAStatus va_FoolCheckContinuity(VADisplay dpy)
368 {
369     DPY2FOOLCTX_CHK(dpy);
370 
371     return 1; /* fool is valid */
372 }
373 
374