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

📄 vorbis.c

📁 xmms-1.2.10.tar.gz学习使用的就下吧
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (C) Tony Arcieri <bascule@inferno.tusculum.edu> * Copyright (C) 2001-2002  Haavard Kvaalen <havardk@xmms.org> * * ReplayGain processing Copyright (C) 2002 Gian-Carlo Pascutto <gcp@sjeng.org> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * *//* * 2002-01-11 ReplayGain processing added by Gian-Carlo Pascutto <gcp@sjeng.org> *//* * Note that this uses vorbisfile, which is not (currently) * thread-safe. */#include "config.h"#include <stdio.h>#include <fcntl.h>#include <stdlib.h>#include <math.h>#include <string.h>#include <pthread.h>#include <glib.h>#include <gtk/gtk.h>#include <ogg/ogg.h>#include <vorbis/codec.h>#include <vorbis/vorbisfile.h>#include "xmms/plugin.h"#include "libxmms/util.h"#include "libxmms/configfile.h"#include "libxmms/titlestring.h"#include <xmms/i18n.h>#include "vorbis.h"#include "http.h"extern vorbis_config_t vorbis_cfg;static int vorbis_check_file(char *filename);static void vorbis_play(char *filename);static void vorbis_stop(void);static void vorbis_pause(short p);static void vorbis_seek(int time);static int vorbis_time(void);static void vorbis_get_song_info(char *filename, char **title, int *length);static gchar *vorbis_generate_title(OggVorbis_File *vorbisfile, char *fn);static void vorbis_aboutbox(void);static void vorbis_init(void);static long vorbis_process_replaygain(float **pcm, int samples, int ch, char *pcmout, float rg_scale);static gboolean vorbis_update_replaygain(float *scale);static size_t ovcb_read(void *ptr, size_t size, size_t nmemb, void *datasource);static int ovcb_seek(void *datasource, int64_t offset, int whence);static int ovcb_close(void *datasource);static long ovcb_tell(void *datasource);ov_callbacks vorbis_callbacks = {	ovcb_read,	ovcb_seek,	ovcb_close,	ovcb_tell};InputPlugin vorbis_ip ={	NULL,	NULL,	NULL,               /* description */	vorbis_init,        /* init */	vorbis_aboutbox,    /* aboutbox */	vorbis_configure,   /* configure */	vorbis_check_file,  /* is_our_file */	NULL,	vorbis_play,	vorbis_stop,	vorbis_pause,	vorbis_seek,	NULL,               /* set eq */	vorbis_time,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	vorbis_get_song_info,	vorbis_file_info_box,       /* file info box, tag editing */	NULL};static OggVorbis_File vf;static pthread_t tid;int vorbis_playing = 0;static int vorbis_eos = 0;static int vorbis_is_streaming = 0;static int vorbis_bytes_streamed = 0;static volatile int seekneeded = -1;static int samplerate, channels;pthread_mutex_t vf_mutex = PTHREAD_MUTEX_INITIALIZER;static gboolean output_error;	InputPlugin *get_iplugin_info(void){	vorbis_ip.description = g_strdup_printf(_("Ogg Vorbis Player %s"), VERSION);	return &vorbis_ip;}static int vorbis_check_file(char *filename){	FILE *stream;	OggVorbis_File vfile; /* avoid thread interaction */	char *ext;	/* is this our http resource? */	if (strncasecmp(filename, "http://", 7) == 0) {		ext = strrchr(filename, '.');		if (ext) {			if (!strncasecmp(ext, ".ogg", 4)) {				return TRUE;			}		}		return FALSE;	}   	if ((stream = fopen(filename, "r")) == NULL)		return FALSE;   	/*	 * The open function performs full stream detection and machine	 * initialization.  If it returns zero, the stream *is* Vorbis and	 * we're fully ready to decode.	 */	/* libvorbisfile isn't thread safe... */	memset(&vfile, 0, sizeof(vfile));	pthread_mutex_lock(&vf_mutex);	if (ov_open(stream, &vfile, NULL, 0) < 0)	{		pthread_mutex_unlock(&vf_mutex);		fclose(stream);		return FALSE;	}	ov_clear(&vfile); /* once the ov_open succeeds, the stream belongs to			     vorbisfile.a.  ov_clear will fclose it */	pthread_mutex_unlock(&vf_mutex);	return TRUE;}static void vorbis_jump_to_time(long time){	pthread_mutex_lock(&vf_mutex);	/*	 * We need to guard against seeking to the end, or things	 * don't work right.  Instead, just seek to one second prior	 * to this	 */	if (time == ov_time_total(&vf, -1))		time--;	vorbis_ip.output->flush(time * 1000);	ov_time_seek(&vf, time);		pthread_mutex_unlock(&vf_mutex);}#ifdef WORDS_BIGENDIAN#define XMMS_BIG_ENDIAN TRUE#define GET_BYTE1(val) ((val) >> 8)#define GET_BYTE2(val) ((val) & 0xff)#else#define XMMS_BIG_ENDIAN FALSE#define GET_BYTE1(val) ((val) & 0xff)#define GET_BYTE2(val) ((val) >> 8)#endifstatic void do_seek(void){	if (seekneeded != -1 && !vorbis_is_streaming) {		vorbis_jump_to_time(seekneeded);		seekneeded = -1;		vorbis_eos = FALSE;	}}static int vorbis_process_data(int last_section, gboolean use_rg, float rg_scale){	char pcmout[4096];	const int bep = XMMS_BIG_ENDIAN;	int bytes;	float **pcm;	/*	 * A vorbis physical bitstream may consist of many logical	 * sections (information for each of which may be fetched from	 * the vf structure).  This value is filled in by ov_read to	 * alert us what section we're currently decoding in case we	 * need to change playback settings at a section boundary	 */	int current_section;	pthread_mutex_lock(&vf_mutex);	if (use_rg)	{		bytes = ov_read_float(&vf, &pcm, sizeof(pcmout)/2/channels,				      &current_section);		if (bytes > 0)			bytes = vorbis_process_replaygain(pcm, bytes, channels,			                                  pcmout, rg_scale);	}	else		bytes = ov_read(&vf, pcmout, sizeof(pcmout), bep, 2, 1,				&current_section);	switch (bytes)	{		case 0:			/* EOF */			pthread_mutex_unlock(&vf_mutex);			vorbis_ip.output->buffer_free();			vorbis_ip.output->buffer_free();			vorbis_eos = TRUE;			return last_section;		case OV_HOLE:		case OV_EBADLINK:			/*			 * error in the stream.  Not a problem, just			 * reporting it in case we (the app) cares.			 * In this case, we don't.			 */			pthread_mutex_unlock(&vf_mutex);			return last_section;	}	if (current_section != last_section)	{		/*		 * The info struct is different in each section.  vf		 * holds them all for the given bitstream.  This		 * requests the current one		 */		vorbis_info* vi = ov_info(&vf, -1);		if (vi->channels > 2)		{			vorbis_eos = TRUE;			pthread_mutex_unlock(&vf_mutex);			return current_section;		}				if (vi->rate != samplerate || vi->channels != channels)		{			samplerate = vi->rate;			channels = vi->channels;			vorbis_ip.output->buffer_free();			vorbis_ip.output->buffer_free();			vorbis_ip.output->close_audio();			if (!vorbis_ip.output->			    open_audio(FMT_S16_NE, vi->rate,				       vi->channels))			{				output_error = TRUE;				vorbis_eos = TRUE;				pthread_mutex_unlock(&vf_mutex);				return current_section;			}			vorbis_ip.output->flush(ov_time_tell(&vf) * 1000);		}	}	pthread_mutex_unlock(&vf_mutex);	vorbis_ip.add_vis_pcm(vorbis_ip.output->written_time(), 			      FMT_S16_NE, channels, bytes, pcmout);     	while (vorbis_ip.output->buffer_free() < bytes)	{		xmms_usleep(20000);		if (!vorbis_playing)			return current_section;		if (seekneeded != -1)			do_seek();	}	vorbis_ip.output->write_audio(pcmout, bytes);	return current_section;}static void *vorbis_play_loop(void *arg){	char *filename = (char *)arg;	gchar *title = NULL;	double time;	long timercount = 0;	vorbis_info *vi;	int last_section = -1;	FILE *stream = NULL;	void *datasource = NULL;	gboolean use_rg;	float rg_scale;	memset(&vf, 0, sizeof(vf));	if (strncasecmp("http://", filename, 7) != 0) {		/* file is a real file */		if ((stream = fopen(filename, "r")) == NULL) {			vorbis_eos = TRUE;			goto play_cleanup;		}		datasource = (void *)stream;	} else {		/* file is a stream */		vorbis_is_streaming = 1;		vorbis_http_open(filename);		datasource = "NULL";	}	/*	 * The open function performs full stream detection and	 * machine initialization.  None of the rest of ov_xx() works	 * without it	 */	pthread_mutex_lock(&vf_mutex);	if (ov_open_callbacks(datasource, &vf, NULL, 0, vorbis_callbacks) < 0)	{		vorbis_callbacks.close_func(datasource);		pthread_mutex_unlock(&vf_mutex);		vorbis_eos = TRUE;		goto play_cleanup;	}	vi = ov_info(&vf, -1);	if (vorbis_is_streaming) 		time = -1;	else		time = ov_time_total(&vf, -1) * 1000;	if (vi->channels > 2) {		vorbis_eos = TRUE;		pthread_mutex_unlock(&vf_mutex);		goto play_cleanup;	}	samplerate = vi->rate;	channels = vi->channels;   	title = vorbis_generate_title(&vf, filename);	use_rg = vorbis_update_replaygain(&rg_scale);	vorbis_ip.set_info(title, time, ov_bitrate(&vf, -1), samplerate, channels);	if (!vorbis_ip.output->open_audio(FMT_S16_NE, vi->rate, vi->channels))	{		output_error = TRUE;		pthread_mutex_unlock(&vf_mutex);		goto play_cleanup;	}	pthread_mutex_unlock(&vf_mutex);	seekneeded = -1;   	/*	 * Note that chaining changes things here; A vorbis file may	 * be a mix of different channels, bitrates and sample rates.	 * You can fetch the information for any section of the file	 * using the ov_ interface.	 */	while (vorbis_playing)	{		int current_section;		if (seekneeded != -1)			do_seek();		if (vorbis_eos)		{			xmms_usleep(20000);			continue;		}					current_section = vorbis_process_data(last_section,						      use_rg, rg_scale);		if (current_section != last_section)		{			/*			 * set total play time, bitrate, rate, and channels of			 * current section			 */			if (title)				g_free(title);			pthread_mutex_lock(&vf_mutex);			title = vorbis_generate_title(&vf, filename);			use_rg = vorbis_update_replaygain(&rg_scale);			if (vorbis_is_streaming)				time = -1;			else				time = ov_time_total(&vf, -1) * 1000;			vorbis_ip.set_info(title, time,					   ov_bitrate(&vf, current_section), 					   samplerate, channels);

⌨️ 快捷键说明

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