[EasyMedia] Change key_info-source to key_pvr
[enigma2-plugins.git] / reconstructapsc / src_cc / reconstruct_apsc.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
26 #define LEN 24064
27
28
29 char* makefilename(const char* dir, const char* base, const char* ext, const char* post)
30 {
31   static char buf[256];
32   int len1, len2, len3;
33   len1 = (dir ? strlen(dir) : 0);
34   len2 = (base ? strlen(base) : 0);
35   len3 = (ext ? strlen(ext) : 0);
36   if (dir) {
37     strcpy(buf, dir);
38     if (buf[len1-1] != '/') {
39       buf[len1++] = '/';
40       buf[len1] = 0;
41     }
42   }
43   if (base)
44     strcpy(buf+len1, base);
45   if (ext && len2>=len3 && !strcmp(base+len2-len3,ext))
46     len2 -= len3;
47   if (ext)
48     strcpy(buf+len1+len2, ext);
49   if (post)
50     strcpy(buf+len1+len2+len3, post);
51   return buf;
52 }
53
54 int writebufinternal(int f, off64_t sz, off64_t tm)
55 {
56   off64_t buf[2];
57   buf[0] = (off64_t)bswap_64((unsigned long long int)sz);
58   buf[1] = (off64_t)bswap_64((unsigned long long int)tm);
59   if (write(f, buf, 16) != 16)
60     return 1;
61   else
62     return 0;
63 }
64
65 int framepid(unsigned char* buf, int pos)
66 {
67   return ((buf[pos+1] & 0x1f) << 8) + buf[pos+2];
68 }
69
70 off64_t framepts(unsigned char* buf, int pos)
71 {
72   int tmp = (buf[pos+3] & 0x20 ? pos+buf[pos+4]+5 : pos+4);
73   off64_t pts;
74   if (buf[pos+1] & 0x40 &&
75       buf[pos+3] & 0x10 &&
76       buf[tmp]==0 && buf[tmp+1]==0 && buf[tmp+2]==1 &&
77       buf[tmp+7] & 0x80) {
78     pts  = ((unsigned long long)(buf[tmp+9]&0xE))  << 29;
79     pts |= ((unsigned long long)(buf[tmp+10]&0xFF)) << 22;
80     pts |= ((unsigned long long)(buf[tmp+11]&0xFE)) << 14;
81     pts |= ((unsigned long long)(buf[tmp+12]&0xFF)) << 7;
82     pts |= ((unsigned long long)(buf[tmp+13]&0xFE)) >> 1;
83   } else
84     pts = -1;
85   return pts;
86 }
87
88 int framesearch(int fts, int first, off64_t& retpos, off64_t& retpts, off64_t& retpos2, off64_t& retdat)
89 {
90   static unsigned char buf[LEN];
91   static int ind;
92   static off64_t pos = -1;
93   static off64_t num;
94   static int pid = -1;
95   static int st = 0;
96   static int sdflag = 0;
97   unsigned char* p;
98   if (pos == -1 || first) {
99     num = read(fts, buf, LEN);
100     ind = 0;
101     pos = 0;
102     st = 0;
103     sdflag = 0;
104     pid = -1;
105   }
106   while (1) {
107     p = buf+ind+st;
108     ind = -1;
109     for (; p < buf+num-6; p++)
110       if (p[0]==0 && p[1]==0 && p[2]==1) {
111         ind = ((p - buf)/188)*188;
112         if ((p[3] & 0xf0) == 0xe0 && (buf[ind+1] & 0x40) &&
113             (p-buf)-ind == (buf[ind+3] & 0x20 ? buf[ind+4] + 5 : 4)) {
114           pid = framepid(buf, ind);
115         } else if (pid != -1 && pid != framepid(buf, ind)) {
116           ind = -1;
117           continue;
118         }
119         if (p[3]==0 || p[3]==0xb3 || p[3]==0xb8) { // MPEG2
120           if (p[3]==0xb3) {
121             retpts = framepts(buf, ind);
122             retpos = pos + ind;
123           } else {
124             retpts = -1;
125             retpos = -1;
126           }
127           retdat = (unsigned int) p[3] | (p[4]<<8) | (p[5]<<16) | (p[6]<<24);
128           retpos2 = pos + (p - buf);
129           st = (p - buf) - ind + 1;
130           sdflag = 1;
131           return 1; 
132         } else if (!sdflag && p[3]==0x09 && (buf[ind+1] & 0x40)) { // H264
133           if ((p[4] >> 5)==0) {
134             retpts = framepts(buf, ind);
135             retpos = pos + ind;
136           } else {
137             retpts = -1;
138             retpos = -1;
139           }
140           retdat = p[3] | (p[4]<<8);
141           retpos2 = pos + (p - buf);
142           st = (p - buf) - ind + 1;
143           return 1; 
144         } else {
145           ind = -1;
146           continue;
147         }
148       }
149     st = 0;
150     sdflag = 0; // reset to get some fault tolerance
151     if (num == LEN) {
152       pos += num;
153       num = read(fts, buf, LEN);
154       ind = 0;
155     } else if (num) {
156       ind = num;
157       retpts = 0;
158       retdat = 0;
159       retpos = pos + num;
160       num = 0;
161       return -1;
162     } else {
163       retpts = 0;
164       retdat = 0;
165       retpos = 0;
166       return -1;
167     }
168   }
169 }
170
171 int do_one(int fts, int fap, int fsc)
172 {
173   off64_t pos;
174   off64_t pos2;
175   off64_t pts;
176   off64_t dat;
177   int first = 1;
178   while (framesearch(fts, first, pos, pts, pos2, dat) >= 0) {
179     first = 0;
180     if (pos >= 0 && pts >= 0)
181       if (fap >= 0 && writebufinternal(fap, pos, pts))
182         return 1;
183     if (fsc >= 0 && writebufinternal(fsc, pos2, dat))
184       return 1;
185   }
186   return 0;
187 }
188
189 int do_movie(char* inname)
190 {
191   int f_ts=-1, f_sc=-1, f_ap=-1, f_tmp=-1;
192   char* tmpname;
193   tmpname = makefilename(0, inname, ".ts", 0);
194   f_ts = open(tmpname, O_RDONLY | O_LARGEFILE);
195   if (f_ts == -1) {
196     printf("Failed to open input stream file \"%s\"\n", tmpname);
197     return 1;
198   }
199   tmpname = makefilename(0, inname, ".ts", ".reconstruct_apsc");
200   f_tmp = open(tmpname, O_WRONLY | O_CREAT | O_TRUNC, 0x1a4);
201   if (f_tmp == -1) {
202     printf("Failed to open sentry file \"%s\"\n", tmpname);
203     goto failure;
204   }
205   close(f_tmp);
206   tmpname = makefilename(0, inname, ".ts", ".ap");
207   f_ap = open(tmpname, O_WRONLY | O_CREAT | O_TRUNC, 0x1a4);
208   if (f_ap == -1) {
209     printf("Failed to open output .ap file \"%s\"\n", tmpname);
210     goto failure;
211   }
212   tmpname = makefilename(0, inname, ".ts", ".sc");
213   f_sc = open(tmpname, O_WRONLY | O_CREAT | O_TRUNC, 0x1a4);
214   if (f_sc == -1) {
215     printf("Failed to open output .sc file \"%s\"\n", tmpname);
216     goto failure;
217   }
218
219   printf("  Processing .ap and .sc of \"%s\" ... ", inname);
220   fflush(stdout);
221   if (do_one(f_ts, f_ap, f_sc)) {
222     printf("\nFailed to reconstruct files for \"%s\"\n", inname);
223     goto failure;
224   }
225   printf("done\n");
226
227   close(f_ts);
228   close(f_ap);
229   close(f_sc);
230   unlink(makefilename(0, inname, ".ts", ".reconstruct_apsc"));
231   return 0;
232  failure:
233   if (f_ts != -1)
234     close(f_ts);
235   if (f_ap != -1) {
236     close(f_ap);
237     unlink(makefilename(0, inname, ".ts", ".ap"));
238   }
239   if (f_sc != -1) {
240     close(f_sc);
241     unlink(makefilename(0, inname, ".ts", ".sc"));
242   }
243   unlink(makefilename(0, inname, ".ts", ".reconstruct_apsc"));
244   return 1;
245 }
246
247 int do_directory(char* dirname)
248 {
249   int f_ts, f_sc, f_ap, f_tmp;
250   int do_ap, do_sc;
251   char *inname, *tmpname;
252   DIR* dir = opendir(dirname);
253   dirent* entry;
254   struct stat statbuf;
255   if (dir) {
256     while ((entry = readdir(dir))) {
257       inname = entry->d_name;
258       if (strlen(inname) > 3 && !strcmp(inname + strlen(inname) - 3, ".ts")) {
259         tmpname = makefilename(dirname, inname, ".ts", ".reconstruct_apsc");
260         errno = 0;
261         if (stat(tmpname, &statbuf) != -1)
262           do_ap = do_sc = 1;
263         else {
264           tmpname = makefilename(dirname, inname, ".ts", ".ap");
265           errno = 0;
266           do_ap = (stat(tmpname, &statbuf) == -1 && errno == ENOENT);
267           tmpname = makefilename(dirname, inname, ".ts", ".sc");
268           errno = 0;
269           do_sc = (stat(tmpname, &statbuf) == -1 && errno == ENOENT);
270         }
271         if (do_ap || do_sc) {
272           f_ts=-1, f_sc=-1, f_ap=-1, f_tmp=-1;
273           tmpname = makefilename(dirname, inname, ".ts", 0);
274           f_ts = open(tmpname, O_RDONLY | O_LARGEFILE);
275           if (f_ts == -1) {
276             printf("Failed to open input stream file \"%s\"\n", tmpname);
277             continue;
278           }
279           tmpname = makefilename(dirname, inname, ".ts", ".reconstruct_apsc");
280           f_tmp = open(tmpname, O_WRONLY | O_CREAT | O_TRUNC, 0x1a4);
281           if (f_tmp == -1) {
282             printf("Failed to open sentry file \"%s\"\n", tmpname);
283             goto failure;
284           }
285           close(f_tmp);
286           if (do_ap) {
287             tmpname = makefilename(dirname, inname, ".ts", ".ap");
288             f_ap = open(tmpname, O_WRONLY | O_CREAT | O_TRUNC, 0x1a4);
289             if (f_ap == -1) {
290               printf("Failed to open output .ap file \"%s\"\n", tmpname);
291               goto failure;
292             }
293           } else
294             f_ap = -1;
295           if (do_sc) {
296             tmpname = makefilename(dirname, inname, ".ts", ".sc");
297             f_sc = open(tmpname, O_WRONLY | O_CREAT | O_TRUNC, 0x1a4);
298             if (f_sc == -1) {
299               printf("Failed to open output .sc file \"%s\"\n", tmpname);
300               goto failure;
301             }
302           } else
303             f_sc = -1;
304
305           printf("  Processing %s of \"%s\" ... ", (do_ap ? (do_sc ? ".ap and .sc" : ".ap") : ".sc"), inname);
306           fflush(stdout);
307           if (do_one(f_ts, f_ap, f_sc)) {
308             printf("\nFailed to reconstruct files for \"%s\"\n", inname);
309             close(f_ts);
310             if (f_ap != -1) {
311               close(f_ap);
312               unlink(makefilename(dirname, inname, ".ts", ".ap"));
313             }
314             if (f_sc != -1) {
315               close(f_sc);
316               unlink(makefilename(dirname, inname, ".ts", ".sc"));
317             }
318             unlink(makefilename(dirname, inname, ".ts", ".reconstruct_apsc"));
319             continue;
320           }
321           printf("done\n");
322
323           close(f_ts);
324           close(f_ap);
325           close(f_sc);
326           unlink(makefilename(dirname, inname, ".ts", ".reconstruct_apsc"));
327         }
328       }
329     }
330     closedir(dir);
331   } else {
332     printf("Failed to open directory \"%s\"\n", dirname);
333     return 1;
334   }
335   return 0;
336  failure:
337   closedir(dir);
338   if (f_ts != -1)
339     close(f_ts);
340   if (f_ap != -1) {
341     close(f_ap);
342     unlink(makefilename(dirname, inname, ".ts", ".ap"));
343   }
344   if (f_sc != -1) {
345     close(f_sc);
346     unlink(makefilename(dirname, inname, ".ts", ".sc"));
347   }
348   unlink(makefilename(dirname, inname, ".ts", ".reconstruct_apsc"));
349   return 1;
350 }
351
352 int main(int argc, char* argv[])
353 {
354   if (argc == 2 && *argv[1] != '-') {
355     if (do_movie(argv[1]))
356       exit(1);
357   } else if (argc == 3 && !strcmp(argv[1], "-d")) {
358     if (do_directory(argv[2]))
359       exit(1);
360   } else {
361     printf("Usage: reconstruct_apsc movie_file\n");
362     printf("       reconstruct_apsc -d movie_directory\n");
363     exit(1);
364   }
365 }
366