package org.kc7bfi.jflac.sound.spi; /** * libFLAC - Free Lossless Audio Codec library * Copyright (C) 2001,2002,2003 Josh Coalson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ import java.io.IOException; import java.io.InputStream; import javax.sound.sampled.AudioFormat; import org.kc7bfi.jflac.PCMProcessor; import org.kc7bfi.jflac.FLACDecoder; import org.kc7bfi.jflac.PropertiesContainer; import org.kc7bfi.jflac.frame.Frame; import org.kc7bfi.jflac.metadata.Metadata; import org.kc7bfi.jflac.metadata.StreamInfo; import org.kc7bfi.jflac.util.ByteData; import org.tritonus.share.sampled.convert.TAsynchronousFilteredAudioInputStream; /** * Converts an Flac bitstream into a PCM 16bits/sample audio stream. * * @author Marc Gimpel, Wimba S.A. (marc@wimba.com) * @author Florian Bomers * @version $Revision: 1.6 $ */ public class Flac2PcmAudioInputStream extends TAsynchronousFilteredAudioInputStream implements PropertiesContainer, PCMProcessor { /** The underlying inputStream. */ private InputStream in; /** Flac Decoder. */ private FLACDecoder decoder; private ByteData pcmData; /** StreamInfo MetaData. */ private StreamInfo streamInfo; /** the meta data from the stream */ private Metadata[] metaData; /** * Constructor. * * @param in the underlying input stream. * @param format the target format of this stream's audio data. * @param length the length in sample frames of the data in this stream. */ public Flac2PcmAudioInputStream(InputStream in, AudioFormat format) { super(format, -1); this.in = in; } /** * Initialize the Flac Decoder after reading the Header. * * @exception IOException */ protected void initDecoder() throws IOException { decoder = new FLACDecoder(in); decoder.addPCMProcessor(this); metaData = decoder.readMetadata(); } /** * Process the StreamInfo block. * * @param streamInfo the StreamInfo block * @see org.kc7bfi.jflac.PCMProcessor#processStreamInfo(org.kc7bfi.jflac.metadata.StreamInfo) */ public void processStreamInfo(StreamInfo streamInfo) { this.streamInfo = streamInfo; } /** * Process the decoded PCM bytes. This is called synchronously from the * fill() method. * * @param pcm The decoded PCM data * @see org.kc7bfi.jflac.PCMProcessor#processPCM(ByteData) */ public void processPCM(ByteData pcm) { getCircularBuffer().write(pcm.getData(), 0, pcm.getLen()); } /** * @return the streamInfo */ public StreamInfo getStreamInfo() { return streamInfo; } /** * @return the metaData */ public Metadata[] getMetaData() { return metaData; } @Override public long skip(long bytes) throws IOException { if (decoder == null) { initDecoder(); } if (decoder.isEOF()) { getCircularBuffer().close(); } else { // long sync = bytes % streamInfo.getMaxBlockSize(); // long bytesRead = super.skip(bytes - sync + 982); long bytesRead = 0L; bytes -= decoder.getTotalBytesRead(); while (bytesRead < bytes) { Frame frame = decoder.readNextFrame(); if (frame != null) { bytesRead = decoder.getTotalBytesRead(); } } return bytesRead; } return -1; } public void execute() { try { if (decoder == null) { initDecoder(); } if (decoder.isEOF()) { getCircularBuffer().close(); return; } else { Frame frame = decoder.readNextFrame(); if (frame != null) { pcmData = decoder.decodeFrame(frame, pcmData); processPCM(pcmData); } } } catch (IOException ex) { } } }