mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2025-04-24 10:38:53 +00:00
More cinematic audio memory mgmt fixes, support cinematic audio looping
(cherry picked from commit bb0b260baa187d2dd88ef2a631e7b7f163095b10)
This commit is contained in:
parent
922f9eddef
commit
22cd420513
7 changed files with 125 additions and 64 deletions
|
@ -862,7 +862,7 @@ void idCommonLocal::Frame()
|
|||
// RB begin
|
||||
#if defined(USE_DOOMCLASSIC)
|
||||
// If we're in Doom or Doom 2, run tics and upload the new texture.
|
||||
// SRS - Add check for com_pause cvar to make sure window is in focus - if not classic game should be paused (FIXME: but classic music still plays in background)
|
||||
// SRS - Add check for com_pause cvar to make sure window is in focus - if not classic game should be paused
|
||||
if( ( GetCurrentGame() == DOOM_CLASSIC || GetCurrentGame() == DOOM2_CLASSIC ) && !( Dialog().IsDialogPausing() || session->IsSystemUIShowing() || com_pause.GetInteger() ) )
|
||||
{
|
||||
RunDoomClassicFrame();
|
||||
|
@ -922,16 +922,18 @@ void idCommonLocal::Frame()
|
|||
{
|
||||
soundWorld->Pause();
|
||||
soundSystem->SetPlayingSoundWorld( menuSoundWorld );
|
||||
soundSystem->SetMute( false );
|
||||
}
|
||||
else
|
||||
{
|
||||
soundWorld->UnPause();
|
||||
soundSystem->SetPlayingSoundWorld( soundWorld );
|
||||
soundSystem->SetMute( false );
|
||||
}
|
||||
// SRS - Play silence when dialog waiting or window not in focus
|
||||
// SRS - Mute all sound output when dialog waiting or window not in focus (mutes Doom3, Classic, Cinematic Audio)
|
||||
if( Dialog().IsDialogPausing() || session->IsSystemUIShowing() || com_pause.GetInteger() )
|
||||
{
|
||||
soundSystem->SetPlayingSoundWorld( NULL );
|
||||
soundSystem->SetMute( true );
|
||||
}
|
||||
|
||||
soundSystem->Render();
|
||||
|
|
|
@ -548,30 +548,9 @@ idCinematicLocal::~idCinematicLocal()
|
|||
av_freep( &frame2 );
|
||||
av_freep( &frame3 );
|
||||
#endif
|
||||
|
||||
// SRS - Free any lagged cinematic audio buffers
|
||||
for( int i = 0; i < NUM_LAG_FRAMES; i++ )
|
||||
{
|
||||
av_freep( &lagBuffer[ i ] );
|
||||
}
|
||||
|
||||
if( fmt_ctx )
|
||||
{
|
||||
avformat_free_context( fmt_ctx );
|
||||
}
|
||||
|
||||
if( img_convert_ctx )
|
||||
{
|
||||
sws_freeContext( img_convert_ctx );
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_BINKDEC
|
||||
if( binkHandle.isValid )
|
||||
{
|
||||
Bink_Close( binkHandle );
|
||||
}
|
||||
|
||||
delete imgY;
|
||||
imgY = NULL;
|
||||
delete imgCr;
|
||||
|
@ -794,10 +773,6 @@ bool idCinematicLocal::InitFromFFMPEGFile( const char* qpath, bool amilooping )
|
|||
int img_bytes = av_image_fill_arrays( frame2->data, frame2->linesize, NULL, AV_PIX_FMT_BGR32, CIN_WIDTH, CIN_HEIGHT, 1 );
|
||||
image = ( byte* )Mem_Alloc( img_bytes, TAG_CINEMATIC );
|
||||
av_image_fill_arrays( frame2->data, frame2->linesize, image, AV_PIX_FMT_BGR32, CIN_WIDTH, CIN_HEIGHT, 1 ); //GK: Straight out of the FFMPEG source code
|
||||
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, AV_PIX_FMT_BGR32, SWS_BICUBIC, NULL, NULL, NULL );
|
||||
|
||||
buf = NULL;
|
||||
|
@ -823,6 +798,21 @@ void idCinematicLocal::FFMPEGReset()
|
|||
//startTime = 0;
|
||||
|
||||
framePos = -1;
|
||||
|
||||
// SRS - If we have an ffmpeg audio context and are not looping, reset audio to release any stale buffers
|
||||
if( dec_ctx2 && ! ( looping && status == FMV_EOF ) )
|
||||
{
|
||||
cinematicAudio->ResetAudio();
|
||||
|
||||
for( int i = 0; i < NUM_LAG_FRAMES; i++ )
|
||||
{
|
||||
lagBufSize[ i ] = 0;
|
||||
if( lagBuffer[ i ] )
|
||||
{
|
||||
av_freep( &lagBuffer[ i ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( av_seek_frame( fmt_ctx, video_stream_index, 0, 0 ) >= 0 )
|
||||
{
|
||||
|
@ -915,6 +905,13 @@ bool idCinematicLocal::InitFromBinkDecFile( const char* qpath, bool amilooping )
|
|||
void idCinematicLocal::BinkDecReset()
|
||||
{
|
||||
framePos = -1;
|
||||
|
||||
// SRS - If we have bink audio tracks, reset audio to release any stale buffers (even if looping)
|
||||
if( audioTracks > 0 )
|
||||
{
|
||||
cinematicAudio->ResetAudio();
|
||||
}
|
||||
|
||||
Bink_GotoFrame( binkHandle, 0 );
|
||||
status = FMV_LOOPED;
|
||||
}
|
||||
|
@ -961,16 +958,12 @@ bool idCinematicLocal::InitFromFile( const char* qpath, bool amilooping )
|
|||
//idLib::Warning( "Original Doom 3 RoQ Cinematic not found: '%s'\n", fileName.c_str() );
|
||||
idStr temp = fileName.StripFileExtension() + ".bik";
|
||||
animationLength = 0;
|
||||
hasFrame = false;
|
||||
RoQShutdown();
|
||||
fileName = temp;
|
||||
//idLib::Warning( "New filename: '%s'\n", fileName.c_str() );
|
||||
return InitFromFFMPEGFile( fileName.c_str(), amilooping );
|
||||
#elif defined(USE_BINKDEC)
|
||||
idStr temp = fileName.StripFileExtension() + ".bik";
|
||||
animationLength = 0;
|
||||
hasFrame = false;
|
||||
RoQShutdown();
|
||||
fileName = temp;
|
||||
//idLib::Warning( "New filename: '%s'\n", fileName.c_str() );
|
||||
return InitFromBinkDecFile( fileName.c_str(), amilooping );
|
||||
|
@ -1032,32 +1025,45 @@ void idCinematicLocal::Close()
|
|||
RoQShutdown();
|
||||
|
||||
#if defined(USE_FFMPEG)
|
||||
hasFrame = false;
|
||||
|
||||
if( !isRoQ )
|
||||
{
|
||||
if( img_convert_ctx )
|
||||
{
|
||||
sws_freeContext( img_convert_ctx );
|
||||
img_convert_ctx = NULL;
|
||||
}
|
||||
|
||||
img_convert_ctx = NULL;
|
||||
// SRS - Free audio codec context and any lagged audio buffers
|
||||
if( dec_ctx2 )
|
||||
{
|
||||
avcodec_close( dec_ctx2 );
|
||||
dec_ctx2 = NULL;
|
||||
|
||||
for( int i = 0; i < NUM_LAG_FRAMES; i++ )
|
||||
{
|
||||
lagBufSize[ i ] = 0;
|
||||
if( lagBuffer[ i ] )
|
||||
{
|
||||
av_freep( &lagBuffer[ i ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( dec_ctx )
|
||||
{
|
||||
avcodec_close( dec_ctx );
|
||||
dec_ctx = NULL;
|
||||
}
|
||||
|
||||
if( fmt_ctx )
|
||||
{
|
||||
avformat_close_input( &fmt_ctx );
|
||||
fmt_ctx = NULL;
|
||||
}
|
||||
status = FMV_EOF;
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_BINKDEC
|
||||
hasFrame = false;
|
||||
|
||||
if( !isRoQ )
|
||||
{
|
||||
if( binkHandle.isValid )
|
||||
|
@ -1322,7 +1328,6 @@ cinData_t idCinematicLocal::ImageForTimeFFMPEG( int thisTime )
|
|||
{
|
||||
desiredFrame = 0;
|
||||
FFMPEGReset();
|
||||
framePos = -1;
|
||||
startTime = thisTime;
|
||||
if( av_read_frame( fmt_ctx, &packet ) < 0 )
|
||||
{
|
||||
|
@ -1493,7 +1498,6 @@ cinData_t idCinematicLocal::ImageForTimeBinkDec( int thisTime )
|
|||
{
|
||||
desiredFrame = 0;
|
||||
BinkDecReset();
|
||||
framePos = -1;
|
||||
startTime = thisTime;
|
||||
status = FMV_PLAY;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ class CinematicAudio
|
|||
public:
|
||||
virtual void InitAudio( void* audioContext ) = 0;
|
||||
virtual void PlayAudio( uint8_t* data, int size ) = 0;
|
||||
virtual void ResetAudio() = 0;
|
||||
virtual void ShutdownAudio() = 0;
|
||||
};
|
||||
|
||||
|
|
|
@ -108,22 +108,29 @@ void CinematicAudio_OpenAL::PlayAudio( uint8_t* data, int size )
|
|||
|
||||
if( trigger )
|
||||
{
|
||||
tBuffer->push( data );
|
||||
sizes->push( size );
|
||||
tBuffer.push( data );
|
||||
sizes.push( size );
|
||||
while( processed > 0 )
|
||||
{
|
||||
ALuint bufid;
|
||||
|
||||
alSourceUnqueueBuffers( alMusicSourceVoicecin, 1, &bufid );
|
||||
processed--;
|
||||
if( !tBuffer->empty() )
|
||||
// SRS - Only unqueue an alBuffer if we don't already have a free bufid to use
|
||||
if( bufids.size() == 0 )
|
||||
{
|
||||
int tempSize = sizes->front();
|
||||
sizes->pop();
|
||||
uint8_t* tempdata = tBuffer->front();
|
||||
tBuffer->pop();
|
||||
alSourceUnqueueBuffers( alMusicSourceVoicecin, 1, &bufid );
|
||||
bufids.push( bufid );
|
||||
processed--;
|
||||
}
|
||||
if( !tBuffer.empty() )
|
||||
{
|
||||
uint8_t* tempdata = tBuffer.front();
|
||||
tBuffer.pop();
|
||||
int tempSize = sizes.front();
|
||||
sizes.pop();
|
||||
if( tempSize > 0 )
|
||||
{
|
||||
bufid = bufids.front();
|
||||
bufids.pop();
|
||||
alBufferData( bufid, av_sample_cin, tempdata, tempSize, av_rate_cin );
|
||||
// SRS - We must free the audio buffer once it has been copied into an alBuffer
|
||||
#if defined(USE_FFMPEG)
|
||||
|
@ -140,6 +147,10 @@ void CinematicAudio_OpenAL::PlayAudio( uint8_t* data, int size )
|
|||
}
|
||||
}
|
||||
}
|
||||
else // SRS - When no new audio frames left to queue, break and continue playing
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -186,18 +197,49 @@ void CinematicAudio_OpenAL::PlayAudio( uint8_t* data, int size )
|
|||
}
|
||||
}
|
||||
|
||||
void CinematicAudio_OpenAL::ResetAudio()
|
||||
{
|
||||
if( alIsSource( alMusicSourceVoicecin ) )
|
||||
{
|
||||
alSourceRewind( alMusicSourceVoicecin );
|
||||
alSourcei( alMusicSourceVoicecin, AL_BUFFER, 0 );
|
||||
}
|
||||
|
||||
if( !tBuffer.empty() )
|
||||
{
|
||||
int buffersize = tBuffer.size();
|
||||
while( buffersize > 0 )
|
||||
{
|
||||
uint8_t* tempdata = tBuffer.front();
|
||||
tBuffer.pop();
|
||||
// SRS - We must free any audio buffers that have not been copied into an alBuffer
|
||||
#if defined(USE_FFMPEG)
|
||||
av_freep( &tempdata );
|
||||
#elif defined(USE_BINKDEC)
|
||||
Mem_Free( tempdata );
|
||||
#endif
|
||||
buffersize--;
|
||||
}
|
||||
}
|
||||
if( !sizes.empty() )
|
||||
{
|
||||
int buffersize = sizes.size();
|
||||
while( buffersize > 0 )
|
||||
{
|
||||
sizes.pop();
|
||||
buffersize--;
|
||||
}
|
||||
}
|
||||
|
||||
offset = 0;
|
||||
trigger = false;
|
||||
}
|
||||
|
||||
void CinematicAudio_OpenAL::ShutdownAudio()
|
||||
{
|
||||
if( alIsSource( alMusicSourceVoicecin ) )
|
||||
{
|
||||
alSourceStop( alMusicSourceVoicecin );
|
||||
// SRS - Make sure we don't try to unqueue buffers that were never processed
|
||||
ALint processed;
|
||||
alGetSourcei( alMusicSourceVoicecin, AL_BUFFERS_PROCESSED, &processed );
|
||||
if( processed > 0 )
|
||||
{
|
||||
alSourceUnqueueBuffers( alMusicSourceVoicecin, processed, alMusicBuffercin );
|
||||
}
|
||||
alSourcei( alMusicSourceVoicecin, AL_BUFFER, 0 );
|
||||
alDeleteSources( 1, &alMusicSourceVoicecin );
|
||||
if( CheckALErrors() == AL_NO_ERROR )
|
||||
|
@ -210,13 +252,13 @@ void CinematicAudio_OpenAL::ShutdownAudio()
|
|||
{
|
||||
alDeleteBuffers( NUM_BUFFERS, alMusicBuffercin );
|
||||
}
|
||||
if( !tBuffer->empty() )
|
||||
if( !tBuffer.empty() )
|
||||
{
|
||||
int buffersize = tBuffer->size();
|
||||
int buffersize = tBuffer.size();
|
||||
while( buffersize > 0 )
|
||||
{
|
||||
uint8_t* tempdata = tBuffer->front();
|
||||
tBuffer->pop();
|
||||
uint8_t* tempdata = tBuffer.front();
|
||||
tBuffer.pop();
|
||||
// SRS - We must free any audio buffers that have not been copied into an alBuffer
|
||||
#if defined(USE_FFMPEG)
|
||||
av_freep( &tempdata );
|
||||
|
@ -226,12 +268,12 @@ void CinematicAudio_OpenAL::ShutdownAudio()
|
|||
buffersize--;
|
||||
}
|
||||
}
|
||||
if( !sizes->empty() )
|
||||
if( !sizes.empty() )
|
||||
{
|
||||
int buffersize = sizes->size();
|
||||
int buffersize = sizes.size();
|
||||
while( buffersize > 0 )
|
||||
{
|
||||
sizes->pop();
|
||||
sizes.pop();
|
||||
buffersize--;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ public:
|
|||
CinematicAudio_OpenAL();
|
||||
void InitAudio( void* audioContext );
|
||||
void PlayAudio( uint8_t* data, int size );
|
||||
void ResetAudio();
|
||||
void ShutdownAudio();
|
||||
private:
|
||||
ALuint alMusicSourceVoicecin;
|
||||
|
@ -55,8 +56,9 @@ private:
|
|||
// So, what happens if there are no freely available buffers but we still geting audio frames ? Loss of data.
|
||||
// That why now I am using two queues in order to store the frames (and their sizes) and when we have available buffers,
|
||||
// then start popping those frames instead of the current, so we don't lose any audio frames and the sound doesn't crack anymore.
|
||||
std::queue<uint8_t*> tBuffer[NUM_BUFFERS];
|
||||
std::queue<int> sizes[NUM_BUFFERS];
|
||||
std::queue<uint8_t*> tBuffer;
|
||||
std::queue<int> sizes;
|
||||
std::queue<ALuint> bufids; // SRS - Added queue of free alBuffer ids to handle audio frame underflow (starvation) case
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -179,6 +179,15 @@ void CinematicAudio_XAudio2::PlayAudio( uint8_t* data, int size )
|
|||
}
|
||||
}
|
||||
|
||||
void CinematicAudio_XAudio2::ResetAudio()
|
||||
{
|
||||
if( pMusicSourceVoice1 )
|
||||
{
|
||||
pMusicSourceVoice1->Stop();
|
||||
pMusicSourceVoice1->FlushSourceBuffers();
|
||||
}
|
||||
}
|
||||
|
||||
void CinematicAudio_XAudio2::ShutdownAudio()
|
||||
{
|
||||
if( pMusicSourceVoice1 )
|
||||
|
|
|
@ -33,6 +33,7 @@ public:
|
|||
CinematicAudio_XAudio2();
|
||||
void InitAudio( void* audioContext );
|
||||
void PlayAudio( uint8_t* data, int size );
|
||||
void ResetAudio();
|
||||
void ShutdownAudio();
|
||||
private:
|
||||
WAVEFORMATEX voiceFormatcine = { 0 };
|
||||
|
|
Loading…
Reference in a new issue