SDL(简单直控媒体层)

SDL(Simple DirectMedia Layer)是一套开放源代码的跨平台多媒体开发库,使用C语言写成。SDL提供了数种控制图像、声音、输出入的函数,让开发者只要用相同或是相似的代码就可以开发出跨多个平台(Linux、Windows、Mac OS X等)的应用软件。目前SDL多用于开发游戏、模拟器、媒体播放器等多媒体应用领域。用下面这张图可以很明确地说明SDL的用途。

SDL实际上并不限于视音频的播放,它将功能分成下列数个子系统(subsystem):

Video(图像):图像控制以及线程(thread)和事件管理(event)。

Audio(声音):声音控制

Joystick(摇杆):游戏摇杆控制

CD-ROM(光盘驱动器):光盘媒体控制

Window Management(视窗管理):与视窗程序设计集成

SDL结构体SDL_AudioSpec


typedef struct SDL_AudioSpec {
	int freq;		/**< DSP frequency -- samples per second */
	Uint16 format;		/**< Audio data format */
	Uint8  channels;	/**< Number of channels: 1 mono, 2 stereo */
	Uint8  silence;		/**< Audio buffer silence value (calculated) */
	Uint16 samples;		/**< Audio buffer size in samples (power of 2) */
	Uint16 padding;		/**< Necessary for some compile environments */
	Uint32 size;		/**< Audio buffer size in bytes (calculated) */
	/**
	 *  This function is called when the audio device needs more data.
	 *
	 *  @param[out] stream	A pointer to the audio data buffer
	 *  @param[in]  len	The length of the audio buffer in bytes.
	 *
	 *  Once the callback returns, the buffer will no longer be valid.
	 *  Stereo samples are stored in a LRLRLR ordering.
	 */
	void (SDLCALL *callback)(void *userdata, Uint8 *stream, int len);
	void  *userdata;
} SDL_AudioSpec;

 其中包含了关于音频各种参数:
freq:音频数据的采样率。常用的有48000,44100等。
format:音频数据的格式。举例几种格式:
AUDIO_U16SYS:Unsigned 16-bit samples
AUDIO_S16SYS:Signed 16-bit samples
AUDIO_S32SYS:32-bit integer samples
AUDIO_F32SYS:32-bit floating point samples
channels:声道数。例如单声道取值为1,立体声取值为2。
silence:设置静音的值。
samples:音频缓冲区中的采样个数,要求必须是2的n次方。
padding:考虑到兼容性的一个参数。
size:音频缓冲区的大小,以字节为单位。
callback:填充音频缓冲区的回调函数。
userdata:用户自定义的数据。
填充音频缓冲区的回调函数的作用。当音频设备需要更多数据的时候会调用该回调函数。回调函数的格式要求如下。
 

void audio_callback(void *userdata, Uint8 *stream, int len)

回调函数的参数含义如下所示。
userdata:SDL_AudioSpec结构中的用户自定义数据,比如传个AVCodecContext *进行音频解码获得audio frame,然后混音。
stream:该指针指向需要填充的音频缓冲区。
len:音频缓冲区的大小(以字节为单位)。
在回调函数中可以使用SDL_MixAudio()完成混音等工作。

以下为播放器中播放音频的接口
 

bool VideoPlayer::openSDL()
{
    if (aCodecCtx == NULL)
    {
        return false;
    }
	
    SDL_LockAudio();
    SDL_AudioSpec spec;//实际音频设备的参数,一般情况下设置为NULL即可
    SDL_AudioSpec wanted_spec;//期望的参数
    wanted_spec.freq = aCodecCtx->sample_rate;
    wanted_spec.format = AUDIO_S16SYS;
    wanted_spec.channels = aCodecCtx->channels;
    wanted_spec.silence = 0;
    wanted_spec.samples = 1024;//SDL_AUDIO_BUFFER_SIZE;
    wanted_spec.callback = audio_callback;
    wanted_spec.userdata = aCodecCtx;
    if(SDL_OpenAudio(&wanted_spec, &spec) < 0)
    {
        fprintf(stderr, "SDL_OpenAudio: %s\n", SDL_GetError());
        return false;
    }
    SDL_UnlockAudio();
    SDL_PauseAudio(0);//使用SDL_PauseAudio()可以播放音频数据

    return true;
}

bool VideoPlayer::closeSDL()
{
    clearQuene();
    SDL_LockAudio();
    SDL_CloseAudio();
    SDL_UnlockAudio();
}

void audio_callback(void *userdata, Uint8 *stream, int len)
{
    AVCodecContext *aCodecCtx = (AVCodecContext *)userdata;
    int len1, audio_size;
    static uint8_t audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];
    static unsigned int audio_buf_size = 0;
    static unsigned int audio_buf_index = 0;
    while(len > 0)
    {
        if(audio_buf_index >= audio_buf_size)
        {
            audio_size = audio_decode_frame(aCodecCtx, audio_buf, sizeof(audio_buf));
            if(audio_size < 0)
            {
                audio_buf_size = 1024;
                memset(audio_buf, 0, audio_buf_size);
            }
            else
            {
                audio_buf_size = audio_size;
            }
            audio_buf_index = 0;
        }
        len1 = audio_buf_size - audio_buf_index;
        if(len1 > len)
            len1 = len;
        SDL_MixAudio(stream, (uint8_t * )audio_buf + audio_buf_index, len1, volume);
        len -= len1;
        stream += len1;
        audio_buf_index += len1;
    }
}

参考:https://blog.csdn.net/leixiaohua1020/article/details/40544521

猜你喜欢

转载自blog.csdn.net/cindywry/article/details/107555231
SDL