Subversion Repositories eduke32

Rev

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

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