以前、TSファイルの録画開始時刻を調べるでプログラムを作った際に「ファイル末尾から逆順にパケットを読むように書き換えれば録画終了日時も求められる」と書いたが、C言語って標準ライブラリだけではファイル末尾まで読み取る以外にファイルサイズを知る方法が無い(fseekでSEEK_ENDを使う方法は環境によっては使えないらしい)と知ったので、一般的に多用されているstat関数を使って処理するソースを書いてみた。
TSファイルを指定して実行すると先頭から最初に見つかったTOTを年、月、日、曜日、時、分、秒で表示した後、パケット末尾から逆順にTOTを探して見つかったものを同様に表示する。エラーチェックとか全然してないのでTOTを含まないTSファイルやファイル先頭からパケットが始まらないTSファイルを指定した場合は保証しない。
日数の計算処理が間違っていた為に2016年2月29日以降の日付がズレていたので、当時書いたバッチファイルで日数を年月日に換算を元に処理を書き直した。(2016/03/03追記)
#include <stdio.h> #include <sys/stat.h> int main(int argc,char *argv[]) { FILE *fp; struct stat st; long fs,rs; unsigned char buf[188]; int mf,pid,mjd,jth,jtm,jts,jdy,jdm,jdd,jdw,jds; char wds[7][4]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; /* TSファイルを開く */ fp=fopen(argv[1],"rb"); /* ファイルサイズを取得する */ fstat(fileno(fp),&st); /* パケット末尾の位置を求める */ fs=st.st_size-(st.st_size % 188); mf=0; while(1) { /* 先頭のTOT発見後は末尾からTOTを探す */ if(mf==1) { fs=fs-188; fseek(fp,fs,SEEK_SET); } /* 188バイトのパケット単位で読み込む */ rs=fread(buf,1,188,fp); if(rs<188) { break; } /* PIDを求める */ pid=((buf[1] << 8) | buf[2]) & 0x1fff; /* PIDがTOTならば処理する */ if(pid==0x14) { /* 修正ユリウス日と時、分、秒を求める */ mjd=(buf[8] << 8) | buf[9]; jth=((buf[10] & 0xf0) >> 4)*10+(buf[10] & 0x0f); jtm=((buf[11] & 0xf0) >> 4)*10+(buf[11] & 0x0f); jts=((buf[12] & 0xf0) >> 4)*10+(buf[12] & 0x0f); /* 修正ユリウス日を西暦1年1月1日からの日数に変換する */ jdd=mjd+678576; /* 日数から曜日を求める */ jdw=jdd % 7; /* 日数から年、月、日を求める */ jdd=jdd-1-31-28+365; jds=jdd%146097%36524%1461%365+jdd%146097/36524/4*365+jdd%146097%36524%1461/365/4*365; jdy=jdd/146097*400+jdd%146097/36524*100-jdd%146097/36524/4+jdd%146097%36524/1461*4+jdd%146097%36524%1461/365-jdd%146097%36524%1461/365/4; jdm=jds/153*5+jds%153/61*2+jds%153%61/31+3; jdd=jds%153%61%31+1; if(jdm>12) { jdy=jdy+1; jdm=jdm-12; } /* 年、月、日、曜日、時、分、秒を表示して終了する */ printf("%04d/%02d/%02d %s %02d:%02d:%02d\n",jdy,jdm,jdd,wds[jdw],jth,jtm,jts); /* 先頭のTOT発見ならモードフラグを変更、末尾のTOT発見ならループから抜ける */ if(mf==0) { mf=1; } else { break; } } } fclose(fp); }