]> git.vomp.tv Git - vompclient.git/blob - demuxer.cc
Fix major Bug in demuxer, fix audio playback on some channels
[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 \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(bool * dataavail)\r
523 {\r
524   return audiostream.drain(dataavail);\r
525 }\r
526 \r
527 bool Demuxer::writeVideo(bool * dataavail)\r
528 {\r
529   return videostream.drain(dataavail);\r
530 }\r
531 \r
532 bool Demuxer::writeTeletext(bool * dataavail)\r
533 {\r
534    return teletextstream.drain(dataavail);\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                 int old_substream=packet.getSubstream();\r
655                 if (old_substream){ //someone else already set it, this is live tv\r
656                         substream_id = old_substream;\r
657                         substream_type = substream_id & 0xF0;\r
658                         substream_index = substream_id & 0x1F;\r
659                 } else {\r
660                 substream_id = PESTYPE_PRIVATE_1;\r
661                 substream_type = 0x80;\r
662                 substream_index = 0;\r
663                 }\r
664 \r
665         }\r
666         switch (substream_type)\r
667         {\r
668         case 0x20://SPU\r
669         case 0x30://SPU\r
670             packet.setSubstream(substream_id);\r
671             break;\r
672         case 0xA0: //LPCM //not supported yet, is there any LPCM transmissio out there?\r
673             break;\r
674         case 0x80: //ac3, currently only one ac3 track per recording supported\r
675             packet.setSubstream(substream_type+substream_index);\r
676 \r
677             // Extract audio PTS if it exists\r
678             if (packet.hasPTS())\r
679             {\r
680                 audio_pts = packet.getPTS();\r
681                 // We continue to seek on the audio if the video PTS that we\r
682                 // are trying to match is ahead of the audio PTS by at most\r
683                 // SEEK_THRESHOLD. We consider the possibility of PTS wrap.\r
684                 if (aud_seeking && !vid_seeking &&\r
685                     !( (video_pts_seek > audio_pts &&\r
686                     video_pts_seek - audio_pts < SEEK_THRESHOLD)\r
687                     ||\r
688                     (video_pts_seek < audio_pts &&\r
689                     video_pts_seek + (1LL<<33) - audio_pts < SEEK_THRESHOLD) ))\r
690                 {\r
691                     aud_seeking = 0;\r
692                     Log::getInstance()->log("Demuxer", Log::DEBUG, "Leaving  audio sync: Audio PTS = %llu", audio_pts);\r
693                 }\r
694             }\r
695             break;\r
696         case 0x10: //Teletext Is this correct?\r
697             packet.setSubstream(substream_id);\r
698             // Extract teletxt PTS if it exists\r
699             if (packet.hasPTS())\r
700             {\r
701                 teletext_pts = packet.getPTS();\r
702             }\r
703             break;\r
704         default:\r
705             if (!ispre_1_3_19)\r
706             {\r
707                 ispre_1_3_19=true; //switching to compat mode and live tv mode\r
708                 goto pre_1_3_19_Recording;\r
709             }\r
710             else\r
711             {\r
712                 packet.setSubstream(0);\r
713             }\r
714             break;\r
715         }\r
716     }\r
717     else if (packet.getPacketType() >= PESTYPE_VID0 &&\r
718         packet.getPacketType() <= PESTYPE_VIDMAX)\r
719     {\r
720         // Extract video PTS if it exists\r
721         if (packet.hasPTS()) video_pts = packet.getPTS();\r
722 \r
723         // If there is a sequence header, extract information\r
724         UINT pos = packet.findSeqHeader(h264);\r
725         if (pos > 1)\r
726         {\r
727             if (!h264) {\r
728                 pos += 4;\r
729                 if (pos+6 >= packet.getSize()) return;\r
730                 horizontal_size = ((int)packet[pos] << 4) | ((int)packet[pos+1] >> 4);\r
731                 \r
732                 vertical_size = (((int)packet[pos+1] & 0xf) << 8) | (int)packet[pos+2];\r
733 \r
734                 setAspectRatio((enum AspectRatio)(packet[pos+3] >> 4));\r
735                 frame_rate = packet[pos+3] & 0x0f;\r
736                 if (frame_rate >= 1 && frame_rate <= 8)\r
737                     frame_rate = FrameRates[frame_rate];\r
738                 else\r
739                     frame_rate = 0;\r
740                 bit_rate = ((int)packet[pos+4] << 10) |\r
741                     ((int)packet[pos+5] << 2) |\r
742                     ((int)packet[pos+6] >> 6);\r
743             } \r
744             else\r
745             {\r
746                 /* 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
747                 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
748                 NALUUnit nalu(packet.getData()+pos,packet.getSize()-pos);\r
749                 profile=nalu.getBits(8);\r
750                 nalu.getBits(8); //constraints\r
751                 nalu.getBits(8); //level_idc\r
752                 nalu.getUe(); //seq_parameter_set_id\r
753                 int chroma=1;\r
754                 if (profile==100 || profile==110 || profile==122 || profile==144)\r
755                 {\r
756                     chroma=nalu.getUe();\r
757                     if (chroma==3)\r
758                     {\r
759                         nalu.getBits(1);\r
760                     }\r
761                     nalu.getUe(); //bit depth lume\r
762                     nalu.getUe(); //bit depth chrome\r
763                     nalu.getBits(1);\r
764                     if (nalu.getBits(1))\r
765                     {\r
766                         for (int i=0;i<8;i++){\r
767                             if (nalu.getBits(1))\r
768                             {\r
769                                 if (i<6)\r
770                                 {\r
771                                     UINT lastscale=8;\r
772                                     UINT nextscale=8;\r
773                                     for (int j=0;j<16;j++) {\r
774                                         if (nextscale!=0) {\r
775                                             UINT delta=nalu.getSe();\r
776                                             nextscale=(lastscale+delta+256)%256;\r
777                                         }\r
778                                         lastscale=(nextscale==0)?lastscale:nextscale;\r
779                                     }\r
780                                 }\r
781                                 else\r
782                                 {\r
783                                     UINT lastscale=8;\r
784                                     UINT nextscale=8;\r
785                                     for (int j=0;j<64;j++) {\r
786                                         if (nextscale!=0) {\r
787                                             UINT delta=nalu.getSe();\r
788                                             nextscale=(lastscale+delta+256)%256;\r
789                                         }\r
790                                         lastscale=(nextscale==0)?lastscale:nextscale;\r
791                                     }\r
792                                 }\r
793                             }\r
794                         }\r
795                     }\r
796                 }\r
797                 int chromunitx=1;\r
798                 int chromunity=1;\r
799                 switch (chroma) {\r
800                 case 0:\r
801                     chromunitx=chromunity=1; break;\r
802                 case 1:\r
803                     chromunitx=chromunity=2; break;\r
804                 case 2:\r
805                     chromunitx=2;chromunity=1; break;\r
806                 case 3:\r
807                     chromunitx=chromunity=1; break;\r
808                 };\r
809 \r
810                 nalu.getUe(); //log2framenum\r
811                 UINT temp=nalu.getUe();\r
812                 if (temp==0) //pict order\r
813                     nalu.getUe();\r
814                 else if (temp==1) {\r
815                     nalu.getBits(1);\r
816                     nalu.getSe();\r
817                     nalu.getSe();\r
818                     UINT temp2=nalu.getUe();\r
819                     for (int i=0;i<temp2;i++)\r
820                         nalu.getSe();\r
821                 }\r
822                 nalu.getUe(); //Num refframes\r
823                 nalu.getBits(1);\r
824                 horizontal_size=(nalu.getUe()+1)*16;\r
825                 \r
826                 vertical_size=(nalu.getUe()+1)*16;\r
827                 int interlaced=nalu.getBits(1);\r
828                 vertical_size*=(2-interlaced);\r
829                 \r
830                 if (!interlaced) nalu.getBits(1);\r
831                 nalu.getBits(1);\r
832                 if (nalu.getBits(1))\r
833                 {\r
834                     horizontal_size-=nalu.getUe()*chromunitx;\r
835                     horizontal_size-=nalu.getUe()*chromunitx;\r
836                     vertical_size-=nalu.getUe()*(2-interlaced)*chromunity;\r
837                     vertical_size-=nalu.getUe()*(2-interlaced)*chromunity;\r
838                 }\r
839                 if (nalu.getBits(1))\r
840                 {\r
841                     if (nalu.getBits(1))\r
842                     {\r
843                         UINT aspectratioidc=nalu.getBits(8);\r
844                         bool hasaspect=false;\r
845                         const float aspects[]={1., 1./1.,12./11.,10./11.,16./11.,40./33.,\r
846                             24./11.,20./11.,32./11.,80./33.,18./11.,15./11.,64./33.,160./99.,4./3.,3./2.,2./1.};\r
847                       \r
848                         float aspectratio=((float) horizontal_size)/((float) vertical_size);\r
849                         if (aspectratioidc<=16) \r
850                         {\r
851                             hasaspect=true;\r
852                             aspectratio*=aspects[aspectratioidc];\r
853                            \r
854                         }\r
855                         else if (aspectratioidc==255)\r
856                         {\r
857                             int t_sar_width=nalu.getBits(16);\r
858                             int t_sar_height=nalu.getBits(16);\r
859                             if (t_sar_width!=0 && t_sar_height!=0)\r
860                             {\r
861                                 hasaspect=true;\r
862                                 aspectratio*=((float)t_sar_width)/((float)t_sar_height);\r
863                             }\r
864                         }\r
865                         if (hasaspect)\r
866                         {\r
867                             if (fabs(aspectratio-16./9.)<0.1) setAspectRatio(ASPECT_16_9);\r
868                             else if (fabs(aspectratio-4./3.)<0.1) setAspectRatio(ASPECT_4_3);\r
869                         }\r
870                     }\r
871 \r
872                 }\r
873 \r
874             }\r
875            \r
876             if (vid_seeking)\r
877             {\r
878                 vid_seeking = 0;\r
879                 video_pts_seek = video_pts;\r
880                 Log::getInstance()->log("Demuxer", Log::DEBUG,\r
881                     "Entering audio sync: Video PTS = %llu", video_pts);\r
882                 Log::getInstance()->log("Demuxer", Log::DEBUG,\r
883                     "Entering audio sync: Audio PTS = %llu", audio_pts);\r
884             }\r
885             return;\r
886         } \r
887     }\r
888 }\r
889 \r
890 UINT Demuxer::stripAudio(UCHAR* buf, UINT len)\r
891 {\r
892   UINT read_pos = 0, write_pos = 0;\r
893   UINT pattern, packet_length;\r
894   if (len < 4) return 0;\r
895   pattern = (buf[0] << 16) | (buf[1] << 8) | (buf[2]);\r
896   while (read_pos + 7 <= len)\r
897   {\r
898     pattern = ((pattern & 0xFFFFFF) << 8) | buf[read_pos+3];\r
899     if (pattern < (0x100|PESTYPE_VID0) || pattern > (0x100|PESTYPE_VIDMAX))\r
900       read_pos++;\r
901     else\r
902     {\r
903       packet_length = ((buf[read_pos+4] << 8) | (buf[read_pos+5])) + 6;\r
904       if (read_pos + packet_length > len)\r
905         read_pos = len;\r
906       else\r
907       {\r
908         if (read_pos != write_pos)\r
909           memmove(buf+write_pos, buf+read_pos, packet_length);\r
910         read_pos += packet_length;\r
911         write_pos += packet_length;\r
912         pattern = (buf[read_pos] << 16) | (buf[read_pos+1] << 8)\r
913                                         | (buf[read_pos+2]);\r
914       }\r
915     }\r
916   }\r
917   return write_pos;\r
918 }\r
919 \r
920 void Demuxer::changeTimes(UCHAR* buf, UINT len,UINT playtime)\r
921 {\r
922         UINT pattern, packet_length;\r
923         UINT read_pos = 0;\r
924         if (len < 4) return;\r
925         pattern = (buf[0] << 16) | (buf[1] << 8) | (buf[2]);\r
926         while (read_pos + 7 <= len)\r
927         {\r
928            pattern = ((pattern & 0xFFFFFF) << 8) | buf[read_pos+3];\r
929            if (pattern < (0x100|PESTYPE_VID0) || pattern > (0x100|PESTYPE_VIDMAX))\r
930               read_pos++;\r
931            else\r
932            {\r
933               packet_length = ((buf[read_pos+4] << 8) | (buf[read_pos+5])) + 6;\r
934               // ok we have a packet figure out if pts and dts are present and replace them\r
935               if (read_pos + 19 > len) return;\r
936               ULLONG new_ts=playtime*90; //play time is on ms so multiply it by 90\r
937               if (buf[read_pos+7] & 0x80) { // pts is here, replace it\r
938                   buf[read_pos+9]=0x21 | (( new_ts>>29)& 0xde );\r
939                   buf[read_pos+10]=0x00 |(( new_ts>>22)& 0xff );\r
940                   buf[read_pos+11]=0x01 | (( new_ts>>14)& 0xfe );\r
941                   buf[read_pos+12]=0x00 | (( new_ts>>7)& 0xff );\r
942                   buf[read_pos+13]=0x01 | (( new_ts<<1)& 0xfe );\r
943               }\r
944 \r
945               if (buf[read_pos+7] & 0x40) { // pts is here, replace it\r
946                    buf[read_pos+14]=0x21 | (( new_ts>>29)& 0xde );\r
947                    buf[read_pos+15]=0x00 | (( new_ts>>22)& 0xff );\r
948                    buf[read_pos+16]=0x01 | (( new_ts>>14)& 0xfe );\r
949                    buf[read_pos+17]=0x00 | (( new_ts>>7)& 0xff );\r
950                    buf[read_pos+18]=0x01 | (( new_ts<<1)& 0xfe );\r
951               }\r
952               read_pos += packet_length;\r
953               pattern = (buf[read_pos] << 16) | (buf[read_pos+1] << 8)\r
954                                                 | (buf[read_pos+2]);\r
955               }\r
956           }\r
957 \r
958 }\r
959 \r
960 bool Demuxer::scanForVideo(UCHAR* buf, UINT len, bool &ish264)\r
961 {\r
962   UINT pos = 3;\r
963   UINT pattern;\r
964   ish264=false;\r
965   if (len < 4) return false;\r
966   pattern = (buf[0] << 16) | (buf[1] << 8) | (buf[2]);\r
967   while (pos < len)\r
968   {\r
969     pattern = ((pattern & 0xFFFFFF) << 8) | buf[pos++];\r
970     if (pattern >= (0x100|PESTYPE_VID0) && pattern <= (0x100|PESTYPE_VIDMAX))\r
971       return true;\r
972   }\r
973   return false;\r
974 }\r
975 \r
976 bool* Demuxer::getmpAudioChannels()\r
977 {\r
978   return avail_mpaudchan;\r
979 }\r
980 \r
981 bool* Demuxer::getac3AudioChannels()\r
982 {\r
983   return avail_ac3audchan;\r
984 }\r
985 \r
986 bool* Demuxer::getSubtitleChannels()\r
987 {\r
988   return avail_dvbsubtitlechan;\r
989 }\r
990 \r
991 int Demuxer::getselSubtitleChannel()\r
992 {\r
993   return subtitle_current;\r
994 }\r
995 \r
996 int Demuxer::getselAudioChannel()\r
997 {\r
998   return audio_current;\r
999 }\r
1000 \r
1001 \r