mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2025-03-15 07:00:58 +00:00
Merge remote-tracking branch 'SRSaunders/master'
This commit is contained in:
commit
d212e5b948
16 changed files with 336 additions and 186 deletions
|
@ -1571,10 +1571,6 @@ void idCommonLocal::Shutdown()
|
|||
printf( "uiManager->Shutdown();\n" );
|
||||
uiManager->Shutdown();
|
||||
|
||||
// shut down the sound system
|
||||
printf( "soundSystem->Shutdown();\n" );
|
||||
soundSystem->Shutdown();
|
||||
|
||||
// shut down the user command input code
|
||||
printf( "usercmdGen->Shutdown();\n" );
|
||||
usercmdGen->Shutdown();
|
||||
|
@ -1584,9 +1580,16 @@ void idCommonLocal::Shutdown()
|
|||
eventLoop->Shutdown();
|
||||
|
||||
// shutdown the decl manager
|
||||
// SRS - Note this also shuts down all cinematic resources, including cinematic audio voices
|
||||
printf( "declManager->Shutdown();\n" );
|
||||
declManager->Shutdown();
|
||||
|
||||
// shut down the sound system
|
||||
// SRS - Shut down sound system after decl manager so cinematic audio voices are destroyed first
|
||||
// Important for XAudio2 where the mastering voice cannot be destroyed if any other voices exist
|
||||
printf( "soundSystem->Shutdown();\n" );
|
||||
soundSystem->Shutdown();
|
||||
|
||||
// shut down the renderSystem
|
||||
printf( "renderSystem->Shutdown();\n" );
|
||||
renderSystem->Shutdown();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -71,11 +71,7 @@ extern "C"
|
|||
#include <libswresample/swresample.h>
|
||||
#include <libavutil/imgutils.h>
|
||||
}
|
||||
// SRS - For handling cinematic audio packets
|
||||
#include <queue>
|
||||
#define NUM_PACKETS 4
|
||||
#define NUM_LAG_FRAMES 15 // SRS - Lag cinematic audio by 15 frames (~1/2 sec at 30 fps) to sync with FFMPEG video
|
||||
bool hasplanar = true;
|
||||
#define NUM_LAG_FRAMES 15 // SRS - Lag audio by 15 frames (~1/2 sec at 30 fps) for ffmpeg bik decoder AV sync
|
||||
#endif
|
||||
|
||||
#ifdef USE_BINKDEC
|
||||
|
@ -118,8 +114,10 @@ private:
|
|||
AVFrame* frame3; //GK: make extra frame for audio
|
||||
#if LIBAVCODEC_VERSION_MAJOR > 58
|
||||
const AVCodec* dec;
|
||||
const AVCodec* dec2; // SRS - Separate decoder for audio
|
||||
#else
|
||||
AVCodec* dec;
|
||||
AVCodec* dec2; // SRS - Separate decoder for audio
|
||||
#endif
|
||||
AVCodecContext* dec_ctx;
|
||||
AVCodecContext* dec_ctx2;
|
||||
|
@ -127,14 +125,15 @@ private:
|
|||
bool hasFrame;
|
||||
long framePos;
|
||||
AVSampleFormat dst_smp;
|
||||
bool hasplanar;
|
||||
SwrContext* swr_ctx;
|
||||
cinData_t ImageForTimeFFMPEG( int milliseconds );
|
||||
bool InitFromFFMPEGFile( const char* qpath, bool looping );
|
||||
void FFMPEGReset();
|
||||
std::queue<AVPacket> packets[NUM_PACKETS];
|
||||
uint8_t* lagBuffer[NUM_LAG_FRAMES] = {};
|
||||
int lagBufSize[NUM_LAG_FRAMES] = {};
|
||||
int lagIndex;
|
||||
bool skipLag;
|
||||
#endif
|
||||
#ifdef USE_BINKDEC
|
||||
BinkHandle binkHandle;
|
||||
|
@ -436,7 +435,6 @@ idCinematicLocal::idCinematicLocal()
|
|||
isRoQ = false; // SRS - Initialize isRoQ for all cases, not just FFMPEG
|
||||
#if defined(USE_FFMPEG)
|
||||
// Carl: ffmpeg stuff, for bink and normal video files:
|
||||
// fmt_ctx = avformat_alloc_context();
|
||||
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55,28,1)
|
||||
frame = av_frame_alloc();
|
||||
frame2 = av_frame_alloc();
|
||||
|
@ -451,10 +449,13 @@ idCinematicLocal::idCinematicLocal()
|
|||
fmt_ctx = NULL;
|
||||
video_stream_index = -1;
|
||||
audio_stream_index = -1;
|
||||
hasplanar = false;
|
||||
swr_ctx = NULL;
|
||||
img_convert_ctx = NULL;
|
||||
hasFrame = false;
|
||||
framePos = -1;
|
||||
lagIndex = 0;
|
||||
skipLag = false;
|
||||
#endif
|
||||
|
||||
#ifdef USE_BINKDEC
|
||||
|
@ -548,30 +549,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;
|
||||
|
@ -677,8 +657,20 @@ bool idCinematicLocal::InitFromFFMPEGFile( const char* qpath, bool amilooping )
|
|||
|
||||
if( ( ret = avformat_open_input( &fmt_ctx, fullpath, NULL, NULL ) ) < 0 )
|
||||
{
|
||||
common->Warning( "idCinematic: Cannot open FFMPEG video file: '%s', %d\n", qpath, looping );
|
||||
return false;
|
||||
// SRS - another case sensitivity hack for Linux, this time for ffmpeg and RoQ files
|
||||
idStr ext;
|
||||
fullpath.ExtractFileExtension( ext );
|
||||
if( idStr::Cmp( ext.c_str(), "roq" ) == 0 )
|
||||
{
|
||||
// SRS - If ffmpeg can't open .roq file, then try again with .RoQ extension instead
|
||||
fullpath.Replace( ".roq", ".RoQ" );
|
||||
ret = avformat_open_input( &fmt_ctx, fullpath, NULL, NULL );
|
||||
}
|
||||
if( ret < 0 )
|
||||
{
|
||||
common->Warning( "idCinematic: Cannot open FFMPEG video file: '%s', %d\n", qpath, looping );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if( ( ret = avformat_find_stream_info( fmt_ctx, NULL ) ) < 0 )
|
||||
{
|
||||
|
@ -712,12 +704,12 @@ bool idCinematicLocal::InitFromFFMPEGFile( const char* qpath, bool amilooping )
|
|||
return false;
|
||||
}
|
||||
//GK:Begin
|
||||
//After the video decoder is open then try to open audio decoder since it will re-bind the main decoder from video to audio
|
||||
ret2 = av_find_best_stream( fmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, &dec, 0 );
|
||||
//After the video decoder is open then try to open audio decoder
|
||||
ret2 = av_find_best_stream( fmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, &dec2, 0 );
|
||||
if( ret2 >= 0 ) //Make audio optional (only intro video has audio no other)
|
||||
{
|
||||
audio_stream_index = ret2;
|
||||
dec_ctx2 = avcodec_alloc_context3( dec );
|
||||
dec_ctx2 = avcodec_alloc_context3( dec2 );
|
||||
if( ( ret2 = avcodec_parameters_to_context( dec_ctx2, fmt_ctx->streams[audio_stream_index]->codecpar ) ) < 0 )
|
||||
{
|
||||
char* error = new char[256];
|
||||
|
@ -727,7 +719,7 @@ bool idCinematicLocal::InitFromFFMPEGFile( const char* qpath, bool amilooping )
|
|||
dec_ctx2->time_base = fmt_ctx->streams[audio_stream_index]->time_base;
|
||||
dec_ctx2->framerate = fmt_ctx->streams[audio_stream_index]->avg_frame_rate;
|
||||
dec_ctx2->pkt_timebase = fmt_ctx->streams[audio_stream_index]->time_base;
|
||||
if( ( ret2 = avcodec_open2( dec_ctx2, dec, NULL ) ) < 0 )
|
||||
if( ( ret2 = avcodec_open2( dec_ctx2, dec2, NULL ) ) < 0 )
|
||||
{
|
||||
common->Warning( "idCinematic: Cannot open audio decoder for: '%s', %d\n", qpath, looping );
|
||||
//return false;
|
||||
|
@ -777,28 +769,32 @@ bool idCinematicLocal::InitFromFFMPEGFile( const char* qpath, bool amilooping )
|
|||
//GK: No duration is given. Check if we get at least bitrate to calculate the length, otherwise set it to a fixed 100 seconds (should it be lower ?)
|
||||
if( durationSec < 0 )
|
||||
{
|
||||
if( dec_ctx->bit_rate > 0 )
|
||||
// SRS - First check the file context bit rate and estimate duration using file size and overall bit rate
|
||||
if( fmt_ctx->bit_rate > 0 )
|
||||
{
|
||||
durationSec = file_size / dec_ctx->bit_rate;
|
||||
durationSec = file_size * 8.0 / fmt_ctx->bit_rate;
|
||||
}
|
||||
// SRS - Likely an RoQ file, so use the video bit rate tolerance plus audio bit rate to estimate duration, then add 10% to correct for variable bit rate
|
||||
else if( dec_ctx->bit_rate_tolerance > 0 )
|
||||
{
|
||||
durationSec = file_size * 8.0 / ( dec_ctx->bit_rate_tolerance + ( dec_ctx2 ? dec_ctx2->bit_rate : 0 ) ) * 1.1;
|
||||
}
|
||||
// SRS - Otherwise just set a large max duration
|
||||
else
|
||||
{
|
||||
durationSec = 100;
|
||||
durationSec = 100.0;
|
||||
}
|
||||
}
|
||||
animationLength = durationSec * 1000;
|
||||
frameRate = av_q2d( fmt_ctx->streams[video_stream_index]->avg_frame_rate );
|
||||
common->Printf( "Loaded FFMPEG file: '%s', looping=%d, %dx%d, %f FPS, %f sec\n", qpath, looping, CIN_WIDTH, CIN_HEIGHT, frameRate, durationSec );
|
||||
common->Printf( "Loaded FFMPEG file: '%s', looping=%d, %dx%d, %3.2f FPS, %4.1f sec\n", qpath, looping, CIN_WIDTH, CIN_HEIGHT, frameRate, durationSec );
|
||||
|
||||
image = ( byte* )Mem_Alloc( CIN_WIDTH * CIN_HEIGHT * 4 * 2, TAG_CINEMATIC );
|
||||
// SRS - Get number of image bytes needed by querying with NULL first, then allocate image and fill with correct parameters
|
||||
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;
|
||||
status = FMV_PLAY;
|
||||
hasFrame = false;
|
||||
framePos = -1;
|
||||
|
@ -821,12 +817,38 @@ void idCinematicLocal::FFMPEGReset()
|
|||
//startTime = 0;
|
||||
|
||||
framePos = -1;
|
||||
|
||||
// SRS - If we have an ffmpeg audio context and are not looping, or skipLag is true, reset audio to release any stale buffers
|
||||
if( dec_ctx2 && ( !( looping && status == FMV_EOF ) || skipLag ) )
|
||||
{
|
||||
cinematicAudio->ResetAudio();
|
||||
|
||||
if( av_seek_frame( fmt_ctx, video_stream_index, 0, 0 ) >= 0 )
|
||||
for( int i = 0; i < NUM_LAG_FRAMES; i++ )
|
||||
{
|
||||
lagBufSize[ i ] = 0;
|
||||
if( lagBuffer[ i ] )
|
||||
{
|
||||
av_freep( &lagBuffer[ i ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SRS - For non-RoQ (i.e. bik) files, use standard frame seek to rewind the stream
|
||||
if( dec_ctx->codec_id != AV_CODEC_ID_ROQ && av_seek_frame( fmt_ctx, video_stream_index, 0, 0 ) >= 0 )
|
||||
{
|
||||
status = FMV_LOOPED;
|
||||
}
|
||||
else if( av_seek_frame( fmt_ctx, audio_stream_index, 0, 0 ) < 0 && av_seek_frame( fmt_ctx, video_stream_index, 0, 0 ) < 0 )
|
||||
// SRS - Special handling for RoQ files: only byte seek works and ffmpeg RoQ decoder needs reset
|
||||
else if( dec_ctx->codec_id == AV_CODEC_ID_ROQ && av_seek_frame( fmt_ctx, video_stream_index, 0, AVSEEK_FLAG_BYTE ) >= 0 )
|
||||
{
|
||||
// Close and reopen the ffmpeg RoQ codec without clearing the context - this seems to reset the decoder properly
|
||||
avcodec_close( dec_ctx );
|
||||
avcodec_open2( dec_ctx, dec, NULL );
|
||||
|
||||
status = FMV_LOOPED;
|
||||
}
|
||||
// SRS - Can't rewind the stream so we really are at EOF
|
||||
else
|
||||
{
|
||||
status = FMV_EOF;
|
||||
}
|
||||
|
@ -888,7 +910,7 @@ bool idCinematicLocal::InitFromBinkDecFile( const char* qpath, bool amilooping )
|
|||
{
|
||||
trackIndex = 0; // SRS - Use the first audio track - is this reasonable?
|
||||
binkInfo = Bink_GetAudioTrackDetails( binkHandle, trackIndex );
|
||||
common->Printf( "Cinematic audio stream found: Sample Rate=%d Hz, Channels=%d\n", binkInfo.sampleRate, binkInfo.nChannels );
|
||||
common->Printf( "Cinematic audio stream found: Sample Rate=%d Hz, Channels=%d, Format=16-bit\n", binkInfo.sampleRate, binkInfo.nChannels );
|
||||
cinematicAudio->InitAudio( &binkInfo );
|
||||
}
|
||||
|
||||
|
@ -896,11 +918,10 @@ 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, %f FPS, %f sec\n", qpath, looping, CIN_WIDTH, CIN_HEIGHT, frameRate, durationSec );
|
||||
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 );
|
||||
|
||||
memset( yuvBuffer, 0, sizeof( yuvBuffer ) );
|
||||
|
||||
buf = NULL;
|
||||
status = FMV_PLAY;
|
||||
hasFrame = false; // SRS - Implemented hasFrame for BinkDec behaviour consistency with FFMPEG
|
||||
framePos = -1;
|
||||
|
@ -913,6 +934,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;
|
||||
}
|
||||
|
@ -927,7 +955,8 @@ bool idCinematicLocal::InitFromFile( const char* qpath, bool amilooping )
|
|||
{
|
||||
unsigned short RoQID;
|
||||
|
||||
Close();
|
||||
// SRS - Don't need to call Close() here, all initialization is handled by constructor
|
||||
//Close();
|
||||
|
||||
inMemory = 0;
|
||||
animationLength = 100000;
|
||||
|
@ -942,33 +971,42 @@ bool idCinematicLocal::InitFromFile( const char* qpath, bool amilooping )
|
|||
sprintf( fileName, "%s", qpath );
|
||||
}
|
||||
// Carl: Look for original Doom 3 RoQ files first:
|
||||
idStr ext;
|
||||
fileName.ExtractFileExtension( ext );
|
||||
fileName = fileName.StripFileExtension();
|
||||
fileName = fileName + ".roq";
|
||||
//if (fileName == "video\\loadvideo.roq") {
|
||||
// fileName = "video\\idlogo.roq";
|
||||
idStr temp = fileName.StripFileExtension() + ".roq";
|
||||
|
||||
// SRS - Cool legacy support, but leaving this disabled since it might break existing mods
|
||||
//if( temp == "video\\loadvideo.roq" )
|
||||
//{
|
||||
// temp = "video\\idlogo.roq";
|
||||
//}
|
||||
|
||||
iFile = fileSystem->OpenFileRead( fileName );
|
||||
iFile = fileSystem->OpenFileRead( temp );
|
||||
|
||||
// Carl: If the RoQ file doesn't exist, try using ffmpeg instead:
|
||||
// Carl: If the RoQ file doesn't exist, try using bik file extension instead:
|
||||
if( !iFile )
|
||||
{
|
||||
//idLib::Warning( "Original Doom 3 RoQ Cinematic not found: '%s'\n", temp.c_str() );
|
||||
#if defined(USE_FFMPEG)
|
||||
//idLib::Warning( "Original Doom 3 RoQ Cinematic not found: '%s'\n", fileName.c_str() );
|
||||
idStr temp = fileName.StripFileExtension() + ".bik";
|
||||
temp = fileName.StripFileExtension() + ".bik";
|
||||
skipLag = false; // SRS - Enable lag buffer for ffmpeg bik decoder AV sync
|
||||
|
||||
// SRS - Support RoQ cinematic playback via ffmpeg decoder - better quality plus audio support
|
||||
}
|
||||
else
|
||||
{
|
||||
fileSystem->CloseFile( iFile ); // SRS - Close the RoQ file and let ffmpeg reopen it
|
||||
iFile = NULL;
|
||||
skipLag = true; // SRS - Disable lag buffer for ffmpeg RoQ decoder AV sync
|
||||
}
|
||||
{
|
||||
// SRS End
|
||||
|
||||
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";
|
||||
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 );
|
||||
|
@ -979,6 +1017,7 @@ bool idCinematicLocal::InitFromFile( const char* qpath, bool amilooping )
|
|||
}
|
||||
// Carl: The rest of this function is for original Doom 3 RoQ files:
|
||||
isRoQ = true;
|
||||
fileName = temp;
|
||||
ROQSize = iFile->Length();
|
||||
|
||||
looping = amilooping;
|
||||
|
@ -1004,6 +1043,7 @@ bool idCinematicLocal::InitFromFile( const char* qpath, bool amilooping )
|
|||
RoQ_init();
|
||||
status = FMV_PLAY;
|
||||
ImageForTime( 0 );
|
||||
common->Printf( "Loaded RoQ file: '%s', looping=%d, %dx%d, %3.2f FPS\n", fileName.c_str(), looping, CIN_WIDTH, CIN_HEIGHT, frameRate );
|
||||
status = ( looping ) ? FMV_PLAY : FMV_IDLE;
|
||||
return true;
|
||||
}
|
||||
|
@ -1027,23 +1067,43 @@ void idCinematicLocal::Close()
|
|||
status = FMV_EOF;
|
||||
}
|
||||
|
||||
RoQShutdown();
|
||||
|
||||
if( isRoQ )
|
||||
{
|
||||
RoQShutdown();
|
||||
}
|
||||
#if defined(USE_FFMPEG)
|
||||
hasFrame = false;
|
||||
|
||||
if( !isRoQ )
|
||||
else //if( !isRoQ )
|
||||
{
|
||||
if( img_convert_ctx )
|
||||
{
|
||||
sws_freeContext( img_convert_ctx );
|
||||
img_convert_ctx = NULL;
|
||||
}
|
||||
|
||||
img_convert_ctx = NULL;
|
||||
// SRS - Free audio codec context, resample context, and any lagged audio buffers
|
||||
if( dec_ctx2 )
|
||||
{
|
||||
avcodec_free_context( &dec_ctx2 );
|
||||
|
||||
// SRS - Free resample context if we were decoding planar audio
|
||||
if( swr_ctx )
|
||||
{
|
||||
swr_free( &swr_ctx );
|
||||
}
|
||||
|
||||
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 );
|
||||
avcodec_free_context( &dec_ctx );
|
||||
}
|
||||
|
||||
if( fmt_ctx )
|
||||
|
@ -1052,11 +1112,8 @@ void idCinematicLocal::Close()
|
|||
}
|
||||
status = FMV_EOF;
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_BINKDEC
|
||||
hasFrame = false;
|
||||
|
||||
if( !isRoQ )
|
||||
#elif defined(USE_BINKDEC)
|
||||
else //if( !isRoQ )
|
||||
{
|
||||
if( binkHandle.isValid )
|
||||
{
|
||||
|
@ -1121,8 +1178,7 @@ cinData_t idCinematicLocal::ImageForTime( int thisTime )
|
|||
{
|
||||
return ImageForTimeFFMPEG( thisTime );
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_BINKDEC // DG: libbinkdec support
|
||||
#elif defined(USE_BINKDEC) // DG: libbinkdec support
|
||||
if( !isRoQ )
|
||||
{
|
||||
return ImageForTimeBinkDec( thisTime );
|
||||
|
@ -1132,15 +1188,16 @@ cinData_t idCinematicLocal::ImageForTime( int thisTime )
|
|||
// Carl: Handle original Doom 3 RoQ video files
|
||||
cinData_t cinData;
|
||||
|
||||
if( thisTime == 0 )
|
||||
// SRS - Changed from == 0 to <= 0 to match behaviour of FFMPEG and BinkDec decoders
|
||||
if( thisTime <= 0 )
|
||||
{
|
||||
thisTime = Sys_Milliseconds();
|
||||
}
|
||||
|
||||
if( thisTime < 0 )
|
||||
{
|
||||
thisTime = 0;
|
||||
}
|
||||
//if( thisTime < 0 )
|
||||
//{
|
||||
// thisTime = 0;
|
||||
//}
|
||||
|
||||
memset( &cinData, 0, sizeof( cinData ) );
|
||||
|
||||
|
@ -1177,7 +1234,8 @@ cinData_t idCinematicLocal::ImageForTime( int thisTime )
|
|||
tfps = 0;
|
||||
}
|
||||
|
||||
if( tfps < numQuads )
|
||||
// SRS - Need to use numQuads - 1 for frame position (otherwise get into reset loop at start)
|
||||
if( tfps < numQuads - 1 )
|
||||
{
|
||||
RoQReset();
|
||||
buf = NULL;
|
||||
|
@ -1186,6 +1244,7 @@ cinData_t idCinematicLocal::ImageForTime( int thisTime )
|
|||
|
||||
if( buf == NULL )
|
||||
{
|
||||
// SRS - This frame init loop is not really necessary, but leaving in to avoid breakage
|
||||
while( buf == NULL )
|
||||
{
|
||||
RoQInterrupt();
|
||||
|
@ -1193,32 +1252,31 @@ cinData_t idCinematicLocal::ImageForTime( int thisTime )
|
|||
}
|
||||
else
|
||||
{
|
||||
while( ( tfps != numQuads && status == FMV_PLAY ) )
|
||||
// SRS - This frame loop is really all we need and could handle the above case as well
|
||||
while( ( numQuads - 1 < tfps && status == FMV_PLAY ) )
|
||||
{
|
||||
RoQInterrupt();
|
||||
}
|
||||
}
|
||||
|
||||
if( status == FMV_LOOPED )
|
||||
{
|
||||
status = FMV_PLAY;
|
||||
while( buf == NULL && status == FMV_PLAY )
|
||||
{
|
||||
RoQInterrupt();
|
||||
}
|
||||
startTime = thisTime;
|
||||
}
|
||||
// SRS - This is redundant code, virtually identical logic correctly handles looping below
|
||||
//if( status == FMV_LOOPED )
|
||||
//{
|
||||
// status = FMV_PLAY;
|
||||
// while( buf == NULL && status == FMV_PLAY )
|
||||
// {
|
||||
// RoQInterrupt();
|
||||
// }
|
||||
// startTime = thisTime;
|
||||
//}
|
||||
|
||||
if( status == FMV_EOF )
|
||||
if( status == FMV_LOOPED || status == FMV_EOF )
|
||||
{
|
||||
if( looping )
|
||||
{
|
||||
RoQReset();
|
||||
//RoQReset(); // SRS - RoQReset() already called by RoQInterrupt() when looping
|
||||
buf = NULL;
|
||||
if( status == FMV_LOOPED )
|
||||
{
|
||||
status = FMV_PLAY;
|
||||
}
|
||||
status = FMV_PLAY;
|
||||
while( buf == NULL && status == FMV_PLAY )
|
||||
{
|
||||
RoQInterrupt();
|
||||
|
@ -1227,8 +1285,10 @@ cinData_t idCinematicLocal::ImageForTime( int thisTime )
|
|||
}
|
||||
else
|
||||
{
|
||||
buf = NULL;
|
||||
status = FMV_IDLE;
|
||||
RoQShutdown();
|
||||
//RoQShutdown(); //SRS - RoQShutdown() not needed on EOF, return null data instead
|
||||
return cinData;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1288,6 +1348,8 @@ cinData_t idCinematicLocal::ImageForTimeFFMPEG( int thisTime )
|
|||
if( desiredFrame < framePos )
|
||||
{
|
||||
FFMPEGReset();
|
||||
hasFrame = false;
|
||||
status = FMV_PLAY;
|
||||
}
|
||||
|
||||
if( hasFrame && desiredFrame == framePos )
|
||||
|
@ -1320,7 +1382,7 @@ cinData_t idCinematicLocal::ImageForTimeFFMPEG( int thisTime )
|
|||
{
|
||||
desiredFrame = 0;
|
||||
FFMPEGReset();
|
||||
framePos = -1;
|
||||
hasFrame = false;
|
||||
startTime = thisTime;
|
||||
if( av_read_frame( fmt_ctx, &packet ) < 0 )
|
||||
{
|
||||
|
@ -1331,6 +1393,7 @@ cinData_t idCinematicLocal::ImageForTimeFFMPEG( int thisTime )
|
|||
}
|
||||
else
|
||||
{
|
||||
hasFrame = false;
|
||||
status = FMV_IDLE;
|
||||
return cinData;
|
||||
}
|
||||
|
@ -1358,8 +1421,7 @@ cinData_t idCinematicLocal::ImageForTimeFFMPEG( int thisTime )
|
|||
//GK:Begin
|
||||
else if( packet.stream_index == audio_stream_index ) //Check if it found any audio data
|
||||
{
|
||||
packets->push( packet );
|
||||
res = avcodec_send_packet( dec_ctx2, &packets->front() );
|
||||
res = avcodec_send_packet( dec_ctx2, &packet );
|
||||
if( res != 0 && res != AVERROR( EAGAIN ) )
|
||||
{
|
||||
char* error = new char[256];
|
||||
|
@ -1368,8 +1430,6 @@ cinData_t idCinematicLocal::ImageForTimeFFMPEG( int thisTime )
|
|||
}
|
||||
else
|
||||
{
|
||||
packet = packets->front();
|
||||
packets->pop();
|
||||
if( ( frameFinished1 = avcodec_receive_frame( dec_ctx2, frame3 ) ) != 0 )
|
||||
{
|
||||
char* error = new char[256];
|
||||
|
@ -1436,7 +1496,7 @@ cinData_t idCinematicLocal::ImageForTimeFFMPEG( int thisTime )
|
|||
lagBuffer[ lagIndex ] = audioBuffer;
|
||||
lagBufSize[ lagIndex ] = num_bytes;
|
||||
|
||||
lagIndex = ( lagIndex + 1 ) % NUM_LAG_FRAMES;
|
||||
lagIndex = ( lagIndex + 1 ) % ( skipLag ? 1 : NUM_LAG_FRAMES );
|
||||
}
|
||||
|
||||
return cinData;
|
||||
|
@ -1484,28 +1544,12 @@ cinData_t idCinematicLocal::ImageForTimeBinkDec( int thisTime )
|
|||
desiredFrame = 0;
|
||||
}
|
||||
|
||||
if( desiredFrame >= numFrames )
|
||||
{
|
||||
status = FMV_EOF;
|
||||
if( looping )
|
||||
{
|
||||
desiredFrame = 0;
|
||||
BinkDecReset();
|
||||
framePos = -1;
|
||||
startTime = thisTime;
|
||||
status = FMV_PLAY;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = FMV_IDLE;
|
||||
return cinData;
|
||||
}
|
||||
}
|
||||
|
||||
// SRS - Enable video replay within PDAs
|
||||
if( desiredFrame < framePos )
|
||||
{
|
||||
BinkDecReset();
|
||||
hasFrame = false;
|
||||
status = FMV_PLAY;
|
||||
}
|
||||
// SRS end
|
||||
|
||||
|
@ -1521,6 +1565,25 @@ cinData_t idCinematicLocal::ImageForTimeBinkDec( int thisTime )
|
|||
return cinData;
|
||||
}
|
||||
|
||||
if( desiredFrame >= numFrames )
|
||||
{
|
||||
status = FMV_EOF;
|
||||
if( looping )
|
||||
{
|
||||
desiredFrame = 0;
|
||||
BinkDecReset();
|
||||
hasFrame = false;
|
||||
startTime = thisTime;
|
||||
status = FMV_PLAY;
|
||||
}
|
||||
else
|
||||
{
|
||||
hasFrame = false;
|
||||
status = FMV_IDLE;
|
||||
return cinData;
|
||||
}
|
||||
}
|
||||
|
||||
// Bink_GotoFrame(binkHandle, desiredFrame);
|
||||
// apparently Bink_GotoFrame() doesn't work super well, so skip frames
|
||||
// (if necessary) by calling Bink_GetNextFrame()
|
||||
|
@ -1586,7 +1649,7 @@ cinData_t idCinematicLocal::ImageForTimeBinkDec( int thisTime )
|
|||
|
||||
if( audioTracks > 0 )
|
||||
{
|
||||
audioBuffer = ( int16_t* )malloc( binkInfo.idealBufferSize );
|
||||
audioBuffer = ( int16_t* )Mem_Alloc( binkInfo.idealBufferSize, TAG_AUDIO );
|
||||
num_bytes = Bink_GetAudioData( binkHandle, trackIndex, audioBuffer );
|
||||
|
||||
// SRS - If we have cinematic audio data, start playing it now
|
||||
|
@ -1598,7 +1661,7 @@ cinData_t idCinematicLocal::ImageForTimeBinkDec( int thisTime )
|
|||
else
|
||||
{
|
||||
// SRS - Even though we have no audio data to play, still need to free the audio buffer
|
||||
free( audioBuffer );
|
||||
Mem_Free( audioBuffer );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3077,7 +3140,7 @@ redump:
|
|||
//
|
||||
// read in next frame data
|
||||
//
|
||||
if( RoQPlayed >= ROQSize )
|
||||
if( RoQPlayed >= ROQSize || status == FMV_EOF ) // SRS - handle FMV_EOF case
|
||||
{
|
||||
if( looping )
|
||||
{
|
||||
|
@ -3153,11 +3216,14 @@ idCinematicLocal::RoQShutdown
|
|||
*/
|
||||
void idCinematicLocal::RoQShutdown()
|
||||
{
|
||||
// SRS - Depending on status, this could prevent closing of iFile on shutdown, disable it
|
||||
/*
|
||||
if( status == FMV_IDLE )
|
||||
{
|
||||
return;
|
||||
}
|
||||
status = FMV_IDLE;
|
||||
*/
|
||||
status = FMV_EOF; // SRS - Changed from FMV_IDLE to FMV_EOF for shutdown consistency
|
||||
|
||||
if( iFile )
|
||||
{
|
||||
|
|
|
@ -3256,13 +3256,20 @@ void idRenderBackend::DBG_TestImage()
|
|||
{
|
||||
cinData_t cin;
|
||||
|
||||
cin = tr.testVideo->ImageForTime( viewDef->renderView.time[1] - tr.testVideoStartTime );
|
||||
// SRS - Don't need calibrated time for testing cinematics, so just call ImageForTime( 0 ) for current system time
|
||||
// This simplification allows cinematic test playback to work over both 2D and 3D background scenes
|
||||
cin = tr.testVideo->ImageForTime( 0 /*viewDef->renderView.time[1] - tr.testVideoStartTime*/ );
|
||||
if( cin.imageY != NULL )
|
||||
{
|
||||
image = cin.imageY;
|
||||
imageCr = cin.imageCr;
|
||||
imageCb = cin.imageCb;
|
||||
}
|
||||
// SRS - Also handle ffmpeg and original RoQ decoders for test videos (using cin.image)
|
||||
else if( cin.image != NULL )
|
||||
{
|
||||
image = cin.image;
|
||||
}
|
||||
else
|
||||
{
|
||||
tr.testImage = NULL;
|
||||
|
@ -3302,9 +3309,9 @@ void idRenderBackend::DBG_TestImage()
|
|||
|
||||
float scale[16] = { 0 };
|
||||
scale[0] = w; // scale
|
||||
scale[5] = -h; // scale
|
||||
scale[5] = h; // scale (SRS - changed h from -ve to +ve so video plays right side up)
|
||||
scale[12] = halfScreenWidth - ( halfScreenWidth * w ); // translate
|
||||
scale[13] = halfScreenHeight - ( halfScreenHeight * h ); // translate
|
||||
scale[13] = halfScreenHeight - ( halfScreenHeight * h ) - h; // translate (SRS - moved up by h)
|
||||
scale[10] = 1.0f;
|
||||
scale[15] = 1.0f;
|
||||
|
||||
|
@ -3340,7 +3347,9 @@ void idRenderBackend::DBG_TestImage()
|
|||
imageCr->Bind();
|
||||
GL_SelectTexture( 2 );
|
||||
imageCb->Bind();
|
||||
renderProgManager.BindShader_Bink();
|
||||
// SRS - Use Bink shader without sRGB to linear conversion, otherwise cinematic colours may be wrong
|
||||
// BindShader_BinkGUI() does not seem to work here - perhaps due to vertex shader input dependencies?
|
||||
renderProgManager.BindShader_Bink_sRGB();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -602,8 +602,8 @@ void idRenderBackend::BindVariableStageImage( const textureStage_t* texture, con
|
|||
GL_SelectTexture( 0 );
|
||||
cin.image->Bind();
|
||||
|
||||
/*
|
||||
if( backEnd.viewDef->is2Dgui )
|
||||
// SRS - Reenable shaders so ffmpeg and RoQ decoder cinematics are rendered with correct colour
|
||||
if( viewDef->is2Dgui )
|
||||
{
|
||||
renderProgManager.BindShader_TextureVertexColor_sRGB();
|
||||
}
|
||||
|
@ -611,7 +611,6 @@ void idRenderBackend::BindVariableStageImage( const textureStage_t* texture, con
|
|||
{
|
||||
renderProgManager.BindShader_TextureVertexColor();
|
||||
}
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -213,6 +213,9 @@ void idRenderProgManager::Init()
|
|||
{ BUILTIN_STEREO_DEGHOST, "builtin/VR/stereoDeGhost", "", 0, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT },
|
||||
{ BUILTIN_STEREO_WARP, "builtin/VR/stereoWarp", "", 0, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT },
|
||||
{ BUILTIN_BINK, "builtin/video/bink", "", 0, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT },
|
||||
// SRS - Added Bink shader without sRGB to linear conversion for testVideo cmd
|
||||
{ BUILTIN_BINK_SRGB, "builtin/video/bink", "_sRGB", BIT( USE_SRGB ), false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT },
|
||||
// SRS end
|
||||
{ BUILTIN_BINK_GUI, "builtin/video/bink_gui", "", 0, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT },
|
||||
{ BUILTIN_STEREO_INTERLACE, "builtin/VR/stereoInterlace", "", 0, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT },
|
||||
{ BUILTIN_MOTION_BLUR, "builtin/post/motionBlur", "", 0, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT },
|
||||
|
|
|
@ -693,6 +693,12 @@ public:
|
|||
BindShader_Builtin( BUILTIN_BINK );
|
||||
}
|
||||
|
||||
// SRS - Added Bink shader without sRGB to linear conversion for testVideo cmd
|
||||
void BindShader_Bink_sRGB()
|
||||
{
|
||||
BindShader_Builtin( BUILTIN_BINK_SRGB );
|
||||
}
|
||||
|
||||
void BindShader_BinkGUI()
|
||||
{
|
||||
BindShader_Builtin( BUILTIN_BINK_GUI );
|
||||
|
@ -854,6 +860,7 @@ private:
|
|||
BUILTIN_STEREO_DEGHOST,
|
||||
BUILTIN_STEREO_WARP,
|
||||
BUILTIN_BINK,
|
||||
BUILTIN_BINK_SRGB, // SRS - Added Bink shader without sRGB to linear conversion for testVideo cmd
|
||||
BUILTIN_BINK_GUI,
|
||||
BUILTIN_STEREO_INTERLACE,
|
||||
BUILTIN_MOTION_BLUR,
|
||||
|
|
|
@ -617,7 +617,8 @@ void R_TestVideo_f( const idCmdArgs& args )
|
|||
|
||||
cinData_t cin;
|
||||
cin = tr.testVideo->ImageForTime( 0 );
|
||||
if( cin.imageY == NULL )
|
||||
// SRS - Also handle ffmpeg and original RoQ decoders for test videos (using cin.image)
|
||||
if( cin.imageY == NULL && cin.image == NULL )
|
||||
{
|
||||
delete tr.testVideo;
|
||||
tr.testVideo = NULL;
|
||||
|
@ -630,7 +631,8 @@ void R_TestVideo_f( const idCmdArgs& args )
|
|||
int len = tr.testVideo->AnimationLength();
|
||||
common->Printf( "%5.1f seconds of video\n", len * 0.001 );
|
||||
|
||||
tr.testVideoStartTime = tr.primaryRenderView.time[1];
|
||||
// SRS - Not needed or used since InitFromFile() sets the correct start time automatically
|
||||
//tr.testVideoStartTime = tr.primaryRenderView.time[1];
|
||||
|
||||
// try to play the matching wav file
|
||||
idStr wavString = args.Argv( ( args.Argc() == 2 ) ? 1 : 2 );
|
||||
|
|
|
@ -563,13 +563,20 @@ void idRenderBackend::DBG_TestImage()
|
|||
{
|
||||
cinData_t cin;
|
||||
|
||||
cin = tr.testVideo->ImageForTime( viewDef->renderView.time[1] - tr.testVideoStartTime );
|
||||
// SRS - Don't need calibrated time for testing cinematics, so just call ImageForTime( 0 ) for current system time
|
||||
// This simplification allows cinematic test playback to work over both 2D and 3D background scenes
|
||||
cin = tr.testVideo->ImageForTime( 0 /*viewDef->renderView.time[1] - tr.testVideoStartTime*/ );
|
||||
if( cin.imageY != NULL )
|
||||
{
|
||||
image = cin.imageY;
|
||||
imageCr = cin.imageCr;
|
||||
imageCb = cin.imageCb;
|
||||
}
|
||||
// SRS - Also handle ffmpeg and original RoQ decoders for test videos (using cin.image)
|
||||
else if( cin.image != NULL )
|
||||
{
|
||||
image = cin.image;
|
||||
}
|
||||
else
|
||||
{
|
||||
tr.testImage = NULL;
|
||||
|
@ -610,7 +617,7 @@ void idRenderBackend::DBG_TestImage()
|
|||
scale[0] = w; // scale
|
||||
scale[5] = h; // scale
|
||||
scale[12] = halfScreenWidth - ( halfScreenWidth * w ); // translate
|
||||
scale[13] = halfScreenHeight - ( halfScreenHeight * h ); // translate
|
||||
scale[13] = halfScreenHeight - ( halfScreenHeight * h ) - h; // translate (SRS - moved up by h)
|
||||
scale[10] = 1.0f;
|
||||
scale[15] = 1.0f;
|
||||
|
||||
|
@ -646,7 +653,9 @@ void idRenderBackend::DBG_TestImage()
|
|||
GL_SelectTexture( 2 );
|
||||
imageCb->Bind();
|
||||
|
||||
renderProgManager.BindShader_Bink();
|
||||
// SRS - Use Bink shader with no sRGB to linear conversion, otherwise cinematic colours may be wrong
|
||||
// BindShader_BinkGUI() does not seem to work here - perhaps due to vertex shader input dependencies?
|
||||
renderProgManager.BindShader_Bink_sRGB();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -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,28 +108,35 @@ 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)
|
||||
av_freep( &tempdata );
|
||||
#elif defined(USE_BINKDEC)
|
||||
free( tempdata );
|
||||
Mem_Free( tempdata );
|
||||
#endif
|
||||
alSourceQueueBuffers( alMusicSourceVoicecin, 1, &bufid );
|
||||
ALenum error = alGetError();
|
||||
|
@ -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
|
||||
|
@ -149,7 +160,7 @@ void CinematicAudio_OpenAL::PlayAudio( uint8_t* data, int size )
|
|||
#if defined(USE_FFMPEG)
|
||||
av_freep( &data );
|
||||
#elif defined(USE_BINKDEC)
|
||||
free( data );
|
||||
Mem_Free( data );
|
||||
#endif
|
||||
offset++;
|
||||
if( offset == NUM_BUFFERS )
|
||||
|
@ -186,18 +197,44 @@ void CinematicAudio_OpenAL::PlayAudio( uint8_t* data, int size )
|
|||
}
|
||||
}
|
||||
|
||||
void CinematicAudio_OpenAL::ResetAudio()
|
||||
{
|
||||
if( alIsSource( alMusicSourceVoicecin ) )
|
||||
{
|
||||
alSourceRewind( alMusicSourceVoicecin );
|
||||
alSourcei( alMusicSourceVoicecin, AL_BUFFER, 0 );
|
||||
}
|
||||
|
||||
while( !tBuffer.empty() )
|
||||
{
|
||||
uint8_t* tempdata = tBuffer.front();
|
||||
tBuffer.pop();
|
||||
sizes.pop();
|
||||
if( tempdata )
|
||||
{
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
while( !bufids.empty() )
|
||||
{
|
||||
bufids.pop();
|
||||
}
|
||||
|
||||
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,29 +247,25 @@ void CinematicAudio_OpenAL::ShutdownAudio()
|
|||
{
|
||||
alDeleteBuffers( NUM_BUFFERS, alMusicBuffercin );
|
||||
}
|
||||
if( !tBuffer->empty() )
|
||||
|
||||
while( !tBuffer.empty() )
|
||||
{
|
||||
int buffersize = tBuffer->size();
|
||||
while( buffersize > 0 )
|
||||
uint8_t* tempdata = tBuffer.front();
|
||||
tBuffer.pop();
|
||||
sizes.pop();
|
||||
if( tempdata )
|
||||
{
|
||||
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)
|
||||
free( tempdata );
|
||||
Mem_Free( tempdata );
|
||||
#endif
|
||||
buffersize--;
|
||||
}
|
||||
}
|
||||
if( !sizes->empty() )
|
||||
|
||||
while( !bufids.empty() )
|
||||
{
|
||||
int buffersize = sizes->size();
|
||||
while( buffersize > 0 )
|
||||
{
|
||||
sizes->pop();
|
||||
buffersize--;
|
||||
}
|
||||
bufids.pop();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -206,11 +206,14 @@ void idSoundVoice_OpenAL::DestroyInternal()
|
|||
idLib::Printf( "%dms: %i destroyed\n", Sys_Milliseconds(), openalSource );
|
||||
}
|
||||
|
||||
// SRS - Make sure the source is stopped before detaching buffers
|
||||
alSourceStop( openalSource );
|
||||
alSourcei( openalSource, AL_BUFFER, 0 );
|
||||
|
||||
// SRS - Delete source only after detaching buffers above
|
||||
alDeleteSources( 1, &openalSource );
|
||||
openalSource = 0;
|
||||
|
||||
alSourcei( openalSource, AL_BUFFER, 0 );
|
||||
|
||||
if( openalStreamingBuffer[0] && openalStreamingBuffer[1] && openalStreamingBuffer[2] )
|
||||
{
|
||||
CheckALErrors();
|
||||
|
|
|
@ -52,7 +52,7 @@ public:
|
|||
#if defined(USE_FFMPEG)
|
||||
av_freep( &data );
|
||||
#elif defined(USE_BINKDEC)
|
||||
free( data );
|
||||
Mem_Free( data );
|
||||
#endif
|
||||
}
|
||||
//Unused methods are stubs
|
||||
|
@ -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 };
|
||||
|
|
|
@ -532,6 +532,7 @@ cinData_t idSoundSystemLocal::ImageForTime( const int milliseconds, const bool w
|
|||
cd.imageY = NULL;
|
||||
cd.imageCr = NULL;
|
||||
cd.imageCb = NULL;
|
||||
cd.image = NULL;
|
||||
cd.imageWidth = 0;
|
||||
cd.imageHeight = 0;
|
||||
cd.status = FMV_IDLE;
|
||||
|
|
Loading…
Reference in a new issue