enable wrap around in epglist and servicelist
[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
18 eDVBTSTools::~eDVBTSTools()
19 {
20         closeFile();
21 }
22
23 int eDVBTSTools::openFile(const char *filename)
24 {
25         closeFile();
26         m_fd = ::open(filename, O_RDONLY);
27         if (m_fd < 0)
28                 return -1;
29         return 0;
30 }
31
32 void eDVBTSTools::closeFile()
33 {
34         if (m_fd >= 0)
35                 ::close(m_fd);
36 }
37
38 void eDVBTSTools::setSyncPID(int pid)
39 {
40         m_pid = pid;
41 }
42
43 void eDVBTSTools::setSearchRange(int maxrange)
44 {
45         m_maxrange = maxrange;
46 }
47
48         /* getPTS extracts a pts value from any PID at a given offset. */
49 int eDVBTSTools::getPTS(off_t &offset, pts_t &pts)
50 {
51         if (m_fd < 0)
52                 return -1;
53
54         offset -= offset % 188;
55         
56                 // TODO: multiple files!        
57         if (lseek(m_fd, offset, SEEK_SET) < 0)
58                 return -1;
59
60         int left = m_maxrange;
61         
62         while (left >= 188)
63         {
64                 unsigned char block[188];
65                 if (read(m_fd, block, 188) != 188)
66                         break;
67                 left -= 188;
68                 offset += 188;
69                 
70                 if (block[0] != 0x47)
71                 {
72                         int i = 0;
73                         while (i < 188)
74                         {
75                                 if (block[i] == 0x47)
76                                         break;
77                                 ++i;
78                         }
79                         offset = lseek(m_fd, i - 188, SEEK_CUR);
80                         continue;
81                 }
82                 
83                 int pid = ((block[1] << 8) | block[2]) & 0x1FFF;
84                 int pusi = !!(block[1] & 0x40);
85                 
86 //              printf("PID %04x, PUSI %d\n", pid, pusi);
87                 
88                 if (m_pid >= 0)
89                         if (pid != m_pid)
90                                 continue;
91                 if (!pusi)
92                         continue;
93                 
94                         /* ok, now we have a PES header */
95                 unsigned char *pes;
96                 
97                         /* check for adaption field */
98                 if (block[3] & 0x20)
99                         pes = block + block[4] + 4 + 1;
100                 else
101                         pes = block + 4;
102                 
103                         /* somehow not a startcode. (this is invalid, since pusi was set.) ignore it. */
104                 if (pes[0] || pes[1] || (pes[2] != 1))
105                         continue;
106                 
107                 if (pes[7] & 0x80) /* PTS */
108                 {
109                         pts  = ((unsigned long long)(pes[ 9]&0xE))  << 29;
110                         pts |= ((unsigned long long)(pes[10]&0xFF)) << 22;
111                         pts |= ((unsigned long long)(pes[11]&0xFE)) << 14;
112                         pts |= ((unsigned long long)(pes[12]&0xFF)) << 7;
113                         pts |= ((unsigned long long)(pes[13]&0xFE)) >> 1;
114                         offset -= 188;
115                         return 0;
116                 }
117         }
118         
119         return -1;
120 }
121
122 void eDVBTSTools::calcBegin()
123 {
124         if (m_fd < 0)   
125                 return;
126
127         if (!m_begin_valid)
128         {
129                 m_offset_begin = 0;
130                 if (!getPTS(m_offset_begin, m_pts_begin))
131                         m_begin_valid = 1;
132         }
133 }
134
135 void eDVBTSTools::calcEnd()
136 {
137         if (m_fd < 0)   
138                 return;
139         
140         off_t end = lseek(m_fd, 0, SEEK_END);
141         
142         if (abs(end - m_offset_end) > 1*1024*1024)
143         {
144                 m_offset_end = end;
145                 m_end_valid = 0;
146                 eDebug("file size changed, recalc length");
147         }
148         
149         int maxiter = 10;
150         
151         while (!m_end_valid)
152         {
153                 if (!--maxiter)
154                         return;
155                 
156                 m_offset_end -= m_maxrange;
157                 if (m_offset_end < 0)
158                         m_offset_end = 0;
159                 if (!getPTS(m_offset_end, m_pts_end))
160                         m_end_valid = 1;
161                 if (!m_offset_end)
162                         return;
163         }
164 }
165
166 int eDVBTSTools::calcLen(pts_t &len)
167 {
168         calcBegin(); calcEnd();
169         if (!(m_begin_valid && m_end_valid))
170                 return -1;
171         len = m_pts_end - m_pts_begin;
172         return 0;
173 }
174
175 int eDVBTSTools::calcBitrate()
176 {
177         calcBegin(); calcEnd();
178         if (!(m_begin_valid && m_end_valid))
179                 return -1;
180
181         pts_t len_in_pts = m_pts_end - m_pts_begin;
182         off_t len_in_bytes = m_offset_end - m_offset_begin;
183         
184         if (!len_in_pts)
185                 return -1;
186         
187         unsigned long long bitrate = len_in_bytes * 90000 * 8 / len_in_pts;
188         if ((bitrate < 10000) || (bitrate > 100000000))
189                 return -1;
190         
191         return bitrate;
192 }