⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 player.c

📁 mp3 plyer linux version
💻 C
📖 第 1 页 / 共 5 页
字号:
      if (player->options & PLAYER_OPTION_SHOWTAGSONLY) {	if (player->verbosity > 0)	  show_tag(tag);      }      else {	if ((tag->flags & TAG_LAME) &&	    (player->output.replay_gain & PLAYER_RGAIN_ENABLED) &&	    !(player->output.replay_gain & PLAYER_RGAIN_SET))	  use_rgain(player, tag->lame.replay_gain);      }      if ((tag->flags & TAG_XING) &&	  (tag->xing.flags & TAG_XING_FRAMES)) {	player->stats.total_time = frame->header.duration;	mad_timer_multiply(&player->stats.total_time, tag->xing.frames);      }      /* total stream byte size adjustment */      frame_size = stream->next_frame - stream->this_frame;      if (player->stats.total_bytes == 0) {	if ((tag->flags & TAG_XING) && (tag->xing.flags & TAG_XING_BYTES) &&	    tag->xing.bytes > frame_size)	  player->stats.total_bytes = tag->xing.bytes - frame_size;      }      else if (player->stats.total_bytes >=	       stream->next_frame - stream->this_frame)	player->stats.total_bytes -= frame_size;      return (player->options & PLAYER_OPTION_SHOWTAGSONLY) ?	MAD_FLOW_STOP : MAD_FLOW_IGNORE;    }    else if (player->options & PLAYER_OPTION_SHOWTAGSONLY)      return MAD_FLOW_STOP;    ++player->stats.absolute_framecount;    mad_timer_add(&player->stats.absolute_timer, frame->header.duration);    ++player->stats.global_framecount;    mad_timer_add(&player->stats.global_timer, frame->header.duration);    if ((player->options & PLAYER_OPTION_SKIP) &&	mad_timer_compare(player->stats.global_timer,			  player->global_start) < 0)      return MAD_FLOW_IGNORE;  }  /* run the filter chain */  return filter_run(player->output.filters, frame);}/* * NAME:	process_id3() * DESCRIPTION:	display and process ID3 tag information */staticvoid process_id3(struct id3_tag const *tag, struct player *player){  struct id3_frame const *frame;  /* display the tag */  if (player->verbosity >= 0 || (player->options & PLAYER_OPTION_SHOWTAGSONLY))    show_id3(tag);  /*   * The following is based on information from the   * ID3 tag version 2.4.0 Native Frames informal standard.   */  /* length information */  frame = id3_tag_findframe(tag, "TLEN", 0);  if (frame) {    union id3_field const *field;    unsigned int nstrings;    field    = id3_frame_field(frame, 1);    nstrings = id3_field_getnstrings(field);    if (nstrings > 0) {      id3_latin1_t *latin1;      latin1 = id3_ucs4_latin1duplicate(id3_field_getstrings(field, 0));      if (latin1) {	signed long ms;	/*	 * "The 'Length' frame contains the length of the audio file	 * in milliseconds, represented as a numeric string."	 */	ms = atol(latin1);	if (ms > 0)	  mad_timer_set(&player->stats.total_time, 0, ms, 1000);	free(latin1);      }    }  }  /* relative volume adjustment information */  if ((player->options & PLAYER_OPTION_SHOWTAGSONLY) ||      !(player->options & PLAYER_OPTION_IGNOREVOLADJ)) {    frame = id3_tag_findframe(tag, "RVA2", 0);    if (frame) {      id3_latin1_t const *id;      id3_byte_t const *data;      id3_length_t length;      enum {	CHANNEL_OTHER         = 0x00,	CHANNEL_MASTER_VOLUME = 0x01,	CHANNEL_FRONT_RIGHT   = 0x02,	CHANNEL_FRONT_LEFT    = 0x03,	CHANNEL_BACK_RIGHT    = 0x04,	CHANNEL_BACK_LEFT     = 0x05,	CHANNEL_FRONT_CENTRE  = 0x06,	CHANNEL_BACK_CENTRE   = 0x07,	CHANNEL_SUBWOOFER     = 0x08      };      id   = id3_field_getlatin1(id3_frame_field(frame, 0));      data = id3_field_getbinarydata(id3_frame_field(frame, 1), &length);      assert(id && data);      /*       * "The 'identification' string is used to identify the situation       * and/or device where this adjustment should apply. The following is       * then repeated for every channel       *       *   Type of channel         $xx       *   Volume adjustment       $xx xx       *   Bits representing peak  $xx       *   Peak volume             $xx (xx ...)"       */      while (length >= 4) {	unsigned int peak_bytes;	peak_bytes = (data[3] + 7) / 8;	if (4 + peak_bytes > length)	  break;	if (data[0] == CHANNEL_MASTER_VOLUME) {	  signed int voladj_fixed;	  double voladj_float;	  /*	   * "The volume adjustment is encoded as a fixed point decibel	   * value, 16 bit signed integer representing (adjustment*512),	   * giving +/- 64 dB with a precision of 0.001953125 dB."	   */	  voladj_fixed  = (data[1] << 8) | (data[2] << 0);	  voladj_fixed |= -(voladj_fixed & 0x8000);	  voladj_float  = (double) voladj_fixed / 512;	  set_gain(player, GAIN_VOLADJ, voladj_float);	  if (player->verbosity >= 0) {	    detail(_("Relative Volume"),		   _("%+.1f dB adjustment (%s)"), voladj_float, id);	  }	  break;	}	data   += 4 + peak_bytes;	length -= 4 + peak_bytes;      }    }  }  /* Replay Gain */  if ((player->options & PLAYER_OPTION_SHOWTAGSONLY) ||      ((player->output.replay_gain & PLAYER_RGAIN_ENABLED) &&       !(player->output.replay_gain & PLAYER_RGAIN_SET))) {    frame = id3_tag_findframe(tag, "RGAD", 0);    if (frame) {      id3_byte_t const *data;      id3_length_t length;      data = id3_field_getbinarydata(id3_frame_field(frame, 0), &length);      assert(data);      /*       * Peak Amplitude                          $xx $xx $xx $xx       * Radio Replay Gain Adjustment            $xx $xx       * Audiophile Replay Gain Adjustment       $xx $xx       */      if (length >= 8) {	struct mad_bitptr ptr;	mad_fixed_t peak;	struct rgain rgain[2];	mad_bit_init(&ptr, data);	peak = mad_bit_read(&ptr, 32) << 5;	rgain_parse(&rgain[0], &ptr);	rgain_parse(&rgain[1], &ptr);	use_rgain(player, rgain);	mad_bit_finish(&ptr);      }    }  }}/* * NAME:	show_status() * DESCRIPTION: generate and output stream statistics */staticvoid show_status(struct stats *stats,		 struct mad_header const *header, char const *label, int now){  signed long seconds;  static char const *const layer_str[3] = { N_("I"), N_("II"), N_("III") };  static char const *const mode_str[4] = {    N_("single channel"), N_("dual channel"), N_("joint stereo"), N_("stereo")  };  if (header) {    unsigned int bitrate;    bitrate = header->bitrate / 1000;    stats->vbr_rate += bitrate;    stats->vbr_frames++;    stats->vbr += (stats->bitrate && stats->bitrate != bitrate) ? 128 : -1;    if (stats->vbr < 0)      stats->vbr = 0;    else if (stats->vbr > 512)      stats->vbr = 512;    stats->bitrate = bitrate;  }  seconds = mad_timer_count(stats->global_timer, MAD_UNITS_SECONDS);  if (seconds != stats->nsecs || !on_same_line || now) {    mad_timer_t timer;    char time_str[18];    char const *joint_str = "";    stats->nsecs = seconds;    switch (stats->show) {    case STATS_SHOW_OVERALL:      timer = stats->global_timer;      break;    case STATS_SHOW_CURRENT:      timer = stats->absolute_timer;      break;    case STATS_SHOW_REMAINING:      timer = stats->total_time;      if (mad_timer_sign(timer) == 0 && stats->total_bytes) {	unsigned long rate;	/* estimate based on size and bitrate */	rate = stats->vbr ?	  stats->vbr_rate * 125 / stats->vbr_frames : stats->bitrate * 125UL;	mad_timer_set(&timer, 0, stats->total_bytes, rate);      }      mad_timer_negate(&timer);      mad_timer_add(&timer, stats->absolute_timer);      break;    }    mad_timer_string(timer, time_str, " %02lu:%02u:%02u",		     MAD_UNITS_HOURS, 0, 0);    if (mad_timer_sign(timer) < 0)      time_str[0] = '-';    if (label || stats->label) {      message("%s %s", time_str, label ? label : stats->label);      stats->label = now ? label : 0;    }    else if (header) {      if (header->mode == MAD_MODE_JOINT_STEREO) {	switch (header->flags & (MAD_FLAG_MS_STEREO | MAD_FLAG_I_STEREO)) {	case 0:	  joint_str = _(" (LR)");	  break;	case MAD_FLAG_MS_STEREO:	  joint_str = _(" (MS)");	  break;	case MAD_FLAG_I_STEREO:	  joint_str = _(" (I)");	  break;	case (MAD_FLAG_MS_STEREO | MAD_FLAG_I_STEREO):	  joint_str = _(" (MS+I)");	  break;	}      }      message(_("%s Layer %s, %s%u kbps%s, %u Hz, %s%s, %s"),	      time_str, gettext(layer_str[header->layer - 1]),	      stats->vbr ? _("VBR (avg ") : "",	      stats->vbr ? ((stats->vbr_rate * 2) /			    stats->vbr_frames + 1) / 2 : stats->bitrate,	      stats->vbr ? _(")") : "",	      header->samplerate, gettext(mode_str[header->mode]), joint_str,	      (header->flags & MAD_FLAG_PROTECTION) ? _("CRC") : _("no CRC"));    }    else      message("%s", time_str);  }}/* * NAME:	decode->output() * DESCRIPTION: configure audio module and output decoded samples */staticenum mad_flow decode_output(void *data, struct mad_header const *header,			    struct mad_pcm *pcm){  struct player *player = data;  struct output *output = &player->output;  mad_fixed_t const *ch1, *ch2;  unsigned int nchannels;  union audio_control control;  ch1 = pcm->samples[0];  ch2 = pcm->samples[1];  switch (nchannels = pcm->channels) {  case 1:    ch2 = 0;    if (output->select == PLAYER_CHANNEL_STEREO) {      ch2 = ch1;      nchannels = 2;    }    break;  case 2:    switch (output->select) {    case PLAYER_CHANNEL_RIGHT:      ch1 = ch2;      /* fall through */    case PLAYER_CHANNEL_LEFT:      ch2 = 0;      nchannels = 1;      /* fall through */    case PLAYER_CHANNEL_STEREO:      break;    default:      if (header->mode == MAD_MODE_DUAL_CHANNEL) {	if (output->select == PLAYER_CHANNEL_DEFAULT) {	  if (player->verbosity >= -1) {	    error("output",		  _("no channel selected for dual channel; using first"));	  }	  output->select = -PLAYER_CHANNEL_LEFT;	}	ch2 = 0;	nchannels = 1;      }    }  }  if (output->channels_in != nchannels ||      output->speed_in != pcm->samplerate) {    unsigned int speed_request;    if (player->verbosity >= 1 &&	pcm->samplerate != header->samplerate) {      error("output", _("decoded sample frequency %u Hz"),	    pcm->samplerate);    }    speed_request = output->speed_request ?      output->speed_request : pcm->samplerate;    audio_control_init(&control, AUDIO_COMMAND_CONFIG);    control.config.channels  = nchannels;    control.config.speed     = speed_request;    control.config.precision = output->precision_in;    if (output->command(&control) == -1) {      error("output", audio_error);      return MAD_FLOW_BREAK;    }    output->channels_in  = nchannels;    output->speed_in     = pcm->samplerate;    output->channels_out  = control.config.channels;    output->speed_out     = control.config.speed;    output->precision_out = control.config.precision;    if (player->verbosity >= -1 &&	output->channels_in != output->channels_out) {      if (output->channels_in == 1)	error("output", _("mono output not available; forcing stereo"));      else {	error("output", _("stereo output not available; using first channel "			  "(use -m to mix)"));      }    }    if (player->verbosity >= -1 &&	output->precision_in &&	output->precision_in != output->precision_out) {      error("output", _("bit depth %u not available; using %u"),	    output->precision_in, output->precision_out);    }    if (player->verbosity >= -1 &&	speed_request != output->speed_out) {      error("output", _("sample frequency %u Hz not available; using %u Hz"),	    speed_request, output->speed_out);    }    /* check whether resampling is necessary */    if (abs(output->speed_out - output->speed_in) <	(long) FREQ_TOLERANCE * output->speed_in / 100) {      if (output->resampled) {	resample_finish(&output->resample[0]);	resample_finish(&output->resample[1]);	free(output->resampled);	output->resampled = 0;      }    }    else {      if (output->resampled) {	resample_finish(&output->resample[0]);	resample_finish(&output->resample[1]);      }      else {	output->resampled = malloc(sizeof(*output->resampled));	if (output->resampled == 0) {	  error("output",		_("not enough memory to allocate resampling buffer"));	  output->speed_in = 0;	  return MAD_FLOW_BREAK;	}      }      if (resample_init(&output->resample[0],			output->speed_in, output->speed_out) == -1 ||	  resample_init(&output->resample[1],			output->speed_in, output->speed_out) == -1) {	error("output", _("cannot resample %u Hz to %u Hz"),	      output->speed_in, output->speed_out);	free(output->resampled);	output->resampled = 0;	output->speed_in = 0;	return MAD_FLOW_BREAK;      }      else if (player->verbosity >= -1) {	error("output", _("resampling %u Hz to %u Hz"),	      output->speed_in, output->speed_out);      }    }  }  audio_control_init(&control, AUDIO_COMMAND_PLAY);  if (output->channels_in != output->channels_out)    ch2 = (output->channels_out == 2) ? ch1 : 0;  if (output->resampled) {    control.play.nsamples = resample_block(&output->resample[0],					   pcm->length, ch1,					   (*output->resampled)[0]);    control.play.samples[0] = (*output->resampled)[0];    if (ch2 == ch1)      control.play.samples[1] = control.play.samples[0];    else if (ch2) {      resample_block(&output->resample[1], pcm->length, ch2,		     (*output->resampled)[1]);      control.play.samples[1] = (*output->resampled)[1];    }    else      control.play.samples[1] = 0;  }  else {    control.play.nsamples   = pcm->length;    control.play.samples[0] = ch1;    control.play.samples[1] = ch2;  }  control.play.mode  = output->mode;  control.play.stats = &player->stats.audio;  if (output->command(&control) == -1) {    error("output", audio_error);    return MAD_FLOW_BREAK;  }  ++player->stats.play_framecount;  mad_timer_add(&player->stats.play_timer, header->duration);  if (player->verbosity > 0)    show_status(&player->stats, header, 0, 0);  return MAD_FLOW_CONTINUE;}/* * NAME:	get_id3() * DESCRIPTION:	read and parse an ID3 tag from a stream */staticstruct id3_tag *get_id3(struct mad_stream *stream, id3_length_t tagsize,			struct input *input){  struct id3_tag *tag = 0;  id3_length_t count;  id3_byte_t const *data;  id3_byte_t *allocated = 0;  count = stream->bufend - stream->this_frame;  if (tagsize <= count) {    data = stream->this_frame;    mad_stream_skip(stream, tagsize);  }  else {    allocated = malloc(tagsize);    if (allocated == 0) {      error("id3", _("not enough memory to allocate tag data buffer"));      goto fail;    }    memcpy(allocated, stream->this_frame, count);    mad_stream_skip(stream, count);    while (count < tagsize) {      int len;      do

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -