Subversion Repositories eduke32

Rev

Rev 4998 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 4998 Rev 5074
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
    uint8_t *const dstpic = codec->pic;
298
    uint8_t *const dstpic = codec->pic;
299
299
300
    uint8_t const *const yplane = img->planes[VPX_PLANE_Y];
300
    uint8_t const *const yplane = img->planes[VPX_PLANE_Y];
301
    uint8_t const *const uplane = img->planes[VPX_PLANE_U];
301
    uint8_t const *const uplane = img->planes[VPX_PLANE_U];
302
    uint8_t const *const vplane = img->planes[VPX_PLANE_V];
302
    uint8_t const *const vplane = img->planes[VPX_PLANE_V];
303
303
304
    const int32_t ystride = img->stride[VPX_PLANE_Y];
304
    const int32_t ystride = img->stride[VPX_PLANE_Y];
305
    const int32_t ustride = img->stride[VPX_PLANE_U];
305
    const int32_t ustride = img->stride[VPX_PLANE_U];
306
    const int32_t vstride = img->stride[VPX_PLANE_V];
306
    const int32_t vstride = img->stride[VPX_PLANE_V];
307
307
308
    if (glinfo.glsl) /*** 3 planes --> packed conversion ***/
308
    if (glinfo.glsl) /*** 3 planes --> packed conversion ***/
309
    {
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) ***/
337
    else /*** 3 planes --> packed conversion (RGB) ***/
338
    {
338
    {
339
        int i = 0;
339
        int i = 0;
340
340
341
        for (unsigned int imgY = 0; imgY < img->d_h; imgY++)
341
        for (unsigned int imgY = 0; imgY < img->d_h; imgY++)
342
        {
342
        {
343
            for (unsigned int imgX = 0; imgX < img->d_w; imgX++)
343
            for (unsigned int imgX = 0; imgX < img->d_w; imgX++)
344
            {
344
            {
345
                uint8_t const y = yplane[imgY * ystride + imgX];
345
                uint8_t const y = yplane[imgY * ystride + imgX];
346
                uint8_t const u = uplane[(imgY >> 1) * ustride + (imgX >> 1)];
346
                uint8_t const u = uplane[(imgY >> 1) * ustride + (imgX >> 1)];
347
                uint8_t const v = vplane[(imgY >> 1) * vstride + (imgX >> 1)];
347
                uint8_t const v = vplane[(imgY >> 1) * vstride + (imgX >> 1)];
348
348
349
                int const c = y - 16;
349
                int const c = y - 16;
350
                int const d = (u + -128);
350
                int const d = (u + -128);
351
                int const e = (v + -128);
351
                int const e = (v + -128);
352
                int const c298 = c * 298;
352
                int const c298 = c * 298;
353
353
354
                dstpic[i + 0] = (uint8_t)clamp((c298 + 409 * e - -128) >> 8, 0, 255);
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);
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);
356
                dstpic[i + 2] = (uint8_t)clamp((c298 + 516 * d - -128) >> 8, 0, 255);
357
357
358
                i += 3;
358
                i += 3;
359
            }
359
            }
360
        }
360
        }
361
    }
361
    }
362
362
363
    t[2] = getticks();
363
    t[2] = getticks();
364
364
365
    codec->sumtimes[0] += t[1]-t[0];
365
    codec->sumtimes[0] += t[1]-t[0];
366
    codec->sumtimes[1] += t[2]-t[1];
366
    codec->sumtimes[1] += t[2]-t[1];
367
367
368
    codec->maxtimes[0] = max(codec->maxtimes[0], t[1]-t[0]);
368
    codec->maxtimes[0] = max(codec->maxtimes[0], t[1]-t[0]);
369
    codec->maxtimes[1] = max(codec->maxtimes[0], t[2]-t[1]);
369
    codec->maxtimes[1] = max(codec->maxtimes[0], t[2]-t[1]);
370
370
371
    *picptr = codec->pic;
371
    *picptr = codec->pic;
372
    return 0;
372
    return 0;
373
}
373
}
374
374
375
375
376
/////////////// DRAWING! ///////////////
376
/////////////// DRAWING! ///////////////
377
static GLuint texname = 0;
377
static GLuint texname = 0;
378
static int32_t texuploaded;
378
static int32_t texuploaded;
379
379
380
// YUV->RGB conversion fragment shader adapted from
380
// YUV->RGB conversion fragment shader adapted from
381
// http://www.fourcc.org/fccyvrgb.php: "Want some sample code?"
381
// http://www.fourcc.org/fccyvrgb.php: "Want some sample code?"
382
// direct link: http://www.fourcc.org/source/YUV420P-OpenGL-GLSLang.c
382
// direct link: http://www.fourcc.org/source/YUV420P-OpenGL-GLSLang.c
383
static char *fragprog_src =
383
static char *fragprog_src =
384
    "#version 120\n"
384
    "#version 120\n"
385
385
386
    "uniform sampler2D tex;\n"
386
    "uniform sampler2D tex;\n"
387
387
388
    "void main(void) {\n"
388
    "void main(void) {\n"
389
389
390
    "  float r,g,b,y,u,v;\n"
390
    "  float r,g,b,y,u,v;\n"
391
    "  vec3 yuv;\n"
391
    "  vec3 yuv;\n"
392
392
393
    "  yuv = texture2D(tex, gl_TexCoord[0].st).rgb;\n"
393
    "  yuv = texture2D(tex, gl_TexCoord[0].st).rgb;\n"
394
    "  y = yuv.r;\n"
394
    "  y = yuv.r;\n"
395
    "  u = yuv.g;\n"
395
    "  u = yuv.g;\n"
396
    "  v = yuv.b;\n"
396
    "  v = yuv.b;\n"
397
397
398
    "  y = 1.1643*(y-0.0625);\n"
398
    "  y = 1.1643*(y-0.0625);\n"
399
    "  u = u-0.5;\n"
399
    "  u = u-0.5;\n"
400
    "  v = v-0.5;\n"
400
    "  v = v-0.5;\n"
401
401
402
    "  r = y + 1.5958*v;\n"
402
    "  r = y + 1.5958*v;\n"
403
    "  g = y - 0.39173*u - 0.81290*v;\n"
403
    "  g = y - 0.39173*u - 0.81290*v;\n"
404
    "  b = y + 2.017*u;\n"
404
    "  b = y + 2.017*u;\n"
405
405
406
    "  gl_FragColor = vec4(r,g,b,1.0);\n"
406
    "  gl_FragColor = vec4(r,g,b,1.0);\n"
407
    "}\n";
407
    "}\n";
408
408
409
void animvpx_setup_glstate(void)
409
void animvpx_setup_glstate(void)
410
{
410
{
411
    if (glinfo.glsl)
411
    if (glinfo.glsl)
412
    {
412
    {
413
        GLint gli;
413
        GLint gli;
414
        GLhandleARB FSHandle, PHandle;
414
        GLhandleARB FSHandle, PHandle;
415
        static char logbuf[512];
415
        static char logbuf[512];
416
416
417
        // first, compile the fragment shader
417
        // first, compile the fragment shader
418
        /* Set up program objects. */
418
        /* Set up program objects. */
419
        PHandle = bglCreateProgramObjectARB();
419
        PHandle = bglCreateProgramObjectARB();
420
        FSHandle = bglCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
420
        FSHandle = bglCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
421
421
422
        /* Compile the shader. */
422
        /* Compile the shader. */
423
        bglShaderSourceARB(FSHandle, 1, (const GLcharARB **)&fragprog_src, NULL);
423
        bglShaderSourceARB(FSHandle, 1, (const GLcharARB **)&fragprog_src, NULL);
424
        bglCompileShaderARB(FSHandle);
424
        bglCompileShaderARB(FSHandle);
425
425
426
        /* Print the compilation log. */
426
        /* Print the compilation log. */
427
        bglGetObjectParameterivARB(FSHandle, GL_OBJECT_COMPILE_STATUS_ARB, &gli);
427
        bglGetObjectParameterivARB(FSHandle, GL_OBJECT_COMPILE_STATUS_ARB, &gli);
428
        bglGetInfoLogARB(FSHandle, sizeof(logbuf), NULL, logbuf);
428
        bglGetInfoLogARB(FSHandle, sizeof(logbuf), NULL, logbuf);
429
        if (logbuf[0])
429
        if (logbuf[0])
430
            OSD_Printf("animvpx compile log: %s\n", logbuf);
430
            OSD_Printf("animvpx compile log: %s\n", logbuf);
431
431
432
        /* Create a complete program object. */
432
        /* Create a complete program object. */
433
        bglAttachObjectARB(PHandle, FSHandle);
433
        bglAttachObjectARB(PHandle, FSHandle);
434
        bglLinkProgramARB(PHandle);
434
        bglLinkProgramARB(PHandle);
435
435
436
        /* And print the link log. */
436
        /* And print the link log. */
437
        bglGetInfoLogARB(PHandle, sizeof(logbuf), NULL, logbuf);
437
        bglGetInfoLogARB(PHandle, sizeof(logbuf), NULL, logbuf);
438
        if (logbuf[0])
438
        if (logbuf[0])
439
            OSD_Printf("animvpx link log: %s\n", logbuf);
439
            OSD_Printf("animvpx link log: %s\n", logbuf);
440
440
441
        /* Finally, use the program. */
441
        /* Finally, use the program. */
442
        bglUseProgramObjectARB(PHandle);
442
        bglUseProgramObjectARB(PHandle);
443
    }
443
    }
444
444
445
    ////////// GL STATE //////////
445
    ////////// GL STATE //////////
446
446
447
    //Force fullscreen (glox1=-1 forces it to restore afterwards)
447
    //Force fullscreen (glox1=-1 forces it to restore afterwards)
448
    bglViewport(0,0,xdim,ydim); glox1 = -1;
448
    bglViewport(0,0,xdim,ydim); glox1 = -1;
449
449
450
    bglMatrixMode(GL_MODELVIEW);
450
    bglMatrixMode(GL_MODELVIEW);
451
    bglLoadIdentity();
451
    bglLoadIdentity();
452
452
453
    bglMatrixMode(GL_PROJECTION);
453
    bglMatrixMode(GL_PROJECTION);
454
    bglLoadIdentity();
454
    bglLoadIdentity();
455
455
456
    bglMatrixMode(GL_TEXTURE);
456
    bglMatrixMode(GL_TEXTURE);
457
    bglLoadIdentity();
457
    bglLoadIdentity();
458
458
459
//    bglPushAttrib(GL_ENABLE_BIT);
459
//    bglPushAttrib(GL_ENABLE_BIT);
460
    bglDisable(GL_ALPHA_TEST);
460
    bglDisable(GL_ALPHA_TEST);
461
    bglDisable(GL_DEPTH_TEST);
461
    bglDisable(GL_DEPTH_TEST);
462
    bglDisable(GL_BLEND);
462
    bglDisable(GL_BLEND);
463
    bglDisable(GL_CULL_FACE);
463
    bglDisable(GL_CULL_FACE);
464
    bglEnable(GL_TEXTURE_2D);
464
    bglEnable(GL_TEXTURE_2D);
465
465
466
    bglActiveTextureARB(GL_TEXTURE0_ARB);
466
    bglActiveTextureARB(GL_TEXTURE0_ARB);
467
    bglGenTextures(1, &texname);
467
    bglGenTextures(1, &texname);
468
    bglBindTexture(GL_TEXTURE_2D, texname);
468
    bglBindTexture(GL_TEXTURE_2D, texname);
469
469
470
    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);
471
    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);
