📄 mpg123.c
字号:
/* * Function mpg123_get_id3v2 (id3d, tag) * * Get desired contents from the indicated id3tag and store it in * `tag'. * */void mpg123_get_id3v2(struct id3_tag *id3d, struct id3tag_t *tag){ struct id3_frame *id3frm; gchar *txt; gint tlen, num;#define ID3_SET(_tid,_fld) \{ \ id3frm = id3_get_frame( id3d, _tid, 1 ); \ if (id3frm) { \ txt = _tid == ID3_TCON ? id3_get_content(id3frm) \ : id3_get_text(id3frm); \ if(txt) \ { \ tlen = strlen(txt); \ if ( tlen >= sizeof(tag->_fld) ) \ tlen = sizeof(tag->_fld)-1; \ strncpy( tag->_fld, txt, tlen ); \ tag->_fld[tlen] = 0; \ g_free(txt); \ } \ else \ tag->_fld[0] = 0; \ } else { \ tag->_fld[0] = 0; \ } \}#define ID3_SET_NUM(_tid,_fld) \{ \ id3frm = id3_get_frame(id3d, _tid, 1); \ if (id3frm) { \ num = id3_get_text_number(id3frm); \ tag->_fld = num >= 0 ? num : 0; \ } else \ tag->_fld = 0; \} ID3_SET (ID3_TIT2, title); ID3_SET (ID3_TPE1, artist); if (strlen(tag->artist) == 0) ID3_SET(ID3_TPE2, artist); ID3_SET (ID3_TALB, album); ID3_SET_NUM (ID3_TYER, year); ID3_SET_NUM (ID3_TRCK, track_number); ID3_SET (ID3_COMM, comment); ID3_SET (ID3_TCON, genre);}/* * Function get_song_title (fd, filename) * * Get song title of file. File position of `fd' will be * clobbered. `fd' may be NULL, in which case `filename' is opened * separately. The returned song title must be subsequently freed * using g_free(). * */static gchar *get_song_title(FILE * fd, char *filename){ FILE *file = fd; char *ret = NULL; struct id3v1tag_t id3v1tag; struct id3tag_t id3tag; if (file || (file = fopen(filename, "rb")) != 0) { struct id3_tag *id3 = NULL; /* * Try reading ID3v2 tag. */ if (!mpg123_cfg.disable_id3v2) { fseek(file, 0, SEEK_SET); id3 = id3_open_fp(file, 0); if (id3) { mpg123_get_id3v2(id3, &id3tag); ret = mpg123_format_song_title(&id3tag, filename); id3_close(id3); } } /* * Try reading ID3v1 tag. */ if (!id3 && (fseek(file, -1 * sizeof (id3v1tag), SEEK_END) == 0) && (fread(&id3v1tag, 1, sizeof (id3v1tag), file) == sizeof (id3v1tag)) && (strncmp(id3v1tag.tag, "TAG", 3) == 0)) { mpg123_id3v1_to_id3v2(&id3v1tag, &id3tag); ret = mpg123_format_song_title(&id3tag, filename); } if (!fd) /* * File was opened in this function. */ fclose(file); } if (ret == NULL) /* * Unable to get ID3 tag. */ ret = mpg123_format_song_title(NULL, filename); return ret;}static long get_song_length(FILE *file){ int len; char tmp[4]; fseek(file, 0, SEEK_END); len = ftell(file); fseek(file, -128, SEEK_END); fread(tmp, 1, 3, file); if (!strncmp(tmp, "TAG", 3)) len -= 128; return len;}static guint get_song_time(FILE * file){ guint32 head; guchar tmp[4], *buf; struct frame frm; xing_header_t xing_header; double tpf, bpf; guint32 len; if (!file) return -1; fseek(file, 0, SEEK_SET); if (fread(tmp, 1, 4, file) != 4) return 0; head = convert_to_header(tmp); while (!mpg123_head_check(head)) { head <<= 8; if (fread(tmp, 1, 1, file) != 1) return 0; head |= tmp[0]; } if (mpg123_decode_header(&frm, head)) { buf = g_malloc(frm.framesize + 4); fseek(file, -4, SEEK_CUR); fread(buf, 1, frm.framesize + 4, file); tpf = mpg123_compute_tpf(&frm); if (mpg123_get_xing_header(&xing_header, buf)) { g_free(buf); if (xing_header.bytes == 0) xing_header.bytes = get_song_length(file); return (tpf * xing_header.frames * 1000); } g_free(buf); bpf = mpg123_compute_bpf(&frm); len = get_song_length(file); return ((guint)(len / bpf) * tpf * 1000); } return 0;}static void get_song_info(char *filename, char **title_real, int *len_real){ FILE *file; (*len_real) = -1; (*title_real) = NULL; /* * TODO: Getting song info from http streams. */ if (strncasecmp(filename, "http://", 7)) { if ((file = fopen(filename, "rb")) != NULL) { (*len_real) = get_song_time(file); (*title_real) = get_song_title(file, filename); fclose(file); } }}static int open_output(void){ int r; AFormat fmt = mpg123_cfg.resolution == 16 ? FMT_S16_NE : FMT_U8; int freq = mpg123_freqs[fr.sampling_frequency] >> mpg123_cfg.downsample; int channels = mpg123_cfg.channels == 2 ? fr.stereo : 1; r = mpg123_ip.output->open_audio(fmt, freq, channels); if (r && dopause) { mpg123_ip.output->pause(TRUE); dopause = FALSE; } return r;}static int mpg123_seek(struct frame *fr, xing_header_t *xh, gboolean vbr, int time){ int jumped = -1; if (xh) { int percent = ((double) time * 100.0) / (mpg123_info->num_frames * mpg123_info->tpf); int byte = mpg123_seek_point(xh, percent); jumped = mpg123_stream_jump_to_byte(fr, byte); } else if (vbr && mpg123_length > 0) { int byte = ((guint64)time * 1000 * mpg123_info->filesize) / mpg123_length; jumped = mpg123_stream_jump_to_byte(fr, byte); } else { int frame = time / mpg123_info->tpf; jumped = mpg123_stream_jump_to_frame(fr, frame); } return jumped;}static void *decode_loop(void *arg){ gboolean have_xing_header = FALSE, vbr = FALSE; int disp_count = 0, temp_time; char *filename = arg; xing_header_t xing_header; /* This is used by fileinfo on http streams */ mpg123_bitrate = 0; mpg123_pcm_sample = g_malloc0(32768); mpg123_pcm_point = 0; mpg123_filename = filename; mpg123_read_frame_init(); mpg123_open_stream(filename, -1); if (mpg123_info->eof || !mpg123_read_frame(&fr)) mpg123_info->eof = TRUE; if (!mpg123_info->eof && mpg123_info->going) { if (mpg123_cfg.channels == 2) fr.single = -1; else fr.single = 3; fr.down_sample = mpg123_cfg.downsample; fr.down_sample_sblimit = SBLIMIT >> mpg123_cfg.downsample; set_synth_functions(&fr); mpg123_init_layer3(fr.down_sample_sblimit); mpg123_info->tpf = mpg123_compute_tpf(&fr); if (strncasecmp(filename, "http://", 7)) { if (mpg123_stream_check_for_xing_header(&fr, &xing_header)) { mpg123_info->num_frames = xing_header.frames; have_xing_header = TRUE; if (xing_header.bytes == 0) { if (mpg123_info->filesize > 0) xing_header.bytes = mpg123_info->filesize; else have_xing_header = FALSE; } mpg123_read_frame(&fr); } } for (;;) { memcpy(&temp_fr, &fr, sizeof(struct frame)); if (!mpg123_read_frame(&temp_fr)) { mpg123_info->eof = TRUE; break; } if (fr.lay != temp_fr.lay || fr.sampling_frequency != temp_fr.sampling_frequency || fr.stereo != temp_fr.stereo || fr.lsf != temp_fr.lsf) memcpy(&fr,&temp_fr,sizeof(struct frame)); else break; } if (!have_xing_header && strncasecmp(filename, "http://", 7)) mpg123_info->num_frames = mpg123_calc_numframes(&fr); memcpy(&fr, &temp_fr, sizeof(struct frame)); mpg123_bitrate = tabsel_123[fr.lsf][fr.lay - 1][fr.bitrate_index]; disp_bitrate = mpg123_bitrate; mpg123_frequency = mpg123_freqs[fr.sampling_frequency]; mpg123_stereo = fr.stereo; mpg123_layer = fr.lay; mpg123_lsf = fr.lsf; mpg123_mpeg25 = fr.mpeg25; mpg123_mode = fr.mode; if (strncasecmp(filename, "http://", 7)) { mpg123_length = mpg123_info->num_frames * mpg123_info->tpf * 1000; if (!mpg123_title) mpg123_title = get_song_title(NULL,filename); } else { if (!mpg123_title) mpg123_title = mpg123_http_get_title(filename); mpg123_length = -1; } mpg123_ip.set_info(mpg123_title, mpg123_length, mpg123_bitrate * 1000, mpg123_freqs[fr.sampling_frequency], fr.stereo); output_opened = TRUE; if (!open_output()) { audio_error = TRUE; mpg123_info->eof = TRUE; } else play_frame(&fr); } mpg123_info->first_frame = FALSE; while (mpg123_info->going) { if (mpg123_info->jump_to_time != -1) { void *xp = NULL; if (have_xing_header) xp = &xing_header; if (mpg123_seek(&fr, xp, vbr, mpg123_info->jump_to_time) > -1) { mpg123_ip.output->flush(mpg123_info->jump_to_time * 1000); mpg123_info->eof = FALSE; } mpg123_info->jump_to_time = -1; } if (!mpg123_info->eof) { if (mpg123_read_frame(&fr) != 0) { if(fr.lay != mpg123_layer || fr.lsf != mpg123_lsf) { memcpy(&temp_fr, &fr, sizeof(struct frame)); if(mpg123_read_frame(&temp_fr) != 0) { if(fr.lay == temp_fr.lay && fr.lsf == temp_fr.lsf) { mpg123_layer = fr.lay; mpg123_lsf = fr.lsf; memcpy(&fr,&temp_fr,sizeof(struct frame)); } else { memcpy(&fr,&temp_fr,sizeof(struct frame)); skip_frames = 2; mpg123_info->output_audio = FALSE; continue; } } } if(mpg123_freqs[fr.sampling_frequency] != mpg123_frequency || mpg123_stereo != fr.stereo) { memcpy(&temp_fr,&fr,sizeof(struct frame)); if(mpg123_read_frame(&temp_fr) != 0) { if(fr.sampling_frequency == temp_fr.sampling_frequency && temp_fr.stereo == fr.stereo) { mpg123_ip.output->buffer_free(); mpg123_ip.output->buffer_free(); while(mpg123_ip.output->buffer_playing() && mpg123_info->going && mpg123_info->jump_to_time == -1) xmms_usleep(20000); if(!mpg123_info->going) break; temp_time = mpg123_ip.output->output_time(); mpg123_ip.output->close_audio(); mpg123_frequency = mpg123_freqs[fr.sampling_frequency]; mpg123_stereo = fr.stereo; if (!mpg123_ip.output->open_audio(mpg123_cfg.resolution == 16 ? FMT_S16_NE : FMT_U8, mpg123_freqs[fr.sampling_frequency] >> mpg123_cfg.downsample, mpg123_cfg.channels == 2 ? fr.stereo : 1)) { audio_error = TRUE; mpg123_info->eof = TRUE; } mpg123_ip.output->flush(temp_time); mpg123_ip.set_info(mpg123_title, mpg123_length, mpg123_bitrate * 1000, mpg123_frequency, mpg123_stereo); memcpy(&fr,&temp_fr,sizeof(struct frame)); } else { memcpy(&fr,&temp_fr,sizeof(struct frame)); skip_frames = 2; mpg123_info->output_audio = FALSE; continue; } } } if (tabsel_123[fr.lsf][fr.lay - 1][fr.bitrate_index] != mpg123_bitrate) mpg123_bitrate = tabsel_123[fr.lsf][fr.lay - 1][fr.bitrate_index]; if (!disp_count) { disp_count = 20; if (mpg123_bitrate != disp_bitrate) { /* FIXME networks streams */ disp_bitrate = mpg123_bitrate; if(!have_xing_header && strncasecmp(filename,"http://",7)) { double rel = mpg123_relative_pos(); if (rel) { mpg123_length = mpg123_ip.output->written_time() / rel; vbr = TRUE; } if (rel == 0 || !(mpg123_length > 0)) { mpg123_info->num_frames = mpg123_calc_numframes(&fr); mpg123_info->tpf = mpg123_compute_tpf(&fr); mpg123_length = mpg123_info->num_frames * mpg123_info->tpf * 1000; } } mpg123_ip.set_info(mpg123_title, mpg123_length, mpg123_bitrate * 1000, mpg123_frequency, mpg123_stereo); } } else disp_count--; play_frame(&fr); } else { mpg123_ip.output->buffer_free(); mpg123_ip.output->buffer_free(); mpg123_info->eof = TRUE; xmms_usleep(10000); } } else { xmms_usleep(10000); } } g_free(mpg123_title); mpg123_title = NULL; mpg123_stream_close(); if (output_opened && !audio_error) mpg123_ip.output->close_audio(); g_free(mpg123_pcm_sample); mpg123_filename = NULL; g_free(filename); pthread_exit(NULL);}static void play_file(char *filename){ memset(&fr, 0, sizeof (struct frame)); memset(&temp_fr, 0, sizeof (struct frame)); mpg123_info = g_malloc0(sizeof (PlayerInfo)); mpg123_info->going = 1; mpg123_info->first_frame = TRUE; mpg123_info->output_audio = TRUE; mpg123_info->jump_to_time = -1; skip_frames = 0; audio_error = FALSE; output_opened = FALSE; dopause = FALSE; pthread_create(&decode_thread, NULL, decode_loop, g_strdup(filename));}static void stop(void){ if (mpg123_info && mpg123_info->going) { mpg123_info->going = FALSE; pthread_join(decode_thread, NULL); g_free(mpg123_info); mpg123_info = NULL; }}static void seek(int time){ mpg123_info->jump_to_time = time; while (mpg123_info->jump_to_time != -1) xmms_usleep(10000);}static void do_pause(short p){ if (output_opened) mpg123_ip.output->pause(p); else dopause = p;}static int get_time(void){ if (audio_error) return -2; if (!mpg123_info) return -1; if (!mpg123_info->going || (mpg123_info->eof && !mpg123_ip.output->buffer_playing())) return -1; return mpg123_ip.output->output_time();}static void aboutbox(void){ static GtkWidget *aboutbox; if (aboutbox != NULL) return; aboutbox = xmms_show_message( _("About MPEG Layer 1/2/3 plugin"), _("mpg123 decoding engine by Michael Hipp <mh@mpg123.de>\n" "Plugin by The XMMS team"), _("Ok"), FALSE, NULL, NULL); gtk_signal_connect(GTK_OBJECT(aboutbox), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &aboutbox);}InputPlugin mpg123_ip ={ NULL, NULL, NULL, /* Description */ init, aboutbox, mpg123_configure, is_our_file, NULL, play_file, stop, do_pause, seek, mpg123_set_eq, get_time, NULL, NULL, NULL, NULL, NULL, NULL, NULL, get_song_info, mpg123_file_info_box, /* file_info_box */ NULL};InputPlugin *get_iplugin_info(void){ mpg123_ip.description = g_strdup_printf(_("MPEG Layer 1/2/3 Player %s"), VERSION); return &mpg123_ip;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -