diff options
Diffstat (limited to 'drivers/theora')
-rw-r--r-- | drivers/theora/SCsub | 35 | ||||
-rw-r--r-- | drivers/theora/decode.c | 46 | ||||
-rw-r--r-- | drivers/theora/encint.h | 1 | ||||
-rw-r--r-- | drivers/theora/video_stream_theora.cpp | 202 | ||||
-rw-r--r-- | drivers/theora/video_stream_theora.h | 34 |
5 files changed, 267 insertions, 51 deletions
diff --git a/drivers/theora/SCsub b/drivers/theora/SCsub index ecabce6c9d..fa85b49804 100644 --- a/drivers/theora/SCsub +++ b/drivers/theora/SCsub @@ -1,4 +1,3 @@ - Import('env') sources = [ @@ -32,7 +31,37 @@ sources = [ "theora/video_stream_theora.cpp", ] -if env['use_theoraplayer_binary'] != "yes": - env.drivers_sources += sources +sources_x86 = [ + "theora/x86/mmxencfrag.c", + "theora/x86/mmxfdct.c", + "theora/x86/mmxfrag.c", + "theora/x86/mmxidct.c", + "theora/x86/mmxstate.c", + "theora/x86/sse2fdct.c", + "theora/x86/x86enc.c", + "theora/x86/x86state.c", +] + +sources_x86_vc = [ + "theora/x86_vc/mmxencfrag.c", + "theora/x86_vc/mmxfdct.c", + "theora/x86_vc/mmxfrag.c", + "theora/x86_vc/mmxidct.c", + "theora/x86_vc/mmxstate.c", + "theora/x86_vc/x86enc.c", + "theora/x86_vc/x86state.c", +] + +env.drivers_sources += sources + +if (env["x86_opt_gcc"]): + env.Append(CCFLAGS=["-DOC_X86_ASM"]) + env.drivers_sources += sources_x86 + +if (env["x86_opt_vc"]): + env.Append(CCFLAGS=["-DOC_X86_ASM"]) + env.drivers_sources += sources_x86_vc + + diff --git a/drivers/theora/decode.c b/drivers/theora/decode.c index 7be66463d8..882606ae77 100644 --- a/drivers/theora/decode.c +++ b/drivers/theora/decode.c @@ -1611,28 +1611,35 @@ static void oc_filter_hedge(unsigned char *_dst,int _dst_ystride, int sum1; int bx; int by; + int _rlimit1; + int _rlimit2; rdst=_dst; rsrc=_src; - for(bx=0;bx<8;bx++){ + for(bx=0;bx<8;++bx){ cdst=rdst; csrc=rsrc; - for(by=0;by<10;by++){ + _rlimit1 = _rlimit2 = _flimit; + for(by=0;by<10;++by){ r[by]=*csrc; csrc+=_src_ystride; } sum0=sum1=0; - for(by=0;by<4;by++){ - sum0+=abs(r[by+1]-r[by]); - sum1+=abs(r[by+5]-r[by+6]); + for(by=0;by<4;++by){ + int sumed = abs(r[by+1]-r[by]); + sum0+=sumed; + _rlimit1-=sumed; + sumed = abs(r[by+5]-r[by+6]); + sum1+=sumed; + _rlimit2-=sumed; } *_variance0+=OC_MINI(255,sum0); *_variance1+=OC_MINI(255,sum1); - if(sum0<_flimit&&sum1<_flimit&&r[5]-r[4]<_qstep&&r[4]-r[5]<_qstep){ + if(_rlimit1&&_rlimit2&&!(r[5]-r[4]-_qstep)&&!(r[4]-r[5]-_qstep)){ *cdst=(unsigned char)(r[0]*3+r[1]*2+r[2]+r[3]+r[4]+4>>3); cdst+=_dst_ystride; *cdst=(unsigned char)(r[0]*2+r[1]+r[2]*2+r[3]+r[4]+r[5]+4>>3); cdst+=_dst_ystride; - for(by=0;by<4;by++){ + for(by=0;by<4;++by){ *cdst=(unsigned char)(r[by]+r[by+1]+r[by+2]+r[by+3]*2+ r[by+4]+r[by+5]+r[by+6]+4>>3); cdst+=_dst_ystride; @@ -1642,13 +1649,13 @@ static void oc_filter_hedge(unsigned char *_dst,int _dst_ystride, *cdst=(unsigned char)(r[5]+r[6]+r[7]+r[8]*2+r[9]*3+4>>3); } else{ - for(by=1;by<=8;by++){ + for(by=1;by<=8;++by){ *cdst=(unsigned char)r[by]; cdst+=_dst_ystride; } } - rdst++; - rsrc++; + ++rdst; + ++rsrc; } } @@ -1663,19 +1670,26 @@ static void oc_filter_vedge(unsigned char *_dst,int _dst_ystride, int sum1; int bx; int by; + int _rlimit1; + int _rlimit2; cdst=_dst; - for(by=0;by<8;by++){ + for(by=0;by<8;++by){ rsrc=cdst-1; rdst=cdst; - for(bx=0;bx<10;bx++)r[bx]=*rsrc++; + for(bx=0;bx<10;++bx)r[bx]=*rsrc++; sum0=sum1=0; - for(bx=0;bx<4;bx++){ - sum0+=abs(r[bx+1]-r[bx]); - sum1+=abs(r[bx+5]-r[bx+6]); + _rlimit1 = _rlimit2 = _flimit; + for(bx=0;bx<4;++bx){ + int sumed = abs(r[bx+1]-r[bx]); + sum0+=sumed; + _rlimit1-=sumed; + sumed = abs(r[bx+5]-r[bx+6]); + sum1+=sumed; + _rlimit2-=sumed; } _variances[0]+=OC_MINI(255,sum0); _variances[1]+=OC_MINI(255,sum1); - if(sum0<_flimit&&sum1<_flimit&&r[5]-r[4]<_qstep&&r[4]-r[5]<_qstep){ + if(_rlimit1&&_rlimit2&&!(r[5]-r[4]-_qstep)&&!(r[4]-r[5]-_qstep)){ *rdst++=(unsigned char)(r[0]*3+r[1]*2+r[2]+r[3]+r[4]+4>>3); *rdst++=(unsigned char)(r[0]*2+r[1]+r[2]*2+r[3]+r[4]+r[5]+4>>3); for(bx=0;bx<4;bx++){ diff --git a/drivers/theora/encint.h b/drivers/theora/encint.h index 97897d5a04..82338256dc 100644 --- a/drivers/theora/encint.h +++ b/drivers/theora/encint.h @@ -14,6 +14,7 @@ last mod: $Id: encint.h 16503 2009-08-22 18:14:02Z giles $ ********************************************************************/ + #if !defined(_encint_H) # define _encint_H (1) # if defined(HAVE_CONFIG_H) diff --git a/drivers/theora/video_stream_theora.cpp b/drivers/theora/video_stream_theora.cpp index bea49e34b7..0659f007e5 100644 --- a/drivers/theora/video_stream_theora.cpp +++ b/drivers/theora/video_stream_theora.cpp @@ -7,11 +7,34 @@ int VideoStreamPlaybackTheora:: buffer_data() { - char *buffer=ogg_sync_buffer(&oy,4096); - int bytes=file->get_buffer((uint8_t*)buffer, 4096); - ogg_sync_wrote(&oy,bytes); - return(bytes); + char *buffer=ogg_sync_buffer(&oy,4096); + +#ifdef THEORA_USE_THREAD_STREAMING + + int read; + + do { + thread_sem->post(); + read = MIN(ring_buffer.data_left(),4096); + if (read) { + ring_buffer.read((uint8_t*)buffer,read); + ogg_sync_wrote(&oy,read); + } else { + OS::get_singleton()->delay_usec(100); + } + + } while(read==0); + + return read; + +#else + + int bytes=file->get_buffer((uint8_t*)buffer, 4096); + ogg_sync_wrote(&oy,bytes); + return(bytes); + +#endif } int VideoStreamPlaybackTheora::queue_page(ogg_page *page){ @@ -178,7 +201,7 @@ void VideoStreamPlaybackTheora::video_write(void){ void VideoStreamPlaybackTheora::clear() { - if (file_name == "") + if (!file) return; if(vorbis_p){ @@ -200,6 +223,14 @@ void VideoStreamPlaybackTheora::clear() { } ogg_sync_clear(&oy); +#ifdef THEORA_USE_THREAD_STREAMING + thread_exit=true; + thread_sem->post(); //just in case + Thread::wait_to_finish(thread); + memdelete(thread); + thread=NULL; + ring_buffer.clear(); +#endif //file_name = ""; theora_p = 0; @@ -208,11 +239,16 @@ void VideoStreamPlaybackTheora::clear() { frames_pending = 0; videobuf_time = 0; + if (file) { + memdelete(file); + } + file=NULL; playing = false; }; void VideoStreamPlaybackTheora::set_file(const String& p_file) { + ERR_FAIL_COND(playing); ogg_packet op; th_setup_info *ts = NULL; @@ -223,7 +259,17 @@ void VideoStreamPlaybackTheora::set_file(const String& p_file) { file = FileAccess::open(p_file, FileAccess::READ); ERR_FAIL_COND(!file); +#ifdef THEORA_USE_THREAD_STREAMING + thread_exit=false; + thread_eof=false; + //pre-fill buffer + int to_read = ring_buffer.space_left(); + int read = file->get_buffer(read_buffer.ptr(),to_read); + ring_buffer.write(read_buffer.ptr(),read); + thread=Thread::create(_streaming_thread,this); + +#endif ogg_sync_init(&oy); @@ -239,7 +285,9 @@ void VideoStreamPlaybackTheora::set_file(const String& p_file) { /* Only interested in Vorbis/Theora streams */ int stateflag = 0; - int audio_track_skip=audio_track; + int audio_track_skip=audio_track; + + while(!stateflag){ int ret=buffer_data(); if(ret==0)break; @@ -265,15 +313,21 @@ void VideoStreamPlaybackTheora::set_file(const String& p_file) { copymem(&to,&test,sizeof(test)); theora_p=1; }else if(!vorbis_p && vorbis_synthesis_headerin(&vi,&vc,&op)>=0){ + + /* it is vorbis */ - if (audio_track_skip) { - vorbis_info_clear(&vi); - vorbis_comment_clear(&vc); - audio_track_skip--; - } else { - copymem(&vo,&test,sizeof(test)); - vorbis_p=1; - } + if (audio_track_skip) { + vorbis_info_clear(&vi); + vorbis_comment_clear(&vc); + ogg_stream_clear(&test); + vorbis_info_init(&vi); + vorbis_comment_init(&vc); + + audio_track_skip--; + } else { + copymem(&vo,&test,sizeof(test)); + vorbis_p=1; + } }else{ /* whatever it is, we don't care about it */ ogg_stream_clear(&test); @@ -357,6 +411,7 @@ void VideoStreamPlaybackTheora::set_file(const String& p_file) { th_decode_ctl(td,TH_DECCTL_GET_PPLEVEL_MAX,&pp_level_max, sizeof(pp_level_max)); pp_level=pp_level_max; + pp_level=0; th_decode_ctl(td,TH_DECCTL_SET_PPLEVEL,&pp_level,sizeof(pp_level)); pp_inc=0; @@ -392,6 +447,7 @@ void VideoStreamPlaybackTheora::set_file(const String& p_file) { fprintf(stderr,"Ogg logical stream %lx is Vorbis %d channel %ld Hz audio.\n", vo.serialno,vi.channels,vi.rate); //_setup(vi.channels, vi.rate); + }else{ /* tear down the partial vorbis setup */ vorbis_info_clear(&vi); @@ -401,6 +457,9 @@ void VideoStreamPlaybackTheora::set_file(const String& p_file) { playing = false; buffering=true; time=0; + audio_frames_wrote=0; + + }; float VideoStreamPlaybackTheora::get_time() const { @@ -417,28 +476,40 @@ Ref<Texture> VideoStreamPlaybackTheora::get_texture() { void VideoStreamPlaybackTheora::update(float p_delta) { - if (!playing) { + if (!playing || paused) { //printf("not playing\n"); return; }; + + +#ifdef THEORA_USE_THREAD_STREAMING + thread_sem->post(); +#endif + //double ctime =AudioServer::get_singleton()->get_mix_time(); //print_line("play "+rtos(p_delta)); time+=p_delta; - if (videobuf_time>get_time()) + if (videobuf_time>get_time()) { return; //no new frames need to be produced + } bool frame_done=false; + bool audio_done=false; - while (!frame_done) { + while (!frame_done || !audio_done) { //a frame needs to be produced ogg_packet op; bool audio_pending = false; + bool no_vorbis=false; + bool no_theora=false; + + while (vorbis_p) { int ret; float **pcm; @@ -490,6 +561,17 @@ void VideoStreamPlaybackTheora::update(float p_delta) { audio_pending=true; + if (vd.granulepos>=0) { + // print_line("wrote: "+itos(audio_frames_wrote)+" gpos: "+itos(vd.granulepos)); + } + + //print_line("mix audio!"); + + audio_frames_wrote+=ret-to_read; + + //print_line("AGP: "+itos(vd.granulepos)+" added "+itos(ret-to_read)); + + } else { /* no pending audio; is there a pending packet to decode? */ @@ -499,10 +581,14 @@ void VideoStreamPlaybackTheora::update(float p_delta) { } } else { /* we need more data; break out to suck in another page */ //printf("need moar data\n"); + no_vorbis=true; break; }; } + + audio_done = videobuf_time < (audio_frames_wrote/float(vi.rate)); + if (buffer_full) break; } @@ -512,7 +598,7 @@ void VideoStreamPlaybackTheora::update(float p_delta) { if(ogg_stream_packetout(&to,&op)>0){ - if(pp_inc){ + if(false && pp_inc){ pp_level+=pp_inc; th_decode_ctl(td,TH_DECCTL_SET_PPLEVEL,&pp_level, sizeof(pp_level)); @@ -540,19 +626,26 @@ void VideoStreamPlaybackTheora::update(float p_delta) { keyframing. Soon enough libtheora will be able to deal with non-keyframe seeks. */ - if(videobuf_time>=get_time()) + if(videobuf_time>=get_time()) { frame_done=true; - else{ + } else{ /*If we are too slow, reduce the pp level.*/ pp_inc=pp_level>0?-1:0; } + } else { + } - } else + } else { + no_theora=true; break; + } } - - if (file && /*!videobuf_ready && */ file->eof_reached()) { +#ifdef THEORA_USE_THREAD_STREAMING + if (file && thread_eof && (no_vorbis || no_theora) && ring_buffer.data_left()==0) { +#else + if (file && /*!videobuf_ready && */ (no_vorbis || no_theora) && file->eof_reached()) { +#endif printf("video done, stopping\n"); stop(); return; @@ -567,7 +660,9 @@ void VideoStreamPlaybackTheora::update(float p_delta) { } } #else - if (!frame_done){ + + + if (!frame_done || !audio_done){ //what's the point of waiting for audio to grab a page? buffer_data(); @@ -596,6 +691,7 @@ void VideoStreamPlaybackTheora::update(float p_delta) { else if(tdiff<ti.fps_denominator*0.05/ti.fps_numerator){ pp_inc=pp_level>0?-1:0; } + } video_write(); @@ -607,15 +703,21 @@ void VideoStreamPlaybackTheora::play() { if (!playing) time=0; + else { + stop(); + } + playing = true; delay_compensation=Globals::get_singleton()->get("audio/video_delay_compensation_ms"); delay_compensation/=1000.0; + }; void VideoStreamPlaybackTheora::stop() { if (playing) { + clear(); set_file(file_name); //reset } @@ -630,12 +732,13 @@ bool VideoStreamPlaybackTheora::is_playing() const { void VideoStreamPlaybackTheora::set_paused(bool p_paused) { - playing = !p_paused; + paused=p_paused; + //pau = !p_paused; }; bool VideoStreamPlaybackTheora::is_paused(bool p_paused) const { - return playing; + return paused; }; void VideoStreamPlaybackTheora::set_loop(bool p_enable) { @@ -693,7 +796,33 @@ int VideoStreamPlaybackTheora::get_mix_rate() const{ return vi.rate; } +#ifdef THEORA_USE_THREAD_STREAMING + + +void VideoStreamPlaybackTheora::_streaming_thread(void *ud) { + + VideoStreamPlaybackTheora *vs=(VideoStreamPlaybackTheora*)ud; + while(!vs->thread_exit) { + + //just fill back the buffer + if (!vs->thread_eof) { + + int to_read = vs->ring_buffer.space_left(); + if (to_read) { + int read = vs->file->get_buffer(vs->read_buffer.ptr(),to_read); + vs->ring_buffer.write(vs->read_buffer.ptr(),read); + vs->thread_eof=vs->file->eof_reached(); + } + + + } + + vs->thread_sem->wait(); + } +} + +#endif VideoStreamPlaybackTheora::VideoStreamPlaybackTheora() { @@ -704,21 +833,40 @@ VideoStreamPlaybackTheora::VideoStreamPlaybackTheora() { playing = false; frames_pending = 0; videobuf_time = 0; + paused=false; buffering=false; texture = Ref<ImageTexture>( memnew(ImageTexture )); mix_callback=NULL; mix_udata=NULL; - audio_track=0; + audio_track=0; delay_compensation=0; + audio_frames_wrote=0; + +#ifdef THEORA_USE_THREAD_STREAMING + int rb_power = nearest_shift(RB_SIZE_KB*1024); + ring_buffer.resize(rb_power); + read_buffer.resize(RB_SIZE_KB*1024); + thread_sem=Semaphore::create(); + thread=NULL; + thread_exit=false; + thread_eof=false; + +#endif }; VideoStreamPlaybackTheora::~VideoStreamPlaybackTheora() { +#ifdef THEORA_USE_THREAD_STREAMING + + memdelete(thread_sem); +#endif clear(); if (file) memdelete(file); + + }; diff --git a/drivers/theora/video_stream_theora.h b/drivers/theora/video_stream_theora.h index 95c7fe88f6..3e144c0125 100644 --- a/drivers/theora/video_stream_theora.h +++ b/drivers/theora/video_stream_theora.h @@ -6,9 +6,13 @@ #include "theora/theoradec.h" #include "vorbis/codec.h" #include "os/file_access.h" - +#include "ring_buffer.h" #include "io/resource_loader.h" #include "scene/resources/video_stream.h" +#include "os/thread.h" +#include "os/semaphore.h" + +//#define THEORA_USE_THREAD_STREAMING class VideoStreamPlaybackTheora : public VideoStreamPlayback { @@ -32,6 +36,7 @@ class VideoStreamPlaybackTheora : public VideoStreamPlayback { void video_write(void); float get_time() const; + ogg_sync_state oy; ogg_page og; ogg_stream_state vo; @@ -64,8 +69,27 @@ class VideoStreamPlaybackTheora : public VideoStreamPlayback { AudioMixCallback mix_callback; void* mix_udata; + bool paused; + +#ifdef THEORA_USE_THREAD_STREAMING + + enum { + RB_SIZE_KB=1024 + }; + + RingBuffer<uint8_t> ring_buffer; + Vector<uint8_t> read_buffer; + bool thread_eof; + Semaphore *thread_sem; + Thread *thread; + volatile bool thread_exit; + + static void _streaming_thread(void *ud); + +#endif + - int audio_track; + int audio_track; protected: @@ -115,20 +139,20 @@ class VideoStreamTheora : public VideoStream { OBJ_TYPE(VideoStreamTheora,VideoStream); String file; - int audio_track; + int audio_track; public: Ref<VideoStreamPlayback> instance_playback() { Ref<VideoStreamPlaybackTheora> pb = memnew( VideoStreamPlaybackTheora ); - pb->set_audio_track(audio_track); + pb->set_audio_track(audio_track); pb->set_file(file); return pb; } void set_file(const String& p_file) { file=p_file; } - void set_audio_track(int p_track) { audio_track=p_track; } + void set_audio_track(int p_track) { audio_track=p_track; } VideoStreamTheora() { audio_track=0; } |