From 8eebfc55196d58b8cf957d92dc5959675de4dc8b Mon Sep 17 00:00:00 2001 From: iovar Date: Sun, 10 Dec 2006 10:03:43 +0000 Subject: multiplexing of vorbis-theora streams corrected git-svn-id: https://recordmydesktop.svn.sourceforge.net/svnroot/recordmydesktop/trunk@228 f606c939-3180-4ac9-a4b8-4b8779d57d0a --- recordmydesktop/src/encode_image_buffer.c | 11 +-- recordmydesktop/src/encode_sound_buffer.c | 17 ++-- recordmydesktop/src/flush_to_ogg.c | 152 +++++++++++++++++++++++------- recordmydesktop/src/load_cache.c | 2 + recordmydesktop/src/opendev.c | 12 ++- 5 files changed, 136 insertions(+), 58 deletions(-) diff --git a/recordmydesktop/src/encode_image_buffer.c b/recordmydesktop/src/encode_image_buffer.c index 979916d..60d87c4 100644 --- a/recordmydesktop/src/encode_image_buffer.c +++ b/recordmydesktop/src/encode_image_buffer.c @@ -51,14 +51,8 @@ void *EncodeImageBuffer(ProgData *pdata){ encoder_busy=0; } //last packet - if(theora_encode_YUVin(&pdata->enc_data->m_th_st,&pdata->enc_data->yuv)){ - fprintf(stderr,"Encoder not ready!\n"); - } - - theora_encode_packetout(&pdata->enc_data->m_th_st,1,&pdata->enc_data->m_ogg_pckt1); - -// ogg_stream_packetin(&pdata->enc_data->m_ogg_ts,&pdata->enc_data->m_ogg_pckt); +// SyncEncodeImageBuffer(pdata); pthread_exit(&errno); } @@ -70,11 +64,12 @@ void SyncEncodeImageBuffer(ProgData *pdata){ fprintf(stderr,"Encoder not ready!\n"); } else{ - if(theora_encode_packetout(&pdata->enc_data->m_th_st,0, + if(theora_encode_packetout(&pdata->enc_data->m_th_st,!pdata->running, &pdata->enc_data->m_ogg_pckt1)==1){ pthread_mutex_lock(&pdata->libogg_mutex); ogg_stream_packetin(&pdata->enc_data->m_ogg_ts, &pdata->enc_data->m_ogg_pckt1); + if(!pdata->running)pdata->enc_data->m_ogg_ts.e_o_s=1; pthread_mutex_unlock(&pdata->libogg_mutex); pdata->avd+=pdata->frametime; } diff --git a/recordmydesktop/src/encode_sound_buffer.c b/recordmydesktop/src/encode_sound_buffer.c index ee19628..e72884b 100644 --- a/recordmydesktop/src/encode_sound_buffer.c +++ b/recordmydesktop/src/encode_sound_buffer.c @@ -79,21 +79,15 @@ void *EncodeSoundBuffer(ProgData *pdata){ free(buff); } - vorbis_analysis_wrote(&pdata->enc_data->m_vo_dsp,0); -// while(vorbis_analysis_blockout(&pdata->enc_data->m_vo_dsp,&pdata->enc_data->m_vo_block)==1){ -// vorbis_analysis(&pdata->enc_data->m_vo_block,NULL); -// vorbis_bitrate_addblock(&pdata->enc_data->m_vo_block); -// while(vorbis_bitrate_flushpacket(&pdata->enc_data->m_vo_dsp,&pdata->enc_data->m_ogg_pckt2)) -// ogg_stream_packetin(&pdata->enc_data->m_ogg_vs,&pdata->enc_data->m_ogg_pckt2); -// } +// SyncEncodeSoundBuffer(pdata,NULL); pthread_exit(&errno); } void SyncEncodeSoundBuffer(ProgData *pdata,signed char *buff){ float **vorbis_buffer; int count=0,i,j; - int sampread=pdata->periodsize; + int sampread=(buff!=NULL)?pdata->periodsize:0; vorbis_buffer=vorbis_analysis_buffer(&pdata->enc_data->m_vo_dsp,sampread); for(i=0;iargs.channels;j++){ @@ -104,18 +98,19 @@ void SyncEncodeSoundBuffer(ProgData *pdata,signed char *buff){ } vorbis_analysis_wrote(&pdata->enc_data->m_vo_dsp,sampread); - + pthread_mutex_lock(&pdata->libogg_mutex); while(vorbis_analysis_blockout(&pdata->enc_data->m_vo_dsp,&pdata->enc_data->m_vo_block)==1){ vorbis_analysis(&pdata->enc_data->m_vo_block,NULL); vorbis_bitrate_addblock(&pdata->enc_data->m_vo_block); while(vorbis_bitrate_flushpacket(&pdata->enc_data->m_vo_dsp,&pdata->enc_data->m_ogg_pckt2)){ - pthread_mutex_lock(&pdata->libogg_mutex); ogg_stream_packetin(&pdata->enc_data->m_ogg_vs,&pdata->enc_data->m_ogg_pckt2); - pthread_mutex_unlock(&pdata->libogg_mutex); } } + if(!pdata->running)pdata->enc_data->m_ogg_vs.e_o_s=1; + pthread_mutex_unlock(&pdata->libogg_mutex); + pdata->avd-=pdata->periodtime; } diff --git a/recordmydesktop/src/flush_to_ogg.c b/recordmydesktop/src/flush_to_ogg.c index 8fa762f..2390810 100644 --- a/recordmydesktop/src/flush_to_ogg.c +++ b/recordmydesktop/src/flush_to_ogg.c @@ -26,55 +26,137 @@ #include +//we copy the page because the next call to ogg_stream_pageout +//will invalidate it. But we must have pages from both streams at every time in +//order to do correct multiplexing +void ogg_page_cp(ogg_page *new,ogg_page *old){ + int i=0; + register unsigned char *newp,*oldp; + + new->header_len=old->header_len; + new->header=malloc(new->header_len); + new->body_len=old->body_len; + new->body=malloc(new->body_len); + + newp=new->header; + oldp=old->header; + for(i=0;iheader_len;i++) + *(newp++)=*(oldp++); + newp=new->body; + oldp=old->body; + for(i=0;ibody_len;i++) + *(newp++)=*(oldp++); + +} +//free our copy +void ogg_page_cp_free(ogg_page *pg){ + pg->header_len=pg->body_len=0; + free(pg->header); + free(pg->body); +} + void *FlushToOgg(ProgData *pdata){ int videoflag=0,audioflag=0; double video_bytesout=0,audio_bytesout=0; - ogg_page videopage,audiopage; - while(pdata->running){ - pthread_mutex_lock(&pdata->libogg_mutex); - videoflag=ogg_stream_pageout(&pdata->enc_data->m_ogg_ts,&videopage); - pthread_mutex_unlock(&pdata->libogg_mutex); - if(videoflag){ - video_bytesout+=fwrite(videopage.header,1,videopage.header_len,pdata->enc_data->fp); - video_bytesout+=fwrite(videopage.body,1,videopage.body_len,pdata->enc_data->fp); - videoflag=0; - if(!pdata->args.nosound){ + ogg_page videopage,//owned by libogg + videopage_copy,//owned by the application + audiopage,//owned by libogg + audiopage_copy;//owned by the application + + double audiotime=0; + double videotime=0; + int working=1, + th_st_fin=0, + v_st_fin=(pdata->args.nosound); + while(working){ + int audio_or_video=0; + if(pdata->running){ + pthread_mutex_lock(&pdata->libogg_mutex); + if(!videoflag){ + videoflag=ogg_stream_pageout(&pdata->enc_data->m_ogg_ts,&videopage); + videotime=(videoflag)?theora_granule_time(&pdata->enc_data->m_th_st,ogg_page_granulepos(&videopage)):-1; + if(videoflag)ogg_page_cp(&videopage_copy,&videopage); + } + if(!pdata->args.nosound) + if(!audioflag){ + audioflag=ogg_stream_pageout(&pdata->enc_data->m_ogg_vs,&audiopage); + audiotime=(audioflag)?vorbis_granule_time(&pdata->enc_data->m_vo_dsp,ogg_page_granulepos(&audiopage)):-1; + if(audioflag)ogg_page_cp(&audiopage_copy,&audiopage); + } + pthread_mutex_unlock(&pdata->libogg_mutex); + } + else{ + if(!th_st_fin && !videoflag){ pthread_mutex_lock(&pdata->libogg_mutex); - audioflag=ogg_stream_pageout(&pdata->enc_data->m_ogg_vs,&audiopage); + videoflag=ogg_stream_flush(&pdata->enc_data->m_ogg_ts,&videopage); + videotime=(videoflag)?theora_granule_time(&pdata->enc_data->m_th_st,ogg_page_granulepos(&videopage)):-1; + if(videoflag)ogg_page_cp(&videopage_copy,&videopage); pthread_mutex_unlock(&pdata->libogg_mutex); - if(audioflag){ - audio_bytesout+=fwrite(audiopage.header,1,audiopage.header_len,pdata->enc_data->fp); - audio_bytesout+=fwrite(audiopage.body,1,audiopage.body_len,pdata->enc_data->fp); - audioflag=0; - } + //we need the last page to properly close the stream + if(!videoflag)SyncEncodeImageBuffer(pdata); + } + if(!pdata->args.nosound && !v_st_fin &&!audioflag){ + pthread_mutex_lock(&pdata->libogg_mutex); + audioflag=ogg_stream_flush(&pdata->enc_data->m_ogg_vs,&audiopage); + audiotime=(audioflag)?vorbis_granule_time(&pdata->enc_data->m_vo_dsp,ogg_page_granulepos(&audiopage)):-1; + if(audioflag)ogg_page_cp(&audiopage_copy,&audiopage); + pthread_mutex_unlock(&pdata->libogg_mutex); + //we need the last page to properly close the stream + if(!audioflag)SyncEncodeSoundBuffer(pdata,NULL); } } - else + if(th_st_fin)videoflag=0; + if(v_st_fin)audioflag=0; + if((!audioflag && !v_st_fin && !pdata->args.nosound) || (!videoflag && !th_st_fin)){ usleep(10000); + continue; + } + if(!audioflag){ + audio_or_video=1; + } + else if(!videoflag) { + audio_or_video=0; + } + else{ + if(audiotimeenc_data->fp); + video_bytesout+=fwrite(videopage_copy.body,1,videopage_copy.body_len,pdata->enc_data->fp); + videoflag=0; + if(!pdata->running){ + pthread_mutex_lock(&pdata->libogg_mutex); + if(ogg_page_eos(&videopage_copy)) + th_st_fin=1; + pthread_mutex_unlock(&pdata->libogg_mutex); + } + ogg_page_cp_free(&videopage_copy); + } + else{ + audio_bytesout+=fwrite(audiopage_copy.header,1,audiopage_copy.header_len,pdata->enc_data->fp); + audio_bytesout+=fwrite(audiopage_copy.body,1,audiopage_copy.body_len,pdata->enc_data->fp); + audioflag=0; + if(!pdata->running){ + pthread_mutex_lock(&pdata->libogg_mutex); + if(ogg_page_eos(&audiopage_copy)) + v_st_fin=1; + pthread_mutex_unlock(&pdata->libogg_mutex); + } + ogg_page_cp_free(&audiopage_copy); + } + working=(!th_st_fin || !v_st_fin); } //last packages - pdata->enc_data->m_ogg_ts.e_o_s=1; - videoflag=ogg_stream_flush(&pdata->enc_data->m_ogg_ts,&videopage); - if(videoflag){ - video_bytesout+=fwrite(videopage.header,1,videopage.header_len,pdata->enc_data->fp); - video_bytesout+=fwrite(videopage.body,1,videopage.body_len,pdata->enc_data->fp); - videoflag=0; - } - if(!pdata->args.nosound){ - pdata->enc_data->m_ogg_vs.e_o_s=1; - do{ - audioflag=ogg_stream_flush(&pdata->enc_data->m_ogg_vs,&audiopage); - if(audioflag){ - audio_bytesout+=fwrite(audiopage.header,1,audiopage.header_len,pdata->enc_data->fp); - audio_bytesout+=fwrite(audiopage.body,1,audiopage.body_len,pdata->enc_data->fp); - audioflag=0; - } - }while(!ogg_page_eos(&audiopage)); - } + + pthread_mutex_lock(&pdata->libogg_mutex); ogg_stream_clear(&pdata->enc_data->m_ogg_ts); if(!pdata->args.nosound) ogg_stream_clear(&pdata->enc_data->m_ogg_vs); + pthread_mutex_unlock(&pdata->libogg_mutex); //this always gives me a segfault :( // theora_clear(&pdata->enc_data->m_th_st); diff --git a/recordmydesktop/src/load_cache.c b/recordmydesktop/src/load_cache.c index eee3fb7..41568c9 100644 --- a/recordmydesktop/src/load_cache.c +++ b/recordmydesktop/src/load_cache.c @@ -194,6 +194,8 @@ void *LoadCache(ProgData *pdata){ } } } + SyncEncodeImageBuffer(pdata); + SyncEncodeSoundBuffer(pdata,sound_data); fprintf(stdout,"\n"); CLEAR_FRAME(&frame) free(sound_data); diff --git a/recordmydesktop/src/opendev.c b/recordmydesktop/src/opendev.c index 9250bab..d5a6af9 100644 --- a/recordmydesktop/src/opendev.c +++ b/recordmydesktop/src/opendev.c @@ -36,14 +36,16 @@ snd_pcm_t *OpenDev(const char *pcm_dev,unsigned int *channels,unsigned int *freq snd_pcm_hw_params_t *hwparams; unsigned int periods=2; unsigned int exactrate = *frequency; - + snd_pcm_uframes_t buffsize=1024; snd_pcm_hw_params_alloca(&hwparams); - snd_pcm_uframes_t buffsize=4096; + if (snd_pcm_open(&mhandle, pcm_dev, SND_PCM_STREAM_CAPTURE, SND_PCM_ASYNC)<0){ fprintf(stderr, "Couldn't open PCM device %s\n", pcm_dev); return NULL; } + else + fprintf(stderr, "Opened PCM device %s\n", pcm_dev); if (snd_pcm_hw_params_any(mhandle, hwparams)<0){ fprintf(stderr, "Couldn't configure PCM device.\n"); return NULL; @@ -76,7 +78,7 @@ snd_pcm_t *OpenDev(const char *pcm_dev,unsigned int *channels,unsigned int *freq fprintf(stderr, "Couldn't set periods.\n"); return NULL; } - buffsize=(exactrate)>>2; + if (snd_pcm_hw_params_set_buffer_size_near(mhandle, hwparams,&buffsize)<0){ fprintf(stderr, "Couldn't set buffer size.\n"); return NULL; @@ -87,11 +89,13 @@ snd_pcm_t *OpenDev(const char *pcm_dev,unsigned int *channels,unsigned int *freq } if(hard_pause!=NULL) if(!snd_pcm_hw_params_can_pause(hwparams)){ -// fprintf(stderr, "Current sound device doesn't seem to support pausing!\nI will attempt to close/reopen device in case you opt to pause during recording.\n"); *hard_pause=1; } if(periodsize!=NULL) snd_pcm_hw_params_get_period_size(hwparams,periodsize,0); + snd_pcm_hw_params_get_buffer_size(hwparams,&buffsize); + fprintf(stderr,"buffsize %d,periodsize %d\n",buffsize,*periodsize); + if(periodtime!=NULL) snd_pcm_hw_params_get_period_time(hwparams,periodtime,0); fprintf(stderr,"Recording on device %s is set to:\n%d channels at %dHz\n",pcm_dev,*channels,*frequency); -- cgit v1.2.3