Subversion Repositories Games.Carmageddon

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 1
/**
2
        libsmacker - A C library for decoding .smk Smacker Video files
3
        Copyright (C) 2012-2017 Greg Kennedy
4
 
5
        See smacker.h for more information.
6
 
7
        smacker.c
8
                Main implementation file of libsmacker.
9
                Open, close, query, render, advance and seek an smk
10
*/
11
 
12
#include "smacker.h"
13
 
14
/* safe malloc and free */
15
#include "smk_malloc.h"
16
 
17
/* data structures */
18
#include "smk_bitstream.h"
19
#include "smk_hufftree.h"
20
 
21
/* GLOBALS */
22
/* tree processing order */
23
#define SMK_TREE_MMAP 0
24
#define SMK_TREE_MCLR 1
25
#define SMK_TREE_FULL 2
26
#define SMK_TREE_TYPE 3
27
 
28
/* SMACKER DATA STRUCTURES */
29
struct smk_t {
30
    /* meta-info */
31
    /* file mode: see flags, smacker.h */
32
    unsigned char mode;
33
 
34
    /* microsec per frame - stored as a double to handle scaling
35
                (large positive millisec / frame values may overflow a ul) */
36
    double usf;
37
 
38
    /* total frames */
39
    unsigned long f;
40
    /* does file have a ring frame? (in other words, does file loop?) */
41
    unsigned char ring_frame;
42
 
43
    /* Index of current frame */
44
    unsigned long cur_frame;
45
 
46
    /* SOURCE union.
47
                Where the data is going to be read from (or be stored),
48
                depending on the file mode. */
49
    union {
50
        struct
51
        {
52
            /* on-disk mode */
53
            FILE* fp;
54
            unsigned long* chunk_offset;
55
        } file;
56
 
57
        /* in-memory mode: unprocessed chunks */
58
        unsigned char** chunk_data;
59
    } source;
60
 
61
    /* shared array of "chunk sizes"*/
62
    unsigned long* chunk_size;
63
 
64
    /* Holds per-frame flags (i.e. 'keyframe') */
65
    unsigned char* keyframe;
66
    /* Holds per-frame type mask (e.g. 'audio track 3, 2, and palette swap') */
67
    unsigned char* frame_type;
68
 
69
    /* video and audio structures */
70
    /* Video data type: enable/disable decode switch,
71
                video info and flags,
72
                pointer to last-decoded-palette */
73
    struct smk_video_t {
74
        /* enable/disable decode switch */
75
        unsigned char enable;
76
 
77
        /* video info */
78
        unsigned long w;
79
        unsigned long h;
80
        /* Y scale mode (constants defined in smacker.h)
81
                        0: unscaled
82
                        1: doubled
83
                        2: interlaced */
84
        unsigned char y_scale_mode;
85
 
86
        /* version ('2' or '4') */
87
        unsigned char v;
88
 
89
        /* Huffman trees */
90
        /* unsigned long tree_size[4]; */
91
        struct smk_huff16_t* tree[4];
92
 
93
        /* Palette data type: pointer to last-decoded-palette */
94
        unsigned char palette[256][3];
95
        /* Last-unpacked frame */
96
        unsigned char* frame;
97
    } video;
98
 
99
    /* audio structure */
100
    struct smk_audio_t {
101
        /* set if track exists in file */
102
        unsigned char exists;
103
 
104
        /* enable/disable switch (per track) */
105
        unsigned char enable;
106
 
107
        /* Info */
108
        unsigned char channels;
109
        unsigned char bitdepth;
110
        unsigned long rate;
111
        long max_buffer;
112
 
113
        /* compression type
114
                        0: raw PCM
115
                        1: SMK DPCM
116
                        2: Bink (Perceptual), unsupported */
117
        unsigned char compress;
118
 
119
        /* pointer to last-decoded-audio-buffer */
120
        void* buffer;
121
        unsigned long buffer_size;
122
    } audio[7];
123
};
124
 
125
union smk_read_t {
126
    FILE* file;
127
    unsigned char* ram;
128
};
129
 
130
/* An fread wrapper: consumes N bytes, or returns -1
131
        on failure (when size doesn't match expected) */
132
static char smk_read_file(void* buf, const size_t size, FILE* fp) {
133
    /* don't bother checking buf or fp, fread does it for us */
134
    size_t bytesRead = fread(buf, 1, size, fp);
135
    if (bytesRead != size) {
136
        fprintf(stderr, "libsmacker::smk_read_file(buf,%lu,fp) - ERROR: Short read, %lu bytes returned\n\tReason: %s\n", (unsigned long)size, (unsigned long)bytesRead, strerror(errno));
137
        return -1;
138
    }
139
    return 0;
140
}
141
 
142
/* A memcpy wrapper: consumes N bytes, or returns -1
143
        on failure (when size too low) */
144
static char smk_read_memory(void* buf, const unsigned long size, unsigned char** p, unsigned long* p_size) {
145
    if (size > *p_size) {
146
        fprintf(stderr, "libsmacker::smk_read_memory(buf,%lu,p,%lu) - ERROR: Short read\n", (unsigned long)size, (unsigned long)*p_size);
147
        return -1;
148
    }
149
    memcpy(buf, *p, size);
150
    *p += size;
151
    *p_size -= size;
152
    return 0;
153
}
154
 
155
/* Helper functions to do the reading, plus
156
        byteswap from LE to host order */
157
/* read n bytes from (source) into ret */
158
#define smk_read(ret, n)                                                                                                                                       \
159
    {                                                                                                                                                          \
160
        if (m) {                                                                                                                                               \
161
            r = (smk_read_file(ret, n, fp.file));                                                                                                              \
162
        } else {                                                                                                                                               \
163
            r = (smk_read_memory(ret, n, &fp.ram, &size));                                                                                                     \
164
        }                                                                                                                                                      \
165
        if (r < 0) {                                                                                                                                           \
166
            fprintf(stderr, "libsmacker::smk_read(...) - Errors encountered on read, bailing out (file: %s, line: %lu)\n", __FILE__, (unsigned long)__LINE__); \
167
            goto error;                                                                                                                                        \
168
        }                                                                                                                                                      \
169
    }
170
 
171
/* Calls smk_read, but returns a ul */
172
#define smk_read_ul(p)                                                                                                              \
173
    {                                                                                                                               \
174
        smk_read(buf, 4);                                                                                                           \
175
        p = ((unsigned long)buf[3] << 24) | ((unsigned long)buf[2] << 16) | ((unsigned long)buf[1] << 8) | ((unsigned long)buf[0]); \
176
    }
177
 
178
/* PUBLIC FUNCTIONS */
179
/* open an smk (from a generic Source) */
180
static smk smk_open_generic(const unsigned char m, union smk_read_t fp, unsigned long size, const unsigned char process_mode) {
181
    smk s = NULL;
182
 
183
    /* Temporary variables */
184
    long temp_l;
185
    unsigned long temp_u;
186
 
187
    /* r is used by macros above for return code */
188
    char r;
189
    unsigned char buf[4] = { '\0' };
190
 
191
    /* video hufftrees are stored as a large chunk (bitstream)
192
                these vars are used to load, then decode them */
193
    unsigned char* hufftree_chunk = NULL;
194
    unsigned long tree_size;
195
    /* a bitstream struct */
196
    struct smk_bit_t* bs = NULL;
197
 
198
    /* safe malloc the structure */
199
    smk_malloc(s, sizeof(struct smk_t));
200
 
201
    /* Check for a valid signature */
202
    smk_read(buf, 3);
203
    if (buf[0] != 'S' || buf[1] != 'M' || buf[2] != 'K') {
204
        fprintf(stderr, "libsmacker::smk_open_generic - ERROR: invalid SMKn signature (got: %s)\n", buf);
205
        goto error;
206
    }
207
 
208
    /* Read .smk file version */
209
    smk_read(&s->video.v, 1);
210
    if (s->video.v != '2' && s->video.v != '4') {
211
        fprintf(stderr, "libsmacker::smk_open_generic - Warning: invalid SMK version %c (expected: 2 or 4)\n", s->video.v);
212
        /* take a guess */
213
        if (s->video.v < '4')
214
            s->video.v = '2';
215
        else
216
            s->video.v = '4';
217
        fprintf(stderr, "\tProcessing will continue as type %c\n", s->video.v);
218
    }
219
 
220
    /* width, height, total num frames */
221
    smk_read_ul(s->video.w);
222
    smk_read_ul(s->video.h);
223
 
224
    smk_read_ul(s->f);
225
 
226
    /* frames per second calculation */
227
    smk_read_ul(temp_u);
228
    temp_l = (int)temp_u;
229
    if (temp_l > 0) {
230
        /* millisec per frame */
231
        s->usf = temp_l * 1000;
232
    } else if (temp_l < 0) {
233
        /* 10 microsec per frame */
234
        s->usf = temp_l * -10;
235
    } else {
236
        /* defaults to 10 usf (= 100000 microseconds) */
237
        s->usf = 100000;
238
    }
239
 
240
    /* Video flags follow.
241
                Ring frame is important to libsmacker.
242
                Y scale / Y interlace go in the Video flags.
243
                The user should scale appropriately. */
244
    smk_read_ul(temp_u);
245
    if (temp_u & 0x01) {
246
        s->ring_frame = 1;
247
    }
248
    if (temp_u & 0x02) {
249
        s->video.y_scale_mode = SMK_FLAG_Y_DOUBLE;
250
    }
251
    if (temp_u & 0x04) {
252
        if (s->video.y_scale_mode == SMK_FLAG_Y_DOUBLE) {
253
            fputs("libsmacker::smk_open_generic - Warning: SMK file specifies both Y-Double AND Y-Interlace.\n", stderr);
254
        }
255
        s->video.y_scale_mode = SMK_FLAG_Y_INTERLACE;
256
    }
257
 
258
    /* Max buffer size for each audio track - used to pre-allocate buffers */
259
    for (temp_l = 0; temp_l < 7; temp_l++) {
260
        smk_read_ul(s->audio[temp_l].max_buffer);
261
    }
262
 
263
    /* Read size of "hufftree chunk" - save for later. */
264
    smk_read_ul(tree_size);
265
 
266
    /* "unpacked" sizes of each huff tree - we don't use
267
                but calling application might. */
268
    for (temp_l = 0; temp_l < 4; temp_l++) {
269
        /*              smk_read_ul(s->video.tree_size[temp_u]); */
270
        smk_read_ul(temp_u);
271
    }
272
 
273
    /* read audio rate data */
274
    for (temp_l = 0; temp_l < 7; temp_l++) {
275
        smk_read_ul(temp_u);
276
        if (temp_u & 0x40000000) {
277
            /* Audio track specifies "exists" flag, malloc structure and copy components. */
278
            s->audio[temp_l].exists = 1;
279
 
280
            /* and for all audio tracks */
281
            smk_malloc(s->audio[temp_l].buffer, s->audio[temp_l].max_buffer);
282
 
283
            if (temp_u & 0x80000000) {
284
                s->audio[temp_l].compress = 1;
285
            }
286
            s->audio[temp_l].bitdepth = ((temp_u & 0x20000000) ? 16 : 8);
287
            s->audio[temp_l].channels = ((temp_u & 0x10000000) ? 2 : 1);
288
            if (temp_u & 0x0c000000) {
289
                fprintf(stderr, "libsmacker::smk_open_generic - Warning: audio track %ld is compressed with Bink (perceptual) Audio Codec: this is currently unsupported by libsmacker\n", temp_l);
290
                s->audio[temp_l].compress = 2;
291
            }
292
            /* Bits 25 & 24 are unused. */
293
            s->audio[temp_l].rate = (temp_u & 0x00FFFFFF);
294
        }
295
    }
296
 
297
    /* Skip over Dummy field */
298
    smk_read_ul(temp_u);
299
 
300
    /* FrameSizes and Keyframe marker are stored together. */
301
    smk_malloc(s->keyframe, (s->f + s->ring_frame));
302
    smk_malloc(s->chunk_size, (s->f + s->ring_frame) * sizeof(unsigned long));
303
 
304
    for (temp_u = 0; temp_u < (s->f + s->ring_frame); temp_u++) {
305
        smk_read_ul(s->chunk_size[temp_u]);
306
 
307
        /* Set Keyframe */
308
        if (s->chunk_size[temp_u] & 0x01) {
309
            s->keyframe[temp_u] = 1;
310
        }
311
        /* Bits 1 is used, but the purpose is unknown. */
312
        s->chunk_size[temp_u] &= 0xFFFFFFFC;
313
    }
314
 
315
    /* That was easy... Now read FrameTypes! */
316
    smk_malloc(s->frame_type, (s->f + s->ring_frame));
317
    for (temp_u = 0; temp_u < (s->f + s->ring_frame); temp_u++) {
318
        smk_read(&s->frame_type[temp_u], 1);
319
    }
320
 
321
    /* HuffmanTrees
322
                We know the sizes already: read and assemble into
323
                something actually parse-able at run-time */
324
    smk_malloc(hufftree_chunk, tree_size);
325
    smk_read(hufftree_chunk, tree_size);
326
 
327
    /* set up a Bitstream */
328
    bs = smk_bs_init(hufftree_chunk, tree_size);
329
    /* create some tables */
330
    for (temp_u = 0; temp_u < 4; temp_u++) {
331
        smk_huff16_build(bs, s->video.tree[temp_u]);
332
    }
333
 
334
    /* clean up */
335
    smk_free(bs);
336
    smk_free(hufftree_chunk);
337
 
338
    /* Go ahead and malloc storage for the video frame */
339
    smk_malloc(s->video.frame, s->video.w * s->video.h);
340
 
341
    /* final processing: depending on ProcessMode, handle what to do with rest of file data */
342
    s->mode = process_mode;
343
 
344
    /* Handle the rest of the data.
345
                For MODE_MEMORY, read the chunks and store */
346
    if (s->mode == SMK_MODE_MEMORY) {
347
        smk_malloc(s->source.chunk_data, (s->f + s->ring_frame) * sizeof(unsigned char*));
348
        for (temp_u = 0; temp_u < (s->f + s->ring_frame); temp_u++) {
349
            smk_malloc(s->source.chunk_data[temp_u], s->chunk_size[temp_u]);
350
            smk_read(s->source.chunk_data[temp_u], s->chunk_size[temp_u]);
351
        }
352
    } else {
353
        /* MODE_STREAM: don't read anything now, just precompute offsets.
354
                        use fseek to verify that the file is "complete" */
355
        smk_malloc(s->source.file.chunk_offset, (s->f + s->ring_frame) * sizeof(unsigned long));
356
        for (temp_u = 0; temp_u < (s->f + s->ring_frame); temp_u++) {
357
            s->source.file.chunk_offset[temp_u] = ftell(fp.file);
358
            if (fseek(fp.file, s->chunk_size[temp_u], SEEK_CUR)) {
359
                fprintf(stderr, "libsmacker::smk_open - ERROR: fseek to frame %lu not OK.\n", temp_u);
360
                perror("\tError reported was");
361
                goto error;
362
            }
363
        }
364
    }
365
 
366
    return s;
367
 
368
error:
369
    smk_free(bs);
370
    smk_free(hufftree_chunk);
371
    smk_close(s);
372
    return NULL;
373
}
374
 
375
/* open an smk (from a memory buffer) */
376
smk smk_open_memory(const unsigned char* buffer, const unsigned long size) {
377
    smk s = NULL;
378
 
379
    union smk_read_t fp;
380
 
381
    smk_assert(buffer);
382
 
383
    /* set up the read union for Memory mode */
384
    fp.ram = (unsigned char*)buffer;
385
 
386
    if (!(s = smk_open_generic(0, fp, size, SMK_MODE_MEMORY))) {
387
        fprintf(stderr, "libsmacker::smk_open_memory(buffer,%lu) - ERROR: Fatal error in smk_open_generic, returning NULL.\n", size);
388
    }
389
 
390
    /* fall through, return s or null */
391
error:
392
    return s;
393
}
394
 
395
/* open an smk (from a file) */
396
smk smk_open_filepointer(FILE* file, const unsigned char mode) {
397
    smk s = NULL;
398
    union smk_read_t fp;
399
 
400
    smk_assert(file);
401
 
402
    /* Copy file ptr to internal union */
403
    fp.file = file;
404
 
405
    if (!(s = smk_open_generic(1, fp, 0, mode))) {
406
        fprintf(stderr, "libsmacker::smk_open_filepointer(file,%u) - ERROR: Fatal error in smk_open_generic, returning NULL.\n", mode);
407
        fclose(fp.file);
408
        goto error;
409
    }
410
 
411
    if (mode == SMK_MODE_MEMORY) {
412
        fclose(fp.file);
413
    } else {
414
        s->source.file.fp = fp.file;
415
    }
416
 
417
    /* fall through, return s or null */
418
error:
419
    return s;
420
}
421
 
422
/* open an smk (from a file) */
423
smk smk_open_file(const char* filename, const unsigned char mode) {
424
    FILE* fp;
425
 
426
    smk_assert(filename);
427
 
428
    if (!(fp = fopen(filename, "rb"))) {
429
        // Jeff commented out error messages
430
        // fprintf(stderr,"libsmacker::smk_open_file(%s,%u) - ERROR: could not open file (errno: %d)\n",filename,mode,errno);
431
        // perror ("\tError reported was");
432
        goto error;
433
    }
434
 
435
    /* kick processing to smk_open_filepointer */
436
    return smk_open_filepointer(fp, mode);
437
 
438
    /* fall through, return s or null */
439
error:
440
    return NULL;
441
}
442
 
443
/* close out an smk file and clean up memory */
444
void smk_close(smk s) {
445
    unsigned long u;
446
 
447
    smk_assert(s);
448
 
449
    /* free video sub-components */
450
    {
451
        for (u = 0; u < 4; u++) {
452
            if (s->video.tree[u])
453
                smk_huff16_free(s->video.tree[u]);
454
        }
455
        smk_free(s->video.frame);
456
    }
457
 
458
    /* free audio sub-components */
459
    for (u = 0; u < 7; u++) {
460
        smk_free(s->audio[u].buffer);
461
    }
462
 
463
    smk_free(s->keyframe);
464
    smk_free(s->frame_type);
465
 
466
    if (s->mode == SMK_MODE_DISK) {
467
        /* disk-mode */
468
        if (s->source.file.fp) {
469
            fclose(s->source.file.fp);
470
        }
471
        smk_free(s->source.file.chunk_offset);
472
    } else {
473
        /* mem-mode */
474
        if (s->source.chunk_data != NULL) {
475
            for (u = 0; u < (s->f + s->ring_frame); u++) {
476
                smk_free(s->source.chunk_data[u]);
477
            }
478
            smk_free(s->source.chunk_data);
479
        }
480
    }
481
    smk_free(s->chunk_size);
482
 
483
    smk_free(s);
484
 
485
error:;
486
}
487
 
488
/* tell some info about the file */
489
char smk_info_all(const smk object, unsigned long* frame, unsigned long* frame_count, double* usf) {
490
    /* sanity check */
491
    smk_assert(object);
492
    if (!frame && !frame_count && !usf) {
493
        fputs("libsmacker::smk_info_all(object,frame,frame_count,usf) - ERROR: Request for info with all-NULL return references\n", stderr);
494
        goto error;
495
    }
496
    if (frame)
497
        *frame = (object->cur_frame % object->f);
498
 
499
    if (frame_count)
500
        *frame_count = object->f;
501
 
502
    if (usf)
503
        *usf = object->usf;
504
 
505
    return 0;
506
 
507
error:
508
    return -1;
509
}
510
 
511
char smk_info_video(const smk object, unsigned long* w, unsigned long* h, unsigned char* y_scale_mode) {
512
    /* sanity check */
513
    smk_assert(object);
514
    if (!w && !h && !y_scale_mode) {
515
        fputs("libsmacker::smk_info_all(object,w,h,y_scale_mode) - ERROR: Request for info with all-NULL return references\n", stderr);
516
        return -1;
517
    }
518
 
519
    if (w)
520
        *w = object->video.w;
521
 
522
    if (h)
523
        *h = object->video.h;
524
 
525
    if (y_scale_mode)
526
        *y_scale_mode = object->video.y_scale_mode;
527
 
528
    return 0;
529
 
530
error:
531
    return -1;
532
}
533
 
534
char smk_info_audio(const smk object, unsigned char* track_mask, unsigned char channels[7], unsigned char bitdepth[7], unsigned long audio_rate[7]) {
535
    unsigned char i;
536
 
537
    /* sanity check */
538
    smk_assert(object);
539
 
540
    if (!track_mask && !channels && !bitdepth && !audio_rate) {
541
        fputs("libsmacker::smk_info_audio(object,track_mask,channels,bitdepth,audio_rate) - ERROR: Request for info with all-NULL return references\n", stderr);
542
        return -1;
543
    }
544
    if (track_mask) {
545
        *track_mask = ((object->audio[0].exists) | ((object->audio[1].exists) << 1) | ((object->audio[2].exists) << 2) | ((object->audio[3].exists) << 3) | ((object->audio[4].exists) << 4) | ((object->audio[5].exists) << 5) | ((object->audio[6].exists) << 6));
546
    }
547
    if (channels) {
548
        for (i = 0; i < 7; i++) {
549
            channels[i] = object->audio[i].channels;
550
        }
551
    }
552
    if (bitdepth) {
553
        for (i = 0; i < 7; i++) {
554
            bitdepth[i] = object->audio[i].bitdepth;
555
        }
556
    }
557
    if (audio_rate) {
558
        for (i = 0; i < 7; i++) {
559
            audio_rate[i] = object->audio[i].rate;
560
        }
561
    }
562
    return 0;
563
 
564
error:
565
    return -1;
566
}
567
 
568
/* Enable-disable switches */
569
char smk_enable_all(smk object, const unsigned char mask) {
570
    unsigned char i;
571
 
572
    /* sanity check */
573
    smk_assert(object);
574
 
575
    /* set video-enable */
576
    object->video.enable = (mask & 0x80);
577
 
578
    for (i = 0; i < 7; i++) {
579
        if (object->audio[i].exists) {
580
            object->audio[i].enable = (mask & (1 << i));
581
        }
582
    }
583
 
584
    return 0;
585
 
586
error:
587
    return -1;
588
}
589
 
590
char smk_enable_video(smk object, const unsigned char enable) {
591
    /* sanity check */
592
    smk_assert(object);
593
 
594
    object->video.enable = enable;
595
    return 0;
596
 
597
error:
598
    return -1;
599
}
600
 
601
char smk_enable_audio(smk object, const unsigned char track, const unsigned char enable) {
602
    /* sanity check */
603
    smk_assert(object);
604
 
605
    object->audio[track].enable = enable;
606
    return 0;
607
 
608
error:
609
    return -1;
610
}
611
 
612
const unsigned char* smk_get_palette(const smk object) {
613
    smk_assert(object);
614
 
615
    return (unsigned char*)object->video.palette;
616
 
617
error:
618
    return NULL;
619
}
620
const unsigned char* smk_get_video(const smk object) {
621
    smk_assert(object);
622
 
623
    return object->video.frame;
624
 
625
error:
626
    return NULL;
627
}
628
const unsigned char* smk_get_audio(const smk object, const unsigned char t) {
629
    smk_assert(object);
630
 
631
    return object->audio[t].buffer;
632
 
633
error:
634
    return NULL;
635
}
636
unsigned long smk_get_audio_size(const smk object, const unsigned char t) {
637
    smk_assert(object);
638
 
639
    return object->audio[t].buffer_size;
640
 
641
error:
642
    return 0;
643
}
644
 
645
/* Decompresses a palette-frame. */
646
static char smk_render_palette(struct smk_video_t* s, unsigned char* p, unsigned long size) {
647
    /* Index into palette */
648
    unsigned short i = 0;
649
    /* Helper variables */
650
    unsigned short count, src;
651
 
652
    static unsigned char oldPalette[256][3];
653
 
654
    /* Smacker palette map: smk colors are 6-bit, this table expands them to 8. */
655
    const unsigned char palmap[64] = {
656
        0x00, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1C,
657
        0x20, 0x24, 0x28, 0x2C, 0x30, 0x34, 0x38, 0x3C,
658
        0x41, 0x45, 0x49, 0x4D, 0x51, 0x55, 0x59, 0x5D,
659
        0x61, 0x65, 0x69, 0x6D, 0x71, 0x75, 0x79, 0x7D,
660
        0x82, 0x86, 0x8A, 0x8E, 0x92, 0x96, 0x9A, 0x9E,
661
        0xA2, 0xA6, 0xAA, 0xAE, 0xB2, 0xB6, 0xBA, 0xBE,
662
        0xC3, 0xC7, 0xCB, 0xCF, 0xD3, 0xD7, 0xDB, 0xDF,
663
        0xE3, 0xE7, 0xEB, 0xEF, 0xF3, 0xF7, 0xFB, 0xFF
664
    };
665
 
666
    /* sanity check */
667
    smk_assert(s);
668
    smk_assert(p);
669
 
670
    // Copy palette to old palette
671
    memcpy(oldPalette, s->palette, 256 * 3);
672
 
673
    /* Loop until palette is complete, or we are out of bytes to process */
674
    while ((i < 256) && (size > 0)) {
675
        if ((*p) & 0x80) {
676
            /* 0x80: Skip block
677
                                (preserve C+1 palette entries from previous palette) */
678
            count = ((*p) & 0x7F) + 1;
679
            p++;
680
            size--;
681
 
682
            /* check for overflow condition */
683
            if (i + count > 256) {
684
                fprintf(stderr, "libsmacker::palette_render(s,p,size) - ERROR: overflow, 0x80 attempt to skip %d entries from %d\n", count, i);
685
                goto error;
686
            }
687
 
688
            /* finally: advance the index. */
689
            i += count;
690
        } else if ((*p) & 0x40) {
691
            /* 0x40: Color-shift block
692
                                Copy (c + 1) color entries of the previous palette,
693
                                starting from entry (s),
694
                                to the next entries of the new palette. */
695
            if (size < 2) {
696
                fputs("libsmacker::palette_render(s,p,size) - ERROR: 0x40 ran out of bytes for copy\n", stderr);
697
                goto error;
698
            }
699
 
700
            /* pick "count" items to copy */
701
            count = ((*p) & 0x3F) + 1;
702
            p++;
703
            size--;
704
 
705
            /* start offset of old palette */
706
            src = *p;
707
            p++;
708
            size--;
709
 
710
            /* overflow: see if we write/read beyond 256colors, or overwrite own palette */
711
            if (i + count > 256 || src + count > 256 || (src < i && src + count > i)) {
712
                fprintf(stderr, "libsmacker::palette_render(s,p,size) - ERROR: overflow, 0x40 attempt to copy %d entries from %d to %d\n", count, src, i);
713
                goto error;
714
            }
715
 
716
            /* OK!  Copy the color-palette entries. */
717
            memmove(&s->palette[i][0], &oldPalette[src][0], count * 3);
718
 
719
            i += count;
720
        } else {
721
            /* 0x00: Set Color block
722
                                Direct-set the next 3 bytes for palette index */
723
            if (size < 3) {
724
                fprintf(stderr, "libsmacker::palette_render - ERROR: 0x3F ran out of bytes for copy, size=%lu\n", size);
725
                goto error;
726
            }
727
 
728
            for (count = 0; count < 3; count++) {
729
                if (*p > 0x3F) {
730
                    fprintf(stderr, "libsmacker::palette_render - ERROR: palette index exceeds 0x3F (entry [%u][%u])\n", i, count);
731
                    goto error;
732
                }
733
                s->palette[i][count] = palmap[*p];
734
                p++;
735
                size--;
736
            }
737
            i++;
738
        }
739
    }
740
 
741
    if (i < 256) {
742
        fprintf(stderr, "libsmacker::palette_render - ERROR: did not completely fill palette (idx=%u)\n", i);
743
        goto error;
744
    }
745
 
746
    return 0;
747
 
748
error:
749
    /* Error, return -1
750
                The new palette probably has errors but is preferrable to a black screen */
751
    return -1;
752
}
753
 
