/** Gets the correct codec from the camera */ public Codec fetchCodec(Format inFormat, Format outFormat) { Vector codecs = PlugInManager.getPlugInList(inFormat, outFormat, PlugInManager.CODEC); if (codecs == null) return null; for (int i = 0; i < codecs.size(); i++) { Codec codec = null; try { Class codecClass = Class.forName((String) codecs.elementAt(i)); if (codecClass != null) codec = (Codec) codecClass.newInstance(); } catch (Exception e) { continue; } if (codec == null || codec.setInputFormat(inFormat) == null) continue; Format[] outFormats = codec.getSupportedOutputFormats(inFormat); if (outFormats == null) continue; for (int j = 0; j < outFormats.length; j++) { if (outFormats[j].matches(outFormat)) { try { codec.setOutputFormat(outFormats[j]); codec.open(); return codec; } catch (Exception e) { } } } } return null; }
/** Free the data line. */ public void close() { logger.info("closing..."); controls.clear(); if (codec != null) { codec.close(); codec = null; } sourceLine.close(); sourceLine = null; }
/** Gets an image via the cam */ boolean camFetchFrame() { try { if (converter == null) { pbs.read(buffer); } else { if (inputBuffer == null) { inputBuffer = new Buffer(); } pbs.read(inputBuffer); converter.process(inputBuffer, buffer); } if (buffer.isDiscard()) { buffer.setDiscard(false); return false; } if (buffer.getData() == null) { return false; } } catch (Exception e) { return false; } return true; }
/** Write the buffer to the SourceDataLine. */ public int process(Buffer buffer) { // if we need to convert the format, do so using the codec. if (codec != null) { final int codecResult = codec.process(buffer, codecBuffer); if (codecResult == BUFFER_PROCESSED_FAILED) return BUFFER_PROCESSED_FAILED; if (codecResult == OUTPUT_BUFFER_NOT_FILLED) return BUFFER_PROCESSED_OK; buffer = codecBuffer; } int length = buffer.getLength(); int offset = buffer.getOffset(); final Format format = buffer.getFormat(); final Class type = format.getDataType(); if (type != Format.byteArray) { return BUFFER_PROCESSED_FAILED; } final byte[] data = (byte[]) buffer.getData(); final boolean bufferNotConsumed; final int newBufferLength; // only applicable if bufferNotConsumed final int newBufferOffset; // only applicable if bufferNotConsumed if (NON_BLOCKING) { // TODO: handle sourceLine.available(). This code currently causes choppy audio. if (length > sourceLine.available()) { // we should only write sourceLine.available() bytes, then return INPUT_BUFFER_NOT_CONSUMED. length = sourceLine.available(); // don't try to write more than available bufferNotConsumed = true; newBufferLength = buffer.getLength() - length; newBufferOffset = buffer.getOffset() + length; } else { bufferNotConsumed = false; newBufferLength = length; newBufferOffset = offset; } } else { bufferNotConsumed = false; newBufferLength = 0; newBufferOffset = 0; } if (length == 0) { logger.finer("Buffer has zero length, flags = " + buffer.getFlags()); } // make sure all the bytes are written. while (length > 0) { // logger.fine("Available: " + sourceLine.available()); // logger.fine("length: " + length); // logger.fine("sourceLine.getBufferSize(): " + sourceLine.getBufferSize()); final int n = sourceLine.write( data, offset, length); // TODO: this can block for a very long time if it doesn't if (n >= length) break; else if (n == 0) { // TODO: we could choose to handle a write failure this way, // assuming that it is considered legal to call stop while process is being called. // however, that seems like a bad idea in general. // if (!sourceLine.isRunning()) // { // buffer.setLength(offset); // buffer.setOffset(length); // return INPUT_BUFFER_NOT_CONSUMED; // our write was interrupted. // } logger.warning( "sourceLine.write returned 0, offset=" + offset + "; length=" + length + "; available=" + sourceLine.available() + "; frame size in bytes" + sourceLine.getFormat().getFrameSize() + "; sourceLine.isActive() = " + sourceLine.isActive() + "; " + sourceLine.isOpen() + "; sourceLine.isRunning()=" + sourceLine.isRunning()); return BUFFER_PROCESSED_FAILED; // sourceLine.write docs indicate that this will only happen // if there is an error. } else { offset += n; length -= n; } } if (bufferNotConsumed) { // return INPUT_BUFFER_NOT_CONSUMED if not all bytes were written buffer.setLength(newBufferLength); buffer.setOffset(newBufferOffset); return INPUT_BUFFER_NOT_CONSUMED; } if (buffer.isEOM()) { // TODO: the proper way to do this is to implement Drainable, and let the processor call our // drain method. sourceLine .drain(); // we need to ensure that the media finishes playing, otherwise the EOM event // will // be posted before the media finishes playing. } return BUFFER_PROCESSED_OK; }
/** * Open the plugin. Must be called after the formats have been determined and before "process" is * called. * * <p>Open the DataLine. */ public void open() throws ResourceUnavailableException { javax.sound.sampled.AudioFormat audioFormat = convertFormat(inputFormat); logger.info("opening with javax.sound format: " + audioFormat); try { if (!inputFormat.getEncoding().equals(AudioFormat.LINEAR)) { logger.info("JavaSoundRenderer: Audio format is not linear, creating conversion"); if (inputFormat.getEncoding().equals(AudioFormat.ULAW)) codec = new net.sf.fmj.media.codec.audio.ulaw .Decoder(); // much more efficient than JavaSoundCodec else if (inputFormat.getEncoding().equals(AudioFormat.ALAW)) codec = new net.sf.fmj.media.codec.audio.alaw .Decoder(); // much more efficient than JavaSoundCodec else throw new ResourceUnavailableException( "Unsupported input format encoding: " + inputFormat.getEncoding()); // codec = new net.sf.fmj.media.codec.JavaSoundCodec(); codec.setInputFormat(inputFormat); final Format[] outputFormats = codec.getSupportedOutputFormats(inputFormat); if (outputFormats.length < 1) throw new ResourceUnavailableException( "Unable to get an output format for input format: " + inputFormat); final AudioFormat codecOutputFormat = (AudioFormat) outputFormats[0]; // TODO: choose the best quality one. codec.setOutputFormat(codecOutputFormat); audioFormat = convertFormat(codecOutputFormat); codec.open(); logger.info( "JavaSoundRenderer: Audio format is not linear, created conversion from " + inputFormat + " to " + codecOutputFormat); } sourceLine = getSourceDataLine(audioFormat); sourceLine.open(audioFormat); { FloatControl gainFloatControl = null; BooleanControl muteBooleanControl = null; try { gainFloatControl = (FloatControl) sourceLine.getControl(FloatControl.Type.MASTER_GAIN); } catch (Exception e) { e.printStackTrace(); } try { muteBooleanControl = (BooleanControl) sourceLine.getControl(BooleanControl.Type.MUTE); } catch (Exception e) { e.printStackTrace(); } // TODO add other controls JavaSoundGainControl gainControl = new JavaSoundGainControl(gainFloatControl, muteBooleanControl); controls.addControl(gainControl); } logControls(sourceLine.getControls()); } catch (LineUnavailableException e) { throw new ResourceUnavailableException(e.getMessage()); } }