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

📄 player.c

📁 linux下MPEG播放器
💻 C
📖 第 1 页 / 共 5 页
字号:
  }  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	len = read(input->fd, allocated + count, tagsize - count);      while (len == -1 && errno == EINTR);      if (len == -1) {	error("id3", ":read");	goto fail;      }      if (len == 0) {	error("id3", _("EOF while reading tag data"));	goto fail;      }      count += len;    }    data = allocated;  }  tag = id3_tag_parse(data, tagsize); fail:  if (allocated)    free(allocated);  return tag;}/* * NAME:	decode->error() * DESCRIPTION:	handle a decoding error */staticenum mad_flow decode_error(void *data, struct mad_stream *stream,			   struct mad_frame *frame){  struct player *player = data;  signed long tagsize;  switch (stream->error) {  case MAD_ERROR_BADDATAPTR:    return MAD_FLOW_CONTINUE;  case MAD_ERROR_LOSTSYNC:    tagsize = id3_tag_query(stream->this_frame,			    stream->bufend - stream->this_frame);    if (tagsize > 0) {      if (player->options & PLAYER_OPTION_STREAMID3) {	struct id3_tag *tag;	tag = get_id3(stream, tagsize, &player->input);	if (tag) {	  process_id3(tag, player);	  id3_tag_delete(tag);	}      }      else	mad_stream_skip(stream, tagsize);      if (player->stats.total_bytes >= tagsize)	player->stats.total_bytes -= tagsize;      return MAD_FLOW_CONTINUE;    }    /* fall through */  default:    if (player->verbosity >= -1 &&	!(player->options & PLAYER_OPTION_SHOWTAGSONLY) &&	((stream->error == MAD_ERROR_LOSTSYNC && !player->input.eof)	 || stream->sync) &&	player->stats.global_framecount != player->stats.error_frame) {      error("error", _("frame %lu: %s"),	    player->stats.absolute_framecount, mad_stream_errorstr(stream));      player->stats.error_frame = player->stats.global_framecount;    }  }  if (stream->error == MAD_ERROR_BADCRC) {    if (player->stats.global_framecount == player->stats.mute_frame)      mad_frame_mute(frame);    player->stats.mute_frame = player->stats.global_framecount + 1;    return MAD_FLOW_IGNORE;  }  return MAD_FLOW_CONTINUE;}/* * NAME:	decode() * DESCRIPTION:	decode and output audio for an open file */staticint 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;  tag_init(&player->input.tag);  /* prepare input buffers */# if defined(HAVE_MMAP)  if (S_ISREG(stat.st_mode) && stat.st_size > 0) {    player->input.length = stat.st_size;    player->input.fdm = map_file(player->input.fd, player->input.length);    if (player->input.fdm == 0 && player->verbosity >= 0)      error("decode", ":mmap");    player->input.data = player->input.fdm;  }# endif  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,# if defined(HAVE_MMAP)		   player->input.fdm ? decode_input_mmap :# endif		   decode_input_read,		   decode_header, decode_filter,		   player->output.command ? decode_output : 0,		   decode_error, 0);  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 defined(HAVE_MMAP)  if (player->input.fdm) {    if (unmap_file(player->input.fdm, player->input.length) == -1) {      error("decode", ":munmap");      result = -1;    }    player->input.fdm = 0;    if (!player->input.eof)      player->input.data = 0;  }# endif  if (player->input.data) {    free(player->input.data);    player->input.data = 0;  }  tag_finish(&player->input.tag);  return result;}/* * NAME:	play_one() * DESCRIPTION:	open and play a single file */staticint 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;    player->input.fd   = open(file, O_RDONLY | O_BINARY);    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;  /* try reading ID3 tag information now (else read later from stream) */  {    int fd;    struct id3_file *file;    player->options &= ~PLAYER_OPTION_STREAMID3;    fd = dup(player->input.fd);    file = id3_file_fdopen(fd, ID3_FILE_MODE_READONLY);    if (file == 0) {      close(fd);      player->options |= PLAYER_OPTION_STREAMID3;    }    else {      process_id3(id3_file_tag(file), player);      id3_file_close(file);    }  }  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 */staticint 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;    return (count == 1) ? key : 0;  }# elif defined(_WIN32)  HANDLE console;  INPUT_RECORD input;  DWORD count;  console = GetStdHandle(STD_INPUT_HANDLE);  do {    if (GetNumberOfConsoleInputEvents(console, &count) == 0) {      error("tty", "GetNumberOfConsoleInputEvents() failed");      return -1;    }    if (count == 0) {      if (!blocking)	return 0;      else {	/* this is necessary to keep Windows from hanging (!) */	Sleep(500);	switch (WaitForSingleObject(console, INFINITE)) {	case WAIT_ABANDONED:	case WAIT_OBJECT_0:	  continue;	case WAIT_TIMEOUT:	default:	  /* ? */	case WAIT_FAILED:	  error("tty", "WaitForSingleObject() failed");	  return -1;	}      }    }    if (ReadConsoleInput(console, &input, 1, &count) == 0 || count != 1) {      error("tty", "ReadConsoleInput() failed");      return -1;    }  }  while (input.EventType != KEY_EVENT || !input.Event.KeyEvent.bKeyDown ||	 input.Event.KeyEvent.uChar.AsciiChar == 0);  return (unsigned char) input.Event.KeyEvent.uChar.AsciiChar;# endif  return blocking ? -1 : 0;}/* * NAME:	tty_filter() * DESCRIPTION:	process TTY commands */staticenum mad_flow tty_filter(void *data, struct mad_frame *frame){  struct player *player = data;  enum mad_flow flow = MAD_FLOW_CONTINUE;  int command, stopped = 0;  command = readkey(0);  if (command == -1)    return MAD_FLOW_BREAK; again:  switch (command) {  case KEY_STOP:    stopped = 1;

⌨️ 快捷键说明

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