home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2004 March / PCWELT_3_2004.ISO / pcwsoft / flaskmpeg_078_39_src.z.exe / flaskmpeg / Demux / Demux.cpp next >
Encoding:
C/C++ Source or Header  |  2002-10-28  |  13.3 KB  |  568 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. CDemux::CDemux()
  29. {    
  30.     inp       = NULL;
  31.   strHandle = NULL;
  32. }
  33.  
  34.  
  35.  
  36. CDemux::~CDemux()
  37. {
  38. }
  39.  
  40. // The Mism is handled externally. Just get it.
  41. int CDemux::SetInput(LPTWorkingMism pMismInfo)
  42. {
  43.     inp = pMismInfo;
  44.   strHandle      = pMismInfo->handle;
  45.   mismReadStream = pMismInfo->pMismInfo->ReadStream;
  46.   return 1;
  47. }
  48.  
  49.  
  50. int inline CDemux::ReadStream(ui8 *buf, unsigned int size)
  51. {
  52.   return mismReadStream( strHandle, buf, size );
  53. }
  54.  
  55. i64 inline CDemux::getSCR()
  56. {
  57.         if(isMPEG2)
  58.             return ((SCRbase*300)+SCRext);
  59.         else
  60.             return SCR*300;
  61. }
  62.  
  63. i64 inline CDemux::getPTS()
  64. {
  65.             return PTS*300;
  66. }
  67.  
  68.  
  69. inline void CDemux::ResetPTS()
  70. {
  71.     PTS=0;
  72. }
  73. inline void CDemux::ResetSCR()
  74. {
  75.     SCR=0;
  76. }
  77.  
  78.  
  79. int CDemux::AlignPack(){
  80.     int val=1;
  81.  
  82.     while( (inbuf[0]!=0x00 || inbuf[1]!=0x00 || inbuf[2]!=0x01 || inbuf[3]!=0xBA)  && val){
  83.         inbuf[0]=inbuf[1];
  84.         inbuf[1]=inbuf[2];
  85.         inbuf[2]=inbuf[3];
  86.         val=ReadStream(&inbuf[3],1);
  87.     }
  88.     //Align
  89.     if(val)
  90.   {
  91.         SetStreamPos( GetStreamPos() - 4 );
  92.   }
  93.     return val;
  94. }
  95.  
  96.  
  97. bool inline CDemux::GetBackByte( ui8 *byte )
  98. {
  99.   // If the chunk is finished, grab previous one
  100.   // this will position the pointer at the end
  101.   // of the chunk
  102.   if( m_nPosEngPtr <= 0)
  103.   {
  104.     if(!GrabPrevChunk())
  105.       return false;
  106.   }
  107.    m_nPosEngPtr--;
  108.    *byte = *( m_pPosEngBfr + m_nPosEngPtr );
  109.  
  110.     return true;
  111. }
  112.  
  113. bool inline CDemux::GetForWord( ui16 *word )
  114. {
  115.     ui8 byte;
  116.     
  117.     *word = 0;
  118.     
  119.     bool bSuccess = GetFordByte( &byte );
  120.     *word = byte << 8;
  121.     if( bSuccess )
  122.         bSuccess = GetFordByte( &byte );
  123.     *word |= byte;
  124.  
  125.     return bSuccess;    
  126. }
  127.  
  128. bool inline CDemux::GetFordDWord( ui32 *dword )
  129. {
  130.     ui8 byte;
  131.     
  132.     *dword = 0;
  133.     
  134.     bool bSuccess = GetFordByte( &byte );
  135.     *dword = byte << 24;
  136.     if( bSuccess )
  137.         bSuccess = GetFordByte( &byte );
  138.     *dword |= byte << 16;
  139.     if( bSuccess )
  140.         bSuccess = GetFordByte( &byte );
  141.     *dword |= byte << 8;        
  142.     if( bSuccess )
  143.         bSuccess = GetFordByte( &byte );
  144.     *dword |= byte;    
  145.     
  146.     return bSuccess;
  147. }
  148.  
  149. bool inline CDemux::GetFordByte( ui8 *byte )
  150. {
  151.   // If not enough data in the chunk get next one.
  152.   // This will position the pointer at the beginning
  153.   if( m_nPosEngPtr>=(i32)m_nPosEngSize )
  154.   {
  155.      if(!GrabNextChunk())
  156.         return false;
  157.   }
  158.   // GetFordByte moves the file pointer. Get it back again.
  159.   *byte = *( m_pPosEngBfr + m_nPosEngPtr );
  160.   m_nPosEngPtr++;
  161.  
  162.   return true;
  163. }
  164.  
  165. ui64 CDemux::GetSyncPoint(ui64 pos)
  166. {
  167.   int i;
  168.     ui32 nTargetStartCode = 0x000001BA;
  169.   ui64 nSyncPos;
  170.   ui8  pPackHdr[6],bByte;
  171.   bool isMPEG2;
  172.   bool bFound   = false;
  173.   bool bSuccess = true;
  174.  
  175.   SetStreamPos(pos);
  176.  
  177.   StartPositioningEngine();
  178.   
  179.   // Look for previous startcode from this position
  180.   while( !bFound && bSuccess )
  181.   {
  182.     ui32 nStartCode = 0xFFFFFFFF;
  183.     while( nStartCode!=nTargetStartCode && bSuccess )
  184.     {
  185.       bSuccess = GetBackByte(&bByte);
  186.       nStartCode = (nStartCode>>8) | (bByte<<24);
  187.     }
  188.     if( bSuccess )
  189.     {
  190.       // We found a suitable startcode and we're aligned with it.
  191.       // Make sure this is a pack start code
  192.       GetFordDWord(&nStartCode);
  193.       // Get next 6 bytes
  194.       for(i=0; i<6; i++)
  195.         GetFordByte( &pPackHdr[i] );
  196.       // now, do the checking
  197.             isMPEG2 = pPackHdr[0]>>6 == 1;
  198.       if(isMPEG2)
  199.       {
  200.         if(!IS_MPEG2PACKHEADER(pPackHdr))
  201.           continue;
  202.       }
  203.       else
  204.       {
  205.         if(!IS_MPEG1PACKHEADER(pPackHdr))
  206.           continue;
  207.       }
  208.  
  209.       // If we are here, the pack was Ok.
  210.       bSuccess = true;
  211.       nSyncPos = GetPosEngPos() - 10;
  212.       break;
  213.     }
  214.   }  
  215.   StopPositioningEngine();
  216.   if(bSuccess)
  217.     return nSyncPos;
  218.   else
  219.     return GetStreamPos();
  220. }
  221.  
  222. // This function sets the file pointer
  223. //  to the beginning of the previous PES
  224. //  with the indicated id. It also updates
  225. //  pack_bytes accordingly.
  226. bool CDemux::RewindPreviousPES( ui8 nStreamID )
  227. {
  228.     bool bFound   = false;
  229.     bool bSuccess = true;
  230.     ui8  bByte;
  231.     ui32 nTargetStartCode = 0x00000100 | nStreamID;
  232.     ui64 nPESBeginPos, nPackBeginPos;
  233.     ui16 nPesLength;
  234.  
  235.   StartPositioningEngine();
  236.  
  237.     // Look for previous startcode from this position
  238.     while( !bFound && bSuccess )
  239.     {
  240.         ui32 nStartCode = 0xFFFFFFFF;
  241.         while( nStartCode!=nTargetStartCode && bSuccess )
  242.         {
  243.             bSuccess = GetBackByte(&bByte);
  244.             nStartCode = (nStartCode>>8) | (bByte<<24);
  245.         }
  246.         if( bSuccess )
  247.         {
  248.             // We found a suitable startcode and we're aligned with it
  249.             // Now look backward in search for the beginning of the pack
  250.             nPESBeginPos = GetPosEngPos();
  251.             // Make a little checking to make
  252.             // sure this is a PES
  253.             GetFordDWord( &nStartCode );
  254.             GetForWord( &nPesLength );
  255.             // Jump to the end of the PES
  256.             SetPosEngPos( nPESBeginPos + nPesLength + 6);
  257.             // Now we must be aligned with a start code prefix
  258.             GetFordDWord( &nStartCode );
  259.             // Return to the original location
  260.             SetPosEngPos( nPESBeginPos );
  261.             if( (nStartCode >> 8) != 1 )
  262.                 // No start code. Continue parsing.
  263.                 continue;
  264.  
  265.             
  266.             nTargetStartCode = 0x000001BA;
  267.             nStartCode = 0xFFFFFFFF;
  268.             while( nStartCode!=nTargetStartCode && bSuccess )
  269.             {
  270.                 bSuccess = GetBackByte(&bByte);
  271.                 nStartCode = (nStartCode>>8) | (bByte<<24);
  272.             }            
  273.             if( bSuccess )
  274.             {
  275.                 // We found the beginning of the Pack. 
  276.                 nPackBeginPos = GetPosEngPos();
  277.                 // Guess if this is an MPEG1 or 2 stream
  278.                 // parse start code
  279.                 GetFordDWord( &nStartCode );
  280.                 GetFordByte( &bByte );
  281.                 isMPEG2 = bByte>>6 == 1;
  282.  
  283.                 // Pack bytes 
  284.                 pack_bytes = (ui32)(nPESBeginPos - nPackBeginPos + 4);
  285.                 // Restore position of the stream to the beginning 
  286.                 // of the PES
  287.                 SetPosEngPos( nPESBeginPos );
  288.                 bFound = true;
  289.             }
  290.         }
  291.     }
  292.   
  293.   StopPositioningEngine();
  294.     return bSuccess;
  295. }
  296.  
  297. bool CDemux::ReadPES(unsigned char **buffer, PESinfo *PES)
  298. {
  299.     ui8    stream_id,substream_id;
  300.     ui16   packet_lenght,header_lenght,bytes_read;
  301.  
  302.  
  303.     //Read prefix    
  304.     PTS = 0;
  305.     PES->pack_header_parsed = false;
  306. start:
  307.     PES->payloadSize        = 0xFF;
  308.  
  309.  
  310.     if(!ReadStream(inbuf, 3)){
  311.         PES->payloadSize=0xFF;
  312.         return false;
  313.     }
  314.     // 3 bytes were read succesfully
  315.     pack_bytes += 3;
  316.        stream_id=0;
  317.     substream_id=0;
  318.     if(inbuf[0]!=0 || inbuf[1]!=0 || inbuf[2]!=1){
  319.         AlignPack();       //Stream is not pack aligned
  320.         goto start;
  321.     }
  322.  
  323.     pack_bytes += ReadStream(&stream_id, 1);   //Read packet identifier
  324.  
  325.     if(stream_id==(ui8)PACK_ID){ //We've got a PACK
  326.         
  327.         PES->pack_header_parsed = true;
  328.         //Retrieve SCR and muxrate
  329.         //Identify either MPEG1 or MPEG2 stream
  330.  
  331.         pack_bytes += ReadStream(inbuf, 1);
  332.         if(    (inbuf[0] & 0xC0)==0x40 ){      //MPEG2 program stream '01'
  333.             isMPEG2=true;
  334.             ReadStream(&inbuf[1], 9);          //Read pack header
  335.  
  336.                     SCRbase     = GET_SCRBASE(inbuf);
  337.                     SCRext   = GET_SCREXT(inbuf);
  338.                     muxRate  = GET_MPEG2MUXRATE(inbuf);
  339.                     //number of bytes after the byte
  340.                     //containing last bit of SCRBASE field
  341.                     pack_bytes = 5;
  342.  
  343.                     //parse stuffing bytes
  344.             pack_bytes += ReadStream(inbuf, GET_MPEG2STUFFING(inbuf));
  345.             //printf("Pack parsed. \n");
  346.         }
  347.         else if ((inbuf[0] & 0xF0)==0x20 ){
  348.             isMPEG2=false;
  349.  
  350.             ReadStream(&inbuf[1], 7);          //Read pack header
  351.                 
  352.                     SCR      = GET_SCR(inbuf);
  353.                     muxRate  = GET_MPEG1_MUXRATE(inbuf);
  354.                     pack_bytes = 3;
  355.                     //printf("Pack parsed. \n");
  356.         }
  357.         else{ //arghh, there's something wrong with this stream
  358.             AlignPack();
  359.             goto start;
  360.         }
  361.         goto start; //Parse next PES or whatever
  362.     }
  363.     
  364.     if( stream_id >= 0xC0 && stream_id <= 0xEF || stream_id==PRIVATE_STREAM_1)
  365.     { //MPEG AUDIO or MPEG video or PRIVATE stream
  366.         if(isMPEG2)
  367.         {
  368.             pack_bytes += ReadStream(inbuf, 5);
  369.             packet_lenght   =   GET_MPEG_PACKET_LENGHT(inbuf);
  370.             header_lenght=   inbuf[4];
  371.             if(GET_MPEG2_PTS_FLAGS(inbuf)&0x02)
  372.             {  //if a PTS stamp is present in this PES
  373.                 pack_bytes += ReadStream(inbuf, 5);
  374.                 PTS=GET_MPEG2_PTS(inbuf);
  375.                 //Read the whole PES
  376.                 pack_bytes += ReadStream(inbuf, packet_lenght-8);    //PES_packet_lenght - 'parsed data'
  377.                 *buffer= (unsigned char *)&inbuf[header_lenght - 5] ; //Set payload base
  378.             }
  379.             else
  380.             {
  381.                 PTS=0;
  382.                 pack_bytes += ReadStream(inbuf, packet_lenght-3);    //PES_packet_lenght - 'parsed data'
  383.                 *buffer= (unsigned char *)&inbuf[header_lenght];     //Set payload base
  384.             }
  385.             PES->payloadSize= packet_lenght - 3 - header_lenght;
  386.             
  387.             if(stream_id==PRIVATE_STREAM_1)
  388.             {
  389.                 substream_id=**buffer;
  390.                 (*buffer)+=1;                          //AC3 ident bytes
  391.                 PES->payloadSize-=1;
  392.                 if(substream_id >= 0x20 && substream_id < 0x40) 
  393.                 {
  394.                     /* subpic; don't do anything special. the subpic code needs
  395.                      * everything else */
  396.                 } else {
  397.                     /* AC3 (or something else which we don't care about): skip an
  398.                      * extra 3 bytes */
  399.                     (*buffer)+=3;                          //AC3 ident bytes
  400.                     PES->payloadSize-=3;
  401.                 }
  402.             }
  403.             else
  404.                 substream_id=0;
  405.  
  406.         }
  407.         else{
  408.             //MPEG1
  409.             pack_bytes += ReadStream(inbuf, 2);
  410.             packet_lenght = GET_MPEG_PACKET_LENGHT(inbuf);
  411.             bytes_read=0;
  412.  
  413.             // Rule: a byte has been read when a field begins
  414.             // Read first byte
  415.             pack_bytes += ReadStream(inbuf, 1);
  416.             bytes_read++;
  417.  
  418.             while(inbuf[0]&0x80)
  419.             {         //Parse stuffing bytes
  420.                 pack_bytes += ReadStream(inbuf, 1);
  421.                 bytes_read++;
  422.             }
  423.  
  424.             if( (inbuf[0]&0xC0) ==0x40 ){
  425.                 // Finish parsing STD field
  426.                 /*pack_bytes += ReadStream(inbuf, 1);     //STD_buffer_scale & size
  427.                 bytes_read++;
  428.                 // Read next byte
  429.                 pack_bytes += ReadStream(inbuf, 1);     //STD_buffer_scale & size
  430.                 bytes_read++;*/
  431.                 pack_bytes += ReadStream(inbuf, 2);     //STD_buffer_scale & size
  432.                 bytes_read+=2;
  433.                 inbuf[0] = inbuf[1];
  434.             }
  435.  
  436.             PTS=0;
  437.             switch ((inbuf[0]&0xF0))
  438.             {
  439.                 case 0x20:
  440.                     pack_bytes += ReadStream(&inbuf[1], 4);
  441.                     bytes_read+=4;
  442.                     PTS=GET_MPEG1_PTS(inbuf);
  443.                     break;
  444.                 case 0x30:
  445.                     pack_bytes += ReadStream(&inbuf[1], 9);
  446.                     bytes_read+=9;
  447.                     PTS=GET_MPEG1_PTS(inbuf);
  448.                     break;
  449.                 default:
  450.                     PTS=0;
  451.             }
  452. /*
  453.             if( (inbuf[0]&0xF0) ==0x20 ){ //PTS stamp present
  454.                 pack_bytes += ReadStream(&inbuf[1], 4);
  455.                 bytes_read+=4;
  456.                 PTS=GET_MPEG1_PTS(inbuf);
  457.             }
  458.             else if( (inbuf[0]&0xF0) ==0x30 ){ //PTS & DTS stamp present
  459.                         pack_bytes += ReadStream(&inbuf[1], 9);
  460.                       bytes_read+=9;
  461.                       PTS=GET_MPEG1_PTS(inbuf);
  462.             }
  463.             // else '00001111'  0x0F
  464.             else{
  465.                 PTS=0;
  466.             }*/
  467.             PES->payloadSize= packet_lenght - bytes_read;
  468.  
  469.             pack_bytes += ReadStream(inbuf, PES->payloadSize);
  470.             *buffer= (unsigned char *)&inbuf[0]; 
  471.         }
  472.     }
  473.     else{
  474.         //Fetch PES length
  475.         pack_bytes += ReadStream(inbuf, 2);
  476.         pack_bytes += ReadStream(inbuf, GET_UINT16(inbuf));
  477.     }
  478.  
  479.     PES->muxrate     = muxRate;
  480.     PES->PTS         = getPTS();
  481.     PES->SCR         = getSCR();
  482.     PES->streamID    = stream_id;
  483.     PES->subStreamID = substream_id;
  484.     PES->pack_bytes  = pack_bytes;
  485.     return true;
  486. }
  487.  
  488.  
  489. i64 CDemux::GetTime()
  490. {
  491.     return getSCR();
  492. }
  493.  
  494. bool CDemux::ReadLPES(unsigned char **buffer, PESinfo *pInfo)
  495. {
  496.     bool ret;
  497.     i64 nextSCR;
  498.  
  499.         ret=ReadPES(buffer, pInfo);
  500.         if(!ret)
  501.             return ret;
  502.  
  503.         if(firstTime){
  504.             delta           = 0 - pInfo->SCR;
  505.             firstTime = false;
  506.         }
  507.         else{
  508.             // Handle clock disruption
  509.             if((lastSCR >= pInfo->SCR) && 
  510.                 pInfo->pack_header_parsed )
  511.             {
  512.                 // work out the time of the last byte of the previous pack
  513.                 nextSCR = lastSCR + 
  514.                           (int)(( (double)(lastPackBytes + 1)
  515.                                /  (double)(lastMuxRate *50  ) ) 
  516.                                *(double)MPEG2_CLK_REF);
  517.  
  518.                 // update delta
  519.                 // delta = OUR_CLK  -  STREAM_CLK
  520.                 // OUR_CLK  =  STREAM_CLK + delta
  521.                 delta = (nextSCR + delta) - pInfo->SCR;
  522.             }
  523.         }
  524.     lastSCR         = pInfo->SCR;
  525.     lastPackBytes   = pInfo->pack_bytes;
  526.     lastMuxRate     = pInfo->muxrate;
  527.  
  528.     pInfo->SCR = pInfo->SCR + delta;
  529.     pInfo->PTS = pInfo->PTS ? (pInfo->PTS + delta) : 0;
  530.  
  531.  
  532.  
  533.     return ret;
  534. }
  535.  
  536. bool CDemux::SetStreamPos(ui64 pos)
  537. {
  538.   return inp->pMismInfo->SetStreamPos(strHandle, pos)==FM_MISM_OK;
  539. }
  540.  
  541. ui64 CDemux::GetStreamPos()
  542. {
  543.   ui64 pos;
  544.   inp->pMismInfo->GetStreamPos(strHandle, &pos);
  545.     return pos;
  546. }
  547.  
  548. char *CDemux::GetFileName()
  549. {
  550.     return inp->pMismInfo->GetFileName(strHandle);
  551. }
  552.  
  553. ui64  CDemux::GetStreamSize()
  554. {
  555.     return inp->pMismInfo->GetStreamSize(strHandle);
  556. }
  557.  
  558. void CDemux::StartReadLPES()
  559. {
  560.     // ReadLPES variables
  561.     delta            = 0;
  562.     lastSCR          = 0;
  563.     lastPackBytes    = 0;
  564.     lastMuxRate      = 0;
  565.     firstTime        = true;
  566.     return; 
  567. }
  568.