diff options
Diffstat (limited to 'src/client')
-rw-r--r-- | src/client/cl_avi.c | 10 | ||||
-rw-r--r-- | src/client/cl_main.c | 8 | ||||
-rw-r--r-- | src/client/client.h | 2 | ||||
-rw-r--r-- | src/client/snd_codec.c | 4 | ||||
-rw-r--r-- | src/client/snd_codec.h | 1 | ||||
-rw-r--r-- | src/client/snd_codec_ogg.c | 465 | ||||
-rw-r--r-- | src/client/snd_dma.c | 2 |
7 files changed, 480 insertions, 12 deletions
diff --git a/src/client/cl_avi.c b/src/client/cl_avi.c index 4a372d8b..178260be 100644 --- a/src/client/cl_avi.c +++ b/src/client/cl_avi.c @@ -332,9 +332,9 @@ qboolean CL_OpenAVIForWriting( const char *fileName ) Com_Memset( &afd, 0, sizeof( aviFileData_t ) ); // Don't start if a framerate has not been chosen - if( cl_avidemo->integer <= 0 ) + if( cl_aviFrameRate->integer <= 0 ) { - Com_Printf( S_COLOR_RED "cl_avidemo must be >= 1\n" ); + Com_Printf( S_COLOR_RED "cl_aviFrameRate must be >= 1\n" ); return qfalse; } @@ -349,7 +349,7 @@ qboolean CL_OpenAVIForWriting( const char *fileName ) Q_strncpyz( afd.fileName, fileName, MAX_QPATH ); - afd.frameRate = cl_avidemo->integer; + afd.frameRate = cl_aviFrameRate->integer; afd.framePeriod = (int)( 1000000.0f / afd.frameRate ); afd.width = cls.glconfig.vidWidth; afd.height = cls.glconfig.vidHeight; @@ -375,7 +375,7 @@ qboolean CL_OpenAVIForWriting( const char *fileName ) while( ( afd.a.rate % suggestRate ) && suggestRate >= 1 ) suggestRate--; - Com_Printf( S_COLOR_YELLOW "WARNING: cl_avidemo is not a divisor " + Com_Printf( S_COLOR_YELLOW "WARNING: cl_aviFrameRate is not a divisor " "of the audio rate, suggest %d\n", suggestRate ); } @@ -484,7 +484,7 @@ void CL_WriteAVIAudioFrame( const byte *pcmBuffer, int size ) bytesInBuffer += size; // Only write if we have a frame's worth of audio - if( bytesInBuffer >= (int)ceil( afd.a.rate / cl_avidemo->value ) * + if( bytesInBuffer >= (int)ceil( afd.a.rate / cl_aviFrameRate->value ) * afd.a.sampleSize ) { int chunkOffset = afd.fileSize - afd.moviOffset - 8; diff --git a/src/client/cl_main.c b/src/client/cl_main.c index a00f901e..3f2e1152 100644 --- a/src/client/cl_main.c +++ b/src/client/cl_main.c @@ -45,7 +45,7 @@ cvar_t *cl_shownet; cvar_t *cl_showSend; cvar_t *cl_timedemo; cvar_t *cl_autoRecordDemo; -cvar_t *cl_avidemo; +cvar_t *cl_aviFrameRate; cvar_t *cl_aviMotionJpeg; cvar_t *cl_forceavidemo; @@ -1974,13 +1974,13 @@ void CL_Frame ( int msec ) { } // if recording an avi, lock to a fixed fps - if ( CL_VideoRecording( ) && cl_avidemo->integer && msec) { + if ( CL_VideoRecording( ) && cl_aviFrameRate->integer && msec) { // save the current screen if ( cls.state == CA_ACTIVE || cl_forceavidemo->integer) { CL_TakeVideoFrame( ); // fixed time for next frame' - msec = (int)ceil( (1000.0f / cl_avidemo->value) * com_timescale->value ); + msec = (int)ceil( (1000.0f / cl_aviFrameRate->value) * com_timescale->value ); if (msec == 0) { msec = 1; } @@ -2362,7 +2362,7 @@ void CL_Init( void ) { cl_timedemo = Cvar_Get ("timedemo", "0", 0); cl_autoRecordDemo = Cvar_Get ("cl_autoRecordDemo", "0", CVAR_ARCHIVE); - cl_avidemo = Cvar_Get ("cl_avidemo", "25", CVAR_ARCHIVE); + cl_aviFrameRate = Cvar_Get ("cl_aviFrameRate", "25", CVAR_ARCHIVE); cl_aviMotionJpeg = Cvar_Get ("cl_aviMotionJpeg", "1", CVAR_ARCHIVE); cl_forceavidemo = Cvar_Get ("cl_forceavidemo", "0", 0); diff --git a/src/client/client.h b/src/client/client.h index 1c4fa198..fb1ecea1 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -343,7 +343,7 @@ extern cvar_t *m_side; extern cvar_t *m_filter; extern cvar_t *cl_timedemo; -extern cvar_t *cl_avidemo; +extern cvar_t *cl_aviFrameRate; extern cvar_t *cl_aviMotionJpeg; extern cvar_t *cl_activeAction; diff --git a/src/client/snd_codec.c b/src/client/snd_codec.c index 338d0306..e1c6bb47 100644 --- a/src/client/snd_codec.c +++ b/src/client/snd_codec.c @@ -192,9 +192,10 @@ snd_stream_t *S_CodecUtilOpen(const char *filename, snd_codec_t *codec) { snd_stream_t *stream; fileHandle_t hnd; + int length; // Try to open the file - FS_FOpenFileRead(filename, &hnd, qtrue); + length = FS_FOpenFileRead(filename, &hnd, qtrue); if(!hnd) { Com_Printf("Can't read sound file %s\n", filename); @@ -212,6 +213,7 @@ snd_stream_t *S_CodecUtilOpen(const char *filename, snd_codec_t *codec) // Copy over, return stream->codec = codec; stream->file = hnd; + stream->length = length; return stream; } diff --git a/src/client/snd_codec.h b/src/client/snd_codec.h index 74ac77e9..582e65ef 100644 --- a/src/client/snd_codec.h +++ b/src/client/snd_codec.h @@ -45,6 +45,7 @@ typedef struct snd_stream_s snd_codec_t *codec; fileHandle_t file; snd_info_t info; + int length; int pos; void *ptr; } snd_stream_t; diff --git a/src/client/snd_codec_ogg.c b/src/client/snd_codec_ogg.c new file mode 100644 index 00000000..20462fcb --- /dev/null +++ b/src/client/snd_codec_ogg.c @@ -0,0 +1,465 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. +Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com) +Copyright (C) 2005-2006 Joerg Dietrich <dietrich_joerg@gmx.de> + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake III Arena source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +// OGG support is enabled by this define +#ifdef USE_CODEC_VORBIS + +// includes for the Q3 sound system +#include "client.h" +#include "snd_codec.h" + +// includes for the OGG codec +#include <errno.h> +#include <vorbis/vorbisfile.h> + +// The OGG codec can return the samples in a number of different formats, +// we use the standard signed short format. +#define OGG_SAMPLEWIDTH 2 + +// Q3 OGG codec +snd_codec_t ogg_codec = +{ + ".ogg", + S_OGG_CodecLoad, + S_OGG_CodecOpenStream, + S_OGG_CodecReadStream, + S_OGG_CodecCloseStream, + NULL +}; + +// callbacks for vobisfile + +// fread() replacement +size_t S_OGG_Callback_read(void *ptr, size_t size, size_t nmemb, void *datasource) +{ + snd_stream_t *stream; + int byteSize = 0; + int bytesRead = 0; + size_t nMembRead = 0; + + // check if input is valid + if(!ptr) + { + errno = EFAULT; + return 0; + } + + if(!(size && nmemb)) + { + // It's not an error, caller just wants zero bytes! + errno = 0; + return 0; + } + + if(!datasource) + { + errno = EBADF; + return 0; + } + + // we use a snd_stream_t in the generic pointer to pass around + stream = (snd_stream_t *) datasource; + + // FS_Read does not support multi-byte elements + byteSize = nmemb * size; + + // read it with the Q3 function FS_Read() + bytesRead = FS_Read(ptr, byteSize, stream->file); + + // update the file position + stream->pos += bytesRead; + + // this function returns the number of elements read not the number of bytes + nMembRead = bytesRead / size; + + // even if the last member is only read partially + // it is counted as a whole in the return value + if(bytesRead % size) + { + nMembRead++; + } + + return nMembRead; +} + +// fseek() replacement +int S_OGG_Callback_seek(void *datasource, ogg_int64_t offset, int whence) +{ + snd_stream_t *stream; + int retVal = 0; + + // check if input is valid + if(!datasource) + { + errno = EBADF; + return -1; + } + + // snd_stream_t in the generic pointer + stream = (snd_stream_t *) datasource; + + // we must map the whence to its Q3 counterpart + switch(whence) + { + case SEEK_SET : + { + // set the file position in the actual file with the Q3 function + retVal = FS_Seek(stream->file, (long) offset, FS_SEEK_SET); + + // something has gone wrong, so we return here + if(!(retVal == 0)) + { + return retVal; + } + + // keep track of file position + stream->pos = (int) offset; + break; + } + + case SEEK_CUR : + { + // set the file position in the actual file with the Q3 function + retVal = FS_Seek(stream->file, (long) offset, FS_SEEK_CUR); + + // something has gone wrong, so we return here + if(!(retVal == 0)) + { + return retVal; + } + + // keep track of file position + stream->pos += (int) offset; + break; + } + + case SEEK_END : + { + // Quake 3 seems to have trouble with FS_SEEK_END + // so we use the file length and FS_SEEK_SET + + // set the file position in the actual file with the Q3 function + retVal = FS_Seek(stream->file, (long) stream->length + (long) offset, FS_SEEK_SET); + + // something has gone wrong, so we return here + if(!(retVal == 0)) + { + return retVal; + } + + // keep track of file position + stream->pos = stream->length + (int) offset; + break; + } + + default : + { + // unknown whence, so we return an error + errno = EINVAL; + return -1; + } + } + + // stream->pos shouldn't be smaller than zero or bigger than the filesize + stream->pos = (stream->pos < 0) ? 0 : stream->pos; + stream->pos = (stream->pos > stream->length) ? stream->length : stream->pos; + + return 0; +} + +// fclose() replacement +int S_OGG_Callback_close(void *datasource) +{ + // we do nothing here and close all things manually in S_OGG_CodecCloseStream() + return 0; +} + +// ftell() replacement +long S_OGG_Callback_tell(void *datasource) +{ + // check if input is valid + if(!datasource) + { + errno = EBADF; + return -1; + } + + // we keep track of the file position in stream->pos + return (long) (((snd_stream_t *) datasource) -> pos); +} + +// the callback structure +const ov_callbacks S_OGG_Callbacks = +{ + &S_OGG_Callback_read, + &S_OGG_Callback_seek, + &S_OGG_Callback_close, + &S_OGG_Callback_tell +}; + +/* +================= +S_OGG_CodecOpenStream +================= +*/ +snd_stream_t *S_OGG_CodecOpenStream(const char *filename) +{ + snd_stream_t *stream; + + // OGG codec control structure + OggVorbis_File *vf; + + // some variables used to get informations about the OGG + vorbis_info *OGGInfo; + ogg_int64_t numSamples; + + // check if input is valid + if(!filename) + { + return NULL; + } + + // Open the stream + stream = S_CodecUtilOpen(filename, &ogg_codec); + if(!stream) + { + return NULL; + } + + // alloctate the OggVorbis_File + vf = Z_Malloc(sizeof(OggVorbis_File)); + if(!vf) + { + S_CodecUtilClose(stream); + + return NULL; + } + + // open the codec with our callbacks and stream as the generic pointer + if(ov_open_callbacks(stream, vf, NULL, 0, S_OGG_Callbacks) != 0) + { + Z_Free(vf); + + S_CodecUtilClose(stream); + + return NULL; + } + + // the stream must be seekable + if(!ov_seekable(vf)) + { + ov_clear(vf); + + Z_Free(vf); + + S_CodecUtilClose(stream); + + return NULL; + } + + // we only support OGGs with one substream + if(ov_streams(vf) != 1) + { + ov_clear(vf); + + Z_Free(vf); + + S_CodecUtilClose(stream); + + return NULL; + } + + // get the info about channels and rate + OGGInfo = ov_info(vf, 0); + if(!OGGInfo) + { + ov_clear(vf); + + Z_Free(vf); + + S_CodecUtilClose(stream); + + return NULL; + } + + // get the number of sample-frames in the OGG + numSamples = ov_pcm_total(vf, 0); + + // fill in the info-structure in the stream + stream->info.rate = OGGInfo->rate; + stream->info.width = OGG_SAMPLEWIDTH; + stream->info.channels = OGGInfo->channels; + stream->info.samples = numSamples; + stream->info.size = stream->info.samples * stream->info.channels * stream->info.width; + stream->info.dataofs = 0; + + // We use stream->pos for the file pointer in the compressed ogg file + stream->pos = 0; + + // We use the generic pointer in stream for the OGG codec control structure + stream->ptr = vf; + + return stream; +} + +/* +================= +S_OGG_CodecCloseStream +================= +*/ +void S_OGG_CodecCloseStream(snd_stream_t *stream) +{ + // check if input is valid + if(!stream) + { + return; + } + + // let the OGG codec cleanup its stuff + ov_clear((OggVorbis_File *) stream->ptr); + + // free the OGG codec control struct + Z_Free(stream->ptr); + + // close the stream + S_CodecUtilClose(stream); +} + +/* +================= +S_OGG_CodecReadStream +================= +*/ +int S_OGG_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer) +{ + // buffer handling + int bytesRead, bytesLeft, c; + char *bufPtr; + + // Bitstream for the decoder + int BS = 0; + + // check if input is valid + if(!(stream && buffer)) + { + return 0; + } + + if(bytes <= 0) + { + return 0; + } + + bytesRead = 0; + bytesLeft = bytes; + bufPtr = buffer; + + // cycle until we have the requested or all available bytes read + while(-1) + { + // read some bytes from the OGG codec + c = ov_read((OggVorbis_File *) stream->ptr, bufPtr, bytesLeft, 0, OGG_SAMPLEWIDTH, 1, &BS); + + // no more bytes are left + if(c <= 0) + { + break; + } + + bytesRead += c; + bytesLeft -= c; + bufPtr += c; + + // we have enough bytes + if(bytesLeft <= 0) + { + break; + } + } + + return bytesRead; +} + +/* +===================================================================== +S_OGG_CodecLoad + +We handle S_OGG_CodecLoad as a special case of the streaming functions +where we read the whole stream at once. +====================================================================== +*/ +void *S_OGG_CodecLoad(const char *filename, snd_info_t *info) +{ + snd_stream_t *stream; + unsigned char *buffer; + int bytesRead; + + // check if input is valid + if(!(filename && info)) + { + return NULL; + } + + // open the file as a stream + stream = S_OGG_CodecOpenStream(filename); + if(!stream) + { + return NULL; + } + + // copy over the info + info->rate = stream->info.rate; + info->width = stream->info.width; + info->channels = stream->info.channels; + info->samples = stream->info.samples; + info->size = stream->info.size; + info->dataofs = stream->info.dataofs; + + // allocate a buffer + // this buffer must be free-ed by the caller of this function + buffer = Z_Malloc(info->size); + if(!buffer) + { + S_OGG_CodecCloseStream(stream); + + return NULL; + } + + // fill the buffer + bytesRead = S_OGG_CodecReadStream(stream, info->size, buffer); + + // we don't even have read a single byte + if(bytesRead <= 0) + { + S_OGG_CodecCloseStream(stream); + + return NULL; + } + + S_OGG_CodecCloseStream(stream); + + return buffer; +} + +#endif // USE_CODEC_VORBIS diff --git a/src/client/snd_dma.c b/src/client/snd_dma.c index d51a4b85..ee57f6f2 100644 --- a/src/client/snd_dma.c +++ b/src/client/snd_dma.c @@ -1142,7 +1142,7 @@ void S_GetSoundtime(void) if( CL_VideoRecording( ) ) { - s_soundtime += (int)ceil( dma.speed / cl_avidemo->value ); + s_soundtime += (int)ceil( dma.speed / cl_aviFrameRate->value ); return; } |