home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2001 September / PC-WELT 9-2001.ISO / software / hw / brennen / flask_src.exe / Demux / Demux.cpp next >
Encoding:
C/C++ Source or Header  |  2000-05-11  |  8.1 KB  |  356 lines

  1. /* 
  2.  *  Demux.cpp 
  3.  *
  4.  *    Copyright (C) Alberto Vigata - January 2000 - ultraflask@yahoo.com
  5.  *
  6.  *  This file is part of FlasKMPEG, a free MPEG to MPEG/AVI converter
  7.  *    
  8.  *  FlasKMPEG is free software; you can redistribute it and/or modify
  9.  *  it under the terms of the GNU General Public License as published by
  10.  *  the Free Software Foundation; either version 2, or (at your option)
  11.  *  any later version.
  12.  *   
  13.  *  FlasKMPEG is distributed in the hope that it will be useful,
  14.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.  *  GNU General Public License for more details.
  17.  *   
  18.  *  You should have received a copy of the GNU General Public License
  19.  *  along with GNU Make; see the file COPYING.  If not, write to
  20.  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
  21.  *
  22.  */
  23.  
  24.  
  25. #include "demux.h"
  26. #include "assert.h"
  27.  
  28. #include "..\flaskmpeg.h"
  29.  
  30.  
  31.  
  32.  
  33.  
  34.  
  35.  
  36.  
  37.  
  38.  
  39. CDemux::CDemux()
  40. {    
  41.     inp=NULL;
  42.     myInputStream=NULL;
  43. }
  44.  
  45.  
  46.  
  47. CDemux::~CDemux()
  48. {
  49.     if(myInputStream)
  50.         delete myInputStream;
  51. }
  52.  
  53. int CDemux::SetInput(char *inputfile)
  54. {
  55.     if(inp)
  56.         return 0; //A file was previously set. Can't set another one
  57.     myInputStream=inp=new CinputStream;
  58.     if(inp) return inp->OpenStream(inputfile, DVD_MODE);
  59.     else return 0;
  60.  
  61. }
  62. int CDemux::SetInput(CinputStream *inpStream)
  63. {
  64.     if(inp)
  65.         return 0; //A file was previously set. Can't set another one
  66.     
  67.     if(inpStream){
  68.         inp=inpStream;
  69.         return 1;
  70.     }
  71.     else 
  72.         return 0;
  73. }
  74. int CDemux::UnSetInput()
  75. {
  76.     if(myInputStream){
  77.         delete myInputStream;
  78.         inp=myInputStream=NULL;
  79.     }
  80.     else{
  81.         inp=NULL;
  82.     }
  83.     return 1;
  84. }
  85.  
  86.  
  87.  
  88. i64 inline CDemux::getSCR()
  89. {
  90.         if(isMPEG2)
  91.             return ((SCRbase*300)+SCRext);
  92.         else
  93.             return SCR*300;
  94. }
  95.  
  96. i64 inline CDemux::getPTS()
  97. {
  98.             return PTS*300;
  99. }
  100.  
  101.  
  102. inline CDemux::ResetPTS()
  103. {
  104.     PTS=0;
  105. }
  106. inline CDemux::ResetSCR()
  107. {
  108.     SCR=0;
  109. }
  110.  
  111.  
  112. int CDemux::AlignPack(){
  113.     int val=1;
  114.     while( (inbuf[0]!=0x00 || inbuf[1]!=0x00 || inbuf[2]!=0x01 || inbuf[3]!=0xBA)  && val){
  115.         inbuf[0]=inbuf[1];
  116.         inbuf[1]=inbuf[2];
  117.         inbuf[2]=inbuf[3];
  118.         val=inp->Read(&inbuf[3],1);
  119.     }
  120.     //Align
  121.     if(val)
  122.         inp->SetStreamPos(inp->GetStreamPos()-4);
  123.     return val;
  124. }
  125.  
  126.  
  127. int inline CDemux::ReadPES(unsigned char **buffer, PESinfo *PES)
  128. {
  129.     ui8    stream_id,substream_id;
  130.     ui16   packet_lenght,header_lenght,bytes_read;
  131.     ui8    ret;
  132.  
  133.     static ui32 pack_bytes;
  134.  
  135.     //Read prefix    
  136.     PTS = 0;
  137.     PES->pack_header_parsed = false;
  138. start:
  139.     PES->payloadSize        = 0xFF;
  140.  
  141.  
  142.     if(!( ret=inp->Read(inbuf, 3) )){
  143.         PES->payloadSize=0xFF;
  144.         return 0;
  145.     }
  146.     // 3 bytes were read succesfully
  147.     pack_bytes += 3;
  148.        stream_id=0;
  149.     substream_id=0;
  150.     if(inbuf[0]!=0 || inbuf[1]!=0 || inbuf[2]!=1){
  151.         AlignPack();       //Stream is not pack aligned
  152.         goto start;
  153.     }
  154.  
  155.     pack_bytes += inp->Read(&stream_id, 1);   //Read packet identifier
  156.  
  157.     if(stream_id==(ui8)PACK_ID){ //We've got a PACK
  158.         
  159.         PES->pack_header_parsed = true;
  160.         //Retrieve SCR and muxrate
  161.         //Identify either MPEG1 or MPEG2 stream
  162.  
  163.         pack_bytes += inp->Read(inbuf, 1);
  164.         if(    (inbuf[0] & 0xC0)==0x40 ){      //MPEG2 program stream '01'
  165.             isMPEG2=true;
  166.             inp->Read(&inbuf[1], 9);          //Read pack header
  167.  
  168.                     SCRbase     = GET_SCRBASE(inbuf);
  169.                     SCRext   = GET_SCREXT(inbuf);
  170.                     muxRate  = GET_MPEG2MUXRATE(inbuf);
  171.                     //number of bytes after the byte
  172.                     //containing last bit of SCRBASE field
  173.                     pack_bytes = 5;
  174.  
  175.                     //parse stuffing bytes
  176.             pack_bytes += inp->Read(inbuf, GET_MPEG2STUFFING(inbuf));
  177.             //printf("Pack parsed. \n");
  178.         }
  179.         else if ((inbuf[0] & 0xF0)==0x20 ){
  180.             isMPEG2=false;
  181.  
  182.             inp->Read(&inbuf[1], 7);          //Read pack header
  183.                 
  184.                     SCR      = GET_SCR(inbuf);
  185.                     muxRate  = GET_MPEG1_MUXRATE(inbuf);
  186.                     pack_bytes = 3;
  187.                     //printf("Pack parsed. \n");
  188.         }
  189.         else{ //arghh, there's something wrong with this stream
  190.             AlignPack();
  191.             goto start;
  192.         }
  193.         goto start; //Parse next PES or whatever
  194.     }
  195.     
  196.     if( stream_id >= 0xC0 && stream_id <= 0xEF || stream_id==PRIVATE_STREAM_1){ //MPEG AUDIO or MPEG video or PRIVATE stream
  197.         if(isMPEG2){
  198.             pack_bytes += inp->Read(inbuf, 5);
  199.             packet_lenght   =   GET_MPEG_PACKET_LENGHT(inbuf);
  200.             header_lenght=   inbuf[4];
  201.             if(GET_MPEG2_PTS_FLAGS(inbuf)&0x02){  //if a PTS stamp is present in this PES
  202.                 pack_bytes += inp->Read(inbuf, 5);
  203.                 PTS=GET_MPEG2_PTS(inbuf);
  204.                 //Read the whole PES
  205.                 pack_bytes += inp->Read(inbuf, packet_lenght-8);    //PES_packet_lenght - 'parsed data'
  206.                 *buffer= (unsigned char *)&inbuf[header_lenght - 5] ; //Set payload base
  207.             }
  208.             else{
  209.                 PTS=0;
  210.                 pack_bytes += inp->Read(inbuf, packet_lenght-3);    //PES_packet_lenght - 'parsed data'
  211.                 *buffer= (unsigned char *)&inbuf[header_lenght];     //Set payload base
  212.             }
  213.             PES->payloadSize= packet_lenght - 3 - header_lenght;
  214.             
  215.             if(stream_id==PRIVATE_STREAM_1){
  216.                 substream_id=**buffer;
  217.                 (*buffer)+=1;                          //AC3 ident bytes
  218.                 PES->payloadSize-=1;
  219.                 if(substream_id >= 0x20 && substream_id < 0x40) {
  220.                     /* subpic; don't do anything special. the subpic code needs
  221.                      * everything else */
  222.                 } else {
  223.                     /* AC3 (or something else which we don't care about): skip an
  224.                      * extra 3 bytes */
  225.                     (*buffer)+=3;                          //AC3 ident bytes
  226.                     PES->payloadSize-=3;
  227.                 }
  228.             }
  229.             else
  230.                 substream_id=0;
  231.  
  232.         }
  233.         else{
  234.             //MPEG1
  235.             pack_bytes += inp->Read(inbuf, 2);
  236.             packet_lenght = GET_MPEG_PACKET_LENGHT(inbuf);
  237.             bytes_read=0;
  238.  
  239.             // Rule: a byte has been read when a field begins
  240.             // Read first byte
  241.             pack_bytes += inp->Read(inbuf, 1);
  242.             bytes_read++;
  243.             while(inbuf[0]&0x80){         //Parse stuffing bytes
  244.                 pack_bytes += inp->Read(inbuf, 1);
  245.                 bytes_read++;
  246.             }
  247.  
  248.             if( (inbuf[0]&0xC0) ==0x40 ){
  249.                 // Finish parsing STD field
  250.                 pack_bytes += inp->Read(inbuf, 1);     //STD_buffer_scale & size
  251.                 bytes_read++;
  252.                 // Read next byte
  253.                 pack_bytes += inp->Read(inbuf, 1);     //STD_buffer_scale & size
  254.                 bytes_read++;
  255.             }
  256.  
  257.             PTS=0;
  258.             if( (inbuf[0]&0xF0) ==0x20 ){ //PTS stamp present
  259.                 pack_bytes += inp->Read(&inbuf[1], 4);
  260.                 bytes_read+=4;
  261.                 PTS=GET_MPEG1_PTS(inbuf);
  262.             }
  263.             else if( (inbuf[0]&0xF0) ==0x30 ){ //PTS & DTS stamp present
  264.                         pack_bytes += inp->Read(&inbuf[1], 9);
  265.                       bytes_read+=9;
  266.                       PTS=GET_MPEG1_PTS(inbuf);
  267.             }
  268.             // else '00001111'  0x0F
  269.             else{
  270.                 PTS=0;
  271.             }
  272.             PES->payloadSize= packet_lenght - bytes_read;
  273.  
  274.             pack_bytes += inp->Read(inbuf, PES->payloadSize);
  275.             *buffer= (unsigned char *)&inbuf[0]; 
  276.         }
  277.     }
  278.     else{
  279.         //Fetch PES length
  280.         pack_bytes += inp->Read(inbuf, 2);
  281.         pack_bytes += inp->Read(inbuf, GET_UINT16(inbuf));
  282.     }
  283.  
  284.     PES->muxrate     = muxRate;
  285.     PES->PTS         = getPTS();
  286.     PES->SCR         = getSCR();
  287.     PES->streamID    = stream_id;
  288.     PES->subStreamID = substream_id;
  289.     PES->pack_bytes  = pack_bytes;
  290.     return ret;
  291. }
  292.  
  293.  
  294. i64 CDemux::GetTime()
  295. {
  296.     return getSCR();
  297. }
  298.  
  299. int CDemux::ReadLPES(unsigned char **buffer, PESinfo *pInfo)
  300. {
  301.     ui32 ret;
  302.     i64 nextSCR;
  303.  
  304.         ret=ReadPES(buffer, pInfo);
  305.         if(!ret)
  306.             return ret;
  307.  
  308.         if(firstTime){
  309.             delta           = 0 - pInfo->SCR;
  310.             firstTime = false;
  311.         }
  312.         else{
  313.             // Handle clock disruption
  314.             if((lastSCR >= pInfo->SCR) && 
  315.                 pInfo->pack_header_parsed )
  316.             {
  317.                 // work out the time of the last byte of the previous pack
  318.                 nextSCR = lastSCR + 
  319.                           (int)(( (double)(lastPackBytes + 1)
  320.                                /  (double)(lastMuxRate *50  ) ) 
  321.                                *(double)MPEG2_CLK_REF);
  322.  
  323.                 // update delta
  324.                 // delta = OUR_CLK  -  STREAM_CLK
  325.                 // OUR_CLK  =  STREAM_CLK + delta
  326.                 delta = (nextSCR + delta) - pInfo->SCR;
  327.             }
  328.         }
  329.     lastSCR         = pInfo->SCR;
  330.     lastPackBytes   = pInfo->pack_bytes;
  331.     lastMuxRate     = pInfo->muxrate;
  332.  
  333.     pInfo->SCR = pInfo->SCR + delta;
  334.     pInfo->PTS = pInfo->PTS ? (pInfo->PTS + delta) : 0;
  335.  
  336.  
  337.  
  338.     return ret;
  339. }
  340.  
  341. void CDemux::StartReadLPES()
  342. {
  343.     // ReadLPES variables
  344.     delta            = 0;
  345.     lastSCR          = 0;
  346.     lastPackBytes    = 0;
  347.     lastMuxRate      = 0;
  348.     firstTime        = true;
  349.     return;
  350. }
  351.  
  352. int CDemux::SetWorkingMode(int mode)
  353. {
  354.     return inp->SetWorkingMode(mode);
  355. }
  356.