Skip to content

Embed URL

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
fix a broken Sony AnyCast DVPRO/PCM AVI file
/*
* fixavi.c - fix a broken Sony AnyCast DVPRO/PCM AVI file
* Written by Matti "Lumpio-" Virkkunen
*
* Compile with: cc -o fixavi fixavi.c (or just make fixavi)
*/
#define _FILE_OFFSET_BITS 64
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdint.h>
FILE *in, *out;
#define STREAM_UNKNOWN 0
#define STREAM_VIDEO 1
#define STREAM_AUDIO 2
struct stream {
char valid;
int id;
char fourcc[4];
int type;
};
off_t in_size, first_chunk;
int nfound, nstreams;
struct stream streams[256];
void init_stream(int id, char *fourcc) {
struct stream *s = &streams[id];
s->valid = 1;
s->id = id;
memcpy(s->fourcc, fourcc, 4);
if (!strncmp(fourcc + 2, "db", 2) ||
!strncmp(fourcc + 2, "dc", 2))
{
s->type = STREAM_VIDEO;
} else if (!strncmp(fourcc + 2, "wb", 2)) {
s->type = STREAM_AUDIO;
} else {
s->type = STREAM_UNKNOWN;
}
nstreams++;
}
void chunk_fail() {
memset(streams, 0, sizeof(streams));
nfound = 0;
first_chunk = 0;
nstreams = 0;
}
void write_str(char *val) {
fwrite(val, strlen(val), 1, out);
}
void write_word(uint16_t val) {
fwrite(&val, 2, 1, out);
}
void write_dword(uint32_t val) {
fwrite(&val, 4, 1, out);
}
off_t begin_size() {
write_str("@@@@");
return ftello(out);
}
void end(off_t start) {
off_t cur = ftello(out);
int32_t val = (int32_t)(cur - start);
fseeko(out, start - 4, SEEK_SET);
fwrite(&val, 4, 1, out);
fseeko(out, cur, SEEK_SET);
}
off_t begin_chunk(char *type) {
write_str(type);
return begin_size();
}
off_t begin_list(char *type) {
off_t start = begin_chunk("LIST");
write_str(type);
return start;
}
int width = 1024, height = 518;
void write_opendml_header() {
off_t odml_o = begin_list("odml");
write_str("dmlh");
write_dword(248);
int i;
for (i = 0; i < 248; i += 4)
write_dword(0);
end(odml_o);
}
void write_avih() {
write_str("avih"); // fcc
write_dword(14 * 4); // cb
write_dword(1000*1000/25); // dwMicroSecPerFrame
write_dword(1024*1024*10); // dwMaxBytesPerSec
write_dword(0); // dwPaddingGranularity
write_dword(0); // dwFlags
write_dword(1024); // dwTotalFrames
write_dword(0); // dwInitialFrames
write_dword(nstreams); // dwStreams
write_dword(1024*1024); // dwSuggestedBufferSize
write_dword(width); // dwWidth
write_dword(height); // dwHeight
write_dword(0); // dwReserved
write_dword(0);
write_dword(0);
write_dword(0);
}
void write_waveformatex() {
off_t strf_o = begin_chunk("strf");
write_word(1); // wFormatTag = WAVE_FORMAT_PCM
write_word(2); // nChannels
write_dword(48000); // nSamplesPerSec
write_dword(48000 * 4); // nAvgBytesPerSec
write_word(2 * 2); // nBlockAlign
write_word(16); // wBitsPerSample
write_word(0); // cbSize
end(strf_o);
}
void write_dvinfo() {
off_t strf_o = begin_chunk("strf");
// No idea what this does, wing it
write_dword(0x00000028);
write_dword(0x000002d0);
write_dword(0x00000240);
write_dword(0x00180001);
write_str("dvsd"); // ??
write_dword(0x00023280);
write_dword(0);
write_dword(0);
write_dword(0);
write_dword(0);
end(strf_o);
}
void write_strl(struct stream *stream) {
off_t strl_o = begin_list("strl");
write_str("strh"); // fcc
write_dword(14 * 4); // cb
switch (stream->type) { // fccType
case STREAM_VIDEO:
//write_str("iavs"); // fccType
write_str("vids"); // fccType
write_str("dvsd"); // fccHandler
break;
case STREAM_AUDIO:
write_str("auds"); // fccType
write_dword(0); // fccHandler
break;
default:
write_str("????"); // fccType
write_str("????"); // fccHandler
break;
}
write_dword(0); // dwFlags
write_word(0); // dwPriority
write_word(0); // dwLanguage
write_dword(0); // dwInitialFrames
switch (stream->type) {
case STREAM_VIDEO:
write_dword(100); // dwScale
write_dword(2500); // dwRate
break;
case STREAM_AUDIO:
write_dword(1); // dwScale
write_dword(48000); // dwRate
break;
default:
write_dword(1); // dwScale
write_dword(1); // dwRate
}
write_dword(0); // dwStart
write_dword(1024); // dwLength
write_dword(1024*1024); // dwSuggestedBufferSize
write_dword(10000); // dwQuality
write_dword(1024); // dwSampleSize
write_word(0); // rcFrame.left
write_word(0); // rcFrame.top
write_word(0); // rcFrame.right
write_word(0); // rcFrame.bottom
switch (stream->type) {
case STREAM_AUDIO:
write_waveformatex();
break;
case STREAM_VIDEO:
write_dvinfo();
break;
}
end(strl_o);
}
int main(int argc, char **argv) {
char buf[4069];
if (argc != 3) {
fprintf(stderr, "USAGE: %s infile outfile\n", argv[0]);
return 1;
}
in = fopen(argv[1], "rb");
if (!in) {
fprintf(stderr, "Failed to open %s\n", argv[1]);
return 1;
}
fseeko(in, 0, SEEK_END);
in_size = ftello(in);
fseeko(in, 0, SEEK_SET);
out = fopen(argv[2], "wb");
if (!out) {
fprintf(stderr, "Failed to open %s\n", argv[2]);
return 1;
}
printf("Looking for an intact AVI chunk...\n");
while (!feof(in)) {
buf[0] = fgetc(in);
if (!isxdigit(buf[0])) {
chunk_fail();
continue;
}
buf[1] = fgetc(in);
if (!isxdigit(buf[1])) {
chunk_fail();
continue;
}
buf[2] = fgetc(in);
if (!isalpha(buf[2])) {
chunk_fail();
continue;
}
buf[3] = fgetc(in);
if (!isalpha(buf[3])) {
chunk_fail();
continue;
}
long pos = ftello(in) - 4;
if (nfound == 0) {
first_chunk = pos;
printf("Found candidate chunk at 0x%x: %.4s\n",
first_chunk, buf);
}
nfound++;
if (nfound >= 32) {
printf("Found at least %d intact chunks\n", nfound);
break;
}
int len;
if (fread(&len, 1, 4, in) != 4)
break;
printf(" type=%.4s length=%d\n", buf, len);
if (len < 0 || pos + len >= in_size) {
printf(" crazy length, ignoring\n");
chunk_fail();
continue;
}
int id;
sscanf(buf, "%2x", &id);
if (!streams[id].valid)
init_stream(id, buf);
fseeko(in, len, SEEK_CUR);
}
if (nfound < 30) {
printf("Didn't find intact chunks :(\n");
return 1;
}
printf("Found %d streams starting from 0x%x:\n",
nstreams, first_chunk);
int i;
for (i = 0; i < sizeof(streams)/sizeof(streams[0]); i++) {
if (!streams[i].valid)
continue;
printf(" id=%2x fourcc=%.4s\n",
i,
streams[i].fourcc);
}
int nriffs = 0, go = 1, output_rest = 0;
uint32_t riffsize = 0;
fseeko(in, first_chunk, SEEK_SET);
while (go) {
nriffs++;
riffsize = 0;
printf("Writing RIFF #%d\n", nriffs);
off_t riff_o = begin_chunk("RIFF");
write_str("AVI ");
off_t hdrl_o = begin_list("hdrl");
write_avih();
for (i = 0; i < sizeof(streams)/sizeof(streams[0]); i++) {
if (!streams[i].valid)
continue;
write_strl(&streams[i]);
}
write_opendml_header();
end(hdrl_o);
printf("Writing chunks\n");
off_t movi_o = begin_list("movi");
while (riffsize < 900 * 1024 * 1024)
{
if (fread(buf, 1, 4, in) == 4)
{
if (!strncmp(buf, "RIFF", 4)) {
printf("Found a new RIFF header, writing the rest as-is\n");
fwrite(buf, 1, 4, out);
output_rest = 1;
go = 0;
break;
}
uint32_t len;
if (fread(&len, 1, 4, in) == 4) {
fwrite(buf, 1, 4, out);
fwrite(&len, 1, 4, out);
riffsize += 4 + len;
while (len > 0 && !feof(in)) {
uint32_t rsize = fread(buf,
1, len > sizeof(buf) ? sizeof(buf) : len, in);
fwrite(buf, 1, rsize, out);
len -= rsize;
}
}
}
//printf("%d\n", riffsize);
if (feof(in)) {
go = 0;
break;
}
}
end(movi_o);
end(riff_o);
}
if (output_rest) {
while (!feof(in)) {
uint32_t rsize = fread(buf, 1, sizeof(buf), in);
fwrite(buf, 1, rsize, out);
}
}
printf("All done!\n");
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.