shithub: aacdec

ref: 91c3d6d0e3f82f9ffddd3fd2e95ea7fafb403111
dir: /plugins/xmms/src/libaac.c/

View raw version
/*
**			  AAC plugin for XMMS 1.2.7
**				by ciberfred
**		------------------------------------------------
** The version of the plugin match the version of XMMS
** for identifie different version use the date :)
**
**			version 1.2.7 (23 august 2002)
**
**
**	       need faad2 package from http://www.audiocoding.com
**
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <glib.h>
#include <gtk/gtk.h>

#include "faad.h"
#include "xmms/plugin.h"
#include "xmms/util.h"
#include "xmms/configfile.h"
#include "xmms/titlestring.h"

#define AAC_DESCRIPTION	"MPEG2/4 AAC player - 1.2.7"
#define AAC_VERSION	"AAC player - 23 Agust 2002"
#define AAC_ABOUT	"Writen from scratch by ciberfred from France"
#define BUFFER_SIZE	FAAD_MIN_STREAMSIZE*64

static void aac_init(void);
static void aac_play(char*);
static void aac_stop(void);
static void aac_pause(short);
static int  aac_getTime(void);
static void aac_seek(int);
static void aac_cleanup(void);
static void aac_about(void);
static void *aac_decode(void*);

static void aac_getSongInfo(char*);
static int  aac_isFile(char*);

extern void readID3tag(char*);
extern GtkWidget *createDialogInfo(void);
static GtkWidget *infoBoxWindow = NULL;
extern char *title, *artist, *album, *track, *genre;
extern void clearWindowDatas(void);
/******************************************************************************/
/*
** struct need by xmms for Library Interface
*/

InputPlugin aac_ip =
{
	0,		// handle
	0,		// filename
	AAC_DESCRIPTION,// description
	aac_init,	// init_func
	aac_about,	// aboutbox
	0,		// configuration
	aac_isFile,	// ???
	0,		// scan dir
	aac_play,	// when play button
	aac_stop,	// when stop
	aac_pause,	// when pause
	aac_seek,	// when seek
	0,		// set equalizer
	aac_getTime,	// ???
	0,		// get volume
	0,		// set volume
	aac_cleanup,	// the cleanup function :)
	0,		// obsolete (???)
	0,		// send visualisation data
	0,		// set player window info
	0,		// set song title text
	0,	// get song title text to show on Playlist
	aac_getSongInfo,// file info box
	0		// pointer to outputPlugin
};
static gboolean 	bPlaying = FALSE;
static gboolean	bOutputOpen = FALSE;
static pthread_t	decodeThread;
static gint		seek_pos = -1; // the track position
static pthread_mutex_t	mutex = PTHREAD_MUTEX_INITIALIZER;

/******************************************************************************/

InputPlugin	*get_iplugin_info(void)
{
	return (&aac_ip);
}

static void aac_init(void)
{
	memset(&decodeThread, 0, sizeof(pthread_t));
}

static void aac_cleanup(void)
{
}

static void aac_play(char *filename)
{
	printf("play\n");
	bPlaying = TRUE;
	pthread_create(&decodeThread, 0, aac_decode, g_strdup(filename));
	return;
}

static void aac_stop(void)
{
	printf("stop\n");
	if (bPlaying){
		bPlaying = FALSE;
		pthread_join(decodeThread, NULL);
		memset(&decodeThread, 0, sizeof(pthread_t));
		aac_ip.output->close_audio();
		clearWindowDatas();
	}
}

static void aac_pause(short paused)
{
	printf("pause\n");
	if(bOutputOpen){
		aac_ip.output->pause(paused);
	}
}

static int aac_getTime(void)
{
	if (!bPlaying){
		return (-1);
	}
	else{
		return (aac_ip.output->output_time());
	}
}


static void aac_seek(int time)
{
	printf("seek\n");
}

static void aac_getSongInfo(char *filename)
{
	infoBoxWindow = createDialogInfo();
	gtk_widget_show(infoBoxWindow);
}

