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