472
    bglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
472
    bglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
473
    bglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
473
    bglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
474
474
475
    texuploaded = 0;
475
    texuploaded = 0;
476
    ////////////////////
476
    ////////////////////
477
477
478
    bglClearColor(0.0,0.0,0.0,1.0);
478
    bglClearColor(0.0,0.0,0.0,1.0);
479
    bglClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
479
    bglClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
480
}
480
}
481
481
482
void animvpx_restore_glstate(void)
482
void animvpx_restore_glstate(void)
483
{
483
{
484
    if (glinfo.glsl)
484
    if (glinfo.glsl)
485
        bglUseProgramObjectARB(0);
485
        bglUseProgramObjectARB(0);
486
486
487
//    bglPopAttrib();
487
//    bglPopAttrib();
488
488
489
    bglDeleteTextures(1, &texname);
489
    bglDeleteTextures(1, &texname);
490
    texname = 0;
490
    texname = 0;
491
    texuploaded = 0;
491
    texuploaded = 0;
492
}
492
}
493
493
494
int32_t animvpx_render_frame(animvpx_codec_ctx *codec)
494
int32_t animvpx_render_frame(animvpx_codec_ctx *codec)
495
{
495
{
496
    int32_t t = getticks();
496
    int32_t t = getticks();
497
497
498
    if (codec->initstate <= 0)  // not inited or error
498
    if (codec->initstate <= 0)  // not inited or error
499
        return 1;
499
        return 1;
500
500
501
    if (codec->pic == NULL)
501
    if (codec->pic == NULL)
502
        return 2;  // shouldn't happen
502
        return 2;  // shouldn't happen
503
503
504
    int fmt = glinfo.glsl ? GL_RGBA : GL_RGB;
504
    int fmt = glinfo.glsl ? GL_RGBA : GL_RGB;
505
505
506
    if (!texuploaded)
506
    if (!texuploaded)
507
    {
507
    {
508
        bglTexImage2D(GL_TEXTURE_2D, 0, fmt, codec->width,codec->height,
508
        bglTexImage2D(GL_TEXTURE_2D, 0, fmt, codec->width,codec->height,
509
                     0, fmt, GL_UNSIGNED_BYTE, codec->pic);
509
                     0, fmt, GL_UNSIGNED_BYTE, codec->pic);
-
 
510
        if (bglGetError() != GL_NO_ERROR) return 1;
510
        texuploaded = 1;
511
        texuploaded = 1;
511
    }
512
    }
512
    else
513
    else
513
    {
514
    {
514
        bglTexSubImage2D(GL_TEXTURE_2D, 0, 0,0, codec->width,codec->height,
515
        bglTexSubImage2D(GL_TEXTURE_2D, 0, 0,0, codec->width,codec->height,
515
                        fmt, GL_UNSIGNED_BYTE, codec->pic);
516
                        fmt, GL_UNSIGNED_BYTE, codec->pic);
-
 
517
        if (bglGetError() != GL_NO_ERROR) return 1;
516
    }
518
    }
517
519
518
    float vid_wbyh = ((float)codec->width)/codec->height;
520
    float vid_wbyh = ((float)codec->width)/codec->height;
519
    float scr_wbyh = ((float)xdim)/ydim;
521
    float scr_wbyh = ((float)xdim)/ydim;
520
522
521
    float x=1.0, y=1.0;
523
    float x=1.0, y=1.0;
522
#if 1
524
#if 1
523
    // aspect correction by pillarboxing/letterboxing
525
    // aspect correction by pillarboxing/letterboxing
524
    // TODO: fullscreen? can't assume square pixels there
526
    // TODO: fullscreen? can't assume square pixels there
525
    if (vid_wbyh != scr_wbyh)
527
    if (vid_wbyh != scr_wbyh)
526
    {
528
    {
527
        if (vid_wbyh < scr_wbyh)
529
        if (vid_wbyh < scr_wbyh)
528
            x = vid_wbyh/scr_wbyh;
530
            x = vid_wbyh/scr_wbyh;
529
        else
531
        else
530
            y = scr_wbyh/vid_wbyh;
532
            y = scr_wbyh/vid_wbyh;
531
    }
533
    }
532
#endif
534
#endif
533
    bglBegin(GL_QUADS);
535
    bglBegin(GL_QUADS);
534
536
535
    if (!glinfo.glsl)
537
    if (!glinfo.glsl)
536
        bglColor3f(1.0, 1.0, 1.0);
538
        bglColor3f(1.0, 1.0, 1.0);
537
539
538
    bglTexCoord2f(0.0,1.0);
540
    bglTexCoord2f(0.0,1.0);
539
    bglVertex3f(-x, -y, 0.0);
541
    bglVertex3f(-x, -y, 0.0);
540
542
541
    bglTexCoord2f(0.0,0.0);
543
    bglTexCoord2f(0.0,0.0);
542
    bglVertex3f(-x, y, 0.0);
544
    bglVertex3f(-x, y, 0.0);
543
545
544
    bglTexCoord2f(1.0,0.0);
546
    bglTexCoord2f(1.0,0.0);
545
    bglVertex3f(x, y, 0.0);
547
    bglVertex3f(x, y, 0.0);
546
548
547
    bglTexCoord2f(1.0,1.0);
549
    bglTexCoord2f(1.0,1.0);
548
    bglVertex3f(x, -y, 0.0);
550
    bglVertex3f(x, -y, 0.0);
549
551
550
    bglEnd();
552
    bglEnd();
551
553
552
    t = getticks()-t;
554
    t = getticks()-t;
553
    codec->sumtimes[2] += t;
555
    codec->sumtimes[2] += t;
554
    codec->maxtimes[2] = max(codec->maxtimes[2], t);
556
    codec->maxtimes[2] = max(codec->maxtimes[2], t);
555
    codec->numframes++;
557
    codec->numframes++;
556
558
557
    return 0;
559
    return 0;
558
}
560
}
559
561
560
void animvpx_print_stats(const animvpx_codec_ctx *codec)
562
void animvpx_print_stats(const animvpx_codec_ctx *codec)
561
{
563
{
562
    if (codec->numframes != 0)
564
    if (codec->numframes != 0)
563
    {
565
    {
564
        const int32_t *s = codec->sumtimes;
566
        const int32_t *s = codec->sumtimes;
565
        const int32_t *m = codec->maxtimes;
567
        const int32_t *m = codec->maxtimes;
566
        int32_t n = codec->numframes;
568
        int32_t n = codec->numframes;
567
569
568
        if (glinfo.glsl)
570
        if (glinfo.glsl)
569
            initprintf("animvpx: GLSL mode\n");
571
            initprintf("animvpx: GLSL mode\n");
570
572
571
        initprintf("VP8 timing stats (mean, max) [ms] for %d frames:\n"
573
        initprintf("VP8 timing stats (mean, max) [ms] for %d frames:\n"
572
                   " read and decode frame: %.02f, %d\n"
574
                   " read and decode frame: %.02f, %d\n"
573
                   " 3 planes -> packed conversion: %.02f, %d\n"
575
                   " 3 planes -> packed conversion: %.02f, %d\n"
574
                   " upload and display: %.02f, %d\n",
576
                   " upload and display: %.02f, %d\n",
575
                   n, (double)s[0]/n, m[0], (double)s[1]/n, m[1], (double)s[2]/n, m[2]);
577
                   n, (double)s[0]/n, m[0], (double)s[1]/n, m[1], (double)s[2]/n, m[2]);
576
    }
578
    }
577
}
579
}
578
580
579
#endif
581
#endif
580
 
582