changeset 489:ce4efa148521 trunk

[svn] flac 112 plugin: playback and detection use vfs; current situation is pretty similar to the one of flac 113 plugin
author giacomo
date Sun, 21 Jan 2007 15:15:38 -0800
parents 5e375eca97da
children be4cde738a73
files ChangeLog src/flac112/plugin.c src/flac112/plugin_common/tags.c
diffstat 3 files changed, 199 insertions(+), 62 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Sun Jan 21 11:17:52 2007 -0800
+++ b/ChangeLog	Sun Jan 21 15:15:38 2007 -0800
@@ -1,3 +1,10 @@
+2007-01-21 19:17:52 +0000  Giacomo Lozito <james@develia.org>
+  revision [1062]
+  - flac 113 plugin: allow to do seek and other operations on http sources
+  trunk/src/flac113/plugin.c |   28 ++++++++--------------------
+  1 file changed, 8 insertions(+), 20 deletions(-)
+
+
 2007-01-21 19:00:54 +0000  Giacomo Lozito <james@develia.org>
   revision [1060]
   - flac 113 plugin: placed a label in configure dialog, explaning that stream options are currently ignored
--- a/src/flac112/plugin.c	Sun Jan 21 11:17:52 2007 -0800
+++ b/src/flac112/plugin.c	Sun Jan 21 15:15:38 2007 -0800
@@ -24,12 +24,12 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include "audacious/plugin.h"
-#include "audacious/output.h"
-#include "audacious/util.h"
-#include "audacious/configdb.h"
-#include "audacious/titlestring.h"
-#include "audacious/vfs.h"
+#include <audacious/plugin.h>
+#include <audacious/output.h>
+#include <audacious/util.h>
+#include <audacious/configdb.h>
+#include <audacious/titlestring.h>
+#include <audacious/vfs.h>
 
 #ifdef HAVE_CONFIG_H
 #include <config.h>
@@ -79,6 +79,7 @@
 	FLAC__bool has_replaygain;
 	double replay_scale;
 	DitherContext dither_context;
+	VFSFile *vfsfile;
 } file_info_struct;
 
 typedef FLAC__StreamDecoderWriteStatus (*WriteCallback) (const void *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
@@ -88,8 +89,9 @@
 typedef struct {
 	FLAC__bool seekable;
 	void* (*new_decoder) (void);
+	FLAC__bool (*set_source) (void *decoder, const char* source);
+	FLAC__bool (*unset_source) (void *decoder);
 	FLAC__bool (*set_md5_checking) (void *decoder, FLAC__bool value);
-	FLAC__bool (*set_source) (void *decoder, const char* source);
 	FLAC__bool (*set_metadata_ignore_all) (void *decoder);
 	FLAC__bool (*set_metadata_respond) (void *decoder, FLAC__MetadataType type);
 	FLAC__bool (*set_write_callback) (void *decoder, WriteCallback value);
@@ -112,6 +114,7 @@
 
 static void FLAC_XMMS__init();
 static int  FLAC_XMMS__is_our_file(char *filename);
+static int  FLAC_XMMS__is_our_file_from_vfs(char *filename, VFSFile *vfsfile);
 static void FLAC_XMMS__play_file(char *filename);
 static void FLAC_XMMS__stop();
 static void FLAC_XMMS__pause(short p);
@@ -163,7 +166,7 @@
 	flac_get_tuple,
         NULL,		// set tuple
         NULL,
-	NULL,
+	FLAC_XMMS__is_our_file_from_vfs,
 	flac_fmts,
 };
 
@@ -302,31 +305,40 @@
 	bmp_cfg_db_close(db);
 }
 
