Created
June 20, 2012 11:55
-
-
Save japsu/2959531 to your computer and use it in GitHub Desktop.
fix a broken Sony AnyCast DVPRO/PCM AVI file
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
/* | |
* 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; | |
} |
how can i use this
Line 156
lool
you rock
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
For background, see http://avp.stackexchange.com/questions/4202/how-do-i-recover-truncated-avi-dv-video