754
static char smk_render_video(struct smk_video_t* s, unsigned char* p, unsigned int size) {
755
    unsigned char* t = s->frame;
756
    unsigned char s1, s2;
757
    unsigned short temp;
758
    unsigned long i, j, k, row, col, skip;
759
 
760
    /* used for video decoding */
761
    struct smk_bit_t* bs = NULL;
762
 
763
    /* results from a tree lookup */
764
    long unpack;
765
 
766
    /* unpack, broken into pieces */
767
    unsigned char type;
768
    unsigned char blocklen;
769
    unsigned char typedata;
770
    char bit;
771
 
772
    const unsigned short sizetable[64] = {
773
        1, 2, 3, 4, 5, 6, 7, 8,
774
        9, 10, 11, 12, 13, 14, 15, 16,
775
        17, 18, 19, 20, 21, 22, 23, 24,
776
        25, 26, 27, 28, 29, 30, 31, 32,
777
        33, 34, 35, 36, 37, 38, 39, 40,
778
        41, 42, 43, 44, 45, 46, 47, 48,
779
        49, 50, 51, 52, 53, 54, 55, 56,
780
        57, 58, 59, 128, 256, 512, 1024, 2048
781
    };
782
 
783
    /* sanity check */
784
    smk_assert(s);
785
    smk_assert(p);
786
 
787
    row = 0;
788
    col = 0;
789
 
790
    /* Set up a bitstream for video unpacking */
791
    /* We could check the return code but it will only fail if p is null and we already verified that. */
792
    bs = smk_bs_init(p, size);
793
 
794
    /* Reset the cache on all bigtrees */
795
    smk_huff16_reset(s->tree[0]);
796
    smk_huff16_reset(s->tree[1]);
797
    smk_huff16_reset(s->tree[2]);
798
    smk_huff16_reset(s->tree[3]);
799
 
800
    while (row < s->h) {
801
        smk_huff16_lookup(bs, s->tree[SMK_TREE_TYPE], unpack);
802
 
803
        type = ((unpack & 0x0003));
804
        blocklen = ((unpack & 0x00FC) >> 2);
805
        typedata = ((unpack & 0xFF00) >> 8);
806
 
807
        /* support for v4 full-blocks */
808
        if (type == 1 && s->v == '4') {
809
            smk_bs_read_1(bs, bit);
810
            if (bit) {
811
                type = 4;
812
            } else {
813
                smk_bs_read_1(bs, bit);
814
                if (bit) {
815
                    type = 5;
816
                }
817
            }
818
        }
819
 
820
        for (j = 0; (j < sizetable[blocklen]) && (row < s->h); j++) {
821
            skip = (row * s->w) + col;
822
            switch (type) {
823
            case 0:
824
                smk_huff16_lookup(bs, s->tree[SMK_TREE_MCLR], unpack);
825
                s1 = (unpack & 0xFF00) >> 8;
826
                s2 = (unpack & 0x00FF);
827
                smk_huff16_lookup(bs, s->tree[SMK_TREE_MMAP], unpack);
828
 
829
                temp = 0x01;
830
                for (k = 0; k < 4; k++) {
831
                    for (i = 0; i < 4; i++) {
832
                        if (unpack & temp) {
833
                            t[skip + i] = s1;
834
                        } else {
835
                            t[skip + i] = s2;
836
                        }
837
                        temp = temp << 1;
838
                    }
839
                    skip += s->w;
840
                }
841
                break;
842
 
843
            case 1: /* FULL BLOCK */
844
                for (k = 0; k < 4; k++) {
845
                    smk_huff16_lookup(bs, s->tree[SMK_TREE_FULL], unpack);
846
                    t[skip + 3] = ((unpack & 0xFF00) >> 8);
847
                    t[skip + 2] = (unpack & 0x00FF);
848
                    smk_huff16_lookup(bs, s->tree[SMK_TREE_FULL], unpack);
849
                    t[skip + 1] = ((unpack & 0xFF00) >> 8);
850
                    t[skip] = (unpack & 0x00FF);
851
                    skip += s->w;
852
                }
853
                break;
854
            case 2: /* VOID BLOCK */
855
                /* break;
856
                                        if (s->frame)
857
                                        {
858
                                                memcpy(&t[skip], &s->frame[skip], 4);
859
                                                skip += s->w;
860
                                                memcpy(&t[skip], &s->frame[skip], 4);
861
                                                skip += s->w;
862
                                                memcpy(&t[skip], &s->frame[skip], 4);
863
                                                skip += s->w;
864
                                                memcpy(&t[skip], &s->frame[skip], 4);
865
                                        } */
866
                break;
867
            case 3: /* SOLID BLOCK */
868
                memset(&t[skip], typedata, 4);
869
                skip += s->w;
870
                memset(&t[skip], typedata, 4);
871
                skip += s->w;
872
                memset(&t[skip], typedata, 4);
873
                skip += s->w;
874
                memset(&t[skip], typedata, 4);
875
                break;
876
            case 4: /* V4 DOUBLE BLOCK */
877
                for (k = 0; k < 2; k++) {
878
                    smk_huff16_lookup(bs, s->tree[SMK_TREE_FULL], unpack);
879
                    for (i = 0; i < 2; i++) {
880
                        memset(&t[skip + 2], (unpack & 0xFF00) >> 8, 2);
881
                        memset(&t[skip], (unpack & 0x00FF), 2);
882
                        skip += s->w;
883
                    }
884
                }
885
                break;
886
            case 5: /* V4 HALF BLOCK */
887
                for (k = 0; k < 2; k++) {
888
                    smk_huff16_lookup(bs, s->tree[SMK_TREE_FULL], unpack);
889
                    t[skip + 3] = ((unpack & 0xFF00) >> 8);
890
                    t[skip + 2] = (unpack & 0x00FF);
891
                    t[skip + s->w + 3] = ((unpack & 0xFF00) >> 8);
892
                    t[skip + s->w + 2] = (unpack & 0x00FF);
893
                    smk_huff16_lookup(bs, s->tree[SMK_TREE_FULL], unpack);
894
                    t[skip + 1] = ((unpack & 0xFF00) >> 8);
895
                    t[skip] = (unpack & 0x00FF);
896
                    t[skip + s->w + 1] = ((unpack & 0xFF00) >> 8);
897
                    t[skip + s->w] = (unpack & 0x00FF);
898
                    skip += (s->w << 1);
899
                }
900
                break;
901
            }
902
            col += 4;
903
            if (col >= s->w) {
904
                col = 0;
905
                row += 4;
906
            }
907
        }
908
    }
909
 
910
    smk_free(bs);
911
 
912
    return 0;
913
 
914
error:
915
    smk_free(bs);
916
    return -1;
917
}
918
 
919
/* Decompress audio track i. */
920
static char smk_render_audio(struct smk_audio_t* s, unsigned char* p, unsigned long size) {
921
    unsigned int j, k;
922
    unsigned char* t = s->buffer;
923
    struct smk_bit_t* bs = NULL;
924
 
925
    char bit;
926
    short unpack, unpack2;
927
 
928
    /* used for audio decoding */
929
    struct smk_huff8_t* aud_tree[4] = { NULL, NULL, NULL, NULL };
930
 
931
    /* sanity check */
932
    smk_assert(s);
933
    smk_assert(p);
934
 
935
    if (!s->compress) {
936
        /* Raw PCM data, update buffer size and malloc */
937
        s->buffer_size = size;
938
 
939
        memcpy(t, p, size);
940
    } else if (s->compress == 1) {
941
        /* SMACKER DPCM compression */
942
        /* need at least 4 bytes to process */
943
        if (size < 4) {
944
            fputs("libsmacker::smk_render_audio() - ERROR: need 4 bytes to get unpacked output buffer size.\n", stderr);
945
            goto error;
946
        }
947
        /* chunk is compressed (huff-compressed dpcm), retrieve unpacked buffer size */
948
        s->buffer_size = ((unsigned int)p[3] << 24) | ((unsigned int)p[2] << 16) | ((unsigned int)p[1] << 8) | ((unsigned int)p[0]);
949
 
950
        p += 4;
951
        size -= 4;
952
 
953
        /* Compressed audio: must unpack here */
954
        /*  Set up a bitstream */
955
        bs = smk_bs_init(p, size);
956
 
957
        smk_bs_read_1(bs, bit);
958
 
959
        if (!bit) {
960
            fputs("libsmacker::smk_render_audio - ERROR: initial get_bit returned 0\n", stderr);
961
            goto error;
962
        }
963
 
964
        smk_bs_read_1(bs, bit);
965
        if (s->channels != (bit == 1 ? 2 : 1)) {
966
            fputs("libsmacker::smk_render - ERROR: mono/stereo mismatch\n", stderr);
967
        }
968
        smk_bs_read_1(bs, bit);
969
        if (s->bitdepth != (bit == 1 ? 16 : 8)) {
970
            fputs("libsmacker::smk_render - ERROR: 8-/16-bit mismatch\n", stderr);
971
        }
972
 
973
        /* build the trees */
974
        smk_huff8_build(bs, aud_tree[0]);
975
        j = 1;
976
        k = 1;
977
        if (s->bitdepth == 16) {
978
            smk_huff8_build(bs, aud_tree[1]);
979
            k = 2;
980
        }
981
        if (s->channels == 2) {
982
            smk_huff8_build(bs, aud_tree[2]);
983
            j = 2;
984
            k = 2;
985
            if (s->bitdepth == 16) {
986
                smk_huff8_build(bs, aud_tree[3]);
987
                k = 4;
988
            }
989
        }
990
 
991
        /* read initial sound level */
992
        if (s->channels == 2) {
993
            smk_bs_read_8(bs, unpack);
994
            if (s->bitdepth == 16) {
995
                smk_bs_read_8(bs, ((short*)t)[1])((short*)t)[1] |= (unpack << 8);
996
            } else {
997
                ((unsigned char*)t)[1] = (unsigned char)unpack;
998
            }
999
        }
1000
        smk_bs_read_8(bs, unpack);
1001
        if (s->bitdepth == 16) {
1002
            smk_bs_read_8(bs, ((short*)t)[0])((short*)t)[0] |= (unpack << 8);
1003
        } else {
1004
            ((unsigned char*)t)[0] = (unsigned char)unpack;
1005
        }
1006
 
1007
        /* All set: let's read some DATA! */
1008
        while (k < s->buffer_size) {
1009
            if (s->bitdepth == 8) {
1010
                smk_huff8_lookup(bs, aud_tree[0], unpack);
1011
                ((unsigned char*)t)[j] = (char)unpack + ((unsigned char*)t)[j - s->channels];
1012
                j++;
1013
                k++;
1014
            } else {
1015
                smk_huff8_lookup(bs, aud_tree[0], unpack);
1016
                smk_huff8_lookup(bs, aud_tree[1], unpack2);
1017
                ((short*)t)[j] = (short)(unpack | (unpack2 << 8)) + ((short*)t)[j - s->channels];
1018
                j++;
1019
                k += 2;
1020
            }
1021
            if (s->channels == 2) {
1022
                if (s->bitdepth == 8) {
1023
                    smk_huff8_lookup(bs, aud_tree[2], unpack);
1024
                    ((unsigned char*)t)[j] = (char)unpack + ((unsigned char*)t)[j - 2];
1025
                    j++;
1026
                    k++;
1027
                } else {
1028
                    smk_huff8_lookup(bs, aud_tree[2], unpack);
1029
                    smk_huff8_lookup(bs, aud_tree[3], unpack2);
1030
                    ((short*)t)[j] = (short)(unpack | (unpack2 << 8)) + ((short*)t)[j - 2];
1031
                    j++;
1032
                    k += 2;
1033
                }
1034
            }
1035
        }
1036
 
1037
        /* All done with the trees, free them. */
1038
        for (j = 0; j < 4; j++) {
1039
            if (aud_tree[j]) {
1040
                smk_huff8_free(aud_tree[j]);
1041
            }
1042
        }
1043
 
1044
        /* free bitstream */
1045
        smk_free(bs);
1046
    }
1047
 
1048
    return 0;
1049
 
1050
error:
1051
    /* All done with the trees, free them. */
1052
    for (j = 0; j < 4; j++) {
1053
        if (aud_tree[j]) {
1054
            smk_huff8_free(aud_tree[j]);
1055
        }
1056
    }
1057
 
1058
    smk_free(bs);
1059
 
1060
    return -1;
1061
}
1062
 
1063
/* "Renders" (unpacks) the frame at cur_frame
1064
        Preps all the image and audio pointers */
