Added createAPSC Files binary with progress output (modified version
[enigma2-plugins.git] / permanenttimeshift / src / createapscfiles / createapscfiles.cc
1  /* Copyright (C) 2009 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
14 #define _LARGEFILE64_SOURCE
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <fcntl.h>
18 #include <dirent.h>
19 #include <unistd.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <byteswap.h>
24 #include <errno.h>
25 #include <iostream>
26
27 #define LEN 24064
28
29 using namespace std;
30
31 char* makefilename(const char* dir, const char* base, const char* ext, const char* post)
32 {
33   static char buf[256];
34   int len1, len2, len3;
35   len1 = (dir ? strlen(dir) : 0);
36   len2 = (base ? strlen(base) : 0);
37   len3 = (ext ? strlen(ext) : 0);
38   if (dir) {
39     strcpy(buf, dir);
40     if (buf[len1-1] != '/') {
41       buf[len1++] = '/';
42       buf[len1] = 0;
43     }
44   }
45   if (base)
46     strcpy(buf+len1, base);
47   if (ext && len2>=len3 && !strcmp(base+len2-len3,ext))
48     len2 -= len3;
49   if (ext)
50     strcpy(buf+len1+len2, ext);
51   if (post)
52     strcpy(buf+len1+len2+len3, post);
53   return buf;
54 }
55
56 int writebufinternal(int f, off64_t sz, off64_t tm)
57 {
58   off64_t buf[2];
59   buf[0] = (off64_t)bswap_64((unsigned long long int)sz);
60   buf[1] = (off64_t)bswap_64((unsigned long long int)tm);
61   if (write(f, buf, 16) != 16)
62     return 1;
63   else
64     return 0;
65 }
66
67 int framepid(unsigned char* buf, int pos)
68 {
69   return ((buf[pos+1] & 0x1f) << 8) + buf[pos+2];
70 }
71
72 off64_t framepts(unsigned char* buf, int pos)
73 {
74   int tmp = (buf[pos+3] & 0x20 ? pos+buf[pos+4]+5 : pos+4);
75   off64_t pts;
76   if (buf[pos+1] & 0x40 &&
77       buf[pos+3] & 0x10 &&
78       buf[tmp]==0 && buf[tmp+1]==0 && buf[tmp+2]==1 &&
79       buf[tmp+7] & 0x80) {
80     pts  = ((unsigned long long)(buf[tmp+9]&0xE))  << 29;
81     pts |= ((unsigned long long)(buf[tmp+10]&0xFF)) << 22;
82     pts |= ((unsigned long long)(buf[tmp+11]&0xFE)) << 14;
83     pts |= ((unsigned long long)(buf[tmp+12]&0xFF)) << 7;
84     pts |= ((unsigned long long)(buf[tmp+13]&0xFE)) >> 1;
85   } else
86     pts = -1;
87   return pts;
88 }
89
90 int framesearch(int fts, int first, off64_t& retpos, off64_t& retpts, off64_t& retpos2, off64_t& retdat, int filesize)
91 {
92   static unsigned char buf[LEN];
93   static int ind;
94   static off64_t pos = -1;
95   static off64_t num;
96   static int pid = -1;
97   static int st = 0;
98   static double bytecount = 0;
99   static double progress = 0.00;
100   static int sdflag = 0;
101   unsigned char* p;
102   if (pos == -1 || first) {
103     num = read(fts, buf, LEN);
104     ind = 0;
105     pos = 0;
106     st = 0;
107     sdflag = 0;
108     pid = -1;
109   }
110   while (1) {
111     p = buf+ind+st;
112     ind = -1;
113     for (; p < buf+num-6; p++) {
114
115       bytecount = bytecount + 1;
116
117       if (p[0]==0 && p[1]==0 && p[2]==1) {
118         ind = ((p - buf)/188)*188;
119         if ((p[3] & 0xf0) == 0xe0 && (buf[ind+1] & 0x40) &&
120             (p-buf)-ind == (buf[ind+3] & 0x20 ? buf[ind+4] + 5 : 4)) {
121           pid = framepid(buf, ind);
122         } else if (pid != -1 && pid != framepid(buf, ind)) {
123           ind = -1;
124           continue;
125         }
126
127         if (p[3]==0 || p[3]==0xb3 || p[3]==0xb8) { // MPEG2
128           if (p[3]==0xb3) {
129             retpts = framepts(buf, ind);
130             retpos = pos + ind;
131           } else {
132             retpts = -1;
133             retpos = -1;
134           }
135           retdat = (unsigned int) p[3] | (p[4]<<8) | (p[5]<<16) | (p[6]<<24);
136           retpos2 = pos + (p - buf);
137           st = (p - buf) - ind + 1;
138           sdflag = 1;
139           return 1; 
140         } else if (!sdflag && p[3]==0x09 && (buf[ind+1] & 0x40)) { // H264
141           if ((p[4] >> 5)==0) {
142             retpts = framepts(buf, ind);
143             retpos = pos + ind;
144           } else {
145             retpts = -1;
146             retpos = -1;
147           }
148           retdat = p[3] | (p[4]<<8);
149           retpos2 = pos + (p - buf);
150           st = (p - buf) - ind + 1;
151           return 1; 
152         } else {
153           ind = -1;
154           continue;
155         }
156       }
157     }
158
159     progress = bytecount/filesize*100;
160     cout << "\rcreating ap&sc files: ";
161     cout.width(2);
162     cout << (int)progress << "%";
163
164     st = 0;
165     sdflag = 0; // reset to get some fault tolerance
166     if (num == LEN) {
167       pos += num;
168       num = read(fts, buf, LEN);
169       ind = 0;
170     } else if (num) {
171       ind = num;
172       retpts = 0;
173       retdat = 0;
174       retpos = pos + num;
175       num = 0;
176       return -1;
177     } else {
178       retpts = 0;
179       retdat = 0;
180       retpos = 0;
181       return -1;
182     }
183   }
184 }
185
186 int do_one(int fts, int fap, int fsc, int filesize)
187 {
188   off64_t pos;
189   off64_t pos2;
190   off64_t pts;
191   off64_t dat;
192   int first = 1;
193   while (framesearch(fts, first, pos, pts, pos2, dat, filesize) >= 0) {
194     first = 0;
195     if (pos >= 0 && pts >= 0)
196       if (fap >= 0 && writebufinternal(fap, pos, pts))
197         return 1;
198     if (fsc >= 0 && writebufinternal(fsc, pos2, dat))
199       return 1;
200   }
201   return 0;
202 }
203
204 int do_movie(char* inname)
205 {
206   int f_ts=-1, f_sc=-1, f_ap=-1, f_tmp=-1;
207   char* tmpname;
208   long filesize;
209   FILE *fp;
210   tmpname = makefilename(0, inname, ".ts", 0);
211   f_ts = open(tmpname, O_RDONLY | O_LARGEFILE);
212
213   if (f_ts == -1) {
214     printf("Failed to open input stream file \"%s\"\n", tmpname);
215     return 1;
216   }
217   tmpname = makefilename(0, inname, ".ts", ".reconstruct_apsc");
218   f_tmp = open(tmpname, O_WRONLY | O_CREAT | O_TRUNC, 0x1a4);
219   if (f_tmp == -1) {
220     printf("Failed to open sentry file \"%s\"\n", tmpname);
221     goto failure;
222   }
223   close(f_tmp);
224   tmpname = makefilename(0, inname, ".ts", ".ap");
225   f_ap = open(tmpname, O_WRONLY | O_CREAT | O_TRUNC, 0x1a4);
226   if (f_ap == -1) {
227     printf("Failed to open output .ap file \"%s\"\n", tmpname);
228     goto failure;
229   }
230   tmpname = makefilename(0, inname, ".ts", ".sc");
231   f_sc = open(tmpname, O_WRONLY | O_CREAT | O_TRUNC, 0x1a4);
232   if (f_sc == -1) {
233     printf("Failed to open output .sc file \"%s\"\n", tmpname);
234     goto failure;
235   }
236
237   //printf("  Processing .ap and .sc of \"%s\" ... ", inname);
238
239   fp=fopen(inname,"rb");
240   fseek(fp,0L,SEEK_END);
241   filesize=ftell(fp);
242   fclose(fp);
243
244   fflush(stdout);
245   if (do_one(f_ts, f_ap, f_sc, filesize)) {
246     printf("\nFailed to reconstruct files for \"%s\"\n", inname);
247     goto failure;
248   }
249
250   cout << "\rcreating ap&sc files: ";
251   cout.width(3);
252   cout << "100" << "%\n";
253
254   close(f_ts);
255   close(f_ap);
256   close(f_sc);
257   unlink(makefilename(0, inname, ".ts", ".reconstruct_apsc"));
258   return 0;
259  failure:
260   if (f_ts != -1)
261     close(f_ts);
262   if (f_ap != -1) {
263     close(f_ap);
264     unlink(makefilename(0, inname, ".ts", ".ap"));
265   }
266   if (f_sc != -1) {
267     close(f_sc);
268     unlink(makefilename(0, inname, ".ts", ".sc"));
269   }
270   unlink(makefilename(0, inname, ".ts", ".reconstruct_apsc"));
271   return 1;
272 }
273
274 int main(int argc, char* argv[])
275 {
276   if (argc == 2 && *argv[1] != '-') {
277     if (do_movie(argv[1]))
278       exit(1);
279   } else {
280     printf("Usage: reconstruct_apsc movie_file\n");
281     exit(1);
282   }
283 }
284