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

📄 player.c

📁 完成MP3播放功能
💻 C
📖 第 1 页 / 共 3 页
字号:
  struct player *player = data;  /* output ancillary data */  if (player->ancillary.file && stream->anc_bitlen &&      write_ancillary(&player->ancillary,		      stream->anc_ptr, stream->anc_bitlen) == -1)    return MAD_FLOW_BREAK;  /* first frame accounting */  if (player->stats.absolute_framecount == 0) {    ++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:	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:	decode->error() * DESCRIPTION:	handle a decoding error */staticenum mad_flow decode_error(void *data, struct mad_stream *stream,			   struct mad_frame *frame){  return MAD_FLOW_CONTINUE;}/** NAME:	decode() DESCRIPTION:	decode and output audio for an open file *///被play_one()调用static int decode(struct player *player){ struct stat stat;  struct mad_decoder decoder;  int options, result;  if (fstat(player->input.fd, &stat) == -1)   { error("decode", ":fstat");    return -1;  }  if (S_ISREG(stat.st_mode))    player->stats.total_bytes = stat.st_size;  /* prepare input buffers */  if (player->input.data == 0)   { player->input.data = malloc(MPEG_BUFSZ);    if (player->input.data == 0)     { error("decode", _("not enough memory to allocate input buffer"));      return -1;    }    player->input.length = 0;  }  player->input.eof = 0;  /* reset statistics */  player->stats.absolute_timer        = mad_timer_zero;  player->stats.play_timer            = mad_timer_zero;  player->stats.absolute_framecount   = 0;  player->stats.play_framecount       = 0;  player->stats.error_frame           = -1;  player->stats.vbr                   = 0;  player->stats.bitrate               = 0;  player->stats.vbr_frames            = 0;  player->stats.vbr_rate              = 0;  player->stats.audio.clipped_samples = 0;  player->stats.audio.peak_clipping   = 0;  player->stats.audio.peak_sample     = 0;  mad_decoder_init(&decoder, player,decode_input_read,decode_header, decode_filter,                   player->output.command ? decode_output : 0, decode_error, 0);//decoder.c  options = 0;  if (player->options & PLAYER_OPTION_DOWNSAMPLE)    options |= MAD_OPTION_HALFSAMPLERATE;  if (player->options & PLAYER_OPTION_IGNORECRC)     options |= MAD_OPTION_IGNORECRC;  mad_decoder_options(&decoder, options);  result = mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);  mad_decoder_finish(&decoder);  if (player->input.data)   { free(player->input.data);    player->input.data = 0;  }  return result;}/*NAME:	play_one(), DESCRIPTION:	open and play a single file *///被play_all()调用static int play_one(struct player *player){ char const *file = player->playlist.entries[player->playlist.current];  int result;  if (strcmp(file, "-") == 0)   { if (isatty(STDIN_FILENO))     { error(0, "%s: %s", _("stdin"), _("is a tty"));      return -1;    }    player->input.path = _("stdin");    player->input.fd   = STDIN_FILENO;  }  else   { player->input.path = file;					//struct:player.h    player->input.fd   = open(file, O_RDONLY | O_BINARY);	//int fd    if (player->input.fd == -1)     { error(0, ":", file);      return -1;    }  }  if (player->verbosity >= 0 && player->playlist.length > 1)    message(">> %s\n", player->input.path);  /* reset file information */  player->stats.total_bytes = 0;  player->stats.total_time  = mad_timer_zero;  if (!(player->options & PLAYER_OPTION_IGNOREVOLADJ))    set_gain(player, GAIN_VOLADJ, 0);  player->output.replay_gain &= ~RGAIN_SET;  result = decode(player);  if (result == 0 && player->verbosity >= 0 && !(player->options & PLAYER_OPTION_SHOWTAGSONLY))   { char time_str[19], db_str[7];    char const *peak_str;    mad_fixed_t peak;    mad_timer_string(player->stats.play_timer, time_str, "%lu:%02u:%02u.%1u",MAD_UNITS_HOURS, MAD_UNITS_DECISECONDS, 0);# if defined(HAVE_LOCALECONV)    { char *point;      point = strchr(time_str, '.');      if (point)	*point = *localeconv()->decimal_point;    }# endif    peak = MAD_F_ONE + player->stats.audio.peak_clipping;    if (peak == MAD_F_ONE)   peak = player->stats.audio.peak_sample;    if (peak == 0)      peak_str = "-inf";    else     { sprintf(db_str, "%+.1f", 20 * log10(mad_f_todouble(peak)));      peak_str = db_str;    }    message("%lu %s (%s), %s dB %s, %lu %s\n", player->stats.play_framecount, player->stats.play_framecount == 1 ?	    _("frame decoded") : _("frames decoded"), time_str, peak_str, _("peak amplitude"), player->stats.audio.clipped_samples,	   player->stats.audio.clipped_samples == 1 ? _("clipped sample") : _("clipped samples"));  }  if (player->input.fd != STDIN_FILENO && close(player->input.fd) == -1 && result == 0)   { error(0, ":", player->input.path);    result = -1;  }  return result;}/* NAME:	play_all() DESCRIPTION:	run the player's playlist *///被player_run()调用static int play_all(struct player *player){ int count, i, j, result = 0;  struct playlist *playlist = &player->playlist;  char const *tmp;  /* set up playlist */  count = playlist->length;  if (player->options & PLAYER_OPTION_SHUFFLE)   {  srand(time(0));    /* initial shuffle */    for (i = 0; i < count; ++i)     { j = rand() % count;      tmp = playlist->entries[i];      playlist->entries[i] = playlist->entries[j];      playlist->entries[j] = tmp;    }  }  /* run playlist */  while (count && (player->repeat == -1 || player->repeat--))   { while (playlist->current < playlist->length)   	{ i = playlist->current;      if (playlist->entries[i] == 0)       {	++playlist->current;				continue;      }      player->control = PLAYER_CONTROL_DEFAULT;      if (play_one(player) == -1)       {	playlist->entries[i] = 0;				--count;				result = -1;      }      if ((player->options & PLAYER_OPTION_TIMED) && mad_timer_compare(player->stats.global_timer,player->global_stop)>0)       { count = 0;				break;      }      switch (player->control)       { case PLAYER_CONTROL_DEFAULT:				if ((player->options & PLAYER_OPTION_SHUFFLE) && player->repeat && ++i < playlist->length) 				{  /* pick something from the next half only */	  			j = (i + rand() % ((playlist->length + 1) / 2)) % playlist->length;				  tmp = playlist->entries[i];	  			playlist->entries[i] = playlist->entries[j];	  			playlist->entries[j] = tmp;				}				/* fall through */	      case PLAYER_CONTROL_NEXT:					++playlist->current;					break;      case PLAYER_CONTROL_PREVIOUS:	do {	  if (playlist->current-- == 0)	    playlist->current = playlist->length;	}	while (playlist->current < playlist->length &&	       playlist->entries[playlist->current] == 0);	break;      case PLAYER_CONTROL_REPLAY:	break;      case PLAYER_CONTROL_STOP:	playlist->current = playlist->length;	count = 0;	break;      }    }    playlist->current = 0;  }  return result;}/* * NAME:	stop_audio() * DESCRIPTION:	stop playing the audio device immediately */staticint stop_audio(struct player *player, int flush){  int result = 0;  if (player->output.command) {    union audio_control control;    audio_control_init(&control, AUDIO_COMMAND_STOP);    control.stop.flush = flush;    result = player->output.command(&control);  }  return result;}# if defined(USE_TTY)/* * NAME:	readkey() * DESCRIPTION:	read a keypress from the keyboard */staticint readkey(int blocking){# if !defined(_WIN32)  unsigned char key;  ssize_t count;  if (!blocking) {    /* tty_fd should be a tty in noncanonical mode with VMIN = VTIME = 0 */    count = read(tty_fd, &key, 1);    if (count == -1 && errno != EINTR) {      error("tty", ":read");      return -1;    }    return (count == 1) ? key : 0;  }  else {    struct termios tty, save_tty;    if (tcgetattr(tty_fd, &tty) == -1) {      error("tty", ":tcgetattr");      return -1;    }    save_tty = tty;    /* change terminal temporarily to get a blocking read() */    tty.c_cc[VMIN] = 1;    if (tcsetattr(tty_fd, TCSANOW, &tty) == -1) {      error("tty", ":tcsetattr");      return -1;    }    do      count = read(tty_fd, &key, 1);    while (count == -1 && errno == EINTR);    if (count == -1)      error("tty", ":read");    if (tcsetattr(tty_fd, TCSANOW, &save_tty) == -1) {      error("tty", ":tcsetattr");      return -1;    }    if (count == -1)      return -1;

⌨️ 快捷键说明

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