Last active
December 20, 2015 19:09
-
-
Save jcmvbkbc/6181029 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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