1 /*********************************************************************
2 original base program http://oku.edu.mie-u.ac.jp/~okumura/dumpwave.c
6 Usage: cmcheckwave filename.wav
7 *********************************************************************/
15 static void usage(void){
19 unsigned char *get_bytes(FILE *f, int n)
21 static unsigned char s[16];
23 assert (n <= sizeof s);
24 if (fread(s, n, 1, f) != 1) {
25 fprintf(stderr, "Read error\n");
31 unsigned long get_ulong(FILE *f)
33 unsigned char *s = get_bytes(f, 4);
34 return s[0] + 256LU * (s[1] + 256LU * (s[2] + 256LU * s[3]));
37 unsigned get_ushort(FILE *f)
39 unsigned char *s = get_bytes(f, 2);
40 return s[0] + 256U * s[1];
51 static muonst m[1000];
54 static int noaudioencode=0;
55 static char *wkfilename=NULL;
56 static int defmuon=250;
59 static char *MP4BOXCMD="/usr/local/bin/MP4Box -quiet -noprog";
60 static char *MP4BOXCMDRAPSTR="Adjusting chunk start time to previous random access at ";
61 static char *SOXCMD="/usr/local/bin/sox";
62 static char *FFMPEGCMD="/usr/local/bin/ffmpeg";
63 static char *AACENCCMD="/usr/local/bin/aacplusenc";
65 FILE *checkMP4(FILE *f,char *filename)
71 memset(readbuf,0,sizeof(readbuf));
72 fread(readbuf,sizeof(readbuf),1,f);
74 if (!strstr(readbuf+4,"ftypisom")) {
77 sprintf(cmdbuf,"%s -v 0 -i %s -f wav pipe: 2>/dev/null",FFMPEGCMD,filename);
78 pp = popen(cmdbuf,"r");
79 if (pp == NULL) return NULL;
81 wkfilename = strdup(filename);
85 FILE *openpipeffmpeg(char *filename)
94 int checkMP4RAP(int stsec,int edsec)
101 if (wkfilename==NULL) return stsec;
103 sprintf(cmdbuf,"%s -splitx %.2f:%.2f %s -out /dev/null",MP4BOXCMD,edsec/1000.0,(edsec+10000)/1000.0,wkfilename);
106 pp = popen(cmdbuf,"r");
107 if (pp == NULL) return stsec;
108 while(fgets(pbuf,1024,pp)!=NULL){
109 if (strstr(pbuf,MP4BOXCMDRAPSTR)) {
110 sscanf(pbuf+strlen(MP4BOXCMDRAPSTR),"%f",&rap);
111 //TODO rapはCM開始フレームの秒数なのでちょっと戻す。
112 // フレームレートとか調べないとだめだな・・・
117 if (rap > 0 && stsec < rap*1000.0) return rap*1000.0;
121 int dumpinfo(int mcnt)
123 int honstart,hcnt,totalsec;
129 printf("#!/bin/sh\n# cmcheckwave %s\n#\n",wkfilename?wkfilename:"");
130 //カットするため、一連のCM,本編時間を結合
131 for(i=0;i<mcnt;i++) {
132 printf("# %.2f %.2f diff %.2f %s\n",m[i].stsec/1000.0,m[i].edsec/1000.0,m[i].diffs/1000.0,m[i].cmflg?"CM":"");
134 if ((m[i].cmflg==0)&&(honstart==0)) {
136 if (i==0) h[hcnt].stsec = 0;
137 else h[hcnt].stsec = m[i-1].edsec+(defmuon*0.5);
141 if ((m[i].cmflg==1)&&(honstart==1)) {
143 //h[hcnt].edsec = m[i-1].stsec;
144 h[hcnt].edsec = checkMP4RAP(m[i-1].stsec,m[i-1].edsec);
145 totalsec += h[hcnt].edsec - h[hcnt].stsec;
151 h[hcnt].edsec = checkMP4RAP(m[i-1].stsec,m[i-1].edsec);
152 totalsec += h[hcnt].edsec - h[hcnt].stsec;
156 printf("# total %.2f\n\n",totalsec/1000.0);
158 for(i=0;i<hcnt;i++) {
160 printf("%s -splitx %.2f:%.2f %s -out %s.%d%s\n",MP4BOXCMD,h[i].stsec/1000.0,h[i].edsec/1000.0,wkfilename,wkfilename,i,noaudioencode?".mp4":"");
161 if (!noaudioencode) {
162 printf("%s -v 0 -i %s.%d -vn %s.%d.wav\n",FFMPEGCMD,wkfilename,i,wkfilename,i);
163 printf("%s -v 0 -i %s.%d -an -vcodec copy %s.%d.mp4\n",FFMPEGCMD,wkfilename,i,wkfilename,i);
167 printf("# %s -splitx %.2f:%.2f \n",MP4BOXCMD,h[i].stsec/1000.0,h[i].edsec/1000.0);
171 if (!noaudioencode) {
172 printf("%s ",SOXCMD);
173 for(i=0;i<hcnt;i++) {
174 printf(" %s.%d.wav ",wkfilename,i);
176 printf(" %s.wav\n",wkfilename);
177 printf("%s %s.wav %s.aac 60\n",AACENCCMD,wkfilename,wkfilename);
179 printf("%s ",MP4BOXCMD);
180 for(i=0;i<hcnt;i++) {
181 printf(" -cat %s.%d.mp4 ",wkfilename,i);
183 printf(" %s-new.mp4\n",wkfilename);
186 printf("%s -add %s.aac %s-new.mp4\n",MP4BOXCMD,wkfilename,wkfilename);
188 printf("rm -f %s.*\n\n",wkfilename);
192 int rechecktext(FILE *f)
211 while(fgets(rbuf,1024,f)!=NULL){
212 if (strstr(rbuf,"# cmcheckwave ")) {
214 if (strlen(rbuf+14)-1>0) {
215 wkfilename = malloc(strlen(rbuf+14));
216 strncpy(wkfilename,rbuf+14,strlen(rbuf+14)-1);
221 if (strstr(rbuf,"# total "))
225 sscanf(rbuf,"# %s %s diff %s %s",wk1,wk2,wk3,wk4);
227 m[cnt].stsec = (int)(atof(wk1)*1000.0);
228 m[cnt].edsec = (int)(atof(wk2)*1000.0);
229 m[cnt].diffs = (int)(atof(wk3)*1000.0);
230 if (strstr(wk4,"CM")) m[cnt].cmflg=1;
237 return dumpinfo(cnt);
242 int cmcheckwave(FILE *f)
244 int i,j, x, channels, bits;
249 int readed,loop,max,totalsec,muonstartsec,kankaku;
252 int mcnt,hcnt,rcnt,readbufsz;
253 unsigned char *readbuf;
258 if (memcmp(get_bytes(f, 4), "RIFF", 4) != 0) {
259 // fprintf(stderr, "Not a 'RIFF' format\n");
262 //fprintf(stderr, "[RIFF] (%lu bytes)\n", get_ulong(f));
264 if (memcmp(get_bytes(f, 8), "WAVEfmt ", 8) != 0) {
265 // fprintf(stderr, "Not a 'WAVEfmt ' format\n");
269 //fprintf(stderr, "[WAVEfmt ] (%lu bytes)\n", len);
270 //fprintf(stderr, " Data type = %u (1 = PCM)\n", get_ushort(f));
272 channels = get_ushort(f);
273 //fprintf(stderr, " Number of channels = %u (1 = mono, 2 = stereo)\n", channels);
274 //fprintf(stderr, " Sampling rate = %luHz\n", get_ulong(f));
277 //fprintf(stderr, " Bytes / second = %lu\n", bsec);
278 //fprintf(stderr, " Bytes x channels = %u\n", get_ushort(f));
280 bits = get_ushort(f);
281 //fprintf(stderr, " Bits / sample = %u\n", bits);
282 for (i = 16; i < len; i++)
284 while (fread(s, 4, 1, f) == 1) {
287 //fprintf(stderr, "[%s] (%lu bytes)\n", s, len);
288 if (memcmp(s, "data", 4) == 0) break;
289 for (i = 0; i < len; i++)
293 readed=max=totalsec=kankaku=mcnt=0;
296 readbuf=malloc(4096*1000);
297 while(rcnt=fread(readbuf,1,4096*1000,f)) {
298 for(readbufsz=0;readbufsz<rcnt;) {
299 for (i = 0; i < channels; i++) {
301 //if ((x = fgetc(f)) == EOF) {loop=0;break;}
302 x = readbuf[readbufsz];
307 //if (fread(s, 2, 1, f) != 1) {loop=0;break;}
308 //x = (short)(s[0] + 256 * s[1]);
309 x = (short)(readbuf[readbufsz+0] + 256 * readbuf[readbufsz+1]);
313 if (x > max) max = x;
315 //if (i != channels - 1) printf("\t");
318 if (readed % (bsec/100) == 0) {
320 if (muonstartsec==-1 && max < defmax) {
321 muonstartsec = totalsec;
325 if (muonstartsec>=0 && max >= defmax) {
326 // 無音が300(defmuon)msより大きい
327 if (totalsec - muonstartsec > defmuon){
329 m[mcnt].stsec = muonstartsec;
330 m[mcnt].edsec = totalsec;
331 m[mcnt].diffs = totalsec - kankaku;
335 dul = (totalsec-muonstartsec)/1000.0;
336 diffs = (totalsec-kankaku)/1000.0;
338 if ((diffs > 14.5) && (diffs < 15.5)) m[mcnt].cmflg=1;
339 if ((diffs > 29.5) && (diffs < 30.5)) m[mcnt].cmflg=1;
340 if ((diffs > 59.5) && (diffs < 60.5)) m[mcnt].cmflg=1;
355 if ((m[0].cmflg==0) && (m[0].diffs < 15000))
358 for(i=1;i<mcnt-1;i++) {
359 // 本編で31秒以下が連続だったら、次の31秒以上の本編もしくはCMまでの時間をチェック
360 if (m[i].cmflg==0 && m[i].diffs < 31000 && m[i+1].cmflg==0 && m[i+1].diffs < 31000) {
362 for(j=i;j<mcnt;j++) {
363 if (m[j].cmflg==1) break;
364 if (m[j].diffs > 31000) break;
365 cmwork = cmwork + m[j].diffs;
367 //合計時間を15秒で割ってcm時間っぽいならばCMとする。
368 // TODO 30(15)秒以下の条件付けがいる?60秒どうする?
369 if (cmwork%15000>14500 || cmwork%15000<500) {
370 for(j=i;j<mcnt;j++) {
371 if (m[j].cmflg==1) break;
372 if (m[j].diffs > 31000) break;
380 if ((m[mcnt-1].cmflg==0) && (m[mcnt-1].diffs < 15000))
383 for(i=1;i<mcnt-1;i++) {
384 //本編で46秒以下かつ、前後がCMの場合CM14-16,29-31,44-46秒でもCMとする。
385 if (m[i].cmflg==0 && m[i].diffs < 46000 && m[i-1].cmflg==1 && m[i+1].cmflg==1) {
386 if ((m[i].diffs > 14000) && (m[i].diffs < 16000)) m[i].cmflg=1;
387 if ((m[i].diffs > 29000) && (m[i].diffs < 31000)) m[i].cmflg=1;
388 if ((m[i].diffs > 44000) && (m[i].diffs < 46000)) m[i].cmflg=1;
389 // 0.9秒以下(おそらく前後CMのあまり時間)
390 if (m[i].diffs < 900) m[i].cmflg=1;
392 //10,5秒のときは提供とみなし、その前を本編にする。
394 if ((m[i].diffs > 9500) && (m[i].diffs < 10500)) m[i-1].cmflg=0;
395 if ((m[i].diffs > 4500) && (m[i].diffs < 5500)) m[i-1].cmflg=0;
397 // TODO 前後が本編で単独でCMの場合は本編とする?
399 // if (m[i].cmflg==1 && m[i-1].cmflg==0 && m[i+1].cmflg==0) {
405 return dumpinfo(mcnt);
408 int main(int argc, char *argv[])
411 extern int optind, opterr;
418 while ((ch = getopt(argc, argv, "adb:m:v:")) != -1){
430 defmuon=atoi(optarg);
446 if (tmpenv=getenv("FFMPEG")) FFMPEGCMD=tmpenv;
447 if (tmpenv=getenv("SOX")) SOXCMD=tmpenv;
448 if (tmpenv=getenv("MP4BOX")) MP4BOXCMD=tmpenv;
449 if (tmpenv=getenv("MP4BOXCMDRAPSTR")) MP4BOXCMDRAPSTR=tmpenv;
450 if (tmpenv=getenv("AACENC")) AACENCCMD=tmpenv;
454 if (strcmp(argv[0],"-")==0)
457 f = fopen(argv[0],"rb");
459 p = checkMP4(f,argv[0]);
465 if (p) ret = cmcheckwave(p);
466 else ret = cmcheckwave(f);
467 // -1 のときはテキストとして再チェック
468 if (ret == -1) rechecktext(f);