2 Copyright 2005-2008 Mark Calderbank
\r
3 Copyright 2007 Marten Richter (AC3 support)
\r
5 This file is part of VOMP.
\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
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
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
22 #include "demuxer.h"
\r
24 #include "callback.h"
\r
25 #include "dvbsubtitles.h"
\r
32 #define DEMUXER_SEQ_HEAD 0x000001B3
\r
33 #define DEMUXER_PIC_HEAD 0x00000101
\r
35 #define DEMUXER_H264_ACCESS_UNIT 0x00000109
\r
36 #define DEMUXER_H264_SEQ_PARAMETER_SET 0x00000107
\r
39 #define SEEK_THRESHOLD 150000 // About 1.5 seconds
\r
42 const int Demuxer::FrameRates[9] = { 0, 23, 24, 25, 29, 30, 50, 59, 60 };
\r
43 Demuxer* Demuxer::instance = NULL;
\r
47 NALUUnit(const UCHAR* buf,UINT length_buf);
\r
50 inline UINT getBits(UINT num_bits);
\r
53 bool isEonalu() {return eonalu;};
\r
65 NALUUnit::NALUUnit(const UCHAR *buf, UINT length_buf)
\r
77 UINT pattern =(((UINT)buf[ 0] << 16) |
\r
78 ((UINT)buf[1] << 8) |
\r
81 while (pattern != 0x000001)
\r
83 if (++nalu_start >= length_buf) return;
\r
84 pattern = ((pattern << 8) | buf[nalu_start])&0x00FFFFFF;
\r
86 nalu_end=nalu_start+1;
\r
87 pattern = ((pattern << 8) | buf[nalu_end])&0x00FFFFFF;
\r
89 while (pattern != 0x000001 && pattern != 0x000000)
\r
91 if (++nalu_end >= length_buf) { nalu_end+=3;break;};
\r
92 pattern = ((pattern << 8) | buf[nalu_end])&0x00FFFFFF;
\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
102 NALUUnit::~NALUUnit()
\r
104 if (nalu_buf) free(nalu_buf);
\r
107 inline UINT NALUUnit::getBits(UINT num_bits)
\r
109 if (num_bits==0) return 0; //???
\r
110 UINT remain_bits=num_bits;
\r
112 //May be slow, but should work!
\r
113 while (remain_bits>0) {
\r
115 if (pos<nalu_length)
\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
121 working_byte=nalu_buf[pos];
\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
147 UINT NALUUnit::getUe()
\r
151 for( bit = 0; !bit && !eonalu; leadbits++ )
\r
153 if (eonalu) return true;
\r
154 return ((1 << leadbits)-1)+getBits(leadbits);
\r
157 int NALUUnit::getSe()
\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
168 static const int PESPacket_initial_size = 2000;
\r
170 // PESPacket methods
\r
171 PESPacket::PESPacket()
\r
173 data_size = PESPacket_initial_size;
\r
174 data = (UCHAR*)malloc(data_size);
\r
181 PESPacket::PESPacket(const PESPacket& packet)
\r
186 PESPacket& PESPacket::operator=(const PESPacket& packet)
\r
188 if (this != &packet)
\r
190 if (data) free(data);
\r
196 PESPacket::~PESPacket()
\r
198 if (data) free(data);
\r
201 void PESPacket::copyFrom(const PESPacket& packet)
\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
209 data = (UCHAR*)malloc(data_size);
\r
210 memcpy(data, packet.data, data_size);
\r
213 void PESPacket::init(UCHAR type, UCHAR sub)
\r
217 data[4] = data[5] = 0;
\r
221 seq_header = 1; // Unknown seq_header status
\r
225 void PESPacket::truncate()
\r
227 init(packetType,substream);
\r
232 int PESPacket::write(const UCHAR *buf, int len)
\r
236 if (size + len > 0x10000) return 0;
\r
237 if (size + len > data_size)
\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
244 memcpy(data + size, buf, 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
254 ULLONG PESPacket::getPTS() const
\r
256 if ( ( (packetType >= Demuxer::PESTYPE_AUD0 &&
\r
257 packetType <= Demuxer::PESTYPE_AUDMAX)
\r
259 (packetType >= Demuxer::PESTYPE_VID0 &&
\r
260 packetType <= Demuxer::PESTYPE_VIDMAX)
\r
262 packetType == Demuxer::PESTYPE_PRIVATE_1
\r
264 && size >= 14 && data[7] & 0x80)
\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
272 else return PTS_INVALID;
\r
275 UCHAR PESPacket::operator[] (UINT index) const
\r
280 return data[index];
\r
283 UINT PESPacket::findPictureHeader(bool h264) const
\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
293 while (pattern != DEMUXER_H264_ACCESS_UNIT)
\r
295 if (++pos >= size) return 0;
\r
296 pattern = (pattern << 8) | data[pos];
\r
300 while (pattern != DEMUXER_PIC_HEAD)
\r
302 if (++pos >= size) return 0;
\r
303 pattern = (pattern << 8) | data[pos];
\r
309 UINT PESPacket::countPictureHeaders(bool h264) const
\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
323 pattern = (pattern << 8) | data[pos];
\r
324 if (pattern==DEMUXER_H264_ACCESS_UNIT) count++;
\r
331 pattern = (pattern << 8) | data[pos];
\r
332 if (pattern==DEMUXER_PIC_HEAD) count++;
\r
338 UINT PESPacket::findSeqHeader(bool h264) const
\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
348 while ((pattern & 0xFFFFFF1F) != DEMUXER_H264_SEQ_PARAMETER_SET)
\r
355 pattern = (pattern << 8) | data[pos];
\r
357 seq_header = pos - 3;
\r
361 while (pattern != DEMUXER_SEQ_HEAD)
\r
368 pattern = (pattern << 8) | data[pos];
\r
370 seq_header = pos - 3;
\r
378 if (instance) return;
\r
383 vid_seeking = aud_seeking = false;
\r
384 video_pts = audio_pts = 0;
\r
385 ispre_1_3_19 = false;
\r
391 Demuxer::~Demuxer()
\r
397 Demuxer* Demuxer::getInstance()
\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
407 if ( !videostream.init(video, demuxMemoryV) ||
\r
408 !audiostream.init(audio, demuxMemoryA) ||
\r
409 !teletextstream.init(teletext, demuxMemoryT))
\r
411 Log::getInstance()->log("Demuxer", Log::CRIT,
\r
412 "Failed to initialize demuxer");
\r
418 isteletextdecoded = true;
\r
420 isteletextdecoded = false;
\r
425 subtitles = tsubtitles;
\r
426 callback = tcallback;
\r
430 void Demuxer::reset()
\r
432 Log::getInstance()->log("Demuxer", Log::DEBUG, "Reset called");
\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
442 for (int i = 0; i <= (PESTYPE_AUDMAX - PESTYPE_AUD0); i++)
\r
444 avail_mpaudchan[i] = false;
\r
446 for (int i = 0; i <= (PESTYPE_SUBSTREAM_AC3MAX - PESTYPE_SUBSTREAM_AC30); i++)
\r
448 avail_ac3audchan[i] = false;
\r
450 for (int i = 0; i <= (PESTYPE_SUBSTREAM_DVBSUBTITLEMAX - PESTYPE_SUBSTREAM_DVBSUBTITLE0); i++)
\r
452 avail_dvbsubtitlechan[i] = false;
\r
456 int Demuxer::shutdown()
\r
458 videostream.shutdown();
\r
459 audiostream.shutdown();
\r
460 teletextstream.shutdown();
\r
465 void Demuxer::flush()
\r
467 Log::getInstance()->log("Demuxer", Log::DEBUG, "Flush called");
\r
469 videostream.flush();
\r
470 audiostream.flush();
\r
471 teletextstream.flush();
\r
474 void Demuxer::flushAudio()
\r
476 audiostream.flush();
\r
479 void Demuxer::seek()
\r
481 vid_seeking = aud_seeking = true;
\r
482 video_pts = audio_pts = teletext_pts = 0;
\r
485 void Demuxer::setAudioStream(int id)
\r
487 audio_current = id;
\r
490 void Demuxer::setVideoStream(int id)
\r
492 video_current = id;
\r
495 void Demuxer::setTeletextStream(int id)
\r
497 teletext_current = id;
\r
500 void Demuxer::setDVBSubtitleStream(int id)
\r
502 subtitle_current = id;
\r
505 void Demuxer::setAspectRatio(enum AspectRatio ar)
\r
507 if (aspect_ratio != ar)
\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
515 if (callback) callback->call(this);
\r
522 bool Demuxer::writeAudio()
\r
524 return audiostream.drain();
\r
527 bool Demuxer::writeVideo()
\r
529 return videostream.drain();
\r
532 bool Demuxer::writeTeletext()
\r
534 return teletextstream.drain();
\r
537 bool Demuxer::submitPacket(PESPacket& packet)
\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
544 if (video_current == -1) video_current = packet_type;
\r
545 if (video_current == packet_type && !vid_seeking)
\r
547 sent = videostream.put(&packetdata[0], packet.getSize(), h264?MPTYPE_VIDEO_H264:MPTYPE_VIDEO_MPEG2,packetnum);
\r
548 if (sent) packetnum++;
\r
551 sent = packet.getSize();
\r
553 else if (packet_type >= PESTYPE_AUD0 && packet_type <= PESTYPE_AUDMAX)
\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
560 sent = audiostream.put(&packetdata[0], packet.getSize(), MPTYPE_MPEG_AUDIO,packetnum);
\r
561 if (sent) packetnum++;
\r
564 sent = packet.getSize();
\r
566 else if (packet_type == PESTYPE_PRIVATE_1 &&
\r
567 packet.getSubstream() >= PESTYPE_SUBSTREAM_AC30 &&
\r
568 packet.getSubstream() <= PESTYPE_SUBSTREAM_AC3MAX)
\r
570 avail_ac3audchan[packet.getSubstream() - PESTYPE_SUBSTREAM_AC30] = true;
\r
571 if (packet.getSubstream() == audio_current)
\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
578 sent = packet.getSize();
\r
581 else if (packet_type == PESTYPE_PRIVATE_1 &&
\r
582 packet.getSubstream() >= PESTYPE_SUBSTREAM_DVBSUBTITLE0 &&
\r
583 packet.getSubstream() <= PESTYPE_SUBSTREAM_DVBSUBTITLEMAX)
\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
589 subtitles->put(packet);
\r
591 sent = packet.getSize();
\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
598 if (teletext_current == -1) teletext_current = packet.getSubstream();
\r
599 if (teletext_current == packet.getSubstream())
\r
601 sent = teletextstream.put(&packetdata[0], packet.getSize(), MPTYPE_TELETEXT,packetnum);
\r
605 sent = packet.getSize();
\r
610 sent = packet.getSize();
\r
613 if (sent < packet.getSize()) // Stream is full.
\r
619 void Demuxer::parsePacketDetails(PESPacket& packet)
\r
621 if (packet.getPacketType() >= PESTYPE_AUD0 &&
\r
622 packet.getPacketType() <= PESTYPE_AUDMAX)
\r
624 // Extract audio PTS if it exists
\r
625 if (packet.hasPTS())
\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
635 (video_pts_seek < audio_pts &&
\r
636 video_pts_seek + (1LL<<33) - audio_pts < SEEK_THRESHOLD) ))
\r
639 Log::getInstance()->log("Demuxer", Log::DEBUG,
\r
640 "Leaving audio sync: Audio PTS = %llu", audio_pts);
\r
644 else if (packet.getPacketType() == PESTYPE_PRIVATE_1) // Private stream
\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
654 substream_id = PESTYPE_PRIVATE_1;
\r
655 substream_type = 0x80;
\r
656 substream_index = 0;
\r
658 switch (substream_type)
\r
662 packet.setSubstream(substream_id);
\r
664 case 0xA0: //LPCM //not supported yet, is there any LPCM transmissio out there?
\r
666 case 0x80: //ac3, currently only one ac3 track per recording supported
\r
667 packet.setSubstream(substream_type+substream_index);
\r
669 // Extract audio PTS if it exists
\r
670 if (packet.hasPTS())
\r
672 audio_pts = packet.getPTS();
\r
673 // We continue to seek on the audio if the video PTS that we
\r
674 // are trying to match is ahead of the audio PTS by at most
\r
675 // SEEK_THRESHOLD. We consider the possibility of PTS wrap.
\r
676 if (aud_seeking && !vid_seeking &&
\r
677 !( (video_pts_seek > audio_pts &&
\r
678 video_pts_seek - audio_pts < SEEK_THRESHOLD)
\r
680 (video_pts_seek < audio_pts &&
\r
681 video_pts_seek + (1LL<<33) - audio_pts < SEEK_THRESHOLD) ))
\r
684 Log::getInstance()->log("Demuxer", Log::DEBUG, "Leaving audio sync: Audio PTS = %llu", audio_pts);
\r
688 case 0x10: //Teletext Is this correct?
\r
689 packet.setSubstream(substream_id);
\r
690 // Extract teletxt PTS if it exists
\r
691 if (packet.hasPTS())
\r
693 teletext_pts = packet.getPTS();
\r
699 ispre_1_3_19=true; //switching to compat mode and live tv mode
\r
700 goto pre_1_3_19_Recording;
\r
704 packet.setSubstream(0);
\r
709 else if (packet.getPacketType() >= PESTYPE_VID0 &&
\r
710 packet.getPacketType() <= PESTYPE_VIDMAX)
\r
712 // Extract video PTS if it exists
\r
713 if (packet.hasPTS()) video_pts = packet.getPTS();
\r
715 // If there is a sequence header, extract information
\r
716 UINT pos = packet.findSeqHeader(h264);
\r
721 if (pos+6 >= packet.getSize()) return;
\r
722 horizontal_size = ((int)packet[pos] << 4) | ((int)packet[pos+1] >> 4);
\r
724 vertical_size = (((int)packet[pos+1] & 0xf) << 8) | (int)packet[pos+2];
\r
726 setAspectRatio((enum AspectRatio)(packet[pos+3] >> 4));
\r
727 frame_rate = packet[pos+3] & 0x0f;
\r
728 if (frame_rate >= 1 && frame_rate <= 8)
\r
729 frame_rate = FrameRates[frame_rate];
\r
732 bit_rate = ((int)packet[pos+4] << 10) |
\r
733 ((int)packet[pos+5] << 2) |
\r
734 ((int)packet[pos+6] >> 6);
\r
738 /* Chris and Mark I know this is ugly, should we move this to a method of PESPacket or to NALUUnit what would be better?
\r
739 This looks so ugly since the header includes variable length parts and I have to parse through the whole header to get the wanted information*/
\r
740 NALUUnit nalu(packet.getData()+pos,packet.getSize()-pos);
\r
741 profile=nalu.getBits(8);
\r
742 nalu.getBits(8); //constraints
\r
743 nalu.getBits(8); //level_idc
\r
744 nalu.getUe(); //seq_parameter_set_id
\r
746 if (profile==100 || profile==110 || profile==122 || profile==144)
\r
748 chroma=nalu.getUe();
\r
753 nalu.getUe(); //bit depth lume
\r
754 nalu.getUe(); //bit depth chrome
\r
756 if (nalu.getBits(1))
\r
758 for (int i=0;i<8;i++){
\r
759 if (nalu.getBits(1))
\r
765 for (int j=0;j<16;j++) {
\r
766 if (nextscale!=0) {
\r
767 UINT delta=nalu.getSe();
\r
768 nextscale=(lastscale+delta+256)%256;
\r
770 lastscale=(nextscale==0)?lastscale:nextscale;
\r
777 for (int j=0;j<64;j++) {
\r
778 if (nextscale!=0) {
\r
779 UINT delta=nalu.getSe();
\r
780 nextscale=(lastscale+delta+256)%256;
\r
782 lastscale=(nextscale==0)?lastscale:nextscale;
\r
793 chromunitx=chromunity=1; break;
\r
795 chromunitx=chromunity=2; break;
\r
797 chromunitx=2;chromunity=1; break;
\r
799 chromunitx=chromunity=1; break;
\r
802 nalu.getUe(); //log2framenum
\r
803 UINT temp=nalu.getUe();
\r
804 if (temp==0) //pict order
\r
806 else if (temp==1) {
\r
810 UINT temp2=nalu.getUe();
\r
811 for (int i=0;i<temp2;i++)
\r
814 nalu.getUe(); //Num refframes
\r
816 horizontal_size=(nalu.getUe()+1)*16;
\r
818 vertical_size=(nalu.getUe()+1)*16;
\r
819 int interlaced=nalu.getBits(1);
\r
820 vertical_size*=(2-interlaced);
\r
822 if (!interlaced) nalu.getBits(1);
\r
824 if (nalu.getBits(1))
\r
826 horizontal_size-=nalu.getUe()*chromunitx;
\r
827 horizontal_size-=nalu.getUe()*chromunitx;
\r
828 vertical_size-=nalu.getUe()*(2-interlaced)*chromunity;
\r
829 vertical_size-=nalu.getUe()*(2-interlaced)*chromunity;
\r
831 if (nalu.getBits(1))
\r
833 if (nalu.getBits(1))
\r
835 UINT aspectratioidc=nalu.getBits(8);
\r
836 bool hasaspect=false;
\r
837 const float aspects[]={1., 1./1.,12./11.,10./11.,16./11.,40./33.,
\r
838 24./11.,20./11.,32./11.,80./33.,18./11.,15./11.,64./33.,160./99.,4./3.,3./2.,2./1.};
\r
840 float aspectratio=((float) horizontal_size)/((float) vertical_size);
\r
841 if (aspectratioidc<=16)
\r
844 aspectratio*=aspects[aspectratioidc];
\r
847 else if (aspectratioidc==255)
\r
849 int t_sar_width=nalu.getBits(16);
\r
850 int t_sar_height=nalu.getBits(16);
\r
851 if (t_sar_width!=0 && t_sar_height!=0)
\r
854 aspectratio*=((float)t_sar_width)/((float)t_sar_height);
\r
859 if (fabs(aspectratio-16./9.)<0.1) setAspectRatio(ASPECT_16_9);
\r
860 else if (fabs(aspectratio-4./3.)<0.1) setAspectRatio(ASPECT_4_3);
\r
871 video_pts_seek = video_pts;
\r
872 Log::getInstance()->log("Demuxer", Log::DEBUG,
\r
873 "Entering audio sync: Video PTS = %llu", video_pts);
\r
874 Log::getInstance()->log("Demuxer", Log::DEBUG,
\r
875 "Entering audio sync: Audio PTS = %llu", audio_pts);
\r
882 UINT Demuxer::stripAudio(UCHAR* buf, UINT len)
\r
884 UINT read_pos = 0, write_pos = 0;
\r
885 UINT pattern, packet_length;
\r
886 if (len < 4) return 0;
\r
887 pattern = (buf[0] << 16) | (buf[1] << 8) | (buf[2]);
\r
888 while (read_pos + 7 <= len)
\r
890 pattern = ((pattern & 0xFFFFFF) << 8) | buf[read_pos+3];
\r
891 if (pattern < (0x100|PESTYPE_VID0) || pattern > (0x100|PESTYPE_VIDMAX))
\r
895 packet_length = ((buf[read_pos+4] << 8) | (buf[read_pos+5])) + 6;
\r
896 if (read_pos + packet_length > len)
\r
900 if (read_pos != write_pos)
\r
901 memmove(buf+write_pos, buf+read_pos, packet_length);
\r
902 read_pos += packet_length;
\r
903 write_pos += packet_length;
\r
904 pattern = (buf[read_pos] << 16) | (buf[read_pos+1] << 8)
\r
905 | (buf[read_pos+2]);
\r
912 void Demuxer::changeTimes(UCHAR* buf, UINT len,UINT playtime)
\r
914 UINT pattern, packet_length;
\r
916 if (len < 4) return;
\r
917 pattern = (buf[0] << 16) | (buf[1] << 8) | (buf[2]);
\r
918 while (read_pos + 7 <= len)
\r
920 pattern = ((pattern & 0xFFFFFF) << 8) | buf[read_pos+3];
\r
921 if (pattern < (0x100|PESTYPE_VID0) || pattern > (0x100|PESTYPE_VIDMAX))
\r
925 packet_length = ((buf[read_pos+4] << 8) | (buf[read_pos+5])) + 6;
\r
926 // ok we have a packet figure out if pts and dts are present and replace them
\r
927 if (read_pos + 19 > len) return;
\r
928 ULLONG new_ts=playtime*90; //play time is on ms so multiply it by 90
\r
929 if (buf[read_pos+7] & 0x80) { // pts is here, replace it
\r
930 buf[read_pos+9]=0x21 | (( new_ts>>29)& 0xde );
\r
931 buf[read_pos+10]=0x00 |(( new_ts>>22)& 0xff );
\r
932 buf[read_pos+11]=0x01 | (( new_ts>>14)& 0xfe );
\r
933 buf[read_pos+12]=0x00 | (( new_ts>>7)& 0xff );
\r
934 buf[read_pos+13]=0x01 | (( new_ts<<1)& 0xfe );
\r
937 if (buf[read_pos+7] & 0x40) { // pts is here, replace it
\r
938 buf[read_pos+14]=0x21 | (( new_ts>>29)& 0xde );
\r
939 buf[read_pos+15]=0x00 | (( new_ts>>22)& 0xff );
\r
940 buf[read_pos+16]=0x01 | (( new_ts>>14)& 0xfe );
\r
941 buf[read_pos+17]=0x00 | (( new_ts>>7)& 0xff );
\r
942 buf[read_pos+18]=0x01 | (( new_ts<<1)& 0xfe );
\r
944 read_pos += packet_length;
\r
945 pattern = (buf[read_pos] << 16) | (buf[read_pos+1] << 8)
\r
946 | (buf[read_pos+2]);
\r
952 bool Demuxer::scanForVideo(UCHAR* buf, UINT len, bool &ish264)
\r
957 if (len < 4) return false;
\r
958 pattern = (buf[0] << 16) | (buf[1] << 8) | (buf[2]);
\r
961 pattern = ((pattern & 0xFFFFFF) << 8) | buf[pos++];
\r
962 if (pattern >= (0x100|PESTYPE_VID0) && pattern <= (0x100|PESTYPE_VIDMAX))
\r
968 bool* Demuxer::getmpAudioChannels()
\r
970 return avail_mpaudchan;
\r
973 bool* Demuxer::getac3AudioChannels()
\r
975 return avail_ac3audchan;
\r
978 bool* Demuxer::getSubtitleChannels()
\r
980 return avail_dvbsubtitlechan;
\r
983 int Demuxer::getselSubtitleChannel()
\r
985 return subtitle_current;
\r
988 int Demuxer::getselAudioChannel()
\r
990 return audio_current;
\r