/*
for disabling audio commentary tracks in MP4 streams
author: DJ Grenola
date: 17 July 2007
license: none (public domain)
target: win32 (MINGW), recommend using the free IDE from bloodshed.net
version: beta 0.1
*/
#define LARGE_FILE_SUPPORT
#ifdef LARGE_FILE_SUPPORT
/* not necessary for mingw/win32 but will probably become so if we start
trying to compile it on linux and friends */
#define _FILE_OFFSET_BITS 64
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* #define VERBOSE */
#define CHECKBYTES_LEN 8
#define CHECKBYTES { 0x74, 0x6B, 0x68, 0x64, 0x00, 0x00, 0x00, 0x01 }
#define REPBYTES { 0x74, 0x6B, 0x68, 0x64, 0x00, 0x00, 0x00, 0x00 }
#define NUM_TO_SKIP 2
#define BUFSIZE 1024*1024
#ifdef LARGE_FILE_SUPPORT
#define FOPEN fopen64
#define FSEEK fseeko64
#define FTELL ftello64
#define OFF_T off64_t
#else
#define FOPEN fopen
#define FSEEK fseek
#define FTELL ftell
#define OFF_T int
#endif
typedef long long int s64;
void usage(char *argv0);
unsigned char checkbytes[CHECKBYTES_LEN]=CHECKBYTES;
unsigned char repbytes[CHECKBYTES_LEN]=REPBYTES;
unsigned char buffer[BUFSIZE];
int main (int argc, char **argv) {
FILE *f;
unsigned int matches=0;
unsigned int bufstart=0;
unsigned int bytes_to_read;
unsigned int error=0;
s64 br;
OFF_T pos=0,tmp64;
char *fname=NULL;
printf ("MP4 audio track disabler\n");
printf ("beta 0.1, DJ Grenola\n\n");
printf ("This software comes with no warranty.\n\n");
if ((argc!=2 && argc!=3) || (argc==3 && strcmp(argv[1],"-x"))) {
usage(argv[0]);
return 0;
}
fname=argv[argc-1];
if ((f=FOPEN(fname,"r+b"))==NULL) {
printf ("[-] Failed to open file \"%s\".\n", fname);
return 1;
}
printf ("[+] Using %u KiB chunks.\n", BUFSIZE/1024);
printf ("[+] Scanning file \"%s\".\n", fname);
while (~0) {
int i;
bytes_to_read=BUFSIZE-bufstart;
br=fread(buffer+bufstart,1,bytes_to_read,f);
pos+=br;
#ifdef VERBOSE
printf ("[+] Read %llu bytes.\n", pos);
#endif
for (i=0;i<br+bufstart;i++) {
if (!memcmp(checkbytes,buffer+i,CHECKBYTES_LEN)) {
matches++;
printf ("[+] Match at offset 0x%0llx", pos-br+(i-bufstart));
if (argc==2) /* dummy mode */
printf (", no action taken.\n");
else {
if (matches<=NUM_TO_SKIP)
printf (", ignored.\n");
else {
printf (", attempting overwrite ...\n");
if (matches>NUM_TO_SKIP) {
/* FIXME: this is kind of dodgy because I don't know if off64_t
can be relied upon to be signed ... it works now, but in the
future ? */
tmp64=-br+(i-bufstart);
if (FSEEK(f,pos+tmp64,SEEK_SET)==-1) {
error=3;
printf ("[-] Error seeking to offset.\n");
goto lbl_end;
}
if (fwrite(repbytes,1,CHECKBYTES_LEN,f) != CHECKBYTES_LEN) {
error=4;
printf ("[-] Error writing replacement string.\n");
goto lbl_end;
}
/* put file pointer back (if necessary) */
if (br==bytes_to_read) {
if (FSEEK(f,pos,SEEK_SET)==-1) {
error=5;
printf ("[-] Error seeking to original position.\n");
goto lbl_end;
}
}
printf ("[+] Replaced successfully.\n");
}
}
}
}
}
bufstart=CHECKBYTES_LEN-1;
memmove(buffer,buffer+(BUFSIZE-(CHECKBYTES_LEN-1)),CHECKBYTES_LEN-1);
if (br!=bytes_to_read)
break;
}
lbl_end:
if (ferror(f) || error) {
/* FIXME: actually report some sort of useful error instead */
printf ("[-] Erk. Something went wrong.\n");
fclose(f);
return error?error:2;
}
fclose(f);
return 0;
}
void usage(char *argv0) {
printf ("Usage: %s [-x] <MP4 file>\n\n", argv0);
printf ("By default, the file is scanned and no changes are made.\n");
printf ("Use the -x switch to force changes to the file.\n");
}