51cc994c560758c9b4480e34423e6e48798b643c
[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_fd = -1;
11         m_pid = -1;
12         m_maxrange = 256*1024;
13         
14         m_begin_valid = 0;
15         m_end_valid = 0;
16         
17         m_use_streaminfo = 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_fd = ::open(filename, O_RDONLY);
40         if (m_fd < 0)
41                 return -1;
42         return 0;
43 }
44
45 void eDVBTSTools::closeFile()
46 {
47         if (m_fd >= 0)
48                 ::close(m_fd);
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_fd < 0)
68                 return -1;
69
70         offset -= offset % 188;
71         
72                 // TODO: multiple files!        
73         if (lseek(m_fd, offset, SEEK_SET) < 0)
74                 return -1;
75
76         int left = m_maxrange;
77         
78         while (left >= 188)
79         {
80                 unsigned char block[188];
81                 if (read(m_fd, block, 188) != 188)
82                 {
83                         eDebug("read error");
84                         break;
85                 }
86                 left -= 188;
87                 offset += 188;
88                 
89                 if (block[0] != 0x47)
90                 {
91                         int i = 0;
92                         while (i < 188)
93                         {
94                                 if (block[i] == 0x47)
95                                         break;
96                                 ++i;
97                         }
98                         offset = lseek(m_fd, i - 188, SEEK_CUR);
99                         continue;
100                 }
101                 
102                 int pid = ((block[1] << 8) | block[2]) & 0x1FFF;
103                 int pusi = !!(block[1] & 0x40);
104                 
105 //              printf("PID %04x, PUSI %d\n", pid, pusi);
106                 
107                 if (m_pid >= 0)
108                         if (pid != m_pid)
109                                 continue;
110                 if (!pusi)
111                         continue;
112                 
113                         /* ok, now we have a PES header */
114                 unsigned char *pes;
115                 
116                         /* check for adaption field */
117                 if (block[3] & 0x20)
118                         pes = block + block[4] + 4 + 1;
119                 else
120                         pes = block + 4;
121                 
122                         /* somehow not a startcode. (this is invalid, since pusi was set.) ignore it. */
123                 if (pes[0] || pes[1] || (pes[2] != 1))
124                         continue;
125                 
126                 if (pes[7] & 0x80) /* PTS */
127                 {
128                         pts  = ((unsigned long long)(pes[ 9]&0xE))  << 29;
129                         pts |= ((unsigned long long)(pes[10]&0xFF)) << 22;
130                         pts |= ((unsigned long long)(pes[11]&0xFE)) << 14;
131                         pts |= ((unsigned long long)(pes[12]&0xFF)) << 7;
132                         pts |= ((unsigned long long)(pes[13]&0xFE)) >> 1;
133                         offset -= 188;
134                         
135                                 /* convert to zero-based */
136                         if (fixed)
137                                 fixupPTS(offset, pts);
138                         return 0;
139                 }
140         }
141         
142         return -1;
143 }
144
145 int eDVBTSTools::fixupPTS(const off_t &offset, pts_t &now)
146 {
147         if (m_use_streaminfo)
148         {
149                 return m_streaminfo.fixupPTS(offset, now);
150         } else
151         {
152                         /* for the simple case, we assume one epoch, with up to one wrap around in the middle. */
153                 calcBegin();
154                 if (!m_begin_valid)
155                 {       
156                         eDebug("begin not valid, can't fixup");
157                         return -1;
158                 }
159                 
160                 pts_t pos = m_pts_begin;
161                 if ((now < pos) && ((pos - now) < 90000 * 10))
162                 {       
163                         pos = 0;
164                         return 0;
165                 }
166                 
167                 if (now < pos) /* wrap around */
168                         now = now + 0x200000000LL - pos;
169                 else
170                         now -= pos;
171                 return 0;
172         }
173 }
174
175 void eDVBTSTools::calcBegin()
176 {
177         if (m_fd < 0)   
178                 return;
179
180         if (!m_begin_valid)
181         {
182                 m_offset_begin = 0;
183                 if (!getPTS(m_offset_begin, m_pts_begin))
184                         m_begin_valid = 1;
185         }
186 }
187
188 void eDVBTSTools::calcEnd()
189 {
190         if (m_fd < 0)   
191                 return;
192         
193         off_t end = lseek(m_fd, 0, SEEK_END);
194         
195         if (abs(end - m_offset_end) > 1*1024*1024)
196         {
197                 m_offset_end = end;
198                 m_end_valid = 0;
199                 eDebug("file size changed, recalc length");
200         }
201         
202         int maxiter = 10;
203         
204         while (!m_end_valid)
205         {
206                 if (!--maxiter)
207                         return;
208                 
209                 m_offset_end -= m_maxrange;
210                 if (m_offset_end < 0)
211                         m_offset_end = 0;
212                 if (!getPTS(m_offset_end, m_pts_end))
213                         m_end_valid = 1;
214                 if (!m_offset_end)
215                         return;
216         }
217 }
218
219 int eDVBTSTools::calcLen(pts_t &len)
220 {
221         calcBegin(); calcEnd();
222         if (!(m_begin_valid && m_end_valid))
223                 return -1;
224         len = m_pts_end - m_pts_begin;
225                 /* wrap around? */
226         if (len < 0)
227                 len += 0x200000000LL;
228         return 0;
229 }
230
231 int eDVBTSTools::calcBitrate()
232 {
233         calcBegin(); calcEnd();
234         if (!(m_begin_valid && m_end_valid))
235                 return -1;
236
237         pts_t len_in_pts = m_pts_end - m_pts_begin;
238
239                 /* wrap around? */
240         if (len_in_pts < 0)
241                 len_in_pts += 0x200000000LL;
242         off_t len_in_bytes = m_offset_end - m_offset_begin;
243         
244         if (!len_in_pts)
245                 return -1;
246         
247         unsigned long long bitrate = len_in_bytes * 90000 * 8 / len_in_pts;
248         if ((bitrate < 10000) || (bitrate > 100000000))
249                 return -1;
250         
251         return bitrate;
252 }