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 */
63int fool_codec = 0;
64int fool_postp  = 0;
65
66#define FOOL_BUFID_MAGIC   0x12345600
67#define FOOL_BUFID_MASK    0xffffff00
68
69struct 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
106void va_errorMessage(const char *msg, ...);
107void va_infoMessage(const char *msg, ...);
108
109int  va_parseConfig(char *env, char *env_value);
110
111void 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
146int 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
170int 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
215VAStatus 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
246VAStatus 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
269static 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
307static 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
333static 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
344VAStatus 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
367VAStatus va_FoolCheckContinuity(VADisplay dpy)
368{
369    DPY2FOOLCTX_CHK(dpy);
370
371    return 1; /* fool is valid */
372}
373
374