Subversion Repositories eduke32

Rev

Rev 4762 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 4762 Rev 4998
1
/* ANM file replacement with VP8 video */
1
/* ANM file replacement with VP8 video */
2
2
3
#ifdef USE_LIBVPX
3
#ifdef USE_LIBVPX
4
4
5
#ifndef __STDC_FORMAT_MACROS
5
#ifndef __STDC_FORMAT_MACROS
6
#define __STDC_FORMAT_MACROS
6
#define __STDC_FORMAT_MACROS
7
#endif
7
#endif
8
#ifndef __STDC_LIMIT_MACROS
8
#ifndef __STDC_LIMIT_MACROS
9
#define __STDC_LIMIT_MACROS
9
#define __STDC_LIMIT_MACROS
10
#endif
10
#endif
11
11
12
12
13
#include <stdint.h>
13
#include <stdint.h>
14
14
15
#include "compat.h"
15
#include "compat.h"
16
#include "baselayer.h"
16
#include "baselayer.h"
17
#include "build.h"
17
#include "build.h"
18
#include "glbuild.h"
18
#include "glbuild.h"
19
19
20
#define VPX_CODEC_DISABLE_COMPAT 1
20
#define VPX_CODEC_DISABLE_COMPAT 1
21
#include <vpx/vpx_decoder.h>
21
#include <vpx/vpx_decoder.h>
22
#include <vpx/vp8dx.h>
22
#include <vpx/vp8dx.h>
23
23
24
#include "duke3d.h"
24
#include "duke3d.h"
25
#include "game.h"  // kopen4loadfrommod
25
#include "game.h"  // kopen4loadfrommod
26
#include "animvpx.h"
26
#include "animvpx.h"
27
27
28
const char *animvpx_read_ivf_header_errmsg[] = {
28
const char *animvpx_read_ivf_header_errmsg[] = {
29
    "All OK",
29
    "All OK",
30
    "couldn't read 32-byte IVF header",
30
    "couldn't read 32-byte IVF header",
31
    "magic mismatch, not an IVF file",
31
    "magic mismatch, not an IVF file",
32
    "unrecognized IVF version, expected 0",
32
    "unrecognized IVF version, expected 0",
33
    "only VP8 video stream supported",
33
    "only VP8 video stream supported",
34
    "invalid framerate numerator or denominator after correction, must not be 0",
34
    "invalid framerate numerator or denominator after correction, must not be 0",
35
};
35
};
36
36
37
EDUKE32_STATIC_ASSERT(sizeof(animvpx_ivf_header_t) == 32);
37
EDUKE32_STATIC_ASSERT(sizeof(animvpx_ivf_header_t) == 32);
38
38
39
int32_t animvpx_read_ivf_header(int32_t inhandle, animvpx_ivf_header_t *hdr)
39
int32_t animvpx_read_ivf_header(int32_t inhandle, animvpx_ivf_header_t *hdr)
40
{
40
{
41
    int32_t err;
41
    int32_t err;
42
42
43
    if (kread(inhandle, hdr, sizeof(animvpx_ivf_header_t)) != sizeof(animvpx_ivf_header_t))
43
    if (kread(inhandle, hdr, sizeof(animvpx_ivf_header_t)) != sizeof(animvpx_ivf_header_t))
44
        return 1;  // "couldn't read header"
44
        return 1;  // "couldn't read header"
45
45
46
    err = animvpx_check_header(hdr);
46
    err = animvpx_check_header(hdr);
47
    if (err)
47
    if (err)
48
        return err;
48
        return err;
49
49
50
    hdr->hdrlen = B_LITTLE16(hdr->hdrlen);
50
    hdr->hdrlen = B_LITTLE16(hdr->hdrlen);
51
51
52
    hdr->width = B_LITTLE16(hdr->width);
52
    hdr->width = B_LITTLE16(hdr->width);
53
    hdr->height = B_LITTLE16(hdr->height);
53
    hdr->height = B_LITTLE16(hdr->height);
54
    hdr->fpsnumer = B_LITTLE16(hdr->fpsnumer);
54
    hdr->fpsnumer = B_LITTLE16(hdr->fpsnumer);
55
    hdr->fpsdenom = B_LITTLE16(hdr->fpsdenom);
55
    hdr->fpsdenom = B_LITTLE16(hdr->fpsdenom);
56
56
57
    hdr->numframes = B_LITTLE32(hdr->numframes);
57
    hdr->numframes = B_LITTLE32(hdr->numframes);
58
58
59
    // the rest is based on vpxdec.c --> file_is_ivf()
59
    // the rest is based on vpxdec.c --> file_is_ivf()
60
60
61
    if (hdr->fpsnumer < 1000)
61
    if (hdr->fpsnumer < 1000)
62
    {
62
    {
63
        // NOTE: We got rid of the 1/(2*fps) correction from libvpx's vpxdec.c,
63
        // NOTE: We got rid of the 1/(2*fps) correction from libvpx's vpxdec.c,
64
        // users are encouraged to use the "ivfrate" utility from the source/
64
        // users are encouraged to use the "ivfrate" utility from the source/
65
        // directory instead.
65
        // directory instead.
66
66
67
        if (hdr->fpsdenom==0 || hdr->fpsnumer==0)
67
        if (hdr->fpsdenom==0 || hdr->fpsnumer==0)
68
            return 5;  // "invalid framerate numerator or denominator"
68
            return 5;  // "invalid framerate numerator or denominator"
69
69
70
        initprintf("animvpx: rate is %d frames / %d seconds (%.03f fps).\n",
70
        initprintf("animvpx: rate is %d frames / %d seconds (%.03f fps).\n",
71
                   hdr->fpsnumer, hdr->fpsdenom, (double)hdr->fpsnumer/hdr->fpsdenom);
71
                   hdr->fpsnumer, hdr->fpsdenom, (double)hdr->fpsnumer/hdr->fpsdenom);
72
    }
72
    }
73
    else
73
    else
74
    {
74
    {
75
        double fps = (hdr->fpsdenom==0) ? 0.0 : (double)hdr->fpsnumer/hdr->fpsdenom;
75
        double fps = (hdr->fpsdenom==0) ? 0.0 : (double)hdr->fpsnumer/hdr->fpsdenom;
76
76
77
        initprintf("animvpx: set rate to 30 fps (header says %d frames / %d seconds = %.03f fps).\n",
77
        initprintf("animvpx: set rate to 30 fps (header says %d frames / %d seconds = %.03f fps).\n",
78
                   hdr->fpsnumer, hdr->fpsdenom, fps);
78
                   hdr->fpsnumer, hdr->fpsdenom, fps);
79
79
80
        /* Don't know FPS for sure, and don't have readahead code
80
        /* Don't know FPS for sure, and don't have readahead code
81
         * (yet?), so just default to 30fps.
81
         * (yet?), so just default to 30fps.
82
         */
82
         */
83
        hdr->fpsnumer = 30;
83
        hdr->fpsnumer = 30;
84
        hdr->fpsdenom = 1;
84
        hdr->fpsdenom = 1;
85
    }
85
    }
86
86
87
    return 0;
87
    return 0;
88
}
88
}
89
89
90
////////// CODEC STUFF //////////
90
////////// CODEC STUFF //////////
91
static void get_codec_error(animvpx_codec_ctx *codec)
91
static void get_codec_error(animvpx_codec_ctx *codec)
92
{
92
{
93
    codec->errmsg_detail = vpx_codec_error_detail(&codec->codec);
93
    codec->errmsg_detail = vpx_codec_error_detail(&codec->codec);
94
    codec->errmsg = vpx_codec_error(&codec->codec);
94
    codec->errmsg = vpx_codec_error(&codec->codec);
95
}
95
}
96
96
97
// no checks for double-init!
97
// no checks for double-init!
98
int32_t animvpx_init_codec(const animvpx_ivf_header_t *info, int32_t inhandle, animvpx_codec_ctx *codec)
98
int32_t animvpx_init_codec(const animvpx_ivf_header_t *info, int32_t inhandle, animvpx_codec_ctx *codec)
99
{
99
{
100
    vpx_codec_dec_cfg_t cfg;
100
    vpx_codec_dec_cfg_t cfg;
101
101
102
    cfg.threads = 1;
102
    cfg.threads = 1;
103
    cfg.w = info->width;
103
    cfg.w = info->width;
104
    cfg.h = info->height;
104
    cfg.h = info->height;
105
105
106
    codec->width = info->width;
106
    codec->width = info->width;
107
    codec->height = info->height;
107
    codec->height = info->height;
108
108
109
    //
109
    //
110
    codec->inhandle = inhandle;
110
    codec->inhandle = inhandle;
111
    codec->pic = (uint8_t *)Bcalloc(info->width*info->height,4);
111
    codec->pic = (uint8_t *)Bcalloc(info->width*info->height,4);
112
112
113
    codec->compbuflen = codec->compbufallocsiz = 0;
113
    codec->compbuflen = codec->compbufallocsiz = 0;
114
    codec->compbuf = NULL;
114
    codec->compbuf = NULL;
115
115
116
    codec->iter = NULL;
116
    codec->iter = NULL;
117
117
118
    if (codec->pic == NULL)
118
    if (codec->pic == NULL)
119
    {
119
    {
120
        codec->initstate = -1;
120
        codec->initstate = -1;
121
        return 1;
121
        return 1;
122
    }
122
    }
123
123
124
    if (vpx_codec_dec_init(&codec->codec, &vpx_codec_vp8_dx_algo, &cfg, 0))
124
    if (vpx_codec_dec_init(&codec->codec, &vpx_codec_vp8_dx_algo, &cfg, 0))
125
    {
125
    {
126
        get_codec_error(codec);
126
        get_codec_error(codec);
127
        codec->initstate = -1;
127
        codec->initstate = -1;
128
        return 1;
128
        return 1;
129
    }
129
    }
130
130
131
    codec->initstate = 1;
131
    codec->initstate = 1;
132
    codec->decstate = 0;
132
    codec->decstate = 0;
133
133
134
    codec->errmsg_detail = codec->errmsg = NULL;
134
    codec->errmsg_detail = codec->errmsg = NULL;
135
135
136
    codec->numframes = 0;
136
    codec->numframes = 0;
137
    Bmemset(codec->sumtimes, 0, sizeof(codec->sumtimes));
137
    Bmemset(codec->sumtimes, 0, sizeof(codec->sumtimes));
138
    Bmemset(codec->maxtimes, 0, sizeof(codec->maxtimes));
138
    Bmemset(codec->maxtimes, 0, sizeof(codec->maxtimes));
139
139
140
    return 0;
140
    return 0;
141
}
141
}
142
142
143
int32_t animvpx_uninit_codec(animvpx_codec_ctx *codec)
143
int32_t animvpx_uninit_codec(animvpx_codec_ctx *codec)
144
{
144
{
145
    if (codec->initstate <= 0)
145
    if (codec->initstate <= 0)
146
        return 2;
146
        return 2;
147
147
148
    Bfree(codec->pic);
148
    Bfree(codec->pic);
149
    codec->pic = NULL;
149
    codec->pic = NULL;
150
150
151
    if (vpx_codec_destroy(&codec->codec))
151
    if (vpx_codec_destroy(&codec->codec))
152
    {
152
    {
153
        get_codec_error(codec);
153
        get_codec_error(codec);
154
        codec->initstate = -2;
154
        codec->initstate = -2;
155
        return 1;
155
        return 1;
156
    }
156
    }
157
157
158
    codec->initstate = 0;
158
    codec->initstate = 0;
159
159
160
    return 0;
160
    return 0;
161
}
161
}
162
162
163
////////// FRAME RETRIEVAL //////////
163
////////// FRAME RETRIEVAL //////////
164
164
165
// read one IVF/VP8 frame, which may code multiple "picture-frames"
165
// read one IVF/VP8 frame, which may code multiple "picture-frames"
166
static int32_t animvpx_read_frame(int32_t inhandle, uint8_t **bufptr, uint32_t *bufsizptr, uint32_t *bufallocsizptr)
166
static int32_t animvpx_read_frame(int32_t inhandle, uint8_t **bufptr, uint32_t *bufsizptr, uint32_t *bufallocsizptr)
167
{
167
{
168
#pragma pack(push,1)
168
#pragma pack(push,1)
169
    struct { uint32_t framesiz; uint64_t timestamp; } hdr;
169
    struct { uint32_t framesiz; uint64_t timestamp; } hdr;
170
#pragma pack(pop)
170
#pragma pack(pop)
171
171
172
    if (kread(inhandle, &hdr, sizeof(hdr)) != sizeof(hdr))
172
    if (kread(inhandle, &hdr, sizeof(hdr)) != sizeof(hdr))
173
        return 1;
173
        return 1;
174
174
175
    if (hdr.framesiz == 0)
175
    if (hdr.framesiz == 0)
176
        return 6;  // must be 6, see animvpx_nextpic_errmsg[]
176
        return 6;  // must be 6, see animvpx_nextpic_errmsg[]
177
177
178
//    OSD_Printf("frame size: %u\n", hdr.framesiz);
178
//    OSD_Printf("frame size: %u\n", hdr.framesiz);
179
179
180
    if (!*bufptr)
180
    if (!*bufptr)
181
    {
181
    {
182
        *bufptr = (uint8_t *)Bmalloc(hdr.framesiz);
182
        *bufptr = (uint8_t *)Bmalloc(hdr.framesiz);
183
        if (!*bufptr)
183
        if (!*bufptr)
184
            return 2;
184
            return 2;
185
        *bufallocsizptr = hdr.framesiz;
185
        *bufallocsizptr = hdr.framesiz;
186
    }
186
    }
187
    else if (*bufallocsizptr < hdr.framesiz)
187
    else if (*bufallocsizptr < hdr.framesiz)
188
    {
188
    {
189
        *bufptr = (uint8_t *)Brealloc(*bufptr, hdr.framesiz);
189
        *bufptr = (uint8_t *)Brealloc(*bufptr, hdr.framesiz);
190
        if (!*bufptr)
190
        if (!*bufptr)
191
            return 2;
191
            return 2;
192
        *bufallocsizptr = hdr.framesiz;
192
        *bufallocsizptr = hdr.framesiz;
193
    }
193
    }
194
194
195
    *bufsizptr = hdr.framesiz;
195
    *bufsizptr = hdr.framesiz;
196
196
197
    if (kread(inhandle, *bufptr, hdr.framesiz) != (signed)hdr.framesiz)
197
    if (kread(inhandle, *bufptr, hdr.framesiz) != (signed)hdr.framesiz)
198
        return 3;
198
        return 3;
199
199
200
    return 0;
200
    return 0;
201
}
201
}
202
202
203
const char *animvpx_nextpic_errmsg[] = {
203
const char *animvpx_nextpic_errmsg[] = {
204
    "All OK",
204
    "All OK",
205
    "INTERNAL ERROR, animvpx_codec_ctx not initalized!",
205
    "INTERNAL ERROR, animvpx_codec_ctx not initalized!",
206
    "OUT OF MEMORY",
206
    "OUT OF MEMORY",
207
    "couldn't read whole frame",
207
    "couldn't read whole frame",
208
    "decoder error, couldn't decode frame",
208
    "decoder error, couldn't decode frame",
209
    "picture dimension mismatch",
209
    "picture dimension mismatch",
210
    "INTERNAL ERROR: read 0 frame length",
210
    "INTERNAL ERROR: read 0 frame length",
211
    "Failed getting corruption status (VP8D_GET_FRAME_CORRUPTED)"
211
    "Failed getting corruption status (VP8D_GET_FRAME_CORRUPTED)"
212
};
212
};
213
213
214
// retrieves one picture-frame from the stream
214
// retrieves one picture-frame from the stream
215
//  pic format:  lines of [Y U V 0] pixels
215
//  pic format:  lines of [Y U V 0] pixels
216
//  *picptr==NULL means EOF has been reached
216
//  *picptr==NULL means EOF has been reached
217
#ifdef DEBUGGINGAIDS
217
#ifdef DEBUGGINGAIDS
218
ATTRIBUTE_OPTIMIZE("O1")
218
ATTRIBUTE_OPTIMIZE("O1")
219
#else
219
#else
220
ATTRIBUTE_OPTIMIZE("O3")
220
ATTRIBUTE_OPTIMIZE("O3")
221
#endif
221
#endif
222
int32_t animvpx_nextpic(animvpx_codec_ctx *codec, uint8_t **picptr)
222
int32_t animvpx_nextpic(animvpx_codec_ctx *codec, uint8_t **picptr)
223
{
223
{
224
    int32_t ret, corrupted;
224
    int32_t ret, corrupted;
225
    vpx_image_t *img;
225
    vpx_image_t *img;
226
226
227
    int32_t t[3];
227
    int32_t t[3];
228
228
229
    if (codec->initstate <= 0)  // not inited or error
229
    if (codec->initstate <= 0)  // not inited or error
230
        return 1;
230
        return 1;
231
231
232
    t[0] = getticks();
232
    t[0] = getticks();
233
233
234
    if (codec->decstate == 0)  // first time / begin
234
    if (codec->decstate == 0)  // first time / begin
235
    {
235
    {
236
read_ivf_frame:
236
read_ivf_frame:
237
        corrupted = 0;
237
        corrupted = 0;
238
238
239
        ret = animvpx_read_frame(codec->inhandle, &codec->compbuf, &codec->compbuflen,
239
        ret = animvpx_read_frame(codec->inhandle, &codec->compbuf, &codec->compbuflen,
240
                                 &codec->compbufallocsiz);
240
                                 &codec->compbufallocsiz);
241
        if (ret == 1)
241
        if (ret == 1)
242
        {
242
        {
243
            // reached EOF
243
            // reached EOF
244
            *picptr = NULL;
244
            *picptr = NULL;
245
            codec->decstate = 2;
245
            codec->decstate = 2;
246
            return 0;
246
            return 0;
247
        }
247
        }
248
        else if (ret == 2 || ret == 3 || ret == 6)
248
        else if (ret == 2 || ret == 3 || ret == 6)
249
        {
249
        {
250
            *picptr = NULL;
250
            *picptr = NULL;
251
            codec->decstate = -1;
251
            codec->decstate = -1;
252
            return ret;
252
            return ret;
253
        }
253
        }
254
        // ^^^ keep in sync with all animvpx_read_frame() errors!
254
        // ^^^ keep in sync with all animvpx_read_frame() errors!
255
255
256
        // codec->compbuf now contains one IVF/VP8 frame
256
        // codec->compbuf now contains one IVF/VP8 frame
257
        codec->decstate = 1;
257
        codec->decstate = 1;
258
258
259
        // decode it!
259
        // decode it!
260
        if (vpx_codec_decode(&codec->codec, codec->compbuf, codec->compbuflen, NULL, 0))
260
        if (vpx_codec_decode(&codec->codec, codec->compbuf, codec->compbuflen, NULL, 0))
261
        {
261
        {
262
            get_codec_error(codec);
262
            get_codec_error(codec);
263
            codec->decstate = -2;
263
            codec->decstate = -2;
264
            return 4;
264
            return 4;
265
        }
265
        }
266
266
267
// Compilation fix for Debian 6.0 (squeeze), which doesn't have
267
// Compilation fix for Debian 6.0 (squeeze), which doesn't have
268
// VP8D_GET_FRAME_CORRUPTED.
268
// VP8D_GET_FRAME_CORRUPTED.
269
// LibVPX doesn't seem to have a version #define, so we use the
269
// LibVPX doesn't seem to have a version #define, so we use the
270
// following one to determine conditional compilation.
270
// following one to determine conditional compilation.
271
#ifdef VPX_CODEC_CAP_ERROR_CONCEALMENT
271
#ifdef VPX_CODEC_CAP_ERROR_CONCEALMENT
272
        if (vpx_codec_control(&codec->codec, VP8D_GET_FRAME_CORRUPTED, &corrupted))
272
        if (vpx_codec_control(&codec->codec, VP8D_GET_FRAME_CORRUPTED, &corrupted))
273
        {
273
        {
274
            get_codec_error(codec);
274
            get_codec_error(codec);
275
            codec->decstate = -2;
275
            codec->decstate = -2;
276
            return 7;
276
            return 7;
277
        }
277
        }
278
#endif
278
#endif
279
        if (corrupted)
279
        if (corrupted)
280
            OSD_Printf("warning: corrupted frame!\n");
280
            OSD_Printf("warning: corrupted frame!\n");
281
    }
281
    }
282
282
283
    img = vpx_codec_get_frame(&codec->codec, &codec->iter);
283
    img = vpx_codec_get_frame(&codec->codec, &codec->iter);
284
    if (img == NULL)
284
    if (img == NULL)
285
    {
285
    {
286
        codec->iter = NULL;  // !
286
        codec->iter = NULL;  // !
287
        goto read_ivf_frame;
287
        goto read_ivf_frame;
288
    }
288
    }
289
289
290
    if (img->d_w != codec->width || img->d_h != codec->height)
290
    if (img->d_w != codec->width || img->d_h != codec->height)
291
    {
291
    {
292
        codec->decstate = -1;
292
        codec->decstate = -1;
293
        return 5;
293
        return 5;
294
    }
294
    }
295
295
296
    t[1] = getticks();
296
    t[1] = getticks();
297
297
298
    /*** 3 planes --> packed conversion ***/
-
 
299
    {
-
 
300
        uint8_t *const dstpic = codec->pic;
298
    uint8_t *const dstpic = codec->pic;
301
299
302
        const uint8_t *const yplane = img->planes[VPX_PLANE_Y];
300
    uint8_t const *const yplane = img->planes[VPX_PLANE_Y];
303
        const uint8_t *const uplane = img->planes[VPX_PLANE_U];
301
    uint8_t const *const uplane = img->planes[VPX_PLANE_U];
304
        const uint8_t *const vplane = img->planes[VPX_PLANE_V];
302
    uint8_t const *const vplane = img->planes[VPX_PLANE_V];
305
303
306
        int32_t ystride = img->stride[VPX_PLANE_Y];
304
    const int32_t ystride = img->stride[VPX_PLANE_Y];
307
        int32_t ustride = img->stride[VPX_PLANE_U];
305
    const int32_t ustride = img->stride[VPX_PLANE_U];
308
        int32_t vstride = img->stride[VPX_PLANE_V];
306
    const int32_t vstride = img->stride[VPX_PLANE_V];
309
307
-
 
308
    if (glinfo.glsl) /*** 3 planes --> packed conversion ***/
-
 
309
    {
310
        int32_t x, y;
310
        int32_t x, y;
311
        const int32_t width=img->d_w, height = img->d_h;
311
        const int32_t width = img->d_w, height = img->d_h;
312
312
313
        for (y=0; y<height; y+=2)
313
        for (y = 0; y < height; y += 2)
314
        {
314
        {
315
            for (x=0; x<width; x+=2)
315
            for (x = 0; x < width; x += 2)
316
            {
316
            {
317
                uint8_t u = uplane[ustride*(y>>1) + (x>>1)];
317
                uint8_t u = uplane[ustride * (y >> 1) + (x >> 1)];
318
                uint8_t v = vplane[vstride*(y>>1) + (x>>1)];
318
                uint8_t v = vplane[vstride * (y >> 1) + (x >> 1)];
319
319
320
                dstpic[(width*y + x)<<2] = yplane[ystride*y + x];
320
                dstpic[(width * y + x) << 2] = yplane[ystride * y + x];
321
                dstpic[(width*y + x+1)<<2] = yplane[ystride*y + x+1];
321
                dstpic[(width * y + x + 1) << 2] = yplane[ystride * y + x + 1];
322
                dstpic[(width*(y+1) + x)<<2] = yplane[ystride*(y+1) + x];
322
                dstpic[(width * (y + 1) + x) << 2] = yplane[ystride * (y + 1) + x];
323
                dstpic[(width*(y+1) + x+1)<<2] = yplane[ystride*(y+1) + x+1];
323
                dstpic[(width * (y + 1) + x + 1) << 2] = yplane[ystride * (y + 1) + x + 1];
324
324
325
                dstpic[((width*y + x)<<2) + 1] = u;
325
                dstpic[((width * y + x) << 2) + 1] = u;
326
                dstpic[((width*y + x+1)<<2) + 1] = u;
326
                dstpic[((width * y + x + 1) << 2) + 1] = u;
327
                dstpic[((width*(y+1) + x)<<2) + 1] = u;
327
                dstpic[((width * (y + 1) + x) << 2) + 1] = u;
328
                dstpic[((width*(y+1) + x+1)<<2) + 1] = u;
328
                dstpic[((width * (y + 1) + x + 1) << 2) + 1] = u;
329
329
330
                dstpic[((width*y + x)<<2) + 2] = v;
330
                dstpic[((width * y + x) << 2) + 2] = v;
331
                dstpic[((width*y + x+1)<<2) + 2] = v;
331
                dstpic[((width * y + x + 1) << 2) + 2] = v;
332
                dstpic[((width*(y+1) + x)<<2) + 2] = v;
332
                dstpic[((width * (y + 1) + x) << 2) + 2] = v;
333
                dstpic[((width*(y+1) + x+1)<<2) + 2] = v;
333
                dstpic[((width * (y + 1) + x + 1) << 2) + 2] = v;
334
            }
334
            }
335
        }
335
        }
336
    }
336
    }
-
 
337
    else /*** 3 planes --> packed conversion (RGB) ***/
-
 
338
    {
-
 
339
        int i = 0;
-
 
340
-
 
341
        for (unsigned int imgY = 0; imgY < img->d_h; imgY++)
-
 
342
        {
-
 
343
            for (unsigned int imgX = 0; imgX < img->d_w; imgX++)
-
 
344
            {
-
 
345
                uint8_t const y = yplane[imgY * ystride + imgX];
-
 
346
                uint8_t const u = uplane[(imgY >> 1) * ustride + (imgX >> 1)];
-
 
347
                uint8_t const v = vplane[(imgY >> 1) * vstride + (imgX >> 1)];
-
 
348
-
 
349
                int const c = y - 16;
-
 
350
                int const d = (u + -128);
-
 
351
                int const e = (v + -128);
-
 
352
                int const c298 = c * 298;
-
 
353
-
 
354
                dstpic[i + 0] = (uint8_t)clamp((c298 + 409 * e - -128) >> 8, 0, 255);
-
 
355
                dstpic[i + 1] = (uint8_t)clamp((c298 - 100 * d - 208 * e - -128) >> 8, 0, 255);
-
 
356
                dstpic[i + 2] = (uint8_t)clamp((c298 + 516 * d - -128) >> 8, 0, 255);
-
 
357
-
 
358
                i += 3;
-
 
359
            }
-
 
360
        }
-
 
361
    }
337
362
338
    t[2] = getticks();
363
    t[2] = getticks();
339
364
340
    codec->sumtimes[0] += t[1]-t[0];
365
    codec->sumtimes[0] += t[1]-t[0];
341
    codec->sumtimes[1] += t[2]-t[1];
366
    codec->sumtimes[1] += t[2]-t[1];
342
367
343
    codec->maxtimes[0] = max(codec->maxtimes[0], t[1]-t[0]);
368
    codec->maxtimes[0] = max(codec->maxtimes[0], t[1]-t[0]);
344
    codec->maxtimes[1] = max(codec->maxtimes[0], t[2]-t[1]);
369
    codec->maxtimes[1] = max(codec->maxtimes[0], t[2]-t[1]);
345
370
346
    *picptr = codec->pic;
371
    *picptr = codec->pic;
347
    return 0;
372
    return 0;
348
}
373
}
349
374
350
375
351
/////////////// DRAWING! ///////////////
376
/////////////// DRAWING! ///////////////
352
static GLuint texname = 0;
377
static GLuint texname = 0;
353
static int32_t texuploaded;
378
static int32_t texuploaded;
354
379
355
// YUV->RGB conversion fragment shader adapted from
380
// YUV->RGB conversion fragment shader adapted from
356
// http://www.fourcc.org/fccyvrgb.php: "Want some sample code?"
381
// http://www.fourcc.org/fccyvrgb.php: "Want some sample code?"
357
// direct link: http://www.fourcc.org/source/YUV420P-OpenGL-GLSLang.c
382
// direct link: http://www.fourcc.org/source/YUV420P-OpenGL-GLSLang.c
358
static char *fragprog_src =
383
static char *fragprog_src =
359
    "#version 120\n"
