mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2025-03-14 06:34:10 +00:00
ffmpeg 5 compatibility plus cinematic audio playback on OpenAL & XAudio2
(cherry picked from commit bcb683e8e6ba6cb23acac2f1121c6e3eece1ed01)
This commit is contained in:
parent
813767feea
commit
3be85d9c4b
9 changed files with 770 additions and 35 deletions
|
@ -680,7 +680,8 @@ set(SOUND_INCLUDES
|
|||
sound/snd_local.h
|
||||
sound/sound.h
|
||||
sound/SoundVoice.h
|
||||
sound/WaveFile.h)
|
||||
sound/WaveFile.h
|
||||
sound/CinematicAudio.h)
|
||||
|
||||
set(SOUND_SOURCES
|
||||
sound/snd_emitter.cpp
|
||||
|
@ -688,28 +689,31 @@ set(SOUND_SOURCES
|
|||
sound/snd_system.cpp
|
||||
sound/snd_world.cpp
|
||||
sound/SoundVoice.cpp
|
||||
sound/WaveFile.cpp
|
||||
)
|
||||
sound/WaveFile.cpp)
|
||||
|
||||
set(XAUDIO2_INCLUDES
|
||||
sound/XAudio2/XA2_SoundHardware.h
|
||||
sound/XAudio2/XA2_SoundSample.h
|
||||
sound/XAudio2/XA2_SoundVoice.h)
|
||||
sound/XAudio2/XA2_SoundVoice.h
|
||||
sound/Xaudio2/XA2_CinematicAudio.h)
|
||||
|
||||
set(XAUDIO2_SOURCES
|
||||
sound/XAudio2/XA2_SoundHardware.cpp
|
||||
sound/XAudio2/XA2_SoundSample.cpp
|
||||
sound/XAudio2/XA2_SoundVoice.cpp)
|
||||
sound/XAudio2/XA2_SoundVoice.cpp
|
||||
sound/Xaudio2/XA2_CinematicAudio.cpp)
|
||||
|
||||
set(OPENAL_INCLUDES
|
||||
sound/OpenAL/AL_SoundHardware.h
|
||||
sound/OpenAL/AL_SoundSample.h
|
||||
sound/OpenAL/AL_SoundVoice.h)
|
||||
sound/OpenAL/AL_SoundVoice.h
|
||||
sound/OpenAL/AL_CinematicAudio.h)
|
||||
|
||||
set(OPENAL_SOURCES
|
||||
sound/OpenAL/AL_SoundHardware.cpp
|
||||
sound/OpenAL/AL_SoundSample.cpp
|
||||
sound/OpenAL/AL_SoundVoice.cpp)
|
||||
sound/OpenAL/AL_SoundVoice.cpp
|
||||
sound/OpenAL/AL_CinematicAudio.cpp)
|
||||
|
||||
set(STUBAUDIO_INCLUDES
|
||||
sound/stub/SoundStub.h)
|
||||
|
@ -1533,16 +1537,18 @@ if(MSVC)
|
|||
include_directories(libs/ffmpeg-win64/include)
|
||||
include_directories(libs/ffmpeg-win64/include/libswscale)
|
||||
include_directories(libs/ffmpeg-win64/include/libavformat)
|
||||
include_directories(libs/ffmpeg-win64/include/libavdevice)
|
||||
include_directories(libs/ffmpeg-win64/include/libavutil)
|
||||
include_directories(libs/ffmpeg-win64/include/libavcodec)
|
||||
include_directories(libs/ffmpeg-win64/include/libswresample)
|
||||
|
||||
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/libs/ffmpeg-win64/lib)
|
||||
else()
|
||||
include_directories(libs/ffmpeg-win32/include)
|
||||
include_directories(libs/ffmpeg-win32/include/libswscale)
|
||||
include_directories(libs/ffmpeg-win32/include/libavformat)
|
||||
include_directories(libs/ffmpeg-win32/include/libavdevice)
|
||||
include_directories(libs/ffmpeg-win32/include/libavutil)
|
||||
include_directories(libs/ffmpeg-win32/include/libavcodec)
|
||||
include_directories(libs/ffmpeg-win32/include/libswresample)
|
||||
|
||||
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/libs/ffmpeg-win32/lib)
|
||||
endif()
|
||||
|
@ -1551,7 +1557,8 @@ if(MSVC)
|
|||
avcodec
|
||||
avformat
|
||||
avutil
|
||||
swscale)
|
||||
swscale
|
||||
swresample)
|
||||
|
||||
endif()
|
||||
|
||||
|
@ -1717,8 +1724,8 @@ else()
|
|||
|
||||
# SRS - Added support for OpenAL Soft headers on OSX (vs default macOS SDK headers)
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin" AND NOT OPENAL_INCLUDE_DIR MATCHES "SDKs/MacOSX.*\.sdk")
|
||||
include_directories(${OPENAL_INCLUDE_DIR})
|
||||
add_definitions(-DUSE_OPENAL_SOFT_INCLUDES)
|
||||
include_directories(${OPENAL_INCLUDE_DIR})
|
||||
add_definitions(-DUSE_OPENAL_SOFT_INCLUDES)
|
||||
endif()
|
||||
|
||||
list(APPEND RBDOOM3_INCLUDES ${OPENAL_INCLUDES})
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
# FFMPEG_LIBAVCODEC
|
||||
# FFMPEG_LIBAVFORMAT
|
||||
# FFMPEG_LIBAVUTIL
|
||||
# FFMPEG_LIBSWSCALE
|
||||
# FFMPEG_LIBSWRESAMPLE
|
||||
#
|
||||
# Copyright (c) 2008 Andreas Schneider <mail@cynapses.org>
|
||||
# Modified for other libraries by Lasse Kärkkäinen <tronic>
|
||||
|
@ -29,6 +31,7 @@ else (FFMPEG_LIBRARIES AND FFMPEG_INCLUDE_DIR)
|
|||
pkg_check_modules(_FFMPEG_AVFORMAT libavformat)
|
||||
pkg_check_modules(_FFMPEG_AVUTIL libavutil)
|
||||
pkg_check_modules(_FFMPEG_SWSCALE libswscale)
|
||||
pkg_check_modules(_FFMPEG_SWRESAMPLE libswresample)
|
||||
endif (PKG_CONFIG_FOUND)
|
||||
|
||||
find_path(FFMPEG_AVCODEC_INCLUDE_DIR
|
||||
|
@ -57,7 +60,12 @@ else (FFMPEG_LIBRARIES AND FFMPEG_INCLUDE_DIR)
|
|||
PATHS ${_FFMPEG_SWSCALE_LIBRARY_DIRS} /usr/lib /usr/local/lib /opt/local/lib /sw/lib
|
||||
)
|
||||
|
||||
if (FFMPEG_LIBAVCODEC AND FFMPEG_LIBAVFORMAT AND FFMPEG_LIBAVUTIL AND FFMPEG_LIBSWSCALE)
|
||||
find_library(FFMPEG_LIBSWRESAMPLE
|
||||
NAMES swresample
|
||||
PATHS ${_FFMPEG_SWRESAMPLE_LIBRARY_DIRS} /usr/lib /usr/local/lib /opt/local/lib /sw/lib
|
||||
)
|
||||
|
||||
if (FFMPEG_LIBAVCODEC AND FFMPEG_LIBAVFORMAT AND FFMPEG_LIBAVUTIL AND FFMPEG_LIBSWSCALE AND FFMPEG_LIBSWRESAMPLE)
|
||||
set(FFMPEG_FOUND TRUE)
|
||||
endif()
|
||||
|
||||
|
@ -69,6 +77,7 @@ else (FFMPEG_LIBRARIES AND FFMPEG_INCLUDE_DIR)
|
|||
${FFMPEG_LIBAVFORMAT}
|
||||
${FFMPEG_LIBAVUTIL}
|
||||
${FFMPEG_LIBSWSCALE}
|
||||
${FFMPEG_LIBSWRESAMPLE}
|
||||
)
|
||||
|
||||
endif (FFMPEG_FOUND)
|
||||
|
|
|
@ -5028,6 +5028,8 @@ bool idGameLocal::SkipCinematic( void )
|
|||
{
|
||||
skipCinematic = true;
|
||||
cinematicMaxSkipTime = gameLocal.time + SEC2MS( g_cinematicMaxSkipTime.GetFloat() );
|
||||
// SRS - Skip the remainder of the currently playing cinematic sound
|
||||
soundSystem->GetPlayingSoundWorld()->Skip( cinematicMaxSkipTime );
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -30,6 +30,11 @@ If you have questions concerning this license or the applicable additional terms
|
|||
|
||||
#include "precompiled.h"
|
||||
#pragma hdrstop
|
||||
#if defined(_MSC_VER) && !defined(USE_OPENAL)
|
||||
#include <sound/XAudio2/XA2_CinematicAudio.h>
|
||||
#else
|
||||
#include <sound/OpenAL/AL_CinematicAudio.h>
|
||||
#endif
|
||||
|
||||
|
||||
extern idCVar s_noSound;
|
||||
|
@ -63,7 +68,10 @@ extern "C"
|
|||
#include <libavcodec/avcodec.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libswscale/swscale.h>
|
||||
#include <libswresample/swresample.h>
|
||||
#include <libavutil/imgutils.h>
|
||||
}
|
||||
bool hasplanar = true;
|
||||
#endif
|
||||
|
||||
#ifdef USE_BINKDEC
|
||||
|
@ -99,18 +107,27 @@ private:
|
|||
|
||||
#if defined(USE_FFMPEG)
|
||||
int video_stream_index;
|
||||
int audio_stream_index; //GK: Make extra indexer for audio
|
||||
AVFormatContext* fmt_ctx;
|
||||
AVFrame* frame;
|
||||
AVFrame* frame2;
|
||||
AVFrame* frame3; //GK: make extra frame for audio
|
||||
#if LIBAVCODEC_VERSION_MAJOR > 58
|
||||
const AVCodec* dec;
|
||||
#else
|
||||
AVCodec* dec;
|
||||
#endif
|
||||
AVCodecContext* dec_ctx;
|
||||
AVCodecContext* dec_ctx2;
|
||||
SwsContext* img_convert_ctx;
|
||||
bool hasFrame;
|
||||
long framePos;
|
||||
|
||||
AVSampleFormat dst_smp;
|
||||
SwrContext* swr_ctx;
|
||||
cinData_t ImageForTimeFFMPEG( int milliseconds );
|
||||
bool InitFromFFMPEGFile( const char* qpath, bool looping );
|
||||
void FFMPEGReset();
|
||||
std::queue<AVPacket> packets[NUM_BUFFERS];
|
||||
#endif
|
||||
#ifdef USE_BINKDEC
|
||||
BinkHandle binkHandle;
|
||||
|
@ -193,6 +210,9 @@ private:
|
|||
void RoQPrepMcomp( int xoff, int yoff );
|
||||
void RoQReset();
|
||||
// RB end
|
||||
|
||||
//GK:Also init variables for XAudio2 or OpenAL (SRS - this must be an instance variable)
|
||||
CinematicAudio* cinematicAudio;
|
||||
};
|
||||
|
||||
// Carl: ROQ files from original Doom 3
|
||||
|
@ -237,13 +257,6 @@ idCinematicLocal::InitCinematic
|
|||
// RB: 64 bit fixes, changed long to int
|
||||
void idCinematic::InitCinematic()
|
||||
{
|
||||
#if defined(USE_FFMPEG)
|
||||
// Carl: ffmpeg for Bink and regular video files
|
||||
//common->Warning( "Loading FFMPEG...\n" );
|
||||
avcodec_register_all();
|
||||
av_register_all();
|
||||
#endif
|
||||
|
||||
// Carl: Doom 3 ROQ:
|
||||
float t_ub, t_vr, t_ug, t_vg;
|
||||
int i;
|
||||
|
@ -417,13 +430,17 @@ idCinematicLocal::idCinematicLocal()
|
|||
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55,28,1)
|
||||
frame = av_frame_alloc();
|
||||
frame2 = av_frame_alloc();
|
||||
frame3 = av_frame_alloc();
|
||||
#else
|
||||
frame = avcodec_alloc_frame();
|
||||
frame2 = avcodec_alloc_frame();
|
||||
frame3 = avcodec_alloc_frame();
|
||||
#endif // LIBAVCODEC_VERSION_INT
|
||||
dec_ctx = NULL;
|
||||
dec_ctx2 = NULL;
|
||||
fmt_ctx = NULL;
|
||||
video_stream_index = -1;
|
||||
audio_stream_index = -1;
|
||||
img_convert_ctx = NULL;
|
||||
hasFrame = false;
|
||||
framePos = -1;
|
||||
|
@ -479,6 +496,12 @@ idCinematicLocal::idCinematicLocal()
|
|||
img->AllocImage( opts, TF_LINEAR, TR_REPEAT );
|
||||
}
|
||||
|
||||
//GK: Make sure the cinematic voices are the first to be initialized
|
||||
#if defined(_MSC_VER) && !defined(USE_OPENAL)
|
||||
cinematicAudio = new( TAG_AUDIO ) CinematicAudio_XAudio2;
|
||||
#else
|
||||
cinematicAudio = new( TAG_AUDIO ) CinematicAudio_OpenAL;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -500,12 +523,16 @@ idCinematicLocal::~idCinematicLocal()
|
|||
// Carl: ffmpeg for bink and other video files:
|
||||
|
||||
// RB: TODO double check this. It seems we have different versions of ffmpeg on Kubuntu 13.10 and the win32 development files
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
//#if defined(_WIN32) || defined(_WIN64)
|
||||
// SRS - Should use the same version criteria as when the frames are allocated in idCinematicLocal() above
|
||||
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55,28,1)
|
||||
av_frame_free( &frame );
|
||||
av_frame_free( &frame2 );
|
||||
av_frame_free( &frame3 );
|
||||
#else
|
||||
av_freep( &frame );
|
||||
av_freep( &frame2 );
|
||||
av_freep( &frame3 );
|
||||
#endif
|
||||
|
||||
if( fmt_ctx )
|
||||
|
@ -535,6 +562,51 @@ idCinematicLocal::~idCinematicLocal()
|
|||
|
||||
delete img;
|
||||
img = NULL;
|
||||
|
||||
//GK: Properly close local XAudio2 or OpenAL voice
|
||||
cinematicAudio->ShutdownAudio();
|
||||
}
|
||||
|
||||
#if defined(USE_FFMPEG)
|
||||
/*
|
||||
==============
|
||||
idCinematicLocal::GetSampleFormat
|
||||
==============
|
||||
*/
|
||||
const char* GetSampleFormat( AVSampleFormat sample_fmt )
|
||||
{
|
||||
switch( sample_fmt )
|
||||
{
|
||||
case AV_SAMPLE_FMT_U8:
|
||||
case AV_SAMPLE_FMT_U8P:
|
||||
{
|
||||
return "8-bit";
|
||||
}
|
||||
case AV_SAMPLE_FMT_S16:
|
||||
case AV_SAMPLE_FMT_S16P:
|
||||
{
|
||||
return "16-bit";
|
||||
}
|
||||
case AV_SAMPLE_FMT_S32:
|
||||
case AV_SAMPLE_FMT_S32P:
|
||||
{
|
||||
return "32-bit";
|
||||
}
|
||||
case AV_SAMPLE_FMT_FLT:
|
||||
case AV_SAMPLE_FMT_FLTP:
|
||||
{
|
||||
return "Float";
|
||||
}
|
||||
case AV_SAMPLE_FMT_DBL:
|
||||
case AV_SAMPLE_FMT_DBLP:
|
||||
{
|
||||
return "Double";
|
||||
}
|
||||
default:
|
||||
{
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -542,10 +614,11 @@ idCinematicLocal::~idCinematicLocal()
|
|||
idCinematicLocal::InitFromFFMPEGFile
|
||||
==============
|
||||
*/
|
||||
#if defined(USE_FFMPEG)
|
||||
bool idCinematicLocal::InitFromFFMPEGFile( const char* qpath, bool amilooping )
|
||||
{
|
||||
int ret;
|
||||
int ret2;
|
||||
int file_size;
|
||||
looping = amilooping;
|
||||
startTime = 0;
|
||||
isRoQ = false;
|
||||
|
@ -557,6 +630,7 @@ bool idCinematicLocal::InitFromFFMPEGFile( const char* qpath, bool amilooping )
|
|||
if( testFile )
|
||||
{
|
||||
fullpath = testFile->GetFullPath();
|
||||
file_size = testFile->Length();
|
||||
fileSystem->CloseFile( testFile );
|
||||
}
|
||||
// RB: case sensitivity HACK for Linux
|
||||
|
@ -569,6 +643,7 @@ bool idCinematicLocal::InitFromFFMPEGFile( const char* qpath, bool amilooping )
|
|||
if( testFile )
|
||||
{
|
||||
fullpath = testFile->GetFullPath();
|
||||
file_size = testFile->Length();
|
||||
fileSystem->CloseFile( testFile );
|
||||
}
|
||||
else
|
||||
|
@ -598,14 +673,65 @@ bool idCinematicLocal::InitFromFFMPEGFile( const char* qpath, bool amilooping )
|
|||
return false;
|
||||
}
|
||||
video_stream_index = ret;
|
||||
dec_ctx = fmt_ctx->streams[video_stream_index]->codec;
|
||||
dec_ctx = avcodec_alloc_context3( dec );
|
||||
if( ( ret = avcodec_parameters_to_context( dec_ctx, fmt_ctx->streams[video_stream_index]->codecpar ) ) < 0 )
|
||||
{
|
||||
char* error = new char[256];
|
||||
av_strerror( ret, error, 256 );
|
||||
common->Warning( "idCinematic: Failed to create codec context from codec parameters with error: %s\n", error );
|
||||
}
|
||||
dec_ctx->time_base = fmt_ctx->streams[video_stream_index]->time_base;
|
||||
dec_ctx->framerate = fmt_ctx->streams[video_stream_index]->avg_frame_rate;
|
||||
dec_ctx->pkt_timebase = fmt_ctx->streams[video_stream_index]->time_base;
|
||||
/* init the video decoder */
|
||||
if( ( ret = avcodec_open2( dec_ctx, dec, NULL ) ) < 0 )
|
||||
{
|
||||
common->Warning( "idCinematic: Cannot open video decoder for: '%s', %d\n", qpath, looping );
|
||||
char* error = new char[256];
|
||||
av_strerror( ret, error, 256 );
|
||||
common->Warning( "idCinematic: Cannot open video decoder for: '%s', %d, with message: %s\n", qpath, looping, error );
|
||||
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 );
|
||||
if( ret2 >= 0 ) //Make audio optional (only intro video has audio no other)
|
||||
{
|
||||
audio_stream_index = ret2;
|
||||
dec_ctx2 = avcodec_alloc_context3( dec );
|
||||
if( ( ret2 = avcodec_parameters_to_context( dec_ctx2, fmt_ctx->streams[audio_stream_index]->codecpar ) ) < 0 )
|
||||
{
|
||||
char* error = new char[256];
|
||||
av_strerror( ret2, error, 256 );
|
||||
common->Warning( "idCinematic: Failed to create codec context from codec parameters with error: %s\n", error );
|
||||
}
|
||||
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 )
|
||||
{
|
||||
common->Warning( "idCinematic: Cannot open audio decoder for: '%s', %d\n", qpath, looping );
|
||||
//return false;
|
||||
}
|
||||
if( dec_ctx2->sample_fmt >= 5 )
|
||||
{
|
||||
dst_smp = static_cast<AVSampleFormat>( dec_ctx2->sample_fmt - 5 );
|
||||
swr_ctx = swr_alloc_set_opts( NULL, dec_ctx2->channel_layout, dst_smp, dec_ctx2->sample_rate, dec_ctx2->channel_layout, dec_ctx2->sample_fmt, dec_ctx2->sample_rate, 0, NULL );
|
||||
int res = swr_init( swr_ctx );
|
||||
hasplanar = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
hasplanar = false;
|
||||
}
|
||||
common->Printf( "Cinematic audio stream found: Sample Rate=%d Hz, Channels=%d, Format=%s, Planar=%d\n", dec_ctx2->sample_rate, dec_ctx2->channels, GetSampleFormat( dec_ctx2->sample_fmt ), hasplanar );
|
||||
cinematicAudio->InitAudio( dec_ctx2 );
|
||||
}
|
||||
else
|
||||
{
|
||||
// SRS - Most cinematics have no audio, so disable the warning to reduce distracting log messages
|
||||
//common->Warning("idCinematic: Cannot find an audio stream in: '%s', %d\n", qpath, looping);
|
||||
}
|
||||
//GK:End
|
||||
CIN_WIDTH = dec_ctx->width;
|
||||
CIN_HEIGHT = dec_ctx->height;
|
||||
/** Calculate Duration in seconds
|
||||
|
@ -626,12 +752,24 @@ bool idCinematicLocal::InitFromFFMPEGFile( const char* qpath, bool amilooping )
|
|||
*/
|
||||
int ticksPerFrame = dec_ctx->ticks_per_frame;
|
||||
float durationSec = static_cast<double>( fmt_ctx->streams[video_stream_index]->duration ) * static_cast<double>( ticksPerFrame ) / static_cast<double>( avr.den );
|
||||
//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 )
|
||||
{
|
||||
durationSec = file_size / dec_ctx->bit_rate;
|
||||
}
|
||||
else
|
||||
{
|
||||
durationSec = 100;
|
||||
}
|
||||
}
|
||||
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, %f FPS, %f sec\n", qpath, looping, CIN_WIDTH, CIN_HEIGHT, frameRate, durationSec );
|
||||
|
||||
image = ( byte* )Mem_Alloc( CIN_WIDTH * CIN_HEIGHT * 4 * 2, TAG_CINEMATIC );
|
||||
avpicture_fill( ( AVPicture* )frame2, image, AV_PIX_FMT_BGR32, CIN_WIDTH, CIN_HEIGHT );
|
||||
image = ( byte* )Mem_Alloc( CIN_WIDTH * CIN_HEIGHT * 4 * 2, 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 );
|
||||
|
@ -666,7 +804,7 @@ void idCinematicLocal::FFMPEGReset()
|
|||
{
|
||||
status = FMV_LOOPED;
|
||||
}
|
||||
else
|
||||
else if( av_seek_frame( fmt_ctx, audio_stream_index, 0, 0 ) < 0 && av_seek_frame( fmt_ctx, video_stream_index, 0, 0 ) < 0 )
|
||||
{
|
||||
status = FMV_EOF;
|
||||
}
|
||||
|
@ -1080,7 +1218,9 @@ idCinematicLocal::ImageForTimeFFMPEG
|
|||
cinData_t idCinematicLocal::ImageForTimeFFMPEG( int thisTime )
|
||||
{
|
||||
cinData_t cinData;
|
||||
|
||||
uint8_t** tBuffer2 = NULL;
|
||||
int num_bytes = 0;
|
||||
|
||||
if( thisTime <= 0 )
|
||||
{
|
||||
thisTime = Sys_Milliseconds();
|
||||
|
@ -1130,10 +1270,14 @@ cinData_t idCinematicLocal::ImageForTimeFFMPEG( int thisTime )
|
|||
AVPacket packet;
|
||||
while( framePos < desiredFrame )
|
||||
{
|
||||
int frameFinished = 0;
|
||||
int frameFinished = -1;
|
||||
//GK: Separate frame finisher for audio in order to not have the video lagging
|
||||
int frameFinished1 = -1;
|
||||
|
||||
int res = 0;
|
||||
|
||||
// Do a single frame by getting packets until we have a full frame
|
||||
while( !frameFinished )
|
||||
while( frameFinished != 0 )
|
||||
{
|
||||
// if we got to the end or failed
|
||||
if( av_read_frame( fmt_ctx, &packet ) < 0 )
|
||||
|
@ -1163,10 +1307,74 @@ cinData_t idCinematicLocal::ImageForTimeFFMPEG( int thisTime )
|
|||
if( packet.stream_index == video_stream_index )
|
||||
{
|
||||
// Decode video frame
|
||||
avcodec_decode_video2( dec_ctx, frame, &frameFinished, &packet );
|
||||
if( ( res = avcodec_send_packet( dec_ctx, &packet ) ) != 0 )
|
||||
{
|
||||
char* error = new char[256];
|
||||
av_strerror( res, error, 256 );
|
||||
common->Warning( "idCinematic: Failed to send packet for decoding with message: %s\n", error );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( ( frameFinished = avcodec_receive_frame( dec_ctx, frame ) ) != 0 )
|
||||
{
|
||||
char* error = new char[256];
|
||||
av_strerror( frameFinished, error, 256 );
|
||||
common->Warning( "idCinematic: Failed to receive frame from decoding with message: %s\n", error );
|
||||
}
|
||||
}
|
||||
}
|
||||
//GK:Begin
|
||||
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() );
|
||||
if( res != 0 && res != AVERROR( EAGAIN ) )
|
||||
{
|
||||
char* error = new char[256];
|
||||
av_strerror( res, error, 256 );
|
||||
common->Warning( "idCinematic: Failed to send packet for decoding with message: %s\n", error );
|
||||
}
|
||||
else
|
||||
{
|
||||
packet = packets->front();
|
||||
packets->pop();
|
||||
if( ( frameFinished1 = avcodec_receive_frame( dec_ctx2, frame3 ) ) != 0 )
|
||||
{
|
||||
char* error = new char[256];
|
||||
av_strerror( frameFinished1, error, 256 );
|
||||
common->Warning( "idCinematic: Failed to receive frame from decoding with message: %s\n", error );
|
||||
}
|
||||
else
|
||||
{
|
||||
int bufflinesize;
|
||||
if( hasplanar )
|
||||
{
|
||||
av_samples_alloc_array_and_samples( &tBuffer2,
|
||||
&bufflinesize,
|
||||
frame3->channels,
|
||||
av_rescale_rnd( frame3->nb_samples, frame3->sample_rate, frame3->sample_rate, AV_ROUND_UP ),
|
||||
dst_smp,
|
||||
0 );
|
||||
int res = swr_convert( swr_ctx, tBuffer2, bufflinesize, ( const uint8_t** )frame3->extended_data, frame3->nb_samples );
|
||||
num_bytes = av_samples_get_buffer_size( &bufflinesize, frame3->channels,
|
||||
res, dst_smp, 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
num_bytes = frame3->linesize[0];
|
||||
tBuffer2 = ( uint8_t** )malloc( sizeof( frame3->extended_data ) / sizeof( uint8_t* ) );
|
||||
tBuffer2[0] = ( uint8_t* )malloc( num_bytes );
|
||||
if( num_bytes > 0 )
|
||||
{
|
||||
memcpy( tBuffer2[0], frame3->extended_data[0], num_bytes );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//GK:End
|
||||
// Free the packet that was allocated by av_read_frame
|
||||
av_free_packet( &packet );
|
||||
av_packet_unref( &packet );
|
||||
}
|
||||
|
||||
framePos++;
|
||||
|
@ -1181,6 +1389,12 @@ cinData_t idCinematicLocal::ImageForTimeFFMPEG( int thisTime )
|
|||
img->UploadScratch( image, CIN_WIDTH, CIN_HEIGHT );
|
||||
hasFrame = true;
|
||||
cinData.image = img;
|
||||
|
||||
// SRS - If we have cinematic audio data, start playing it now
|
||||
if( tBuffer2 )
|
||||
{
|
||||
cinematicAudio->PlayAudio( tBuffer2[0], num_bytes );
|
||||
}
|
||||
|
||||
return cinData;
|
||||
}
|
||||
|
|
36
neo/sound/CinematicAudio.h
Normal file
36
neo/sound/CinematicAudio.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
/**
|
||||
* Copyright (C) 2021 George Kalmpokis
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is furnished to
|
||||
* do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software. As clarification, there
|
||||
* is no requirement that the copyright notice and permission be included in
|
||||
* binary distributions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#include <precompiled.h>
|
||||
#ifndef __CINEMATIC_AUDIO_H__
|
||||
#define __CINEMATIC_AUDIO_H__
|
||||
|
||||
class CinematicAudio
|
||||
{
|
||||
public:
|
||||
virtual void InitAudio( void* audioContext ) = 0;
|
||||
virtual void PlayAudio( uint8_t* data, int size ) = 0;
|
||||
virtual void ShutdownAudio() = 0;
|
||||
};
|
||||
|
||||
#endif
|
216
neo/sound/OpenAL/AL_CinematicAudio.cpp
Normal file
216
neo/sound/OpenAL/AL_CinematicAudio.cpp
Normal file
|
@ -0,0 +1,216 @@
|
|||
/**
|
||||
* Copyright (C) 2021 George Kalmpokis
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is furnished to
|
||||
* do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software. As clarification, there
|
||||
* is no requirement that the copyright notice and permission be included in
|
||||
* binary distributions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#include "precompiled.h"
|
||||
#include "AL_CinematicAudio.h"
|
||||
#include <sound/snd_local.h>
|
||||
|
||||
#if defined(USE_FFMPEG)
|
||||
extern "C"
|
||||
{
|
||||
#define __STDC_CONSTANT_MACROS
|
||||
#include <libavcodec/avcodec.h>
|
||||
}
|
||||
#endif
|
||||
|
||||
extern idCVar s_noSound;
|
||||
extern idCVar s_volume_dB;
|
||||
|
||||
CinematicAudio_OpenAL::CinematicAudio_OpenAL():
|
||||
av_rate_cin( 0 ),
|
||||
av_sample_cin( 0 ),
|
||||
offset( 0 ),
|
||||
trigger( false )
|
||||
{
|
||||
alGenSources( 1, &alMusicSourceVoicecin );
|
||||
|
||||
alSource3i( alMusicSourceVoicecin, AL_POSITION, 0, 0, 0 );
|
||||
alSourcei( alMusicSourceVoicecin, AL_SOURCE_RELATIVE, AL_TRUE );
|
||||
alSourcei( alMusicSourceVoicecin, AL_ROLLOFF_FACTOR, 0 );
|
||||
alListenerf( AL_GAIN, s_noSound.GetBool() ? 0.0f : DBtoLinear( s_volume_dB.GetFloat() ) ); //GK: Set the sound volume the same that is used in DOOM 3
|
||||
alGenBuffers( NUM_BUFFERS, &alMusicBuffercin[0] );
|
||||
}
|
||||
|
||||
void CinematicAudio_OpenAL::InitAudio( void* audioContext )
|
||||
{
|
||||
//SRS - This InitAudio() implementation is FFMPEG-only until we have a BinkDec solution as well
|
||||
#if defined(USE_FFMPEG)
|
||||
AVCodecContext* dec_ctx2 = ( AVCodecContext* )audioContext;
|
||||
av_rate_cin = dec_ctx2->sample_rate;
|
||||
|
||||
switch( dec_ctx2->sample_fmt )
|
||||
{
|
||||
case AV_SAMPLE_FMT_U8:
|
||||
case AV_SAMPLE_FMT_U8P:
|
||||
{
|
||||
av_sample_cin = dec_ctx2->channels == 2 ? AL_FORMAT_STEREO8 : AL_FORMAT_MONO8;
|
||||
break;
|
||||
}
|
||||
case AV_SAMPLE_FMT_S16:
|
||||
case AV_SAMPLE_FMT_S16P:
|
||||
{
|
||||
av_sample_cin = dec_ctx2->channels == 2 ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16;
|
||||
break;
|
||||
}
|
||||
case AV_SAMPLE_FMT_FLT:
|
||||
case AV_SAMPLE_FMT_FLTP:
|
||||
{
|
||||
av_sample_cin = dec_ctx2->channels == 2 ? AL_FORMAT_STEREO_FLOAT32 : AL_FORMAT_MONO_FLOAT32;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
common->Warning( "Unknown or incompatible cinematic audio format for OpenAL, sample_fmt = %d\n", dec_ctx2->sample_fmt );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
alSourceRewind( alMusicSourceVoicecin );
|
||||
alSourcei( alMusicSourceVoicecin, AL_BUFFER, 0 );
|
||||
offset = 0;
|
||||
trigger = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void CinematicAudio_OpenAL::PlayAudio( uint8_t* data, int size )
|
||||
{
|
||||
ALint processed, state;
|
||||
|
||||
alGetSourcei( alMusicSourceVoicecin, AL_SOURCE_STATE, &state );
|
||||
alGetSourcei( alMusicSourceVoicecin, AL_BUFFERS_PROCESSED, &processed );
|
||||
|
||||
if( trigger )
|
||||
{
|
||||
tBuffer->push( data );
|
||||
sizes->push( size );
|
||||
while( processed > 0 )
|
||||
{
|
||||
ALuint bufid;
|
||||
|
||||
alSourceUnqueueBuffers( alMusicSourceVoicecin, 1, &bufid );
|
||||
processed--;
|
||||
if( !tBuffer->empty() )
|
||||
{
|
||||
int tempSize = sizes->front();
|
||||
sizes->pop();
|
||||
uint8_t* tempdata = tBuffer->front();
|
||||
tBuffer->pop();
|
||||
if( tempSize > 0 )
|
||||
{
|
||||
alBufferData( bufid, av_sample_cin, tempdata, tempSize, av_rate_cin );
|
||||
alSourceQueueBuffers( alMusicSourceVoicecin, 1, &bufid );
|
||||
ALenum error = alGetError();
|
||||
if( error != AL_NO_ERROR )
|
||||
{
|
||||
common->Warning( "OpenAL Cinematic: %s\n", alGetString( error ) );
|
||||
return;
|
||||
}
|
||||
}
|
||||
offset++;
|
||||
if( offset == NUM_BUFFERS )
|
||||
{
|
||||
offset = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
alBufferData( alMusicBuffercin[offset], av_sample_cin, data, size, av_rate_cin );
|
||||
offset++;
|
||||
if( offset == NUM_BUFFERS )
|
||||
{
|
||||
alSourceQueueBuffers( alMusicSourceVoicecin, offset, alMusicBuffercin );
|
||||
ALenum error = alGetError();
|
||||
if( error != AL_NO_ERROR )
|
||||
{
|
||||
common->Warning( "OpenAL Cinematic: %s\n", alGetString( error ) );
|
||||
return;
|
||||
}
|
||||
trigger = true;
|
||||
offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if( trigger )
|
||||
{
|
||||
if( state != AL_PLAYING )
|
||||
{
|
||||
ALint queued;
|
||||
alGetSourcei( alMusicSourceVoicecin, AL_BUFFERS_QUEUED, &queued );
|
||||
if( queued == 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
alSourcePlay( alMusicSourceVoicecin );
|
||||
ALenum error = alGetError();
|
||||
if( error != AL_NO_ERROR )
|
||||
{
|
||||
common->Warning( "OpenAL Cinematic: %s\n", alGetString( error ) );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CinematicAudio_OpenAL::ShutdownAudio()
|
||||
{
|
||||
if( alIsSource( alMusicSourceVoicecin ) )
|
||||
{
|
||||
alSourceStop( alMusicSourceVoicecin );
|
||||
// SRS - Make sure we don't try to unqueue buffers that were never queued in the first place
|
||||
if( !tBuffer->empty() )
|
||||
{
|
||||
alSourceUnqueueBuffers( alMusicSourceVoicecin, NUM_BUFFERS, alMusicBuffercin );
|
||||
}
|
||||
alSourcei( alMusicSourceVoicecin, AL_BUFFER, 0 );
|
||||
alDeleteSources( 1, &alMusicSourceVoicecin );
|
||||
if( CheckALErrors() == AL_NO_ERROR )
|
||||
{
|
||||
alMusicSourceVoicecin = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if( alMusicBuffercin )
|
||||
{
|
||||
alDeleteBuffers( NUM_BUFFERS, alMusicBuffercin );
|
||||
}
|
||||
if( !tBuffer->empty() )
|
||||
{
|
||||
int buffersize = tBuffer->size();
|
||||
while( buffersize > 0 )
|
||||
{
|
||||
tBuffer->pop();
|
||||
buffersize--;
|
||||
}
|
||||
}
|
||||
if( !sizes->empty() )
|
||||
{
|
||||
int buffersize = sizes->size();
|
||||
while( buffersize > 0 )
|
||||
{
|
||||
sizes->pop();
|
||||
buffersize--;
|
||||
}
|
||||
}
|
||||
}
|
61
neo/sound/OpenAL/AL_CinematicAudio.h
Normal file
61
neo/sound/OpenAL/AL_CinematicAudio.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
* Copyright (C) 2021 George Kalmpokis
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is furnished to
|
||||
* do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software. As clarification, there
|
||||
* is no requirement that the copyright notice and permission be included in
|
||||
* binary distributions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#include <precompiled.h>
|
||||
#include "../CinematicAudio.h"
|
||||
// SRS - Added check on OSX for OpenAL Soft headers vs macOS SDK headers
|
||||
#if defined(__APPLE__) && !defined(USE_OPENAL_SOFT_INCLUDES)
|
||||
#include <OpenAL/al.h>
|
||||
#else
|
||||
#include <AL/al.h>
|
||||
#endif
|
||||
#include <queue>
|
||||
#ifndef __CINEMATIC_AUDIO_AL_H__
|
||||
#define __CINEMATIC_AUDIO_AL_H__
|
||||
#define NUM_BUFFERS 4
|
||||
|
||||
class CinematicAudio_OpenAL: public CinematicAudio
|
||||
{
|
||||
public:
|
||||
CinematicAudio_OpenAL();
|
||||
void InitAudio( void* audioContext );
|
||||
void PlayAudio( uint8_t* data, int size );
|
||||
void ShutdownAudio();
|
||||
private:
|
||||
ALuint alMusicSourceVoicecin;
|
||||
ALuint alMusicBuffercin[NUM_BUFFERS];
|
||||
ALenum av_sample_cin;
|
||||
int av_rate_cin;
|
||||
int offset;
|
||||
bool trigger;
|
||||
|
||||
//GK: Unlike XAudio2 which can accept buffer until the end of this world.
|
||||
// OpenAL can accept buffers as long as there are freely available buffers.
|
||||
// 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 poping 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];
|
||||
};
|
||||
|
||||
#endif
|
144
neo/sound/XAudio2/XA2_CinematicAudio.cpp
Normal file
144
neo/sound/XAudio2/XA2_CinematicAudio.cpp
Normal file
|
@ -0,0 +1,144 @@
|
|||
/**
|
||||
* Copyright (C) 2021 George Kalmpokis
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is furnished to
|
||||
* do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software. As clarification, there
|
||||
* is no requirement that the copyright notice and permission be included in
|
||||
* binary distributions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#include "precompiled.h"
|
||||
#include "XA2_CinematicAudio.h"
|
||||
#include <sound/snd_local.h>
|
||||
|
||||
#if defined(USE_FFMPEG)
|
||||
extern "C"
|
||||
{
|
||||
#define __STDC_CONSTANT_MACROS
|
||||
#include <libavcodec/avcodec.h>
|
||||
}
|
||||
#endif
|
||||
|
||||
void CinematicAudio_XAudio2::InitAudio( void* audioContext )
|
||||
{
|
||||
//SRS - This InitAudio() implementation is FFMPEG-only until we have a BinkDec solution as well
|
||||
#if defined(USE_FFMPEG)
|
||||
AVCodecContext* dec_ctx2 = ( AVCodecContext* )audioContext;
|
||||
int format_byte = 0;
|
||||
bool use_ext = false;
|
||||
|
||||
switch( dec_ctx2->sample_fmt )
|
||||
{
|
||||
case AV_SAMPLE_FMT_U8:
|
||||
case AV_SAMPLE_FMT_U8P:
|
||||
{
|
||||
format_byte = 1;
|
||||
break;
|
||||
}
|
||||
case AV_SAMPLE_FMT_S16:
|
||||
case AV_SAMPLE_FMT_S16P:
|
||||
{
|
||||
format_byte = 2;
|
||||
break;
|
||||
}
|
||||
case AV_SAMPLE_FMT_FLT:
|
||||
case AV_SAMPLE_FMT_FLTP:
|
||||
{
|
||||
format_byte = 4;
|
||||
use_ext = true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
common->Warning( "Unknown or incompatible cinematic audio format for XAudio2, sample_fmt = %d\n", dec_ctx2->sample_fmt );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
WAVEFORMATEXTENSIBLE exvoice = { 0 };
|
||||
voiceFormatcine.wFormatTag = WAVE_FORMAT_EXTENSIBLE; //Use extensible wave format in order to handle properly the audio
|
||||
voiceFormatcine.nChannels = dec_ctx2->channels; //fixed
|
||||
voiceFormatcine.nSamplesPerSec = dec_ctx2->sample_rate; //fixed
|
||||
voiceFormatcine.wBitsPerSample = format_byte * 8; //fixed
|
||||
voiceFormatcine.nBlockAlign = format_byte * voiceFormatcine.nChannels; //fixed
|
||||
voiceFormatcine.nAvgBytesPerSec = voiceFormatcine.nSamplesPerSec * voiceFormatcine.nBlockAlign; //fixed
|
||||
voiceFormatcine.cbSize = 22; //fixed
|
||||
exvoice.Format = voiceFormatcine;
|
||||
switch( voiceFormatcine.nChannels )
|
||||
{
|
||||
case 1:
|
||||
exvoice.dwChannelMask = SPEAKER_MONO;
|
||||
break;
|
||||
case 2:
|
||||
exvoice.dwChannelMask = SPEAKER_STEREO;
|
||||
break;
|
||||
case 4:
|
||||
exvoice.dwChannelMask = SPEAKER_QUAD;
|
||||
break;
|
||||
case 5:
|
||||
exvoice.dwChannelMask = SPEAKER_5POINT1_SURROUND;
|
||||
break;
|
||||
case 7:
|
||||
exvoice.dwChannelMask = SPEAKER_7POINT1_SURROUND;
|
||||
break;
|
||||
default:
|
||||
exvoice.dwChannelMask = SPEAKER_MONO;
|
||||
break;
|
||||
}
|
||||
exvoice.Samples.wReserved = 0;
|
||||
exvoice.Samples.wValidBitsPerSample = voiceFormatcine.wBitsPerSample;
|
||||
exvoice.Samples.wSamplesPerBlock = voiceFormatcine.wBitsPerSample;
|
||||
exvoice.SubFormat = use_ext ? KSDATAFORMAT_SUBTYPE_IEEE_FLOAT : KSDATAFORMAT_SUBTYPE_PCM;
|
||||
( ( IXAudio2* )soundSystemLocal.GetInternal() )->CreateSourceVoice( &pMusicSourceVoice1, ( WAVEFORMATEX* )&exvoice, XAUDIO2_VOICE_USEFILTER ); //Use the XAudio2 that the game has initialized instead of making your own
|
||||
#endif
|
||||
}
|
||||
|
||||
void CinematicAudio_XAudio2::PlayAudio( uint8_t* data, int size )
|
||||
{
|
||||
//Store the data to XAudio2 buffer
|
||||
Packet.Flags = XAUDIO2_END_OF_STREAM;
|
||||
Packet.AudioBytes = size;
|
||||
Packet.pAudioData = ( BYTE* )data;
|
||||
Packet.PlayBegin = 0;
|
||||
Packet.PlayLength = 0;
|
||||
Packet.LoopBegin = 0;
|
||||
Packet.LoopLength = 0;
|
||||
Packet.LoopCount = 0;
|
||||
Packet.pContext = NULL;
|
||||
HRESULT hr;
|
||||
if( FAILED( hr = pMusicSourceVoice1->SubmitSourceBuffer( &Packet ) ) )
|
||||
{
|
||||
int fail = 1;
|
||||
}
|
||||
|
||||
// Play the source voice
|
||||
if( FAILED( hr = pMusicSourceVoice1->Start( 0 ) ) )
|
||||
{
|
||||
int fail = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void CinematicAudio_XAudio2::ShutdownAudio()
|
||||
{
|
||||
if( pMusicSourceVoice1 )
|
||||
{
|
||||
pMusicSourceVoice1->Stop();
|
||||
pMusicSourceVoice1->FlushSourceBuffers();
|
||||
pMusicSourceVoice1->DestroyVoice();
|
||||
pMusicSourceVoice1 = NULL;
|
||||
}
|
||||
}
|
46
neo/sound/XAudio2/XA2_CinematicAudio.h
Normal file
46
neo/sound/XAudio2/XA2_CinematicAudio.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
/**
|
||||
* Copyright (C) 2021 George Kalmpokis
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is furnished to
|
||||
* do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software. As clarification, there
|
||||
* is no requirement that the copyright notice and permission be included in
|
||||
* binary distributions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#include <precompiled.h>
|
||||
#include "../CinematicAudio.h"
|
||||
#include <xaudio2.h>
|
||||
#ifndef __CINEMATIC_AUDIO_XA2_H__
|
||||
#define __CINEMATIC_AUDIO_XA2_H__
|
||||
|
||||
class CinematicAudio_XAudio2: public CinematicAudio
|
||||
{
|
||||
public:
|
||||
CinematicAudio_XAudio2():
|
||||
pMusicSourceVoice1( NULL )
|
||||
{
|
||||
}
|
||||
void InitAudio( void* audioContext );
|
||||
void PlayAudio( uint8_t* data, int size );
|
||||
void ShutdownAudio();
|
||||
private:
|
||||
WAVEFORMATEX voiceFormatcine = { 0 };
|
||||
IXAudio2SourceVoice* pMusicSourceVoice1;
|
||||
XAUDIO2_BUFFER Packet = { 0 };
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue