From 446e1487e45af46a62f00ce0165b830081073cda Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Sun, 12 Aug 2007 18:31:37 +0100 Subject: Fix goom visualization plug-in I noticed that goom visualization plug-in doesn't work / freezes at some combination of bit rates and its FPS. Digging through it I found that algorithm that dispatches sound data to goom is buggy, and so I have rewrote/cleaned it a lot. Let me explain what is wrong: I am talking about goom_port_put_buffer in /xine-lib-1.1.7/src/post/goom/xine_goom.c The counter this->skip_frame is supposed to hold count of frames that goom should skip because of _video render unable to render video_. But that algorithm also skips frames on its own, and still decrements that counter. So it goes negative, and no frames are displayed. Basically to fix that you need to add if (this->skip_frame > 0) before this->skip_frame--; But since I want to fix that properly I decided to learn why goom skips frames on its own, and I now understand that whole algorithm is buggy. Thus I reimplemented it properly. I tested it , and it works with all my sound files, also I added lot of debug printfs to test whenever it works as expected, and it does. --HG-- extra : transplant_source : %B6%0C%09%D6%93%B8%00cj%3B8%C7%B5%0B%DB%21%08%92%3E%7B --- src/post/goom/xine_goom.c | 112 ++++++++++++++++++++++++++++------------------ 1 file changed, 68 insertions(+), 44 deletions(-) (limited to 'src/post') diff --git a/src/post/goom/xine_goom.c b/src/post/goom/xine_goom.c index 5871618e0..7c2939105 100644 --- a/src/post/goom/xine_goom.c +++ b/src/post/goom/xine_goom.c @@ -82,13 +82,12 @@ struct post_plugin_goom_s { /* goom context */ PluginInfo *goom; - int data_idx; + int data_idx; gint16 data [2][NUMSAMPLES]; audio_buffer_t buf; /* dummy buffer just to hold a copy of audio data */ int channels; int sample_rate; - int sample_counter; int samples_per_frame; int width, height; int width_back, height_back; @@ -96,6 +95,11 @@ struct post_plugin_goom_s { int fps; int csc_method; + + int do_samples_skip; /* true = skipping samples, false reading samples*/ + int left_to_read; /* data to read before switching modes*/ + + yuv_planes_t yuv; /* frame skipping */ @@ -282,7 +286,6 @@ static post_plugin_t *goom_open_plugin(post_class_t *class_gen, int inputs, this->ratio = (double)this->width_back/(double)this->height_back; - this->sample_counter = 0; this->buf.mem = NULL; this->buf.mem_size = 0; @@ -386,9 +389,11 @@ static int goom_port_open(xine_audio_port_t *port_gen, xine_stream_t *stream, this->sample_rate = rate; this->samples_per_frame = rate / this->fps; this->data_idx = 0; - this->sample_counter = 0; init_yuv_planes(&this->yuv, this->width, this->height); this->skip_frame = 0; + + this->do_samples_skip = 0; + this->left_to_read = NUMSAMPLES; this->vo_port->open(this->vo_port, XINE_ANON_STREAM); this->metronom->set_master(this->metronom, stream->metronom); @@ -422,11 +427,12 @@ static void goom_port_put_buffer (xine_audio_port_t *port_gen, uint8_t *goom_frame, *goom_frame_end; int16_t *data; int8_t *data8; - int samples_used = 0; int64_t pts = buf->vpts; int i, j; uint8_t *dest_ptr; int width, height; + + int current_sample = 0; /* make a copy of buf data for private use */ if( this->buf.mem_size < buf->mem_size ) { @@ -444,59 +450,73 @@ static void goom_port_put_buffer (xine_audio_port_t *port_gen, * to the fifo of free audio buffers. just use our private copy instead. */ buf = &this->buf; - - this->sample_counter += buf->num_frames; j = (this->channels >= 2) ? 1 : 0; - do { - + + while (current_sample < buf->num_frames) { + + if (this->do_samples_skip) { + if (current_sample + this->left_to_read > buf->num_frames) { + this->left_to_read -= (buf->num_frames-current_sample); + break; + } else { + current_sample+=this->left_to_read; + this->left_to_read = NUMSAMPLES; + this->do_samples_skip = 0; + + } + } else { + if( port->bits == 8 ) { data8 = (int8_t *)buf->mem; - data8 += samples_used * this->channels; + data8 += current_sample * this->channels; /* scale 8 bit data to 16 bits and convert to signed as well */ - for( i = samples_used; i < buf->num_frames && this->data_idx < NUMSAMPLES; - i++, this->data_idx++, data8 += this->channels ) { + for ( i=current_sample ; this->data_idx < NUMSAMPLES && i < buf->num_frames; + i++, this->data_idx++,data8 += this->channels) { + this->data[0][this->data_idx] = ((int16_t)data8[0] << 8) - 0x8000; this->data[1][this->data_idx] = ((int16_t)data8[j] << 8) - 0x8000; } } else { data = buf->mem; - data += samples_used * this->channels; - - for( i = samples_used; i < buf->num_frames && this->data_idx < NUMSAMPLES; - i++, this->data_idx++, data += this->channels ) { + data += current_sample * this->channels; + + for ( i=current_sample ; this->data_idx < NUMSAMPLES && i < buf->num_frames; + i++, this->data_idx++,data += this->channels) { + this->data[0][this->data_idx] = data[0]; this->data[1][this->data_idx] = data[j]; } } - - if( this->sample_counter >= this->samples_per_frame ) { - - samples_used += this->samples_per_frame; + + if (this->data_idx < NUMSAMPLES) { + this->left_to_read = NUMSAMPLES - this->data_idx; + break; + } else { + _x_assert(this->data_idx == NUMSAMPLES); + this->data_idx = 0; + + if (this->samples_per_frame > NUMSAMPLES) { + current_sample += NUMSAMPLES; + this->do_samples_skip = 1; + this->left_to_read = this->samples_per_frame - NUMSAMPLES; + } else { + current_sample += this->samples_per_frame; + this->left_to_read = NUMSAMPLES; + } frame = this->vo_port->get_frame (this->vo_port, this->width_back, this->height_back, - this->ratio, XINE_IMGFMT_YUY2, - VO_BOTH_FIELDS); + this->ratio, XINE_IMGFMT_YUY2, + VO_BOTH_FIELDS); frame->extra_info->invalid = 1; - /* frame is marked as bad if we don't have enough samples for - * updating the viz plugin (calculations may be skipped). - * we must keep the framerate though. */ - if( this->data_idx == NUMSAMPLES ) { - frame->bad_frame = 0; - this->data_idx = 0; - } else { - frame->bad_frame = 1; - } frame->duration = 90000 * this->samples_per_frame / this->sample_rate; frame->pts = pts; this->metronom->got_video_frame(this->metronom, frame); - this->sample_counter -= this->samples_per_frame; - - if (!this->skip_frame && !frame->bad_frame) { + if (!this->skip_frame) { /* Try to be fast */ goom_frame = (uint8_t *)goom_update (this->goom, this->data, 0, 0, NULL, NULL); @@ -561,21 +581,25 @@ static void goom_port_put_buffer (xine_audio_port_t *port_gen, } else { frame->bad_frame = 1; frame->draw(frame, XINE_ANON_STREAM); - this->skip_frame--; + + _x_assert(this->skip_frame>0); + this->skip_frame--; } + frame->free(frame); width = this->width; height = this->height; if ((width != this->width_back) || (height != this->height_back)) { - goom_close(this->goom); - this->goom = goom_init (this->width, this->height); - this->width_back = width; - this->height_back = height; - this->ratio = (double)width/(double)height; - free_yuv_planes(&this->yuv); - init_yuv_planes(&this->yuv, this->width, this->height); - } + goom_close(this->goom); + this->goom = goom_init (this->width, this->height); + this->width_back = width; + this->height_back = height; + this->ratio = (double)width/(double)height; + free_yuv_planes(&this->yuv); + init_yuv_planes(&this->yuv, this->width, this->height); + } } - } while( this->sample_counter >= this->samples_per_frame ); + } + } } -- cgit v1.2.3 From 7047d9e5acf97c91a523c99ccc4b008a35a3e094 Mon Sep 17 00:00:00 2001 From: Darren Salt Date: Wed, 15 Aug 2007 13:42:38 +0100 Subject: Fix an audio resampling problem which was causing regular clicking. The cause was that the resampling code was using only the samples in the buffer but not really handling the transition between two buffers (which it would handle completely independently). The new code remembers the last sample from the previous buffer and uses it in the resampling. We therefore end up one sample behind and without the clicks. --- src/post/audio/stretch.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'src/post') diff --git a/src/post/audio/stretch.c b/src/post/audio/stretch.c index a1e921e03..054468517 100644 --- a/src/post/audio/stretch.c +++ b/src/post/audio/stretch.c @@ -225,6 +225,8 @@ struct post_plugin_stretch_s { int frames_per_frag; int frames_per_outfrag; int num_frames; /* current # of frames on audiofrag */ + + int16_t last_sample[RESAMPLE_MAX_CHANNELS]; int64_t pts; /* pts for audiofrag */ @@ -353,12 +355,16 @@ static void stretch_process_fragment( post_audio_port_t *port, if( !this->params.preserve_pitch ) { if( this->channels == 2 ) - _x_audio_out_resample_stereo(this->audiofrag, num_frames_in, + _x_audio_out_resample_stereo(this->last_sample, this->audiofrag, num_frames_in, this->outfrag, num_frames_out); else if( this->channels == 1 ) - _x_audio_out_resample_mono(this->audiofrag, num_frames_in, + _x_audio_out_resample_mono(this->last_sample, this->audiofrag, num_frames_in, this->outfrag, num_frames_out); } else { + if (this->channels == 2) + memcpy (this->last_sample, &this->audiofrag[(num_frames_in - 1) * 2], 2 * sizeof (this->last_sample[0])); + else if (this->channels == 1) + memcpy (this->last_sample, &this->audiofrag[num_frames_in - 1], sizeof (this->last_sample[0])); if( num_frames_in > num_frames_out ) { /* -- cgit v1.2.3