home *** CD-ROM | disk | FTP | other *** search
- /*
- * Player.cpp
- *
- * Copyright (C) Alberto Vigata - July 2000 - ultraflask@yahoo.com
- *
- * 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 "playerthread.h"
- #include "debug.h"
- #include "runstate.h"
-
- extern TRunState rs;
-
-
- // Actual running thread
- DWORD CPlayerThread::ThreadProc()
- {
- m_nState = stStopped;
- TCommand sCommand;
-
- ui64 size, nCommandResult;
- tick tkPresTime, tkWaitTime, tkCurrentTime, tkFrameDelay;
-
- TVideoOptions video_opt;
- CFrame *pDecodedFrame = NULL;
- CFrame frProcessedFrame(NULL);
- CFrame frDisplay;
- FlPostProcess pp;
-
- enum {perfNormal =0, perfIOnly, perfSkip} perfState;
-
- perfState = perfNormal;
-
- // Post processing
- // Start Post processing
- m_pp.nInHeight = rs.video->GetHeight();
- m_pp.nInWidth = rs.video->GetWidth();
- m_pp.nProcessingFormat = rs.conf.nProcessingFormat;
- pp.Set(&m_pp);
-
- if( pp.Start() == false ) {
- DBG_STR(( str, "CPlayerThread::ThreadProc - Couldnt start post processing. Exiting thread\n"))
- return 0;
- }
-
- // FIXME : the buffer size of post processed frames has to be larger than the final size
- frProcessedFrame.Set( pp.GetWidth(), pp.GetHeight(), FRAME_YV12 );
-
- // Update video options
- video_opt.idctIndex = m_nIdctIndex;
- video_opt.recons_progressive = m_bReconsProgressive;
- video_opt.bStartInSync = false;
- video_opt.nSyncPoint = 0;
- video_opt.nEndPoint = rs.video->GetStreamSize();
- video_opt.pFrameBuffer = new CListFrameBuffer( rs.video->pictureWidth,
- rs.video->pictureHeight,
- FRAME_YV12,
- 3);
-
- tkFrameDelay = (mmtick)(rs.video->GetFrameDelay() * 10000);
- pDecodedFrame = NULL;
- while(1)
- {
-
- // open scope to lock command
- if(GetCommand(&sCommand))
- {
- nCommandResult = 0;
- switch( sCommand.nCommand )
- {
- case noCommand:
- break;
- case seek:
- // Stop if necessary
- if(m_nState!=stStopped)
- m_pVideoDecoder->Stop();
- m_pVideoDecoder->SetStreamPos(sCommand.nParam);
- m_pVideoDecoder->Start(&video_opt);
- m_nState = stNextFrame;
- break;
- case seekKeyFrame:
- // Stop if necessary
- if(m_nState!=stStopped)
- m_pVideoDecoder->Stop();
- m_pVideoDecoder->SetStreamPos(sCommand.nParam);
- m_pVideoDecoder->Start(&video_opt);
- m_nState = stNextKeyFrame;
- break;
- case seekBeginning:
- // Stop if necessary
- if(m_nState!=stStopped)
- m_pVideoDecoder->Stop();
- m_pVideoDecoder->SetStreamPos(0);
- m_pVideoDecoder->Start(&video_opt);
- m_nState = stNextFrame;
- break;
- case seekEnd:
- // Stop if necessary
- if(m_nState!=stStopped)
- m_pVideoDecoder->Stop();
- // Go to end
- size = m_pVideoDecoder->GetStreamSize();
- m_pVideoDecoder->SetStreamPos( size );
- // Start video
- m_pVideoDecoder->Start(&video_opt);
- m_nState = stPrevFrame;
- break;
- case nextFrame:
- // Stop if necessary
- if(m_nState!=stStopped)
- m_pVideoDecoder->Stop();
- // Start video
- m_pVideoDecoder->Start(&video_opt);
- m_nState = stNextFrame;
- break;
- case prevFrame:
- // Stop if necessary
- if(m_nState!=stStopped)
- m_pVideoDecoder->Stop();
- // Start video
- m_pVideoDecoder->Start(&video_opt);
- m_nState = stPrevFrame;
- break;
- case nextKeyFrame:
- // Stop if necessary
- if(m_nState!=stStopped)
- m_pVideoDecoder->Stop();
- // Start video
- m_pVideoDecoder->Start(&video_opt);
- m_nState = stNextKeyFrame;
- break;
- case prevKeyFrame:
- // Stop if necessary
- if(m_nState!=stStopped)
- m_pVideoDecoder->Stop();
- // Start video
- m_pVideoDecoder->Start(&video_opt);
- m_nState = stPrevKeyFrame;
- break;
- case fastForward:
- // Stop if necessary
- if(m_nState!=stStopped)
- m_pVideoDecoder->Stop();
- // Start video
- m_pVideoDecoder->Start(&video_opt);
- m_nState = stFastForward;
- break;
- case fastRewind:
- // Stop if necessary
- if(m_nState!=stStopped)
- m_pVideoDecoder->Stop();
- // Start video
- m_pVideoDecoder->Start(&video_opt);
- m_nState = stFastRewind;
- break;
- case getFrameStartPos:
- // Stop if necessary
- if(m_nState!=stStopped)
- m_pVideoDecoder->Stop();
- m_nState = stStopped;
- nCommandResult = m_pVideoDecoder->GetLastDecodedFrameStart();
- break;
- case play:
- // Stop if necessary
- if(m_nState!=stStopped)
- m_pVideoDecoder->Stop();
-
- // Set the sync point
- video_opt.bStartInSync = true;
- video_opt.nSyncPoint = m_pVideoDecoder->GetSyncPoint( m_pVideoDecoder->GetLastDecodedFrameStart() );
-
- // Start video
- m_pVideoDecoder->Start(&video_opt);
- DBG_STR((str, "Starting Video Playing at %I64d ms\n", m_pMasterClock->GetTickCount()/10 ))
-
- // Set this to false for all the rest of modes
- video_opt.bStartInSync = false;
-
- perfState = perfNormal;
-
- m_nState = stPlaying;
- m_lPlayFrameCount = 0;
- break;
- case playBack:
- // Stop if necessary
- if(m_nState!=stStopped)
- m_pVideoDecoder->Stop();
-
- // Start video
- m_pVideoDecoder->Start(&video_opt);
- m_nState = stPlayingBack;
- break;
- case ppChange:
- pp.Stop();
- m_pp = *((TPPost *)(sCommand.nParam));
- pp.Set(&m_pp);
- pp.Start();
- frProcessedFrame.Set( pp.GetWidth(), pp.GetHeight(), FRAME_YV12 );
- break;
- case stop:
- // Stop if necessary
- if(m_nState!=stStopped)
- m_pVideoDecoder->Stop();
- m_nState = stStopped;
- break;
- case exit:
- if(m_nState!=stStopped)
- m_pVideoDecoder->Stop();
-
- if(video_opt.pFrameBuffer)
- delete video_opt.pFrameBuffer;
-
- // Reply the command
- ReplyCommand(&sCommand);
- // Exit
- return 0;
- break;
- }
- ReplyCommand(&sCommand, nCommandResult);
- }
- else // No command. Wait if stopped
- {
- if(m_nState==stStopped)
- WaitCommand();
- }
-
- // Perform action according the state of the playe
-
-
- switch(m_nState)
- {
- case stStopped:
- break;
- case stPlaying:
- if( !m_pVideoDecoder->GetFrame(&pDecodedFrame) )
- Stop();
-
- // If there is a frame to display
- // time it
- if( pDecodedFrame )
- {
- // Timing
- tkFrameDelay = pDecodedFrame->GetDuration();
- tkPresTime = pDecodedFrame->GetPresTime()/2700;
- tkCurrentTime = m_pMasterClock->GetTickCount();
-
- if ( !tkPresTime )// If we dont have presentation time wait the frame delay
- {
- // FIXME
- // THIS IS NOT CORRECT given that the decoding time is not
- // instantaneous. You should wait less than the frame delay here.
- m_pMasterClock->Wait( tkFrameDelay , tkFrameDelay );
- DBG_STR((str, "NO TIMESTAMP. Waiting %I64d ms\n", tkFrameDelay/10))
- }
- else if ( tkPresTime >= tkCurrentTime )
- {
- perfState = perfNormal;
- tkWaitTime = tkPresTime - tkCurrentTime;
- m_pMasterClock->Wait( tkWaitTime, tkFrameDelay*4 );
- // DBG_STR((str, "Presenting frame: DR:%I64d ms PTS:%I64d CT:%I64d ms\n", tkWaitTime/10, tkPresTime/10, tkCurrentTime/10))
- }
- else if ( (tkCurrentTime-tkPresTime) >= 2500 )
- {
- // If its late by 1000 ms or more, probably
- // the video is lagging behind
- // set the master clock back
-
- // tkPresTime is < tkCurrentTime
-
- // m_pMasterClock->Set(tkPresTime);
- //DBG_STR((str, "Video lagging. Setting time to %I64d ms. Current Time was %I64d ms\n",
- // tkPresTime/10, tkCurrentTime/10))
- DBG_STR((str, "Video lagging behind.\n"));
- perfState = perfIOnly;
- }
-
-
- }
-
- m_lPlayFrameCount++;
- break;
- case stPlayingBack:
- m_pVideoDecoder->GetPrevFrame(&pDecodedFrame);
- break;
- case stNextFrame:
- m_pVideoDecoder->GetNextFrame(&pDecodedFrame);
- m_pVideoDecoder->Stop();
- m_nState = stStopped;
- break;
- case stPrevFrame:
- m_pVideoDecoder->GetPrevFrame(&pDecodedFrame);
- m_pVideoDecoder->Stop();
- m_nState = stStopped;
- break;
- case stNextKeyFrame:
- m_pVideoDecoder->GetNextIFrame(&pDecodedFrame);
- m_pVideoDecoder->Stop();
- m_nState = stStopped;
- break;
- case stPrevKeyFrame:
- m_pVideoDecoder->GetPrevIFrame(&pDecodedFrame);
- m_pVideoDecoder->Stop();
- m_nState = stStopped;
- break;
- case stFastForward:
- m_pVideoDecoder->GetNextIFrame(&pDecodedFrame);
- break;
- case stFastRewind:
- m_pVideoDecoder->GetPrevIFrame(&pDecodedFrame);
- break;
- }
-
- // If something to draw, draw it
- if(pDecodedFrame)
- {
- if( perfState == perfNormal || (m_lPlayFrameCount%20 == 0) || m_nState!=stPlaying )
- {
- // If there is a video sink, pass the frame over
- if(m_pVidSink)
- m_pVidSink->PutFrame(pDecodedFrame);
-
- // Continue regular renderer
- pp.Process(pDecodedFrame, &frProcessedFrame);
-
-
- rs.pVideoRenderer->Draw(&frProcessedFrame);
- }
- pDecodedFrame->Release();
- }
-
- // If we're going to stopeed, pause the video renderer
- if(m_nState==stStopped)
- {
- rs.pVideoRenderer->StopPlaying();
- if( pDecodedFrame ) rs.pVideoRenderer->SetStaticFrame(&frProcessedFrame);
- }
- else
- rs.pVideoRenderer->StartPlaying();
- }
-
- pp.Stop();
- }