]> git.vomp.tv Git - vompclient.git/blob - demuxer.cc
Preparations for dynamic mode switching
[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   astreamtype=4;\r
429 }\r
430 \r
431 Demuxer::~Demuxer()\r
432 {\r
433   shutdown();\r
434   instance = NULL;\r
435 }\r
436 \r
437 Demuxer* Demuxer::getInstance()\r
438 {\r
439   return instance;\r
440 }\r
441 \r
442 int Demuxer::init(Callback* tcallback, DrainTarget* audio, DrainTarget* video, DrainTarget* teletext,\r
443                   ULONG demuxMemoryV, ULONG demuxMemoryA, ULONG demuxMemoryT,double infps, DVBSubtitles* tsubtitles)\r
444 {\r
445   if (!initted)\r
446   {\r
447     if ( !videostream.init(video, demuxMemoryV) ||\r
448          !audiostream.init(audio, demuxMemoryA) ||\r
449          !teletextstream.init(teletext, demuxMemoryT))\r
450     {\r
451       Log::getInstance()->log("Demuxer", Log::CRIT,\r
452                               "Failed to initialize demuxer");\r
453       shutdown();\r
454       return 0;\r
455     }\r
456   }\r
457   if (teletext) {\r
458       isteletextdecoded = true;\r
459   } else {\r
460       isteletextdecoded = false;\r
461   }\r
462   fps=infps;\r
463   reset();\r
464   initted = true;\r
465   subtitles = tsubtitles;\r
466   callback = tcallback;\r
467   return 1;\r
468 }\r
469 \r
470 void Demuxer::reset()\r
471 {\r
472   Log::getInstance()->log("Demuxer", Log::DEBUG, "Reset called");\r
473   flush();\r
474   video_current = audio_current = teletext_current = subtitle_current = -1;\r
475   horizontal_size = vertical_size = 0;\r
476   interlaced=true; // default is true\r
477   aspect_ratio = (enum AspectRatio) 0;\r
478   frame_rate = bit_rate = 0;\r
479   ispre_1_3_19 = false;\r
480   h264 = false;\r
481   packetnum=0;\r
482   astreamtype=4;\r
483 \r
484   for (int i = 0; i <= (PESTYPE_AUDMAX - PESTYPE_AUD0); i++)\r
485   {\r
486     avail_mpaudchan[i] = false;\r
487   }\r
488   for (int i = 0; i <= (PESTYPE_SUBSTREAM_AC3MAX - PESTYPE_SUBSTREAM_AC30); i++)\r
489   {\r
490     avail_ac3audchan[i] = false;\r
491   }\r
492   for (int i = 0; i <= (PESTYPE_SUBSTREAM_DVBSUBTITLEMAX - PESTYPE_SUBSTREAM_DVBSUBTITLE0); i++)\r
493   {\r
494     avail_dvbsubtitlechan[i] = false;\r
495   }\r
496 }\r
497 \r
498 int Demuxer::shutdown()\r
499 {\r
500   videostream.shutdown();\r
501   audiostream.shutdown();\r
502   teletextstream.shutdown();\r
503   initted = false;\r
504   return 1;\r
505 }\r
506 \r
507 void Demuxer::flush()\r
508 {\r
509   Log::getInstance()->log("Demuxer", Log::DEBUG, "Flush called");\r
510 \r
511   videostream.flush();\r
512   audiostream.flush();\r
513   teletextstream.flush();\r
514 }\r
515 \r
516 void Demuxer::flushAudio()\r
517 {\r
518   audiostream.flush();\r
519 }\r
520 \r
521 void Demuxer::seek()\r
522 {\r
523   vid_seeking = aud_seeking = true;\r
524   video_pts = audio_pts = teletext_pts = 0;\r
525 }\r
526 \r
527 void Demuxer::setAudioStream(int id)\r
528 {\r
529   audio_current = id;\r
530 }\r
531 \r
532 void Demuxer::setVideoStream(int id)\r
533 {\r
534   video_current = id;\r
535 }\r
536 \r
537 void Demuxer::setTeletextStream(int id)\r
538 {\r
539   teletext_current = id;\r
540 }\r
541 \r
542 void Demuxer::setDVBSubtitleStream(int id)\r
543 {\r
544   subtitle_current = id;\r
545 }\r
546 \r
547 void Demuxer::setAspectRatio(enum AspectRatio ar)\r
548 {\r
549   if (aspect_ratio != ar)\r
550   {\r
551     Log::getInstance()->log("Demux", Log::DEBUG,\r
552                             "Aspect ratio difference signalled");\r
553     if (++arcnt > 3) // avoid changing aspect ratio if glitch in signal\r
554     {\r
555       arcnt = 0;\r
556       aspect_ratio = ar;\r
557       if (callback) callback->call(this);\r
558     }\r
559   }\r
560   else\r
561     arcnt = 0;\r
562 }\r
563 \r
564 bool Demuxer::writeAudio(bool * dataavail)\r
565 {\r
566   return audiostream.drain(dataavail);\r
567 }\r
568 \r
569 bool Demuxer::writeVideo(bool * dataavail)\r
570 {\r
571   return videostream.drain(dataavail);\r
572 }\r
573 \r
574 bool Demuxer::writeTeletext(bool * dataavail)\r
575 {\r
576    return teletextstream.drain(dataavail);\r
577 }\r
578 \r
579 bool Demuxer::submitPacket(PESPacket& packet)\r
580 {\r
581   UINT sent = 0;\r
582   UCHAR packet_type = packet.getPacketType();\r
583   const UCHAR* packetdata = packet.getData();\r
584   if (packet_type >= PESTYPE_VID0 && packet_type <= PESTYPE_VIDMAX)\r
585   {\r
586     if (video_current == -1) video_current = packet_type;\r
587     if (video_current == packet_type && !vid_seeking)\r
588         {\r
589         sent = videostream.put(&packetdata[0], packet.getSize(), h264?MPTYPE_VIDEO_H264:MPTYPE_VIDEO_MPEG2,packetnum);\r
590         if (sent) packetnum++;\r
591         }\r
592         else\r
593       sent = packet.getSize();\r
594   }\r
595   else if (packet_type >= PESTYPE_AUD0 && packet_type <= PESTYPE_AUDMAX)\r
596   {\r
597 \r
598     if (audio_current == -1) audio_current = packet_type;\r
599     avail_mpaudchan[packet_type - PESTYPE_AUD0] = true;\r
600     if (audio_current == packet_type && !aud_seeking)\r
601         {\r
602       UCHAR type=MPTYPE_MPEG_AUDIO;\r
603       switch (astreamtype)\r
604       {\r
605       case 3:\r
606       case 4:\r
607           type=MPTYPE_MPEG_AUDIO; break;\r
608       case 0x11:\r
609           type=MPTYPE_AAC_LATM; break;\r
610       };\r
611       sent = audiostream.put(&packetdata[0], packet.getSize(), type,packetnum);\r
612           if (sent)  packetnum++;\r
613         }\r
614         else\r
615       sent = packet.getSize();\r
616   }\r
617   else if (packet_type == PESTYPE_PRIVATE_1 &&\r
618            packet.getSubstream() >= PESTYPE_SUBSTREAM_AC30 &&\r
619            packet.getSubstream() <= PESTYPE_SUBSTREAM_AC3MAX)\r
620   {\r
621     avail_ac3audchan[packet.getSubstream() - PESTYPE_SUBSTREAM_AC30] = true;\r
622     if (packet.getSubstream() == audio_current)\r
623     {\r
624       sent = audiostream.put(&packetdata[0], packet.getSize(), (ispre_1_3_19)? MPTYPE_AC3_PRE13 : MPTYPE_AC3,packetnum);\r
625           if (sent) packetnum++;\r
626     }\r
627     else\r
628     {\r
629       sent = packet.getSize();\r
630     }\r
631   }\r
632   else if (packet_type == PESTYPE_PRIVATE_1 &&\r
633            packet.getSubstream() >= PESTYPE_SUBSTREAM_DVBSUBTITLE0 &&\r
634            packet.getSubstream() <= PESTYPE_SUBSTREAM_DVBSUBTITLEMAX)\r
635   {\r
636     avail_dvbsubtitlechan[packet.getSubstream()-PESTYPE_SUBSTREAM_DVBSUBTITLE0]=true;\r
637     if (subtitle_current == -1) subtitle_current = packet.getSubstream();\r
638     if (subtitles && packet.getSubstream()==subtitle_current)\r
639     {\r
640          subtitles->put(packet);\r
641     }\r
642     sent = packet.getSize();\r
643   }\r
644   else if (isteletextdecoded  && packet_type == PESTYPE_PRIVATE_1 &&\r
645            packet.getSubstream() >= PESTYPE_SUBSTREAM_TELETEXT0 &&\r
646            packet.getSubstream() <= PESTYPE_SUBSTREAM_TELETEXTMAX)\r
647   {\r
648 \r
649     if (teletext_current == -1) teletext_current = packet.getSubstream();\r
650     if (teletext_current == packet.getSubstream())\r
651     {\r
652         sent = teletextstream.put(&packetdata[0], packet.getSize(), MPTYPE_TELETEXT,packetnum);\r
653     }\r
654     else \r
655     {\r
656         sent = packet.getSize();\r
657     }\r
658   }\r
659   else\r
660   {\r
661     sent = packet.getSize();\r
662   }\r
663 \r
664   if (sent < packet.getSize()) // Stream is full.\r
665     return false;\r
666   else\r
667     return true;\r
668 }\r
669 \r
670 void Demuxer::parsePacketDetails(PESPacket& packet)\r
671 {\r
672     if (packet.getPacketType() >= PESTYPE_AUD0 &&\r
673         packet.getPacketType() <= PESTYPE_AUDMAX)\r
674     {\r
675         // Extract audio PTS if it exists\r
676         if (packet.hasPTS())\r
677         {\r
678             audio_pts = packet.getPTS();\r
679             // We continue to seek on the audio if the video PTS that we\r
680             // are trying to match is ahead of the audio PTS by at most\r
681             // SEEK_THRESHOLD. We consider the possibility of PTS wrap.\r
682             if (aud_seeking && !vid_seeking &&\r
683                 !( (video_pts_seek > audio_pts &&\r
684                 video_pts_seek - audio_pts < SEEK_THRESHOLD)\r
685                 ||\r
686                 (video_pts_seek < audio_pts &&\r
687                 video_pts_seek + (1LL<<33) - audio_pts < SEEK_THRESHOLD) ))\r
688             {\r
689                 aud_seeking = 0;\r
690                 Log::getInstance()->log("Demuxer", Log::DEBUG,\r
691                     "Leaving  audio sync: Audio PTS = %llu", audio_pts);\r
692             }\r
693         }\r
694     }\r
695     else if (packet.getPacketType() == PESTYPE_PRIVATE_1) // Private stream\r
696     {\r
697         //Inspired by vdr's device.c\r
698         int payload_begin = packet[8]+9;\r
699         unsigned char substream_id = packet[payload_begin];\r
700         unsigned char substream_type = substream_id & 0xF0;\r
701         unsigned char substream_index = substream_id & 0x1F;\r
702 pre_1_3_19_Recording: //This is for old recordings stuff and live TV\r
703         if (ispre_1_3_19)\r
704         {\r
705                 int old_substream=packet.getSubstream();\r
706                 if (old_substream){ //someone else already set it, this is live tv\r
707                         substream_id = old_substream;\r
708                         substream_type = substream_id & 0xF0;\r
709                         substream_index = substream_id & 0x1F;\r
710                 } else {\r
711                 substream_id = PESTYPE_PRIVATE_1;\r
712                 substream_type = 0x80;\r
713                 substream_index = 0;\r
714                 }\r
715 \r
716         }\r
717         switch (substream_type)\r
718         {\r
719         case 0x20://SPU\r
720         case 0x30://SPU\r
721             packet.setSubstream(substream_id);\r
722             break;\r
723         case 0xA0: //LPCM //not supported yet, is there any LPCM transmissio out there?\r
724             break;\r
725         case 0x80: //ac3, currently only one ac3 track per recording supported\r
726             packet.setSubstream(substream_type+substream_index);\r
727 \r
728             // Extract audio PTS if it exists\r
729             if (packet.hasPTS())\r
730             {\r
731                 audio_pts = packet.getPTS();\r
732                 // We continue to seek on the audio if the video PTS that we\r
733                 // are trying to match is ahead of the audio PTS by at most\r
734                 // SEEK_THRESHOLD. We consider the possibility of PTS wrap.\r
735                 if (aud_seeking && !vid_seeking &&\r
736                     !( (video_pts_seek > audio_pts &&\r
737                     video_pts_seek - audio_pts < SEEK_THRESHOLD)\r
738                     ||\r
739                     (video_pts_seek < audio_pts &&\r
740                     video_pts_seek + (1LL<<33) - audio_pts < SEEK_THRESHOLD) ))\r
741                 {\r
742                     aud_seeking = 0;\r
743                     Log::getInstance()->log("Demuxer", Log::DEBUG, "Leaving  audio sync: Audio PTS = %llu", audio_pts);\r
744                 }\r
745             }\r
746             break;\r
747         case 0x10: //Teletext Is this correct?\r
748             packet.setSubstream(substream_id);\r
749             // Extract teletxt PTS if it exists\r
750             if (packet.hasPTS())\r
751             {\r
752                 teletext_pts = packet.getPTS();\r
753             }\r
754             break;\r
755         default:\r
756             if (!ispre_1_3_19)\r
757             {\r
758                 ispre_1_3_19=true; //switching to compat mode and live tv mode\r
759                 goto pre_1_3_19_Recording;\r
760             }\r
761             else\r
762             {\r
763                 packet.setSubstream(0);\r
764             }\r
765             break;\r
766         }\r
767     }\r
768     else if (packet.getPacketType() >= PESTYPE_VID0 &&\r
769         packet.getPacketType() <= PESTYPE_VIDMAX)\r
770     {\r
771         // Extract video PTS if it exists\r
772         if (packet.hasPTS()) video_pts = packet.getPTS();\r
773 \r
774         // If there is a sequence header, extract information\r
775         UINT pos = packet.findSeqHeader(h264);\r
776         if (pos > 1)\r
777         {\r
778             if (!h264) {\r
779                 pos += 4;\r
780                 if (pos+6 >= packet.getSize()) return;\r
781                 horizontal_size = ((int)packet[pos] << 4) | ((int)packet[pos+1] >> 4);\r
782                 \r
783                 vertical_size = (((int)packet[pos+1] & 0xf) << 8) | (int)packet[pos+2];\r
784 \r
785                 setAspectRatio((enum AspectRatio)(packet[pos+3] >> 4));\r
786                 frame_rate = packet[pos+3] & 0x0f;\r
787                 if (frame_rate >= 1 && frame_rate <= 8)\r
788                     frame_rate = FrameRates[frame_rate];\r
789                 else\r
790                     frame_rate = 0;\r
791                 bit_rate = ((int)packet[pos+4] << 10) |\r
792                     ((int)packet[pos+5] << 2) |\r
793                     ((int)packet[pos+6] >> 6);\r
794             } \r
795             else\r
796             {\r
797                 /* 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
798                 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
799                 NALUUnit nalu(packet.getData()+pos,packet.getSize()-pos);\r
800                 profile=nalu.getBits(8);\r
801                 nalu.getBits(8); //constraints\r
802                 nalu.getBits(8); //level_idc\r
803                 nalu.getUe(); //seq_parameter_set_id\r
804                 int chroma=1;\r
805                 if (profile==100 || profile==110 || profile==122 || profile==144)\r
806                 {\r
807                     chroma=nalu.getUe();\r
808                     if (chroma==3)\r
809                     {\r
810                         nalu.getBits(1);\r
811                     }\r
812                     nalu.getUe(); //bit depth lume\r
813                     nalu.getUe(); //bit depth chrome\r
814                     nalu.getBits(1);\r
815                     if (nalu.getBits(1))\r
816                     {\r
817                         for (int i=0;i<8;i++){\r
818                             if (nalu.getBits(1))\r
819                             {\r
820                                 if (i<6)\r
821                                 {\r
822                                     UINT lastscale=8;\r
823                                     UINT nextscale=8;\r
824                                     for (int j=0;j<16;j++) {\r
825                                         if (nextscale!=0) {\r
826                                             UINT delta=nalu.getSe();\r
827                                             nextscale=(lastscale+delta+256)%256;\r
828                                         }\r
829                                         lastscale=(nextscale==0)?lastscale:nextscale;\r
830                                     }\r
831                                 }\r
832                                 else\r
833                                 {\r
834                                     UINT lastscale=8;\r
835                                     UINT nextscale=8;\r
836                                     for (int j=0;j<64;j++) {\r
837                                         if (nextscale!=0) {\r
838                                             UINT delta=nalu.getSe();\r
839                                             nextscale=(lastscale+delta+256)%256;\r
840                                         }\r
841                                         lastscale=(nextscale==0)?lastscale:nextscale;\r
842                                     }\r
843                                 }\r
844                             }\r
845                         }\r
846                     }\r
847                 }\r
848                 int chromunitx=1;\r
849                 int chromunity=1;\r
850                 switch (chroma) {\r
851                 case 0:\r
852                     chromunitx=chromunity=1; break;\r
853                 case 1:\r
854                     chromunitx=chromunity=2; break;\r
855                 case 2:\r
856                     chromunitx=2;chromunity=1; break;\r
857                 case 3:\r
858                     chromunitx=chromunity=1; break;\r
859                 };\r
860 \r
861                 nalu.getUe(); //log2framenum\r
862                 UINT temp=nalu.getUe();\r
863                 if (temp==0) //pict order\r
864                     nalu.getUe();\r
865                 else if (temp==1) {\r
866                     nalu.getBits(1);\r
867                     nalu.getSe();\r
868                     nalu.getSe();\r
869                     UINT temp2=nalu.getUe();\r
870                     for (int i=0;i<temp2;i++)\r
871                         nalu.getSe();\r
872                 }\r
873                 nalu.getUe(); //Num refframes\r
874                 nalu.getBits(1);\r
875                 horizontal_size=(nalu.getUe()+1)*16;\r
876                 \r
877                 vertical_size=(nalu.getUe()+1)*16;\r
878                 int tinterlaced=nalu.getBits(1);\r
879                 vertical_size*=(2-tinterlaced);\r
880                 interlaced=!tinterlaced;\r
881                 \r
882                 if (!tinterlaced) nalu.getBits(1);\r
883                 nalu.getBits(1);\r
884                 if (nalu.getBits(1))\r
885                 {\r
886                     horizontal_size-=nalu.getUe()*chromunitx;\r
887                     horizontal_size-=nalu.getUe()*chromunitx;\r
888                     vertical_size-=nalu.getUe()*(2-tinterlaced)*chromunity;\r
889                     vertical_size-=nalu.getUe()*(2-tinterlaced)*chromunity;\r
890                 }\r
891                 if (nalu.getBits(1))\r
892                 {\r
893                     if (nalu.getBits(1))\r
894                     {\r
895                         UINT aspectratioidc=nalu.getBits(8);\r
896                         bool hasaspect=false;\r
897                         const float aspects[]={1., 1./1.,12./11.,10./11.,16./11.,40./33.,\r
898                             24./11.,20./11.,32./11.,80./33.,18./11.,15./11.,64./33.,160./99.,4./3.,3./2.,2./1.};\r
899                       \r
900                         float aspectratio=((float) horizontal_size)/((float) vertical_size);\r
901                         if (aspectratioidc<=16) \r
902                         {\r
903                             hasaspect=true;\r
904                             aspectratio*=aspects[aspectratioidc];\r
905                            \r
906                         }\r
907                         else if (aspectratioidc==255)\r
908                         {\r
909                             int t_sar_width=nalu.getBits(16);\r
910                             int t_sar_height=nalu.getBits(16);\r
911                             if (t_sar_width!=0 && t_sar_height!=0)\r
912                             {\r
913                                 hasaspect=true;\r
914                                 aspectratio*=((float)t_sar_width)/((float)t_sar_height);\r
915                             }\r
916                         }\r
917                         if (hasaspect)\r
918                         {\r
919                             if (fabs(aspectratio-16./9.)<0.1) setAspectRatio(ASPECT_16_9);\r
920                             else if (fabs(aspectratio-4./3.)<0.1) setAspectRatio(ASPECT_4_3);\r
921                         }\r
922                     }\r
923 \r
924                 }\r
925 \r
926             }\r
927             UINT posext = packet.findSeqExtHeader(h264);\r
928             if (posext>1) {\r
929                 if (!h264) {\r
930                         interlaced=!(packet[pos+1] & 0x08); //really simple\r
931                         // if more than full hd is coming we need to add additional parsers here\r
932                 } else {\r
933                 /*      NALUUnit nalu(packet.getData()+posext,packet.getSize()-posext);\r
934                         while (!nalu.isEonalu()) {\r
935                                 unsigned int payloadtype=0;\r
936                                 unsigned int payloadadd=0xFF;\r
937                                 while (payloadadd==0xFF && !nalu.isEonalu()) {\r
938                                         payloadadd=nalu.getBits(8);\r
939                                         payloadtype+=payloadadd;\r
940                                 }\r
941                                 unsigned int payloadsize=0;\r
942                                 payloadadd=0xff;\r
943                                 while (payloadadd==0xFF && !nalu.isEonalu()) {\r
944                                        payloadadd=nalu.getBits(8);\r
945                                        payloadsize+=payloadadd;\r
946                             }\r
947                                 switch (payloadtype) {\r
948                                 case 1: { // picture timing SEI\r
949 \r
950                                 } break;\r
951                                 default: {\r
952                                         while (payloadsize) { // not handled skip\r
953                                                 nalu.getBits(8);\r
954                                                 payloadsize--;\r
955                                         }\r
956                                 } break;\r
957                                 }\r
958 \r
959 \r
960 \r
961                         }*/\r
962 \r
963 \r
964                 }\r
965             }\r
966            \r
967             if (vid_seeking)\r
968             {\r
969                 vid_seeking = 0;\r
970                 video_pts_seek = video_pts;\r
971                 Log::getInstance()->log("Demuxer", Log::DEBUG,\r
972                     "Entering audio sync: Video PTS = %llu", video_pts);\r
973                 Log::getInstance()->log("Demuxer", Log::DEBUG,\r
974                     "Entering audio sync: Audio PTS = %llu", audio_pts);\r
975             }\r
976             return;\r
977         } \r
978     }\r
979 }\r
980 \r
981 UINT Demuxer::stripAudio(UCHAR* buf, UINT len)\r
982 {\r
983   UINT read_pos = 0, write_pos = 0;\r
984   UINT pattern, packet_length;\r
985   if (len < 4) return 0;\r
986   pattern = (buf[0] << 16) | (buf[1] << 8) | (buf[2]);\r
987   while (read_pos + 7 <= len)\r
988   {\r
989     pattern = ((pattern & 0xFFFFFF) << 8) | buf[read_pos+3];\r
990     if (pattern < (0x100|PESTYPE_VID0) || pattern > (0x100|PESTYPE_VIDMAX))\r
991       read_pos++;\r
992     else\r
993     {\r
994       packet_length = ((buf[read_pos+4] << 8) | (buf[read_pos+5])) + 6;\r
995       if (read_pos + packet_length > len)\r
996         read_pos = len;\r
997       else\r
998       {\r
999         if (read_pos != write_pos)\r
1000           memmove(buf+write_pos, buf+read_pos, packet_length);\r
1001         read_pos += packet_length;\r
1002         write_pos += packet_length;\r
1003         pattern = (buf[read_pos] << 16) | (buf[read_pos+1] << 8)\r
1004                                         | (buf[read_pos+2]);\r
1005       }\r
1006     }\r
1007   }\r
1008   return write_pos;\r
1009 }\r
1010 \r
1011 void Demuxer::changeTimes(UCHAR* buf, UINT len,UINT playtime)\r
1012 {\r
1013         UINT pattern, packet_length;\r
1014         UINT read_pos = 0;\r
1015         if (len < 4) return;\r
1016         pattern = (buf[0] << 16) | (buf[1] << 8) | (buf[2]);\r
1017         while (read_pos + 7 <= len)\r
1018         {\r
1019            pattern = ((pattern & 0xFFFFFF) << 8) | buf[read_pos+3];\r
1020            if (pattern < (0x100|PESTYPE_VID0) || pattern > (0x100|PESTYPE_VIDMAX))\r
1021               read_pos++;\r
1022            else\r
1023            {\r
1024               packet_length = ((buf[read_pos+4] << 8) | (buf[read_pos+5])) + 6;\r
1025               // ok we have a packet figure out if pts and dts are present and replace them\r
1026               if (read_pos + 19 > len) return;\r
1027               ULLONG new_ts=playtime*90; //play time is on ms so multiply it by 90\r
1028               if (buf[read_pos+7] & 0x80) { // pts is here, replace it\r
1029                   buf[read_pos+9]=0x21 | (( new_ts>>29)& 0xde );\r
1030                   buf[read_pos+10]=0x00 |(( new_ts>>22)& 0xff );\r
1031                   buf[read_pos+11]=0x01 | (( new_ts>>14)& 0xfe );\r
1032                   buf[read_pos+12]=0x00 | (( new_ts>>7)& 0xff );\r
1033                   buf[read_pos+13]=0x01 | (( new_ts<<1)& 0xfe );\r
1034               }\r
1035 \r
1036               if (buf[read_pos+7] & 0x40) { // pts is here, replace it\r
1037                    buf[read_pos+14]=0x21 | (( new_ts>>29)& 0xde );\r
1038                    buf[read_pos+15]=0x00 | (( new_ts>>22)& 0xff );\r
1039                    buf[read_pos+16]=0x01 | (( new_ts>>14)& 0xfe );\r
1040                    buf[read_pos+17]=0x00 | (( new_ts>>7)& 0xff );\r
1041                    buf[read_pos+18]=0x01 | (( new_ts<<1)& 0xfe );\r
1042               }\r
1043               read_pos += packet_length;\r
1044               pattern = (buf[read_pos] << 16) | (buf[read_pos+1] << 8)\r
1045                                                 | (buf[read_pos+2]);\r
1046               }\r
1047           }\r
1048 \r
1049 }\r
1050 \r
1051 bool Demuxer::scanForVideo(UCHAR* buf, UINT len, bool &ish264)\r
1052 {\r
1053   UINT pos = 3;\r
1054   UINT pattern;\r
1055   ish264=false;\r
1056   if (len < 4) return false;\r
1057   pattern = (buf[0] << 16) | (buf[1] << 8) | (buf[2]);\r
1058   while (pos < len)\r
1059   {\r
1060     pattern = ((pattern & 0xFFFFFF) << 8) | buf[pos++];\r
1061     if (pattern >= (0x100|PESTYPE_VID0) && pattern <= (0x100|PESTYPE_VIDMAX))\r
1062       return true;\r
1063   }\r
1064   return false;\r
1065 }\r
1066 \r
1067 bool* Demuxer::getmpAudioChannels()\r
1068 {\r
1069   return avail_mpaudchan;\r
1070 }\r
1071 \r
1072 bool* Demuxer::getac3AudioChannels()\r
1073 {\r
1074   return avail_ac3audchan;\r
1075 }\r
1076 \r
1077 bool* Demuxer::getSubtitleChannels()\r
1078 {\r
1079   return avail_dvbsubtitlechan;\r
1080 }\r
1081 \r
1082 int Demuxer::getselSubtitleChannel()\r
1083 {\r
1084   return subtitle_current;\r
1085 }\r
1086 \r
1087 int Demuxer::getselAudioChannel()\r
1088 {\r
1089   return audio_current;\r
1090 }\r
1091 \r
1092 \r