static void *aac_decode(void *args)
{
	char 			*filename = args;
	char			*xmmstitle=NULL;
	FILE 			*file = NULL;
	faacDecHandle		decoder = 0;
	unsigned char		*buffer = 0;
	unsigned long		bufferconsumed = 0;
	unsigned long		samplerate = 0;
	char			channels;
	unsigned long		buffervalid = 0;
	TitleInput		*input;
	char 			*temp = g_strdup(filename);
	char			*ext  = strrchr(temp, '.');

	printf("decoding...\n");
	pthread_mutex_lock(&mutex);
	clearWindowDatas();
	if ((file = fopen(filename, "rb")) == 0){
		printf("can't find file %s\n", filename);
		pthread_mutex_unlock(&mutex);
		pthread_exit(NULL);
	}
	if ((decoder = faacDecOpen()) == NULL){
		printf("Open Decoder Error\n");
		fclose(file);
		pthread_mutex_unlock(&mutex);
		pthread_exit(NULL);
	}
	if ((buffer = g_malloc(BUFFER_SIZE)) == NULL)
		printf("error g_malloc\n");
	buffervalid = fread(buffer, 1, BUFFER_SIZE, file);
// check for ID3 tag
		XMMS_NEW_TITLEINPUT(input);
		input->file_name = g_basename(temp);
		input->file_ext = ext ? ext+1 : NULL;
		input->file_path = temp;
	if (!strncmp(buffer, "ID3", 3)){
		int size = 0;

		printf("Song with a ID3Tagv2\n");
		readID3tag(filename);
		if(title)
		input->track_name = g_strdup(title);
		if(artist)
		input->performer = g_strdup(artist);
		if(genre)
		input->genre = g_strdup(genre);
		if(track)
		input->track_number = atoi(track);
		fseek(file, 0, SEEK_SET);
/*
** hum .. horrible hack taken from the winamp plugin to jump
** the tag, is there any id3 function to do this ???? hum... seems not :(
*/
		size = (buffer[6]<<21) | (buffer[7]<<14) | (buffer[8]<<7) | buffer[9];
		size+=10;
		fread(buffer, 1, size, file);
		buffervalid = fread(buffer, 1, BUFFER_SIZE, file);
	}
	xmmstitle = xmms_get_titlestring(xmms_get_gentitle_format(), input);
	if(xmmstitle == NULL)
		xmmstitle = g_strdup(input->file_name);
	g_free(temp);
	g_free(input->performer);
	g_free(input->album_name);
	g_free(input->track_name);
	g_free(input->genre);
	g_free(input);
	bufferconsumed = faacDecInit(decoder, buffer, &samplerate, &channels);
//	printf("song with %d channels at %d Hz\n", channels, samplerate);
	if((bOutputOpen = aac_ip.output->open_audio(FMT_S16_NE, samplerate, channels)) == FALSE){
		printf("Output Error\n");
		g_free(buffer);
		buffer=0;
		faacDecClose(decoder);
		fclose(file);
		aac_ip.output->close_audio();
		pthread_mutex_unlock(&mutex);
		pthread_exit(NULL);
	}
	aac_ip.set_info(xmmstitle, -1, -1, samplerate, channels);
	aac_ip.output->flush(0);

	while(bPlaying && buffervalid > 0){
		faacDecFrameInfo	finfo;
		unsigned long		samplesdecoded;
		char			*sample_buffer = NULL;

		if(bufferconsumed > 0){
		memmove(buffer, &buffer[bufferconsumed], buffervalid-bufferconsumed);
			buffervalid -= bufferconsumed;
			buffervalid += fread(&buffer[buffervalid], 1, BUFFER_SIZE-buffervalid, file);
			bufferconsumed = 0;
		}
		sample_buffer = faacDecDecode(decoder, &finfo, buffer);
		if(finfo.error){
			buffervalid = 0;
			printf("FAAD2 Error %s\n", faacDecGetErrorMessage(finfo.error));
			printf("---Use Psystrip.exe on the file to avoid the ADTS error---\n");
		}
		bufferconsumed += finfo.bytesconsumed;
		samplesdecoded = finfo.samples;
		if((samplesdecoded<=0) && !sample_buffer){
			printf("error\n");
		}
		while(bPlaying && aac_ip.output->buffer_free() < (samplesdecoded<<1)){
			xmms_usleep(10000);
		}
		aac_ip.add_vis_pcm(aac_ip.output->written_time(), FMT_S16_LE, channels, samplesdecoded<<1, sample_buffer);
		aac_ip.output->write_audio(sample_buffer, samplesdecoded<<1);
	}
	while(bPlaying && aac_ip.output->buffer_playing()){
		xmms_usleep(10000);
	}
//	aac_ip.output->flush(0);
	aac_ip.output->buffer_free();
	aac_ip.output->close_audio();
	bPlaying = FALSE;
	bOutputOpen = FALSE;
	g_free(buffer);
	faacDecClose(decoder);
	g_free(xmmstitle);
	fclose(file);
	printf("...ended\n");
	seek_pos = -1;
	pthread_mutex_unlock(&mutex);
	pthread_exit(NULL);
}

static int aac_isFile(char *filename)
{
	char *extention = strrchr(filename, '.');
	if (extention && !strcasecmp(extention, ".aac")){
		return (1);
	}
	return(0);
}

static void aac_about(void)
{
	GtkWidget *dialog, *button, *label, *label2;

	dialog = gtk_dialog_new();
	gtk_window_set_title(GTK_WINDOW(dialog), "About FAAD2 plugin");
	label = gtk_label_new(AAC_ABOUT);
	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), label, TRUE, TRUE, 0);
	gtk_widget_show(label);
	label2 = gtk_label_new(AAC_VERSION);
	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), label2, TRUE, TRUE, 0);
	gtk_widget_show(label2);
	button = gtk_button_new_with_label("close");
	gtk_signal_connect_object(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(dialog));
	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, FALSE, FALSE, 0);
	gtk_widget_show(button);
	gtk_widget_show(dialog);
}