]> git.vomp.tv Git - vompclient.git/blob - demuxervdr.cc
Fix text corruption in live TV OSD clock
[vompclient.git] / demuxervdr.cc
1 /*
2     Copyright 2005-2008 Mark Calderbank
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP.  If not, see <https://www.gnu.org/licenses/>.
18 */
19
20 #include "demuxervdr.h"
21 #include "video.h"
22 #include "dvbsubtitles.h"
23 #include "log.h"
24
25 #ifndef WIN32
26 #include <endian.h>
27 #else
28 #define __LITTLE_ENDIAN 1234
29 #define __BIG_ENDIAN  4321
30 #define __BYTE_ORDER __LITTLE_ENDIAN
31 #endif
32
33 #define PTS_JUMP_MARGIN   10000
34 #define PTS_ALLOWANCE 90000
35
36 static const char* TAG = "DemuxerVDR";
37
38 // TODO: PTS class to handle wrapping arithmetic & comparisons?
39 static ULLONG PTSDistance(ULLONG pts1, ULLONG pts2)
40 {
41   // Assume pts1, pts2 < 2^33; calculate shortest distance between
42   ULLONG ret = (pts1 > pts2) ? pts1 - pts2 : pts2 - pts1;
43   if (ret > (1LL<<32)) ret = (1LL<<33) - ret;
44   return ret;
45 }
46
47 static ULLONG PTSDifference(ULLONG pts1, ULLONG pts2)
48 {
49   // Assume pts1, pts2 < 2^33; calculate pts1 - pts2
50   if (pts1 > pts2)
51     return pts1 - pts2;
52   else
53     return (1LL<<33) + pts1 - pts2;
54 }
55
56 DemuxerVDR::DemuxerVDR()
57 {
58   frameCounting = false;
59   packetCounting = false;
60   subtitlePacketPosition = 0;
61 }
62
63 void DemuxerVDR::reset()
64 {
65   frameCounting = false;
66   packetCounting = false;
67   pts_map.clear();
68   Demuxer::reset();
69 }
70
71 void DemuxerVDR::flush()
72 {
73   state = 0;
74   submitting = false;
75   subtitlePacketPosition = 0;
76   Demuxer::flush();
77 }
78
79 int DemuxerVDR::scan(UCHAR *buf, int len) {
80         // Temporarily, just look for the lowest audio stream and return it
81         UCHAR HiByte = PESTYPE_AUDMAX;
82         int ret = 0;
83
84         while (len >= 4) {
85                 UINT pattern = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
86                 buf++;
87                 len--;
88
89                 if (pattern < (UINT)(0x100 | PESTYPE_AUD0) || pattern > (UINT)(
90                                 0x100 | HiByte))
91                         continue;
92                 HiByte = pattern & 0xFF;
93
94                 ret = HiByte;
95                 if (HiByte == PESTYPE_AUD0)
96                         break;
97         }
98         return ret;
99 }
100
101 int DemuxerVDR::findPTS(UCHAR* buf, int len, ULLONG* dest) {
102         while (len >= 14) {
103                 UINT pattern = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
104                 buf++;
105                 len--;
106                 if (pattern < (0x100 | PESTYPE_AUD0) || pattern > (0x100
107                                 | PESTYPE_VIDMAX))
108                         continue;
109
110                 if ((buf[5] & 0xC0) != 0x80)
111                         continue;
112
113                 UINT packetlength = ((UINT) buf[3] << 8) | buf[4];
114
115                 if (buf[6] & 0x80) // PTS_DTS_flags indicate that PTS is present
116                 {
117                         if ((buf[8] & 0x01) != 0x01 || (buf[10] & 0x01) != 0x01 || (buf[12]
118                                         & 0x01) != 0x01)
119                                 continue;
120
121                         *dest = ((ULLONG)(buf[8] & 0x0E) << 29) | ((ULLONG)(buf[9]) << 22)
122                                         | ((ULLONG)(buf[10] & 0xFE) << 14) | ((ULLONG)(buf[11])
123                                         << 7) | ((ULLONG)(buf[12] & 0xFE) >> 1);
124                         return 1;
125                 }
126
127                 buf += 5;
128                 len -= 5;
129                 buf += packetlength;
130                 len -= packetlength;
131         }
132         // No PTS found.
133         return 0;
134 }
135
136 void DemuxerVDR::setFrameNum(ULONG frame)
137 {
138   frameCounting = true;
139   frameNumber = frame;
140   LogNT::getInstance()->debug(TAG, "setFrameNum {}", frame);
141 }
142
143 void DemuxerVDR::setPacketNum(ULONG npacket)
144 {
145   packetCounting = true;
146   packetNumber = npacket;
147   LogNT::getInstance()->debug(TAG, "setPacketNum {}", npacket);
148 }
149
150 int DemuxerVDR::put(UCHAR* buf, int len)
151 {
152   int ret = 0;    // return number of bytes consumed
153   if (submitting)
154   {
155     if (submitPacket(packet) == 0) // Still full!
156       return ret;
157     else
158       submitting = false;
159   }
160
161   if (state > 0) // We are half way through a PES packet.
162   {
163     if (len >= state) // The remainder of the packet is available.
164     {
165       packet.write(buf, state);
166       buf += state; len -= state; ret += state;
167       state = 0;
168       parseVDRPacketDetails();
169       if (submitPacket(packet) == 0) // Stream is full
170       {
171         submitting = true;
172         return ret;
173       }
174     }
175     else // Write what we have, then exit.
176     {
177       packet.write(buf, len);
178       state -= len;
179       return len;
180     }
181   }
182
183   while (len > 0)
184   {
185     switch (state)
186     {
187       case  0:
188       case -1:
189         if (*buf == 0x00) state--; else state = 0;
190         buf++; len--; ret++;
191         break;
192       case -2:
193         if (*buf == 0x01) state--; else if (*buf != 0x00) state = 0;
194         buf++; len--; ret++;
195         break;
196       case -3:
197         if ((*buf >= PESTYPE_VID0 && *buf <= PESTYPE_VIDMAX) ||
198             (*buf >= PESTYPE_AUD0 && *buf <= PESTYPE_AUDMAX) ||
199             (*buf == PESTYPE_PRIVATE_1))
200         {
201           packet.init(*buf);
202           state--;
203         }
204         else if (*buf == 0x00)
205           state = -1;
206         else
207           state = 0;
208         buf++; len--; ret++;
209         break;
210       case -4:
211         packetLength = ((UINT)*buf) << 8;
212         state--;
213         buf++; len--; ret++;
214         break;
215       case -5:
216         packetLength += *buf;
217         state--;
218         buf++; len--; ret++;
219         break;
220     }
221
222     if (state == -6) // Packet header complete
223     {
224       if (len >= packetLength) // The entire packet is available.
225       {
226         packet.write(buf, packetLength);
227         buf += packetLength; len -= packetLength; ret += packetLength;
228         state = 0;
229         parseVDRPacketDetails();
230         if (submitPacket(packet) == 0) // Stream is full
231         {
232           submitting = true;
233           return ret;
234         }
235       }
236       else // Write what we have.
237       {
238         packet.write(buf, len);
239         state = packetLength - len;
240         ret += len;
241         len = 0;
242       }
243     }
244   }
245   return ret;
246 }
247
248 ULONG DemuxerVDR::getPacketNum()
249 {
250   return packetNumber;
251 }
252
253 ULONG DemuxerVDR::getFrameNumFromPTS(ULLONG pts)
254 {
255   ULLONG difference = (1LL<<33);
256   ULONG ref_frame = 0;
257   int total = 0, actual = 0;
258   pts_map_mutex.lock();
259   PTSMap::iterator iter = pts_map.begin();
260   while (iter != pts_map.end())
261   {
262     ++total;
263     if (PTSDifference(iter->pts, pts) < PTS_ALLOWANCE)
264     {
265       difference = 0;
266       ref_frame = iter->frame;
267       actual = total;
268       break;
269     }
270     ULLONG newdiff = PTSDifference(pts, iter->pts);
271     if (newdiff < difference)
272     {
273       difference = newdiff;
274       ref_frame = iter->frame;
275       actual = total;
276     }
277     ++iter;
278   }
279   if (total > 1 && actual == 1) // We are using the most recent PTS ref.
280   {                             // Delete the rest.
281     iter = pts_map.begin(); iter++;
282     pts_map.erase(iter, pts_map.end());
283   }
284   pts_map_mutex.unlock();
285
286   if (difference == (1LL<<33))
287     return 0; // We cannot make sense of the pts
288   else
289     return ref_frame + (ULONG)((double) (difference / 90000) *fps);
290 }
291
292 void DemuxerVDR::dealWithSubtitlePacket()
293 {
294   const UCHAR* data = packet.getData();
295   UINT packetSize = packet.getSize();
296   if (packetSize < 9) return;
297   UINT payloadOffset = data[8] + 9;
298   if (packetSize < payloadOffset + 5) return;
299   if (data[payloadOffset + 3] == 0x00)
300   { // Not a continuation packet
301     if (packetSize < payloadOffset + 7) return;
302     subtitlePacket.init(data[3]);
303     subtitlePacket.write(&data[6], payloadOffset - 6);
304     subtitlePacket.write(&data[payloadOffset+4], packetSize-payloadOffset-4);
305     subtitlePacketPosition = payloadOffset + 2;
306   }
307   else
308   { // Continuation packet
309     if (subtitlePacketPosition == 0) return;
310     subtitlePacket.write(&data[payloadOffset+4], packetSize-payloadOffset-4);
311   }
312   
313   const UCHAR* sub_data = subtitlePacket.getData();
314   UINT subSize = subtitlePacket.getSize();
315   while (subtitlePacketPosition < subSize)
316   {
317     if (sub_data[subtitlePacketPosition] == 0xFF)
318     { // Packet is complete. Switch it into the "real" packet to be submitted.
319       packet = subtitlePacket;
320       parsePacketDetails(packet);
321       subtitlePacketPosition = 0; // Wait for next non-continuation packet
322       break;
323     }
324     if (sub_data[subtitlePacketPosition] != 0x0F)
325     {
326       subtitlePacketPosition = 0; // Wait for next non-continuation packet
327       break;
328     }
329     if (subSize < subtitlePacketPosition + 6) break;
330     UINT segmentLength = (sub_data[subtitlePacketPosition + 4] << 8)
331                         + sub_data[subtitlePacketPosition + 5];
332     subtitlePacketPosition += segmentLength + 6;
333   }
334 }
335
336 void DemuxerVDR::parseVDRPacketDetails()
337 {
338   if (packet.getPacketType() == PESTYPE_PRIVATE_1 && packet.getSize() > 8)
339   {
340     UINT payload_begin = packet[8] + 9;
341     if (packet.getSize() > payload_begin)
342     {
343       UCHAR substream_type = packet[payload_begin] & 0xF0;
344       if (substream_type == 0x20) // Subtitles
345       {
346         dealWithSubtitlePacket();
347       }
348       else // Not subtitles
349         parsePacketDetails(packet);
350     }
351   }
352   else // Not a private packet*/
353     parsePacketDetails(packet);
354
355   if (packetCounting && packet.getPacketType() >= PESTYPE_AUD0 &&
356                         packet.getPacketType() <= PESTYPE_AUDMAX)
357   {
358     packetNumber++;
359   }
360
361   if (frameCounting && packet.findPictureHeader(h264) &&
362       packet.getPacketType() >= PESTYPE_VID0 &&
363       packet.getPacketType() <= PESTYPE_VIDMAX)
364   {
365     ULONG frame_num = (frameNumber)++;
366     if (packet.findSeqHeader(h264) > 1 && packet.hasPTS())
367     {
368       PTSMapEntry me;
369       pts_map_mutex.lock();
370       if (pts_map.empty())
371       {
372         me.pts = packet.getPTS();
373         me.frame = frame_num;
374         pts_map_mutex.unlock();
375 LogNT::getInstance()->debug(TAG, "+* PTS INIT *+ {} {}", me.pts, me.frame);
376         pts_map_mutex.lock();
377         pts_map.push_front(me);
378       }
379       me = pts_map.front();
380       pts_map_mutex.unlock();
381
382 //      UINT fps = Video::getInstance()->getFPS();
383       ULLONG pts_expected = me.pts + 90000*((ULONG)((double)(frame_num - me.frame)) / fps);
384       while (pts_expected > (1LL<<33)) pts_expected -= (1LL<<33);
385
386       if (PTSDistance(pts_expected, packet.getPTS()) > PTS_JUMP_MARGIN) // PTS jump!
387       {
388 LogNT::getInstance()->debug(TAG, "+* PTS JUMP *+ {} {}", packet.getPTS(), frame_num);
389         me.pts = packet.getPTS();
390         me.frame = frame_num;
391         pts_map_mutex.lock();
392         pts_map.push_front(me);
393         pts_map_mutex.unlock();
394       }
395     }
396   }
397 }