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