- add tstools to evaluate PTS values from TS files for playback
[vuplus_dvbapp] / lib / dvb / tstools.cpp
1 #include <lib/dvb/tstools.h>
2 #include <unistd.h>
3 #include <fcntl.h>
4
5 #include <stdio.h>
6
7 eDVBTSTools::eDVBTSTools()
8 {
9         m_fd = -1;
10         m_pid = -1;
11         m_maxrange = 1*1024*1024;
12         
13         m_begin_valid = 0;
14         m_end_valid = 0;
15 }
16
17 eDVBTSTools::~eDVBTSTools()
18 {
19         closeFile();
20 }
21
22 int eDVBTSTools::openFile(const char *filename)
23 {
24         closeFile();
25         m_fd = ::open(filename, O_RDONLY);
26         if (m_fd < 0)
27                 return -1;
28         return 0;
29 }
30
31 void eDVBTSTools::closeFile()
32 {
33         if (m_fd >= 0)
34                 ::close(m_fd);
35 }
36
37 void eDVBTSTools::setSyncPID(int pid)
38 {
39         m_pid = pid;
40 }
41
42 void eDVBTSTools::setSearchRange(int maxrange)
43 {
44         m_maxrange = maxrange;
45 }
46
47 int eDVBTSTools::getPTS(off_t &offset, pts_t &pts)
48 {
49         if (m_fd < 0)
50                 return -1;
51         if (m_pid < 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                                 if (block[i] == 0x47)
75                                         break;
76                         offset = lseek(m_fd, i - 188, SEEK_CUR);
77                         continue;
78                 }
79                 
80                 int pid = ((block[1] << 8) | block[2]) & 0x1FFF;
81                 int pusi = !!(block[1] & 0x40);
82                 
83 //              printf("PID %04x, PUSI %d\n", pid, pusi);
84                 
85                 if (pid != m_pid)
86                         continue;
87                 if (!pusi)
88                         continue;
89                 
90                         /* ok, now we have a PES header */
91                 unsigned char *pes;
92                 
93                         /* check for adaption field */
94                 if (block[3] & 0x10)
95                         pes = block + block[4] + 4 + 1;
96                 else
97                         pes = block + 4;
98                 
99                         /* somehow not a startcode. (this is invalid, since pusi was set.) ignore it. */
100                 if (pes[0] || pes[1] || (pes[2] != 1))
101                         continue;
102                 
103                 if (pes[7] & 0x80) /* PTS */
104                 {
105                         pts  = ((unsigned long long)(pes[ 9]&0xE))  << 29;
106                         pts |= ((unsigned long long)(pes[10]&0xFF)) << 22;
107                         pts |= ((unsigned long long)(pes[11]&0xFE)) << 14;
108                         pts |= ((unsigned long long)(pes[12]&0xFF)) << 7;
109                         pts |= ((unsigned long long)(pes[13]&0xFE)) >> 1;
110                         offset -= 188;
111                         return 0;
112                 }
113         }
114
115         return -1;
116 }
117
118 void eDVBTSTools::calcBegin()
119 {
120         if (m_fd < 0)   
121                 return;
122         if (!m_begin_valid)
123         {
124                 m_offset_begin = 0;
125                 if (!getPTS(m_offset_begin, m_pts_begin))
126                         m_begin_valid = 1;
127         }
128 }
129
130 void eDVBTSTools::calcEnd()
131 {
132         if (m_fd < 0)   
133                 return;
134         
135         if (!m_end_valid)
136         {
137                 m_offset_end = lseek(m_fd, 0, SEEK_END) - m_maxrange;
138                 if (!getPTS(m_offset_end, m_pts_end))
139                         m_end_valid = 1;
140         }
141 }
142
143 int eDVBTSTools::calcLen(pts_t &len)
144 {
145         calcBegin(); calcEnd();
146         if (!(m_begin_valid && m_end_valid))
147                 return -1;
148         len = m_pts_end - m_pts_begin;
149         return 0;
150 }
151