stretch.c
来自「linux下的MPEG1」· C语言 代码 · 共 697 行 · 第 1/2 页
C
697 行
audio_buffer_t *outbuf; int16_t *data_out = this->outfrag; int num_frames_in = this->num_frames; int num_frames_out = this->num_frames * this->frames_per_outfrag / this->frames_per_frag; if( !this->params.preserve_pitch ) { if( this->channels == 2 ) _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->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 ) { /* * time compressing strategy * * input chunk has two halves, A and B. * output chunk is composed as follow: * - some frames copied directly from A * - some frames copied from A merged with frames from B * weighted by an increasing factor (0 -> 1.0) * - frames from A weighted by a decreasing factor (1.0 -> 0) * merged with frames copied from B * - some frames copied directly from B */ int merge_frames = num_frames_in - num_frames_out; int copy_frames; int16_t *src = this->audiofrag; int16_t *dst = this->outfrag; int i, j; if( merge_frames > num_frames_out ) merge_frames = num_frames_out; copy_frames = num_frames_out - merge_frames; memcpy(dst, src, copy_frames/2 * this->bytes_per_frame); dst += copy_frames/2 * this->channels; src += copy_frames/2 * this->channels; for( i = 0; i < merge_frames/2; i++ ) { for( j = 0; j < this->channels; j++, src++, dst++ ) { int32_t s = (int32_t) ((_ftype_t) src[0] + src[merge_frames * this->channels] * this->w[i]); *dst = CLIP_INT16(s); } } for( ; i < merge_frames; i++ ) { for( j = 0; j < this->channels; j++, src++, dst++ ) { int32_t s = (int32_t) ((_ftype_t) src[0] * this->w[i] + src[merge_frames * this->channels]); *dst = CLIP_INT16(s); } } src += merge_frames * this->channels; memcpy(dst, src, (copy_frames - copy_frames/2) * this->bytes_per_frame); } else { /* * time expansion strategy * * output chunk is composed of two versions of the * input chunk: * - first part copied directly from input, and then * merged with the second (delayed) part using a * decreasing factor (1.0 -> 0) * - the delayed version of the input is merged with * an increasing factor (0 -> 1.0) and then (when * factor reaches 1.0) just copied until the end. */ int merge_frames = num_frames_out - num_frames_in; int copy_frames = num_frames_out - merge_frames; int16_t *src1 = this->audiofrag; int16_t *src2; int16_t *dst = this->outfrag; int i, j; memcpy(dst, src1, copy_frames/2 * this->bytes_per_frame); dst += copy_frames/2 * this->channels; src1 += copy_frames/2 * this->channels; src2 = src1 - merge_frames * this->channels; for( i = 0; i < merge_frames/2; i++ ) { for( j = 0; j < this->channels; j++, src1++, src2++, dst++ ) { int32_t s = (int32_t) ((_ftype_t) *src1 + *src2 * this->w[i]); *dst = CLIP_INT16(s); } } for( ; i < merge_frames; i++ ) { for( j = 0; j < this->channels; j++, src1++, src2++, dst++ ) { int32_t s = (int32_t) ((_ftype_t) *src1 * this->w[i] + *src2); *dst = CLIP_INT16(s); } } memcpy(dst, src2, (copy_frames - copy_frames/2) * this->bytes_per_frame); } } /* copy processed fragment into multiple audio buffers, if needed */ while( num_frames_out ) { outbuf = port->original_port->get_buffer(port->original_port); outbuf->num_frames = outbuf->mem_size / this->bytes_per_frame; if( outbuf->num_frames > num_frames_out ) outbuf->num_frames = num_frames_out; memcpy( outbuf->mem, data_out, outbuf->num_frames * this->bytes_per_frame ); num_frames_out -= outbuf->num_frames; data_out = (uint16_t *)((uint8_t *)data_out + outbuf->num_frames * this->bytes_per_frame); outbuf->vpts = this->pts; this->pts = 0; outbuf->stream = stream; outbuf->format.bits = port->bits; outbuf->format.rate = port->rate; outbuf->format.mode = port->mode; _x_extra_info_merge( outbuf->extra_info, extra_info ); port->original_port->put_buffer(port->original_port, outbuf, stream ); } this->num_frames = 0;}static void stretch_port_put_buffer (xine_audio_port_t *port_gen, audio_buffer_t *buf, xine_stream_t *stream) { post_audio_port_t *port = (post_audio_port_t *)port_gen; post_plugin_stretch_t *this = (post_plugin_stretch_t *)port->post; int16_t *data_in; pthread_mutex_lock (&this->lock); if( this->params_changed ) { int64_t audio_step; if( this->num_frames && this->audiofrag && this->outfrag ) { /* output whatever we have before changing parameters */ stretch_process_fragment( port, stream, buf->extra_info ); } this->channels = _x_ao_mode2channels(port->mode); this->bytes_per_frame = port->bits / 8 * this->channels; audio_step = ((int64_t)90000 * (int64_t)32768) / (int64_t)port->rate; audio_step = (int64_t) ((double)audio_step / this->params.factor); stream->metronom->set_audio_rate(stream->metronom, audio_step); stretchscr_set_speed(&this->scr->scr, this->scr->xine_speed); if(this->audiofrag) { free(this->audiofrag); this->audiofrag = NULL; } if(this->outfrag) { free(this->outfrag); this->outfrag = NULL; } if(this->w) { free(this->w); this->w = NULL; } this->frames_per_frag = port->rate * AUDIO_FRAGMENT; this->frames_per_outfrag = (int) ((double)this->params.factor * this->frames_per_frag); if( this->frames_per_frag != this->frames_per_outfrag ) { int wsize; this->audiofrag = malloc( this->frames_per_frag * this->bytes_per_frame ); this->outfrag = malloc( this->frames_per_outfrag * this->bytes_per_frame ); if( this->frames_per_frag > this->frames_per_outfrag ) wsize = this->frames_per_frag - this->frames_per_outfrag; else wsize = this->frames_per_outfrag - this->frames_per_frag; this->w = (_ftype_t*) malloc( wsize * sizeof(_ftype_t) ); triang(wsize, this->w); } this->num_frames = 0; this->pts = 0; this->params_changed = 0; } pthread_mutex_unlock (&this->lock); /* just pass data through if we have nothing to do */ if( this->frames_per_frag == this->frames_per_outfrag || /* FIXME: we only handle 1 or 2 channels, 16 bits for now */ (this->channels != 1 && this->channels != 2) || port->bits != 16 ) { port->original_port->put_buffer(port->original_port, buf, stream ); return; } /* update pts for our current audio fragment */ if( buf->vpts ) this->pts = buf->vpts - (this->num_frames * 90000 / port->rate); data_in = buf->mem; while( buf->num_frames ) { int frames_to_copy = this->frames_per_frag - this->num_frames; if( frames_to_copy > buf->num_frames ) frames_to_copy = buf->num_frames; /* copy up to one fragment from input buf to our buffer */ memcpy( (uint8_t *)this->audiofrag + this->num_frames * this->bytes_per_frame, data_in, frames_to_copy * this->bytes_per_frame ); data_in = (uint16_t *)((uint8_t *)data_in + frames_to_copy * this->bytes_per_frame); this->num_frames += frames_to_copy; buf->num_frames -= frames_to_copy; /* check if we have a complete audio fragment to process */ if( this->num_frames == this->frames_per_frag ) { stretch_process_fragment( port, stream, buf->extra_info ); } } buf->num_frames=0; /* UNDOCUMENTED, but hey, it works! Force old audio_out buffer free. */ port->original_port->put_buffer(port->original_port, buf, stream ); return;}static void stretch_dispose(post_plugin_t *this_gen){ post_plugin_stretch_t *this = (post_plugin_stretch_t *)this_gen; if (_x_post_dispose(this_gen)) { free(this); }}/* plugin class functions */static post_plugin_t *stretch_open_plugin(post_class_t *class_gen, int inputs, xine_audio_port_t **audio_target, xine_video_port_t **video_target){ post_plugin_stretch_t *this = (post_plugin_stretch_t *)xine_xmalloc(sizeof(post_plugin_stretch_t)); post_in_t *input; post_out_t *output; xine_post_in_t *input_api; post_audio_port_t *port; stretch_parameters_t init_params; if (!this || !audio_target || !audio_target[0] ) { free(this); return NULL; } _x_post_init(&this->post, 1, 0); init_params.preserve_pitch = 1; init_params.factor = 0.80; pthread_mutex_init (&this->lock, NULL); set_parameters ((xine_post_t *)&this->post, &init_params); port = _x_post_intercept_audio_port(&this->post, audio_target[0], &input, &output); port->new_port.open = stretch_port_open; port->new_port.close = stretch_port_close; port->new_port.put_buffer = stretch_port_put_buffer; input_api = &this->params_input; input_api->name = "parameters"; input_api->type = XINE_POST_DATA_PARAMETERS; input_api->data = &post_api; xine_list_push_back(this->post.input, input_api); this->post.xine_post.audio_input[0] = &port->new_port; this->post.dispose = stretch_dispose; return &this->post;}static char *stretch_get_identifier(post_class_t *class_gen){ return "stretch";}static char *stretch_get_description(post_class_t *class_gen){ return "Time stretch by a given factor, optionally preserving pitch";}static void stretch_class_dispose(post_class_t *class_gen){ free(class_gen);}/* plugin class initialization function */void *stretch_init_plugin(xine_t *xine, void *data){ post_class_stretch_t *class = (post_class_stretch_t *)malloc(sizeof(post_class_stretch_t)); if (!class) return NULL; class->post_class.open_plugin = stretch_open_plugin; class->post_class.get_identifier = stretch_get_identifier; class->post_class.get_description = stretch_get_description; class->post_class.dispose = stretch_class_dispose; class->xine = xine; return class;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?