384
    "#version 120\n"
360
385
361
    "uniform sampler2D tex;\n"
386
    "uniform sampler2D tex;\n"
362
387
363
    "void main(void) {\n"
388
    "void main(void) {\n"
364
389
365
    "  float r,g,b,y,u,v;\n"
390
    "  float r,g,b,y,u,v;\n"
366
    "  vec3 yuv;\n"
391
    "  vec3 yuv;\n"
367
392
368
    "  yuv = texture2D(tex, gl_TexCoord[0].st).rgb;\n"
393
    "  yuv = texture2D(tex, gl_TexCoord[0].st).rgb;\n"
369
    "  y = yuv.r;\n"
394
    "  y = yuv.r;\n"
370
    "  u = yuv.g;\n"
395
    "  u = yuv.g;\n"
371
    "  v = yuv.b;\n"
396
    "  v = yuv.b;\n"
372
397
373
    "  y = 1.1643*(y-0.0625);\n"
398
    "  y = 1.1643*(y-0.0625);\n"
374
    "  u = u-0.5;\n"
399
    "  u = u-0.5;\n"
375
    "  v = v-0.5;\n"
400
    "  v = v-0.5;\n"
376
401
377
    "  r = y + 1.5958*v;\n"
402
    "  r = y + 1.5958*v;\n"
378
    "  g = y - 0.39173*u - 0.81290*v;\n"
403
    "  g = y - 0.39173*u - 0.81290*v;\n"
379
    "  b = y + 2.017*u;\n"
404
    "  b = y + 2.017*u;\n"
380
405
381
    "  gl_FragColor = vec4(r,g,b,1.0);\n"
406
    "  gl_FragColor = vec4(r,g,b,1.0);\n"
382
    "}\n";
407
    "}\n";
383
408
384
void animvpx_setup_glstate(void)
409
void animvpx_setup_glstate(void)
385
{
410
{
-
 
411
    if (glinfo.glsl)
-
 
412
    {
386
    GLint gli;
413
        GLint gli;
387
    GLhandleARB FSHandle, PHandle;
414
        GLhandleARB FSHandle, PHandle;
388
    static char logbuf[512];
415
        static char logbuf[512];
389
416
390
    // first, compile the fragment shader
417
        // first, compile the fragment shader
391
    /* Set up program objects. */
418
        /* Set up program objects. */
392
    PHandle = bglCreateProgramObjectARB();
419
        PHandle = bglCreateProgramObjectARB();
393
    FSHandle = bglCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
420
        FSHandle = bglCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
394
421
395
    /* Compile the shader. */
422
        /* Compile the shader. */
396
    bglShaderSourceARB(FSHandle, 1, (const GLcharARB **)&fragprog_src, NULL);
423
        bglShaderSourceARB(FSHandle, 1, (const GLcharARB **)&fragprog_src, NULL);
397
    bglCompileShaderARB(FSHandle);
424
        bglCompileShaderARB(FSHandle);
398
425
399
    /* Print the compilation log. */
426
        /* Print the compilation log. */
400
    bglGetObjectParameterivARB(FSHandle, GL_OBJECT_COMPILE_STATUS_ARB, &gli);
427
        bglGetObjectParameterivARB(FSHandle, GL_OBJECT_COMPILE_STATUS_ARB, &gli);
401
    bglGetInfoLogARB(FSHandle, sizeof(logbuf), NULL, logbuf);
428
        bglGetInfoLogARB(FSHandle, sizeof(logbuf), NULL, logbuf);
402
    if (logbuf[0])
429
        if (logbuf[0])
403
        OSD_Printf("animvpx compile log: %s\n", logbuf);
430
            OSD_Printf("animvpx compile log: %s\n", logbuf);
404
431
405
    /* Create a complete program object. */
432
        /* Create a complete program object. */
406
    bglAttachObjectARB(PHandle, FSHandle);
433
        bglAttachObjectARB(PHandle, FSHandle);
407
    bglLinkProgramARB(PHandle);
434
        bglLinkProgramARB(PHandle);
408
435
409
    /* And print the link log. */
436
        /* And print the link log. */
410
    bglGetInfoLogARB(PHandle, sizeof(logbuf), NULL, logbuf);
437
        bglGetInfoLogARB(PHandle, sizeof(logbuf), NULL, logbuf);
411
    if (logbuf[0])
438
        if (logbuf[0])
412
        OSD_Printf("animvpx link log: %s\n", logbuf);
439
            OSD_Printf("animvpx link log: %s\n", logbuf);
413
440
414
    /* Finally, use the program. */
441
        /* Finally, use the program. */
415
    bglUseProgramObjectARB(PHandle);
442
        bglUseProgramObjectARB(PHandle);
-
 
443
    }
416
444
417
    ////////// GL STATE //////////
445
    ////////// GL STATE //////////
418
446
419
    //Force fullscreen (glox1=-1 forces it to restore afterwards)
447
    //Force fullscreen (glox1=-1 forces it to restore afterwards)
420
    bglViewport(0,0,xdim,ydim); glox1 = -1;
448
    bglViewport(0,0,xdim,ydim); glox1 = -1;
421
449
422
    bglMatrixMode(GL_MODELVIEW);
450
    bglMatrixMode(GL_MODELVIEW);
423
    bglLoadIdentity();
451
    bglLoadIdentity();
424
452
425
    bglMatrixMode(GL_PROJECTION);
453
    bglMatrixMode(GL_PROJECTION);
426
    bglLoadIdentity();
454
    bglLoadIdentity();
427
455
428
    bglMatrixMode(GL_COLOR);
-
 
429
    bglLoadIdentity();
-
 
430
-
 
431
    bglMatrixMode(GL_TEXTURE);
456
    bglMatrixMode(GL_TEXTURE);
432
    bglLoadIdentity();
457
    bglLoadIdentity();
433
458
434
    bglPushAttrib(GL_ENABLE_BIT);
459
//    bglPushAttrib(GL_ENABLE_BIT);
435
    bglDisable(GL_ALPHA_TEST);
460
    bglDisable(GL_ALPHA_TEST);
436
//    bglDisable(GL_LIGHTING);
-
 
437
    bglDisable(GL_DEPTH_TEST);
461
    bglDisable(GL_DEPTH_TEST);
438
    bglDisable(GL_BLEND);
462
    bglDisable(GL_BLEND);
439
    bglDisable(GL_CULL_FACE);
463
    bglDisable(GL_CULL_FACE);
440
//    bglDisable(GL_SCISSOR_TEST);
-
 
441
    bglEnable(GL_TEXTURE_2D);
464
    bglEnable(GL_TEXTURE_2D);
442
465
443
-
 
444
    bglActiveTextureARB(GL_TEXTURE0_ARB);
466
    bglActiveTextureARB(GL_TEXTURE0_ARB);
445
    bglGenTextures(1, &texname);
467
    bglGenTextures(1, &texname);
446
//    gli = bglGetUniformLocationARB(PHandle,"tex");
-
 
447
//    bglUniform1iARB(gli,0);  // 0: texture unit
-
 
448
    bglBindTexture(GL_TEXTURE_2D, texname);
468
    bglBindTexture(GL_TEXTURE_2D, texname);
449
469
450
    bglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glinfo.clamptoedge?GL_CLAMP_TO_EDGE:GL_CLAMP);
470
    bglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glinfo.clamptoedge?GL_CLAMP_TO_EDGE:GL_CLAMP);
