TSファイルの整形プログラム tslint を作ってみた

TSファイルは0x47で始まる188バイトのTSパケットが連続して出来ているが、チューナーから受信して加工せずに保存したTSファイルや、保存時などに問題が発生したTSファイルの場合は、TSパケットの前後や間に無駄なデータが付いていたりする可能性があるので、これを確認するためのプログラムを作ってみた。
TSファイルを指定して実行するとTSパケットを見つけた位置と大きさ、パケット数を表示する。最後に表示されるTSファイルのサイズと大きさが同じで、TSパケットを見つけた位置が0なら無駄なデータは無いことになる。出力先ファイル名も指定すると、TSパケットを見つけた位置をファイル名に加えて、TSパケットを見つけた位置から大きさの分だけ出力する。
ロジックは単純で、188バイト読み込んで、0〜187バイト目の位置が0x47なら、その位置のパケットカウンタを進め、0x47でなくて、その位置のパケットカウンタが1以上ならパケットカウンタを表示する仕組みになっている。TSパケットを見つけた位置は、パケットカウンタを進めるのが初回の時に保存している。パケットカウンタの表示はpacket_out関数で、他の位置に同じ値以上のパケットカウンタがあれば行わないようにしている。
ファイル末尾になってメインループから抜けた後、各位置のパケットカウンタと見つけた位置はファイル末尾を超えていたらパケットカウンタを1つ戻して、最後に全ての位置の有効なパケットカウンタの表示を行っている。

#include <stdio.h>

int packet_out(int i,size_t *pc,size_t *pa,int ac,char *av,FILE *fp1,size_t as) {
	FILE *fp2;
	unsigned char buf[188];
	char fn[32768];
	size_t pi;
	int j;

	/* 有効なパケットカウンタなら処理する */
	if(pc[i]>0) {
		/* 他の位置に同じ値以上のパケットカウンタが無ければ処理を続行する */
		for(j=0;j<188;j++) if(j!=i && pc[j]>=pc[i]) break;
		if(j==188) {
			/* パケットカウンタを表示する */
			printf("start: %ld, size: %ld, packet: %ld\n",pa[i]+i,pc[i]*188,pc[i]);
			/* 出力ファイル名が指定されていたらパケットカウンタと開始位置で示す範囲を出力する */
			if(ac>2) {
				sprintf(fn,"%s_%ld.ts",av,pa[i]+i);
				fp2=fopen(fn,"wb");
				fseek(fp1,pa[i]+i,SEEK_SET);
				for(pi=0;pi<pc[i];pi++) {
					fread(buf,1,188,fp1);
					fwrite(buf,1,188,fp2);
				}
				fclose(fp2);
				/* 読み込み位置を元に戻す */
				fseek(fp1,as,SEEK_SET);
			}
		}
	}
}

int main(int argc,char *argv[]) {
	FILE *fp1;
	unsigned char buf[188];
	size_t pc[188],pa[188],sz,ad;
	int i;

	fp1=fopen(argv[1],"rb");
	ad=0;
	for(i=0;i<188;i++) pc[i]=0;
	while(1) {
		/* 188バイト読み込む */
		sz=fread(buf,1,188,fp1);
		for(i=0;i<sz;i++) {
			/* 0x47ならパケットカウンタを進める */
			if(buf[i]==0x47) {
				/* 初回なら開始位置を保存する */
				if(pc[i]==0) pa[i]=ad;
				pc[i]++;
			}
			/* 0x47でなければパケットカウンタを表示する */
			else {
				packet_out(i,pc,pa,argc,argv[2],fp1,ad+sz);
				pc[i]=0;
			}
		}
		/* ファイル末尾ならループから抜ける */
		if(sz<188) break;
		ad=ad+sz;
	}
	/* 有効なパケットカウンタと開始位置がファイル末尾を超えていたらパケットカウンタを戻す */
	for(i=0;i<188;i++) if(pc[i]>0 && (ad+sz)<(pa[i]+i+(pc[i]*188))) pc[i]--;
	/* 有効なパケットカウンタを表示する */
	for(i=0;i<188;i++) packet_out(i,pc,pa,argc,argv[2],fp1,ad+sz);
	printf("total: %ld\n",ad+sz);
	fclose(fp1);
}