diff options
-rw-r--r-- | src/libflac/Makefile.am | 33 | ||||
-rw-r--r-- | src/libflac/decoder_flac.c | 408 | ||||
-rw-r--r-- | src/libflac/demux_flac.c | 601 |
3 files changed, 1042 insertions, 0 deletions
diff --git a/src/libflac/Makefile.am b/src/libflac/Makefile.am new file mode 100644 index 000000000..9fe261d85 --- /dev/null +++ b/src/libflac/Makefile.am @@ -0,0 +1,33 @@ +# +# the Makefile for flac plugins +# + +LIBTOOL = $(SHELL) $(top_builddir)/libtool-nofpic + +libdir = $(XINE_PLUGINDIR) +XINE_LIB = $(top_builddir)/src/xine-engine/libxine.la + +lib_LTLIBRARIES = xineplug_flac.la + +xineplug_flac_la_SOURCES = demux_flac.c decoder_flac.c +xineplug_flac_la_LDFLAGS = -avoid-version -module -lFLAC @XINE_PLUGIN_MIN_SYMS@ + + +# noinst_HEADERS = + +$(XINE_LIB): + @cd $(top_builddir)/src/xine-engine && $(MAKE) + +debug: + @$(MAKE) CFLAGS="$(DEBUG_CFLAGS)" + +install-debug: debug + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +mostlyclean-generic: + -rm -f *~ \#* .*~ .\#* + +maintainer-clean-generic: + -@echo "This command is intended for maintainers to use;" + -@echo "it deletes files that may require special tools to rebuild." + -rm -f Makefile.in diff --git a/src/libflac/decoder_flac.c b/src/libflac/decoder_flac.c new file mode 100644 index 000000000..f46d35cbf --- /dev/null +++ b/src/libflac/decoder_flac.c @@ -0,0 +1,408 @@ +/* + * Copyright (C) 2000-2002 the xine project + * + * This file is part of xine, a free video player. + * + * xine 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. + * + * xine 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 + * + * John McCutchan 2003 + * FLAC Decoder (http://flac.sf.net) + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> +#include <string.h> + +#include <FLAC/stream_decoder.h> + + +#include "xine_internal.h" +#include "audio_out.h" +#include "buffer.h" + + +typedef struct { + audio_decoder_class_t decoder_class; +} flac_class_t; + +typedef struct flac_decoder_s { + audio_decoder_t audio_decoder; + + int64_t pts; + + int output_sampling_rate; + int output_open; + int output_mode; + + xine_stream_t *stream; + + FLAC__StreamDecoder *flac_decoder; + + int sample_rate; + int bits_per_sample; + int channels; + + unsigned char *buf; + int buf_size; + int buf_pos; + int min_size; + +} flac_decoder_t; + +/* + * FLAC callback functions + */ + +static FLAC__StreamDecoderReadStatus +flac_read_callback (const FLAC__StreamDecoder *decoder, + FLAC__byte buffer[], + unsigned *bytes, + void *client_data) +{ + flac_decoder_t *this = (flac_decoder_t *)client_data; + int number_of_bytes_to_copy; + + printf("FLAC_DEC: flac_read_callback: %d\n", *bytes); + + if (this->buf_pos > *bytes) + number_of_bytes_to_copy = *bytes; + else + number_of_bytes_to_copy = this->buf_pos; + + printf("FLAC_DEC: number_of_bytes_to_copy: %d\n", number_of_bytes_to_copy); + + *bytes = number_of_bytes_to_copy; + + xine_fast_memcpy (buffer, this->buf, number_of_bytes_to_copy); + + this->buf_pos -= number_of_bytes_to_copy; + memmove(this->buf, &this->buf[number_of_bytes_to_copy], this->buf_pos ); + + if(number_of_bytes_to_copy) + return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; + else + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; +} + +static FLAC__StreamDecoderWriteStatus +flac_write_callback (const FLAC__StreamDecoder *decoder, + const FLAC__Frame *frame, + const FLAC__int32 *const buffer[], + void *client_data) +{ + flac_decoder_t *this = (flac_decoder_t *)client_data; + audio_buffer_t *audio_buffer = NULL; + int samples_left = frame->header.blocksize; + int bytes_per_sample = (frame->header.bits_per_sample == 8)?1:2; + int buf_samples; + int8_t *data8; + int16_t *data16; + int i,j; + + printf("FLAC_DEC: flac_write_callback\n"); + + while( samples_left ) { + + audio_buffer = this->stream->audio_out->get_buffer(this->stream->audio_out); + + if( audio_buffer->mem_size < samples_left * frame->header.channels * bytes_per_sample ) + buf_samples = audio_buffer->mem_size / (frame->header.channels * bytes_per_sample); + else + buf_samples = samples_left; + + + if( frame->header.bits_per_sample == 8 ) { + data8 = (int8_t *)audio_buffer->mem; + + for( j=0; j < buf_samples; j++ ) + for( i=0; i < frame->header.channels; i++ ) + *data8++ = buffer[i][j]; + + } else { + + data16 = (int16_t *)audio_buffer->mem; + + for( j=0; j < buf_samples; j++ ) + for( i=0; i < frame->header.channels; i++ ) + *data16++ = buffer[i][j]; + } + + audio_buffer->num_frames = buf_samples; + audio_buffer->vpts = this->pts; + this->pts = 0; + this->stream->audio_out->put_buffer (this->stream->audio_out, audio_buffer, this->stream); + + samples_left -= buf_samples; + } + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; +} + +static void +flac_metadata_callback (const FLAC__StreamDecoder *decoder, + const FLAC__StreamMetadata *metadata, + void *client_data) +{ + flac_decoder_t *this = (flac_decoder_t *)client_data; + + printf("FLAC_DEC: Metadata callback called!\n"); + + if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) { + printf("FLAC_DEC: min_blocksize = %d\n", metadata->data.stream_info.min_blocksize); + printf("FLAC_DEC: max_blocksize = %d\n", metadata->data.stream_info.max_blocksize); + printf("FLAC_DEC: min_framesize = %d\n", metadata->data.stream_info.min_framesize); + printf("FLAC_DEC: max_framesize = %d\n", metadata->data.stream_info.max_framesize); + + /* does not work well: + this->min_size = 2 * metadata->data.stream_info.max_blocksize; */ + } + return; +} + +static void +flac_error_callback (const FLAC__StreamDecoder *decoder, + FLAC__StreamDecoderErrorStatus status, + void *client_data) +{ + /* This will be called if there is an error in the flac stream */ + printf("FLAC_DEC: flac_error_callback\n"); + + if (status == FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC) + printf("FLAC_DEC: Decoder lost synchronization.\n"); + else if (status == FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER) + printf("FLAC_DEC: Decoder encounted a corrupted frame header.\n"); + else if (status == FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH) + printf("FLAC_DEC: Frame's data did not match the CRC in the footer.\n"); + else + printf("FLAC_DEC: unknown error.\n"); + + return; +} + + + + +/* + * FLAC plugin decoder + */ + +static void +flac_reset (audio_decoder_t *this_gen) +{ + flac_decoder_t *this = (flac_decoder_t *) this_gen; + + this->buf_pos = 0; + + if( FLAC__stream_decoder_get_state(this->flac_decoder) != + FLAC__STREAM_DECODER_SEARCH_FOR_METADATA ) + FLAC__stream_decoder_flush (this->flac_decoder); +} + +static void +flac_discontinuity (audio_decoder_t *this_gen) +{ + flac_decoder_t *this = (flac_decoder_t *) this_gen; + + this->pts = 0; + printf("FLAC_DEC: Discontinuity!\n"); +} + +static void +flac_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) +{ + flac_decoder_t *this = (flac_decoder_t *) this_gen; + int ret = 1; + + /* We are getting the stream header, open up the audio + * device, and collect information about the stream + */ + if (buf->decoder_flags & BUF_FLAG_HEADER) + { + int mode = AO_CAP_MODE_MONO; + + this->sample_rate = buf->decoder_info[1]; + this->bits_per_sample = buf->decoder_info[2]; + this->channels = buf->decoder_info[3]; + + switch (this->channels) + { + case 1: + mode = AO_CAP_MODE_MONO; + break; + case 2: + mode = AO_CAP_MODE_STEREO; + break; + case 4: + mode = AO_CAP_MODE_4CHANNEL; + break; + case 5: + mode = AO_CAP_MODE_5CHANNEL; + break; + case 6: + mode = AO_CAP_MODE_5_1CHANNEL; + } + + if (!this->output_open) + { + this->output_open = this->stream->audio_out->open ( + this->stream->audio_out, + this->stream, + this->bits_per_sample, + this->sample_rate, + mode); + + + } + this->buf_pos = 0; + } else if (this->output_open) + { + /* This isn't a header frame and we have opened the output device */ + + + /* What we have buffered so far, and what is coming in + * is larger than our buffer + */ + if (this->buf_pos + buf->size > this->buf_size) + { + this->buf_size += 2 * buf->size; + this->buf = realloc (this->buf, this->buf_size); + printf("FLAC_DEC: reallocating buffer to %d\n", this->buf_size); + } + + xine_fast_memcpy (&this->buf[this->buf_pos], buf->content, buf->size); + this->buf_pos += buf->size; + + if (buf->pts) + this->pts = buf->pts; + + /* We have enough to decode a frame */ + while( ret && this->buf_pos > this->min_size ) { + + if( FLAC__stream_decoder_get_state(this->flac_decoder) == + FLAC__STREAM_DECODER_SEARCH_FOR_METADATA ) { + printf("FLAC_DEC: process_until_end_of_metadata\n"); + ret = FLAC__stream_decoder_process_until_end_of_metadata (this->flac_decoder); + } else { + printf("FLAC_DEC: process_single\n"); + ret = FLAC__stream_decoder_process_single (this->flac_decoder); + } + } + } else + return; + + +} + +static void +flac_dispose (audio_decoder_t *this_gen) { + flac_decoder_t *this = (flac_decoder_t *) this_gen; + + FLAC__stream_decoder_finish (this->flac_decoder); + + FLAC__stream_decoder_delete (this->flac_decoder); + + if (this->output_open) + this->stream->audio_out->close (this->stream->audio_out, this->stream); + + free (this_gen); +} + +static audio_decoder_t * +open_plugin (audio_decoder_class_t *class_gen, xine_stream_t *stream) { + flac_decoder_t *this ; + + this = (flac_decoder_t *) malloc (sizeof (flac_decoder_t)); + + this->audio_decoder.decode_data = flac_decode_data; + this->audio_decoder.reset = flac_reset; + this->audio_decoder.discontinuity = flac_discontinuity; + this->audio_decoder.dispose = flac_dispose; + this->stream = stream; + + this->output_open = 0; + this->buf = NULL; + this->buf_size = 0; + this->min_size = 65536; + this->pts = 0; + + this->flac_decoder = FLAC__stream_decoder_new(); + + FLAC__stream_decoder_set_read_callback (this->flac_decoder, + flac_read_callback); + FLAC__stream_decoder_set_write_callback (this->flac_decoder, + flac_write_callback); + FLAC__stream_decoder_set_metadata_callback (this->flac_decoder, + flac_metadata_callback); + FLAC__stream_decoder_set_error_callback (this->flac_decoder, + flac_error_callback); + + FLAC__stream_decoder_set_client_data (this->flac_decoder, this); + + FLAC__stream_decoder_init (this->flac_decoder); + + return (audio_decoder_t *) this; +} + +/* + * flac plugin class + */ + +static char *get_identifier (audio_decoder_class_t *this) { + return "flacdec"; +} + +static char *get_description (audio_decoder_class_t *this) { + return "flac audio decoder plugin"; +} + +static void dispose_class (audio_decoder_class_t *this) { + free (this); +} + +static void * +init_plugin (xine_t *xine, void *data) { + flac_class_t *this; + + this = (flac_class_t *) malloc (sizeof (flac_class_t)); + + this->decoder_class.open_plugin = open_plugin; + this->decoder_class.get_identifier = get_identifier; + this->decoder_class.get_description = get_description; + this->decoder_class.dispose = dispose_class; + + + return this; +} + +static uint32_t audio_types[] = { + BUF_AUDIO_FLAC, 0 + }; + +static decoder_info_t dec_info_audio = { + audio_types, /* supported types */ + 5 /* priority */ +}; + +/* from demux_flac.c */ +void *demux_flac_init_class (xine_t *xine, void *data); + +plugin_info_t xine_plugin_info[] = { + /* type, API, "name", version, special_info, init_function */ + { PLUGIN_DEMUX, 20, "flac", XINE_VERSION_CODE, NULL, demux_flac_init_class }, + { PLUGIN_AUDIO_DECODER, 13, "flacdec", XINE_VERSION_CODE, &dec_info_audio, init_plugin }, + { PLUGIN_NONE, 0, "", 0, NULL, NULL } +}; diff --git a/src/libflac/demux_flac.c b/src/libflac/demux_flac.c new file mode 100644 index 000000000..d0ffa80c0 --- /dev/null +++ b/src/libflac/demux_flac.c @@ -0,0 +1,601 @@ +/* + * Copyright (C) 2000-2002 the xine project + * + * This file is part of xine, a free video player. + * + * xine 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. + * + * xine 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 + * + * + * John McCutchan + * FLAC demuxer (http://flac.sf.net) + * + * TODO: Skip id3v2 tags. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <sched.h> +#include <string.h> +#include <stdlib.h> + +#include <FLAC/seekable_stream_decoder.h> + +#include "xine_internal.h" +#include "xineutils.h" +#include "../demuxers/demux.h" + +/* FLAC Demuxer plugin */ +typedef struct demux_flac_s { + demux_plugin_t demux_plugin; + + xine_stream_t *stream; + + fifo_buffer_t *audio_fifo; + fifo_buffer_t *video_fifo; + + input_plugin_t *input; + + int status; + + int seek_flag; + + off_t data_start; + off_t data_size; + + /* FLAC Stuff */ + FLAC__SeekableStreamDecoder *flac_decoder; + + uint64_t total_samples; + uint64_t bits_per_sample; + uint64_t channels; + uint64_t sample_rate; + uint64_t length_in_msec; +} demux_flac_t ; + + +/* FLAC Demuxer class */ +typedef struct demux_flac_class_s { + demux_class_t demux_class; + + xine_t *xine; + config_values_t *config; + +} demux_flac_class_t; + +/* FLAC Callbacks */ +static FLAC__SeekableStreamDecoderReadStatus +flac_read_callback (const FLAC__SeekableStreamDecoder *decoder, + FLAC__byte buffer[], + unsigned *bytes, + void *client_data) +{ + demux_flac_t *this = (demux_flac_t *)client_data; + input_plugin_t *input = this->input; + off_t offset = *bytes; + + printf("FLAC_DMXR: flac_read_callback\n"); + + /* This should only be called when flac is reading the metadata + * of the flac stream. + */ + + offset = input->read (input, buffer, offset); + + printf("FLAC_DMXR: Read %lld / %u bytes into buffer\n", offset, *bytes); + + *bytes = offset; + /* This is the way to detect EOF with xine input plugins */ + if ( (offset != *bytes) && (*bytes != 0) ) + { + printf("FLAC_DMXR: Marking EOF\n"); + this->status = DEMUX_FINISHED; + return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR; + } + else + { + printf("FLAC_DMXR: Read was perfect\n"); + return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK; + } +} + +static FLAC__SeekableStreamDecoderSeekStatus +flac_seek_callback (const FLAC__SeekableStreamDecoder *decoder, + FLAC__uint64 absolute_byte_offset, + void *client_data) +{ + input_plugin_t *input = ((demux_flac_t *)client_data)->input; + off_t offset; + + printf("FLAC_DMXR: flac_seek_callback\n"); + + offset = input->seek (input, absolute_byte_offset, SEEK_SET); + + if (offset == -1) + return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR; + else + return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK; +} + +static FLAC__SeekableStreamDecoderTellStatus +flac_tell_callback (const FLAC__SeekableStreamDecoder *decoder, + FLAC__uint64 *absolute_byte_offset, + void *client_data) +{ + input_plugin_t *input = ((demux_flac_t *)client_data)->input; + off_t offset; + + printf("FLAC_DMXR: flac_tell_callback\n"); + offset = input->get_current_pos (input); + + *absolute_byte_offset = offset; + + return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK; +} + +static FLAC__SeekableStreamDecoderLengthStatus +flac_length_callback (const FLAC__SeekableStreamDecoder *decoder, + FLAC__uint64 *stream_length, + void *client_data) +{ + input_plugin_t *input = ((demux_flac_t *)client_data)->input; + off_t offset; + + printf("FLAC_DMXR: flac_length_callback\n"); + offset = input->get_length (input); + + /* FIXME, can flac handle -1 as offset ? */ + return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK; +} + +static FLAC__bool +flac_eof_callback (const FLAC__SeekableStreamDecoder *decoder, + void *client_data) +{ + demux_flac_t *this = (demux_flac_t *)client_data; + printf("FLAC_DMXR: flac_eof_callback\n"); + + if (this->status == DEMUX_FINISHED) + { + printf("FLAC_DMXR: flac_eof_callback: True!\n"); + return true; + } + else + { + printf("FLAC_DMXR: flac_eof_callback: False!\n"); + return false; + } +} + +static FLAC__StreamDecoderWriteStatus +flac_write_callback (const FLAC__SeekableStreamDecoder *decoder, + const FLAC__Frame *frame, + const FLAC__int32 * const buffer[], + void *client_data) +{ + /* This should never be called, all we use flac for in this demuxer + * is seeking. We do the decoding in the decoder + */ + + printf("FLAC_DMXR: Error: Write callback was called!\n"); + + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; +} + +static void +flac_metadata_callback (const FLAC__SeekableStreamDecoder *decoder, + const FLAC__StreamMetadata *metadata, + void *client_data) +{ + demux_flac_t *this = (demux_flac_t *)client_data; + + printf("FLAC_DMXR: IN: Metadata callback\n"); + /* This should be called when we first look at a flac stream, + * We get information about the stream here. + */ + if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) { + printf("FLAC_DMXR: Got METADATA!\n"); + this->total_samples = metadata->data.stream_info.total_samples; + this->bits_per_sample = metadata->data.stream_info.bits_per_sample; + this->channels = metadata->data.stream_info.channels; + this->sample_rate = metadata->data.stream_info.sample_rate; + this->length_in_msec = (this->total_samples * 10 / + (this->sample_rate / 100))/1000; + } + return; +} + +static void +flac_error_callback (const FLAC__SeekableStreamDecoder *decoder, + FLAC__StreamDecoderErrorStatus status, + void *client_data) +{ + /* This will be called if there is an error when flac is seeking + * in the stream. + */ + + printf("FLAC_DMXR: flac_error_callback\n"); + if (status == FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC) + printf("FLAC_DMXR: Decoder lost synchronization.\n"); + else if (status == FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER) + printf("FLAC_DMXR: Decoder encounted a corrupted frame header.\n"); + else if (status == FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH) + printf("FLAC_DMXR: Frame's data did not match the CRC in the footer.\n"); + else + printf("FLAC_DMXR: unknown error.\n"); + + return; +} + +/* FLAC Demuxer plugin */ +static int +demux_flac_send_chunk (demux_plugin_t *this_gen) { + demux_flac_t *this = (demux_flac_t *) this_gen; + buf_element_t *buf = NULL; + off_t current_file_pos; + int64_t current_pts; + unsigned int remaining_sample_bytes = 0; + + remaining_sample_bytes = 2048; + + current_file_pos = this->input->get_current_pos (this->input) + - this->data_start; + + current_pts = current_file_pos; + current_pts *= 90000; + if (this->sample_rate != 0) + { + current_pts /= this->sample_rate; + } + + if (this->seek_flag) { + xine_demux_control_newpts (this->stream, current_pts, 0); + this->seek_flag = 0; + } + + while (remaining_sample_bytes) + { + buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); + buf->type = BUF_AUDIO_FLAC; + buf->extra_info->input_pos = current_file_pos; + buf->extra_info->input_length = this->data_size; + buf->extra_info->input_time = current_pts / 90; + //buf->pts = current_pts; + + if (remaining_sample_bytes > buf->max_size) + buf->size = buf->max_size; + else + buf->size = remaining_sample_bytes; + + remaining_sample_bytes -= buf->size; + + if (this->input->read (this->input,buf->content,buf->size)!=buf->size) { + printf("FLAC_DMXR: buf->size != input->read()\n"); + buf->free_buffer (buf); + this->status = DEMUX_FINISHED; + break; + } + + /* + if (!remaining_sample_bytes) + { + buf->decoder_flags |= BUF_FLAG_FRAME_END; + }*/ + + this->audio_fifo->put (this->audio_fifo, buf); + } + + return this->status; +} + +static void +demux_flac_send_headers (demux_plugin_t *this_gen) { + demux_flac_t *this = (demux_flac_t *) this_gen; + + buf_element_t *buf; + + printf("FLAC_DMXR: demux_flac_send_headers\n"); + + this->video_fifo = this->stream->video_fifo; + this->audio_fifo = this->stream->audio_fifo; + + this->status = DEMUX_OK; + + this->stream->stream_info[XINE_STREAM_INFO_HAS_VIDEO] = 0; + this->stream->stream_info[XINE_STREAM_INFO_HAS_AUDIO] = 1; + this->stream->stream_info[XINE_STREAM_INFO_AUDIO_CHANNELS] = this->channels; + this->stream->stream_info[XINE_STREAM_INFO_AUDIO_SAMPLERATE] = this->sample_rate; + this->stream->stream_info[XINE_STREAM_INFO_AUDIO_BITS] = this->bits_per_sample; + + xine_demux_control_start (this->stream); + + if (this->audio_fifo) { + buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); + buf->type = BUF_AUDIO_FLAC; + buf->decoder_flags = BUF_FLAG_HEADER; + buf->decoder_info[0] = 0; + buf->decoder_info[1] = this->sample_rate; + buf->decoder_info[2] = this->bits_per_sample; + buf->decoder_info[3] = this->channels; + buf->size = 0; + this->audio_fifo->put (this->audio_fifo, buf); + } +} + +static void +demux_flac_dispose (demux_plugin_t *this_gen) { + demux_flac_t *this = (demux_flac_t *) this_gen; + + printf("FLAC_DMXR: demux_flac_dispose\n"); + if (this->flac_decoder) + FLAC__seekable_stream_decoder_delete (this->flac_decoder); + + free(this); + return; +} + +static int +demux_flac_get_status (demux_plugin_t *this_gen) { + demux_flac_t *this = (demux_flac_t *) this_gen; + + printf("FLAC_DMXR: demux_flac_get_status\n"); + + return this->status; +} + + +static int +demux_flac_seek (demux_plugin_t *this_gen, off_t start_pos, int start_time) { + demux_flac_t *this = (demux_flac_t *) this_gen; + + printf("FLAC_DMXR: demux_flac_seek\n"); + if (start_pos || !start_time) { + + this->input->seek (this->input, start_pos, SEEK_SET); + printf ("Seek to position: %lld\n", start_pos); + + } else { + + double distance = (double)start_time*1000.0; + uint64_t target_sample = (uint64_t)(distance * this->total_samples); + FLAC__bool s = false; + + if (this->length_in_msec != 0) + { + distance /= (double)this->length_in_msec; + } + + + s = FLAC__seekable_stream_decoder_seek_absolute (this->flac_decoder, + target_sample); + + if (s) + printf ("Seek to: %d successfull!\n", start_time); + else + this->status = DEMUX_FINISHED; + } + + xine_demux_flush_engine (this->stream); + + return this->status; +} + +static int +demux_flac_get_stream_length (demux_plugin_t *this_gen) { + demux_flac_t *this = (demux_flac_t *) this_gen; + + printf("FLAC_DMXR: demux_flac_get_stream_length\n"); + + if (this->flac_decoder) + return this->length_in_msec; + else + return 0; +} + +static uint32_t +demux_flac_get_capabilities (demux_plugin_t *this_gen) { + printf("FLAC_DMXR: demux_flac_get_capabilities\n"); + return DEMUX_CAP_NOCAP; +} + +static int +demux_flac_get_optional_data (demux_plugin_t *this_gen, void *data, int dtype) { + printf("FLAC_DMXR: demux_flac_get_optional_data\n"); + return DEMUX_OPTIONAL_UNSUPPORTED; +} + +static demux_plugin_t * +open_plugin (demux_class_t *class_gen, + xine_stream_t *stream, + input_plugin_t *input) { + demux_flac_t *this; + + printf("FLAC_DMXR: open_plugin\n"); +#if 0 + if ((input->get_capabilities (input) & INPUT_CAP_SEEKABLE) != 0) + { + printf("FLAC_DMXR: Input is not seekable, will not handle.\n"); + return NULL; + } +#endif + + switch (stream->content_detection_method) { + case METHOD_BY_CONTENT: + { + uint8_t buf[4096]; + + /* Seek to the beginning */ + input->seek(input, 0, SEEK_SET); + + + /* FIXME: Skip id3v2 tag */ + if (input->read (input, buf, 4)) { + input->seek(input, 0, SEEK_SET); + /* Look for fLaC tag at the beginning of file */ + if ( (buf[0] != 'f') || (buf[1] != 'L') || + (buf[2] != 'a') || (buf[3] != 'C') ) + return NULL; + } + } + break; + case METHOD_BY_EXTENSION: { + char *ending, *mrl; + + mrl = input->get_mrl (input); + + ending = strrchr (mrl, '.'); + + if (!ending || (strlen (ending) < 5)) + return NULL; + + if (strncasecmp (ending, ".flac", 5)) + return NULL; + } + break; + case METHOD_EXPLICIT: + break; + default: + return NULL; + break; + } + + /* + * if we reach this point, the input has been accepted. + */ + + this = xine_xmalloc (sizeof (demux_flac_t)); + this->stream = stream; + this->input = input; + + this->demux_plugin.send_headers = demux_flac_send_headers; + this->demux_plugin.send_chunk = demux_flac_send_chunk; + this->demux_plugin.seek = demux_flac_seek; + this->demux_plugin.dispose = demux_flac_dispose; + this->demux_plugin.get_status = demux_flac_get_status; + this->demux_plugin.get_stream_length = demux_flac_get_stream_length; + this->demux_plugin.get_video_frame = NULL; + this->demux_plugin.got_video_frame_cb= NULL; + this->demux_plugin.get_capabilities = demux_flac_get_capabilities; + this->demux_plugin.get_optional_data = demux_flac_get_optional_data; + this->demux_plugin.demux_class = class_gen; + + this->seek_flag = 0; + + + /* Get a new FLAC decoder and hook up callbacks */ + this->flac_decoder = FLAC__seekable_stream_decoder_new(); + printf("FLAC_DMXR: this->flac_decoder: %p\n", this->flac_decoder); + FLAC__seekable_stream_decoder_set_md5_checking (this->flac_decoder, false); + FLAC__seekable_stream_decoder_set_read_callback (this->flac_decoder, + flac_read_callback); + FLAC__seekable_stream_decoder_set_seek_callback (this->flac_decoder, + flac_seek_callback); + FLAC__seekable_stream_decoder_set_tell_callback (this->flac_decoder, + flac_tell_callback); + FLAC__seekable_stream_decoder_set_length_callback (this->flac_decoder, + flac_length_callback); + FLAC__seekable_stream_decoder_set_eof_callback (this->flac_decoder, + flac_eof_callback); + FLAC__seekable_stream_decoder_set_metadata_callback (this->flac_decoder, + flac_metadata_callback); + FLAC__seekable_stream_decoder_set_write_callback (this->flac_decoder, + flac_write_callback); + FLAC__seekable_stream_decoder_set_error_callback (this->flac_decoder, + flac_error_callback); + FLAC__seekable_stream_decoder_set_client_data (this->flac_decoder, + this); + + FLAC__seekable_stream_decoder_init (this->flac_decoder); + + /* Get some stream info */ + this->data_size = this->input->get_length (this->input); + this->data_start = this->input->get_current_pos (this->input); + + /* This will cause FLAC to give us the rest of the information on + * this flac stream + */ + this->status = DEMUX_OK; + FLAC__seekable_stream_decoder_process_until_end_of_metadata (this->flac_decoder); + printf("FLAC_DMXR: Processed file until end of metadata\n"); + + return &this->demux_plugin; +} + + +/* FLAC Demuxer class */ + +static char * +get_description (demux_class_t *this_gen) { + return "FLAC demux plugin"; +} + +static char * +get_identifier (demux_class_t *this_gen) { + return "FLAC"; +} + +static char * +get_extensions (demux_class_t *this_gen) { + return "flac"; +} + +static char * +get_mimetypes (demux_class_t *this_gen) { + return "application/x-flac: flac: FLAC Audio;"; +} + +static void +class_dispose (demux_class_t *this_gen) { + demux_flac_class_t *this = (demux_flac_class_t *) this_gen; + + printf("FLAC_DMXR: class_dispose\n"); + free (this); +} + +void * +demux_flac_init_class (xine_t *xine, void *data) { + + demux_flac_class_t *this; + + printf("FLAC_DMXR: demux_flac_init_class\n"); + this = xine_xmalloc (sizeof (demux_flac_class_t)); + this->config = xine->config; + this->xine = xine; + + this->demux_class.open_plugin = open_plugin; + this->demux_class.get_description = get_description; + this->demux_class.get_identifier = get_identifier; + this->demux_class.get_mimetypes = get_mimetypes; + this->demux_class.get_extensions = get_extensions; + this->demux_class.dispose = class_dispose; + + return this; +} + +/* + * exported plugin catalog entry + */ +#if 0 +plugin_info_t xine_plugin_info[] = { + /* type, API, "name", version, special_info, init_function */ + { PLUGIN_DEMUX, 20, "flac", XINE_VERSION_CODE, NULL, demux_flac_init_class }, + { PLUGIN_NONE, 0, "", 0, NULL, NULL } +}; +#endif |