mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2024-12-11 13:11:47 +00:00
Fixed FFmpeg video timings and crashes. Also fixes the black screen problem with Ubuntu 14.04 #92
This commit is contained in:
parent
e47429f532
commit
8943a6d4a2
6 changed files with 180 additions and 23 deletions
|
@ -16,7 +16,7 @@ option(OPENAL
|
|||
"Use OpenAL soft instead of XAudio2" OFF)
|
||||
|
||||
option(FFMPEG
|
||||
"Use FMPEG to render Bink videos" OFF)
|
||||
"Use FMPEG to render Bink videos" ON)
|
||||
|
||||
if(UNIX)
|
||||
set(OPENAL TRUE)
|
||||
|
|
|
@ -113,8 +113,8 @@ idGameEdit* gameEdit = NULL;
|
|||
idCommonLocal commonLocal;
|
||||
idCommon* common = &commonLocal;
|
||||
|
||||
|
||||
idCVar com_skipIntroVideos( "com_skipIntroVideos", "0", CVAR_BOOL , "skips intro videos" );
|
||||
// RB: defaulted this to 1 because we don't have a sound for the intro .bik video
|
||||
idCVar com_skipIntroVideos( "com_skipIntroVideos", "1", CVAR_BOOL , "skips intro videos" );
|
||||
|
||||
// For doom classic
|
||||
struct Globals;
|
||||
|
@ -900,14 +900,101 @@ void idCommonLocal::RenderBink( const char* path )
|
|||
material->Parse( materialText.c_str(), materialText.Length(), false );
|
||||
material->ResetCinematicTime( Sys_Milliseconds() );
|
||||
|
||||
while( Sys_Milliseconds() <= material->GetCinematicStartTime() + material->CinematicLength() )
|
||||
// RB: FFmpeg might return the wrong play length so I changed the intro video to play max 30 seconds until finished
|
||||
int cinematicLength = 30000; //material->CinematicLength();
|
||||
int mouseEvents[MAX_MOUSE_EVENTS][2];
|
||||
|
||||
bool escapeEvent = false;
|
||||
while( ( Sys_Milliseconds() <= ( material->GetCinematicStartTime() + cinematicLength ) ) && material->CinematicIsPlaying() )
|
||||
{
|
||||
renderSystem->DrawStretchPic( chop, 0, imageWidth, renderSystem->GetVirtualHeight(), 0, 0, 1, 1, material );
|
||||
const emptyCommand_t* cmd = renderSystem->SwapCommandBuffers( &time_frontend, &time_backend, &time_shadows, &time_gpu );
|
||||
renderSystem->RenderCommandBuffers( cmd );
|
||||
|
||||
Sys_GenerateEvents();
|
||||
|
||||
// queue system events ready for polling
|
||||
Sys_GetEvent();
|
||||
|
||||
// RB: allow to escape video by pressing anything
|
||||
int numKeyEvents = Sys_PollKeyboardInputEvents();
|
||||
if( numKeyEvents > 0 )
|
||||
{
|
||||
for( int i = 0; i < numKeyEvents; i++ )
|
||||
{
|
||||
int key;
|
||||
bool state;
|
||||
|
||||
if( Sys_ReturnKeyboardInputEvent( i, key, state ) )
|
||||
{
|
||||
if( key == K_ESCAPE && state == true )
|
||||
{
|
||||
escapeEvent = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Sys_EndKeyboardInputEvents();
|
||||
}
|
||||
|
||||
int numMouseEvents = Sys_PollMouseInputEvents( mouseEvents );
|
||||
if( numMouseEvents > 0 )
|
||||
{
|
||||
for( int i = 0; i < numMouseEvents; i++ )
|
||||
{
|
||||
int action = mouseEvents[i][0];
|
||||
switch( action )
|
||||
{
|
||||
case M_ACTION1:
|
||||
case M_ACTION2:
|
||||
case M_ACTION3:
|
||||
case M_ACTION4:
|
||||
case M_ACTION5:
|
||||
case M_ACTION6:
|
||||
case M_ACTION7:
|
||||
case M_ACTION8:
|
||||
escapeEvent = true;
|
||||
break;
|
||||
|
||||
default: // some other undefined button
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int numJoystickEvents = Sys_PollJoystickInputEvents( 0 );
|
||||
if( numJoystickEvents > 0 )
|
||||
{
|
||||
for( int i = 0; i < numJoystickEvents; i++ )
|
||||
{
|
||||
int action;
|
||||
int value;
|
||||
|
||||
if( Sys_ReturnJoystickInputEvent( i, action, value ) )
|
||||
{
|
||||
if( action >= J_ACTION1 && action <= J_ACTION_MAX )
|
||||
{
|
||||
if( value != 0 )
|
||||
{
|
||||
escapeEvent = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Sys_EndJoystickInputEvents();
|
||||
}
|
||||
|
||||
if( escapeEvent )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
Sys_Sleep( 10 );
|
||||
}
|
||||
// RB end
|
||||
|
||||
material->MakeDefault();
|
||||
}
|
||||
|
|
|
@ -75,6 +75,9 @@ public:
|
|||
virtual bool InitFromFile( const char* qpath, bool looping );
|
||||
virtual cinData_t ImageForTime( int milliseconds );
|
||||
virtual int AnimationLength();
|
||||
// RB begin
|
||||
bool IsPlaying() const;
|
||||
// RB end
|
||||
virtual void Close();
|
||||
virtual void ResetTime( int time );
|
||||
|
||||
|
@ -89,7 +92,7 @@ private:
|
|||
AVCodecContext* dec_ctx;
|
||||
SwsContext* img_convert_ctx;
|
||||
bool hasFrame;
|
||||
long FramePos;
|
||||
long framePos;
|
||||
|
||||
cinData_t ImageForTimeFFMPEG( int milliseconds );
|
||||
bool InitFromFFMPEGFile( const char* qpath, bool looping );
|
||||
|
@ -359,6 +362,13 @@ void idCinematic::Close()
|
|||
{
|
||||
}
|
||||
|
||||
// RB begin
|
||||
bool idCinematic::IsPlaying() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// RB end
|
||||
|
||||
|
||||
//===========================================
|
||||
|
||||
|
@ -511,19 +521,25 @@ bool idCinematicLocal::InitFromFFMPEGFile( const char* qpath, bool amilooping )
|
|||
float durationSec = static_cast<double>( fmt_ctx->streams[video_stream_index]->duration ) * static_cast<double>( ticksPerFrame ) / static_cast<double>( avr.den );
|
||||
animationLength = durationSec * 1000;
|
||||
frameRate = av_q2d( fmt_ctx->streams[video_stream_index]->r_frame_rate );
|
||||
startTime = 0;
|
||||
buf = NULL;
|
||||
hasFrame = false;
|
||||
FramePos = -1;
|
||||
framePos = -1;
|
||||
common->Warning( "%dx%d, %f FPS, %f sec", CIN_WIDTH, CIN_HEIGHT, frameRate, durationSec );
|
||||
image = ( byte* )Mem_Alloc( CIN_WIDTH * CIN_HEIGHT * 4 * 2, TAG_CINEMATIC );
|
||||
avpicture_fill( ( AVPicture* )frame2, image, PIX_FMT_BGR32, CIN_WIDTH, CIN_HEIGHT );
|
||||
if( img_convert_ctx )
|
||||
{
|
||||
sws_freeContext( img_convert_ctx );
|
||||
}
|
||||
img_convert_ctx = sws_getContext( dec_ctx->width, dec_ctx->height, dec_ctx->pix_fmt, CIN_WIDTH, CIN_HEIGHT, PIX_FMT_BGR32, SWS_BICUBIC, NULL, NULL, NULL );
|
||||
status = FMV_PLAY;
|
||||
|
||||
startTime = 0;
|
||||
ImageForTime( 0 );
|
||||
status = ( looping ) ? FMV_PLAY : FMV_IDLE;
|
||||
|
||||
//startTime = Sys_Milliseconds();
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
@ -536,10 +552,19 @@ idCinematicLocal::FFMPEGReset
|
|||
#if defined(USE_FFMPEG)
|
||||
void idCinematicLocal::FFMPEGReset()
|
||||
{
|
||||
startTime = 0;
|
||||
FramePos = -1;
|
||||
av_seek_frame( fmt_ctx, video_stream_index, 0, 0 );
|
||||
status = FMV_LOOPED;
|
||||
// RB: don't reset startTime here because that breaks video replays in the PDAs
|
||||
//startTime = 0;
|
||||
|
||||
framePos = -1;
|
||||
|
||||
if( av_seek_frame( fmt_ctx, video_stream_index, 0, 0 ) >= 0 )
|
||||
{
|
||||
status = FMV_LOOPED;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = FMV_EOF;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -683,6 +708,13 @@ int idCinematicLocal::AnimationLength()
|
|||
return animationLength;
|
||||
}
|
||||
|
||||
// RB begin
|
||||
bool idCinematicLocal::IsPlaying() const
|
||||
{
|
||||
return ( status == FMV_PLAY );
|
||||
}
|
||||
// RB end
|
||||
|
||||
/*
|
||||
==============
|
||||
idCinematicLocal::ResetTime
|
||||
|
@ -840,6 +872,12 @@ cinData_t idCinematicLocal::ImageForTimeFFMPEG( int thisTime )
|
|||
return cinData;
|
||||
}
|
||||
|
||||
if( !fmt_ctx )
|
||||
{
|
||||
// RB: .bik requested but not found
|
||||
return cinData;
|
||||
}
|
||||
|
||||
if( ( !hasFrame ) || startTime == -1 )
|
||||
{
|
||||
if( startTime == -1 )
|
||||
|
@ -849,10 +887,18 @@ cinData_t idCinematicLocal::ImageForTimeFFMPEG( int thisTime )
|
|||
startTime = thisTime;
|
||||
}
|
||||
|
||||
long DesiredFrame = ( ( thisTime - startTime ) * frameRate ) / 1000;
|
||||
if( DesiredFrame < 0 ) DesiredFrame = 0;
|
||||
if( DesiredFrame < FramePos ) FFMPEGReset();
|
||||
if( hasFrame && DesiredFrame == FramePos )
|
||||
long desiredFrame = ( ( thisTime - startTime ) * frameRate ) / 1000;
|
||||
if( desiredFrame < 0 )
|
||||
{
|
||||
desiredFrame = 0;
|
||||
}
|
||||
|
||||
if( desiredFrame < framePos )
|
||||
{
|
||||
FFMPEGReset();
|
||||
}
|
||||
|
||||
if( hasFrame && desiredFrame == framePos )
|
||||
{
|
||||
cinData.imageWidth = CIN_WIDTH;
|
||||
cinData.imageHeight = CIN_HEIGHT;
|
||||
|
@ -862,22 +908,23 @@ cinData_t idCinematicLocal::ImageForTimeFFMPEG( int thisTime )
|
|||
}
|
||||
|
||||
AVPacket packet;
|
||||
while( FramePos < DesiredFrame )
|
||||
while( framePos < desiredFrame )
|
||||
{
|
||||
int frameFinished = 0;
|
||||
//Do a single frame by getting packets until we have a full frame
|
||||
|
||||
// Do a single frame by getting packets until we have a full frame
|
||||
while( !frameFinished )
|
||||
{
|
||||
//if we got to the end or failed
|
||||
// if we got to the end or failed
|
||||
if( av_read_frame( fmt_ctx, &packet ) < 0 )
|
||||
{
|
||||
//can't read any more, set to EOF
|
||||
// can't read any more, set to EOF
|
||||
status = FMV_EOF;
|
||||
if( looping )
|
||||
{
|
||||
DesiredFrame = 0;
|
||||
desiredFrame = 0;
|
||||
FFMPEGReset();
|
||||
FramePos = -1;
|
||||
framePos = -1;
|
||||
startTime = thisTime;
|
||||
if( av_read_frame( fmt_ctx, &packet ) < 0 )
|
||||
{
|
||||
|
@ -901,8 +948,10 @@ cinData_t idCinematicLocal::ImageForTimeFFMPEG( int thisTime )
|
|||
// Free the packet that was allocated by av_read_frame
|
||||
av_free_packet( &packet );
|
||||
}
|
||||
FramePos++;
|
||||
|
||||
framePos++;
|
||||
}
|
||||
|
||||
// We have reached the desired frame
|
||||
// Convert the image from its native format to RGB
|
||||
sws_scale( img_convert_ctx, frame->data, frame->linesize, 0, dec_ctx->height, frame2->data, frame2->linesize );
|
||||
|
@ -912,6 +961,7 @@ cinData_t idCinematicLocal::ImageForTimeFFMPEG( int thisTime )
|
|||
img->UploadScratch( image, CIN_WIDTH, CIN_HEIGHT );
|
||||
hasFrame = true;
|
||||
cinData.image = img;
|
||||
|
||||
return cinData;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -89,6 +89,10 @@ public:
|
|||
// returns the length of the animation in milliseconds
|
||||
virtual int AnimationLength();
|
||||
|
||||
// RB: let us know wether this video went EOF or is still active
|
||||
virtual bool IsPlaying() const;
|
||||
// RB end
|
||||
|
||||
// the pointers in cinData_t will remain valid until the next UpdateForTime() call
|
||||
virtual cinData_t ImageForTime( int milliseconds );
|
||||
|
||||
|
|
|
@ -3157,6 +3157,18 @@ int idMaterial::GetCinematicStartTime() const
|
|||
return -1;
|
||||
}
|
||||
|
||||
// RB: added because we can't rely on the FFmpeg feedback how long a video really is
|
||||
bool idMaterial::CinematicIsPlaying() const
|
||||
{
|
||||
if( !stages || !stages[0].texture.cinematic )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return stages[0].texture.cinematic->IsPlaying();
|
||||
}
|
||||
// RB end
|
||||
|
||||
/*
|
||||
==================
|
||||
idMaterial::CheckForConstantRegisters
|
||||
|
|
|
@ -739,6 +739,10 @@ public:
|
|||
|
||||
void UpdateCinematic( int time ) const;
|
||||
|
||||
// RB: added because we can't rely on the FFmpeg feedback how long a video really is
|
||||
bool CinematicIsPlaying() const;
|
||||
// RB end
|
||||
|
||||
//------------------------------------------------------------------
|
||||
|
||||
// gets an image for the editor to use
|
||||
|
|
Loading…
Reference in a new issue