/******************************************************** Audio renderer object for file output Copyright 2001 Alexander Oelzant (aoe@mars.tuwien.ac.at) derived from lib/aviplay/audio.cpp Copyright 2000 Eugene Kuznetsov (divx@euro.ru) *********************************************************/ #undef DEBUG_TOCONSOLE #define QUIET #ifndef QUIET #define debug_out(X) Debug cout< #include #include #include #include #include #include //#include "aviplay_impl.h" #include "audio.h" #include #include #define __MODULE__ "File_AudioRenderer" using namespace std; //template inline T min(const T x, const T y){if(x inline T max(const T x, const T y){if(x>y)return x;else return y;} /********************************************** Audio queue implementation **********************************************/ audio_queue::audio_queue() { pthread_mutex_init(&mutex, NULL); pthread_cond_init(&cond, NULL); frame_in=frame_out=frame_size=0; } audio_queue::~audio_queue() { pthread_cond_destroy(&cond); pthread_mutex_destroy(&mutex); } int audio_queue::push(const char* data, int size) { pthread_mutex_lock(&mutex); { int new_pos = frame_in+size; if(frame_in+size>sizeof(audio_frame))size=sizeof(audio_frame)-frame_in; memcpy(audio_frame+frame_in, data, size); while(new_pos > frame_max) { memcpy(audio_frame, audio_frame + frame_max, new_pos - frame_max); new_pos = new_pos - frame_max; } frame_in = new_pos; frame_size += size; } pthread_mutex_unlock(&mutex); broadcast(); return 0; } int audio_queue::read(char* data, int size, int volume) { pthread_mutex_lock(&mutex); { while(size>0) { if(frame_out==frame_max)frame_out=0; int step=min(size, frame_max-frame_out); #ifdef USE_SDL SDL_MixAudio((unsigned char*)data, (unsigned char*)(audio_frame+frame_out), step, volume); #else memcpy(data, audio_frame+frame_out, step); #endif data+=step; frame_out+=step; frame_size-=step; size-=step; } if(frame_size<0) frame_size=0; } pthread_mutex_unlock(&mutex); broadcast(); return 0; } int audio_queue::unread(int size) { frame_out-=size; while(frame_out<0)frame_out+=frame_max; frame_size=(frame_out<=frame_in)?(frame_in-frame_out):(frame_max+frame_in-frame_out); return 0; } int audio_queue::write(int fd)//writes some data { int startpos, size, tmp; #ifdef __FreeBSD__ const int AUDIO_BUFFER_SIZE=2048; #else const int AUDIO_BUFFER_SIZE=8192; #endif pthread_mutex_lock(&mutex); { size = AUDIO_BUFFER_SIZE; if((frame_in > frame_out) && (frame_in - frame_out < AUDIO_BUFFER_SIZE)) size = frame_in - frame_out; if((frame_in < frame_out) && (frame_max - frame_out < AUDIO_BUFFER_SIZE)) size = frame_max - frame_out; tmp=frame_in-frame_out; while(tmp<0)tmp+=frame_max; if(tmp!=frame_size) { printf("OOPS: frame_size!=tmp(%d,%d,%d)\n", frame_out, frame_in, frame_size); } startpos=frame_out; if(frame_out == frame_max) frame_out = 0; } pthread_mutex_unlock(&mutex); int answer=::write(fd, audio_frame+startpos, size); if(answer==0)return 0;//sound card doesn't accept any more data ( e.g. DMA buffer is full ) pthread_mutex_lock(&mutex); { if(frame_size==0) //someone has cleared buffers while we were writing //forget what we wrote, user should reset device { pthread_mutex_unlock(&mutex); return -1; } frame_out += answer; if(frame_sizeEof(); } void IAudioRenderer::setAsync(float async) { m_async=async; } void IAudioRenderer::setVolume(float volume) { if(volume<0)return; if(volume>1)return; #ifdef USE_SDL m_pVolume=(int)(SDL_MIX_MAXVOLUME*volume); #endif } void IAudioRenderer::Pause(int) { } void IAudioRenderer::Reset() { } double IAudioRenderer::getTime() { pthread_mutex_lock(&mutex); if(time_start==0) { audio_time=longcount(); time_start=longcount(); audio_realpos=audiostream->GetTime()-double(queue.size())/owf.nChannels/(owf.wBitsPerSample/8)/owf.nSamplesPerSec; // audio_realpos=audiostream->GetTime()-double(m_spec.size+queue.size())/owf.nChannels/(owf.wBitsPerSample/8)/owf.nSamplesPerSec; // cout<<"Cleared audio_time"<audiostream->GetTime())actual_time=audiostream->GetTime(); // cout<SeekToTime(0); queue.clear(); Pause(0); time_start=0; hangup=0; initialized=1; pthread_mutex_unlock(&mutex); } void IAudioRenderer::doAudioSkip(double video_time) { audiostream->SeekToTime(video_time); } void IAudioRenderer::doAudioExtract(double video_time) { int t1, t2; int frames_written=0; const int one_frame_sound=max(20000, audiostream->GetFrameSize()); const int sound_size_max=176400; if(quit) return; if(queue.size()>sound_size_max) return; if(audiostream->Eof()) { cout<<"Audio stream finished"<ReadFrames(local_frame, one_frame_sound, one_frame_sound, samples, ocnt); Debug cout<<"doAudioExtract: Read "<SeekToTime(pos); if(initialized==0) { pthread_mutex_unlock(&mutex); return; } hangup=1; wake(); while(hangup)usleep(10000); queue.clear(); char fake[16]; memset(fake, 0, 16); queue.push(fake, 16); Reset(); time_start=0; initialized=1; pthread_mutex_unlock(&mutex); } double IAudioRenderer::getLength() { if(!audiostream)return 0; return audiostream->GetEndTime(); } /********************************************************* Implementation of file output renderer class *********************************************************/ File_AudioRenderer::File_AudioRenderer(IAviReadStream* as, int audio_fd_new) { try { audiostream=as; if(audiostream==0) throw FATAL("NULL audiostream"); int audio_status=audiostream->StartStreaming(); if(audio_status!=0) throw FATAL("Failed to start streaming"); int tmp; audiostream->GetOutputFormat(&owf, sizeof owf); sprintf(audio_desc, " %dkbit/s %dHz %s", (int)owf.nAvgBytesPerSec/128, (int)owf.nSamplesPerSec, owf.nChannels!=1?"stereo":"mono"); #ifndef QUIET cout << "Audio format " << owf.nSamplesPerSec << "/" << owf.wBitsPerSample << "/" << ((owf.nChannels!=1)?"stereo":"mono") << endl; #endif audio_fd=audio_fd_new; try { // audio_fd=open("/dev/dsp",O_RDWR|O_NDELAY); if(audio_fd<=0) throw FATAL("Output file not open"); // if(audio_fd>0) // { // int flag; // if((flag=fcntl(audio_fd,F_GETFL,0))<0) // throw FATAL("fcntl"); // flag&=~O_NDELAY; // if(fcntl(audio_fd,F_SETFL,flag)<0) // throw FATAL("fcntl"); // } } catch(FatalError&) { if(audio_fd>0)::close(audio_fd); fprintf(stderr,"fatal error ocurred, exiting\n"); exit(1); } // if(audio_fd<=0) // throw FATAL("Can't open audio device"); /* ioctl(audio_fd, SNDCTL_DSP_RESET, NULL); audio_buf_info zz; ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &zz); Snd_Limit=zz.bytes; cout<<"Snd_Limit "<0) ::close(audio_fd); audio_fd=-1; audiostream=0; throw; } initialized=0; hangup=0; paused=0; audio_realpos=0; audio_time=longcount(); time_start=0; quit=0; audiostream->SeekToTime(0); pthread_create(&audio_thread, NULL, doAudioOut, (void*)this); return; } void File_AudioRenderer::Reset() { // if(audio_fd) // ioctl(audio_fd, SNDCTL_DSP_RESET, NULL); } File_AudioRenderer::~File_AudioRenderer() { cout<<"Destroying audio renderer"<"<GetTime()<<" "< "<GetTime()-a.buffer_time() <<" "<GetTime()-frame_time; // cout<GetTime()<<" "< "<