⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sdl_audio.cpp

📁 linux下实现视频播放的播放器
💻 CPP
字号:
/* *  Copyright (C) 2005-2007  gulikoza * *  This program 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. * *  This program 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 this program; if not, write to the Free Software *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *//* $Id$ */#include "main.h"#include "video.h"#include "timer.h"#include <math.h>#include "samplerate.h"//#define DEBUG#include "log.h"#define MODULE "sdl_audio"#define SAMPLES 2048void audio_callback(void *userdata, Uint8 *stream, int len);void init_audio(void){    /* Allocate decoding buffer */    sdl.audio = (Audioinfo*)malloc(sizeof(Audioinfo));    SDL_memset(sdl.audio, 0, sizeof(Audioinfo));    // Should hold about 2.5 sec    sdl.audio->data = (float*)_aligned_malloc(sizeof(char)*BUFFERSIZE, 64);    sdl.audio->data_out = (float*)_aligned_malloc(sizeof(float)*2*SAMPLES, 64);    sdl.audio->audio_change = SDL_CreateSemaphore(0);    sdl.audio->volume = 1.0f;    sdl.audio->prevVolume = 1.0f;    sdl.audio->src_state = src_new(SRC_LINEAR, 2, NULL);    sdl_bar.SetVolume(lrintf(sdl.audio->volume*100), 0);}void reinit_audio(unsigned int freq){    if(!sdl.audio)	return;    if(sdl.audio->spec == NULL) {	/* Open the audio device */	SDL_AudioSpec desired;	/* Allocate space for the obtained SDL_AudioSpec */	sdl.audio->spec = (SDL_AudioSpec*)malloc(sizeof(SDL_AudioSpec));	/* Sampling frequency */	desired.freq = freq;	/* 16-bit signed audio */	desired.format = AUDIO_S16SYS;	/* Stereo */	desired.channels = 2;	/* Large audio buffer reduces risk of dropouts but increases response time */	desired.samples = SAMPLES;	/* Our callback function */	desired.callback = audio_callback;	desired.userdata = NULL;	/* Open the audio device */	if(SDL_OpenAudio(&desired, sdl.audio->spec) < 0) {	    ERROR_MSG("Couldn't open audio: %s", SDL_GetError());	    SDL_SemPost(sdl.audio->audio_change);	    return;	}	ERROR_MSG("Opened audio device at %d Hz, %s", sdl.audio->spec->freq,	    sdl.audio->spec->channels == 2 ? "stereo":"mono");    }    SDL_LockAudio();    sdl.audio->pts = 0.0;    sdl.audio->w_pos = sdl.audio->r_pos = 0;    sdl.audio->ptsstart = 0;    sdl.audio->size = 0;    sdl.audio->ratio = ((double)sdl.audio->spec->freq)/freq;    src_reset(sdl.audio->src_state);    LOG_MSG("Resample ratio set to %lf (source freq: %d)", sdl.audio->ratio, freq);    SDL_UnlockAudio();    SDL_PauseAudio(0);    SDL_SemPost(sdl.audio->audio_change);}void close_audio(const bool clear){    if(sdl.audio) {	if(sdl.audio->spec) {	    SDL_CloseAudio();	    free(sdl.audio->spec);	    sdl.audio->spec = NULL;	}	if(clear) {	    src_delete(sdl.audio->src_state);	    _aligned_free(sdl.audio->data);	    _aligned_free(sdl.audio->data_out);	    SDL_DestroySemaphore(sdl.audio->audio_change);	    free(sdl.audio);	    sdl.audio = NULL;	}    }}void audio_callback(void *userdata, Uint8 *stream, int len){    int freq = sdl.audio->spec->freq;    unsigned int buf_pts = (unsigned int)lrint(sdl.audio->pts);    if(sdl.audio->r_pos == 0) {	if(sdl.audio->ptsstart == 0) {	    for(buf_pts = 0; buf_pts < (unsigned int)len; buf_pts++)		*stream++ = 0x0;	    LOG_MSG("No audio PTS, nothing to play");	    return;	}	LOG_MSG("Setting audio PTS to %u", sdl.audio->ptsstart);	// Calibrate PTS each buffer start	if(sdl.audio->ptsstart >= buf_pts) {	    sdl.audio->pts = (double)sdl.audio->ptsstart;	    buf_pts = sdl.audio->ptsstart;	} else {	    ERROR_MSG("%u is smaller than %.2f, missing timestamp?", sdl.audio->ptsstart, sdl.audio->pts);	}    }    // Get audio delay (in samples)    int delay = sdl.audio->delay;    unsigned int pts = timer->GetPTS();    if(delay > 0) {	LOG_MSG("Audio buffer delay is %d samples, %d ms", delay, delay*1000/freq);	delay = delay*1000/freq;    } else {#if (SDL_IS_PATCHED)	sdl.audio->delay = SDL_AudioDelay();	LOG_MSG("Failed to get buffer delay");#endif	delay = 0;    }    LOG_MSG("Requested %d bytes (%d ms, %d samples), current PTS: %u, should play at PTS %u",	len, len*1000/(freq<<2), (len>>1), pts, pts+delay);    pts += delay;    delay = 0;    // Mix as much data as possible    double ratio = sdl.audio->ratio;    // Current audio pts is sdl.audio->pts    if(pts+5 < buf_pts) {	// Audio buffer position is more than 1/2 call ahead	if(buf_pts-pts > (unsigned int)(len*1000)/(freq<<3)) {	    LOG_MSG("Playback is %u ms ahead (buffer PTS: %.2f), dropping entire frame", buf_pts-pts, sdl.audio->pts);	    for(buf_pts = 0; buf_pts < (unsigned int)len; buf_pts++)		*stream++ = 0x0;	    return;	}	// Mix fewer samples, increase samplerate	delay  = (buf_pts-pts);	delay *= (-freq)/(32*1000);	LOG_MSG("Playback is %u ms ahead, mixing %d samples less", buf_pts-pts, -delay);    } else if(pts > buf_pts+5) {	// Audio buffer position is behind	// Try to mix additional samples, lower samplerate	delay = ((pts-buf_pts)*freq)/(32*1000);	LOG_MSG("Playback is %u ms behind, mixing %d more samples", pts-buf_pts, delay);    }    LOG_MSG("Audio buffer PTS: %.2f, %d ms jitter", sdl.audio->pts, (int)buf_pts - (int)pts);    // Calculate samplerate ratio    if(delay != 0)	ratio = ratio * ((double)(len>>2)/((len>>2)+delay));    LOG_MSG("Frequency resample ratio: %lf, frames needed: %d", ratio, len>>2);    SRC_DATA src_data;    src_data.end_of_input = 0;    src_data.src_ratio = ratio;    // input_frames = floats for each channel    src_data.input_frames = (sdl.audio->size-sdl.audio->r_pos)>>1;    src_data.data_in = sdl.audio->data+sdl.audio->r_pos;    src_data.output_frames = len>>2;    src_data.data_out = sdl.audio->data_out;    src_data.input_frames_used = 0;    delay = 0;write_audio:    if((buf_pts=src_process(sdl.audio->src_state, &src_data))) {	ERROR_MSG("Error SRC returned %s", src_strerror(buf_pts));	return;    }    delay += src_data.output_frames_gen;    src_data.input_frames -= src_data.input_frames_used;    sdl.audio->r_pos += src_data.input_frames_used<<1;    src_data.output_frames -= src_data.output_frames_gen;    LOG_MSG("%d frames used, %d frames generated (%d available)", src_data.input_frames_used,			src_data.output_frames_gen, src_data.input_frames);    // Advance PTS    sdl.audio->pts += (double)(src_data.output_frames_gen*1000.0)/(freq*ratio);    LOG_MSG("Audio played, PTS advance: %.2f, new PTS: %.2f",	    (double)(src_data.output_frames_gen*1000.0)/(freq*ratio), sdl.audio->pts);    if(src_data.output_frames) {	LOG_MSG("%d samples missing", src_data.output_frames);	if(src_data.input_frames == 0) {	    if(sdl.audio->w_pos < sdl.audio->size) {		sdl.audio->r_pos = 0;		sdl.audio->size = sdl.audio->w_pos;		src_data.data_in = sdl.audio->data;		src_data.input_frames = sdl.audio->size>>1;		src_data.data_out += src_data.output_frames_gen<<1;		LOG_MSG("Syncing buffer pts %.2f to %u (%.2f)", sdl.audio->pts,				sdl.audio->ptsstart, sdl.audio->ptsstart-sdl.audio->pts);		sdl.audio->pts = sdl.audio->ptsstart;	    }	    if(src_data.input_frames != 0)		goto write_audio;	    ERROR_MSG("Audio buffer underrun!");	}    }    // Adjust volume, convert to short and write to output buffer    ratio = (8.0 * 0x10000000) * sdl.audio->volume;    signed short * oup = (signed short*)stream;    float * inp = sdl.audio->data_out;    // Data is stereo    delay = delay<<1;    while(delay--) {	float scaled_value = (*inp++) * ratio;	if(scaled_value > (1.0 * 0x7FFFFFFE)) {	    *oup++ = 32767;	    continue;	}	if(scaled_value < (-8.0 * 0xFFFFFFF)) {	    *oup++ = -32768;	    continue;	}	*oup++ = (lrintf(scaled_value) >> 16);    }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -