Skip to content

Instantly share code, notes, and snippets.

@japsu
Created June 20, 2012 11:55
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save japsu/2959531 to your computer and use it in GitHub Desktop.
Save japsu/2959531 to your computer and use it in GitHub Desktop.
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;
}
@japsu
Copy link
Author

japsu commented Jun 20, 2012

@senjer
Copy link

senjer commented Apr 7, 2016

how can i use this

@aksel
Copy link

aksel commented Feb 12, 2024

Line 156

lool
you rock

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment