Initial revision
[enigma2-plugins.git] / moviecut / src_cc / mcut.cc
1  /* Copyright (C) 2007, 2008 Anders Holst
2   *
3   * This program is free software; you can redistribute it and/or
4   * modify it under the terms of the GNU General Public License as
5   * published by the Free Software Foundation; either version 2, or
6   * (at your option) any later version.
7   * 
8   * This program is distributed in the hope that it will be useful,
9   * but WITHOUT ANY WARRANTY; without even the implied warranty of
10   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11   * GNU General Public License for more details.
12   * 
13   * You should have received a copy of the GNU General Public License
14   * along with this software; see the file COPYING.  If not, write to
15   * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16   * Boston, MA 02111-1307 USA
17   */
18
19 #define _LARGEFILE64_SOURCE
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <fcntl.h>
23 #include <unistd.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #define LEN 24064
29
30 static off64_t* buf0 = 0;
31 static off64_t* buf1 = 0;
32 static off64_t time_offset;
33 static off64_t size_offset;
34
35 int use_leadin = 1;
36 int use_leadout = 1;
37
38 inline int absless(long long int x, int lim)
39 {
40   return (x<lim && x>-lim);
41 }
42
43 double strtotime(char* str)
44 {
45   int i=0, t1, tt;
46   char *p1, *p2;
47   double tmp;
48   p1 = str;
49   tt = strtol(p1, &p2, 10);
50   if (p1==p2) return -1.0;
51   while (*p2 == ':' && i<2) {
52     i++;
53     if (p2-p1>2) return -1.0;
54     p1 = p2+1;
55     t1 = strtol(p1, &p2, 10);
56     if (p1==p2) return -1.0;
57     tt = 60*tt + t1;
58   }
59   if (i>0 && p2-p1>2) return -1.0;
60   if (*p2 == 0) return (double)tt;
61   if (*p2 != '.') return -1.0;
62   p1 = p2+1;
63   t1 = strtol(p1, &p2, 10);
64   for (i=0, tmp=1.0; i<(p2-p1); tmp*=0.1, i++);
65   return (double)tt + tmp*t1;
66 }
67
68 char* timetostr(double tm)
69 {
70   static char buf[15];
71   int r = (int)(tm/60);
72   sprintf(buf, "%d:%d:%.3f", r/60, r%60, tm-60*r);
73   return buf;
74 }
75
76 inline unsigned int byteswop(unsigned int n)
77 {
78   return ((n&0xff000000)>>24) | ((n&0xff0000)>>8) | ((n&0xff00)<<8) | ((n&0xff)<<24);
79 }
80
81 inline unsigned long long int byteswopl(unsigned long long int n)
82 {
83   return (n>>56) | ((n>>40)&0xff00) | ((n>>24)&0xff0000) | ((n>>8)&0xff000000) | ((n&0xff000000)<<8) | ((n&0xff0000)<<24) | ((n&0xff00)<<40) | ((n&0xff)<<56);
84 }
85
86 double inttotime(unsigned int t1, unsigned int t2)
87 {
88   return (byteswop(t2)*1.1111111111111112e-05 + byteswop(t1)*47721.858844444447);
89 }
90
91 double lltotime(long long int t)
92 {
93   return ((unsigned int)(t&0xffffffff)*1.1111111111111112e-05) + ((unsigned int)(t>>32)*47721.858844444447);
94 }
95
96 void timetoint(double tm, unsigned int& t1, unsigned int& t2)
97 {
98   double tmp=tm/47721.858844444447;
99   t1 = byteswop((unsigned int)tmp);
100   t2 = byteswop((unsigned int)((tm - t1*47721.858844444447)*90000));
101 }
102
103 int readbufinternal(int f)
104 {
105   off64_t* buf;
106   buf = buf0;
107   buf0 = buf1;
108   buf1 = buf;
109   if (read(f, buf, 16) != 16)
110     return 0;
111   buf[0] = (off64_t)byteswopl((unsigned long long int)buf[0]);
112   buf[1] = (off64_t)byteswopl((unsigned long long int)buf[1]);
113   return 1;
114 }
115
116 void writebufinternal(int f)
117 {
118   off64_t buf2[2];
119   buf2[0] = (off64_t)byteswopl((unsigned long long int)buf0[0] - size_offset);
120   buf2[1] = (off64_t)byteswopl((unsigned long long int)buf0[1]);
121   write(f, buf2, 16);
122 }
123
124 off64_t readoff(int f, int fo, double t, int beg, double& tr)
125 {
126   static off64_t lastreturn;
127   static double last;
128   static int endp;
129   off64_t sizetmp;
130   double tt, lt;
131   if (!buf0) {
132     buf0 = new off64_t[2];
133     buf1 = new off64_t[2];
134     if (!(readbufinternal(f) && readbufinternal(f))) {
135       printf("The corresponding \".ap\"-file is empty.\n");
136       exit(8);
137     }
138     time_offset = buf0[1];
139     if (buf1[1] > buf0[1] && buf1[1] - buf0[1] < 900000)
140       time_offset -= (buf1[1]-buf0[1])*buf0[0]/(buf1[0]-buf0[0]);
141     size_offset = buf0[0];
142     lastreturn = 0;
143     last = 0.0;
144     endp = 0;
145   }
146   if (t < last && t != -1.0) {
147     sizetmp = buf0[0];
148     lseek(f, 0, SEEK_SET);
149     readbufinternal(f);
150     readbufinternal(f);
151     time_offset = buf0[1];
152     if (buf1[1]>buf0[1] && buf1[1]-buf0[1]<900000)
153       time_offset -= (buf1[1]-buf0[1])*buf0[0]/(buf1[0]-buf0[0]);
154     size_offset += buf0[0] - sizetmp;
155     lastreturn = 0;
156     last = 0.0;
157     endp = 0;
158   }
159   if (t == last || endp == 1) {
160     return lastreturn;
161   }
162   if (!beg)
163     writebufinternal(fo);
164   last = t;
165   lt = lltotime(buf0[1] - time_offset);
166   tt = lltotime(buf1[1] - time_offset);
167   sizetmp = buf0[0];
168   while (tt < t || t == -1.0) {
169     if (!readbufinternal(f))
170       endp = 1;
171     if (!beg)
172       writebufinternal(fo);
173     if (endp)
174       break;
175     if (buf1[1] < buf0[1] || buf1[1] - buf0[1] > 900000) {
176       if (absless(buf1[1] + ((long long int)1)<<33 - buf0[1], 900000))
177         time_offset -= ((long long int)1)<<33;
178       else
179         time_offset += buf1[1] - buf0[1];
180     }
181     lt = tt;
182     tt = lltotime(buf1[1] - time_offset);
183   }
184   if (endp) {
185     tr = tt;
186   } else if (beg ? (lt == tt || (t-lt > tt-t && tt-t<0.18)) : (t-lt >= tt-t || t-lt>0.18)) {
187     if (!readbufinternal(f))
188       endp = 1;
189     if (!beg)
190       writebufinternal(fo);
191     tr = tt;
192   } else {
193     tr = lt;
194   }
195   if (beg)
196     size_offset += buf0[0] - sizetmp;
197   lastreturn = buf0[0];
198   return lastreturn;
199 }
200
201 int framepid(char* buf, int pos)
202 {
203   return ((buf[pos+1] & 0x1f) << 8) + buf[pos+2];
204 }
205
206 int framesearch_f(char* buf, int start, int stop, int pid)
207 {
208   char* p;
209   int pos = -1;
210   for (p = buf+start; p < buf+stop-3; p++)
211     if (p[0]==0 && p[1]==0 && p[2]==1 && p[3]==0) {
212         pos = ((p - buf)/188)*188;
213         if (pid == -1 || framepid(buf, pos) == pid)
214           return pos;
215     }
216   return -1;
217 }
218
219 int framesearch_b(char* buf, int start, int stop, int pid)
220 {
221   char* p;
222   int pos = -1;
223   for (p = buf+stop-1; p >= buf+start+3; p--)
224     if (p[0]==0 && p[-1]==1 && p[-2]==0 && p[-3]==0) {
225         pos = ((p - buf)/188)*188;
226         if (pid == -1 || framepid(buf, pos) == pid)
227           return pos;
228     }
229   return -1;
230 }
231
232 int transfer_start(int f_ts, int f_out, off64_t n1, off64_t& n1ret)
233 {
234   off64_t num;
235   int pos, tmp;
236   char buf[LEN];
237   if (use_leadin) {
238     num = 0;
239     tmp = 0;
240     do {
241       num += LEN;
242       if (num > n1)
243         tmp = LEN - (int)(num - n1), num = n1;
244       else
245         tmp = LEN;
246       lseek64(f_ts, n1 - num, SEEK_SET);
247       if (read(f_ts, buf, tmp) != tmp) return 1;
248     } while ((pos = framesearch_b(buf, 0, tmp, -1)) == -1 && num < n1);
249     if (pos != -1) {
250       if (write(f_out, buf+pos, tmp-pos) != tmp-pos) return 1;
251       n1ret = n1 - (num - pos);
252       size_offset -= (num - pos);
253       num -= tmp;
254       while (num > 0) {
255         if (read(f_ts, buf, LEN) != LEN) return 1;
256         if (write(f_out, buf, LEN) != LEN) return 1;
257         num -= LEN;
258       }
259     } else {
260       n1ret = n1;
261     }
262     return 0;
263   }
264   else {
265     lseek64(f_ts, n1, SEEK_SET);
266     n1ret = n1;
267     return 0;
268   }
269 }
270
271 int transfer_rest(int f_ts, int f_out, off64_t n1, off64_t n2, off64_t& n2ret)
272 {
273   off64_t i;
274   int num, pos, st, pid, tmp;
275   char buf[LEN];
276   static off64_t lastn2 = -1, lastn2ret;
277   if (n1 == lastn2) {
278     i = lastn2ret;
279     lseek64(f_ts, i, SEEK_SET);
280   } else
281     i = n1;
282   for (; i+LEN<=n2; i+=LEN) {
283     if (read(f_ts, buf, LEN) != LEN) return 1;
284     if (write(f_out, buf, LEN) != LEN) return 1;
285   }
286   if (use_leadout) {
287     num = read(f_ts, buf, LEN);
288     pid = framepid(buf, n2-i);
289     st = (i < n2 ? n2-i : 0);
290     tmp = -st;
291     st += 188;
292     while ((pos = framesearch_f(buf, st, num, pid)) == -1 && num == LEN) {
293       if (write(f_out, buf, LEN) != LEN) return 1;
294       num = read(f_ts, buf, LEN);
295       st = 0;
296       tmp += LEN;
297     }
298     if (st && num < st)
299       return 1;
300     else if (pos == -1) {
301       if (write(f_out, buf, num) != num) return 1;
302       tmp += num;
303       size_offset -= tmp;
304     } else {
305       if (write(f_out, buf, pos) != pos) return 1;
306       tmp += pos;
307       size_offset -= tmp;
308     }
309     lastn2 = n2;
310     lastn2ret = n2ret = n2 + tmp;
311     return 0;
312   } else {
313     if (i < n2) {
314       if (read(f_ts, buf, n2-i) != n2-i) return 1;
315       if (write(f_out, buf, n2-i) != n2-i) return 1;
316     }
317     lastn2 = lastn2ret = n2ret = n2;
318     return 0;
319   }
320 }
321
322 int donextinterval1(int fc, int fco, int fa, int fao, int fts, int ftso)
323 {
324   static int n = -1;
325   static double tlast, toff = 0.0;
326   static off64_t c2;
327   off64_t c1, c1ret, c2ret;
328   double ttmp;
329   unsigned int buf[3];
330   unsigned int tmp, lcheck=0;
331   if (n==0)
332     return 0;
333   else if (n==-1) {
334     n = lseek(fc, 0, SEEK_END) / 12;
335     lseek(fc, 0, SEEK_SET);
336     while (1) {
337       if (n == 0)
338         return 0;
339       read(fc, buf, 12);
340       n--;
341       tmp = byteswop(buf[2]);
342       if (tmp == 1) {
343         c1 = readoff(fa, fao, 0.0, 1, toff);
344         if (transfer_start(fts, ftso, c1, c1ret)) return -1;
345         c2 = readoff(fa, fao, inttotime(buf[0], buf[1]), 0, tlast);
346         if (transfer_rest(fts, ftso, c1, c2, c2ret)) return -1;
347         printf("Interval: %lld - %lld\n", c1ret, c2ret);
348         // move all passed marks
349         lseek(fc, 0, SEEK_SET);
350         read(fc, buf, 12);
351         while (byteswop(buf[2]) != 1) {
352           write(fco, buf, 12);
353           read(fc, buf, 12);
354         }
355         return 1;
356       } else if (tmp == 0) {
357         c1 = readoff(fa, fao, inttotime(buf[0], buf[1]), 1, toff);
358         if (transfer_start(fts, ftso, c1, c1ret)) return -1;
359         if (lcheck) {
360           buf[0] = buf[1] = 0;
361           write(fco, buf, 12);
362         }
363         break;
364       } else if (tmp == 3)
365         lcheck = 1;
366     }
367   } else {
368     while (1) {
369       read(fc, buf, 12);
370       n--;
371       tmp = byteswop(buf[2]);
372       if (tmp == 0) {
373         c1 = readoff(fa, fao, inttotime(buf[0], buf[1]), 1, ttmp);
374         if (c1 != c2)
375           if (transfer_start(fts, ftso, c1, c1ret)) return -1;
376         toff += ttmp - tlast;
377         break;
378       } else if (tmp == 3) {
379         timetoint(tlast-toff, buf[0], buf[1]);
380         write(fco, buf, 12);
381       }
382       if (n == 0)
383         return 0;
384     }
385   }
386   while (1) {
387     if (n == 0) {
388       c2 = readoff(fa, fao, -1.0, 0, tlast);
389       if (transfer_rest(fts, ftso, c1, c2, c2ret)) return -1;
390       printf("Interval: %lld - %lld\n", c1ret, c2ret);
391       return 1;
392     }
393     read(fc, buf, 12);
394     n--;
395     tmp = byteswop(buf[2]);
396     if (tmp == 1) {
397       c2 = readoff(fa, fao, inttotime(buf[0], buf[1]), 0, tlast);
398       if (transfer_rest(fts, ftso, c1, c2, c2ret)) return -1;
399       printf("Interval: %lld - %lld\n", c1ret, c2ret);
400       return 1;
401     } else if (tmp != 0) {
402       timetoint(inttotime(buf[0], buf[1])-toff, buf[0], buf[1]);
403       write(fco, buf, 12);
404     }
405   }
406   return 0;
407 }
408
409 int donextinterval2(int barg, int earg, char* argv[], int fc, int fco, int fa, int fao, int fts, int ftso)
410 {
411   static int n = -1, i, lio = -1, lcheck=0;
412   static double tlast = 0.0, toff = 0.0;
413   static off64_t c2 = -1;
414   off64_t c1, c1ret, c2ret;
415   double ttmp, ttmp2;
416   int j, io = -1;
417   unsigned int buf[3];
418   unsigned int buff[3];
419   unsigned int tmp;
420   if (i>=earg) {
421     if (!lcheck && n!=-1) {
422       lseek(fc, 0, SEEK_SET);
423       for (j=0; j<n; j++) {
424         read(fc, buf, 12);
425         tmp = byteswop(buf[2]);
426         if (tmp == 3) {
427           timetoint(tlast-toff, buf[0], buf[1]);
428           write(fco, buf, 12);
429           break;
430         }
431       }
432     }
433     if (lio != -1) {  // Add an extra "out" at the end to avoid bug in playback
434       buff[2] = byteswop(1);
435       timetoint(tlast-toff, buff[0], buff[1]);
436       write(fco, buff, 12);
437     }
438     return 0;
439   }
440   if (n==-1) {
441     i = barg;
442     n = lseek(fc, 0, SEEK_END) / 12;
443   }
444   c1 = readoff(fa, fao, strtotime(argv[i]), 1, ttmp);
445   if (c1 != c2)
446     if (transfer_start(fts, ftso, c1, c1ret)) return -1;
447   toff += ttmp - tlast;
448   c2 = readoff(fa, fao, strtotime(argv[i+1]), 0, tlast);
449   if (transfer_rest(fts, ftso, c1, c2, c2ret)) return -1;
450   printf("Interval: %lld - %lld\n", c1ret, c2ret);
451   lseek(fc, 0, SEEK_SET);
452   for (j=0; j<n; j++) {
453     read(fc, buf, 12);
454     tmp = byteswop(buf[2]);
455     ttmp2=inttotime(buf[0], buf[1]);
456     if (tmp == 3) {
457       if (!lcheck) {
458         if (ttmp2 <= ttmp) {
459           timetoint(ttmp-toff, buf[0], buf[1]);
460           write(fco, buf, 12);
461           lcheck = 1;
462         } else if (ttmp2 <= tlast) {
463           timetoint(ttmp2-toff, buf[0], buf[1]);
464           write(fco, buf, 12);
465           lcheck = 1;
466         }
467       }
468     } else if (ttmp2 >= ttmp && ttmp2 <= tlast) {
469       if (tmp < 2) {
470         if (lio != io && lio != -1) {
471           buff[2] = byteswop(io);
472           timetoint(ttmp-toff, buff[0], buff[1]);
473           write(fco, buff, 12);
474         }
475         lio = io = tmp;
476       }
477       timetoint(ttmp2-toff, buf[0], buf[1]);
478       write(fco, buf, 12);
479     } else if (tmp < 2) {
480       io = tmp;
481     }
482   }
483   i+=2;
484   return 1;
485 }
486
487 char* makefilename(const char* base, const char* pre, const char* ext, const char* post)
488 {
489   static char buf[256];
490   int len1, len2, len3;
491   len1 = strlen(base);
492   len2 = (pre ? strlen(pre) : 0);
493   len3 = (ext ? strlen(ext) : 0);
494   strcpy(buf, base);
495   if (ext && len1>=len3 && !strcmp(base+len1-len3,ext))
496     len1 -= len3;
497   if (pre)
498     strcpy(buf+len1, pre);
499   if (ext)
500     strcpy(buf+len1+len2, ext);
501   if (post)
502     strcpy(buf+len1+len2+len3, post);
503   return buf;
504 }
505
506 void copymeta(int n, int f1, int f2, const char* title, const char* suff, const char* descr)
507
508   int i, j, k;
509   char* buf = new char[n];
510   read(f1, buf, n);
511   for (i=0; i<n; i++)
512     if (buf[i] == 10)
513       break;
514   write(f2, buf, i);
515   if (i == n) return;
516   for (j=i+1; j<n; j++)
517     if (buf[j] == 10)
518       break;
519   if (title) {
520     write(f2, buf+i, 1);
521     for (k=0; title[k] && title[k] != 10; k++);
522     write(f2, title, k);
523   } else {
524     write(f2, buf+i, j-i);
525     if (suff && j-i>1)
526       write(f2, suff, strlen(suff));
527   }
528   if (j == n) return;
529   i = j;
530   for (j=i+1; j<n; j++)
531     if (buf[j] == 10)
532       break;
533   if (descr) {
534     write(f2, buf+i, 1);
535     for (k=0; descr[k] && descr[k] != 10; k++);
536     write(f2, descr, k);
537   } else {
538     write(f2, buf+i, j-i);
539   }
540   if (j < n)
541     write(f2, buf+j, n-j);
542   delete [] buf;
543 }
544
545 int main(int argc, char* argv[])
546 {
547   int f_ts, f_out, f_cuts, f_cutsout, f_ap, f_apout, f_meta, f_metaout;
548   char* tmpname;
549   const char* suff = 0;
550   char* inname = 0;
551   char* outname = 0;
552   char* title = 0;
553   char* descr = 0;
554   int cutarg = 0, cutargend = 0;
555   int replace = 0;
556   int i, j, ok, bad = 0;
557   double t1, t2;
558   struct stat statbuf;
559   struct stat64 statbuf64;
560
561   for (i=1; i<argc; i++) {
562     if (!strcmp(argv[i], "-r"))
563       replace = 1;
564     else if (!strcmp(argv[i], "-o")) {
565       if (i == argc-1) {
566         bad = 1;
567         break;
568       }
569       outname = argv[++i];
570     } else if (!strcmp(argv[i], "-n")) {
571       if (i == argc-1) {
572         bad = 1;
573         break;
574       }
575       title = argv[++i];
576     } else if (!strcmp(argv[i], "-d")) {
577       if (i == argc-1) {
578         bad = 1;
579         break;
580       }
581       descr = argv[++i];
582     } else if (!strcmp(argv[i], "-c")) {
583       cutarg = ++i;
584       for (j=i; j<argc; j+=2) {
585         t1 = strtotime(argv[j]);
586         t2 = (j+1<argc ? strtotime(argv[j+1]) : -1.0);
587         if (t1 < 0 || t2 < 0)
588           break;
589         else if (t1 > t2) {
590           printf("Bad time interval: %s - %s\n", argv[j], argv[j+1]);
591           bad = 1;
592           break;
593         }
594       }
595       cutargend = i = j;
596       if (bad)
597         break;
598     } else if (*argv[i] == '-' && (*(argv[i]+1) == 0 ||*(argv[i]+2) == 0)) {
599       bad = 1;
600       break;
601     } else if (!inname)
602       inname = argv[i];
603     else {
604       bad = 1;
605       break;
606     }
607   }
608   if (argc == 1 || bad) {
609     printf("Usage: mcut [-r] [-o output_ts_file] [-n title] [-d description] ts_file [-c start1 end1 [start2 end2] ... ]\n");
610     printf("   -r : Replace (= remove) the original movie.\n");
611     printf("   -o : Filename of resulting movie (defaults to the original name appended by \" cut\", unless -r is given).\n");
612     printf("   -n : Title of resulting movie.\n");
613     printf("   -d : Description of resulting movie.\n");
614     printf("   -c : A sequence of starttime and endtime pairs. Each time is given as hour:min:sec. The portion between start and end is retained (i.e. not cut away).\n");
615     exit(1);
616   }
617   if (outname) {
618     suff = 0;
619   } else {
620     outname = inname;
621     suff = (replace ? "_" : " cut");
622   }
623   tmpname = makefilename(inname, 0, ".ts", 0);
624   f_ts = open(tmpname, O_RDONLY | O_LARGEFILE);
625   if (f_ts == -1) {
626     printf("Failed to open input stream file \"%s\"\n", tmpname);
627     exit(2);
628   }
629   tmpname = makefilename(inname, 0, ".ts", ".cuts");
630   f_cuts = open(tmpname, O_RDONLY);
631   if (f_cuts == -1) {
632     printf("Failed to open input cuts file \"%s\"\n", tmpname);
633     close(f_ts);
634     exit(3);
635   }
636   tmpname = makefilename(inname, 0, ".ts", ".ap");
637   f_ap = open(tmpname, O_RDONLY);
638   if (f_ap == -1) {
639     printf("Failed to open input ap file \"%s\"\n", tmpname);
640     close(f_ts);
641     close(f_cuts);
642     exit(4);
643   }
644   if (fstat64(f_ts, &statbuf64)) {
645     printf("Failed to stat input stream file.\n");
646     close(f_ts);
647     close(f_cuts);
648     close(f_ap);
649     exit(2);
650   }
651   tmpname = makefilename(outname, suff, ".ts", 0);
652   f_out = open(tmpname, O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, statbuf64.st_mode & 0xfff);
653   if (f_out == -1) {
654     printf("Failed to open output stream file \"%s\"\n", tmpname);
655     close(f_ts);
656     close(f_cuts);
657     close(f_ap);
658     exit(5);
659   }
660   if (fstat(f_cuts, &statbuf)) {
661     printf("Failed to stat input cuts file.\n");
662     close(f_ts);
663     close(f_cuts);
664     close(f_ap);
665     close(f_out);
666     unlink(makefilename(outname, suff, ".ts", 0));
667     exit(3);
668   }
669   tmpname = makefilename(outname, suff, ".ts", ".cuts");
670   f_cutsout = open(tmpname, O_WRONLY | O_CREAT | O_TRUNC, statbuf.st_mode & 0xfff);
671   if (f_cutsout == -1) {
672     printf("Failed to open output cuts file \"%s\"\n", tmpname);
673     close(f_ts);
674     close(f_cuts);
675     close(f_ap);
676     close(f_out);
677     unlink(makefilename(outname, suff, ".ts", 0));
678     exit(6);
679   }
680   if (fstat(f_ap, &statbuf)) {
681     printf("Failed to stat input ap file.\n");
682     close(f_ts);
683     close(f_cuts);
684     close(f_ap);
685     close(f_out);
686     close(f_cutsout);
687     unlink(makefilename(outname, suff, ".ts", 0));
688     unlink(makefilename(outname, suff, ".ts", ".cuts"));
689     exit(4);
690   }
691   tmpname = makefilename(outname, suff, ".ts", ".ap");
692   f_apout = open(tmpname, O_WRONLY | O_CREAT | O_TRUNC, statbuf.st_mode & 0xfff);
693   if (f_apout == -1) {
694     printf("Failed to open output ap file \"%s\"\n", tmpname);
695     close(f_ts);
696     close(f_cuts);
697     close(f_ap);
698     close(f_out);
699     close(f_cutsout);
700     unlink(makefilename(outname, suff, ".ts", 0));
701     unlink(makefilename(outname, suff, ".ts", ".cuts"));
702     exit(7);
703   }
704
705   if (cutarg)
706     ok = donextinterval2(cutarg, cutargend, argv, f_cuts, f_cutsout, f_ap, f_apout, f_ts, f_out);
707   else
708     ok = donextinterval1(f_cuts, f_cutsout, f_ap, f_apout, f_ts, f_out);
709   if (!ok) {
710     printf("There are no cuts specified. Leaving the movie as it is.\n");
711     close(f_ts);
712     close(f_cuts);
713     close(f_ap);
714     close(f_out);
715     close(f_cutsout);
716     close(f_apout);
717     unlink(makefilename(outname, suff, ".ts", 0));
718     unlink(makefilename(outname, suff, ".ts", ".cuts"));
719     unlink(makefilename(outname, suff, ".ts", ".ap"));
720     exit(9);
721   }
722
723   while (ok > 0) {
724     if (cutarg)
725       ok = donextinterval2(cutarg, cutargend, argv, f_cuts, f_cutsout, f_ap, f_apout, f_ts, f_out);
726     else
727       ok = donextinterval1(f_cuts, f_cutsout, f_ap, f_apout, f_ts, f_out);
728   }
729
730   close(f_ts);
731   close(f_cuts);
732   close(f_ap);
733   close(f_out);
734   close(f_cutsout);
735   close(f_apout);
736   if (ok < 0) {
737     printf("Copying %s failed, read/write error.\n", makefilename(inname, 0, ".ts", 0));
738     unlink(makefilename(outname, suff, ".ts", 0));
739     unlink(makefilename(outname, suff, ".ts", ".cuts"));
740     unlink(makefilename(outname, suff, ".ts", ".ap"));
741     exit(10);
742   }
743
744   tmpname = makefilename(inname, 0, ".ts", ".meta");
745   f_meta = open(tmpname, O_RDONLY);
746   if (f_meta == -1) {
747     printf("Failed to open input meta file \"%s\"\n", tmpname);
748     exit(0);
749   }
750   if (fstat(f_meta, &statbuf)) {
751     printf("Failed to stat input meta file.\n");
752     close(f_meta);
753     exit(0);
754   }
755   tmpname = makefilename(outname, suff, ".ts", ".meta");
756   f_metaout = open(tmpname, O_WRONLY | O_CREAT | O_TRUNC, statbuf.st_mode & 0xfff);
757   if (f_metaout == -1) {
758     printf("Failed to open output meta file \"%s\"\n", tmpname);
759     close(f_meta);
760     exit(0);
761   }
762   copymeta((int)statbuf.st_size, f_meta, f_metaout, title, (replace ? 0 : suff), descr);
763   close(f_meta);
764   close(f_metaout);
765
766   if (replace) {
767     if (suff) {
768       tmpname = makefilename(inname, 0, ".ts", 0);
769       tmpname = strcpy(new char[strlen(tmpname)+1], tmpname);
770       unlink(tmpname);
771       rename(makefilename(outname, suff, ".ts", 0), tmpname);
772       tmpname = makefilename(inname, 0, ".ts", ".cuts");
773       tmpname = strcpy(new char[strlen(tmpname)+1], tmpname);
774       unlink(tmpname);
775       rename(makefilename(outname, suff, ".ts", ".cuts"), tmpname);
776       tmpname = makefilename(inname, 0, ".ts", ".ap");
777       tmpname = strcpy(new char[strlen(tmpname)+1], tmpname);
778       unlink(tmpname);
779       rename(makefilename(outname, suff, ".ts", ".ap"), tmpname);
780       tmpname = makefilename(inname, 0, ".ts", ".meta");
781       tmpname = strcpy(new char[strlen(tmpname)+1], tmpname);
782       unlink(tmpname);
783       rename(makefilename(outname, suff, ".ts", ".meta"), tmpname);
784     } else {
785       unlink(makefilename(inname, 0, ".ts", 0));
786       unlink(makefilename(inname, 0, ".ts", ".cuts"));
787       unlink(makefilename(inname, 0, ".ts", ".ap"));
788       unlink(makefilename(inname, 0, ".ts", ".meta"));
789     }
790   }
791 }
792