]> git.vomp.tv Git - vompclient-marten.git/blob - demuxer.cc
Add handling reference frame pointers
[vompclient-marten.git] / demuxer.cc
1 /*\r
2     Copyright 2005-2008 Mark Calderbank\r
3     Copyright 2007 Marten Richter (AC3 support)\r
4 \r
5     This file is part of VOMP.\r
6 \r
7     VOMP is free software; you can redistribute it and/or modify\r
8     it under the terms of the GNU General Public License as published by\r
9     the Free Software Foundation; either version 2 of the License, or\r
10     (at your option) any later version.\r
11 \r
12     VOMP is distributed in the hope that it will be useful,\r
13     but WITHOUT ANY WARRANTY; without even the implied warranty of\r
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
15     GNU General Public License for more details.\r
16 \r
17     You should have received a copy of the GNU General Public License\r
18     along with VOMP; if not, write to the Free Software Foundation, Inc.,\r
19     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
20 */\r
21 \r
22 #include "demuxer.h"\r
23 \r
24 #include "callback.h"\r
25 #include "dvbsubtitles.h"\r
26 #include "log.h"\r
27 \r
28 #include <cstdlib>\r
29 \r
30 #include <math.h>\r
31 \r
32 #define DEMUXER_SEQ_HEAD 0x000001B3\r
33 #define DEMUXER_PIC_HEAD 0x00000101\r
34 \r
35 #define DEMUXER_H264_ACCESS_UNIT 0x00000109\r
36 #define DEMUXER_H264_SEQ_PARAMETER_SET 0x00000107\r
37 \r
38 \r
39 #define SEEK_THRESHOLD 150000 // About 1.5 seconds\r
40 \r
41 // Statics\r
42 const int Demuxer::FrameRates[9] = { 0, 23, 24, 25, 29, 30, 50, 59, 60 };\r
43 Demuxer* Demuxer::instance = NULL;\r
44 \r
45 class NALUUnit {\r
46 public:\r
47     NALUUnit(const UCHAR* buf,UINT length_buf);\r
48     ~NALUUnit();\r
49 \r
50 inline    UINT getBits(UINT num_bits);\r
51     UINT getUe();\r
52     int getSe();\r
53     bool isEonalu() {return eonalu;};\r
54 \r
55 protected:\r
56     UCHAR* nalu_buf;\r
57     UINT nalu_length;\r
58     UINT pos;\r
59     UCHAR bit_pos;\r
60     UCHAR working_byte;\r
61     UINT last_bytes;\r
62     bool eonalu;\r
63 };\r
64 \r
65 NALUUnit::NALUUnit(const UCHAR *buf, UINT length_buf)\r
66 {\r
67     nalu_length=0;\r
68     nalu_buf=NULL;\r
69     pos=0;\r
70     bit_pos=0;\r
71     working_byte=0;\r
72     last_bytes=0;\r
73     eonalu=false;\r
74 \r
75     UINT nalu_start=0;\r
76     UINT nalu_end=0;\r
77     UINT pattern =(((UINT)buf[ 0] << 16) |\r
78                    ((UINT)buf[1] <<  8) |\r
79                     (UINT)buf[2]  );\r
80     nalu_start=3;\r
81     while (pattern != 0x000001)\r
82     {\r
83         if (++nalu_start >= length_buf) return;\r
84         pattern = ((pattern << 8) | buf[nalu_start])&0x00FFFFFF;\r
85     }\r
86     nalu_end=nalu_start+1;\r
87     pattern = ((pattern << 8) | buf[nalu_end])&0x00FFFFFF;\r
88 \r
89     while (pattern != 0x000001 && pattern != 0x000000)\r
90     {\r
91         if (++nalu_end >= length_buf) { nalu_end+=3;break;};\r
92         pattern = ((pattern << 8) | buf[nalu_end])&0x00FFFFFF;\r
93     }\r
94     nalu_end-=3;\r
95     nalu_end=min(length_buf-1,nalu_end);\r
96     nalu_length=nalu_end-nalu_start;\r
97     nalu_buf=(UCHAR*)malloc(nalu_length);\r
98     memcpy(nalu_buf,buf+nalu_start,nalu_length);\r
99     pos=1;\r
100 }\r
101 \r
102 NALUUnit::~NALUUnit()\r
103 {\r
104     if (nalu_buf) free(nalu_buf);\r
105 }\r
106 \r
107 inline UINT NALUUnit::getBits(UINT num_bits)\r
108 {\r
109     if (num_bits==0) return 0; //???\r
110     UINT remain_bits=num_bits;\r
111     UINT work=0;\r
112     //May be slow, but should work!\r
113     while (remain_bits>0) {\r
114         if (bit_pos==0) {\r
115             if (pos<nalu_length)\r
116             {\r
117                 last_bytes=(last_bytes<<8) & nalu_buf[pos];\r
118                 if ((last_bytes & 0x00FFFFFF) == 0x000003) pos++; //emulation prevention byte\r
119                  if (pos<nalu_length)\r
120                  {\r
121                      working_byte=nalu_buf[pos];\r
122                      pos++;\r
123                  } \r
124                  else\r
125                  {\r
126                      working_byte=0;\r
127                      eonalu=true;\r
128                  }\r
129             } \r
130             else\r
131             {\r
132                 working_byte=0;\r
133                 eonalu=true;\r
134             }\r
135 \r
136         }\r
137         UINT fetch_bits=min(remain_bits,8-bit_pos);\r
138         work=work <<fetch_bits;\r
139         //work|=((working_byte>>bit_pos) & (0xFF>>(8-fetch_bits)));\r
140         work|=(working_byte &(0xFF>>(bit_pos)))>>(8-fetch_bits-bit_pos);\r
141         remain_bits-=fetch_bits;\r
142         bit_pos=(bit_pos+fetch_bits)%8;\r
143     }\r
144     return work;\r
145 }\r
146 \r
147 UINT NALUUnit::getUe()\r
148 {\r
149     int leadbits=-1;\r
150     bool bit;\r
151     for( bit = 0; !bit && !eonalu; leadbits++ )\r
152         bit = getBits(1);\r
153     if (eonalu) return true;\r
154     return ((1 << leadbits)-1)+getBits(leadbits);\r
155 }\r
156 \r
157 int NALUUnit::getSe()\r
158 {\r
159     UINT input=getUe();\r
160     if (input==0) return 0;\r
161     int output=((input+1)>>1);\r
162     if (input & 0x1) output*=-1;\r
163     return output;\r
164 }\r
165 \r
166 \r
167 \r
168 static const int PESPacket_initial_size = 2000;\r
169 \r
170 // PESPacket methods\r
171 PESPacket::PESPacket()\r
172 {\r
173   data_size = PESPacket_initial_size;\r
174   data = (UCHAR*)malloc(data_size);\r
175   data[0] = 0x00;\r
176   data[1] = 0x00;\r
177   data[2] = 0x01;\r
178   init(0);\r
179 }\r
180 \r
181 PESPacket::PESPacket(const PESPacket& packet)\r
182 {\r
183   copyFrom(packet);\r
184 }\r
185 \r
186 PESPacket& PESPacket::operator=(const PESPacket& packet)\r
187 {\r
188   if (this != &packet)\r
189   {\r
190     if (data) free(data);\r
191     copyFrom(packet);\r
192   }\r
193   return *this;\r
194 }\r
195 \r
196 PESPacket::~PESPacket()\r
197 {\r
198   if (data) free(data);\r
199 }\r
200 \r
201 void PESPacket::copyFrom(const PESPacket& packet)\r
202 {\r
203   length = packet.length;\r
204   size = packet.size;\r
205   packetType = packet.packetType;\r
206   substream = packet.substream;\r
207   seq_header = packet.seq_header;\r
208   data_size = size;\r
209   data = (UCHAR*)malloc(data_size);\r
210   memcpy(data, packet.data, data_size);\r
211 }\r
212 \r
213 void PESPacket::init(UCHAR type, UCHAR sub)\r
214 {\r
215   length = 0; \r
216   size = 6;\r
217   data[4] = data[5] = 0;\r
218   data[3] = type;\r
219   packetType = type;\r
220   substream = sub;\r
221   seq_header = 1; // Unknown seq_header status\r
222 \r
223 }\r
224 \r
225 void PESPacket::truncate()\r
226 {\r
227   init(packetType,substream);\r
228 }\r
229 \r
230 \r
231 \r
232 int PESPacket::write(const UCHAR *buf, int len)\r
233 {\r
234 \r
235 \r
236   if (size + len > 0x10000) return 0;\r
237   if (size + len > data_size)\r
238   { // Reallocate\r
239     UINT new_data_size = max(data_size + data_size / 2, data_size + len);\r
240     if (new_data_size > 0x10000) new_data_size = 0x10000;\r
241     data_size = new_data_size;\r
242     data = (UCHAR*)realloc(data, data_size);\r
243   }\r
244   memcpy(data + size, buf, len);\r
245   length += len;\r
246   size += len;\r
247   data[4] = (length >> 8);\r
248   data[5] = (length & 0xFF);\r
249   // We have added data - reset seq_header indicator if necessary\r
250   if (seq_header == 0) seq_header = 1; // Reset to 'unknown'\r
251   return 1;\r
252 }\r
253 \r
254 ULLONG PESPacket::getPTS() const\r
255 {\r
256   if ( ( (packetType >= Demuxer::PESTYPE_AUD0 &&\r
257           packetType <= Demuxer::PESTYPE_AUDMAX)\r
258          ||\r
259          (packetType >= Demuxer::PESTYPE_VID0 &&\r
260           packetType <= Demuxer::PESTYPE_VIDMAX)\r
261    ||\r
262           packetType == Demuxer::PESTYPE_PRIVATE_1\r
263        )\r
264        && size >= 14 && data[7] & 0x80)\r
265   {\r
266     return ( (ULLONG)(data[ 9] & 0x0E) << 29) |\r
267            ( (ULLONG)(data[10])        << 22 ) |\r
268            ( (ULLONG)(data[11] & 0xFE) << 14 ) |\r
269            ( (ULLONG)(data[12])        <<  7 ) |\r
270            ( (ULLONG)(data[13] & 0xFE) >>  1 );\r
271   }\r
272   else return PTS_INVALID;\r
273 }\r
274 \r
275 UCHAR PESPacket::operator[] (UINT index) const\r
276 {\r
277   if (index >= size)\r
278     return 0;\r
279   else\r
280     return data[index];\r
281 }\r
282 \r
283 UINT PESPacket::findPictureHeader(bool h264) const\r
284 {\r
285   if (size < 12) return 0;\r
286   UINT pattern = ( ((UINT)data[ 8] << 24) |\r
287                    ((UINT)data[ 9] << 16) |\r
288                    ((UINT)data[10] <<  8) |\r
289                     (UINT)data[11]  );\r
290   UINT pos = 11;\r
291   if (h264) {\r
292           \r
293           while (pattern != DEMUXER_H264_ACCESS_UNIT)\r
294           {\r
295                   if (++pos >= size) return 0;\r
296                   pattern = (pattern << 8) | data[pos];\r
297           }\r
298           return pos-3;\r
299   } else {\r
300           while (pattern != DEMUXER_PIC_HEAD)\r
301           {\r
302                   if (++pos >= size) return 0;\r
303                   pattern = (pattern << 8) | data[pos];\r
304           }\r
305           return pos-3;\r
306   }\r
307 }\r
308 \r
309 UINT PESPacket::countPictureHeaders(bool h264) const\r
310 {\r
311   if (size < 12) return 0;\r
312   UINT pattern = ( ((UINT)data[ 8] << 24) |\r
313                    ((UINT)data[ 9] << 16) |\r
314                    ((UINT)data[10] <<  8) |\r
315                     (UINT)data[11]  );\r
316   UINT pos = 11;\r
317   UINT count=0;\r
318   if (h264) {\r
319           \r
320           while (pos<size)\r
321           {\r
322           pos++;\r
323                   pattern = (pattern << 8) | data[pos];\r
324           if (pattern==DEMUXER_H264_ACCESS_UNIT) count++;\r
325           }\r
326           return count;\r
327   } else {\r
328       while (pos<size)\r
329           {\r
330           pos++;\r
331                   pattern = (pattern << 8) | data[pos];\r
332           if (pattern==DEMUXER_PIC_HEAD) count++;\r
333           }\r
334           return count;\r
335   }\r
336 }\r
337 \r
338 UINT PESPacket::findSeqHeader(bool h264) const\r
339 {\r
340   if (seq_header != 1) return seq_header;\r
341   if (size < 12) return 0;\r
342   UINT pattern = ( ((UINT)data[ 8] << 24) |\r
343                    ((UINT)data[ 9] << 16) |\r
344                    ((UINT)data[10] <<  8) |\r
345                     (UINT)data[11]  );\r
346   UINT pos = 11;\r
347   if (h264) {\r
348       while ((pattern & 0xFFFFFF1F) != DEMUXER_H264_SEQ_PARAMETER_SET)\r
349           {\r
350                   if (++pos >= size)\r
351                   {\r
352                           seq_header = 0;\r
353                           return 0;\r
354                   }\r
355                   pattern = (pattern << 8) | data[pos];\r
356           }\r
357           seq_header = pos - 3;\r
358   } \r
359   else \r
360   {\r
361           while (pattern != DEMUXER_SEQ_HEAD)\r
362           {\r
363                   if (++pos >= size)\r
364                   {\r
365                           seq_header = 0;\r
366                           return 0;\r
367                   }\r
368                   pattern = (pattern << 8) | data[pos];\r
369           }\r
370           seq_header = pos - 3;\r
371   }\r
372   return seq_header;\r
373 }\r
374 \r
375 // Demuxer methods\r
376 Demuxer::Demuxer()\r
377 {\r
378   if (instance) return;\r
379   instance = this;\r
380   initted = false;\r
381   callback = NULL;\r
382   arcnt = 0;\r
383   vid_seeking = aud_seeking = false;\r
384   video_pts = audio_pts = 0;\r
385   ispre_1_3_19 = false;\r
386   packetnum=0;\r
387   h264 = false;\r
388   fps = 25.0;\r
389 }\r
390 \r
391 Demuxer::~Demuxer()\r
392 {\r
393   shutdown();\r
394   instance = NULL;\r
395 }\r
396 \r
397 Demuxer* Demuxer::getInstance()\r
398 {\r
399   return instance;\r
400 }\r
401 \r
402 int Demuxer::init(Callback* tcallback, DrainTarget* audio, DrainTarget* video, DrainTarget* teletext,\r
403                   ULONG demuxMemoryV, ULONG demuxMemoryA, ULONG demuxMemoryT,double infps, DVBSubtitles* tsubtitles)\r
404 {\r
405   if (!initted)\r
406   {\r
407     if ( !videostream.init(video, demuxMemoryV) ||\r
408          !audiostream.init(audio, demuxMemoryA) ||\r
409          !teletextstream.init(teletext, demuxMemoryT))\r
410     {\r
411       Log::getInstance()->log("Demuxer", Log::CRIT,\r
412                               "Failed to initialize demuxer");\r
413       shutdown();\r
414       return 0;\r
415     }\r
416   }\r
417   if (teletext) {\r
418       isteletextdecoded = true;\r
419   } else {\r
420       isteletextdecoded = false;\r
421   }\r
422   fps=infps;\r
423   reset();\r
424   initted = true;\r
425   subtitles = tsubtitles;\r
426   callback = tcallback;\r
427   return 1;\r
428 }\r
429 \r
430 void Demuxer::reset()\r
431 {\r
432   Log::getInstance()->log("Demuxer", Log::DEBUG, "Reset called");\r
433   flush();\r
434   video_current = audio_current = teletext_current = subtitle_current = -1;\r
435   horizontal_size = vertical_size = 0;\r
436   aspect_ratio = (enum AspectRatio) 0;\r
437   frame_rate = bit_rate = 0;\r
438   ispre_1_3_19 = false;\r
439   h264 = false;\r
440   packetnum=0;\r
441 \r
442   for (int i = 0; i <= (PESTYPE_AUDMAX - PESTYPE_AUD0); i++)\r
443   {\r
444     avail_mpaudchan[i] = false;\r
445   }\r
446   for (int i = 0; i <= (PESTYPE_SUBSTREAM_AC3MAX - PESTYPE_SUBSTREAM_AC30); i++)\r
447   {\r
448     avail_ac3audchan[i] = false;\r
449   }\r
450   for (int i = 0; i <= (PESTYPE_SUBSTREAM_DVBSUBTITLEMAX - PESTYPE_SUBSTREAM_DVBSUBTITLE0); i++)\r
451   {\r
452     avail_dvbsubtitlechan[i] = false;\r
453   }\r
454 }\r
455 \r
456 int Demuxer::shutdown()\r
457 {\r
458   videostream.shutdown();\r
459   audiostream.shutdown();\r
460   teletextstream.shutdown();\r
461   initted = false;\r
462   return 1;\r
463 }\r
464 \r
465 void Demuxer::flush()\r
466 {\r
467   Log::getInstance()->log("Demuxer", Log::DEBUG, "Flush called");\r
468 \r
469   videostream.flush();\r
470   audiostream.flush();\r
471   teletextstream.flush();\r
472 }\r
473 \r
474 void Demuxer::flushAudio()\r
475 {\r
476   audiostream.flush();\r
477 }\r
478 \r
479 void Demuxer::seek()\r
480 {\r
481   vid_seeking = aud_seeking = true;\r
482   video_pts = audio_pts = teletext_pts = 0;\r
483 }\r
484 \r
485 void Demuxer::setAudioStream(int id)\r
486 {\r
487   audio_current = id;\r
488 }\r
489 \r
490 void Demuxer::setVideoStream(int id)\r
491 {\r
492   video_current = id;\r
493 }\r
494 \r
495 void Demuxer::setTeletextStream(int id)\r
496 {\r
497   teletext_current = id;\r
498 }\r
499 \r
500 void Demuxer::setDVBSubtitleStream(int id)\r
501 {\r
502   subtitle_current = id;\r
503 }\r
504 \r
505 void Demuxer::setAspectRatio(enum AspectRatio ar)\r
506 {\r
507   if (aspect_ratio != ar)\r
508   {\r
509     Log::getInstance()->log("Demux", Log::DEBUG,\r
510                             "Aspect ratio difference signalled");\r
511     if (++arcnt > 3) // avoid changing aspect ratio if glitch in signal\r
512     {\r
513       arcnt = 0;\r
514       aspect_ratio = ar;\r
515       if (callback) callback->call(this);\r
516     }\r
517   }\r
518   else\r
519     arcnt = 0;\r
520 }\r
521 \r
522 bool Demuxer::writeAudio()\r
523 {\r
524   return audiostream.drain();\r
525 }\r
526 \r
527 bool Demuxer::writeVideo()\r
528 {\r
529   return videostream.drain();\r
530 }\r
531 \r
532 bool Demuxer::writeTeletext()\r
533 {\r
534    return teletextstream.drain();\r
535 }\r
536 \r
537 bool Demuxer::submitPacket(PESPacket& packet)\r
538 {\r
539   UINT sent = 0;\r
540   UCHAR packet_type = packet.getPacketType();\r
541   const UCHAR* packetdata = packet.getData();\r
542   if (packet_type >= PESTYPE_VID0 && packet_type <= PESTYPE_VIDMAX)\r
543   {\r
544     if (video_current == -1) video_current = packet_type;\r
545     if (video_current == packet_type && !vid_seeking)\r
546         {\r
547         sent = videostream.put(&packetdata[0], packet.getSize(), h264?MPTYPE_VIDEO_H264:MPTYPE_VIDEO_MPEG2,packetnum);\r
548         if (sent) packetnum++;\r
549         }\r
550         else\r
551       sent = packet.getSize();\r
552   }\r
553   else if (packet_type >= PESTYPE_AUD0 && packet_type <= PESTYPE_AUDMAX)\r
554   {\r
555 \r
556     if (audio_current == -1) audio_current = packet_type;\r
557     avail_mpaudchan[packet_type - PESTYPE_AUD0] = true;\r
558     if (audio_current == packet_type && !aud_seeking)\r
559         {\r
560       sent = audiostream.put(&packetdata[0], packet.getSize(), MPTYPE_MPEG_AUDIO,packetnum);\r
561           if (sent)  packetnum++;\r
562         }\r
563         else\r
564       sent = packet.getSize();\r
565   }\r
566   else if (packet_type == PESTYPE_PRIVATE_1 &&\r
567            packet.getSubstream() >= PESTYPE_SUBSTREAM_AC30 &&\r
568            packet.getSubstream() <= PESTYPE_SUBSTREAM_AC3MAX)\r
569   {\r
570     avail_ac3audchan[packet.getSubstream() - PESTYPE_SUBSTREAM_AC30] = true;\r
571     if (packet.getSubstream() == audio_current)\r
572     {\r
573       sent = audiostream.put(&packetdata[0], packet.getSize(), (ispre_1_3_19)? MPTYPE_AC3_PRE13 : MPTYPE_AC3,packetnum);\r
574           if (sent) packetnum++;\r
575     }\r
576     else\r
577     {\r
578       sent = packet.getSize();\r
579     }\r
580   }\r
581   else if (packet_type == PESTYPE_PRIVATE_1 &&\r
582            packet.getSubstream() >= PESTYPE_SUBSTREAM_DVBSUBTITLE0 &&\r
583            packet.getSubstream() <= PESTYPE_SUBSTREAM_DVBSUBTITLEMAX)\r
584   {\r
585     avail_dvbsubtitlechan[packet.getSubstream()-PESTYPE_SUBSTREAM_DVBSUBTITLE0]=true;\r
586     if (subtitle_current == -1) subtitle_current = packet.getSubstream();\r
587     if (subtitles && packet.getSubstream()==subtitle_current)\r
588     {\r
589          subtitles->put(packet);\r
590     }\r
591     sent = packet.getSize();\r
592   }\r
593   else if (isteletextdecoded  && packet_type == PESTYPE_PRIVATE_1 &&\r
594            packet.getSubstream() >= PESTYPE_SUBSTREAM_TELETEXT0 &&\r
595            packet.getSubstream() <= PESTYPE_SUBSTREAM_TELETEXTMAX)\r
596   {\r
597 \r
598     if (teletext_current == -1) teletext_current = packet.getSubstream();\r
599     if (teletext_current == packet.getSubstream())\r
600     {\r
601         sent = teletextstream.put(&packetdata[0], packet.getSize(), MPTYPE_TELETEXT,packetnum);\r
602     }\r
603     else \r
604     {\r
605         sent = packet.getSize();\r
606     }\r
607   }\r
608   else\r
609   {\r
610     sent = packet.getSize();\r
611   }\r
612 \r
613   if (sent < packet.getSize()) // Stream is full.\r
614     return false;\r
615   else\r
616     return true;\r
617 }\r
618 \r
619 void Demuxer::parsePacketDetails(PESPacket& packet)\r
620 {\r
621     if (packet.getPacketType() >= PESTYPE_AUD0 &&\r
622         packet.getPacketType() <= PESTYPE_AUDMAX)\r
623     {\r
624         // Extract audio PTS if it exists\r
625         if (packet.hasPTS())\r
626         {\r
627             audio_pts = packet.getPTS();\r
628             // We continue to seek on the audio if the video PTS that we\r
629             // are trying to match is ahead of the audio PTS by at most\r
630             // SEEK_THRESHOLD. We consider the possibility of PTS wrap.\r
631             if (aud_seeking && !vid_seeking &&\r
632                 !( (video_pts_seek > audio_pts &&\r
633                 video_pts_seek - audio_pts < SEEK_THRESHOLD)\r
634                 ||\r
635                 (video_pts_seek < audio_pts &&\r
636                 video_pts_seek + (1LL<<33) - audio_pts < SEEK_THRESHOLD) ))\r
637             {\r
638                 aud_seeking = 0;\r
639                 Log::getInstance()->log("Demuxer", Log::DEBUG,\r
640                     "Leaving  audio sync: Audio PTS = %llu", audio_pts);\r
641             }\r
642         }\r
643     }\r
644     else if (packet.getPacketType() == PESTYPE_PRIVATE_1) // Private stream\r
645     {\r
646         //Inspired by vdr's device.c\r
647         int payload_begin = packet[8]+9;\r
648         unsigned char substream_id = packet[payload_begin];\r
649         unsigned char substream_type = substream_id & 0xF0;\r
650         unsigned char substream_index = substream_id & 0x1F;\r
651 pre_1_3_19_Recording: //This is for old recordings stuff and live TV\r
652         if (ispre_1_3_19)\r
653         {\r
654             substream_id = PESTYPE_PRIVATE_1;\r
655             substream_type = 0x80;\r
656             substream_index = 0;\r
657         }\r
658         switch (substream_type)\r
659         {\r
660         case 0x20://SPU\r
661         case 0x30://SPU\r
662             packet.setSubstream(substream_id);\r
663             break;\r
664         case 0xA0: //LPCM //not supported yet, is there any LPCM transmissio out there?\r
665             break;\r
666         case 0x80: //ac3, currently only one ac3 track per recording supported\r
667             packet.setSubstream(substream_type+substream_index);\r
668 \r
669             // Extract audio PTS if it exists\r
670             if (packet.hasPTS())\r
671             {\r
672                 audio_pts = packet.getPTS();\r
673                 // We continue to seek on the audio if the video PTS that we\r
674                 // are trying to match is ahead of the audio PTS by at most\r
675                 // SEEK_THRESHOLD. We consider the possibility of PTS wrap.\r
676                 if (aud_seeking && !vid_seeking &&\r
677                     !( (video_pts_seek > audio_pts &&\r
678                     video_pts_seek - audio_pts < SEEK_THRESHOLD)\r
679                     ||\r
680                     (video_pts_seek < audio_pts &&\r
681                     video_pts_seek + (1LL<<33) - audio_pts < SEEK_THRESHOLD) ))\r
682                 {\r
683                     aud_seeking = 0;\r
684                     Log::getInstance()->log("Demuxer", Log::DEBUG, "Leaving  audio sync: Audio PTS = %llu", audio_pts);\r
685                 }\r
686             }\r
687             break;\r
688         case 0x10: //Teletext Is this correct?\r
689             packet.setSubstream(substream_id);\r
690             // Extract teletxt PTS if it exists\r
691             if (packet.hasPTS())\r
692             {\r
693                 teletext_pts = packet.getPTS();\r
694             }\r
695             break;\r
696         default:\r
697             if (!ispre_1_3_19)\r
698             {\r
699                 ispre_1_3_19=true; //switching to compat mode and live tv mode\r
700                 goto pre_1_3_19_Recording;\r
701             }\r
702             else\r
703             {\r
704                 packet.setSubstream(0);\r
705             }\r
706             break;\r
707         }\r
708     }\r
709     else if (packet.getPacketType() >= PESTYPE_VID0 &&\r
710         packet.getPacketType() <= PESTYPE_VIDMAX)\r
711     {\r
712         // Extract video PTS if it exists\r
713         if (packet.hasPTS()) video_pts = packet.getPTS();\r
714 \r
715         // If there is a sequence header, extract information\r
716         UINT pos = packet.findSeqHeader(h264);\r
717         if (pos > 1)\r
718         {\r
719             if (!h264) {\r
720                 pos += 4;\r
721                 if (pos+6 >= packet.getSize()) return;\r
722                 horizontal_size = ((int)packet[pos] << 4) | ((int)packet[pos+1] >> 4);\r
723                 \r
724                 vertical_size = (((int)packet[pos+1] & 0xf) << 8) | (int)packet[pos+2];\r
725 \r
726                 setAspectRatio((enum AspectRatio)(packet[pos+3] >> 4));\r
727                 frame_rate = packet[pos+3] & 0x0f;\r
728                 if (frame_rate >= 1 && frame_rate <= 8)\r
729                     frame_rate = FrameRates[frame_rate];\r
730                 else\r
731                     frame_rate = 0;\r
732                 bit_rate = ((int)packet[pos+4] << 10) |\r
733                     ((int)packet[pos+5] << 2) |\r
734                     ((int)packet[pos+6] >> 6);\r
735             } \r
736             else\r
737             {\r
738                 /* Chris and Mark I know this is ugly, should we move this to a method  of PESPacket or to NALUUnit what would be better?\r
739                 This looks so ugly since the header includes variable length parts and I have to parse through the whole header to get the wanted information*/\r
740                 NALUUnit nalu(packet.getData()+pos,packet.getSize()-pos);\r
741                 profile=nalu.getBits(8);\r
742                 nalu.getBits(8); //constraints\r
743                 nalu.getBits(8); //level_idc\r
744                 nalu.getUe(); //seq_parameter_set_id\r
745                 int chroma=1;\r
746                 if (profile==100 || profile==110 || profile==122 || profile==144)\r
747                 {\r
748                     chroma=nalu.getUe();\r
749                     if (chroma==3)\r
750                     {\r
751                         nalu.getBits(1);\r
752                     }\r
753                     nalu.getUe(); //bit depth lume\r
754                     nalu.getUe(); //bit depth chrome\r
755                     nalu.getBits(1);\r
756                     if (nalu.getBits(1))\r
757                     {\r
758                         for (int i=0;i<8;i++){\r
759                             if (nalu.getBits(1))\r
760                             {\r
761                                 if (i<6)\r
762                                 {\r
763                                     UINT lastscale=8;\r
764                                     UINT nextscale=8;\r
765                                     for (int j=0;j<16;j++) {\r
766                                         if (nextscale!=0) {\r
767                                             UINT delta=nalu.getSe();\r
768                                             nextscale=(lastscale+delta+256)%256;\r
769                                         }\r
770                                         lastscale=(nextscale==0)?lastscale:nextscale;\r
771                                     }\r
772                                 }\r
773                                 else\r
774                                 {\r
775                                     UINT lastscale=8;\r
776                                     UINT nextscale=8;\r
777                                     for (int j=0;j<64;j++) {\r
778                                         if (nextscale!=0) {\r
779                                             UINT delta=nalu.getSe();\r
780                                             nextscale=(lastscale+delta+256)%256;\r
781                                         }\r
782                                         lastscale=(nextscale==0)?lastscale:nextscale;\r
783                                     }\r
784                                 }\r
785                             }\r
786                         }\r
787                     }\r
788                 }\r
789                 int chromunitx=1;\r
790                 int chromunity=1;\r
791                 switch (chroma) {\r
792                 case 0:\r
793                     chromunitx=chromunity=1; break;\r
794                 case 1:\r
795                     chromunitx=chromunity=2; break;\r
796                 case 2:\r
797                     chromunitx=2;chromunity=1; break;\r
798                 case 3:\r
799                     chromunitx=chromunity=1; break;\r
800                 };\r
801 \r
802                 nalu.getUe(); //log2framenum\r
803                 UINT temp=nalu.getUe();\r
804                 if (temp==0) //pict order\r
805                     nalu.getUe();\r
806                 else if (temp==1) {\r
807                     nalu.getBits(1);\r
808                     nalu.getSe();\r
809                     nalu.getSe();\r
810                     UINT temp2=nalu.getUe();\r
811                     for (int i=0;i<temp2;i++)\r
812                         nalu.getSe();\r
813                 }\r
814                 nalu.getUe(); //Num refframes\r
815                 nalu.getBits(1);\r
816                 horizontal_size=(nalu.getUe()+1)*16;\r
817                 \r
818                 vertical_size=(nalu.getUe()+1)*16;\r
819                 int interlaced=nalu.getBits(1);\r
820                 vertical_size*=(2-interlaced);\r
821                 \r
822                 if (!interlaced) nalu.getBits(1);\r
823                 nalu.getBits(1);\r
824                 if (nalu.getBits(1))\r
825                 {\r
826                     horizontal_size-=nalu.getUe()*chromunitx;\r
827                     horizontal_size-=nalu.getUe()*chromunitx;\r
828                     vertical_size-=nalu.getUe()*(2-interlaced)*chromunity;\r
829                     vertical_size-=nalu.getUe()*(2-interlaced)*chromunity;\r
830                 }\r
831                 if (nalu.getBits(1))\r
832                 {\r
833                     if (nalu.getBits(1))\r
834                     {\r
835                         UINT aspectratioidc=nalu.getBits(8);\r
836                         bool hasaspect=false;\r
837                         const float aspects[]={1., 1./1.,12./11.,10./11.,16./11.,40./33.,\r
838                             24./11.,20./11.,32./11.,80./33.,18./11.,15./11.,64./33.,160./99.,4./3.,3./2.,2./1.};\r
839                       \r
840                         float aspectratio=((float) horizontal_size)/((float) vertical_size);\r
841                         if (aspectratioidc<=16) \r
842                         {\r
843                             hasaspect=true;\r
844                             aspectratio*=aspects[aspectratioidc];\r
845                            \r
846                         }\r
847                         else if (aspectratioidc==255)\r
848                         {\r
849                             int t_sar_width=nalu.getBits(16);\r
850                             int t_sar_height=nalu.getBits(16);\r
851                             if (t_sar_width!=0 && t_sar_height!=0)\r
852                             {\r
853                                 hasaspect=true;\r
854                                 aspectratio*=((float)t_sar_width)/((float)t_sar_height);\r
855                             }\r
856                         }\r
857                         if (hasaspect)\r
858                         {\r
859                             if (fabs(aspectratio-16./9.)<0.1) setAspectRatio(ASPECT_16_9);\r
860                             else if (fabs(aspectratio-4./3.)<0.1) setAspectRatio(ASPECT_4_3);\r
861                         }\r
862                     }\r
863 \r
864                 }\r
865 \r
866             }\r
867            \r
868             if (vid_seeking)\r
869             {\r
870                 vid_seeking = 0;\r
871                 video_pts_seek = video_pts;\r
872                 Log::getInstance()->log("Demuxer", Log::DEBUG,\r
873                     "Entering audio sync: Video PTS = %llu", video_pts);\r
874                 Log::getInstance()->log("Demuxer", Log::DEBUG,\r
875                     "Entering audio sync: Audio PTS = %llu", audio_pts);\r
876             }\r
877             return;\r
878         } \r
879     }\r
880 }\r
881 \r
882 UINT Demuxer::stripAudio(UCHAR* buf, UINT len)\r
883 {\r
884   UINT read_pos = 0, write_pos = 0;\r
885   UINT pattern, packet_length;\r
886   if (len < 4) return 0;\r
887   pattern = (buf[0] << 16) | (buf[1] << 8) | (buf[2]);\r
888   while (read_pos + 7 <= len)\r
889   {\r
890     pattern = ((pattern & 0xFFFFFF) << 8) | buf[read_pos+3];\r
891     if (pattern < (0x100|PESTYPE_VID0) || pattern > (0x100|PESTYPE_VIDMAX))\r
892       read_pos++;\r
893     else\r
894     {\r
895       packet_length = ((buf[read_pos+4] << 8) | (buf[read_pos+5])) + 6;\r
896       if (read_pos + packet_length > len)\r
897         read_pos = len;\r
898       else\r
899       {\r
900         if (read_pos != write_pos)\r
901           memmove(buf+write_pos, buf+read_pos, packet_length);\r
902         read_pos += packet_length;\r
903         write_pos += packet_length;\r
904         pattern = (buf[read_pos] << 16) | (buf[read_pos+1] << 8)\r
905                                         | (buf[read_pos+2]);\r
906       }\r
907     }\r
908   }\r
909   return write_pos;\r
910 }\r
911 \r
912 void Demuxer::changeTimes(UCHAR* buf, UINT len,UINT playtime)\r
913 {\r
914         UINT pattern, packet_length;\r
915         UINT read_pos = 0;\r
916         if (len < 4) return;\r
917         pattern = (buf[0] << 16) | (buf[1] << 8) | (buf[2]);\r
918         while (read_pos + 7 <= len)\r
919         {\r
920            pattern = ((pattern & 0xFFFFFF) << 8) | buf[read_pos+3];\r
921            if (pattern < (0x100|PESTYPE_VID0) || pattern > (0x100|PESTYPE_VIDMAX))\r
922               read_pos++;\r
923            else\r
924            {\r
925               packet_length = ((buf[read_pos+4] << 8) | (buf[read_pos+5])) + 6;\r
926               // ok we have a packet figure out if pts and dts are present and replace them\r
927               if (read_pos + 19 > len) return;\r
928               ULLONG new_ts=playtime*90; //play time is on ms so multiply it by 90\r
929               if (buf[read_pos+7] & 0x80) { // pts is here, replace it\r
930                   buf[read_pos+9]=0x21 | (( new_ts>>29)& 0xde );\r
931                   buf[read_pos+10]=0x00 |(( new_ts>>22)& 0xff );\r
932                   buf[read_pos+11]=0x01 | (( new_ts>>14)& 0xfe );\r
933                   buf[read_pos+12]=0x00 | (( new_ts>>7)& 0xff );\r
934                   buf[read_pos+13]=0x01 | (( new_ts<<1)& 0xfe );\r
935               }\r
936 \r
937               if (buf[read_pos+7] & 0x40) { // pts is here, replace it\r
938                    buf[read_pos+14]=0x21 | (( new_ts>>29)& 0xde );\r
939                    buf[read_pos+15]=0x00 | (( new_ts>>22)& 0xff );\r
940                    buf[read_pos+16]=0x01 | (( new_ts>>14)& 0xfe );\r
941                    buf[read_pos+17]=0x00 | (( new_ts>>7)& 0xff );\r
942                    buf[read_pos+18]=0x01 | (( new_ts<<1)& 0xfe );\r
943               }\r
944               read_pos += packet_length;\r
945               pattern = (buf[read_pos] << 16) | (buf[read_pos+1] << 8)\r
946                                                 | (buf[read_pos+2]);\r
947               }\r
948           }\r
949 \r
950 }\r
951 \r
952 bool Demuxer::scanForVideo(UCHAR* buf, UINT len, bool &ish264)\r
953 {\r
954   UINT pos = 3;\r
955   UINT pattern;\r
956   ish264=false;\r
957   if (len < 4) return false;\r
958   pattern = (buf[0] << 16) | (buf[1] << 8) | (buf[2]);\r
959   while (pos < len)\r
960   {\r
961     pattern = ((pattern & 0xFFFFFF) << 8) | buf[pos++];\r
962     if (pattern >= (0x100|PESTYPE_VID0) && pattern <= (0x100|PESTYPE_VIDMAX))\r
963       return true;\r
964   }\r
965   return false;\r
966 }\r
967 \r
968 bool* Demuxer::getmpAudioChannels()\r
969 {\r
970   return avail_mpaudchan;\r
971 }\r
972 \r
973 bool* Demuxer::getac3AudioChannels()\r
974 {\r
975   return avail_ac3audchan;\r
976 }\r
977 \r
978 bool* Demuxer::getSubtitleChannels()\r
979 {\r
980   return avail_dvbsubtitlechan;\r
981 }\r
982 \r
983 int Demuxer::getselSubtitleChannel()\r
984 {\r
985   return subtitle_current;\r
986 }\r
987 \r
988 int Demuxer::getselAudioChannel()\r
989 {\r
990   return audio_current;\r
991 }\r
992 \r
993 \r