fix LCD in MoviePlayer
[enigma2.git] / lib / dvb / tstools.cpp
1 #include <lib/dvb/tstools.h>
2 #include <lib/base/eerror.h>
3 #include <unistd.h>
4 #include <fcntl.h>
5
6 #include <stdio.h>
7
8 eDVBTSTools::eDVBTSTools()
9 {
10         m_pid = -1;
11         m_maxrange = 256*1024;
12         
13         m_begin_valid = 0;
14         m_end_valid = 0;
15         
16         m_use_streaminfo = 0;
17         m_samples_taken = 0;
18 }
19
20 eDVBTSTools::~eDVBTSTools()
21 {
22         closeFile();
23 }
24
25 int eDVBTSTools::openFile(const char *filename)
26 {
27         closeFile();
28         
29         m_streaminfo.load((std::string(filename) + ".ap").c_str());
30         
31         if (!m_streaminfo.empty())
32                 m_use_streaminfo = 1;
33         else
34         {
35                 eDebug("no recorded stream information available");
36                 m_use_streaminfo = 0;
37         }
38         
39         m_samples_taken = 0;
40
41         if (m_file.open(filename) < 0)
42                 return -1;
43         return 0;
44 }
45
46 void eDVBTSTools::closeFile()
47 {
48         m_file.close();
49 }
50
51 void eDVBTSTools::setSyncPID(int pid)
52 {
53         m_pid = pid;
54 }
55
56 void eDVBTSTools::setSearchRange(int maxrange)
57 {
58         m_maxrange = maxrange;
59 }
60
61         /* getPTS extracts a pts value from any PID at a given offset. */
62 int eDVBTSTools::getPTS(off_t &offset, pts_t &pts, int fixed)
63 {
64         if (m_use_streaminfo)
65                 return m_streaminfo.getPTS(offset, pts);
66         
67         if (!m_file.valid() < 0)
68                 return -1;
69
70         offset -= offset % 188;
71         
72         if (m_file.lseek(offset, SEEK_SET) < 0)
73                 return -1;
74
75         int left = m_maxrange;
76         
77         while (left >= 188)
78         {
79                 unsigned char block[188];
80                 if (m_file.read(block, 188) != 188)
81                 {
82                         eDebug("read error");
83                         break;
84                 }
85                 left -= 188;
86                 offset += 188;
87                 
88                 if (block[0] != 0x47)
89                 {
90                         int i = 0;
91                         while (i < 188)
92                         {
93                                 if (block[i] == 0x47)
94                                         break;
95                                 ++i;
96                         }
97                         offset = m_file.lseek(i - 188, SEEK_CUR);
98                         continue;
99                 }
100                 
101                 int pid = ((block[1] << 8) | block[2]) & 0x1FFF;
102                 int pusi = !!(block[1] & 0x40);
103                 
104 //              printf("PID %04x, PUSI %d\n", pid, pusi);
105                 
106                 if (m_pid >= 0)
107                         if (pid != m_pid)
108                                 continue;
109                 if (!pusi)
110                         continue;
111                 
112                         /* ok, now we have a PES header */
113                 unsigned char *pes;
114                 
115                         /* check for adaption field */
116                 if (block[3] & 0x20)
117                         pes = block + block[4] + 4 + 1;
118                 else
119                         pes = block + 4;
120                 
121                         /* somehow not a startcode. (this is invalid, since pusi was set.) ignore it. */
122                 if (pes[0] || pes[1] || (pes[2] != 1))
123                         continue;
124                 
125                 if (pes[7] & 0x80) /* PTS */
126                 {
127                         pts  = ((unsigned long long)(pes[ 9]&0xE))  << 29;
128                         pts |= ((unsigned long long)(pes[10]&0xFF)) << 22;
129                         pts |= ((unsigned long long)(pes[11]&0xFE)) << 14;
130                         pts |= ((unsigned long long)(pes[12]&0xFF)) << 7;
131                         pts |= ((unsigned long long)(pes[13]&0xFE)) >> 1;
132                         offset -= 188;
133                         
134 //                      eDebug("found pts %08llx at %08llx", pts, offset);
135                         
136                                 /* convert to zero-based */
137                         if (fixed)
138                                 fixupPTS(offset, pts);
139                         return 0;
140                 }
141         }
142         
143         return -1;
144 }
145
146 int eDVBTSTools::fixupPTS(const off_t &offset, pts_t &now)
147 {
148         if (m_use_streaminfo)
149         {
150                 return m_streaminfo.fixupPTS(offset, now);
151         } else
152         {
153                         /* for the simple case, we assume one epoch, with up to one wrap around in the middle. */
154                 calcBegin();
155                 if (!m_begin_valid)
156                 {       
157                         eDebug("begin not valid, can't fixup");
158                         return -1;
159                 }
160                 
161                 pts_t pos = m_pts_begin;
162                 if ((now < pos) && ((pos - now) < 90000 * 10))
163                 {       
164                         pos = 0;
165                         return 0;
166                 }
167                 
168                 if (now < pos) /* wrap around */
169                         now = now + 0x200000000LL - pos;
170                 else
171                         now -= pos;
172                 return 0;
173         }
174 }
175
176 int eDVBTSTools::getOffset(off_t &offset, pts_t &pts)
177 {
178         if (m_use_streaminfo)
179         {
180                 offset = m_streaminfo.getAccessPoint(pts);
181                 return 0;
182         } else
183         {
184 //              eDebug("get offset");
185                 if (!m_samples_taken)
186                         takeSamples();
187                 
188                 if (m_samples.empty())
189                         return -1;
190                 
191 //              eDebug("ok, samples ok");
192                         /* search entry before and after */
193                 std::map<pts_t, off_t>::const_iterator l = m_samples.lower_bound(pts);
194                 std::map<pts_t, off_t>::const_iterator u = l;
195
196                 if (l != m_samples.begin())
197                         --l;
198                 
199                 int birate;
200                 if ((u == m_samples.end()) || (l == m_samples.end()))
201                         return -1;
202
203                 pts_t pts_diff = u->first - l->first;
204                 off_t offset_diff = u->second - l->second;
205 //              eDebug("using: %llx:%llx -> %llx:%llx", l->first, u->first, l->second, u->second);
206         
207                 if (!pts_diff)
208                         return -1;
209
210                 int bitrate = calcBitrate(); /* in bits/s */
211                 bitrate = offset_diff * 90000 * 8 / pts_diff;
212
213                 if (bitrate <= 0)
214                         return -1;
215                 
216                 offset = l->second;
217                 offset += ((pts - l->first) * (pts_t)bitrate) / 8ULL / 90000ULL;
218                 offset -= offset % 188;
219
220                 return 0;
221         }
222 }
223
224 int eDVBTSTools::getNextAccessPoint(pts_t &ts, const pts_t &start, int direction)
225 {
226         if (m_use_streaminfo)
227                 return m_streaminfo.getNextAccessPoint(ts, start, direction);
228         else
229         {
230                 eDebug("can't get next access point without streaminfo");
231                 return -1;
232         }
233 }
234
235 void eDVBTSTools::calcBegin()
236 {
237         if (!m_file.valid())
238                 return;
239
240         if (!m_begin_valid)
241         {
242                 m_offset_begin = 0;
243                 if (!getPTS(m_offset_begin, m_pts_begin))
244                         m_begin_valid = 1;
245         }
246 }
247
248 void eDVBTSTools::calcEnd()
249 {
250         if (!m_file.valid())
251                 return;
252         
253         off_t end = m_file.lseek(0, SEEK_END);
254         
255         if (abs(end - m_offset_end) > 1*1024*1024)
256         {
257                 m_offset_end = end;
258                 m_end_valid = 0;
259                 eDebug("file size changed, recalc length");
260         }
261         
262         int maxiter = 10;
263         
264         while (!m_end_valid)
265         {
266                 if (!--maxiter)
267                         return;
268                 
269                 m_offset_end -= m_maxrange;
270                 if (m_offset_end < 0)
271                         m_offset_end = 0;
272                 if (!getPTS(m_offset_end, m_pts_end))
273                         m_end_valid = 1;
274                 if (!m_offset_end)
275                         return;
276         }
277 }
278
279 int eDVBTSTools::calcLen(pts_t &len)
280 {
281         calcBegin(); calcEnd();
282         if (!(m_begin_valid && m_end_valid))
283                 return -1;
284         len = m_pts_end - m_pts_begin;
285                 /* wrap around? */
286         if (len < 0)
287                 len += 0x200000000LL;
288         return 0;
289 }
290
291 int eDVBTSTools::calcBitrate()
292 {
293         calcBegin(); calcEnd();
294         if (!(m_begin_valid && m_end_valid))
295                 return -1;
296
297         pts_t len_in_pts = m_pts_end - m_pts_begin;
298
299                 /* wrap around? */
300         if (len_in_pts < 0)
301                 len_in_pts += 0x200000000LL;
302         off_t len_in_bytes = m_offset_end - m_offset_begin;
303         
304         if (!len_in_pts)
305                 return -1;
306         
307         unsigned long long bitrate = len_in_bytes * 90000 * 8 / len_in_pts;
308         if ((bitrate < 10000) || (bitrate > 100000000))
309                 return -1;
310         
311         return bitrate;
312 }
313
314         /* pts, off */
315 void eDVBTSTools::takeSamples()
316 {
317         m_samples_taken = 1;
318         m_samples.clear();
319         pts_t dummy;
320         if (calcLen(dummy) == -1)
321                 return;
322         
323         int nr_samples = 30;
324         off_t bytes_per_sample = (m_offset_end - m_offset_begin) / (long long)nr_samples;
325         if (bytes_per_sample < 1*1024*1024)
326                 bytes_per_sample = 1*1024*1024;
327         
328         bytes_per_sample -= bytes_per_sample % 188;
329         
330         for (off_t offset = m_offset_begin; offset < m_offset_end; offset += bytes_per_sample)
331         {
332                 off_t o = offset;
333                 pts_t p;
334                 if (!eDVBTSTools::getPTS(o, p, 1))
335                 {
336 //                      eDebug("sample: %llx, %llx", o, p);
337                         m_samples[p] = o;
338                 }
339         }
340         m_samples[m_pts_begin] = m_offset_begin;
341         m_samples[m_pts_end] = m_offset_end;
342 //      eDebug("begin, end: %llx %llx", m_offset_begin, m_offset_end); 
343 }