451
    bglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glinfo.clamptoedge?GL_CLAMP_TO_EDGE:GL_CLAMP);
471
    bglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glinfo.clamptoedge?GL_CLAMP_TO_EDGE:GL_CLAMP);
452
    bglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
472
    bglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
453
    bglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
473
    bglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
454
474
455
    texuploaded = 0;
475
    texuploaded = 0;
456
    ////////////////////
476
    ////////////////////
457
477
458
    bglClearColor(0.0,0.0,0.0,1.0);
478
    bglClearColor(0.0,0.0,0.0,1.0);
459
    bglClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
479
    bglClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
460
}
480
}
461
481
462
void animvpx_restore_glstate(void)
482
void animvpx_restore_glstate(void)
463
{
483
{
-
 
484
    if (glinfo.glsl)
464
    bglUseProgramObjectARB(0);
485
        bglUseProgramObjectARB(0);
465
486
466
    bglPopAttrib();
487
//    bglPopAttrib();
467
488
468
    bglDeleteTextures(1, &texname);
489
    bglDeleteTextures(1, &texname);
469
    texname = 0;
490
    texname = 0;
470
    texuploaded = 0;
491
    texuploaded = 0;
471
}
492
}
472
493
473
int32_t animvpx_render_frame(animvpx_codec_ctx *codec)
494
int32_t animvpx_render_frame(animvpx_codec_ctx *codec)
474
{
495
{
475
    int32_t t = getticks();
496
    int32_t t = getticks();
476
497
477
    if (codec->initstate <= 0)  // not inited or error
498
    if (codec->initstate <= 0)  // not inited or error
478
        return 1;
499
        return 1;
479
500
480
    if (codec->pic == NULL)
501
    if (codec->pic == NULL)
481
        return 2;  // shouldn't happen
502
        return 2;  // shouldn't happen
482
503
-
 
504
    int fmt = glinfo.glsl ? GL_RGBA : GL_RGB;
-
 
505
483
    if (!texuploaded)
506
    if (!texuploaded)
484
    {
507
    {
485
        bglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, codec->width,codec->height,
508
        bglTexImage2D(GL_TEXTURE_2D, 0, fmt, codec->width,codec->height,
486
                     0, GL_RGBA, GL_UNSIGNED_BYTE, codec->pic);
509
                     0, fmt, GL_UNSIGNED_BYTE, codec->pic);
487
        texuploaded = 1;
510
        texuploaded = 1;
488
    }
511
    }
489
    else
512
    else
490
    {
513
    {
491
        bglTexSubImage2D(GL_TEXTURE_2D, 0, 0,0, codec->width,codec->height,
514
        bglTexSubImage2D(GL_TEXTURE_2D, 0, 0,0, codec->width,codec->height,
492
                        GL_RGBA, GL_UNSIGNED_BYTE, codec->pic);
515
                        fmt, GL_UNSIGNED_BYTE, codec->pic);
493
    }
516
    }
494
517
495
    {
-
 
496
        float vid_wbyh = ((float)codec->width)/codec->height;
518
    float vid_wbyh = ((float)codec->width)/codec->height;
497
        float scr_wbyh = ((float)xdim)/ydim;
519
    float scr_wbyh = ((float)xdim)/ydim;
498
520
499
        float x=1.0, y=1.0;
521
    float x=1.0, y=1.0;
500
#if 1
522
#if 1
501
        // aspect correction by pillarboxing/letterboxing
523
    // aspect correction by pillarboxing/letterboxing
502
        // TODO: fullscreen? can't assume square pixels there
524
    // TODO: fullscreen? can't assume square pixels there
503
        if (vid_wbyh != scr_wbyh)
525
    if (vid_wbyh != scr_wbyh)
504
        {
526
    {
505
            if (vid_wbyh < scr_wbyh)
527
        if (vid_wbyh < scr_wbyh)
506
                x = vid_wbyh/scr_wbyh;
528
            x = vid_wbyh/scr_wbyh;
507
            else
529
        else
508
                y = scr_wbyh/vid_wbyh;
530
            y = scr_wbyh/vid_wbyh;
509
        }
531
    }
510
#endif
532
#endif
511
        bglBegin(GL_QUADS);
533
    bglBegin(GL_QUADS);
512
534
-
 
535
    if (!glinfo.glsl)
-
 
536
        bglColor3f(1.0, 1.0, 1.0);
-
 
537
513
        bglTexCoord2f(0.0,1.0);
538
    bglTexCoord2f(0.0,1.0);
514
        bglVertex3f(-x, -y, 0.0);
539
    bglVertex3f(-x, -y, 0.0);
515
540
516
        bglTexCoord2f(0.0,0.0);
541
    bglTexCoord2f(0.0,0.0);
517
        bglVertex3f(-x, y, 0.0);
542
    bglVertex3f(-x, y, 0.0);
518
543
519
        bglTexCoord2f(1.0,0.0);
544
    bglTexCoord2f(1.0,0.0);
520
        bglVertex3f(x, y, 0.0);
545
    bglVertex3f(x, y, 0.0);
521
546
522
        bglTexCoord2f(1.0,1.0);
547
    bglTexCoord2f(1.0,1.0);
523
        bglVertex3f(x, -y, 0.0);
548
    bglVertex3f(x, -y, 0.0);
524
549
525
        bglEnd();
550
    bglEnd();
526
    }
-
 
527
551
528
    t = getticks()-t;
552
    t = getticks()-t;
529
    codec->sumtimes[2] += t;
553
    codec->sumtimes[2] += t;
530
    codec->maxtimes[2] = max(codec->maxtimes[2], t);
554
    codec->maxtimes[2] = max(codec->maxtimes[2], t);
531
    codec->numframes++;
555
    codec->numframes++;
532
556
533
    return 0;
557
    return 0;
534
}
558
}
535
559
536
void animvpx_print_stats(const animvpx_codec_ctx *codec)
560
void animvpx_print_stats(const animvpx_codec_ctx *codec)
537
{
561
{
538
    if (codec->numframes != 0)
562
    if (codec->numframes != 0)
539
    {
563
    {
540
        const int32_t *s = codec->sumtimes;
564
        const int32_t *s = codec->sumtimes;
541
        const int32_t *m = codec->maxtimes;
565
        const int32_t *m = codec->maxtimes;
542
        int32_t n = codec->numframes;
566
        int32_t n = codec->numframes;
543
567
-
 
568
        if (glinfo.glsl)
-
 
569
            initprintf("animvpx: GLSL mode\n");
-
 
570
544
        initprintf("VP8 timing stats (mean, max) [ms] for %d frames:\n"
571
        initprintf("VP8 timing stats (mean, max) [ms] for %d frames:\n"
545
                   " read and decode frame: %.02f, %d\n"
572
                   " read and decode frame: %.02f, %d\n"
546
                   " 3 planes -> packed conversion: %.02f, %d\n"
573
                   " 3 planes -> packed conversion: %.02f, %d\n"
547
                   " upload and display: %.02f, %d\n",
574
                   " upload and display: %.02f, %d\n",
548
                   n, (double)s[0]/n, m[0], (double)s[1]/n, m[1], (double)s[2]/n, m[2]);
575
                   n, (double)s[0]/n, m[0], (double)s[1]/n, m[1], (double)s[2]/n, m[2]);
549
    }
576
    }
550
}
577
}
551
578
552
#endif
579
#endif
553
 
580