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 + -
显示快捷键?