Skip to content

Instantly share code, notes, and snippets.

@jcmvbkbc
Last active December 20, 2015 19:09
Show Gist options
  • Save jcmvbkbc/6181029 to your computer and use it in GitHub Desktop.
Save jcmvbkbc/6181029 to your computer and use it in GitHub Desktop.
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdint.h>
#include <malloc.h>
#include <unistd.h>
struct FstHdr {
uint32_t signature;
uint32_t width;
uint32_t height;
uint32_t ticks;
uint32_t frames;
uint32_t rate;
uint32_t sound_rate;
uint32_t sound_bits;
} __attribute__((packed));
struct Frame {
uint32_t video_size;
uint16_t audio_size;
} __attribute__((packed));
struct VideoData {
uint16_t bitmap_size;
uint8_t bitmap[8192];
uint8_t palette[768];
} __attribute__((packed));
struct VideoDataReadState {
unsigned bitmap_pos;
unsigned data_pos;
};
uint32_t get_bit(unsigned i, const uint8_t *bitmap)
{
return (bitmap[i / 8] >> (7 - i % 8)) & 1;
}
int read_header(int fd, struct FstHdr *hdr)
{
read(fd, hdr, sizeof(*hdr));
return 0;
}
int read_frames(int fd, const struct FstHdr *hdr, struct Frame **frame_)
{
int rd;
struct Frame *frame;
frame = calloc(hdr->frames, sizeof(struct Frame));
rd = read(fd, frame, hdr->frames * sizeof(struct Frame));
*frame_ = frame;
return 0;
}
int read_video_data(int fd, struct VideoData *vd)
{
int rd;
rd = read(fd, &vd->bitmap_size, sizeof(vd->bitmap_size));
rd = read(fd, vd->bitmap, vd->bitmap_size / 8 + 1);
if (get_bit(0, vd->bitmap))
rd = read(fd, vd->palette, sizeof(vd->palette));
return 0;
}
void set_pixel(uint8_t *video_frame_bitmap, unsigned x, unsigned y,
const struct FstHdr *hdr, uint8_t color)
{
video_frame_bitmap[x + y * hdr->width] = color;
}
int read_video_frame(int fd, const struct FstHdr *hdr, const struct Frame *frame,
const struct VideoData *vd, struct VideoDataReadState *vdrs, uint8_t *video_frame_bitmap)
{
unsigned x, y;
for (y = 0; y < hdr->height; y += 4) {
for (x = 0; x < hdr->width; x += 4) {
uint8_t bit = get_bit(vdrs->bitmap_pos++, vd->bitmap);
unsigned i, j;
if (!bit)
continue;
bit = get_bit(vdrs->bitmap_pos++, vd->bitmap);
if (bit) {
struct {
uint8_t color0, color1;
uint16_t btc_map;
} __attribute__((packed)) pack;
vdrs->data_pos += 4;
read(fd, &pack, sizeof(pack));
for (i = 0; i < 4; ++i) {
for (j = 0; j < 4; ++j) {
set_pixel(video_frame_bitmap, x + j, y + i, hdr,
(pack.btc_map & 0x8000) ? pack.color1 : pack.color0);
pack.btc_map <<= 1;
}
}
} else {
uint8_t colors[4][4];
vdrs->data_pos += 16;
read(fd, &colors, sizeof(colors));
for (i = 0; i < 4; ++i) {
for (j = 0; j < 4; ++j) {
set_pixel(video_frame_bitmap, x + j, y + i, hdr,
colors[i][j]);
}
}
}
}
}
}
unsigned get_color_bits(const struct VideoData *vd, unsigned index, unsigned component)
{
return vd->palette[index * 3 + component];
}
void write_xpm(FILE *fd, const struct FstHdr *hdr, const struct VideoData *vd,
uint8_t *video_frame_bitmap)
{
unsigned i, j;
fprintf(fd,
"/* XPM */\n"
"static char * XFACE[] = {\n"
"/* <Values> */\n"
"/* <width/cols> <height/rows> <colors> <char on pixel>*/\n"
"\"%u %u %u %u\",\n"
"/* <Colors> */\n",
hdr->width, hdr->height, 256, 2);
for (i = 0; i < 256; ++i) {
fprintf(fd,
"\"%02x c #%02x%02x%02x\",\n",
i,
get_color_bits(vd, i, 0),
get_color_bits(vd, i, 1),
get_color_bits(vd, i, 2));
}
fprintf(fd,
"/* <Pixels> */\n");
for (i = 0; i < hdr->height; ++i) {
fprintf(fd, "\"");
for (j = 0; j < hdr->width; ++j)
fprintf(fd, "%02x", video_frame_bitmap[j + hdr->width * i]);
fprintf(fd, "\",\n");
}
fprintf(fd, "};\n");
}
int main(int argc, char **argv)
{
int fd = argc > 1 ? open(argv[1], O_RDONLY) : 0;
struct FstHdr hdr;
struct Frame *frame;
uint8_t *video_frame_bitmap;
unsigned i;
read_header(fd, &hdr);
video_frame_bitmap = calloc(1, hdr.width * hdr.height);
read_frames(fd, &hdr, &frame);
for (i = 0; i < hdr.frames; ++i) {
struct VideoDataReadState vdrs = {1};
struct VideoData vd;
off_t off = lseek(fd, 0, SEEK_CUR);
read_video_data(fd, &vd);
printf("frame %u, video_size: %u, audio_size: %u\n", i, frame[i].video_size, frame[i].audio_size);
read_video_frame(fd, &hdr, frame + i, &vd, &vdrs, video_frame_bitmap);
{
char name[16];
FILE *f;
sprintf(name, "frame%04u.xpm", i);
f = fopen(name, "w");
write_xpm(f, &hdr, &vd, video_frame_bitmap);
fclose(f);
}
printf("video_data: %u\n", 2 + vd.bitmap_size / 8 + 1 + (get_bit(0, vd.bitmap) ? 768 : 0) + vdrs.data_pos);
lseek(fd, off, SEEK_SET);
lseek(fd, frame[i].video_size, SEEK_CUR);
lseek(fd, frame[i].audio_size, SEEK_CUR);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment