From 4f504469bd4dc187cd09c664a3ed9aba9691bdd2 Mon Sep 17 00:00:00 2001 From: Lyubomir Marinov Date: Fri, 17 Jun 2011 16:27:23 +0000 Subject: [PATCH] Implements a workaround which allows the H.264 decoder to request key frames in addition to the depacketizer. --- .../codec/video/h264/DePacketizer.java | 15 +++++++++++ .../neomedia/codec/video/h264/JNIDecoder.java | 27 +++++++++++++++++++ .../device/VideoMediaDeviceSession.java | 23 ++++++++++++++-- .../impl/protocol/sip/CallPeerSipImpl.java | 1 - .../neomedia/control/KeyFrameControl.java | 10 +++++++ .../control/KeyFrameControlAdapter.java | 25 +++++++++++++++++ 6 files changed, 98 insertions(+), 3 deletions(-) diff --git a/src/net/java/sip/communicator/impl/neomedia/codec/video/h264/DePacketizer.java b/src/net/java/sip/communicator/impl/neomedia/codec/video/h264/DePacketizer.java index 6bd2ee3e5..9c547bae6 100644 --- a/src/net/java/sip/communicator/impl/neomedia/codec/video/h264/DePacketizer.java +++ b/src/net/java/sip/communicator/impl/neomedia/codec/video/h264/DePacketizer.java @@ -515,6 +515,21 @@ private void padOutput(byte[] out, int outOffset) Arrays.fill(out, outOffset, outOffset + outputPaddingSize, (byte) 0); } + /** + * Requests a key frame from the remote peer associated with this + * DePacketizer using the logic of DePacketizer. + * + * @return true if a key frame was indeed requested in response to + * the call; otherwise, false + * @deprecated The method and its callers are part of a quick workaround to + * expose the logic of DePacketizer to JNIDecoder. + */ + public boolean requestKeyFrame() + { + setRequestKeyFrame(true); + return true; + } + /** * Resets the states of this DePacketizer and a specific output * Buffer so that they are ready to have this DePacketizer diff --git a/src/net/java/sip/communicator/impl/neomedia/codec/video/h264/JNIDecoder.java b/src/net/java/sip/communicator/impl/neomedia/codec/video/h264/JNIDecoder.java index 2d37b2409..ea00a908a 100644 --- a/src/net/java/sip/communicator/impl/neomedia/codec/video/h264/JNIDecoder.java +++ b/src/net/java/sip/communicator/impl/neomedia/codec/video/h264/JNIDecoder.java @@ -13,6 +13,7 @@ import net.java.sip.communicator.impl.neomedia.codec.*; import net.java.sip.communicator.impl.neomedia.codec.video.*; +import net.java.sip.communicator.service.neomedia.control.*; import net.sf.fmj.media.*; /** @@ -58,6 +59,12 @@ public class JNIDecoder */ private int height; + /** + * The KeyFrameControl used by this JNIDecoder to + * control its key frame-related logic. + */ + private KeyFrameControl keyFrameControl; + /** * Array of output VideoFormats. */ @@ -281,6 +288,12 @@ public synchronized int process(Buffer inBuffer, Buffer outBuffer) if (!got_picture[0]) { + if ((inBuffer.getFlags() & Buffer.FLAG_RTP_MARKER) != 0) + { + if (keyFrameControl != null) + keyFrameControl.requestKeyFrame(); + } + outBuffer.setDiscard(true); return BUFFER_PROCESSED_OK; } @@ -354,4 +367,18 @@ public Format setInputFormat(Format format) reset(); return setFormat; } + + /** + * Sets the KeyFrameControl to be used by this + * DePacketizer as a means of control over its key frame-related + * logic. + * + * @param keyFrameControl the KeyFrameControl to be used by this + * DePacketizer as a means of control over its key frame-related + * logic + */ + public void setKeyFrameControl(KeyFrameControl keyFrameControl) + { + this.keyFrameControl = keyFrameControl; + } } diff --git a/src/net/java/sip/communicator/impl/neomedia/device/VideoMediaDeviceSession.java b/src/net/java/sip/communicator/impl/neomedia/device/VideoMediaDeviceSession.java index 8d459a1bc..f8f1a6e97 100644 --- a/src/net/java/sip/communicator/impl/neomedia/device/VideoMediaDeviceSession.java +++ b/src/net/java/sip/communicator/impl/neomedia/device/VideoMediaDeviceSession.java @@ -23,6 +23,7 @@ import net.java.sip.communicator.impl.neomedia.format.*; import net.java.sip.communicator.impl.neomedia.transform.*; import net.java.sip.communicator.service.neomedia.*; +import net.java.sip.communicator.service.neomedia.control.*; import net.java.sip.communicator.service.neomedia.control.KeyFrameControl; // disambiguation import net.java.sip.communicator.service.neomedia.event.*; import net.java.sip.communicator.service.neomedia.format.*; @@ -828,13 +829,31 @@ protected void playerConfigureComplete(final Processor player) if ("h264/rtp".equalsIgnoreCase( getFormat().getJMFEncoding())) { - DePacketizer depacketizer = new DePacketizer(); + final DePacketizer depacketizer = new DePacketizer(); + JNIDecoder decoder = new JNIDecoder(); if (keyFrameControl != null) + { depacketizer.setKeyFrameControl(keyFrameControl); + decoder.setKeyFrameControl( + new KeyFrameControlAdapter() + { + @Override + public boolean requestKeyFrame() + { + return + depacketizer.requestKeyFrame(); + } + }); + } trackControl.setCodecChain( - new Codec[] { depacketizer, playerScaler }); + new Codec[] + { + depacketizer, + decoder, + playerScaler + }); } else { diff --git a/src/net/java/sip/communicator/impl/protocol/sip/CallPeerSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/CallPeerSipImpl.java index 8cf375458..aae8ec349 100644 --- a/src/net/java/sip/communicator/impl/protocol/sip/CallPeerSipImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/sip/CallPeerSipImpl.java @@ -355,7 +355,6 @@ boolean processPictureFastUpdate( Request request) throws OperationFailedException { - System.err.println("processPictureFastUpdate Request"); CallPeerMediaHandlerSipImpl mediaHandler = getMediaHandler(); boolean requested = (mediaHandler == null) diff --git a/src/net/java/sip/communicator/service/neomedia/control/KeyFrameControl.java b/src/net/java/sip/communicator/service/neomedia/control/KeyFrameControl.java index 65554e812..499a37e54 100644 --- a/src/net/java/sip/communicator/service/neomedia/control/KeyFrameControl.java +++ b/src/net/java/sip/communicator/service/neomedia/control/KeyFrameControl.java @@ -100,6 +100,16 @@ public void addKeyFrameRequester( */ public boolean removeKeyFrameRequester(KeyFrameRequester keyFrameRequester); + /** + * Requests a key frame from the remote peer of the associated + * VideoMediaStream. + * + * @return true if a key frame was indeed requested from the remote + * peer of the associated VideoMediaStream in response to the call; + * otherwise, false + */ + public boolean requestKeyFrame(); + /** * Represents a way for the remote peer of a VideoMediaStream to * request a key frame from its local peer. diff --git a/src/net/java/sip/communicator/service/neomedia/control/KeyFrameControlAdapter.java b/src/net/java/sip/communicator/service/neomedia/control/KeyFrameControlAdapter.java index 50449aadf..1517389bf 100644 --- a/src/net/java/sip/communicator/service/neomedia/control/KeyFrameControlAdapter.java +++ b/src/net/java/sip/communicator/service/neomedia/control/KeyFrameControlAdapter.java @@ -248,4 +248,29 @@ public boolean removeKeyFrameRequester(KeyFrameRequester keyFrameRequester) return false; } } + + /** + * Implements {@link KeyFrameControl#requestKeyFrame()}. + * + * {@inheritDoc} + */ + public boolean requestKeyFrame() + { + for (KeyFrameRequester keyFrameRequester : getKeyFrameRequesters()) + { + try + { + if (keyFrameRequester.requestKeyFrame()) + return true; + } + catch (Exception e) + { + /* + * A KeyFrameRequestee has malfunctioned, do not let it + * interfere with the others. + */ + } + } + return false; + } }