home *** CD-ROM | disk | FTP | other *** search
- /*
- * OutputManager.cpp
- *
- * Copyright (C) Alberto Vigata - January 2000
- *
- * This file is part of FlasKMPEG, a free MPEG to MPEG/AVI converter
- *
- * FlasKMPEG is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * FlasKMPEG is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Make; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
- #include "flaskmpeg.h"
- #include "flasktypes.h"
- #include "OutputManager.h"
- #include "debug.h"
-
- #include "runstate.h"
- #include "error.h"
-
-
- extern TRunState rs;
-
- extern HWND hMainWnd;
- extern HINSTANCE hInst;
-
- // Globals
- flreturn_t static flout_getstream( ui32 compileid, ui32 streamid, getstream_s *st )
- {
- return ((COutputManager *)compileid)->getstream( streamid, st);
- }
-
- flreturn_t static flout_getstream_report( ui32 compileid, ui32 streamid, getstream_report_s *str )
- {
- return ((COutputManager *)compileid)->getstream_report( streamid, str);
- }
-
- //////////////////////////////////////////////////////////////////////
- // Construction/Destruction
- //////////////////////////////////////////////////////////////////////
- COutputManager::COutputManager()
- {
- m_bTerminated = true;
- m_bConvInProgress = false;
- }
-
- COutputManager::~COutputManager()
- {
-
- }
-
- void COutputManager::ConfigureOutput(long nIndex)
- {
- FlPluginWrapper *pw= &rs.plugs.outPlugs[nIndex].plug;
- pw->floutentry( flo_configure, 0, 0);
- }
-
- char *COutputManager::AddFileExtension(char *file)
- {
- if(!file)
- return NULL;
-
- fileinfo_s fi;
- rs.plugs.outPlugs[rs.selected_out_plug].plug.floutentry( flo_getinfo, flo_getfileinfo, (ui32)&fi );
- strcat( file, "." );
- strcat( file, fi.extension );
-
- return file;
- }
-
-
- /////////////////////////////////////////////////////////////////
- // COutputManager::Run - This is the main entrance routine
- //
- /////////////////////////////////////////////////////////////////
- bool COutputManager::Run( TOutputManagerRunInfo *pRunInfo )
- {
- if(!pRunInfo)
- return false;
-
- m_sRunInfo = *pRunInfo;
- m_pReport = pRunInfo->pReport;
- m_prof = pRunInfo->prof;
- FromConfigToPPost( rs.profiler->GetSelected(), &m_pps,
- rs.video->GetWidth(),
- rs.video->GetHeight(),
- rs.video->DAR,
- FRAME_YV12 );
-
- m_nConversionProcessed = 0;
- m_nConversionSize = 0;
- m_nJobInProcess = 0;
- m_nJobCount = 0;
-
- // Set the initial state of some events
- m_bIsRunning = true;
- m_bConvInProgress = false;
-
- //Negotiate an processing format with the output
- FlPluginWrapper *pw = &rs.plugs.outPlugs[rs.selected_out_plug].plug;
-
- if( rs.conf.bProcessingFormatAuto ) {
- videoinfo_s vi;
-
- if ( pw->floutentry( flo_getinfo, flo_getvideoinfo, (ui32)&vi ) != flo_ok ) {
- DBG_STR(( str, "COutputManager::Start - Couldnt retrieve output processing formats.\n" ))
- return false;
- }
-
- rs.conf.nProcessingFormat = vi.supported_fmt&FLO_VIDEO_YV12 ? FRAME_YV12 :
- vi.supported_fmt&FLO_VIDEO_YUY2 ? FRAME_YUY2 :
- FRAME_RGB32;
- }
-
- m_evCompileTerminated.Reset();
- // Close any resources allocated for a previous thread
- Close();
- // Create the encoding thread
- Create();
- return true;
- }
-
- ////////////////////////////////////////////////////////////////
- // COutputManager::StartInput -
- // Starts the input and processing
- // pipeline for a conversion with the specified parameters.
- //
- //////////////////////////////////////////////////////////////////
- bool COutputManager::StartInput( ui64 nStart, ui64 nStop )
- {
- bool bSuccess = true;
-
- ////////////////////////////////////////////////
- // Prepare the video
- ////////////////////////////////////////////////
- TVideoOptions video_opt;
-
- // Create the frame buffer for the video
- m_pDecodedFrameBuffer = new CListFrameBuffer( rs.video->pictureWidth,
- rs.video->pictureHeight,
- FRAME_YV12, 4);
-
- video_opt.pFrameBuffer = m_pDecodedFrameBuffer;
- video_opt.idctIndex = rs.conf.idctIndex;
- video_opt.recons_progressive = m_prof.recons_progressive;
- video_opt.bStartInSync = true;
- video_opt.nSyncPoint = rs.video->GetSyncPoint(nStart);
- video_opt.nEndPoint = nStop;
-
-
- if(rs.video && bSuccess) bSuccess = rs.video->Start(&video_opt) > 0;
-
- // Create the video source
- if( bSuccess ) {
- m_pVideoSource = new CVideoSource();
- bSuccess = m_pVideoSource->Start( rs.video, &m_pps );
- }
-
-
- ////////////////////////////////////////////////
- // Prepare the audio
- ////////////////////////////////////////////////
- if( bSuccess ) {
- if(m_prof.sampleFreqSameAsInput)
- m_prof.outSampleFrequency = rs.audio->sampleRate;
-
- if(rs.audio) {
-
- rs.audio->SetStreamPos(video_opt.nSyncPoint);
- rs.audio->SetAudioMode(m_prof.audioMode);
-
- switch( m_prof.audioMode)
- {
- case DSC:
- bSuccess = rs.audio->Start(rs.conf.audioOutFile, m_prof.audioMode) > 0;
- break;
- case DO_AUDIO:
- m_prof.sAudioProperties.sAudioTrack = rs.sAudioTrack;
- bSuccess = rs.audio->Start(m_prof.outSampleFrequency,
- m_prof.audioMode,
- &m_prof.sAudioProperties );
- break;
- case NO_AUDIO:
- break;
- default:
- bSuccess = false;
- }
- }
- }
- return bSuccess;
- }
-
- ////////////////////////////////////////////////////////////////
- // COutputManager::StopInput -
- // Stops the input and processing
- //
- //////////////////////////////////////////////////////////////////
- bool COutputManager::StopInput()
- {
- if(m_pVideoSource) {
- m_pVideoSource->Stop();
- delete m_pVideoSource;
- m_pVideoSource = NULL;
- }
-
-
- if(rs.video)
- rs.video->Stop();
- if(rs.audio)
- rs.audio->Stop();
-
- if( m_pDecodedFrameBuffer ) {
- delete m_pDecodedFrameBuffer;
- m_pDecodedFrameBuffer = NULL;
- }
-
-
- return true;
- }
-
-
- ////////////////////////////////////////////////////////////////
- // COutputManager::StartJob
- //
- //////////////////////////////////////////////////////////////////
- bool COutputManager::StartJob( int nJobIndex )
- {
-
- char myFile[1024];
-
- if(rs.conf.warn_overwrite){
- FILE *input = NULL;
- strcpy( myFile, m_pOutputFileName );
- if(input=fopen(AddFileExtension(myFile), "rb")){
- fclose(input);
- if(MessageBox(hMainWnd, GS(WARN_OVERWRITE), GS(WARNING), MB_YESNO) == IDNO)
- return false;
- }
- strcpy( myFile, rs.conf.audioOutFile );
- if(input=fopen(AddFileExtension(myFile), "rb")){
- fclose(input);
- if(MessageBox(hMainWnd, GS(WARN_OVERWRITE), GS(WARNING), MB_YESNO) == IDNO)
- return false;
- }
-
- }
-
- // Adapt filename if multiple jobs
- strcpy( m_pOutputFileName, rs.conf.outputFile );
- if(nJobIndex>0)
- sprintf(m_pOutputFileName,"%s%d", rs.conf.outputFile, nJobIndex+1);
-
- AddFileExtension(m_pOutputFileName);
-
- // update job in process
- m_nJobInProcess = nJobIndex;
-
- m_nFrameSpan= (i64)((1/((double)(m_prof.timeBase.scale)/
- (double)(m_prof.timeBase.sampleSize)))*(double)MPEG2_CLK_REF);
-
- // Init some variable for conversion
- m_bImageWaiting = false;
- m_bFirstTime = true;
- m_bFirstPass = true;
- m_bInputStarted = false;
- m_pFrameInProcess = NULL;
- m_nMyClock=0;
- m_nFrameCount =0 ;
- m_nAudPrevFrame = 0;
-
- rs.pVideoRenderer->StartPlaying();
-
- return true;
- }
-
- ////////////////////////////////////////////////////////////////
- // COutputManager::StopJob
- //
- //////////////////////////////////////////////////////////////////
- void COutputManager::StopJob(int nJobIndex )
- {
- // Update conversion processed
- m_nConversionProcessed = 0;
- m_nPartialProcessed += m_nStopPos - m_nStartPos;
- }
-
- ////////////////////////////////////////////////////////////////
- // COutputManager::ThreadProc
- //
- // Thread that does the conversion
- //////////////////////////////////////////////////////////////////
- DWORD COutputManager::ThreadProc()
- {
- bool bSuccess=true;
- ui32 nResult;
- int i;
-
- m_bTerminated = false;
- m_oJobList = *m_sRunInfo.pJobList;
-
- ui32 nJobItems = m_oJobList.size();
-
- // No jobs? Add a job that
- // spans the whole project
- if(!nJobItems)
- {
- TBatchListElement el;
- el.nStart = 0;
- el.nEnd = rs.video->GetStreamSize();
- m_oJobList.push_back(el);
- nJobItems = m_oJobList.size();
- }
-
- // Update total job size
- for( i=0; i<nJobItems; i++)
- m_nConversionSize += m_oJobList[i].nEnd - m_oJobList[i].nStart;
-
- m_nJobCount = nJobItems;
-
-
-
- m_nPartialProcessed=0;
- m_nConversionProcessed = 0;
- for( i=0; i<nJobItems; i++)
- {
- m_nStartPos = m_oJobList[i].nStart;
- m_nStopPos = m_oJobList[i].nEnd;
-
-
- if( StartJob(i) == false )
- break;
- if( StartInput( m_nStartPos, m_nStopPos ) == false )
- break;
- // Do conversion
- nResult = Convert();
-
- StopInput();
- StopJob(i);
-
- // Exit if error in conversion
- if(nResult!=flo_ok &&
- nResult!=flo_stop )
- {
- bSuccess = false;
- if(!bSuccess)
- PrintError(ERROR_COMPILE, (int)NULL, 0);
- break;
- }
-
- }
-
- CFlAutoLock lock( &m_csConv );
-
- m_bTerminated = true;
- m_evCompileTerminated.Set();
- m_evCompileCanceled.Set();
-
- return true;
-
- }
-
- ui32 COutputManager::Convert()
- {
- flreturn_t ret;
- //Setup compiler plugin info
- compile_s cs;
- memset( &cs, 0, sizeof compile_s );
-
- // setup compile options
- cs.compileid = (ui32) this;
-
- cs.isoutfile = 1;
- strcpy( cs.filename, m_pOutputFileName );
-
-
- cs.getstream = flout_getstream;
- cs.getstream_report = flout_getstream_report;
-
-
- // Setup streams
- streamdef_s *streams[2];
- streams[0]=streams[1]=NULL;
- cs.streamcnt = 0;
-
- // Video stream definition
- videodef_s vd;
- // Audio stream definition
- audiodef_s ad;
-
- memset( &vd, 0, sizeof videodef_s );
- vd.strdef.cbsize = sizeof videodef_s;
- vd.strdef.streamid = video;
- vd.strdef.streamtype = flo_video;
-
- vd.width = m_pVideoSource->GetWidth();
- vd.height = m_pVideoSource->GetHeight();
- vd.vidformat = rs.conf.nProcessingFormat&FRAME_RGB32 ? FLO_VIDEO_RGB32 :
- rs.conf.nProcessingFormat&FRAME_YV12 ? FLO_VIDEO_YV12 :
- rs.conf.nProcessingFormat&FRAME_YUY2 ? FLO_VIDEO_YUY2 : 0;
-
- vd.framerate_num = m_prof.timeBase.scale;
- vd.framerate_den = m_prof.timeBase.sampleSize;
-
- streams[0] = (streamdef_s *)&vd;
- cs.streamcnt++;
-
- // Audio stream definition
- if( m_prof.audioMode == DO_AUDIO)
- {
-
- memset( &ad, 0, sizeof audiodef_s );
- ad.strdef.cbsize = sizeof audiodef_s;
- ad.strdef.streamid = audio;
- ad.strdef.streamtype = flo_audio;
-
- ad.fmt.channels = 2;
- ad.fmt.depth = 16;
- ad.fmt.frequency = m_prof.outSampleFrequency;
-
- streams[1] = (streamdef_s *)&ad;
- cs.streamcnt++;
- }
-
- FlPluginWrapper *pw = &rs.plugs.outPlugs[rs.selected_out_plug].plug;
-
- cs.streams = streams;
- cs.length = rs.conf.compileWhole ? 600000 : rs.conf.framesToCompile;
-
- m_bIsDualPass = pw->GetStartup()->dualpass ? rs.conf.bDualPass : 0;
- cs.istwopass = m_bIsDualPass;
-
- // Open scope for the lock to work
- {
- CFlAutoLock lock( &m_csConv );
- m_bConvInProgress = true;
- }
-
- ret = pw->floutentry(flo_compile, (ui32)&cs,0);
-
- // Open scope for the lock to work
- {
- CFlAutoLock lock( &m_csConv );
- m_bConvInProgress = false;
- }
-
- return ret;
- }
-
-
- flreturn_t COutputManager::getaudio(getaudio_s *ga)
- {
- int nSampleCnt = ga->samplecnt;
- ui8 *sample_ptr;
-
- rs.audio->GetSamples( 0, (short **)&sample_ptr, nSampleCnt );
-
- ga->gs.buf = sample_ptr;
- ga->gs.bufsize = nSampleCnt * 4; //FIXME. samplesize depends on processing output
- ga->gs.timestamp = 0;
-
- return flo_ok;
- }
-
-
- flreturn_t COutputManager::getvideo( getvideo_s *gv )
- {
- CFrame *pFrame;
- bool bAbortCompile = false;
- bool bEndOfStream = false;
- flreturn_t ret = flo_ok;
-
- if( m_evCancelCompile.Check() )
- bAbortCompile = true;
-
- if(m_bFirstTime)
- {
- m_nMyClock = 0;
- m_bFirstTime = false;
- }
-
- pFrame = m_pFrameInProcess;
-
- while(1)
- {
- if(!m_bImageWaiting)
- {
- // Release the previous frame
- if( m_pFrameInProcess )
- m_pFrameInProcess->Release();
-
- if(m_pVideoSource->GetFrame(&m_pFrameInProcess)!=FRAME_OK)
- {
- bEndOfStream = true;
- break;
- }
-
- pFrame = m_pFrameInProcess;
- }
- //Check if th image has to be displayed in this frame
- if((pFrame->GetPresTime() >= m_nMyClock) &&
- (pFrame->GetPresTime() <(m_nMyClock + m_nFrameSpan)))
- {
- m_bImageWaiting=false;
- break;
- }
- else if(pFrame->GetPresTime() >= (m_nMyClock + m_nFrameSpan) )
- {
- m_bImageWaiting=true;
- break;
- }
- //Image has a PTS lower than myClock. Drop it
- m_bImageWaiting=false;
- DBG_STR((str, "OutputManager::fgetFrame - Dropping image by %d clock units\n", m_nMyClock - pFrame->GetPresTime()));
- }
-
- m_nMyClock += m_nFrameSpan;
-
- //If GetFrame returns FRAME_NOFRAME, video bitstream is over
- if(rs.audio)
- if(m_prof.audioMode==DSC)//If we are in Direct Stream Copy audio mode
- rs.audio->GetAudioDSC(pFrame->GetPresTime(), rs.video->GetStreamPos());
-
-
- if(rs.conf.displayVideo && m_nFrameCount%30==0 )
- rs.pVideoRenderer->Draw(pFrame);
-
- m_frDest.Set( pFrame->GetWidth(), pFrame->GetHeight(),
- rs.conf.nProcessingFormat,
- pFrame->GetFlags() );
- m_frDest.SetFrame( pFrame );
-
- if(rs.conf.displayVideo && m_nFrameCount%30==0 )
- rs.pVideoRenderer->Draw(&m_frDest);
-
- if(m_evPauseCompile.Check())
- {
- m_evPauseCompile.Reset();
- m_bIsRunning = false;
- m_evResumeCompile.Wait();
- m_bIsRunning = true;
- }
-
-
- gv->gs.buf = m_frDest.GetBuffer();
- gv->gs.bufsize = m_frDest.GetBufferSize();
- gv->gs.timestamp = 0;
-
-
-
- m_nFrameCount++;
- // Update job position every 15 frames
- if(m_nFrameCount%15)
- m_nConversionProcessed = rs.video->GetStreamPos() - m_nStartPos;
-
-
- // Handle dual pass
- if( (bEndOfStream || m_nFrameCount > rs.conf.framesToCompile) && m_bIsDualPass && m_bFirstPass)
- {
- if(m_pFrameInProcess){
- m_pFrameInProcess->Release();
- m_pFrameInProcess = NULL;
- }
-
- StopInput();
- StartInput( m_nStartPos, m_nStopPos );
- ret = flo_endfirstpass;
-
-
- m_bFirstPass = false;
- m_bImageWaiting = false;
- m_bFirstTime = true;
- m_pFrameInProcess = NULL;
- m_nMyClock=0;
- m_nFrameCount =0 ;
- m_nAudPrevFrame = 0;
-
- }
- else if( bEndOfStream || bAbortCompile || m_nFrameCount > rs.conf.framesToCompile )
- {
- ret = flo_stop;
- if(m_pFrameInProcess) {
- m_pFrameInProcess->Release();
- m_pFrameInProcess = NULL;
- }
- }
-
- return ret;
- }
-
- flreturn_t COutputManager::getstream( ui32 streamid, getstream_s *st )
- {
- flreturn_t ret;
- switch( streamid )
- {
- case video:
- ret = getvideo( (getvideo_s *)st );
- break;
- case audio:
- ret = getaudio( (getaudio_s *)st );
- break;
- }
- return ret;
- }
-
- flreturn_t COutputManager::getvideo_report(getvideo_report_s *gvr)
- {
- if( !gvr )
- return flo_error;
-
- m_pReport->NewFrameInfo(gvr->bytes, gvr->type==1 );
-
- return flo_ok;
- }
-
- flreturn_t COutputManager::getstream_report( ui32 streamid, getstream_report_s *str )
- {
- flreturn_t ret = flo_ok;
- switch( streamid )
- {
- case video:
- ret = getvideo_report( (getvideo_report_s *)str );
- break;
- case flo_streamreport:
- m_pReport->StreamInfo( ((getstream_streamreport_s *)str)->byteswritten );
- break;
- default:
- break;
- }
- return ret;
- }
-