From 8d0828feb74d91958d151284494cad1aeac62432 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Diego=20=27Flameeyes=27=20Petten=C3=B2?= Date: Thu, 9 Nov 2006 15:13:19 +0000 Subject: Add support for playing OggFlac files (still not 100% complete, but will play). Add a flacutils.h header with functions to parse FLAC data structure, to be shared with demux_flac. Closes bug #1590690. CVS patchset: 8362 CVS date: 2006/11/09 15:13:19 --- src/demuxers/demux_flac.c | 13 ++----- src/demuxers/demux_ogg.c | 79 ++++++++++++++++++++++++++++++++++++---- src/demuxers/flacutils.h | 91 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 166 insertions(+), 17 deletions(-) create mode 100644 src/demuxers/flacutils.h (limited to 'src') diff --git a/src/demuxers/demux_flac.c b/src/demuxers/demux_flac.c index a0ae6c5ba..94c668555 100644 --- a/src/demuxers/demux_flac.c +++ b/src/demuxers/demux_flac.c @@ -23,7 +23,7 @@ * For more information on the FLAC file format, visit: * http://flac.sourceforge.net/ * - * $Id: demux_flac.c,v 1.10 2006/06/02 22:33:37 dsalt Exp $ + * $Id: demux_flac.c,v 1.11 2006/11/09 15:13:19 dgp85 Exp $ */ #ifdef HAVE_CONFIG_H @@ -49,16 +49,7 @@ #include "bswap.h" #include "group_audio.h" -typedef struct { - off_t offset; - int64_t sample_number; - int64_t pts; - int size; -} flac_seekpoint_t; - -#define FLAC_SIGNATURE_SIZE 4 -#define FLAC_STREAMINFO_SIZE 34 -#define FLAC_SEEKPOINT_SIZE 18 +#include "flacutils.h" typedef struct { demux_plugin_t demux_plugin; diff --git a/src/demuxers/demux_ogg.c b/src/demuxers/demux_ogg.c index 92eb6507d..9a44d77cd 100644 --- a/src/demuxers/demux_ogg.c +++ b/src/demuxers/demux_ogg.c @@ -19,7 +19,7 @@ */ /* - * $Id: demux_ogg.c,v 1.168 2006/09/14 02:04:48 dgp85 Exp $ + * $Id: demux_ogg.c,v 1.169 2006/11/09 15:13:19 dgp85 Exp $ * * demultiplexer for ogg streams * @@ -55,6 +55,7 @@ #define LOG_MODULE "demux_ogg" #define LOG_VERBOSE + /* #define LOG */ @@ -68,6 +69,7 @@ #include "xineutils.h" #include "demux.h" #include "bswap.h" +#include "flacutils.h" #define CHUNKSIZE 8500 #define PACKET_TYPE_HEADER 0x01 @@ -592,6 +594,7 @@ static void send_ogg_buf (demux_ogg_t *this, } if ((this->si[stream_num]->buf_types & 0xFFFF0000) == BUF_AUDIO_SPEEX || + (this->si[stream_num]->buf_types & 0xFFFF0000) == BUF_AUDIO_FLAC || (this->si[stream_num]->buf_types & 0xFFFF0000) == BUF_AUDIO_VORBIS) { data = op->packet; size = op->bytes; @@ -615,10 +618,9 @@ static void send_ogg_buf (demux_ogg_t *this, pts); _x_demux_send_data(this->audio_fifo, data, size, - pts, this->si[stream_num]->buf_types, decoder_flags, - normpos, - pts / 90, this->time_length, 0); - + pts, this->si[stream_num]->buf_types, decoder_flags, + normpos, + pts / 90, this->time_length, 0); #ifdef HAVE_THEORA } else if ((this->si[stream_num]->buf_types & 0xFFFF0000) == BUF_VIDEO_THEORA) { @@ -1179,6 +1181,69 @@ static void decode_theora_header (demux_ogg_t *this, const int stream_num, ogg_p #endif } +static void decode_flac_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) { + xine_flac_metadata_header header; + xine_flac_streaminfo_block streaminfo; + buf_element_t *buf; + xine_waveformatex wave; + + /* Packet type */ + _x_assert(op->packet[0] == 0x7F); + + /* OggFLAC signature */ + _x_assert(op->packet[1] == 'F'); _x_assert(op->packet[2] == 'L'); + _x_assert(op->packet[3] == 'A'); _x_assert(op->packet[4] == 'C'); + + /* Version: supported only 1.0 */ + _x_assert(op->packet[5] == 1); _x_assert(op->packet[6] == 0); + + /* Header count */ + this->si[stream_num]->headers = 0/*BE_16(&op->packet[7]) +1*/; + + /* fLaC signature */ + _x_assert(op->packet[9] == 'f'); _x_assert(op->packet[10] == 'L'); + _x_assert(op->packet[11] == 'a'); _x_assert(op->packet[12] == 'C'); + + _x_parse_flac_metadata_header(&op->packet[13], &header); + + switch ( header.blocktype ) { + case FLAC_BLOCKTYPE_STREAMINFO: + _x_assert(header.length == FLAC_STREAMINFO_SIZE); + _x_parse_flac_streaminfo_block(&op->packet[17], &streaminfo); + break; + } + + this->si[stream_num]->buf_types = BUF_AUDIO_FLAC + +this->num_audio_streams++; + + _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_SAMPLERATE, streaminfo.samplerate); + _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_CHANNELS, streaminfo.channels); + _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITS, streaminfo.bits_per_sample); + + this->si[stream_num]->factor = 90000; + + buf = this->audio_fifo->buffer_pool_alloc(this->audio_fifo); + + buf->type = BUF_AUDIO_FLAC; + buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_STDHEADER|BUF_FLAG_FRAME_END; + + buf->decoder_info[0] = 0; + buf->decoder_info[1] = streaminfo.samplerate; + buf->decoder_info[2] = streaminfo.bits_per_sample; + buf->decoder_info[3] = streaminfo.channels; + buf->size = sizeof(xine_waveformatex) + FLAC_STREAMINFO_SIZE; + memcpy(buf->content+sizeof(xine_waveformatex), &op->packet[17], FLAC_STREAMINFO_SIZE); + xine_hexdump(&op->packet[17], FLAC_STREAMINFO_SIZE); + wave.cbSize = FLAC_STREAMINFO_SIZE; + memcpy(buf->content, &wave, sizeof(xine_waveformatex)); + + this->audio_fifo->put(this->audio_fifo, buf); + + /* Skip the Ogg framing info */ + op->bytes -= 9; + op->packet += 9; +} + static void decode_annodex_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) { lprintf ("Annodex stream detected\n"); this->si[stream_num]->buf_types = BUF_CONTROL_NOP; @@ -1325,6 +1390,8 @@ static void send_header (demux_ogg_t *this) { decode_text_header(this, stream_num, &op); } else if (!strncmp (&op.packet[1], "theora", 6)) { decode_theora_header(this, stream_num, &op); + } else if (!strncmp (&op.packet[1], "FLAC", 4)) { + decode_flac_header(this, stream_num, &op); } else if (!strncmp (&op.packet[0], "Annodex", 7)) { decode_annodex_header(this, stream_num, &op); } else if (!strncmp (&op.packet[0], "AnxData", 7)) { @@ -1439,7 +1506,7 @@ static int demux_ogg_send_chunk (demux_plugin_t *this_gen) { /* printf("demux_ogg: got a packet\n"); */ if ((*op.packet & PACKET_TYPE_HEADER) && - (this->si[stream_num]->buf_types!=BUF_VIDEO_THEORA) && (this->si[stream_num]->buf_types!=BUF_AUDIO_SPEEX)) { + (this->si[stream_num]->buf_types!=BUF_VIDEO_THEORA) && (this->si[stream_num]->buf_types!=BUF_AUDIO_SPEEX) && (this->si[stream_num]->buf_types!=BUF_AUDIO_FLAC)) { if (op.granulepos != -1) { this->si[stream_num]->header_granulepos = op.granulepos; lprintf ("header with granulepos, remembering granulepos\n"); diff --git a/src/demuxers/flacutils.h b/src/demuxers/flacutils.h new file mode 100644 index 000000000..67f5d66c9 --- /dev/null +++ b/src/demuxers/flacutils.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2006 the xine project + * Based on the FLAC File Demuxer by Mike Melanson + * + * 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 + */ + +#ifndef __FLACUTILS_H__ +#define __FLACUTILS_H__ + +typedef struct { + off_t offset; + int64_t sample_number; + int64_t pts; + int size; +} flac_seekpoint_t; + +#define FLAC_SIGNATURE_SIZE 4 +#define FLAC_STREAMINFO_SIZE 34 +#define FLAC_SEEKPOINT_SIZE 18 + +enum { + FLAC_BLOCKTYPE_STREAMINFO, + FLAC_BLOCKTYPE_PADDING, + FLAC_BLOCKTYPE_APPLICATION, + FLAC_BLOCKTYPE_SEEKTABLE, + FLAC_BLOCKTYPE_VORBIS_COMMENT, + FLAC_BLOCKTYPE_CUESHEET, + FLAC_BLOCKTYPE_INVALID = 127 +}; + +/* + * WARNING: These structures are *not* using the same format + * used by FLAC files, bitwise. + * + * Using bitfields to read the whole data is unfeasible because + * of endianness problems with non-byte-aligned values. + */ + +typedef struct { + uint8_t last; + uint8_t blocktype; + uint32_t length; +} xine_flac_metadata_header; + +typedef struct { + uint16_t blocksize_min; + uint16_t blocksize_max; + uint32_t framesize_min; + uint32_t framesize_max; + uint32_t samplerate; + uint8_t channels; + uint8_t bits_per_sample; + uint64_t total_samples; + uint8_t md5[16]; +} xine_flac_streaminfo_block; + +static inline void _x_parse_flac_metadata_header(uint8_t *buffer, xine_flac_metadata_header *parsed) { + parsed->last = buffer[0] & 0x80 ? 1 : 0; + parsed->blocktype = buffer[0] & 0x7f; + + parsed->length = BE_24(&buffer[1]); +} + +static inline void _x_parse_flac_streaminfo_block(uint8_t *buffer, xine_flac_streaminfo_block *parsed) { + parsed->blocksize_min = BE_16(&buffer[0]); + parsed->blocksize_max = BE_16(&buffer[2]); + parsed->framesize_min = BE_24(&buffer[4]); + parsed->framesize_max = BE_24(&buffer[7]); + parsed->samplerate = BE_32(&buffer[10]); + parsed->channels = ((parsed->samplerate >> 9) & 0x07) + 1; + parsed->bits_per_sample = ((parsed->samplerate >> 4) & 0x1F) + 1; + parsed->samplerate >>= 12; + parsed->total_samples = BE_64(&buffer[10]) & UINT64_C(0x0FFFFFFFFF); /* 36 bits */ +} + +#endif -- cgit v1.2.3