sd2snes/snes/msu1/msu1conv.c
ikari b964f1fa7b MSU1 video player update (framerate support)
There is now a small header for the MSU video files:

 uint16_t framecount;
 uint8_t  std_frameduration;
 uint8_t  alt_frameduration;
 uint8_t  alt_durfreq;

framecount is the number of frames in the video.
std_frameduration is the usual duration of a video frame in SNES video frames.
alt_frameduration is an alternate duration
alt_durfreq specifies after how many frames the alternate duration should be used for a single video frame. The frame counter is reset afterwards.

This allows to use simple pulldown patterns.
e.g. for a 29.97fps video you need 2:2 pulldown (display every video frame for two SNES video frames).
In this case, std_frameduration, alt_frameduration, alt_durfreq are: 2, 2, x (any number is good for the freq in this case)
For 23.976fps video one would do 3:2 pulldown (displaying every other video frame for three SNES video frames).
The format would be: 2, 3, 1

Frame size is always 224x144, 32512 bytes (4 tiles wasted to save tilemap memory), followed by 512 bytes of palette.
2010-12-31 03:07:22 +01:00

126 lines
3.1 KiB
C

#include <stdio.h>
#include <fcntl.h>
#include <stdint.h>
#include <string.h>
uint16_t tilemap[28][18];
void preparetilemap(void) {
uint16_t x, y;
uint16_t tilecnt = 0;
for(y=0; y<18; y+=2) {
for(x=0; x<28; x++) {
tilemap[x][y] = tilecnt;
tilemap[x][y+1] = tilecnt + 0x10;
tilecnt++;
if(!(tilecnt & 0xf)) tilecnt += 0x10;
}
}
}
void converttile(char *in, char *out, uint8_t x, uint8_t y) {
uint32_t srctilestart = (x*8)+(y*8*224);
uint32_t tgttilestart = tilemap[x][y]*64;
char *tin = in + srctilestart;
char *tout = out + tgttilestart;
memset(tout, 0, 64);
int px, py;
for(py = 0; py < 8; py++) {
for(px = 0; px < 8; px++) {
tout[ 0+2*py] |= ((tin[px+224*py] & 0x01) << 7) >> px;
tout[ 1+2*py] |= ((tin[px+224*py] & 0x02) << 6) >> px;
tout[16+2*py] |= ((tin[px+224*py] & 0x04) << 5) >> px;
tout[17+2*py] |= ((tin[px+224*py] & 0x08) << 4) >> px;
tout[32+2*py] |= ((tin[px+224*py] & 0x10) << 3) >> px;
tout[33+2*py] |= ((tin[px+224*py] & 0x20) << 2) >> px;
tout[48+2*py] |= ((tin[px+224*py] & 0x40) << 1) >> px;
tout[49+2*py] |= ((tin[px+224*py] & 0x80) << 0) >> px;
}
}
}
void convertpalette(char *in, char *out) {
uint16_t tgtcol;
int pc;
uint8_t r, g, b;
for(pc = 0; pc < 256; pc++) {
b = in[pc*3+0];
g = in[pc*3+1];
r = in[pc*3+2];
tgtcol = ((b & 0xf8) << 7) | ((g & 0xf8) << 2) | ((r & 0xf8) >> 3);
out[pc*2+0] = tgtcol & 0xff;
out[pc*2+1] = tgtcol >> 8;
}
}
void readflip(FILE *in, char *inbuf) {
int y;
for(y=0; y<144; y++) {
fread(inbuf+224*(143-y), 224, 1, in);
}
}
int main(int argc, char **argv) {
preparetilemap();
uint16_t x,y;
for(y=0; y<18; y++) {
for(x=0; x<28; x++) {
printf("%03x ", tilemap[x][y]);
}
printf("\n");
}
char inbuf[32256], outbuf[32512];
char inpal[768], outpal[512];
FILE *in, *out;
int fileno=0, startframe=0;
uint16_t numcolors;
char filename[80];
out=fopen("out.msu", "wb");
uint8_t numframes_l, numframes_h;
uint8_t std_frameduration = 2;
uint8_t alt_frameduration = 0;
uint8_t alt_durfreq = 0;
fwrite(&filename, 5, 1, out); /* write padding for now */
while(1) {
sprintf(filename, "%08d.tga", fileno++);
if((in=fopen(filename, "rb"))==NULL) {
if(fileno==1) {
startframe = 1;
continue;
} else {
break;
}
}
fseek(in, 5, SEEK_SET);
fread(&numcolors, 2, 1, in);
fseek(in, 18, SEEK_SET);
fread(inpal, numcolors*3, 1, in);
readflip(in, inbuf);
// fread(inbuf, 32256, 1, in);
fclose(in);
for(y=0; y<18; y++) {
for(x=0; x<28; x++) {
converttile(inbuf, outbuf, x, y);
}
}
fwrite(outbuf, 32512, 1, out);
convertpalette(inpal, outpal);
fwrite(outpal, 512, 1, out);
}
fileno-=startframe;
numframes_l=fileno&0xff;
numframes_h=fileno>>8;
fseek(out, 0, SEEK_SET);
fwrite(&numframes_l, 1, 1, out);
fwrite(&numframes_h, 1, 1, out);
fwrite(&std_frameduration, 1, 1, out);
fwrite(&alt_frameduration, 1, 1, out);
fwrite(&alt_durfreq, 1, 1, out);
fclose(out);
return 0;
}