home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2004 March / PCWELT_3_2004.ISO / pcwsoft / flaskmpeg_078_39_src.z.exe / flaskmpeg / OutputManager.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2002-10-28  |  16.3 KB  |  642 lines

  1. /* 
  2.  *  OutputManager.cpp
  3.  *
  4.  *    Copyright (C) Alberto Vigata - January 2000
  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. #include "flaskmpeg.h"
  25. #include "flasktypes.h"
  26. #include "OutputManager.h"
  27. #include "debug.h"
  28.  
  29. #include "runstate.h"
  30. #include "error.h"
  31.  
  32.  
  33. extern TRunState rs;
  34.  
  35. extern HWND hMainWnd;
  36. extern HINSTANCE hInst;
  37.  
  38. // Globals
  39. flreturn_t static flout_getstream( ui32 compileid, ui32 streamid, getstream_s *st )
  40. {
  41.   return ((COutputManager *)compileid)->getstream( streamid, st);
  42. }
  43.  
  44. flreturn_t static flout_getstream_report( ui32 compileid, ui32 streamid, getstream_report_s *str )
  45. {
  46.   return ((COutputManager *)compileid)->getstream_report( streamid, str);
  47. }
  48.  
  49. //////////////////////////////////////////////////////////////////////
  50. // Construction/Destruction
  51. //////////////////////////////////////////////////////////////////////
  52. COutputManager::COutputManager()
  53. {
  54.     m_bTerminated = true;
  55.     m_bConvInProgress = false;
  56. }
  57.  
  58. COutputManager::~COutputManager()
  59. {
  60.  
  61. }
  62.  
  63. void COutputManager::ConfigureOutput(long nIndex)
  64. {
  65.   FlPluginWrapper *pw= &rs.plugs.outPlugs[nIndex].plug;
  66.   pw->floutentry( flo_configure, 0, 0);
  67. }
  68.  
  69. char *COutputManager::AddFileExtension(char *file)
  70. {
  71.   if(!file)
  72.     return NULL;
  73.  
  74.   fileinfo_s fi;
  75.   rs.plugs.outPlugs[rs.selected_out_plug].plug.floutentry( flo_getinfo, flo_getfileinfo, (ui32)&fi );
  76.   strcat( file, "." );
  77.   strcat( file, fi.extension );
  78.  
  79.   return file;
  80. }
  81.  
  82.  
  83. /////////////////////////////////////////////////////////////////
  84. // COutputManager::Run - This is the main entrance routine
  85. //
  86. /////////////////////////////////////////////////////////////////
  87. bool COutputManager::Run( TOutputManagerRunInfo *pRunInfo )
  88. {
  89.   if(!pRunInfo)
  90.     return false;
  91.  
  92.   m_sRunInfo = *pRunInfo;
  93.   m_pReport = pRunInfo->pReport;
  94.   m_prof = pRunInfo->prof;
  95.   FromConfigToPPost( rs.profiler->GetSelected(), &m_pps, 
  96.                      rs.video->GetWidth(), 
  97.                      rs.video->GetHeight(),
  98.                      rs.video->DAR,
  99.                      FRAME_YV12 );  
  100.  
  101.   m_nConversionProcessed = 0;
  102.   m_nConversionSize      = 0;
  103.   m_nJobInProcess   = 0; 
  104.   m_nJobCount       = 0;
  105.  
  106.   // Set the initial state of some events
  107.   m_bIsRunning  = true;
  108.   m_bConvInProgress = false;
  109.  
  110.   //Negotiate an processing format with the output
  111.   FlPluginWrapper *pw = &rs.plugs.outPlugs[rs.selected_out_plug].plug;
  112.  
  113.   if( rs.conf.bProcessingFormatAuto ) { 
  114.     videoinfo_s vi;
  115.     
  116.     if ( pw->floutentry( flo_getinfo, flo_getvideoinfo, (ui32)&vi ) != flo_ok ) {
  117.       DBG_STR(( str, "COutputManager::Start - Couldnt retrieve output processing formats.\n" ))
  118.       return false;
  119.     }
  120.  
  121.     rs.conf.nProcessingFormat = vi.supported_fmt&FLO_VIDEO_YV12 ? FRAME_YV12 :
  122.                                 vi.supported_fmt&FLO_VIDEO_YUY2 ? FRAME_YUY2 :
  123.                                 FRAME_RGB32;
  124.   }
  125.  
  126.   m_evCompileTerminated.Reset();
  127.   // Close any resources allocated for a previous thread
  128.   Close();
  129.   // Create the encoding thread
  130.   Create();
  131.   return true;
  132. }
  133.  
  134. ////////////////////////////////////////////////////////////////
  135. // COutputManager::StartInput - 
  136. //   Starts the input and processing 
  137. //   pipeline for a conversion with the specified parameters.
  138. //
  139. //////////////////////////////////////////////////////////////////
  140. bool COutputManager::StartInput( ui64 nStart, ui64 nStop )
  141. {
  142.   bool bSuccess = true;
  143.  
  144.   ////////////////////////////////////////////////
  145.   // Prepare the video
  146.   ////////////////////////////////////////////////
  147.   TVideoOptions video_opt;
  148.  
  149.   // Create the frame buffer for the video
  150.   m_pDecodedFrameBuffer = new CListFrameBuffer( rs.video->pictureWidth, 
  151.                                                 rs.video->pictureHeight, 
  152.                                                 FRAME_YV12, 4);
  153.  
  154.   video_opt.pFrameBuffer         = m_pDecodedFrameBuffer;
  155.   video_opt.idctIndex            = rs.conf.idctIndex;
  156.   video_opt.recons_progressive   = m_prof.recons_progressive;
  157.   video_opt.bStartInSync         = true;
  158.   video_opt.nSyncPoint           = rs.video->GetSyncPoint(nStart);
  159.   video_opt.nEndPoint            = nStop;
  160.  
  161.  
  162.   if(rs.video && bSuccess) bSuccess = rs.video->Start(&video_opt) > 0;
  163.   
  164.   // Create the video source
  165.   if( bSuccess ) {
  166.     m_pVideoSource = new CVideoSource();
  167.     bSuccess = m_pVideoSource->Start( rs.video, &m_pps );
  168.   }
  169.  
  170.  
  171.   ////////////////////////////////////////////////
  172.   // Prepare the audio
  173.   ////////////////////////////////////////////////
  174.   if( bSuccess ) {
  175.     if(m_prof.sampleFreqSameAsInput)
  176.       m_prof.outSampleFrequency = rs.audio->sampleRate;
  177.  
  178.     if(rs.audio) {
  179.  
  180.       rs.audio->SetStreamPos(video_opt.nSyncPoint);
  181.         rs.audio->SetAudioMode(m_prof.audioMode);
  182.  
  183.       switch( m_prof.audioMode) 
  184.       {
  185.         case DSC:
  186.           bSuccess = rs.audio->Start(rs.conf.audioOutFile, m_prof.audioMode) > 0;
  187.           break;
  188.         case DO_AUDIO:
  189.           m_prof.sAudioProperties.sAudioTrack = rs.sAudioTrack;
  190.           bSuccess = rs.audio->Start(m_prof.outSampleFrequency, 
  191.                                      m_prof.audioMode, 
  192.                                     &m_prof.sAudioProperties );
  193.           break;
  194.         case NO_AUDIO:
  195.           break;
  196.         default:
  197.           bSuccess = false;
  198.       }
  199.     }
  200.   }
  201.   return bSuccess;
  202. }
  203.  
  204. ////////////////////////////////////////////////////////////////
  205. // COutputManager::StopInput - 
  206. //   Stops the input and processing 
  207. //
  208. //////////////////////////////////////////////////////////////////
  209. bool COutputManager::StopInput()
  210. {
  211.   if(m_pVideoSource) {
  212.     m_pVideoSource->Stop();
  213.     delete m_pVideoSource;
  214.     m_pVideoSource = NULL;
  215.   }
  216.  
  217.  
  218.   if(rs.video)
  219.     rs.video->Stop();
  220.   if(rs.audio)
  221.     rs.audio->Stop();
  222.  
  223.   if(  m_pDecodedFrameBuffer ) {
  224.     delete m_pDecodedFrameBuffer;
  225.     m_pDecodedFrameBuffer = NULL;
  226.   }
  227.  
  228.  
  229.   return true;
  230. }
  231.  
  232.  
  233. ////////////////////////////////////////////////////////////////
  234. // COutputManager::StartJob 
  235. //
  236. //////////////////////////////////////////////////////////////////
  237. bool COutputManager::StartJob( int nJobIndex )
  238. {
  239.  
  240.   char  myFile[1024];
  241.  
  242.   if(rs.conf.warn_overwrite){
  243.     FILE *input = NULL;
  244.     strcpy( myFile, m_pOutputFileName );
  245.     if(input=fopen(AddFileExtension(myFile), "rb")){
  246.       fclose(input);
  247.       if(MessageBox(hMainWnd, GS(WARN_OVERWRITE), GS(WARNING), MB_YESNO) == IDNO)
  248.         return false;
  249.     }
  250.     strcpy( myFile, rs.conf.audioOutFile );
  251.     if(input=fopen(AddFileExtension(myFile), "rb")){
  252.       fclose(input);
  253.       if(MessageBox(hMainWnd, GS(WARN_OVERWRITE), GS(WARNING), MB_YESNO) == IDNO)
  254.         return false;
  255.     }
  256.     
  257.   }
  258.  
  259.   // Adapt filename if multiple jobs
  260.   strcpy( m_pOutputFileName, rs.conf.outputFile );
  261.   if(nJobIndex>0)
  262.     sprintf(m_pOutputFileName,"%s%d", rs.conf.outputFile, nJobIndex+1);
  263.   
  264.   AddFileExtension(m_pOutputFileName);
  265.     
  266.   // update job in process
  267.   m_nJobInProcess = nJobIndex;
  268.   
  269.   m_nFrameSpan= (i64)((1/((double)(m_prof.timeBase.scale)/
  270.                           (double)(m_prof.timeBase.sampleSize)))*(double)MPEG2_CLK_REF);
  271.  
  272.   // Init some variable for conversion
  273.   m_bImageWaiting = false;
  274.   m_bFirstTime    = true;
  275.   m_bFirstPass    = true;
  276.   m_bInputStarted = false;
  277.   m_pFrameInProcess = NULL;
  278.   m_nMyClock=0;
  279.   m_nFrameCount =0 ;
  280.   m_nAudPrevFrame = 0;
  281.  
  282.   rs.pVideoRenderer->StartPlaying();
  283.  
  284.   return true;
  285. }
  286.  
  287. ////////////////////////////////////////////////////////////////
  288. // COutputManager::StopJob 
  289. //
  290. //////////////////////////////////////////////////////////////////
  291. void COutputManager::StopJob(int nJobIndex )
  292. {
  293.   // Update conversion processed
  294.   m_nConversionProcessed = 0;
  295.   m_nPartialProcessed += m_nStopPos - m_nStartPos;    
  296. }
  297.  
  298. ////////////////////////////////////////////////////////////////
  299. // COutputManager::ThreadProc 
  300. //
  301. //   Thread that does the conversion
  302. //////////////////////////////////////////////////////////////////
  303. DWORD COutputManager::ThreadProc()
  304. {    
  305.   bool bSuccess=true;
  306.   ui32 nResult;
  307.   int i;
  308.  
  309.   m_bTerminated = false;
  310.   m_oJobList = *m_sRunInfo.pJobList;
  311.  
  312.   ui32  nJobItems = m_oJobList.size();
  313.  
  314.   // No jobs? Add a job that
  315.   // spans the whole project
  316.   if(!nJobItems)
  317.   {
  318.     TBatchListElement el;
  319.     el.nStart = 0;
  320.     el.nEnd   = rs.video->GetStreamSize();
  321.     m_oJobList.push_back(el);
  322.     nJobItems = m_oJobList.size();
  323.   }
  324.  
  325.   // Update total job size
  326.   for( i=0; i<nJobItems; i++)
  327.     m_nConversionSize += m_oJobList[i].nEnd - m_oJobList[i].nStart;
  328.  
  329.   m_nJobCount = nJobItems;
  330.  
  331.  
  332.  
  333.   m_nPartialProcessed=0;
  334.   m_nConversionProcessed = 0;
  335.   for( i=0; i<nJobItems; i++)
  336.   {
  337.     m_nStartPos = m_oJobList[i].nStart;
  338.     m_nStopPos = m_oJobList[i].nEnd;
  339.  
  340.  
  341.     if( StartJob(i) == false )
  342.       break;
  343.     if( StartInput( m_nStartPos, m_nStopPos ) == false )
  344.       break;
  345.     // Do conversion
  346.     nResult = Convert();
  347.  
  348.     StopInput();
  349.     StopJob(i);
  350.  
  351.     // Exit if error in conversion
  352.     if(nResult!=flo_ok && 
  353.        nResult!=flo_stop )
  354.     {
  355.       bSuccess = false;
  356.       if(!bSuccess)
  357.         PrintError(ERROR_COMPILE, (int)NULL, 0);
  358.       break;
  359.     }
  360.       
  361.   }
  362.  
  363.   CFlAutoLock lock( &m_csConv );
  364.  
  365.   m_bTerminated = true;  
  366.   m_evCompileTerminated.Set();
  367.   m_evCompileCanceled.Set();
  368.  
  369.   return true;
  370.  
  371. }
  372.  
  373. ui32 COutputManager::Convert()
  374. {
  375.   flreturn_t ret;
  376.   //Setup compiler plugin info
  377.   compile_s cs;
  378.   memset( &cs, 0, sizeof compile_s );
  379.  
  380.   // setup compile options
  381.   cs.compileid = (ui32) this;
  382.   
  383.   cs.isoutfile = 1;
  384.   strcpy( cs.filename, m_pOutputFileName );
  385.  
  386.  
  387.   cs.getstream        = flout_getstream;
  388.   cs.getstream_report = flout_getstream_report;
  389.  
  390.  
  391.   // Setup streams
  392.   streamdef_s *streams[2];
  393.   streams[0]=streams[1]=NULL;
  394.   cs.streamcnt = 0;
  395.  
  396.   // Video stream definition
  397.   videodef_s vd;
  398.   // Audio stream definition
  399.   audiodef_s ad;
  400.  
  401.   memset( &vd, 0, sizeof videodef_s );
  402.   vd.strdef.cbsize = sizeof videodef_s;
  403.   vd.strdef.streamid = video;
  404.   vd.strdef.streamtype = flo_video;
  405.   
  406.   vd.width = m_pVideoSource->GetWidth();
  407.   vd.height = m_pVideoSource->GetHeight();
  408.   vd.vidformat = rs.conf.nProcessingFormat&FRAME_RGB32 ? FLO_VIDEO_RGB32 :
  409.                  rs.conf.nProcessingFormat&FRAME_YV12  ? FLO_VIDEO_YV12  :
  410.                  rs.conf.nProcessingFormat&FRAME_YUY2  ? FLO_VIDEO_YUY2  : 0;
  411.  
  412.   vd.framerate_num = m_prof.timeBase.scale;
  413.   vd.framerate_den = m_prof.timeBase.sampleSize;
  414.   
  415.   streams[0] = (streamdef_s *)&vd;
  416.   cs.streamcnt++;
  417.  
  418.   // Audio stream definition
  419.   if( m_prof.audioMode == DO_AUDIO)
  420.   {
  421.  
  422.     memset( &ad, 0, sizeof audiodef_s );
  423.     ad.strdef.cbsize = sizeof audiodef_s;
  424.     ad.strdef.streamid = audio;
  425.     ad.strdef.streamtype = flo_audio;
  426.     
  427.     ad.fmt.channels = 2;
  428.     ad.fmt.depth    = 16;
  429.     ad.fmt.frequency = m_prof.outSampleFrequency;
  430.  
  431.     streams[1] = (streamdef_s *)&ad;
  432.     cs.streamcnt++;
  433.   }
  434.  
  435.   FlPluginWrapper *pw = &rs.plugs.outPlugs[rs.selected_out_plug].plug;
  436.  
  437.   cs.streams = streams; 
  438.   cs.length = rs.conf.compileWhole ? 600000 : rs.conf.framesToCompile;
  439.  
  440.   m_bIsDualPass = pw->GetStartup()->dualpass ? rs.conf.bDualPass : 0;
  441.   cs.istwopass = m_bIsDualPass;
  442.  
  443.   // Open scope for the lock to work
  444.   {
  445.     CFlAutoLock lock( &m_csConv );
  446.     m_bConvInProgress = true;
  447.   }
  448.  
  449.   ret = pw->floutentry(flo_compile, (ui32)&cs,0);
  450.  
  451.   // Open scope for the lock to work
  452.    {
  453.      CFlAutoLock lock( &m_csConv );
  454.      m_bConvInProgress = false;
  455.    }
  456.   
  457.   return ret;
  458. }
  459.  
  460.  
  461. flreturn_t COutputManager::getaudio(getaudio_s *ga)
  462. {
  463.   int nSampleCnt = ga->samplecnt;
  464.   ui8 *sample_ptr;
  465.   
  466.   rs.audio->GetSamples( 0, (short **)&sample_ptr,    nSampleCnt );
  467.  
  468.   ga->gs.buf = sample_ptr;
  469.   ga->gs.bufsize = nSampleCnt * 4; //FIXME. samplesize depends on processing output
  470.   ga->gs.timestamp = 0;
  471.  
  472.   return flo_ok;
  473. }
  474.  
  475.  
  476. flreturn_t COutputManager::getvideo( getvideo_s *gv )
  477.   CFrame *pFrame;
  478.   bool bAbortCompile = false;
  479.   bool bEndOfStream = false;
  480.   flreturn_t ret = flo_ok;
  481.  
  482.   if( m_evCancelCompile.Check() )
  483.     bAbortCompile = true;
  484.  
  485.     if(m_bFirstTime)
  486.   {
  487.         m_nMyClock   = 0;
  488.         m_bFirstTime = false;
  489.     }
  490.  
  491.   pFrame = m_pFrameInProcess;
  492.  
  493.   while(1)
  494.   {
  495.     if(!m_bImageWaiting)
  496.     {  
  497.       // Release the previous frame
  498.       if( m_pFrameInProcess )
  499.         m_pFrameInProcess->Release();
  500.  
  501.       if(m_pVideoSource->GetFrame(&m_pFrameInProcess)!=FRAME_OK)
  502.       {
  503.         bEndOfStream = true;
  504.         break;
  505.       }
  506.       
  507.       pFrame = m_pFrameInProcess;
  508.     }
  509.     //Check if th image has to be displayed in this frame
  510.     if((pFrame->GetPresTime() >= m_nMyClock) && 
  511.        (pFrame->GetPresTime() <(m_nMyClock + m_nFrameSpan)))
  512.     {
  513.       m_bImageWaiting=false;
  514.       break;
  515.     }
  516.     else if(pFrame->GetPresTime() >= (m_nMyClock + m_nFrameSpan) )
  517.     {
  518.       m_bImageWaiting=true;
  519.       break;
  520.     }
  521.     //Image has a PTS lower than myClock. Drop it
  522.     m_bImageWaiting=false;
  523.     DBG_STR((str, "OutputManager::fgetFrame - Dropping image by %d clock units\n", m_nMyClock - pFrame->GetPresTime()));
  524.   }
  525.  
  526.     m_nMyClock += m_nFrameSpan;
  527.  
  528.   //If GetFrame returns FRAME_NOFRAME, video bitstream is over
  529.     if(rs.audio)
  530.         if(m_prof.audioMode==DSC)//If we are in Direct Stream Copy audio mode
  531.             rs.audio->GetAudioDSC(pFrame->GetPresTime(), rs.video->GetStreamPos());
  532.  
  533.  
  534.     if(rs.conf.displayVideo && m_nFrameCount%30==0 )
  535.     rs.pVideoRenderer->Draw(pFrame);
  536.  
  537.   m_frDest.Set( pFrame->GetWidth(), pFrame->GetHeight(), 
  538.                 rs.conf.nProcessingFormat,
  539.                 pFrame->GetFlags() );
  540.   m_frDest.SetFrame( pFrame );
  541.  
  542.     if(rs.conf.displayVideo && m_nFrameCount%30==0 )
  543.     rs.pVideoRenderer->Draw(&m_frDest);
  544.     
  545.   if(m_evPauseCompile.Check())
  546.   {
  547.     m_evPauseCompile.Reset();
  548.     m_bIsRunning = false;
  549.     m_evResumeCompile.Wait();
  550.     m_bIsRunning = true;
  551.   }
  552.         
  553.  
  554.   gv->gs.buf     = m_frDest.GetBuffer();
  555.   gv->gs.bufsize = m_frDest.GetBufferSize();
  556.   gv->gs.timestamp = 0;
  557.  
  558.  
  559.  
  560.     m_nFrameCount++;
  561.   // Update job position every 15 frames
  562.   if(m_nFrameCount%15)
  563.     m_nConversionProcessed = rs.video->GetStreamPos() - m_nStartPos;
  564.  
  565.  
  566.   // Handle dual pass
  567.   if( (bEndOfStream || m_nFrameCount > rs.conf.framesToCompile) && m_bIsDualPass && m_bFirstPass)
  568.   { 
  569.     if(m_pFrameInProcess){
  570.       m_pFrameInProcess->Release();
  571.       m_pFrameInProcess = NULL;
  572.     }
  573.  
  574.     StopInput();
  575.     StartInput( m_nStartPos, m_nStopPos );
  576.     ret = flo_endfirstpass;
  577.     
  578.  
  579.     m_bFirstPass = false;
  580.     m_bImageWaiting = false;
  581.     m_bFirstTime    = true;  
  582.     m_pFrameInProcess = NULL;
  583.     m_nMyClock=0;
  584.     m_nFrameCount =0 ;
  585.     m_nAudPrevFrame = 0;
  586.  
  587.   }
  588.   else if( bEndOfStream || bAbortCompile || m_nFrameCount > rs.conf.framesToCompile )
  589.   {
  590.         ret  = flo_stop;
  591.     if(m_pFrameInProcess) {
  592.       m_pFrameInProcess->Release();
  593.       m_pFrameInProcess = NULL;
  594.     }
  595.   }
  596.  
  597.     return ret;
  598. }
  599.  
  600. flreturn_t COutputManager::getstream( ui32 streamid, getstream_s *st )
  601. {
  602.   flreturn_t ret;
  603.   switch( streamid )
  604.   {
  605.     case video:
  606.       ret = getvideo( (getvideo_s *)st );
  607.       break;
  608.     case audio:
  609.       ret = getaudio( (getaudio_s *)st );
  610.       break;
  611.   }
  612.   return ret;
  613. }
  614.  
  615. flreturn_t COutputManager::getvideo_report(getvideo_report_s *gvr)
  616. {
  617.   if( !gvr )
  618.     return flo_error;
  619.  
  620.   m_pReport->NewFrameInfo(gvr->bytes, gvr->type==1 );
  621.  
  622.   return flo_ok;
  623. }
  624.  
  625. flreturn_t COutputManager::getstream_report( ui32 streamid, getstream_report_s *str )
  626. {
  627.   flreturn_t ret = flo_ok;
  628.   switch( streamid )
  629.   {
  630.     case video:
  631.       ret = getvideo_report( (getvideo_report_s *)str );
  632.       break;
  633.     case flo_streamreport:
  634.       m_pReport->StreamInfo( ((getstream_streamreport_s *)str)->byteswritten );
  635.       break;
  636.     default:
  637.       break;
  638.   }
  639.   return ret;
  640. }
  641.