1065
static char smk_render(smk s) {
1066
    unsigned long i, size;
1067
    unsigned char *buffer = NULL, *p, track;
1068
 
1069
    /* sanity check */
1070
    smk_assert(s);
1071
 
1072
    /* Retrieve current chunk_size for this frame. */
1073
    if (!(i = s->chunk_size[s->cur_frame])) {
1074
        fprintf(stderr, "libsmacker::smk_render(s) - Warning: frame %lu: chunk_size is 0.\n", s->cur_frame);
1075
        goto error;
1076
    }
1077
 
1078
    if (s->mode == SMK_MODE_DISK) {
1079
        /* Skip to frame in file */
1080
        if (fseek(s->source.file.fp, s->source.file.chunk_offset[s->cur_frame], SEEK_SET)) {
1081
            fprintf(stderr, "libsmacker::smk_render(s) - ERROR: fseek to frame %lu (offset %lu) failed.\n", s->cur_frame, s->source.file.chunk_offset[s->cur_frame]);
1082
            perror("\tError reported was");
1083
            goto error;
1084
        }
1085
 
1086
        /* In disk-streaming mode: make way for our incoming chunk buffer */
1087
        smk_malloc(buffer, i);
1088
 
1089
        /* Read into buffer */
1090
        if (smk_read_file(buffer, s->chunk_size[s->cur_frame], s->source.file.fp) < 0) {
1091
            fprintf(stderr, "libsmacker::smk_render(s) - ERROR: frame %lu (offset %lu): smk_read had errors.\n", s->cur_frame, s->source.file.chunk_offset[s->cur_frame]);
1092
            goto error;
1093
        }
1094
    } else {
1095
        /* Just point buffer at the right place */
1096
        if (!s->source.chunk_data[s->cur_frame]) {
1097
            fprintf(stderr, "libsmacker::smk_render(s) - ERROR: frame %lu: memory chunk is a NULL pointer.\n", s->cur_frame);
1098
            goto error;
1099
        }
1100
        buffer = s->source.chunk_data[s->cur_frame];
1101
    }
1102
 
1103
    p = buffer;
1104
 
1105
    /* Palette record first */
1106
    if (s->frame_type[s->cur_frame] & 0x01) {
1107
        /* need at least 1 byte to process */
1108
        if (!i) {
1109
            fprintf(stderr, "libsmacker::smk_render(s) - ERROR: frame %lu: insufficient data for a palette rec.\n", s->cur_frame);
1110
            goto error;
1111
        }
1112
 
1113
        /* Byte 1 in block, times 4, tells how many
1114
                        subsequent bytes are present */
1115
        size = 4 * (*p);
1116
 
1117
        /* If video rendering enabled, kick this off for decode. */
1118
        if (s->video.enable) {
1119
            smk_render_palette(&(s->video), p + 1, size - 1);
1120
        }
1121
        p += size;
1122
        i -= size;
1123
    }
1124
 
1125
    /* Unpack audio chunks */
1126
    for (track = 0; track < 7; track++) {
1127
        if (s->frame_type[s->cur_frame] & (0x02 << track)) {
1128
            /* need at least 4 byte to process */
1129
            if (i < 4) {
1130
                fprintf(stderr, "libsmacker::smk_render(s) - ERROR: frame %lu: insufficient data for audio[%u] rec.\n", s->cur_frame, track);
1131
                goto error;
1132
            }
1133
 
1134
            /* First 4 bytes in block tell how many
1135
                                subsequent bytes are present */
1136
            size = (((unsigned int)p[3] << 24) | ((unsigned int)p[2] << 16) | ((unsigned int)p[1] << 8) | ((unsigned int)p[0]));
1137
 
1138
            /* If audio rendering enabled, kick this off for decode. */
1139
            if (s->audio[track].enable) {
1140
                smk_render_audio(&s->audio[track], p + 4, size - 4);
1141
            }
1142
            p += size;
1143
            i -= size;
1144
        } else {
1145
            s->audio[track].buffer_size = 0;
1146
        }
1147
    }
1148
 
1149
    /* Unpack video chunk */
1150
    if (s->video.enable) {
1151
        smk_render_video(&(s->video), p, i);
1152
    }
1153
 
1154
    if (s->mode == SMK_MODE_DISK) {
1155
        /* Remember that buffer we allocated?  Trash it */
1156
        smk_free(buffer);
1157
    }
1158
 
1159
    return 0;
1160
 
1161
error:
1162
    if (s->mode == SMK_MODE_DISK) {
1163
        /* Remember that buffer we allocated?  Trash it */
1164
        smk_free(buffer);
1165
    }
1166
 
1167
    return -1;
1168
}
1169
 
1170
/* rewind to first frame and unpack */
1171
char smk_first(smk s) {
1172
    smk_assert(s);
1173
 
1174
    s->cur_frame = 0;
1175
    if (smk_render(s) < 0) {
1176
        fprintf(stderr, "libsmacker::smk_first(s) - Warning: frame %lu: smk_render returned errors.\n", s->cur_frame);
1177
        goto error;
1178
    }
1179
 
1180
    if (s->f == 1)
1181
        return SMK_LAST;
1182
    return SMK_MORE;
1183
 
1184
error:
1185
    return -1;
1186
}
1187
 
1188
/* advance to next frame */
1189
char smk_next(smk s) {
1190
    smk_assert(s);
1191
 
1192
    if (s->cur_frame + 1 < (s->f + s->ring_frame)) {
1193
        s->cur_frame++;
1194
        if (smk_render(s) < 0) {
1195
            fprintf(stderr, "libsmacker::smk_next(s) - Warning: frame %lu: smk_render returned errors.\n", s->cur_frame);
1196
            goto error;
1197
        }
1198
        if (s->cur_frame + 1 == (s->f + s->ring_frame)) {
1199
            return SMK_LAST;
1200
        }
1201
        return SMK_MORE;
1202
    } else if (s->ring_frame) {
1203
        s->cur_frame = 1;
1204
        if (smk_render(s) < 0) {
1205
            fprintf(stderr, "libsmacker::smk_next(s) - Warning: frame %lu: smk_render returned errors.\n", s->cur_frame);
1206
            goto error;
1207
        }
1208
        if (s->cur_frame + 1 == (s->f + s->ring_frame)) {
1209
            return SMK_LAST;
1210
        }
1211
        return SMK_MORE;
1212
    }
1213
    return SMK_DONE;
1214
 
1215
error:
1216
    return -1;
1217
}
1218
 
1219
/* seek to a keyframe in an smk */
1220
char smk_seek_keyframe(smk s, unsigned long f) {
1221
    smk_assert(s);
1222
 
1223
    /* rewind (or fast forward!) exactly to f */
1224
    s->cur_frame = f;
1225
 
1226
    /* roll back to previous keyframe in stream, or 0 if no keyframes exist */
1227
    while (s->cur_frame > 0 && !(s->keyframe[s->cur_frame])) {
1228
        s->cur_frame--;
1229
    }
1230
 
1231
    /* render the frame: we're ready */
1232
    if (smk_render(s) < 0) {
1233
        fprintf(stderr, "libsmacker::smk_seek_keyframe(s,%lu) - Warning: frame %lu: smk_render returned errors.\n", f, s->cur_frame);
1234
        goto error;
1235
    }
1236
 
1237
    return 0;
1238
 
1239
error:
1240
    return -1;
1241
}