📄 handler.java
字号:
{ FilterGraph.stop(root); } catch (IOException e) { logger.log(Level.WARNING, "" + e, e); postControllerErrorEvent("" + e); return false; } return true; } private boolean firstStart = true; //@Override public boolean doPlayerSyncStart(Time time) { logger.info("Handler.doPlayerSyncStart " + time + " " + getState()); // the first time we start, the threads are usually in place. we only need to // create them here if we've been stopped. if (firstStart) { firstStart = false; } else { // TODO: this code is duplicated in doRealize. if (TRACE) logger.fine("Starting filter graph(s)"); try { FilterGraph.start(root); } catch (IOException e) { logger.log(Level.WARNING, "" + e, e); postControllerErrorEvent("" + e); return false; } // TODO: we need to go to the correct time! trackThreads = new TrackThread[root.getNumDestLinks()]; for (int i = 0; i < root.getNumDestLinks(); ++i) { if (root.getDestLink(i) != null) { final DemuxNode rootCopy = (DemuxNode) root.duplicate(); trackThreads[i] = new TrackThread(rootCopy, i, FilterGraph.PROCESS_DEFAULT); // use a copy of the graph for each thread, so that they don't interfere with each other. } } } for (int i = 0; i < trackThreads.length; ++i) { final TrackThread t = trackThreads[i]; if (t != null) t.start(); } return true; } //@Override public Time getPlayerDuration() { // tricky because this gets called by the parent class. during realize, so we won't be in the realized state // although we already have the tracks. if( getState() < Realizing || root == null ) { logger.fine("getPlayerDuration: returning demuxDuration"); return demuxDuration; } else { // if( getState() < Prefetched ) { // code borrowed from AbstractPlayer. TODO: once each track has its own controller, there will be no need for this to be calculated here. Time duration = null; //Time d = getSource().getDuration(); //if (duration != null && duration.getNanoseconds() != Duration.DURATION_UNKNOWN.getNanoseconds() final Track[] tracks = root.getTracks(); for (int i = 0; i < tracks.length; ++i) { try { Time d = tracks[i].getDuration(); logger.fine("Track " + i + " has duration of " + d.getNanoseconds()); if (duration == null) { duration = d; continue; } if (d == DURATION_UNKNOWN ) { duration = d; break; } if( duration != DURATION_UNBOUNDED && ( d == DURATION_UNBOUNDED || d.getNanoseconds() > duration.getNanoseconds() ) ) { duration = d; } } catch (Exception e) { logger.log(Level.WARNING, "" + e, e); continue; // TODO: we get an NPE in at com.sun.media.parser.RawBufferParser$FrameTrack.getDuration(RawBufferParser.java:227) // when using that class for RTP reception. Not sure why this is occurring, if it is a bug in JMF or FMJ. // for now, this is just a workaround so that we can continue. } } if (duration == null) { logger.fine("getPlayerDuration: returning DURATION_UNKNOWN (2)"); return DURATION_UNKNOWN; } logger.fine("getPlayerDuration: returning " + duration.getNanoseconds()); return duration; } // TODO: // } else// // return DURATION_UNKNOWN; // TODO// TODO: } //@Override public Time getPlayerStartLatency() { return new Time(0); } //@Override public Component getVisualComponent() { return visualComponent; } // Processor: public boolean doConfigure() { if (mode == PLAYER) throw new UnsupportedOperationException(); // TODO: what to do here? return true; } public DataSource getDataOutput() throws NotRealizedError { if (mode == PLAYER) throw new UnsupportedOperationException(); if (getState() < Realized) throw new NotRealizedError("Cannot call getDataOutput on an unrealized Processor."); final MuxNode muxNode = (MuxNode) FilterGraph.getTail(root.getDestLink(0).getDestNode()); // TODO: hard coded to track zero return muxNode.getMultiplexer().getDataOutput(); } private TrackControl[] trackControls; public TrackControl[] getTrackControls() throws NotConfiguredError { if (mode == PLAYER) throw new UnsupportedOperationException(); if (getState() < Configured) throw new NotConfiguredError("Cannot call getTrackControls on an unconfigured Processor."); if (trackControls == null) { try { if (!getDemuxTracks()) throw new RuntimeException("Unable to get demux tracks"); final Track[] tracks = demux.getTracks(); trackControls = new TrackControl[tracks.length]; for (int trackNum = 0; trackNum < tracks.length; ++trackNum) { trackControls[trackNum] = new MyTrackControl(trackNum); } } catch (IOException e) { throw new RuntimeException(e); } catch (BadHeaderException e) { throw new RuntimeException(e); } } return trackControls; } public ContentDescriptor[] getSupportedContentDescriptors() throws NotConfiguredError { if (mode == PLAYER) throw new UnsupportedOperationException(); if (getState() < Configured) throw new NotConfiguredError("Cannot call getSupportedContentDescriptors on an unconfigured Processor."); final List muxs = /*<Multiplexer>*/ FilterGraph.findMuxs(); // TODO: only find ones that are reachable given the input final List/*<ContentDescriptor>*/ result = new ArrayList(); for (int i = 0; i < muxs.size(); ++i) { final Multiplexer mux = (Multiplexer) muxs.get(i); final Format[] f = mux.getSupportedOutputContentDescriptors(null); for (int j = 0; j < f.length; ++j) result.add(f[j]); } final ContentDescriptor[] arrayResult = new ContentDescriptor[result.size()]; for (int i = 0; i < result.size(); ++i) arrayResult[i] = (ContentDescriptor) result.get(i); return arrayResult; } /** builds mux muxInputFormats, only if not already built */ private void buildMux() { if (mux != null) return; if (!getDemuxTracks()) throw new RuntimeException("Unable to get demux tracks"); mux = FilterGraph.findMux(outputContentDescriptor); // TODO: this works for RAW, but not RAW_RTP if (mux == null) throw new RuntimeException("Unable to find mux for " + outputContentDescriptor); mux.setNumTracks(numTracks); mux.setContentDescriptor(outputContentDescriptor); muxInputFormats = new Format[numTracks]; // by default, input formats to the mux will be the same as the output formats // of the demux. If the caller uses a TrackControl, they can change this. for (int i = 0; i < numTracks; ++i) { muxInputFormats[i] = mux.setInputFormat(tracks[i].getFormat(), i); } } // TODO: implement. // this appears to be able to control how the filter graph is built. private class MyTrackControl implements TrackControl { private final int trackNum; public MyTrackControl(final int trackNum) { super(); this.trackNum = trackNum; } public void setCodecChain(Codec[] codecs) throws UnsupportedPlugInException, NotConfiguredError { // TODO } public void setRenderer(Renderer renderer) throws UnsupportedPlugInException, NotConfiguredError {// TODO } public Object getControl(String controlType) { return null; } public Object[] getControls() { return new Object[0]; } public Format getFormat() { if (!getDemuxTracks()) throw new RuntimeException("Unable to get demux tracks"); if (muxInputFormats == null) return tracks[trackNum].getFormat(); // TODO: this appears to be what JMF returns, if the format is not set. return muxInputFormats[trackNum]; } public Format[] getSupportedFormats() { buildMux(); // Not sure when JMF builds the MUX. // TODO: FMJ returns this, but JMF returns a bunch of specific formats. // we need to build FilterGraph.buildGraphToMux for this track, for all // possible codec chains from the demux to the mux. // if the mux supports multiple input formats, we should probably build all // possible codec chains to all possible muxs. // in FMJ, this is a relatively slow operation, by the way. return mux.getSupportedInputFormats(); } private boolean enabled = true; public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled;// TODO: how to actually make this take effect, if it is false? } public Format setFormat(Format format) { buildMux(); // Not sure when JMF builds the MUX. // supposed to set the format of the input to this track of the MUX. // this means we must already have created the mux? // or maybe what this means, is we have to build a chain of configured codecs to // get to the mux? // I think what this means is that we build the mux, and set the input format for this // track on the mux. when it comes time to build the graph, the input format on the mux // is already fixed, so we don't negotiate it. muxInputFormats[trackNum] = mux.setInputFormat(format, trackNum); return muxInputFormats[trackNum]; } public Component getControlComponent() { return null; } } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -