📄 mpegaudio.cpp
字号:
/*
SMPEG - SDL MPEG Player Library
Copyright (C) 1999 Loki Entertainment Software
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* A class based on the MPEG stream class, used to parse and play audio */
#include "MPEGaudio.h"
/*
* The below is commented out in favor of our interface routines
*/
#if 0
#include "MPEGstream.h"
MPEGaudio:: MPEGaudio(MPEGstream *stream, bool initSDL) : sdl_audio(initSDL)
{
/* Initialize MPEG audio */
mpeg = stream;
initialize();
/* Just be paranoid. If all goes well, this will be set to true */
valid_stream = false;
/* Analyze the MPEG audio stream */
if ( loadheader() ) {
SDL_AudioSpec wanted;
WantedSpec(&wanted);
/* Calculate the samples per frame */
samplesperframe = 32*wanted.channels;
if( layer == 3 ) {
samplesperframe *= 18;
if ( version == 0 ) {
samplesperframe *= 2;
}
} else {
samplesperframe *= SCALEBLOCK;
if ( layer == 2 ) {
samplesperframe *= 3;
}
}
if ( sdl_audio ) {
/* Open the audio, get actual audio hardware format and convert */
bool audio_active;
SDL_AudioSpec actual;
audio_active = (SDL_OpenAudio(&wanted, &actual) == 0);
if ( audio_active ) {
ActualSpec(&actual);
valid_stream = true;
} else {
SetError(SDL_GetError());
}
SDL_PauseAudio(0);
} else { /* The stream is always valid if we don't initialize SDL */
valid_stream = true;
}
Volume(100);
}
/* For using system timestamp */
for (int i=0; i<N_TIMESTAMPS; i++)
timestamp[i] = -1;
}
MPEGaudio:: ~MPEGaudio()
{
#ifdef THREADED_AUDIO
/* Stop the decode thread */
StopDecoding();
#endif
/* Remove ourselves from the mixer hooks */
Stop();
if ( sdl_audio ) {
/* Close up the audio so others may play */
SDL_CloseAudio();
}
}
bool
MPEGaudio:: WantedSpec(SDL_AudioSpec *wanted)
{
wanted->freq = frequencies[version][frequency];
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
wanted->format = AUDIO_S16LSB;
#else
wanted->format = AUDIO_S16MSB;
#endif
if ( outputstereo ) {
wanted->channels = 2;
} else {
wanted->channels = 1;
}
wanted->samples = 4096;
wanted->callback = Play_MPEGaudio;
wanted->userdata = this;
return true;
}
void
MPEGaudio:: ActualSpec(const SDL_AudioSpec *actual)
{
/* Splay can optimize some of the conversion */
if ( actual->channels == 1 && outputstereo ) {
forcetomonoflag = true;
}
if ( actual->channels == 2 && !outputstereo ) {
forcetostereoflag = true;
samplesperframe *= 2;
}
/* FIXME: Create an audio conversion block */
if ( (actual->freq/100) == ((frequencies[version][frequency]/2)/100) ) {
downfrequency = 1;
} else if ( actual->freq != frequencies[version][frequency] ) {
#ifdef VERBOSE_WARNINGS
fprintf(stderr, "Warning: wrong audio frequency (wanted %d, got %d)\n",
frequencies[version][frequency], actual->freq);
#else
;
#endif
}
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
if ( actual->format != AUDIO_S16LSB)
#else
if ( actual->format != AUDIO_S16MSB)
#endif
{
fprintf(stderr, "Warning: incorrect audio format\n");
}
rate_in_s=((double)((actual->format&0xFF)/8)*actual->channels*actual->freq);
stereo=((actual->channels-1) > 0);
}
#ifdef THREADED_AUDIO
void
MPEGaudio:: StartDecoding(void)
{
decoding = true;
/* Create the ring buffer to hold audio */
if ( ! ring ) {
ring = new MPEG_ring(samplesperframe*2);
}
if ( ! decode_thread ) {
decode_thread = SDL_CreateThread(Decode_MPEGaudio, this);
}
}
void
MPEGaudio:: StopDecoding(void)
{
decoding = false;
if ( decode_thread ) {
if( ring ) ring->ReleaseThreads();
SDL_WaitThread(decode_thread, NULL);
decode_thread = NULL;
}
if ( ring ) {
delete ring;
ring = NULL;
}
}
#endif
/* MPEG actions */
double
MPEGaudio:: Time(void)
{
double now;
if ( frag_time ) {
now = (play_time + (double)(SDL_GetTicks() - frag_time)/1000.0);
} else {
now = play_time;
}
return now;
}
void
MPEGaudio:: Play(void)
{
ResetPause();
if ( valid_stream ) {
#ifdef THREADED_AUDIO
StartDecoding();
#endif
playing = true;
}
}
void
MPEGaudio:: Stop(void)
{
if ( valid_stream ) {
SDL_LockAudio();
playing = false;
SDL_UnlockAudio();
}
ResetPause();
}
void
MPEGaudio:: Rewind(void)
{
Stop();
#ifdef THREADED_AUDIO
/* Stop the decode thread */
StopDecoding();
#endif
clearrawdata();
decodedframe = 0;
currentframe = 0;
frags_playing = 0;
}
void
MPEGaudio:: ResetSynchro(double time)
{
play_time = time;
frag_time = 0;
/* Reinit the timestamp FIFO */
for (int i=0; i<N_TIMESTAMPS; i++)
timestamp[i] = -1;
}
void
MPEGaudio:: Skip(float seconds)
{
/* Called only when there is no timestamp info in the MPEG */
printf("Audio: Skipping %f seconds...\n", seconds);
while(seconds > 0)
{
seconds -= (float) samplesperframe / ((float) frequencies[version][frequency]*(1+inputstereo));
if(!loadheader()) break;
}
}
void
MPEGaudio:: Volume(int vol)
{
if ( (vol >= 0) && (vol <= 100) ) {
volume = (vol*SDL_MIX_MAXVOLUME)/100;
}
}
MPEGstatus
MPEGaudio:: Status(void)
{
if ( valid_stream ) {
/* Has decoding stopped because of end of stream? */
if ( mpeg->eof() && (decodedframe <= currentframe) ) {
return(MPEG_STOPPED);
}
/* Have we been told to play? */
if ( playing ) {
return(MPEG_PLAYING);
} else {
return(MPEG_STOPPED);
}
} else {
return(MPEG_ERROR);
}
}
bool
MPEGaudio:: GetAudioInfo(MPEG_AudioInfo *info)
{
if ( info ) {
info->mpegversion = version;
info->mode = mode;
info->frequency = frequencies[version][frequency];
info->layer = layer;
info->bitrate = bitrate[version][layer-1][bitrateindex];
info->current_frame = currentframe;
}
return true;
}
bool
MPEGaudio:: fillbuffer(int size)
{
bitindex=0;
_buffer_pos = mpeg->pos;
return(mpeg->copy_data(_buffer, size) > 0);
};
#endif
void
MPEGaudio:: sync(void)
{
bitindex=(bitindex+7)&0xFFFFFFF8;
}
bool
MPEGaudio:: issync(void)
{
return (bitindex&7) != 0;
}
int
MPEGaudio::getbyte(void)
{
int r=(unsigned char)_buffer[bitindex>>3];
bitindex+=8;
return r;
}
int
MPEGaudio::getbit(void)
{
register int r=(_buffer[bitindex>>3]>>(7-(bitindex&7)))&1;
bitindex++;
return r;
}
int
MPEGaudio::getbits8(void)
{
register unsigned short a;
{ int offset=bitindex>>3;
a=(((unsigned char)_buffer[offset])<<8) | ((unsigned char)_buffer[offset+1]);
}
a<<=(bitindex&7);
bitindex+=8;
return (int)((unsigned int)(a>>8));
}
int
MPEGaudio::getbits9(int bits)
{
register unsigned short a;
{ int offset=bitindex>>3;
a=(((unsigned char)_buffer[offset])<<8) | ((unsigned char)_buffer[offset+1]);
}
a<<=(bitindex&7);
bitindex+=bits;
return (int)((unsigned int)(a>>(16-bits)));
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -