public void startProcessing() { try { processor = Manager.createProcessor(getMainCamSource()); } catch (IOException e) { // JOptionPane.showMessageDialog(parent, // "IO Exception creating processor: " + e.getMessage(), "Error", // JOptionPane.WARNING_MESSAGE); return; } catch (NoProcessorException e) { // JOptionPane.showMessageDialog(parent, // "Exception creating processor: " + e.getMessage(), "Error", // JOptionPane.WARNING_MESSAGE); return; } CamStateHelper playhelper = new CamStateHelper(processor); if (!playhelper.configure(10000)) { JOptionPane.showMessageDialog( parent, "cannot configure processor", "Error", JOptionPane.WARNING_MESSAGE); return; } processor.setContentDescriptor(null); if (!playhelper.realize(10000)) { JOptionPane.showMessageDialog( parent, "cannot realize processor", "Error", JOptionPane.WARNING_MESSAGE); return; } // In order for or your clones to start, you must start the original source processor.start(); setProcessing(true); }
/** * Callback for controller events. This method is called by the processor whenever state changes. * * @param event - describes the nature of the state change. */ public synchronized void controllerUpdate(ControllerEvent event) { if (event instanceof ConfigureCompleteEvent) { // ConfigurationCompleteEvents come after we // call configure() and before we can call realize(). // At this point we can query the controls to figure // out what tracks we have. // Debug.trace("ConfigureCompleteEvent"); setHandlers(); // set content descriptor to null // so that the processor can be used as a player processor.setContentDescriptor(null); // request transition to realized state processor.realize(); } else if (event instanceof RealizeCompleteEvent) { // RealizeCompleteEvents come after we call realize() and // before we can call start() or do anything else interesting. // Debug.trace("RealizeCompleteEvent"); controlThread.setState(REALIZED | REWOUND); // at this point we should be able to access duration // we convert it to the vrml convention (-1 for unknown) double vrmlDuration; Time duration = processor.getDuration(); if (duration == Duration.DURATION_UNKNOWN || duration == Duration.DURATION_UNBOUNDED) { vrmlDuration = -1.0; } else { vrmlDuration = duration.getSeconds(); } videoHandler.videoStreamDuration(vrmlDuration); // finally we call prefetch will will send the first // frame to the video handler. processor.prefetch(); } else if (event instanceof StartEvent) { controlThread.setState(STARTED); // set STARTED controlThread.unsetState(REWOUND); // clear REWOUND } else if (event instanceof StopEvent) { // includes EndOfMediaEvent, StopByRequestEvent controlThread.unsetState(STARTED); // clear STARTED } else if (event instanceof MediaTimeSetEvent) { controlThread.setState(TIMESET); // notify any waiting thread } }
/** With the given processor info generated from matchTracks, build each of the processors. */ public boolean buildTracks(ProcInfo pInfo[]) { ContentDescriptor cd = new ContentDescriptor(ContentDescriptor.RAW); Processor p; for (int i = 0; i < pInfo.length; i++) { p = pInfo[i].p; p.setContentDescriptor(cd); // We are done with programming the processor. Let's just // realize the it. if (!waitForState(p, Controller.Realized)) { System.err.println("- Failed to realize the processor."); return false; } // Set the JPEG quality to .5. setJPEGQuality(p, 0.5f); PushBufferStream pbs[]; TrackInfo tInfo; int trackID; // Cheating. I should have checked the type of DataSource // returned. pInfo[i].ds = (PushBufferDataSource) p.getDataOutput(); pbs = pInfo[i].ds.getStreams(); // Find the matching data stream for the given track for audio. for (int type = AUDIO; type < MEDIA_TYPES; type++) { for (trackID = 0; trackID < pInfo[i].numTracksByType[type]; trackID++) { tInfo = pInfo[i].tracksByType[type][trackID]; tInfo.pbs = pbs[tInfo.idx]; } } } return true; }
/** * Creates a video stream of the interactions with the given component at the specified frame rate * and saves it as the given file. */ public static Processor recordVideo(Component component, int fps, File dest) { if (component == null) return null; Dimension size = component.getSize(); Point location = component.getLocationOnScreen(); String loc = MessageFormat.format( "screen://{0},{1},{2},{3}/{4}", new Object[] { new Integer(location.x), new Integer(location.y), new Integer(size.width - size.width % 8), new Integer(size.height - size.height % 8), new Integer(fps) }); MediaLocator mSource = new MediaLocator(loc); Processor p = null; try { DataSource data = Manager.createDataSource(mSource); p = Manager.createProcessor(mSource); waitForState(p, Processor.Configured); p.setContentDescriptor(new FileTypeDescriptor("video.x_msvideo")); p.getTrackControls()[0].setFormat(new VideoFormat(VideoFormat.MJPG)); waitForState(p, Processor.Realized); DataSource data2 = p.getDataOutput(); String path = dest.getParent(); String name = dest.getName(); if (!name.toLowerCase().endsWith(".avi")) name += ".avi"; MediaLocator mediaDest = new MediaLocator(new File(path, name).toURL()); DataSink dataSink = Manager.createDataSink(data2, mediaDest); dataSink.open(); dataSink.start(); p.start(); } catch (Exception ex) { ex.printStackTrace(); p = null; } return p; }
public static void main(String[] args) { if (args.length != 2) { System.out.println("Usage: rtpaudio <targetIP> <targetPort>"); System.exit(0); } try { RegistryDefaults.setDefaultFlags(RegistryDefaults.FMJ); // create a clean registry RegistryDefaults.unRegisterAll(RegistryDefaults.ALL); RegistryDefaults.registerAll(RegistryDefaults.FMJ); // remove all capture devices Vector deviceList = (Vector) CaptureDeviceManager.getDeviceList(null).clone(); for (int i = 0; i < deviceList.size(); i++) { CaptureDeviceInfo cdi = (CaptureDeviceInfo) deviceList.elementAt(i); CaptureDeviceManager.removeDevice(cdi); } // update capture device list new net.sf.fmj.media.cdp.javasound.CaptureDevicePlugger().addCaptureDevices(); PlugInManager.commit(); deviceList = (Vector) CaptureDeviceManager.getDeviceList(null).clone(); if ((null == deviceList) || (deviceList.size() == 0)) { System.out.println("### ERROR found no audio capture device"); System.exit(0); } // enumerate all codec Vector codecList = PlugInManager.getPlugInList(null, null, PlugInManager.CODEC); System.out.println("found " + codecList.size() + " codec"); for (int i = 0; i < codecList.size(); i++) { String aCodecClass = (String) codecList.elementAt(i); System.out.println("# " + (i + 1) + " " + aCodecClass); } // fetch first available audio capture device deviceList = (Vector) CaptureDeviceManager.getDeviceList(null).clone(); CaptureDeviceInfo captureDeviceInfo = (CaptureDeviceInfo) deviceList.elementAt(0); System.out.println("### using " + captureDeviceInfo.getName()); System.out.println("### locator " + captureDeviceInfo.getLocator()); javax.media.protocol.DataSource dataSource = javax.media.Manager.createDataSource( new javax.media.MediaLocator(captureDeviceInfo.getLocator().toString())); // javax.media.protocol.DataSource dataSource = // javax.media.Manager.createDataSource(new // javax.media.MediaLocator("javasound://")); System.out.println("### created datasource " + dataSource.getClass().getName()); javax.media.control.FormatControl[] formatControls = ((javax.media.protocol.CaptureDevice) dataSource).getFormatControls(); System.out.println("got format control " + formatControls[0].getClass().getName()); System.out.println("current format is " + formatControls[0].getFormat()); // set audio capture format javax.media.Format[] formats = formatControls[0].getSupportedFormats(); for (int i = 0; i < formats.length; i++) { javax.media.format.AudioFormat af = (javax.media.format.AudioFormat) formats[i]; if ((af.getChannels() == 1) && (af.getSampleSizeInBits() == 16)) { if (af.getSampleRate() == Format.NOT_SPECIFIED) { javax.media.format.AudioFormat newAudioFormat = new javax.media.format.AudioFormat( af.getEncoding(), 8000.0f, javax.media.Format.NOT_SPECIFIED, javax.media.Format.NOT_SPECIFIED); // javax.media.format.AudioFormat newAudioFormat = new // javax.media.format.AudioFormat(af.getEncoding(), // 44100.0f, javax.media.Format.NOT_SPECIFIED, // javax.media.Format.NOT_SPECIFIED); formatControls[0].setFormat(newAudioFormat.intersects(af)); break; } } } System.out.println("current format is now " + formatControls[0].getFormat()); FrameProcessingControl fpc = null; // adujst recording buffer ( to adjust latency ) dataSource.stop(); Object[] controls = dataSource.getControls(); for (int i = 0; i < controls.length; i++) { String className = controls[i].getClass().getName(); if (-1 != className.indexOf("JavaSoundBufferControl")) { javax.media.control.BufferControl bc = (javax.media.control.BufferControl) controls[i]; System.out.println( "### current javasound buffer length is " + bc.getBufferLength() + " ms"); bc.setBufferLength(40); System.out.println( "### current javasound buffer length is " + bc.getBufferLength() + " ms"); } else if (-1 != className.indexOf("JitterBufferControl")) { javax.media.control.BufferControl bc = (javax.media.control.BufferControl) controls[i]; System.out.println("### current jitter buffer length is " + bc.getBufferLength() + " ms"); bc.setBufferLength(80); System.out.println("### current jitter buffer length is " + bc.getBufferLength() + " ms"); } else if (-1 != className.indexOf("FPC")) { fpc = (FrameProcessingControl) controls[i]; System.out.println("### found bitrate control " + fpc.getClass()); } } dataSource.start(); // create processor javax.media.Processor processor = javax.media.Manager.createProcessor(dataSource); System.out.println("### created processor " + processor.getClass().getName()); processor.configure(); for (int idx = 0; idx < 100; idx++) { if (processor.getState() == Processor.Configured) { break; } Thread.sleep(100); } System.out.println("### processor state " + processor.getState()); processor.setContentDescriptor( new javax.media.protocol.ContentDescriptor(ContentDescriptor.RAW_RTP)); javax.media.control.TrackControl[] tracks = processor.getTrackControls(); // /tracks[0].setFormat(new // javax.media.format.AudioFormat(javax.media.format.AudioFormat.ULAW_RTP, // 8000, 8, 1)); tracks[0].setFormat( new javax.media.format.AudioFormat(javax.media.format.AudioFormat.GSM_RTP, 8000, 8, 1)); processor.realize(); for (int idx = 0; idx < 100; idx++) { if (processor.getState() == Controller.Realized) { break; } Thread.sleep(100); } System.out.println("### processor state " + processor.getState()); javax.media.protocol.DataSource dataOutput = processor.getDataOutput(); System.out.println("### processor data output " + dataOutput.getClass().getName()); // BitRateControl BitRateControl bitrateControl = null; Object[] controls2 = dataOutput.getControls(); for (int i = 0; i < controls2.length; i++) { if (controls2[i] instanceof BitRateControl) { bitrateControl = (BitRateControl) controls2[i]; System.out.println("### found bitrate control " + bitrateControl.getClass()); break; } } // PacketSizeControl Object[] controls3 = processor.getControls(); for (int i = 0; i < controls3.length; i++) { if (controls3[i] instanceof PacketSizeControl) { PacketSizeControl psc = (PacketSizeControl) controls3[i]; System.out.println("### current packetsize is " + psc.getPacketSize() + " bytes"); psc.setPacketSize(66); System.out.println("### current packetsize is " + psc.getPacketSize() + " bytes"); break; } } // enumerate all controls of the processor Object[] pcontrols = processor.getControls(); for (int i = 0; i < pcontrols.length; i++) { System.out.println("processor control " + i + " " + pcontrols[i]); } javax.media.rtp.RTPManager rtpManager = javax.media.rtp.RTPManager.newInstance(); javax.media.rtp.SessionAddress local = new javax.media.rtp.SessionAddress( InetAddress.getLocalHost(), Integer.valueOf(args[1]).intValue()); javax.media.rtp.SessionAddress target = new javax.media.rtp.SessionAddress( InetAddress.getByName(args[0]), Integer.valueOf(args[1]).intValue()); rtpManager.initialize(local); rtpManager.addTarget(target); javax.media.rtp.SendStream sendStream = rtpManager.createSendStream(dataOutput, 0); sendStream.start(); processor.start(); Thread.sleep(1000); System.out.println("\n>>>>>> TRANSMITTING ULAW/RTP AUDIO NOW"); while (2 > 1) { Thread.sleep(1000); if (null != bitrateControl) { TransmissionStats stats = sendStream.getSourceTransmissionStats(); System.out.println( "rtp audio send: bitrate=" + bitrateControl.getBitRate() + " (pdu=" + stats.getPDUTransmitted() + " bytes=" + stats.getBytesTransmitted() + " overrun=" + fpc.getFramesDropped() + ")"); } } } catch (Exception ex) { ex.printStackTrace(); } System.exit(0); }
/** * Implements {@link ControllerListener#controllerUpdate(ControllerEvent)}. Handles events from * the <tt>Processor</tt>s that this instance uses to transcode media. * * @param ev the event to handle. */ public void controllerUpdate(ControllerEvent ev) { if (ev == null || ev.getSourceController() == null) { return; } Processor processor = (Processor) ev.getSourceController(); ReceiveStreamDesc desc = findReceiveStream(processor); if (desc == null) { logger.warn("Event from an orphaned processor, ignoring: " + ev); return; } if (ev instanceof ConfigureCompleteEvent) { if (logger.isInfoEnabled()) { logger.info( "Configured processor for ReceiveStream ssrc=" + desc.ssrc + " (" + desc.format + ")" + " " + System.currentTimeMillis()); } boolean audio = desc.format instanceof AudioFormat; if (audio) { ContentDescriptor cd = processor.setContentDescriptor(AUDIO_CONTENT_DESCRIPTOR); if (!AUDIO_CONTENT_DESCRIPTOR.equals(cd)) { logger.error( "Failed to set the Processor content " + "descriptor to " + AUDIO_CONTENT_DESCRIPTOR + ". Actual result: " + cd); removeReceiveStream(desc, false); return; } } for (TrackControl track : processor.getTrackControls()) { Format trackFormat = track.getFormat(); if (audio) { final long ssrc = desc.ssrc; SilenceEffect silenceEffect; if (Constants.OPUS_RTP.equals(desc.format.getEncoding())) { silenceEffect = new SilenceEffect(48000); } else { // We haven't tested that the RTP timestamps survive // the journey through the chain when codecs other than // opus are in use, so for the moment we rely on FMJ's // timestamps for non-opus formats. silenceEffect = new SilenceEffect(); } silenceEffect.setListener( new SilenceEffect.Listener() { boolean first = true; @Override public void onSilenceNotInserted(long timestamp) { if (first) { first = false; // send event only audioRecordingStarted(ssrc, timestamp); } else { // change file and send event resetRecording(ssrc, timestamp); } } }); desc.silenceEffect = silenceEffect; AudioLevelEffect audioLevelEffect = new AudioLevelEffect(); audioLevelEffect.setAudioLevelListener( new SimpleAudioLevelListener() { @Override public void audioLevelChanged(int level) { activeSpeakerDetector.levelChanged(ssrc, level); } }); try { // We add an effect, which will insert "silence" in // place of lost packets. track.setCodecChain(new Codec[] {silenceEffect, audioLevelEffect}); } catch (UnsupportedPlugInException upie) { logger.warn("Failed to insert silence effect: " + upie); // But do go on, a recording without extra silence is // better than nothing ;) } } else { // transcode vp8/rtp to vp8 (i.e. depacketize vp8) if (trackFormat.matches(vp8RtpFormat)) track.setFormat(vp8Format); else { logger.error("Unsupported track format: " + trackFormat + " for ssrc=" + desc.ssrc); // we currently only support vp8 removeReceiveStream(desc, false); return; } } } processor.realize(); } else if (ev instanceof RealizeCompleteEvent) { desc.dataSource = processor.getDataOutput(); long ssrc = desc.ssrc; boolean audio = desc.format instanceof AudioFormat; String suffix = audio ? AUDIO_FILENAME_SUFFIX : VIDEO_FILENAME_SUFFIX; // XXX '\' on windows? String filename = getNextFilename(path + "/" + ssrc, suffix); desc.filename = filename; DataSink dataSink; if (audio) { try { dataSink = Manager.createDataSink(desc.dataSource, new MediaLocator("file:" + filename)); } catch (NoDataSinkException ndse) { logger.error("Could not create DataSink: " + ndse); removeReceiveStream(desc, false); return; } } else { dataSink = new WebmDataSink(filename, desc.dataSource); } if (logger.isInfoEnabled()) logger.info( "Created DataSink (" + dataSink + ") for SSRC=" + ssrc + ". Output filename: " + filename); try { dataSink.open(); } catch (IOException e) { logger.error("Failed to open DataSink (" + dataSink + ") for" + " SSRC=" + ssrc + ": " + e); removeReceiveStream(desc, false); return; } if (!audio) { final WebmDataSink webmDataSink = (WebmDataSink) dataSink; webmDataSink.setSsrc(ssrc); webmDataSink.setEventHandler(eventHandler); webmDataSink.setKeyFrameControl( new KeyFrameControlAdapter() { @Override public boolean requestKeyFrame(boolean urgent) { return requestFIR(webmDataSink); } }); } try { dataSink.start(); } catch (IOException e) { logger.error( "Failed to start DataSink (" + dataSink + ") for" + " SSRC=" + ssrc + ". " + e); removeReceiveStream(desc, false); return; } if (logger.isInfoEnabled()) logger.info("Started DataSink for SSRC=" + ssrc); desc.dataSink = dataSink; processor.start(); } else if (logger.isDebugEnabled()) { logger.debug( "Unhandled ControllerEvent from the Processor for ssrc=" + desc.ssrc + ": " + ev); } }
/** * Given an array of input media locators and an output locator, this method will concatenate the * input media files to generate a single concatentated output. */ public boolean doIt(MediaLocator inML[], MediaLocator outML) { // Guess the output content descriptor from the file extension. ContentDescriptor cd; if ((cd = fileExtToCD(outML.getRemainder())) == null) { System.err.println("Couldn't figure out from the file extension the type of output needed!"); return false; } // Build the ProcInfo data structure for each processor. ProcInfo pInfo[] = new ProcInfo[inML.length]; for (int i = 0; i < inML.length; i++) { pInfo[i] = new ProcInfo(); pInfo[i].ml = inML[i]; try { System.err.println("- Create processor for: " + inML[i]); pInfo[i].p = Manager.createProcessor(inML[i]); } catch (Exception e) { System.err.println("Yikes! Cannot create a processor from the given url: " + e); return false; } } // Try to match the tracks from different processors. if (!matchTracks(pInfo, cd)) { System.err.println("Failed to match the tracks."); return false; } // Program each processors to perform the necessary transcoding // to concatenate the tracks. if (!buildTracks(pInfo)) { System.err.println("Failed to build processors for the inputs."); return false; } // Generate a super glue data source from the processors. SuperGlueDataSource ds = new SuperGlueDataSource(pInfo); // Create the processor to generate the final output. Processor p; try { p = Manager.createProcessor(ds); } catch (Exception e) { System.err.println("Failed to create a processor to concatenate the inputs."); return false; } p.addControllerListener(this); // Put the Processor into configured state. if (!waitForState(p, Processor.Configured)) { System.err.println("Failed to configure the processor."); return false; } // Set the output content descriptor on the final processor. System.err.println("- Set output content descriptor to: " + cd); if ((p.setContentDescriptor(cd)) == null) { System.err.println("Failed to set the output content descriptor on the processor."); return false; } // We are done with programming the processor. Let's just // realize it. if (!waitForState(p, Controller.Realized)) { System.err.println("Failed to realize the processor."); return false; } // Now, we'll need to create a DataSink. DataSink dsink; if ((dsink = createDataSink(p, outML)) == null) { System.err.println("Failed to create a DataSink for the given output MediaLocator: " + outML); return false; } dsink.addDataSinkListener(this); fileDone = false; System.err.println("- Start concatenation..."); // OK, we can now start the actual concatenation. try { p.start(); dsink.start(); } catch (IOException e) { System.err.println("IO error during concatenation"); return false; } // Wait for EndOfStream event. waitForFileDone(); // Cleanup. try { dsink.close(); } catch (Exception e) { } p.removeControllerListener(this); System.err.println(" ...done concatenation."); return true; }
private String createProcessor() { if (locator == null) return "Locator is null"; DataSource ds; DataSource clone; try { ds = Manager.createDataSource(locator); } catch (Exception e) { return "Couldn't create DataSource"; } // Try to create a processor to handle the input media locator try { processor = Manager.createProcessor(ds); } catch (NoProcessorException npe) { return "Couldn't create processor"; } catch (IOException ioe) { return "IOException creating processor"; } // Wait for it to configure boolean result = waitForState(processor, Processor.Configured); if (result == false) return "Couldn't configure processor"; // Get the tracks from the processor TrackControl[] tracks = processor.getTrackControls(); // Do we have atleast one track? if (tracks == null || tracks.length < 1) return "Couldn't find tracks in processor"; boolean programmed = false; // Search through the tracks for a video track for (int i = 0; i < tracks.length; i++) { Format format = tracks[i].getFormat(); if (tracks[i].isEnabled() && format instanceof VideoFormat && !programmed) { // Found a video track. Try to program it to output JPEG/RTP // Make sure the sizes are multiple of 8's. Dimension size = ((VideoFormat) format).getSize(); float frameRate = ((VideoFormat) format).getFrameRate(); int w = (size.width % 8 == 0 ? size.width : (int) (size.width / 8) * 8); int h = (size.height % 8 == 0 ? size.height : (int) (size.height / 8) * 8); VideoFormat jpegFormat = new VideoFormat( VideoFormat.JPEG_RTP, new Dimension(w, h), Format.NOT_SPECIFIED, Format.byteArray, frameRate); tracks[i].setFormat(jpegFormat); System.err.println("Video transmitted as:"); System.err.println(" " + jpegFormat); // Assume succesful programmed = true; } else tracks[i].setEnabled(false); } if (!programmed) return "Couldn't find video track"; // Set the output content descriptor to RAW_RTP ContentDescriptor cd = new ContentDescriptor(ContentDescriptor.RAW_RTP); processor.setContentDescriptor(cd); // Realize the processor. This will internally create a flow // graph and attempt to create an output datasource for JPEG/RTP // video frames. result = waitForState(processor, Controller.Realized); if (result == false) return "Couldn't realize processor"; // Set the JPEG quality to .5. setJPEGQuality(processor, 0.5f); // Get the output data source of the processor dataOutput = processor.getDataOutput(); return null; }