From a1a18f77a50804e0127dfa4b0f5240c49c541184 Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Mon, 2 Jul 2012 21:24:02 -0700 Subject: Initial Commit --- .../subsonic/io/TranscodeInputStream.java | 124 +++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 subsonic-main/src/main/java/net/sourceforge/subsonic/io/TranscodeInputStream.java (limited to 'subsonic-main/src/main/java/net/sourceforge/subsonic/io/TranscodeInputStream.java') diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/io/TranscodeInputStream.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/io/TranscodeInputStream.java new file mode 100644 index 00000000..b7a5e31e --- /dev/null +++ b/subsonic-main/src/main/java/net/sourceforge/subsonic/io/TranscodeInputStream.java @@ -0,0 +1,124 @@ +/* + This file is part of Subsonic. + + Subsonic 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 3 of the License, or + (at your option) any later version. + + Subsonic 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 Subsonic. If not, see . + + Copyright 2009 (C) Sindre Mehus + */ +package net.sourceforge.subsonic.io; + +import net.sourceforge.subsonic.*; + +import org.apache.commons.io.*; + +import java.io.*; + +/** + * Subclass of {@link InputStream} which provides on-the-fly transcoding. + * Instances of TranscodeInputStream can be chained together, for instance to convert + * from OGG to WAV to MP3. + * + * @author Sindre Mehus + */ +public class TranscodeInputStream extends InputStream { + + private static final Logger LOG = Logger.getLogger(TranscodeInputStream.class); + + private InputStream processInputStream; + private OutputStream processOutputStream; + private Process process; + private final File tmpFile; + + /** + * Creates a transcoded input stream by executing an external process. If in is not null, + * data from it is copied to the command. + * + * @param processBuilder Used to create the external process. + * @param in Data to feed to the process. May be {@code null}. + * @param tmpFile Temporary file to delete when this stream is closed. May be {@code null}. + * @throws IOException If an I/O error occurs. + */ + public TranscodeInputStream(ProcessBuilder processBuilder, final InputStream in, File tmpFile) throws IOException { + this.tmpFile = tmpFile; + + StringBuffer buf = new StringBuffer("Starting transcoder: "); + for (String s : processBuilder.command()) { + buf.append('[').append(s).append("] "); + } + LOG.debug(buf); + + process = processBuilder.start(); + processOutputStream = process.getOutputStream(); + processInputStream = process.getInputStream(); + + // Must read stderr from the process, otherwise it may block. + final String name = processBuilder.command().get(0); + new InputStreamReaderThread(process.getErrorStream(), name, true).start(); + + // Copy data in a separate thread + if (in != null) { + new Thread(name + " TranscodedInputStream copy thread") { + public void run() { + try { + IOUtils.copy(in, processOutputStream); + } catch (IOException x) { + // Intentionally ignored. Will happen if the remote player closes the stream. + } finally { + IOUtils.closeQuietly(in); + IOUtils.closeQuietly(processOutputStream); + } + } + }.start(); + } + } + + /** + * @see InputStream#read() + */ + public int read() throws IOException { + return processInputStream.read(); + } + + /** + * @see InputStream#read(byte[]) + */ + public int read(byte[] b) throws IOException { + return processInputStream.read(b); + } + + /** + * @see InputStream#read(byte[], int, int) + */ + public int read(byte[] b, int off, int len) throws IOException { + return processInputStream.read(b, off, len); + } + + /** + * @see InputStream#close() + */ + public void close() throws IOException { + IOUtils.closeQuietly(processInputStream); + IOUtils.closeQuietly(processOutputStream); + + if (process != null) { + process.destroy(); + } + + if (tmpFile != null) { + if (!tmpFile.delete()) { + LOG.warn("Failed to delete tmp file: " + tmpFile); + } + } + } +} -- cgit v1.2.3