Files

195 lines
5.4 KiB
C

/* movie.c -- pure decoder for the BAPL tile-delta movie format.
*
* K&R C: the 1987 TMS34010 compiler has no const, no ANSI prototypes and no
* stdint.h. The host test compiles this same file with gcc -std=c99.
*/
#include "movie.h"
#define HEADER_SIZE 36
#define INDEX_ENTRY_SIZE 6
static unsigned int rd16(p)
unsigned char *p;
{
return (unsigned int)p[0] | ((unsigned int)p[1] << 8);
}
static unsigned long rd32(p)
unsigned char *p;
{
return (unsigned long)p[0] | ((unsigned long)p[1] << 8)
| ((unsigned long)p[2] << 16) | ((unsigned long)p[3] << 24);
}
int movie_open(data, len, header)
unsigned char *data;
unsigned long len;
struct movie_header *header;
{
unsigned int version;
if (data == 0 || header == 0 || len < HEADER_SIZE) {
return -1;
}
if (data[0] != 'B' || data[1] != 'A' || data[2] != 'P' || data[3] != 'L') {
return -1;
}
version = rd16(data + 4);
if (version != 1) {
return -1;
}
header->width = rd16(data + 6);
header->height = rd16(data + 8);
header->scale = rd16(data + 10);
header->tile = rd16(data + 12);
header->tiles_x = rd16(data + 14);
header->tiles_y = rd16(data + 16);
header->frame_count = (unsigned int)rd32(data + 18);
header->index_offset = (unsigned int)rd32(data + 22);
header->data_offset = (unsigned int)rd32(data + 26);
header->source_fps = rd16(data + 30);
header->display_hz = rd16(data + 32);
if (header->scale == 0 || header->scale > 4 || header->tile == 0
|| header->tile > 32 || header->tiles_x == 0
|| header->tiles_y == 0) {
return -1;
}
if (header->width != header->tiles_x * header->tile
|| header->height != header->tiles_y * header->tile
|| header->width * header->scale > 1280
|| header->height * header->scale > 1024) {
return -1;
}
if ((unsigned long)header->index_offset
+ (unsigned long)header->frame_count * INDEX_ENTRY_SIZE > len) {
return -1;
}
return 0;
}
unsigned int movie_frame_ticks(data, len, frame, header)
unsigned char *data;
unsigned long len;
unsigned int frame;
struct movie_header *header;
{
unsigned long index_off;
if (data == 0 || header == 0 || frame >= header->frame_count) {
return 1;
}
index_off = (unsigned long)header->index_offset
+ (unsigned long)frame * INDEX_ENTRY_SIZE;
if (index_off + INDEX_ENTRY_SIZE > len) {
return 1;
}
return (unsigned int)data[index_off + 4];
}
int movie_decode_frame(data, len, frame, header, fill, ctx)
unsigned char *data;
unsigned long len;
unsigned int frame;
struct movie_header *header;
movie_fill_fn fill;
void *ctx;
{
unsigned long index_off;
unsigned long off;
unsigned int count;
unsigned int i;
unsigned int j;
unsigned int tile_index;
unsigned int packed;
unsigned int bg;
unsigned int rects;
unsigned int tx;
unsigned int ty;
unsigned int value;
unsigned int x0;
unsigned int y0;
unsigned int w;
unsigned int h;
int sx;
int sy;
if (data == 0 || header == 0 || fill == 0) {
return -1;
}
if (frame >= header->frame_count) {
return -1;
}
index_off = (unsigned long)header->index_offset
+ (unsigned long)frame * INDEX_ENTRY_SIZE;
if (index_off + INDEX_ENTRY_SIZE > len) {
return -1;
}
off = rd32(data + index_off);
if (off + 2 > len) {
return -1;
}
count = rd16(data + off);
off += 2;
for (i = 0; i < count; i++) {
if (off + 4 > len) {
return -1;
}
tile_index = rd16(data + off);
packed = rd16(data + off + 2);
off += 4;
if (tile_index >= header->tiles_x * header->tiles_y) {
return -1;
}
bg = packed >> 15;
rects = packed & 0x7FFF;
if (off + (unsigned long)rects * 3 > len) {
return -1;
}
tx = tile_index % header->tiles_x;
ty = tile_index / header->tiles_x;
/* The whole tile first: the old pixels outside every new rect must
* go away. The C test skips this first call per tile. */
sx = (int)(tx * header->tile * header->scale);
sy = (int)(ty * header->tile * header->scale);
fill(sx, sy, (int)(header->tile * header->scale),
(int)(header->tile * header->scale), (int)bg, ctx);
for (j = 0; j < rects; j++) {
value = (unsigned int)data[off]
| ((unsigned int)data[off + 1] << 8)
| ((unsigned int)data[off + 2] << 16);
off += 3;
x0 = value & 0x1F;
y0 = (value >> 5) & 0x1F;
w = ((value >> 10) & 0x1F) + 1;
h = ((value >> 15) & 0x1F) + 1;
if (x0 + w > header->tile || y0 + h > header->tile) {
return -1;
}
sx = (int)((tx * header->tile + x0) * header->scale);
sy = (int)((ty * header->tile + y0) * header->scale);
fill(sx, sy, (int)(w * header->scale),
(int)(h * header->scale), (int)(1 - bg), ctx);
}
}
return 0;
}
unsigned int movie_checksum(data, len)
unsigned char *data;
unsigned long len;
{
unsigned long sum = 0;
unsigned long i;
if (data == 0) {
return 0;
}
for (i = 0; i < len; i++) {
sum = (sum + data[i]) & 0xFFFFFFFF;
}
return (unsigned int)sum;
}