+int FLAC_XMMS__is_our_file_from_vfs( gchar * filename , VFSFile * vfsfile )
+{
+	gchar magic_bytes[4];
+
+	if ( vfsfile == NULL )
+		return 0;
+
+	if ( vfs_fread( magic_bytes , 1 , 4 , vfsfile ) != 4 )
+		return 0;
+
+	if ( !strncmp( magic_bytes , "fLaC" , 4 ) )
+		return 1;
+	else
+		return 0;
+}
+
 int FLAC_XMMS__is_our_file(char *filename)
 {
-	FILE *f;
-	FLAC__StreamMetadata streaminfo;
+	VFSFile *vfsfile;
+	gint result = 0;
+
+	vfsfile = vfs_fopen( filename , "rb" );
 
-        if (source_to_decoder_type (filename) == DECODER_FILE) {
-                if(0 == (f = fopen(filename, "r")))
-                        return 0;
-                fclose(f);
-	        if(!FLAC__metadata_get_streaminfo(filename, &streaminfo))
-			return 0;
-		return 1;
-        }
+	if ( vfsfile == NULL ) return 0;
+
+	result = FLAC_XMMS__is_our_file_from_vfs( filename , vfsfile );
 
-	if(!safe_decoder_init_(filename, &decoder2, &decoder_func_table2))
-		return 0;
+	vfs_fclose( vfsfile );
 
-	decoder_func_table2 -> safe_decoder_finish(decoder2);	
-	return 1;
+	return result;
 }
 
 void FLAC_XMMS__play_file(char *filename)
 {
-	FILE *f;
-
 	sample_buffer_first_ = sample_buffer_last_ = 0;
 	audio_error_ = false;
 	file_info_.abort_flag = false;
@@ -335,12 +347,6 @@
 	file_info_.play_thread_open = false;
 	file_info_.has_replaygain = false;
 
-	if (source_to_decoder_type (filename) == DECODER_FILE) {
-		if(0 == (f = fopen(filename, "r")))
-			return;
-		fclose(f);
-	}
-
 	if(decoder_ == 0)
 		return;
 
@@ -529,7 +535,7 @@
 				}
 				blocksize = sample_buffer_last_ - sample_buffer_first_ - s;
 				decode_position_frame_last = decode_position_frame;
-				if(!decoder_func_table_->seekable || !FLAC__file_decoder_get_decode_position(decoder_, &decode_position_frame))
+				if(!decoder_func_table_->seekable || !FLAC__seekable_stream_decoder_get_decode_position(decoder_, &decode_position_frame))
 					decode_position_frame = 0;
 			}
 			if(sample_buffer_last_ - sample_buffer_first_ > 0) {
@@ -571,10 +577,10 @@
 		if(decoder_func_table_->seekable && file_info_.seek_to_in_sec != -1) {
 			const double distance = (double)file_info_.seek_to_in_sec * 1000.0 / (double)file_info_.length_in_msec;
 			unsigned target_sample = (unsigned)(distance * (double)file_info_.total_samples);
-			if(FLAC__file_decoder_seek_absolute(decoder_, (FLAC__uint64)target_sample)) {
+			if(FLAC__seekable_stream_decoder_seek_absolute(decoder_, (FLAC__uint64)target_sample)) {
 				flac_ip.output->flush(file_info_.seek_to_in_sec * 1000);
 				bh_index_last_w = bh_index_last_o = flac_ip.output->output_time() / BITRATE_HIST_SEGMENT_MSEC % BITRATE_HIST_SIZE;
-				if(!FLAC__file_decoder_get_decode_position(decoder_, &decode_position_frame))
+				if(!FLAC__seekable_stream_decoder_get_decode_position(decoder_, &decode_position_frame))
 					decode_position_frame = 0;
 				file_info_.seek_to_in_sec = -1;
 				file_info_.eof = false;
@@ -605,60 +611,156 @@
 
 /*********** File decoder functions */
 
-static FLAC__bool file_decoder_init (void *decoder)
+static FLAC__bool file_decoder_unset_source(void *decoder)
 {
-	return FLAC__file_decoder_init( (FLAC__FileDecoder*) decoder) == FLAC__FILE_DECODER_OK;
+	if ( file_info_.vfsfile != NULL )
+	{
+		vfs_fclose( file_info_.vfsfile );
+		file_info_.vfsfile = NULL;
+	}
 }
 
 static void file_decoder_safe_decoder_finish_(void *decoder)
 {
-	if(decoder && FLAC__file_decoder_get_state((FLAC__FileDecoder *) decoder) != FLAC__FILE_DECODER_UNINITIALIZED)
-		FLAC__file_decoder_finish((FLAC__FileDecoder *) decoder);
+	file_decoder_unset_source(decoder);
+	if(decoder && FLAC__seekable_stream_decoder_get_state((FLAC__SeekableStreamDecoder *) decoder) != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED)
+		FLAC__seekable_stream_decoder_finish((FLAC__SeekableStreamDecoder *) decoder);
 }
 
 static void file_decoder_safe_decoder_delete_(void *decoder)
 {
 	if(decoder) {
 		file_decoder_safe_decoder_finish_(decoder);
-		FLAC__file_decoder_delete( (FLAC__FileDecoder *) decoder);
+		FLAC__seekable_stream_decoder_delete( (FLAC__SeekableStreamDecoder *) decoder);
 	}
 }
 
 static FLAC__bool file_decoder_is_eof(void *decoder)
 {
-	return FLAC__file_decoder_get_state((FLAC__FileDecoder *) decoder) == FLAC__FILE_DECODER_END_OF_FILE;
+	return FLAC__seekable_stream_decoder_get_state((FLAC__SeekableStreamDecoder *) decoder) == FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM;
+}
+
+static FLAC__bool file_decoder_set_source(void *decoder, const char *filename)
+{
+	if ( ( file_info_.vfsfile = vfs_fopen( filename , "rb" ) ) == NULL )
+		return false;
+	else
+		return true;
+}
+
+static FLAC__SeekableStreamDecoderReadStatus file_decoder_read_callback (const FLAC__SeekableStreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data)
+{
+	file_info_struct *file_info = (file_info_struct *)client_data;
+	(void) decoder;
+
+	if( *bytes > 0 )
+	{
+		*bytes = vfs_fread( buffer , sizeof(FLAC__byte) , *bytes , file_info->vfsfile );
+		if ( *bytes == 0 )
+			 return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR;
+		else
+			return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK;
+	}
+	else
+		return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR;	
+}
+
+static FLAC__SeekableStreamDecoderSeekStatus file_decoder_seek_callback(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data)
+{
+	file_info_struct *file_info = (file_info_struct *)client_data;
+	(void) decoder;
+
+	if ( vfs_fseek( file_info->vfsfile , (glong)absolute_byte_offset , SEEK_SET ) < 0 )
+		return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR;
+	else
+		return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK;
+}
+
+static FLAC__SeekableStreamDecoderTellStatus file_decoder_tell_callback(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+{
+	file_info_struct *file_info = (file_info_struct *)client_data;
+	glong pos;
+	(void)decoder;
+
+	if ( (pos = vfs_ftell(file_info->vfsfile)) < 0 )
+		return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_ERROR;
+	else
+	{
+		*absolute_byte_offset = (FLAC__uint64)pos;
+		return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK;
+	}
+}
+
+static FLAC__SeekableStreamDecoderLengthStatus file_decoder_length_callback(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data)
+{
+	file_info_struct *file_info = (file_info_struct *)client_data;
+	glong current_pos = 0;
+	glong length = 0;
+	(void)decoder;
+
+	current_pos = vfs_ftell(file_info->vfsfile);
+	if ( current_pos < 0 )
+		return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_ERROR;
+
+	if ( vfs_fseek( file_info->vfsfile , 0 , SEEK_END ) < 0 )
+		return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_ERROR;
+
+	length = vfs_ftell(file_info->vfsfile);
+	if ( length < 0 )
+		return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_ERROR;
+
+	/* put back stream position */
+	if ( vfs_fseek( file_info->vfsfile , current_pos , SEEK_SET ) < 0 )
+		return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_ERROR;
+	else
+	{
+		*stream_length = (FLAC__uint64)length;
+		return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK;
+	}
+}
+
+static FLAC__bool file_decoder_eof_callback (const FLAC__SeekableStreamDecoder *decoder, void *client_data)
+{
+	file_info_struct *file_info = (file_info_struct *)client_data;
+	(void)decoder;
+
+	return vfs_feof( file_info->vfsfile );
+}
+
+static FLAC__bool file_decoder_init (void *decoder)
+{
+	gint result = 0;
+	FLAC__seekable_stream_decoder_set_read_callback(decoder, file_decoder_read_callback);
+	FLAC__seekable_stream_decoder_set_seek_callback(decoder, file_decoder_seek_callback);
+	FLAC__seekable_stream_decoder_set_tell_callback(decoder, file_decoder_tell_callback);
+	FLAC__seekable_stream_decoder_set_length_callback(decoder, file_decoder_length_callback);
+	FLAC__seekable_stream_decoder_set_eof_callback(decoder, file_decoder_eof_callback);
+	return FLAC__seekable_stream_decoder_init( (FLAC__SeekableStreamDecoder*) decoder) == FLAC__SEEKABLE_STREAM_DECODER_OK;
 }
 
 static const decoder_funcs_t FILE_DECODER_FUNCTIONS = {
 	true,
-	(void* (*) (void)) FLAC__file_decoder_new,
-	(FLAC__bool (*) (void *, FLAC__bool)) FLAC__file_decoder_set_md5_checking,
-	(FLAC__bool (*) (void *, const char*)) FLAC__file_decoder_set_filename,
-	(FLAC__bool (*) (void *)) FLAC__file_decoder_set_metadata_ignore_all,
-	(FLAC__bool (*) (void *, FLAC__MetadataType)) FLAC__file_decoder_set_metadata_respond,
-	(FLAC__bool (*) (void *, WriteCallback)) FLAC__file_decoder_set_write_callback,
-	(FLAC__bool (*) (void *, MetadataCallback)) FLAC__file_decoder_set_metadata_callback,
-	(FLAC__bool (*) (void *, ErrorCallback)) FLAC__file_decoder_set_error_callback,
-	(FLAC__bool (*) (void *, void *)) FLAC__file_decoder_set_client_data,
+	(void* (*) (void)) FLAC__seekable_stream_decoder_new,
+	(FLAC__bool (*) (void *, const char*)) file_decoder_set_source,
+	(FLAC__bool (*) (void *)) file_decoder_unset_source,
+	(FLAC__bool (*) (void *, FLAC__bool)) FLAC__seekable_stream_decoder_set_md5_checking,
+	(FLAC__bool (*) (void *)) FLAC__seekable_stream_decoder_set_metadata_ignore_all,
+	(FLAC__bool (*) (void *, FLAC__MetadataType)) FLAC__seekable_stream_decoder_set_metadata_respond,
+	(FLAC__bool (*) (void *, WriteCallback)) FLAC__seekable_stream_decoder_set_write_callback,
+	(FLAC__bool (*) (void *, MetadataCallback)) FLAC__seekable_stream_decoder_set_metadata_callback,
+	(FLAC__bool (*) (void *, ErrorCallback)) FLAC__seekable_stream_decoder_set_error_callback,
+	(FLAC__bool (*) (void *, void *)) FLAC__seekable_stream_decoder_set_client_data,
 	(FLAC__bool (*) (void *)) file_decoder_init,
 	(void (*) (void *)) file_decoder_safe_decoder_finish_,
 	(void (*) (void *)) file_decoder_safe_decoder_delete_,
-	(FLAC__bool (*) (void *)) FLAC__file_decoder_process_until_end_of_metadata,
-	(FLAC__bool (*) (void *)) FLAC__file_decoder_process_single,
+	(FLAC__bool (*) (void *)) FLAC__seekable_stream_decoder_process_until_end_of_metadata,
+	(FLAC__bool (*) (void *)) FLAC__seekable_stream_decoder_process_single,
 	file_decoder_is_eof
 };
 
 /*********** HTTP decoder functions */
 
-static gchar *url_;
-
-static FLAC__bool http_decoder_set_md5_checking (void *decoder, FLAC__bool value)
-{
-	(void) value;
-	// operation unsupported
-	return FLAC__stream_decoder_get_state ((const FLAC__StreamDecoder *) decoder) ==
-		FLAC__STREAM_DECODER_UNINITIALIZED;
-}
+static gchar *url_ = NULL;
 
 static FLAC__bool http_decoder_set_url (void *decoder, const char* url)
 {
@@ -667,6 +769,17 @@
 	return true;
 }
 
+static FLAC__bool http_decoder_unset_url (void *decoder)
+{
+	(void) decoder;
+	if ( url_ != NULL )
+	{
+		g_free(url_);
+		url_ = NULL;
+	}
+	return true;
+}
+
 static FLAC__StreamDecoderReadStatus http_decoder_read_callback (const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data)
 {
 	(void) decoder;
@@ -678,11 +791,16 @@
 static FLAC__bool http_decoder_init (void *decoder)
 {
 	flac_http_open (url_, 0);
-	g_free (url_);
+	http_decoder_unset_url(decoder);
 	FLAC__stream_decoder_set_read_callback (decoder, http_decoder_read_callback);
 	return FLAC__stream_decoder_init( (FLAC__StreamDecoder*) decoder) == FLAC__STREAM_DECODER_SEARCH_FOR_METADATA;
 }
 
+static FLAC__bool http_decoder_set_md5_checking (void *decoder, FLAC__bool value)
+{
+	return false;
+}
+
 static void http_decoder_safe_decoder_finish_(void *decoder)
 {
 	if(decoder && FLAC__stream_decoder_get_state((FLAC__StreamDecoder *) decoder) != FLAC__STREAM_DECODER_UNINITIALIZED) {
@@ -707,8 +825,9 @@
 static const decoder_funcs_t HTTP_DECODER_FUNCTIONS = {
 	false,
 	(void* (*) (void)) FLAC__stream_decoder_new,
-	http_decoder_set_md5_checking,
 	(FLAC__bool (*) (void *, const char*)) http_decoder_set_url,
+	(FLAC__bool (*) (void *)) http_decoder_unset_url,
+	(FLAC__bool (*) (void *, FLAC__bool)) http_decoder_set_md5_checking,
 	(FLAC__bool (*) (void *)) FLAC__stream_decoder_set_metadata_ignore_all,
 	(FLAC__bool (*) (void *, FLAC__MetadataType)) FLAC__stream_decoder_set_metadata_respond,
 	(FLAC__bool (*) (void *, WriteCallback)) FLAC__stream_decoder_set_write_callback,
@@ -762,8 +881,8 @@
 		decoder = *decoderp;
 		fntab = *fntabp;
 
+		fntab -> set_source(decoder, filename);
 		fntab -> set_md5_checking(decoder, false);
-		fntab -> set_source(decoder, filename);
 		fntab -> set_metadata_ignore_all(decoder);
 		fntab -> set_metadata_respond(decoder, FLAC__METADATA_TYPE_STREAMINFO);
 		fntab -> set_metadata_respond(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT);
@@ -772,10 +891,16 @@
 		fntab -> set_error_callback(decoder, error_callback_);
 		fntab -> set_client_data(decoder, &file_info_);
 		if(!fntab -> decoder_init(decoder))
+		{
+			fntab -> unset_source(decoder);
 			return false;
+		}
 
 		if(!fntab -> process_until_end_of_metadata(decoder))
+		{
+			fntab -> unset_source(decoder);
 			return false;
+		}
 	}
 
 	return true;
--- a/src/flac112/plugin_common/tags.c	Sun Jan 21 11:17:52 2007 -0800
+++ b/src/flac112/plugin_common/tags.c	Sun Jan 21 15:15:38 2007 -0800
@@ -160,6 +160,11 @@
 
 FLAC__bool FLAC_plugin__tags_get(const char *filename, FLAC__StreamMetadata **tags)
 {
+	/* NOTE vfs is not used here, so only try
+	   to pick tags if you can do it with flac library stdio */
+	if ( strncmp(filename,"/",1) )
+		return false;
+
 	if(!FLAC__metadata_get_tags(filename, tags))
 		if(0 == (*tags = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT)))
 			return false;