📄 mpeg_audio.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 "iptv.h"#define USES_BASECLASS#include "video.h"#include "wxgui/StreamInfo.h"#include "mad.h"//#define DEBUG#include "log.h"#define MODULE "mpeg_audio"#define SOUNDBUFFER 16384static inline int scale(mad_fixed_t sample){ // Round sample += (1L << (MAD_F_FRACBITS - 16)); // Clip if(sample >= MAD_F_ONE) sample = MAD_F_ONE - 1; else if(sample < -MAD_F_ONE) sample = -MAD_F_ONE; // Quantize return sample >> (MAD_F_FRACBITS + 1 - 16);}int mpeg_audio::Run(){ mad_synth synth; mad_stream stream; mad_frame frame; mad_timer_t timer; unsigned int frequency = 0; Audioinfo * audio = (Audioinfo*)filterinfo; unsigned char * soundbuf = (unsigned char*)_aligned_malloc((sizeof(char)*SOUNDBUFFER)+8, 64); unsigned int soundoff = 0;#if (C_HAVE_WXGUI) Uint32 frameStartTicks;#endif if(soundbuf == NULL) { ERROR_MSG("Error allocating memory!"); return 0; } mad_synth_init (&synth); mad_stream_init(&stream); mad_frame_init (&frame); ERROR_MSG("(ThreadID: %u) init complete", SDL_ThreadID()); LOG_MSG("Buffer address 0x%x", buffer); while(ThreadRun()) { unsigned int m_size; unsigned int offset, audiopts; m_size = fifo->GetPacket(&offset, &audiopts); if((m_size == 0) || (m_size > buffersize)) { LOG_MSG("Error invalid packet size: %d", m_size); SDL_Delay(10); continue; } LockBuffer(); roffset = offset; if(!SDL_SemValue(data)) SDL_SemPost(data); UnlockBuffer(); if(m_size > SOUNDBUFFER-soundoff) { ERROR_MSG("PES size %d too large (%d), contact the author!", m_size, SOUNDBUFFER-soundoff); SDL_Delay(10); continue; } // Copy into temporary decoding buffer SDL_memcpy(soundbuf+soundoff, buffer+offset, m_size); DEBUG_MSG("%d bytes added to the buffer, %d total", m_size, soundoff+m_size); // MAD will only decode up to frame boundry // (leave a part of next frame in the buffer) mad_stream_buffer(&stream, soundbuf, soundoff+m_size+8); if(audiopts) mad_timer_set(&timer, audiopts/1000, audiopts%1000, 1000); while(true) { if(stream.next_frame > soundbuf+soundoff+m_size-1) { soundoff = 0; break; } LOG_MSG("Decode frame at: 0x%x (%d bytes left)", stream.next_frame, soundbuf+soundoff+m_size-stream.next_frame); if(mad_frame_decode(&frame, &stream) == -1) { if(stream.error == MAD_ERROR_BUFLEN) { LOG_MSG("ERROR: End of buffer, frame 0x%x!", stream.next_frame); // Copy remaning data SDL_memcpy(soundbuf, stream.next_frame, soundbuf+soundoff+m_size-stream.next_frame); soundoff = soundbuf+soundoff+m_size-stream.next_frame; break; } if(!MAD_RECOVERABLE(stream.error)) { ERROR_MSG("Critical error while decoding frame!"); return -1; } ERROR_MSG("Error while decoding frame: 0x%x!", stream.error); // Really needed? //mad_timer_add(&timer, frame.header.duration); continue; } mad_synth_frame(&synth, &frame); // Decoded channels const mad_fixed_t *left_ch = synth.pcm.samples[0]; const mad_fixed_t *right_ch = synth.pcm.samples[1]; unsigned int decoded = synth.pcm.length;#if (C_HAVE_WXGUI) Uint32 frameTimeTaken = SDL_GetTicks() - frameStartTicks; // Update ~twice per second if(frameTimeTaken > 500) { if(gui.wxStreamInfo != NULL) gui.wxStreamInfo->UpdateAudioStream(frame.header.samplerate, frame.header.bitrate); frameStartTicks = SDL_GetTicks(); }#endif if((frequency != synth.pcm.samplerate) || (audio->stereo != (synth.pcm.channels-1))) { SDL_Event event; event.type = SDL_USEREVENT+2; event.user.data1 = (void*)((intptr_t)synth.pcm.samplerate); event.user.data2 = (void*)((intptr_t)synth.pcm.channels); audio->stereo = (synth.pcm.channels - 1); if(!audio->stereo) audio->mode = 0; SDL_PushEvent(&event);#ifdef SEM_SILENT SDL_SemWait(audio->audio_change);#else while(SDL_SemWaitTimeout(audio->audio_change, 1000) == SDL_MUTEX_TIMEDOUT) { ERROR_MSG("Semaphore timeout expired, line: %d, thread: %u", __LINE__, SDL_ThreadID()); }#endif frequency = synth.pcm.samplerate; } SDL_LockAudio(); DEBUG_MSG("Audio PTS: %d, timer: %.3fs", audiopts, (float)mad_timer_count(timer, MAD_UNITS_MILLISECONDS)/1000.0f); LOG_MSG("Decoded %d samples of data (%d), samplerate: %d, buffer offset %d", decoded, frame.header.bitrate, synth.pcm.samplerate, audio->w_pos); // Samples output float * output = audio->data + audio->w_pos; unsigned int i = (BUFFERSIZE>>2) - audio->w_pos; unsigned int m_samples = 0;write_buffer: if(audio->w_pos == 0) { audiopts = mad_timer_count(timer, MAD_UNITS_MILLISECONDS); audiopts += (1000*m_samples)/synth.pcm.samplerate; audio->ptsstart = audiopts; } i = (i > decoded<<1 ? decoded : i>>1); decoded -= i; m_samples += i; audio->w_pos += i<<1; if((audio->mode == 0) && (synth.pcm.channels - 1)) { DEBUG_MSG("Writing %d samples (stereo), samples left %d", i, decoded); while(i) { *output++ = scale(*left_ch++) / (1.0 * 0x8000); *output++ = scale(*right_ch++) / (1.0 * 0x8000); i--; } } else { if((audio->mode == 2) && (synth.pcm.channels - 1)) left_ch = right_ch; DEBUG_MSG("Writing %d samples (mono), samples left %d", i, decoded); while(i) { float tmp = scale(*left_ch++) / (1.0 * 0x8000); *output++ = tmp; *output++ = tmp; i--; } } // If samples are still in the buffer... if(decoded) { DEBUG_MSG("Audio buffer wrap"); i = BUFFERSIZE>>2; audio->size = audio->w_pos; audio->w_pos = 0; output = audio->data; goto write_buffer; } if(audio->size < audio->w_pos) audio->size = audio->w_pos; DEBUG_MSG("Buffer written to pos: %d", audio->w_pos); SDL_UnlockAudio(); mad_timer_add(&timer, frame.header.duration); } LOG_MSG("Sound offset set to %d", soundoff); } _aligned_free(soundbuf); mad_frame_finish (&frame); mad_stream_finish(&stream); ERROR_MSG("(ThreadID: %u) finish complete", SDL_ThreadID()); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -