mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2025-03-14 22:50:45 +00:00
Fix for cinematic audio when playing Bink video files with ffmpeg decoder, improve ffmpeg a/v resync
This commit is contained in:
parent
8f84e54bb0
commit
f7751f6428
1 changed files with 47 additions and 34 deletions
|
@ -130,9 +130,8 @@ private:
|
|||
cinData_t ImageForTimeFFMPEG( int milliseconds, nvrhi::ICommandList* commandList );
|
||||
bool InitFromFFMPEGFile( const char* qpath, bool looping, nvrhi::ICommandList* commandList );
|
||||
void FFMPEGReset();
|
||||
uint8_t* lagBuffer[NUM_LAG_FRAMES] = {};
|
||||
int lagBufSize[NUM_LAG_FRAMES] = {};
|
||||
int lagIndex;
|
||||
std::queue<uint8_t*> lagBuffer;
|
||||
std::queue<int> lagBufSize;
|
||||
bool skipLag;
|
||||
#endif
|
||||
#ifdef USE_BINKDEC
|
||||
|
@ -469,7 +468,6 @@ idCinematicLocal::idCinematicLocal()
|
|||
img_convert_ctx = NULL;
|
||||
hasFrame = false;
|
||||
framePos = -1;
|
||||
lagIndex = 0;
|
||||
skipLag = false;
|
||||
#endif
|
||||
|
||||
|
@ -842,14 +840,11 @@ void idCinematicLocal::FFMPEGReset()
|
|||
{
|
||||
cinematicAudio->ResetAudio();
|
||||
|
||||
lagIndex = 0;
|
||||
for( int i = 0; i < NUM_LAG_FRAMES; i++ )
|
||||
while( !lagBuffer.empty() )
|
||||
{
|
||||
lagBufSize[ i ] = 0;
|
||||
if( lagBuffer[ i ] )
|
||||
{
|
||||
av_freep( &lagBuffer[ i ] );
|
||||
}
|
||||
av_freep( &lagBuffer.front() );
|
||||
lagBuffer.pop();
|
||||
lagBufSize.pop();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -910,7 +905,7 @@ bool idCinematicLocal::InitFromBinkDecFile( const char* qpath, bool amilooping,
|
|||
}
|
||||
else
|
||||
{
|
||||
common->Warning( "idCinematic: Cannot open BinkDec video file: '%s', %d\n", qpath, looping );
|
||||
common->Warning( "idCinematic: Cannot open Bink video file: '%s', %d\n", qpath, looping );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -918,7 +913,7 @@ bool idCinematicLocal::InitFromBinkDecFile( const char* qpath, bool amilooping,
|
|||
binkHandle = Bink_Open( fullpath );
|
||||
if( !binkHandle.isValid )
|
||||
{
|
||||
common->Warning( "idCinematic: Cannot open BinkDec video file: '%s', %d\n", qpath, looping );
|
||||
common->Warning( "idCinematic: Cannot open Bink video file: '%s', %d\n", qpath, looping );
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -948,7 +943,7 @@ bool idCinematicLocal::InitFromBinkDecFile( const char* qpath, bool amilooping,
|
|||
numFrames = Bink_GetNumFrames( binkHandle );
|
||||
float durationSec = numFrames / frameRate; // SRS - fixed Bink durationSec calculation
|
||||
animationLength = durationSec * 1000; // SRS - animationLength is in milliseconds
|
||||
common->Printf( "Loaded BinkDec file: '%s', looping=%d, %dx%d, %3.2f FPS, %4.1f sec\n", qpath, looping, CIN_WIDTH, CIN_HEIGHT, frameRate, durationSec );
|
||||
common->Printf( "Loaded Bink file: '%s', looping=%d, %dx%d, %3.2f FPS, %4.1f sec\n", qpath, looping, CIN_WIDTH, CIN_HEIGHT, frameRate, durationSec );
|
||||
|
||||
memset( yuvBuffer, 0, sizeof( yuvBuffer ) );
|
||||
|
||||
|
@ -1174,14 +1169,11 @@ void idCinematicLocal::Close()
|
|||
swr_free( &swr_ctx );
|
||||
}
|
||||
|
||||
lagIndex = 0;
|
||||
for( int i = 0; i < NUM_LAG_FRAMES; i++ )
|
||||
while( !lagBuffer.empty() )
|
||||
{
|
||||
lagBufSize[ i ] = 0;
|
||||
if( lagBuffer[ i ] )
|
||||
{
|
||||
av_freep( &lagBuffer[ i ] );
|
||||
}
|
||||
av_freep( &lagBuffer.front() );
|
||||
lagBuffer.pop();
|
||||
lagBufSize.pop();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1378,6 +1370,7 @@ cinData_t idCinematicLocal::ImageForTimeFFMPEG( int thisTime, nvrhi::ICommandLis
|
|||
char error[64];
|
||||
uint8_t* audioBuffer = NULL;
|
||||
int num_bytes = 0;
|
||||
bool syncLost = false;
|
||||
|
||||
memset( &cinData, 0, sizeof( cinData ) );
|
||||
if( !fmt_ctx )
|
||||
|
@ -1491,8 +1484,8 @@ cinData_t idCinematicLocal::ImageForTimeFFMPEG( int thisTime, nvrhi::ICommandLis
|
|||
common->Warning( "idCinematic: Failed to receive audio frame from decoding with error: %s\n", error );
|
||||
}
|
||||
}
|
||||
// SRS - For the final (desired) frame only: allocate audio buffers, convert to packed format, and play the synced audio frames
|
||||
else if( framePos + 1 == desiredFrame )
|
||||
// SRS - Allocate audio buffer, convert to packed format, save in queue, and play synced audio for desired frame
|
||||
else
|
||||
{
|
||||
// SRS - Since destination sample format is packed (non-planar), returned bufflinesize equals num_bytes
|
||||
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(59,37,100)
|
||||
|
@ -1521,28 +1514,48 @@ cinData_t idCinematicLocal::ImageForTimeFFMPEG( int thisTime, nvrhi::ICommandLis
|
|||
memcpy( audioBuffer, frame3->extended_data[0], num_bytes );
|
||||
}
|
||||
}
|
||||
// SRS - If we have cinematic audio data, play a lagged frame (for bik video sync) and save the current frame
|
||||
|
||||
// SRS - If we have cinematic audio data, save the current frame onto the back of the queue
|
||||
if( num_bytes > 0 )
|
||||
{
|
||||
// SRS - If we have a lagged cinematic audio frame, then play it now
|
||||
if( lagBufSize[ lagIndex ] > 0 )
|
||||
// SRS - If queue is at max size we have lost a/v sync: drop frame and set syncLost flag
|
||||
if( lagBuffer.size() == ( skipLag ? 1 : NUM_LAG_FRAMES ) )
|
||||
{
|
||||
// SRS - Note that PlayAudio() is responsible for releasing any audio buffers sent to it
|
||||
cinematicAudio->PlayAudio( lagBuffer[ lagIndex ], lagBufSize[ lagIndex ] );
|
||||
av_freep( &lagBuffer.front() );
|
||||
lagBuffer.pop();
|
||||
lagBufSize.pop();
|
||||
|
||||
syncLost = true;
|
||||
}
|
||||
|
||||
// SRS - Save the current (new) audio buffer and its size to play in the future
|
||||
lagBuffer[ lagIndex ] = audioBuffer;
|
||||
lagBufSize[ lagIndex ] = num_bytes;
|
||||
|
||||
// SRS - If skipLag is true (e.g. RoQ, mp4, webm), reduce lag to 1 frame since AV playback is already synced
|
||||
lagIndex = ( lagIndex + 1 ) % ( skipLag ? 1 : NUM_LAG_FRAMES );
|
||||
// SRS - Save the current (new) audio buffer and its size to play during the desired frame
|
||||
lagBuffer.push( audioBuffer );
|
||||
lagBufSize.push( num_bytes );
|
||||
}
|
||||
// SRS - Not sure if an audioBuffer can ever be allocated on failure, but check and free just in case
|
||||
else if( audioBuffer )
|
||||
{
|
||||
av_freep( &audioBuffer );
|
||||
}
|
||||
|
||||
// SRS - If we have any synced audio frames available for the desired frame, play now and drain queue
|
||||
if( framePos + 1 == desiredFrame )
|
||||
{
|
||||
if( syncLost )
|
||||
{
|
||||
// SRS - If we have lost sync, reset / resync audio stream before starting to play again
|
||||
cinematicAudio->ResetAudio();
|
||||
syncLost = false;
|
||||
}
|
||||
|
||||
while( !lagBuffer.empty() )
|
||||
{
|
||||
// SRS - Note that PlayAudio() is responsible for releasing any audio buffers sent to it
|
||||
cinematicAudio->PlayAudio( lagBuffer.front(), lagBufSize.front() );
|
||||
lagBuffer.pop();
|
||||
lagBufSize.pop();
|
||||
}
|
||||
}
|
||||
//common->Printf( "idCinematic: video pts = %7.3f, audio pts = %7.3f, samples = %4d, num_bytes = %5d\n", static_cast<double>( frame->pts ) * av_q2d( dec_ctx->pkt_timebase ), static_cast<double>( frame3->pts ) * av_q2d( dec_ctx2->pkt_timebase ), frame3->nb_samples, num_bytes );
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue